xref: /libCEED/interface/ceed-operator.c (revision d99fa3c5cd91a1690aedf0679cbf290d44fec74c)
1d7b241e6Sjeremylt // Copyright (c) 2017, Lawrence Livermore National Security, LLC. Produced at
2d7b241e6Sjeremylt // the Lawrence Livermore National Laboratory. LLNL-CODE-734707. All Rights
3d7b241e6Sjeremylt // reserved. See files LICENSE and NOTICE for details.
4d7b241e6Sjeremylt //
5d7b241e6Sjeremylt // This file is part of CEED, a collection of benchmarks, miniapps, software
6d7b241e6Sjeremylt // libraries and APIs for efficient high-order finite element and spectral
7d7b241e6Sjeremylt // element discretizations for exascale applications. For more information and
8d7b241e6Sjeremylt // source code availability see http://github.com/ceed.
9d7b241e6Sjeremylt //
10d7b241e6Sjeremylt // The CEED research is supported by the Exascale Computing Project 17-SC-20-SC,
11d7b241e6Sjeremylt // a collaborative effort of two U.S. Department of Energy organizations (Office
12d7b241e6Sjeremylt // of Science and the National Nuclear Security Administration) responsible for
13d7b241e6Sjeremylt // the planning and preparation of a capable exascale ecosystem, including
14d7b241e6Sjeremylt // software, applications, hardware, advanced system engineering and early
15d7b241e6Sjeremylt // testbed platforms, in support of the nation's exascale computing imperative.
16d7b241e6Sjeremylt 
17d7b241e6Sjeremylt #include <ceed-impl.h>
18d863ab9bSjeremylt #include <ceed-backend.h>
19d7b241e6Sjeremylt #include <string.h>
203bd813ffSjeremylt #include <math.h>
21d7b241e6Sjeremylt 
22dfdf5a53Sjeremylt /// @file
237a982d89SJeremy L. Thompson /// Implementation of CeedOperator interfaces
247a982d89SJeremy L. Thompson 
257a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
267a982d89SJeremy L. Thompson /// CeedOperator Library Internal Functions
277a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
287a982d89SJeremy L. Thompson /// @addtogroup CeedOperatorDeveloper
297a982d89SJeremy L. Thompson /// @{
307a982d89SJeremy L. Thompson 
317a982d89SJeremy L. Thompson /**
327a982d89SJeremy L. Thompson   @brief Duplicate a CeedOperator with a reference Ceed to fallback for advanced
337a982d89SJeremy L. Thompson            CeedOperator functionality
347a982d89SJeremy L. Thompson 
357a982d89SJeremy L. Thompson   @param op           CeedOperator to create fallback for
367a982d89SJeremy L. Thompson 
377a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
387a982d89SJeremy L. Thompson 
397a982d89SJeremy L. Thompson   @ref Developer
407a982d89SJeremy L. Thompson **/
417a982d89SJeremy L. Thompson int CeedOperatorCreateFallback(CeedOperator op) {
427a982d89SJeremy L. Thompson   int ierr;
437a982d89SJeremy L. Thompson 
447a982d89SJeremy L. Thompson   // Fallback Ceed
457a982d89SJeremy L. Thompson   const char *resource, *fallbackresource;
467a982d89SJeremy L. Thompson   ierr = CeedGetResource(op->ceed, &resource); CeedChk(ierr);
477a982d89SJeremy L. Thompson   ierr = CeedGetOperatorFallbackResource(op->ceed, &fallbackresource);
487a982d89SJeremy L. Thompson   CeedChk(ierr);
497a982d89SJeremy L. Thompson   if (!strcmp(resource, fallbackresource))
507a982d89SJeremy L. Thompson     // LCOV_EXCL_START
517a982d89SJeremy L. Thompson     return CeedError(op->ceed, 1, "Backend %s cannot create an operator"
527a982d89SJeremy L. Thompson                      "fallback to resource %s", resource, fallbackresource);
537a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
547a982d89SJeremy L. Thompson 
557a982d89SJeremy L. Thompson   // Fallback Ceed
567a982d89SJeremy L. Thompson   Ceed ceedref;
577a982d89SJeremy L. Thompson   if (!op->ceed->opfallbackceed) {
587a982d89SJeremy L. Thompson     ierr = CeedInit(fallbackresource, &ceedref); CeedChk(ierr);
597a982d89SJeremy L. Thompson     ceedref->opfallbackparent = op->ceed;
607a982d89SJeremy L. Thompson     op->ceed->opfallbackceed = ceedref;
617a982d89SJeremy L. Thompson   }
627a982d89SJeremy L. Thompson   ceedref = op->ceed->opfallbackceed;
637a982d89SJeremy L. Thompson 
647a982d89SJeremy L. Thompson   // Clone Op
657a982d89SJeremy L. Thompson   CeedOperator opref;
667a982d89SJeremy L. Thompson   ierr = CeedCalloc(1, &opref); CeedChk(ierr);
677a982d89SJeremy L. Thompson   memcpy(opref, op, sizeof(*opref)); CeedChk(ierr);
687a982d89SJeremy L. Thompson   opref->data = NULL;
697a982d89SJeremy L. Thompson   opref->setupdone = 0;
707a982d89SJeremy L. Thompson   opref->ceed = ceedref;
717a982d89SJeremy L. Thompson   ierr = ceedref->OperatorCreate(opref); CeedChk(ierr);
727a982d89SJeremy L. Thompson   op->opfallback = opref;
737a982d89SJeremy L. Thompson 
747a982d89SJeremy L. Thompson   // Clone QF
757a982d89SJeremy L. Thompson   CeedQFunction qfref;
767a982d89SJeremy L. Thompson   ierr = CeedCalloc(1, &qfref); CeedChk(ierr);
777a982d89SJeremy L. Thompson   memcpy(qfref, (op->qf), sizeof(*qfref)); CeedChk(ierr);
787a982d89SJeremy L. Thompson   qfref->data = NULL;
797a982d89SJeremy L. Thompson   qfref->ceed = ceedref;
807a982d89SJeremy L. Thompson   ierr = ceedref->QFunctionCreate(qfref); CeedChk(ierr);
817a982d89SJeremy L. Thompson   opref->qf = qfref;
827a982d89SJeremy L. Thompson   op->qffallback = qfref;
837a982d89SJeremy L. Thompson 
847a982d89SJeremy L. Thompson   return 0;
857a982d89SJeremy L. Thompson }
867a982d89SJeremy L. Thompson 
877a982d89SJeremy L. Thompson /**
887a982d89SJeremy L. Thompson   @brief Check if a CeedOperator is ready to be used.
897a982d89SJeremy L. Thompson 
907a982d89SJeremy L. Thompson   @param[in] ceed Ceed object for error handling
917a982d89SJeremy L. Thompson   @param[in] op   CeedOperator to check
927a982d89SJeremy L. Thompson 
937a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
947a982d89SJeremy L. Thompson 
957a982d89SJeremy L. Thompson   @ref Developer
967a982d89SJeremy L. Thompson **/
977a982d89SJeremy L. Thompson static int CeedOperatorCheckReady(Ceed ceed, CeedOperator op) {
987a982d89SJeremy L. Thompson   CeedQFunction qf = op->qf;
997a982d89SJeremy L. Thompson 
1007a982d89SJeremy L. Thompson   if (op->composite) {
1017a982d89SJeremy L. Thompson     if (!op->numsub)
1027a982d89SJeremy L. Thompson       // LCOV_EXCL_START
1037a982d89SJeremy L. Thompson       return CeedError(ceed, 1, "No suboperators set");
1047a982d89SJeremy L. Thompson     // LCOV_EXCL_STOP
1057a982d89SJeremy L. Thompson   } else {
1067a982d89SJeremy L. Thompson     if (op->nfields == 0)
1077a982d89SJeremy L. Thompson       // LCOV_EXCL_START
1087a982d89SJeremy L. Thompson       return CeedError(ceed, 1, "No operator fields set");
1097a982d89SJeremy L. Thompson     // LCOV_EXCL_STOP
1107a982d89SJeremy L. Thompson     if (op->nfields < qf->numinputfields + qf->numoutputfields)
1117a982d89SJeremy L. Thompson       // LCOV_EXCL_START
1127a982d89SJeremy L. Thompson       return CeedError(ceed, 1, "Not all operator fields set");
1137a982d89SJeremy L. Thompson     // LCOV_EXCL_STOP
1147a982d89SJeremy L. Thompson     if (!op->hasrestriction)
1157a982d89SJeremy L. Thompson       // LCOV_EXCL_START
1167a982d89SJeremy L. Thompson       return CeedError(ceed, 1,"At least one restriction required");
1177a982d89SJeremy L. Thompson     // LCOV_EXCL_STOP
1187a982d89SJeremy L. Thompson     if (op->numqpoints == 0)
1197a982d89SJeremy L. Thompson       // LCOV_EXCL_START
1207a982d89SJeremy L. Thompson       return CeedError(ceed, 1,"At least one non-collocated basis required");
1217a982d89SJeremy L. Thompson     // LCOV_EXCL_STOP
1227a982d89SJeremy L. Thompson   }
1237a982d89SJeremy L. Thompson 
1247a982d89SJeremy L. Thompson   return 0;
1257a982d89SJeremy L. Thompson }
1267a982d89SJeremy L. Thompson 
1277a982d89SJeremy L. Thompson /**
1287a982d89SJeremy L. Thompson   @brief View a field of a CeedOperator
1297a982d89SJeremy L. Thompson 
1307a982d89SJeremy L. Thompson   @param[in] field       Operator field to view
1314c4400c7SValeria Barra   @param[in] qffield     QFunction field (carries field name)
1327a982d89SJeremy L. Thompson   @param[in] fieldnumber Number of field being viewed
1334c4400c7SValeria Barra   @param[in] sub         true indicates sub-operator, which increases indentation; false for top-level operator
1344c4400c7SValeria Barra   @param[in] in          true for an input field; false for output field
1357a982d89SJeremy L. Thompson   @param[in] stream      Stream to view to, e.g., stdout
1367a982d89SJeremy L. Thompson 
1377a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
1387a982d89SJeremy L. Thompson 
1397a982d89SJeremy L. Thompson   @ref Utility
1407a982d89SJeremy L. Thompson **/
1417a982d89SJeremy L. Thompson static int CeedOperatorFieldView(CeedOperatorField field,
1427a982d89SJeremy L. Thompson                                  CeedQFunctionField qffield,
1437a982d89SJeremy L. Thompson                                  CeedInt fieldnumber, bool sub, bool in,
1447a982d89SJeremy L. Thompson                                  FILE *stream) {
1457a982d89SJeremy L. Thompson   const char *pre = sub ? "  " : "";
1467a982d89SJeremy L. Thompson   const char *inout = in ? "Input" : "Output";
1477a982d89SJeremy L. Thompson 
1487a982d89SJeremy L. Thompson   fprintf(stream, "%s    %s Field [%d]:\n"
1497a982d89SJeremy L. Thompson           "%s      Name: \"%s\"\n",
1507a982d89SJeremy L. Thompson           pre, inout, fieldnumber, pre, qffield->fieldname);
1517a982d89SJeremy L. Thompson 
1527a982d89SJeremy L. Thompson   if (field->basis == CEED_BASIS_COLLOCATED)
1537a982d89SJeremy L. Thompson     fprintf(stream, "%s      Collocated basis\n", pre);
1547a982d89SJeremy L. Thompson 
1557a982d89SJeremy L. Thompson   if (field->vec == CEED_VECTOR_ACTIVE)
1567a982d89SJeremy L. Thompson     fprintf(stream, "%s      Active vector\n", pre);
1577a982d89SJeremy L. Thompson   else if (field->vec == CEED_VECTOR_NONE)
1587a982d89SJeremy L. Thompson     fprintf(stream, "%s      No vector\n", pre);
1597a982d89SJeremy L. Thompson 
1607a982d89SJeremy L. Thompson   return 0;
1617a982d89SJeremy L. Thompson }
1627a982d89SJeremy L. Thompson 
1637a982d89SJeremy L. Thompson /**
1647a982d89SJeremy L. Thompson   @brief View a single CeedOperator
1657a982d89SJeremy L. Thompson 
1667a982d89SJeremy L. Thompson   @param[in] op     CeedOperator to view
1677a982d89SJeremy L. Thompson   @param[in] sub    Boolean flag for sub-operator
1687a982d89SJeremy L. Thompson   @param[in] stream Stream to write; typically stdout/stderr or a file
1697a982d89SJeremy L. Thompson 
1707a982d89SJeremy L. Thompson   @return Error code: 0 - success, otherwise - failure
1717a982d89SJeremy L. Thompson 
1727a982d89SJeremy L. Thompson   @ref Utility
1737a982d89SJeremy L. Thompson **/
1747a982d89SJeremy L. Thompson int CeedOperatorSingleView(CeedOperator op, bool sub, FILE *stream) {
1757a982d89SJeremy L. Thompson   int ierr;
1767a982d89SJeremy L. Thompson   const char *pre = sub ? "  " : "";
1777a982d89SJeremy L. Thompson 
1787a982d89SJeremy L. Thompson   CeedInt totalfields;
1797a982d89SJeremy L. Thompson   ierr = CeedOperatorGetNumArgs(op, &totalfields); CeedChk(ierr);
1807a982d89SJeremy L. Thompson 
1817a982d89SJeremy L. Thompson   fprintf(stream, "%s  %d Field%s\n", pre, totalfields, totalfields>1 ? "s" : "");
1827a982d89SJeremy L. Thompson 
1837a982d89SJeremy L. Thompson   fprintf(stream, "%s  %d Input Field%s:\n", pre, op->qf->numinputfields,
1847a982d89SJeremy L. Thompson           op->qf->numinputfields>1 ? "s" : "");
1857a982d89SJeremy L. Thompson   for (CeedInt i=0; i<op->qf->numinputfields; i++) {
1867a982d89SJeremy L. Thompson     ierr = CeedOperatorFieldView(op->inputfields[i], op->qf->inputfields[i],
1877a982d89SJeremy L. Thompson                                  i, sub, 1, stream); CeedChk(ierr);
1887a982d89SJeremy L. Thompson   }
1897a982d89SJeremy L. Thompson 
1907a982d89SJeremy L. Thompson   fprintf(stream, "%s  %d Output Field%s:\n", pre, op->qf->numoutputfields,
1917a982d89SJeremy L. Thompson           op->qf->numoutputfields>1 ? "s" : "");
1927a982d89SJeremy L. Thompson   for (CeedInt i=0; i<op->qf->numoutputfields; i++) {
1937a982d89SJeremy L. Thompson     ierr = CeedOperatorFieldView(op->outputfields[i], op->qf->inputfields[i],
1947a982d89SJeremy L. Thompson                                  i, sub, 0, stream); CeedChk(ierr);
1957a982d89SJeremy L. Thompson   }
1967a982d89SJeremy L. Thompson 
1977a982d89SJeremy L. Thompson   return 0;
1987a982d89SJeremy L. Thompson }
1997a982d89SJeremy L. Thompson 
200*d99fa3c5SJeremy L Thompson /**
201*d99fa3c5SJeremy L Thompson   @brief Find the active vector basis for a CeedOperator
202*d99fa3c5SJeremy L Thompson 
203*d99fa3c5SJeremy L Thompson   @param[in] op            CeedOperator to find active basis for
204*d99fa3c5SJeremy L Thompson   @param[out] activeBasis  Basis for active input vector
205*d99fa3c5SJeremy L Thompson 
206*d99fa3c5SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
207*d99fa3c5SJeremy L Thompson 
208*d99fa3c5SJeremy L Thompson   @ ref Developer
209*d99fa3c5SJeremy L Thompson **/
210*d99fa3c5SJeremy L Thompson static int CeedOperatorGetActiveBasis(CeedOperator op,
211*d99fa3c5SJeremy L Thompson                                       CeedBasis *activeBasis) {
212*d99fa3c5SJeremy L Thompson   *activeBasis = NULL;
213*d99fa3c5SJeremy L Thompson   for (int i = 0; i < op->qf->numinputfields; i++)
214*d99fa3c5SJeremy L Thompson     if (op->inputfields[i]->vec == CEED_VECTOR_ACTIVE) {
215*d99fa3c5SJeremy L Thompson       *activeBasis = op->inputfields[i]->basis;
216*d99fa3c5SJeremy L Thompson       break;
217*d99fa3c5SJeremy L Thompson     }
218*d99fa3c5SJeremy L Thompson 
219*d99fa3c5SJeremy L Thompson   if (!*activeBasis) {
220*d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
221*d99fa3c5SJeremy L Thompson     int ierr;
222*d99fa3c5SJeremy L Thompson     Ceed ceed;
223*d99fa3c5SJeremy L Thompson     ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr);
224*d99fa3c5SJeremy L Thompson     return CeedError(ceed, 1,
225*d99fa3c5SJeremy L Thompson                      "No active basis found for automatic multigrid setup");
226*d99fa3c5SJeremy L Thompson     // LCOV_EXCL_STOP
227*d99fa3c5SJeremy L Thompson   }
228*d99fa3c5SJeremy L Thompson   return 0;
229*d99fa3c5SJeremy L Thompson }
230*d99fa3c5SJeremy L Thompson 
231*d99fa3c5SJeremy L Thompson 
232*d99fa3c5SJeremy L Thompson /**
233*d99fa3c5SJeremy L Thompson   @brief Common code for creating a multigrid coarse operator and level
234*d99fa3c5SJeremy L Thompson            transfer operators for a CeedOperator
235*d99fa3c5SJeremy L Thompson 
236*d99fa3c5SJeremy L Thompson   @param[in] opFine       Fine grid operator
237*d99fa3c5SJeremy L Thompson   @param[in] PMultFine    L-vector multiplicity in parallel gather/scatter
238*d99fa3c5SJeremy L Thompson   @param[in] rstrCoarse   Coarse grid restriction
239*d99fa3c5SJeremy L Thompson   @param[in] basisCoarse  Coarse grid active vector basis
240*d99fa3c5SJeremy L Thompson   @param[in] basisCtoF    Basis for coarse to fine interpolation
241*d99fa3c5SJeremy L Thompson   @param[out] opCoarse    Coarse grid operator
242*d99fa3c5SJeremy L Thompson   @param[out] opProlong   Coarse to fine operator
243*d99fa3c5SJeremy L Thompson   @param[out] opRestrict  Fine to coarse operator
244*d99fa3c5SJeremy L Thompson 
245*d99fa3c5SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
246*d99fa3c5SJeremy L Thompson 
247*d99fa3c5SJeremy L Thompson   @ref Developer
248*d99fa3c5SJeremy L Thompson **/
249*d99fa3c5SJeremy L Thompson static int CeedOperatorMultigridLevel_Core(CeedOperator opFine,
250*d99fa3c5SJeremy L Thompson     CeedVector PMultFine, CeedElemRestriction rstrCoarse, CeedBasis basisCoarse,
251*d99fa3c5SJeremy L Thompson     CeedBasis basisCtoF, CeedOperator *opCoarse, CeedOperator *opProlong,
252*d99fa3c5SJeremy L Thompson     CeedOperator *opRestrict) {
253*d99fa3c5SJeremy L Thompson   int ierr;
254*d99fa3c5SJeremy L Thompson   Ceed ceed;
255*d99fa3c5SJeremy L Thompson   ierr = CeedOperatorGetCeed(opFine, &ceed); CeedChk(ierr);
256*d99fa3c5SJeremy L Thompson 
257*d99fa3c5SJeremy L Thompson   // Check for composite operator
258*d99fa3c5SJeremy L Thompson   bool isComposite;
259*d99fa3c5SJeremy L Thompson   ierr = CeedOperatorIsComposite(opFine, &isComposite); CeedChk(ierr);
260*d99fa3c5SJeremy L Thompson   if (isComposite)
261*d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
262*d99fa3c5SJeremy L Thompson     return CeedError(ceed, 1,
263*d99fa3c5SJeremy L Thompson                      "Automatic multigrid setup for composite operators not supported");
264*d99fa3c5SJeremy L Thompson   // LCOV_EXCL_STOP
265*d99fa3c5SJeremy L Thompson 
266*d99fa3c5SJeremy L Thompson   // Coarse Grid
267*d99fa3c5SJeremy L Thompson   ierr = CeedOperatorCreate(ceed, opFine->qf, opFine->dqf, opFine->dqfT,
268*d99fa3c5SJeremy L Thompson                             opCoarse); CeedChk(ierr);
269*d99fa3c5SJeremy L Thompson   CeedElemRestriction rstrFine = NULL;
270*d99fa3c5SJeremy L Thompson   // -- Clone input fields
271*d99fa3c5SJeremy L Thompson   for (int i = 0; i < opFine->qf->numinputfields; i++) {
272*d99fa3c5SJeremy L Thompson     if (opFine->inputfields[i]->vec == CEED_VECTOR_ACTIVE) {
273*d99fa3c5SJeremy L Thompson       rstrFine = opFine->inputfields[i]->Erestrict;
274*d99fa3c5SJeremy L Thompson       ierr = CeedOperatorSetField(*opCoarse, opFine->inputfields[i]->fieldname,
275*d99fa3c5SJeremy L Thompson                                   rstrCoarse, basisCoarse, CEED_VECTOR_ACTIVE);
276*d99fa3c5SJeremy L Thompson       CeedChk(ierr);
277*d99fa3c5SJeremy L Thompson     } else {
278*d99fa3c5SJeremy L Thompson       ierr = CeedOperatorSetField(*opCoarse, opFine->inputfields[i]->fieldname,
279*d99fa3c5SJeremy L Thompson                                   opFine->inputfields[i]->Erestrict,
280*d99fa3c5SJeremy L Thompson                                   opFine->inputfields[i]->basis,
281*d99fa3c5SJeremy L Thompson                                   opFine->inputfields[i]->vec); CeedChk(ierr);
282*d99fa3c5SJeremy L Thompson     }
283*d99fa3c5SJeremy L Thompson   }
284*d99fa3c5SJeremy L Thompson   // -- Clone output fields
285*d99fa3c5SJeremy L Thompson   for (int i = 0; i < opFine->qf->numoutputfields; i++) {
286*d99fa3c5SJeremy L Thompson     if (opFine->outputfields[i]->vec == CEED_VECTOR_ACTIVE) {
287*d99fa3c5SJeremy L Thompson       ierr = CeedOperatorSetField(*opCoarse, opFine->outputfields[i]->fieldname,
288*d99fa3c5SJeremy L Thompson                                   rstrCoarse, basisCoarse, CEED_VECTOR_ACTIVE);
289*d99fa3c5SJeremy L Thompson       CeedChk(ierr);
290*d99fa3c5SJeremy L Thompson     } else {
291*d99fa3c5SJeremy L Thompson       ierr = CeedOperatorSetField(*opCoarse, opFine->outputfields[i]->fieldname,
292*d99fa3c5SJeremy L Thompson                                   opFine->outputfields[i]->Erestrict,
293*d99fa3c5SJeremy L Thompson                                   opFine->outputfields[i]->basis,
294*d99fa3c5SJeremy L Thompson                                   opFine->outputfields[i]->vec); CeedChk(ierr);
295*d99fa3c5SJeremy L Thompson     }
296*d99fa3c5SJeremy L Thompson   }
297*d99fa3c5SJeremy L Thompson 
298*d99fa3c5SJeremy L Thompson   // Multiplicity vector
299*d99fa3c5SJeremy L Thompson   CeedVector multVec, multE;
300*d99fa3c5SJeremy L Thompson   ierr = CeedElemRestrictionCreateVector(rstrFine, &multVec, &multE);
301*d99fa3c5SJeremy L Thompson   CeedChk(ierr);
302*d99fa3c5SJeremy L Thompson   ierr = CeedVectorSetValue(multE, 0.0); CeedChk(ierr);
303*d99fa3c5SJeremy L Thompson   ierr = CeedElemRestrictionApply(rstrFine, CEED_NOTRANSPOSE, PMultFine, multE,
304*d99fa3c5SJeremy L Thompson                                   CEED_REQUEST_IMMEDIATE); CeedChk(ierr);
305*d99fa3c5SJeremy L Thompson   ierr = CeedVectorSetValue(multVec, 0.0); CeedChk(ierr);
306*d99fa3c5SJeremy L Thompson   ierr = CeedElemRestrictionApply(rstrFine, CEED_TRANSPOSE, multE, multVec,
307*d99fa3c5SJeremy L Thompson                                   CEED_REQUEST_IMMEDIATE); CeedChk(ierr);
308*d99fa3c5SJeremy L Thompson   ierr = CeedVectorDestroy(&multE); CeedChk(ierr);
309*d99fa3c5SJeremy L Thompson   ierr = CeedVectorReciprocal(multVec); CeedChk(ierr);
310*d99fa3c5SJeremy L Thompson 
311*d99fa3c5SJeremy L Thompson   // Restriction
312*d99fa3c5SJeremy L Thompson   CeedInt ncomp;
313*d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumComponents(basisCoarse, &ncomp); CeedChk(ierr);
314*d99fa3c5SJeremy L Thompson   CeedQFunction qfRestrict;
315*d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionCreateInteriorByName(ceed, "Scale", &qfRestrict);
316*d99fa3c5SJeremy L Thompson   CeedChk(ierr);
317*d99fa3c5SJeremy L Thompson   CeedInt *ctxR;
318*d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(1, &ctxR); CeedChk(ierr);
319*d99fa3c5SJeremy L Thompson   ctxR[0] = ncomp;
320*d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionSetContext(qfRestrict, ctxR, sizeof(*ctxR)); CeedChk(ierr);
321*d99fa3c5SJeremy L Thompson   qfRestrict->ctx_allocated = qfRestrict->ctx;
322*d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionAddInput(qfRestrict, "input", ncomp, CEED_EVAL_NONE);
323*d99fa3c5SJeremy L Thompson   CeedChk(ierr);
324*d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionAddInput(qfRestrict, "scale", ncomp, CEED_EVAL_NONE);
325*d99fa3c5SJeremy L Thompson   CeedChk(ierr);
326*d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionAddOutput(qfRestrict, "output", ncomp, CEED_EVAL_INTERP);
327*d99fa3c5SJeremy L Thompson   CeedChk(ierr);
328*d99fa3c5SJeremy L Thompson 
329*d99fa3c5SJeremy L Thompson   ierr = CeedOperatorCreate(ceed, qfRestrict, CEED_QFUNCTION_NONE,
330*d99fa3c5SJeremy L Thompson                             CEED_QFUNCTION_NONE, opRestrict);
331*d99fa3c5SJeremy L Thompson   CeedChk(ierr);
332*d99fa3c5SJeremy L Thompson   ierr = CeedOperatorSetField(*opRestrict, "input", rstrFine,
333*d99fa3c5SJeremy L Thompson                               CEED_BASIS_COLLOCATED, CEED_VECTOR_ACTIVE);
334*d99fa3c5SJeremy L Thompson   CeedChk(ierr);
335*d99fa3c5SJeremy L Thompson   ierr = CeedOperatorSetField(*opRestrict, "scale", rstrFine,
336*d99fa3c5SJeremy L Thompson                               CEED_BASIS_COLLOCATED, multVec);
337*d99fa3c5SJeremy L Thompson   CeedChk(ierr);
338*d99fa3c5SJeremy L Thompson   ierr = CeedOperatorSetField(*opRestrict, "output", rstrCoarse, basisCtoF,
339*d99fa3c5SJeremy L Thompson                               CEED_VECTOR_ACTIVE); CeedChk(ierr);
340*d99fa3c5SJeremy L Thompson 
341*d99fa3c5SJeremy L Thompson   // Prolongation
342*d99fa3c5SJeremy L Thompson   CeedQFunction qfProlong;
343*d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionCreateInteriorByName(ceed, "Scale", &qfProlong);
344*d99fa3c5SJeremy L Thompson   CeedChk(ierr);
345*d99fa3c5SJeremy L Thompson   CeedInt *ctxP;
346*d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(1, &ctxP); CeedChk(ierr);
347*d99fa3c5SJeremy L Thompson   ctxP[0] = ncomp;
348*d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionSetContext(qfProlong, ctxP, sizeof(*ctxP)); CeedChk(ierr);
349*d99fa3c5SJeremy L Thompson   qfProlong->ctx_allocated = qfProlong->ctx;
350*d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionAddInput(qfProlong, "input", ncomp, CEED_EVAL_INTERP);
351*d99fa3c5SJeremy L Thompson   CeedChk(ierr);
352*d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionAddInput(qfProlong, "scale", ncomp, CEED_EVAL_NONE);
353*d99fa3c5SJeremy L Thompson   CeedChk(ierr);
354*d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionAddOutput(qfProlong, "output", ncomp, CEED_EVAL_NONE);
355*d99fa3c5SJeremy L Thompson   CeedChk(ierr);
356*d99fa3c5SJeremy L Thompson 
357*d99fa3c5SJeremy L Thompson   ierr = CeedOperatorCreate(ceed, qfProlong, CEED_QFUNCTION_NONE,
358*d99fa3c5SJeremy L Thompson                             CEED_QFUNCTION_NONE, opProlong);
359*d99fa3c5SJeremy L Thompson   CeedChk(ierr);
360*d99fa3c5SJeremy L Thompson   ierr = CeedOperatorSetField(*opProlong, "input", rstrCoarse, basisCtoF,
361*d99fa3c5SJeremy L Thompson                               CEED_VECTOR_ACTIVE); CeedChk(ierr);
362*d99fa3c5SJeremy L Thompson   ierr = CeedOperatorSetField(*opProlong, "scale", rstrFine,
363*d99fa3c5SJeremy L Thompson                               CEED_BASIS_COLLOCATED, multVec);
364*d99fa3c5SJeremy L Thompson   CeedChk(ierr);
365*d99fa3c5SJeremy L Thompson   ierr = CeedOperatorSetField(*opProlong, "output", rstrFine,
366*d99fa3c5SJeremy L Thompson                               CEED_BASIS_COLLOCATED, CEED_VECTOR_ACTIVE);
367*d99fa3c5SJeremy L Thompson   CeedChk(ierr);
368*d99fa3c5SJeremy L Thompson 
369*d99fa3c5SJeremy L Thompson   // Cleanup
370*d99fa3c5SJeremy L Thompson   ierr = CeedVectorDestroy(&multVec); CeedChk(ierr);
371*d99fa3c5SJeremy L Thompson   ierr = CeedBasisDestroy(&basisCtoF); CeedChk(ierr);
372*d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionDestroy(&qfRestrict); CeedChk(ierr);
373*d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionDestroy(&qfProlong); CeedChk(ierr);
374*d99fa3c5SJeremy L Thompson 
375*d99fa3c5SJeremy L Thompson   return 0;
376*d99fa3c5SJeremy L Thompson }
377*d99fa3c5SJeremy L Thompson 
3787a982d89SJeremy L. Thompson /// @}
3797a982d89SJeremy L. Thompson 
3807a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
3817a982d89SJeremy L. Thompson /// CeedOperator Backend API
3827a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
3837a982d89SJeremy L. Thompson /// @addtogroup CeedOperatorBackend
3847a982d89SJeremy L. Thompson /// @{
3857a982d89SJeremy L. Thompson 
3867a982d89SJeremy L. Thompson /**
3877a982d89SJeremy L. Thompson   @brief Get the Ceed associated with a CeedOperator
3887a982d89SJeremy L. Thompson 
3897a982d89SJeremy L. Thompson   @param op              CeedOperator
3907a982d89SJeremy L. Thompson   @param[out] ceed       Variable to store Ceed
3917a982d89SJeremy L. Thompson 
3927a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
3937a982d89SJeremy L. Thompson 
3947a982d89SJeremy L. Thompson   @ref Backend
3957a982d89SJeremy L. Thompson **/
3967a982d89SJeremy L. Thompson 
3977a982d89SJeremy L. Thompson int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) {
3987a982d89SJeremy L. Thompson   *ceed = op->ceed;
3997a982d89SJeremy L. Thompson   return 0;
4007a982d89SJeremy L. Thompson }
4017a982d89SJeremy L. Thompson 
4027a982d89SJeremy L. Thompson /**
4037a982d89SJeremy L. Thompson   @brief Get the number of elements associated with a CeedOperator
4047a982d89SJeremy L. Thompson 
4057a982d89SJeremy L. Thompson   @param op              CeedOperator
4067a982d89SJeremy L. Thompson   @param[out] numelem    Variable to store number of elements
4077a982d89SJeremy L. Thompson 
4087a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
4097a982d89SJeremy L. Thompson 
4107a982d89SJeremy L. Thompson   @ref Backend
4117a982d89SJeremy L. Thompson **/
4127a982d89SJeremy L. Thompson 
4137a982d89SJeremy L. Thompson int CeedOperatorGetNumElements(CeedOperator op, CeedInt *numelem) {
4147a982d89SJeremy L. Thompson   if (op->composite)
4157a982d89SJeremy L. Thompson     // LCOV_EXCL_START
4167a982d89SJeremy L. Thompson     return CeedError(op->ceed, 1, "Not defined for composite operator");
4177a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
4187a982d89SJeremy L. Thompson 
4197a982d89SJeremy L. Thompson   *numelem = op->numelements;
4207a982d89SJeremy L. Thompson   return 0;
4217a982d89SJeremy L. Thompson }
4227a982d89SJeremy L. Thompson 
4237a982d89SJeremy L. Thompson /**
4247a982d89SJeremy L. Thompson   @brief Get the number of quadrature points associated with a CeedOperator
4257a982d89SJeremy L. Thompson 
4267a982d89SJeremy L. Thompson   @param op              CeedOperator
4277a982d89SJeremy L. Thompson   @param[out] numqpts    Variable to store vector number of quadrature points
4287a982d89SJeremy L. Thompson 
4297a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
4307a982d89SJeremy L. Thompson 
4317a982d89SJeremy L. Thompson   @ref Backend
4327a982d89SJeremy L. Thompson **/
4337a982d89SJeremy L. Thompson 
4347a982d89SJeremy L. Thompson int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *numqpts) {
4357a982d89SJeremy L. Thompson   if (op->composite)
4367a982d89SJeremy L. Thompson     // LCOV_EXCL_START
4377a982d89SJeremy L. Thompson     return CeedError(op->ceed, 1, "Not defined for composite operator");
4387a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
4397a982d89SJeremy L. Thompson 
4407a982d89SJeremy L. Thompson   *numqpts = op->numqpoints;
4417a982d89SJeremy L. Thompson   return 0;
4427a982d89SJeremy L. Thompson }
4437a982d89SJeremy L. Thompson 
4447a982d89SJeremy L. Thompson /**
4457a982d89SJeremy L. Thompson   @brief Get the number of arguments associated with a CeedOperator
4467a982d89SJeremy L. Thompson 
4477a982d89SJeremy L. Thompson   @param op              CeedOperator
4487a982d89SJeremy L. Thompson   @param[out] numargs    Variable to store vector number of arguments
4497a982d89SJeremy L. Thompson 
4507a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
4517a982d89SJeremy L. Thompson 
4527a982d89SJeremy L. Thompson   @ref Backend
4537a982d89SJeremy L. Thompson **/
4547a982d89SJeremy L. Thompson 
4557a982d89SJeremy L. Thompson int CeedOperatorGetNumArgs(CeedOperator op, CeedInt *numargs) {
4567a982d89SJeremy L. Thompson   if (op->composite)
4577a982d89SJeremy L. Thompson     // LCOV_EXCL_START
4587a982d89SJeremy L. Thompson     return CeedError(op->ceed, 1, "Not defined for composite operators");
4597a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
4607a982d89SJeremy L. Thompson 
4617a982d89SJeremy L. Thompson   *numargs = op->nfields;
4627a982d89SJeremy L. Thompson   return 0;
4637a982d89SJeremy L. Thompson }
4647a982d89SJeremy L. Thompson 
4657a982d89SJeremy L. Thompson /**
4667a982d89SJeremy L. Thompson   @brief Get the setup status of a CeedOperator
4677a982d89SJeremy L. Thompson 
4687a982d89SJeremy L. Thompson   @param op                CeedOperator
469fd364f38SJeremy L Thompson   @param[out] issetupdone  Variable to store setup status
4707a982d89SJeremy L. Thompson 
4717a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
4727a982d89SJeremy L. Thompson 
4737a982d89SJeremy L. Thompson   @ref Backend
4747a982d89SJeremy L. Thompson **/
4757a982d89SJeremy L. Thompson 
476fd364f38SJeremy L Thompson int CeedOperatorIsSetupDone(CeedOperator op, bool *issetupdone) {
477fd364f38SJeremy L Thompson   *issetupdone = op->setupdone;
4787a982d89SJeremy L. Thompson   return 0;
4797a982d89SJeremy L. Thompson }
4807a982d89SJeremy L. Thompson 
4817a982d89SJeremy L. Thompson /**
4827a982d89SJeremy L. Thompson   @brief Get the QFunction associated with a CeedOperator
4837a982d89SJeremy L. Thompson 
4847a982d89SJeremy L. Thompson   @param op              CeedOperator
4857a982d89SJeremy L. Thompson   @param[out] qf         Variable to store QFunction
4867a982d89SJeremy L. Thompson 
4877a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
4887a982d89SJeremy L. Thompson 
4897a982d89SJeremy L. Thompson   @ref Backend
4907a982d89SJeremy L. Thompson **/
4917a982d89SJeremy L. Thompson 
4927a982d89SJeremy L. Thompson int CeedOperatorGetQFunction(CeedOperator op, CeedQFunction *qf) {
4937a982d89SJeremy L. Thompson   if (op->composite)
4947a982d89SJeremy L. Thompson     // LCOV_EXCL_START
4957a982d89SJeremy L. Thompson     return CeedError(op->ceed, 1, "Not defined for composite operator");
4967a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
4977a982d89SJeremy L. Thompson 
4987a982d89SJeremy L. Thompson   *qf = op->qf;
4997a982d89SJeremy L. Thompson   return 0;
5007a982d89SJeremy L. Thompson }
5017a982d89SJeremy L. Thompson 
5027a982d89SJeremy L. Thompson /**
503c04a41a7SJeremy L Thompson   @brief Get a boolean value indicating if the CeedOperator is composite
504c04a41a7SJeremy L Thompson 
505c04a41a7SJeremy L Thompson   @param op                CeedOperator
506fd364f38SJeremy L Thompson   @param[out] iscomposite  Variable to store composite status
507c04a41a7SJeremy L Thompson 
508c04a41a7SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
509c04a41a7SJeremy L Thompson 
510c04a41a7SJeremy L Thompson   @ref Backend
511c04a41a7SJeremy L Thompson **/
512c04a41a7SJeremy L Thompson 
513fd364f38SJeremy L Thompson int CeedOperatorIsComposite(CeedOperator op, bool *iscomposite) {
514fd364f38SJeremy L Thompson   *iscomposite = op->composite;
515c04a41a7SJeremy L Thompson   return 0;
516c04a41a7SJeremy L Thompson }
517c04a41a7SJeremy L Thompson 
518c04a41a7SJeremy L Thompson /**
5197a982d89SJeremy L. Thompson   @brief Get the number of suboperators associated with a CeedOperator
5207a982d89SJeremy L. Thompson 
5217a982d89SJeremy L. Thompson   @param op              CeedOperator
5227a982d89SJeremy L. Thompson   @param[out] numsub     Variable to store number of suboperators
5237a982d89SJeremy L. Thompson 
5247a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5257a982d89SJeremy L. Thompson 
5267a982d89SJeremy L. Thompson   @ref Backend
5277a982d89SJeremy L. Thompson **/
5287a982d89SJeremy L. Thompson 
5297a982d89SJeremy L. Thompson int CeedOperatorGetNumSub(CeedOperator op, CeedInt *numsub) {
5307a982d89SJeremy L. Thompson   if (!op->composite)
5317a982d89SJeremy L. Thompson     // LCOV_EXCL_START
5327a982d89SJeremy L. Thompson     return CeedError(op->ceed, 1, "Not a composite operator");
5337a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
5347a982d89SJeremy L. Thompson 
5357a982d89SJeremy L. Thompson   *numsub = op->numsub;
5367a982d89SJeremy L. Thompson   return 0;
5377a982d89SJeremy L. Thompson }
5387a982d89SJeremy L. Thompson 
5397a982d89SJeremy L. Thompson /**
5407a982d89SJeremy L. Thompson   @brief Get the list of suboperators associated with a CeedOperator
5417a982d89SJeremy L. Thompson 
5427a982d89SJeremy L. Thompson   @param op                CeedOperator
5437a982d89SJeremy L. Thompson   @param[out] suboperators Variable to store list of suboperators
5447a982d89SJeremy L. Thompson 
5457a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5467a982d89SJeremy L. Thompson 
5477a982d89SJeremy L. Thompson   @ref Backend
5487a982d89SJeremy L. Thompson **/
5497a982d89SJeremy L. Thompson 
5507a982d89SJeremy L. Thompson int CeedOperatorGetSubList(CeedOperator op, CeedOperator **suboperators) {
5517a982d89SJeremy L. Thompson   if (!op->composite)
5527a982d89SJeremy L. Thompson     // LCOV_EXCL_START
5537a982d89SJeremy L. Thompson     return CeedError(op->ceed, 1, "Not a composite operator");
5547a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
5557a982d89SJeremy L. Thompson 
5567a982d89SJeremy L. Thompson   *suboperators = op->suboperators;
5577a982d89SJeremy L. Thompson   return 0;
5587a982d89SJeremy L. Thompson }
5597a982d89SJeremy L. Thompson 
5607a982d89SJeremy L. Thompson /**
5617a982d89SJeremy L. Thompson   @brief Get the backend data of a CeedOperator
5627a982d89SJeremy L. Thompson 
5637a982d89SJeremy L. Thompson   @param op              CeedOperator
5647a982d89SJeremy L. Thompson   @param[out] data       Variable to store data
5657a982d89SJeremy L. Thompson 
5667a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5677a982d89SJeremy L. Thompson 
5687a982d89SJeremy L. Thompson   @ref Backend
5697a982d89SJeremy L. Thompson **/
5707a982d89SJeremy L. Thompson 
5717a982d89SJeremy L. Thompson int CeedOperatorGetData(CeedOperator op, void **data) {
5727a982d89SJeremy L. Thompson   *data = op->data;
5737a982d89SJeremy L. Thompson   return 0;
5747a982d89SJeremy L. Thompson }
5757a982d89SJeremy L. Thompson 
5767a982d89SJeremy L. Thompson /**
5777a982d89SJeremy L. Thompson   @brief Set the backend data of a CeedOperator
5787a982d89SJeremy L. Thompson 
5797a982d89SJeremy L. Thompson   @param[out] op         CeedOperator
5807a982d89SJeremy L. Thompson   @param data            Data to set
5817a982d89SJeremy L. Thompson 
5827a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5837a982d89SJeremy L. Thompson 
5847a982d89SJeremy L. Thompson   @ref Backend
5857a982d89SJeremy L. Thompson **/
5867a982d89SJeremy L. Thompson 
5877a982d89SJeremy L. Thompson int CeedOperatorSetData(CeedOperator op, void **data) {
5887a982d89SJeremy L. Thompson   op->data = *data;
5897a982d89SJeremy L. Thompson   return 0;
5907a982d89SJeremy L. Thompson }
5917a982d89SJeremy L. Thompson 
5927a982d89SJeremy L. Thompson /**
5937a982d89SJeremy L. Thompson   @brief Set the setup flag of a CeedOperator to True
5947a982d89SJeremy L. Thompson 
5957a982d89SJeremy L. Thompson   @param op              CeedOperator
5967a982d89SJeremy L. Thompson 
5977a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5987a982d89SJeremy L. Thompson 
5997a982d89SJeremy L. Thompson   @ref Backend
6007a982d89SJeremy L. Thompson **/
6017a982d89SJeremy L. Thompson 
6027a982d89SJeremy L. Thompson int CeedOperatorSetSetupDone(CeedOperator op) {
6037a982d89SJeremy L. Thompson   op->setupdone = 1;
6047a982d89SJeremy L. Thompson   return 0;
6057a982d89SJeremy L. Thompson }
6067a982d89SJeremy L. Thompson 
6077a982d89SJeremy L. Thompson /**
6087a982d89SJeremy L. Thompson   @brief Get the CeedOperatorFields of a CeedOperator
6097a982d89SJeremy L. Thompson 
6107a982d89SJeremy L. Thompson   @param op                 CeedOperator
6117a982d89SJeremy L. Thompson   @param[out] inputfields   Variable to store inputfields
6127a982d89SJeremy L. Thompson   @param[out] outputfields  Variable to store outputfields
6137a982d89SJeremy L. Thompson 
6147a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6157a982d89SJeremy L. Thompson 
6167a982d89SJeremy L. Thompson   @ref Backend
6177a982d89SJeremy L. Thompson **/
6187a982d89SJeremy L. Thompson 
6197a982d89SJeremy L. Thompson int CeedOperatorGetFields(CeedOperator op, CeedOperatorField **inputfields,
6207a982d89SJeremy L. Thompson                           CeedOperatorField **outputfields) {
6217a982d89SJeremy L. Thompson   if (op->composite)
6227a982d89SJeremy L. Thompson     // LCOV_EXCL_START
6237a982d89SJeremy L. Thompson     return CeedError(op->ceed, 1, "Not defined for composite operator");
6247a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
6257a982d89SJeremy L. Thompson 
6267a982d89SJeremy L. Thompson   if (inputfields) *inputfields = op->inputfields;
6277a982d89SJeremy L. Thompson   if (outputfields) *outputfields = op->outputfields;
6287a982d89SJeremy L. Thompson   return 0;
6297a982d89SJeremy L. Thompson }
6307a982d89SJeremy L. Thompson 
6317a982d89SJeremy L. Thompson /**
6327a982d89SJeremy L. Thompson   @brief Get the CeedElemRestriction of a CeedOperatorField
6337a982d89SJeremy L. Thompson 
6347a982d89SJeremy L. Thompson   @param opfield         CeedOperatorField
6357a982d89SJeremy L. Thompson   @param[out] rstr       Variable to store CeedElemRestriction
6367a982d89SJeremy L. Thompson 
6377a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6387a982d89SJeremy L. Thompson 
6397a982d89SJeremy L. Thompson   @ref Backend
6407a982d89SJeremy L. Thompson **/
6417a982d89SJeremy L. Thompson 
6427a982d89SJeremy L. Thompson int CeedOperatorFieldGetElemRestriction(CeedOperatorField opfield,
6437a982d89SJeremy L. Thompson                                         CeedElemRestriction *rstr) {
6447a982d89SJeremy L. Thompson   *rstr = opfield->Erestrict;
6457a982d89SJeremy L. Thompson   return 0;
6467a982d89SJeremy L. Thompson }
6477a982d89SJeremy L. Thompson 
6487a982d89SJeremy L. Thompson /**
6497a982d89SJeremy L. Thompson   @brief Get the CeedBasis of a CeedOperatorField
6507a982d89SJeremy L. Thompson 
6517a982d89SJeremy L. Thompson   @param opfield         CeedOperatorField
6527a982d89SJeremy L. Thompson   @param[out] basis      Variable to store CeedBasis
6537a982d89SJeremy L. Thompson 
6547a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6557a982d89SJeremy L. Thompson 
6567a982d89SJeremy L. Thompson   @ref Backend
6577a982d89SJeremy L. Thompson **/
6587a982d89SJeremy L. Thompson 
6597a982d89SJeremy L. Thompson int CeedOperatorFieldGetBasis(CeedOperatorField opfield, CeedBasis *basis) {
6607a982d89SJeremy L. Thompson   *basis = opfield->basis;
6617a982d89SJeremy L. Thompson   return 0;
6627a982d89SJeremy L. Thompson }
6637a982d89SJeremy L. Thompson 
6647a982d89SJeremy L. Thompson /**
6657a982d89SJeremy L. Thompson   @brief Get the CeedVector of a CeedOperatorField
6667a982d89SJeremy L. Thompson 
6677a982d89SJeremy L. Thompson   @param opfield         CeedOperatorField
6687a982d89SJeremy L. Thompson   @param[out] vec        Variable to store CeedVector
6697a982d89SJeremy L. Thompson 
6707a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6717a982d89SJeremy L. Thompson 
6727a982d89SJeremy L. Thompson   @ref Backend
6737a982d89SJeremy L. Thompson **/
6747a982d89SJeremy L. Thompson 
6757a982d89SJeremy L. Thompson int CeedOperatorFieldGetVector(CeedOperatorField opfield, CeedVector *vec) {
6767a982d89SJeremy L. Thompson   *vec = opfield->vec;
6777a982d89SJeremy L. Thompson   return 0;
6787a982d89SJeremy L. Thompson }
6797a982d89SJeremy L. Thompson 
6807a982d89SJeremy L. Thompson /// @}
6817a982d89SJeremy L. Thompson 
6827a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
6837a982d89SJeremy L. Thompson /// CeedOperator Public API
6847a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
6857a982d89SJeremy L. Thompson /// @addtogroup CeedOperatorUser
686dfdf5a53Sjeremylt /// @{
687d7b241e6Sjeremylt 
688d7b241e6Sjeremylt /**
6890219ea01SJeremy L Thompson   @brief Create a CeedOperator and associate a CeedQFunction. A CeedBasis and
6900219ea01SJeremy L Thompson            CeedElemRestriction can be associated with CeedQFunction fields with
6910219ea01SJeremy L Thompson            \ref CeedOperatorSetField.
692d7b241e6Sjeremylt 
693b11c1e72Sjeremylt   @param ceed    A Ceed object where the CeedOperator will be created
694d7b241e6Sjeremylt   @param qf      QFunction defining the action of the operator at quadrature points
69534138859Sjeremylt   @param dqf     QFunction defining the action of the Jacobian of @a qf (or
6964cc79fe7SJed Brown                    @ref CEED_QFUNCTION_NONE)
697d7b241e6Sjeremylt   @param dqfT    QFunction defining the action of the transpose of the Jacobian
6984cc79fe7SJed Brown                    of @a qf (or @ref CEED_QFUNCTION_NONE)
699b11c1e72Sjeremylt   @param[out] op Address of the variable where the newly created
700b11c1e72Sjeremylt                      CeedOperator will be stored
701b11c1e72Sjeremylt 
702b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
703dfdf5a53Sjeremylt 
7047a982d89SJeremy L. Thompson   @ref User
705d7b241e6Sjeremylt  */
706d7b241e6Sjeremylt int CeedOperatorCreate(Ceed ceed, CeedQFunction qf, CeedQFunction dqf,
707d7b241e6Sjeremylt                        CeedQFunction dqfT, CeedOperator *op) {
708d7b241e6Sjeremylt   int ierr;
709d7b241e6Sjeremylt 
7105fe0d4faSjeremylt   if (!ceed->OperatorCreate) {
7115fe0d4faSjeremylt     Ceed delegate;
712aefd8378Sjeremylt     ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr);
7135fe0d4faSjeremylt 
7145fe0d4faSjeremylt     if (!delegate)
715c042f62fSJeremy L Thompson       // LCOV_EXCL_START
7165fe0d4faSjeremylt       return CeedError(ceed, 1, "Backend does not support OperatorCreate");
717c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
7185fe0d4faSjeremylt 
7195fe0d4faSjeremylt     ierr = CeedOperatorCreate(delegate, qf, dqf, dqfT, op); CeedChk(ierr);
7205fe0d4faSjeremylt     return 0;
7215fe0d4faSjeremylt   }
7225fe0d4faSjeremylt 
723b3b7035fSJeremy L Thompson   if (!qf || qf == CEED_QFUNCTION_NONE)
724b3b7035fSJeremy L Thompson     // LCOV_EXCL_START
725b3b7035fSJeremy L Thompson     return CeedError(ceed, 1, "Operator must have a valid QFunction.");
726b3b7035fSJeremy L Thompson   // LCOV_EXCL_STOP
727d7b241e6Sjeremylt   ierr = CeedCalloc(1, op); CeedChk(ierr);
728d7b241e6Sjeremylt   (*op)->ceed = ceed;
729d7b241e6Sjeremylt   ceed->refcount++;
730d7b241e6Sjeremylt   (*op)->refcount = 1;
731d7b241e6Sjeremylt   (*op)->qf = qf;
732d7b241e6Sjeremylt   qf->refcount++;
733442e7f0bSjeremylt   if (dqf && dqf != CEED_QFUNCTION_NONE) {
734d7b241e6Sjeremylt     (*op)->dqf = dqf;
735442e7f0bSjeremylt     dqf->refcount++;
736442e7f0bSjeremylt   }
737442e7f0bSjeremylt   if (dqfT && dqfT != CEED_QFUNCTION_NONE) {
738d7b241e6Sjeremylt     (*op)->dqfT = dqfT;
739442e7f0bSjeremylt     dqfT->refcount++;
740442e7f0bSjeremylt   }
741fe2413ffSjeremylt   ierr = CeedCalloc(16, &(*op)->inputfields); CeedChk(ierr);
742fe2413ffSjeremylt   ierr = CeedCalloc(16, &(*op)->outputfields); CeedChk(ierr);
743d7b241e6Sjeremylt   ierr = ceed->OperatorCreate(*op); CeedChk(ierr);
744d7b241e6Sjeremylt   return 0;
745d7b241e6Sjeremylt }
746d7b241e6Sjeremylt 
747d7b241e6Sjeremylt /**
74852d6035fSJeremy L Thompson   @brief Create an operator that composes the action of several operators
74952d6035fSJeremy L Thompson 
75052d6035fSJeremy L Thompson   @param ceed    A Ceed object where the CeedOperator will be created
75152d6035fSJeremy L Thompson   @param[out] op Address of the variable where the newly created
75252d6035fSJeremy L Thompson                      Composite CeedOperator will be stored
75352d6035fSJeremy L Thompson 
75452d6035fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
75552d6035fSJeremy L Thompson 
7567a982d89SJeremy L. Thompson   @ref User
75752d6035fSJeremy L Thompson  */
75852d6035fSJeremy L Thompson int CeedCompositeOperatorCreate(Ceed ceed, CeedOperator *op) {
75952d6035fSJeremy L Thompson   int ierr;
76052d6035fSJeremy L Thompson 
76152d6035fSJeremy L Thompson   if (!ceed->CompositeOperatorCreate) {
76252d6035fSJeremy L Thompson     Ceed delegate;
763aefd8378Sjeremylt     ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr);
76452d6035fSJeremy L Thompson 
765250756a7Sjeremylt     if (delegate) {
76652d6035fSJeremy L Thompson       ierr = CeedCompositeOperatorCreate(delegate, op); CeedChk(ierr);
76752d6035fSJeremy L Thompson       return 0;
76852d6035fSJeremy L Thompson     }
769250756a7Sjeremylt   }
77052d6035fSJeremy L Thompson 
77152d6035fSJeremy L Thompson   ierr = CeedCalloc(1, op); CeedChk(ierr);
77252d6035fSJeremy L Thompson   (*op)->ceed = ceed;
77352d6035fSJeremy L Thompson   ceed->refcount++;
77452d6035fSJeremy L Thompson   (*op)->composite = true;
77552d6035fSJeremy L Thompson   ierr = CeedCalloc(16, &(*op)->suboperators); CeedChk(ierr);
776250756a7Sjeremylt 
777250756a7Sjeremylt   if (ceed->CompositeOperatorCreate) {
77852d6035fSJeremy L Thompson     ierr = ceed->CompositeOperatorCreate(*op); CeedChk(ierr);
779250756a7Sjeremylt   }
78052d6035fSJeremy L Thompson   return 0;
78152d6035fSJeremy L Thompson }
78252d6035fSJeremy L Thompson 
78352d6035fSJeremy L Thompson /**
784b11c1e72Sjeremylt   @brief Provide a field to a CeedOperator for use by its CeedQFunction
785d7b241e6Sjeremylt 
786d7b241e6Sjeremylt   This function is used to specify both active and passive fields to a
787d7b241e6Sjeremylt   CeedOperator.  For passive fields, a vector @arg v must be provided.  Passive
788d7b241e6Sjeremylt   fields can inputs or outputs (updated in-place when operator is applied).
789d7b241e6Sjeremylt 
790d7b241e6Sjeremylt   Active fields must be specified using this function, but their data (in a
791d7b241e6Sjeremylt   CeedVector) is passed in CeedOperatorApply().  There can be at most one active
792d7b241e6Sjeremylt   input and at most one active output.
793d7b241e6Sjeremylt 
7948c91a0c9SJeremy L Thompson   @param op         CeedOperator on which to provide the field
7958795c945Sjeremylt   @param fieldname  Name of the field (to be matched with the name used by
7968795c945Sjeremylt                       CeedQFunction)
797b11c1e72Sjeremylt   @param r          CeedElemRestriction
7984cc79fe7SJed Brown   @param b          CeedBasis in which the field resides or @ref CEED_BASIS_COLLOCATED
799b11c1e72Sjeremylt                       if collocated with quadrature points
8004cc79fe7SJed Brown   @param v          CeedVector to be used by CeedOperator or @ref CEED_VECTOR_ACTIVE
8014cc79fe7SJed Brown                       if field is active or @ref CEED_VECTOR_NONE if using
8024cc79fe7SJed Brown                       @ref CEED_EVAL_WEIGHT in the QFunction
803b11c1e72Sjeremylt 
804b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
805dfdf5a53Sjeremylt 
8067a982d89SJeremy L. Thompson   @ref User
807b11c1e72Sjeremylt **/
808d7b241e6Sjeremylt int CeedOperatorSetField(CeedOperator op, const char *fieldname,
809a8d32208Sjeremylt                          CeedElemRestriction r, CeedBasis b, CeedVector v) {
810d7b241e6Sjeremylt   int ierr;
81152d6035fSJeremy L Thompson   if (op->composite)
812c042f62fSJeremy L Thompson     // LCOV_EXCL_START
81352d6035fSJeremy L Thompson     return CeedError(op->ceed, 1, "Cannot add field to composite operator.");
814c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
8158b067b84SJed Brown   if (!r)
816c042f62fSJeremy L Thompson     // LCOV_EXCL_START
817c042f62fSJeremy L Thompson     return CeedError(op->ceed, 1,
818c042f62fSJeremy L Thompson                      "ElemRestriction r for field \"%s\" must be non-NULL.",
819c042f62fSJeremy L Thompson                      fieldname);
820c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
8218b067b84SJed Brown   if (!b)
822c042f62fSJeremy L Thompson     // LCOV_EXCL_START
823c042f62fSJeremy L Thompson     return CeedError(op->ceed, 1, "Basis b for field \"%s\" must be non-NULL.",
824c042f62fSJeremy L Thompson                      fieldname);
825c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
8268b067b84SJed Brown   if (!v)
827c042f62fSJeremy L Thompson     // LCOV_EXCL_START
828c042f62fSJeremy L Thompson     return CeedError(op->ceed, 1, "Vector v for field \"%s\" must be non-NULL.",
829c042f62fSJeremy L Thompson                      fieldname);
830c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
83152d6035fSJeremy L Thompson 
832d7b241e6Sjeremylt   CeedInt numelements;
833d7b241e6Sjeremylt   ierr = CeedElemRestrictionGetNumElements(r, &numelements); CeedChk(ierr);
83415910d16Sjeremylt   if (r != CEED_ELEMRESTRICTION_NONE && op->hasrestriction &&
83515910d16Sjeremylt       op->numelements != numelements)
836c042f62fSJeremy L Thompson     // LCOV_EXCL_START
837d7b241e6Sjeremylt     return CeedError(op->ceed, 1,
8381d102b48SJeremy L Thompson                      "ElemRestriction with %d elements incompatible with prior "
8391d102b48SJeremy L Thompson                      "%d elements", numelements, op->numelements);
840c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
84115910d16Sjeremylt   if (r != CEED_ELEMRESTRICTION_NONE) {
842d7b241e6Sjeremylt     op->numelements = numelements;
8432cb0afc5Sjeremylt     op->hasrestriction = true; // Restriction set, but numelements may be 0
84415910d16Sjeremylt   }
845d7b241e6Sjeremylt 
846783c99b3SValeria Barra   if (b != CEED_BASIS_COLLOCATED) {
847d7b241e6Sjeremylt     CeedInt numqpoints;
848d7b241e6Sjeremylt     ierr = CeedBasisGetNumQuadraturePoints(b, &numqpoints); CeedChk(ierr);
849d7b241e6Sjeremylt     if (op->numqpoints && op->numqpoints != numqpoints)
850c042f62fSJeremy L Thompson       // LCOV_EXCL_START
8511d102b48SJeremy L Thompson       return CeedError(op->ceed, 1, "Basis with %d quadrature points "
8521d102b48SJeremy L Thompson                        "incompatible with prior %d points", numqpoints,
8531d102b48SJeremy L Thompson                        op->numqpoints);
854c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
855d7b241e6Sjeremylt     op->numqpoints = numqpoints;
856d7b241e6Sjeremylt   }
85715910d16Sjeremylt   CeedQFunctionField qfield;
858d1bcdac9Sjeremylt   CeedOperatorField *ofield;
859d7b241e6Sjeremylt   for (CeedInt i=0; i<op->qf->numinputfields; i++) {
860fe2413ffSjeremylt     if (!strcmp(fieldname, (*op->qf->inputfields[i]).fieldname)) {
86115910d16Sjeremylt       qfield = op->qf->inputfields[i];
862d7b241e6Sjeremylt       ofield = &op->inputfields[i];
863d7b241e6Sjeremylt       goto found;
864d7b241e6Sjeremylt     }
865d7b241e6Sjeremylt   }
866d7b241e6Sjeremylt   for (CeedInt i=0; i<op->qf->numoutputfields; i++) {
867fe2413ffSjeremylt     if (!strcmp(fieldname, (*op->qf->outputfields[i]).fieldname)) {
86815910d16Sjeremylt       qfield = op->qf->inputfields[i];
869d7b241e6Sjeremylt       ofield = &op->outputfields[i];
870d7b241e6Sjeremylt       goto found;
871d7b241e6Sjeremylt     }
872d7b241e6Sjeremylt   }
873c042f62fSJeremy L Thompson   // LCOV_EXCL_START
874d7b241e6Sjeremylt   return CeedError(op->ceed, 1, "QFunction has no knowledge of field '%s'",
875d7b241e6Sjeremylt                    fieldname);
876c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
877d7b241e6Sjeremylt found:
87815910d16Sjeremylt   if (r == CEED_ELEMRESTRICTION_NONE && qfield->emode != CEED_EVAL_WEIGHT)
879b0d62198Sjeremylt     // LCOV_EXCL_START
88015910d16Sjeremylt     return CeedError(op->ceed, 1, "CEED_ELEMRESTRICTION_NONE can only be used "
88115910d16Sjeremylt                      "for a field with eval mode CEED_EVAL_WEIGHT");
882b0d62198Sjeremylt   // LCOV_EXCL_STOP
883fe2413ffSjeremylt   ierr = CeedCalloc(1, ofield); CeedChk(ierr);
884fe2413ffSjeremylt   (*ofield)->Erestrict = r;
88571352a93Sjeremylt   r->refcount += 1;
886fe2413ffSjeremylt   (*ofield)->basis = b;
88771352a93Sjeremylt   if (b != CEED_BASIS_COLLOCATED)
88871352a93Sjeremylt     b->refcount += 1;
889fe2413ffSjeremylt   (*ofield)->vec = v;
89071352a93Sjeremylt   if (v != CEED_VECTOR_ACTIVE && v != CEED_VECTOR_NONE)
89171352a93Sjeremylt     v->refcount += 1;
892d7b241e6Sjeremylt   op->nfields += 1;
893*d99fa3c5SJeremy L Thompson 
894*d99fa3c5SJeremy L Thompson   size_t len = strlen(fieldname);
895*d99fa3c5SJeremy L Thompson   char *tmp;
896*d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(len+1, &tmp); CeedChk(ierr);
897*d99fa3c5SJeremy L Thompson   memcpy(tmp, fieldname, len+1);
898*d99fa3c5SJeremy L Thompson   (*ofield)->fieldname = tmp;
899d7b241e6Sjeremylt   return 0;
900d7b241e6Sjeremylt }
901d7b241e6Sjeremylt 
902d7b241e6Sjeremylt /**
90352d6035fSJeremy L Thompson   @brief Add a sub-operator to a composite CeedOperator
904288c0443SJeremy L Thompson 
90534138859Sjeremylt   @param[out] compositeop Composite CeedOperator
90634138859Sjeremylt   @param      subop       Sub-operator CeedOperator
90752d6035fSJeremy L Thompson 
90852d6035fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
90952d6035fSJeremy L Thompson 
9107a982d89SJeremy L. Thompson   @ref User
91152d6035fSJeremy L Thompson  */
912692c2638Sjeremylt int CeedCompositeOperatorAddSub(CeedOperator compositeop, CeedOperator subop) {
91352d6035fSJeremy L Thompson   if (!compositeop->composite)
914c042f62fSJeremy L Thompson     // LCOV_EXCL_START
9151d102b48SJeremy L Thompson     return CeedError(compositeop->ceed, 1, "CeedOperator is not a composite "
9161d102b48SJeremy L Thompson                      "operator");
917c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
91852d6035fSJeremy L Thompson 
91952d6035fSJeremy L Thompson   if (compositeop->numsub == CEED_COMPOSITE_MAX)
920c042f62fSJeremy L Thompson     // LCOV_EXCL_START
9211d102b48SJeremy L Thompson     return CeedError(compositeop->ceed, 1, "Cannot add additional suboperators");
922c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
92352d6035fSJeremy L Thompson 
92452d6035fSJeremy L Thompson   compositeop->suboperators[compositeop->numsub] = subop;
92552d6035fSJeremy L Thompson   subop->refcount++;
92652d6035fSJeremy L Thompson   compositeop->numsub++;
92752d6035fSJeremy L Thompson   return 0;
92852d6035fSJeremy L Thompson }
92952d6035fSJeremy L Thompson 
93052d6035fSJeremy L Thompson /**
9311d102b48SJeremy L Thompson   @brief Assemble a linear CeedQFunction associated with a CeedOperator
9321d102b48SJeremy L Thompson 
9331d102b48SJeremy L Thompson   This returns a CeedVector containing a matrix at each quadrature point
9341d102b48SJeremy L Thompson     providing the action of the CeedQFunction associated with the CeedOperator.
9351d102b48SJeremy L Thompson     The vector 'assembled' is of shape
9361d102b48SJeremy L Thompson       [num_elements, num_input_fields, num_output_fields, num_quad_points]
9371d102b48SJeremy L Thompson     and contains column-major matrices representing the action of the
9381d102b48SJeremy L Thompson     CeedQFunction for a corresponding quadrature point on an element. Inputs and
9391d102b48SJeremy L Thompson     outputs are in the order provided by the user when adding CeedOperator fields.
9404cc79fe7SJed Brown     For example, a CeedQFunction with inputs 'u' and 'gradu' and outputs 'gradv' and
9411d102b48SJeremy L Thompson     'v', provided in that order, would result in an assembled QFunction that
9421d102b48SJeremy L Thompson     consists of (1 + dim) x (dim + 1) matrices at each quadrature point acting
9431d102b48SJeremy L Thompson     on the input [u, du_0, du_1] and producing the output [dv_0, dv_1, v].
9441d102b48SJeremy L Thompson 
9451d102b48SJeremy L Thompson   @param op             CeedOperator to assemble CeedQFunction
9461d102b48SJeremy L Thompson   @param[out] assembled CeedVector to store assembled CeedQFunction at
9471d102b48SJeremy L Thompson                           quadrature points
9481d102b48SJeremy L Thompson   @param[out] rstr      CeedElemRestriction for CeedVector containing assembled
9491d102b48SJeremy L Thompson                           CeedQFunction
9501d102b48SJeremy L Thompson   @param request        Address of CeedRequest for non-blocking completion, else
9514cc79fe7SJed Brown                           @ref CEED_REQUEST_IMMEDIATE
9521d102b48SJeremy L Thompson 
9531d102b48SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
9541d102b48SJeremy L Thompson 
9557a982d89SJeremy L. Thompson   @ref User
9561d102b48SJeremy L Thompson **/
95780ac2e43SJeremy L Thompson int CeedOperatorLinearAssembleQFunction(CeedOperator op, CeedVector *assembled,
9587f823360Sjeremylt                                         CeedElemRestriction *rstr,
9597f823360Sjeremylt                                         CeedRequest *request) {
9601d102b48SJeremy L Thompson   int ierr;
9611d102b48SJeremy L Thompson   Ceed ceed = op->ceed;
962250756a7Sjeremylt   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
9631d102b48SJeremy L Thompson 
9647172caadSjeremylt   // Backend version
96580ac2e43SJeremy L Thompson   if (op->LinearAssembleQFunction) {
96680ac2e43SJeremy L Thompson     ierr = op->LinearAssembleQFunction(op, assembled, rstr, request);
9671d102b48SJeremy L Thompson     CeedChk(ierr);
9685107b09fSJeremy L Thompson   } else {
9695107b09fSJeremy L Thompson     // Fallback to reference Ceed
9705107b09fSJeremy L Thompson     if (!op->opfallback) {
9715107b09fSJeremy L Thompson       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
9725107b09fSJeremy L Thompson     }
9735107b09fSJeremy L Thompson     // Assemble
97480ac2e43SJeremy L Thompson     ierr = op->opfallback->LinearAssembleQFunction(op->opfallback, assembled,
9755107b09fSJeremy L Thompson            rstr, request); CeedChk(ierr);
9765107b09fSJeremy L Thompson   }
977250756a7Sjeremylt 
9781d102b48SJeremy L Thompson   return 0;
9791d102b48SJeremy L Thompson }
9801d102b48SJeremy L Thompson 
9811d102b48SJeremy L Thompson /**
982d965c7a7SJeremy L Thompson   @brief Assemble the diagonal of a square linear CeedOperator
983b7ec98d8SJeremy L Thompson 
9849e9210b8SJeremy L Thompson   This overwrites a CeedVector with the diagonal of a linear CeedOperator.
985b7ec98d8SJeremy L Thompson 
986c04a41a7SJeremy L Thompson   Note: Currently only non-composite CeedOperators with a single field and
987c04a41a7SJeremy L Thompson           composite CeedOperators with single field sub-operators are supported.
988d965c7a7SJeremy L Thompson 
989b7ec98d8SJeremy L Thompson   @param op             CeedOperator to assemble CeedQFunction
990b7ec98d8SJeremy L Thompson   @param[out] assembled CeedVector to store assembled CeedOperator diagonal
991b7ec98d8SJeremy L Thompson   @param request        Address of CeedRequest for non-blocking completion, else
9924cc79fe7SJed Brown                           @ref CEED_REQUEST_IMMEDIATE
993b7ec98d8SJeremy L Thompson 
994b7ec98d8SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
995b7ec98d8SJeremy L Thompson 
9967a982d89SJeremy L. Thompson   @ref User
997b7ec98d8SJeremy L Thompson **/
9982bba3ffaSJeremy L Thompson int CeedOperatorLinearAssembleDiagonal(CeedOperator op, CeedVector assembled,
9997f823360Sjeremylt                                        CeedRequest *request) {
1000b7ec98d8SJeremy L Thompson   int ierr;
1001b7ec98d8SJeremy L Thompson   Ceed ceed = op->ceed;
1002250756a7Sjeremylt   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
1003b7ec98d8SJeremy L Thompson 
1004b7ec98d8SJeremy L Thompson   // Use backend version, if available
100580ac2e43SJeremy L Thompson   if (op->LinearAssembleDiagonal) {
100680ac2e43SJeremy L Thompson     ierr = op->LinearAssembleDiagonal(op, assembled, request); CeedChk(ierr);
10079e9210b8SJeremy L Thompson   } else if (op->LinearAssembleAddDiagonal) {
10089e9210b8SJeremy L Thompson     ierr = CeedVectorSetValue(assembled, 0.0); CeedChk(ierr);
10099e9210b8SJeremy L Thompson     return CeedOperatorLinearAssembleAddDiagonal(op, assembled, request);
10109e9210b8SJeremy L Thompson   } else {
10119e9210b8SJeremy L Thompson     // Fallback to reference Ceed
10129e9210b8SJeremy L Thompson     if (!op->opfallback) {
10139e9210b8SJeremy L Thompson       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
10149e9210b8SJeremy L Thompson     }
10159e9210b8SJeremy L Thompson     // Assemble
10169e9210b8SJeremy L Thompson     if (op->opfallback->LinearAssembleDiagonal) {
10179e9210b8SJeremy L Thompson       ierr = op->opfallback->LinearAssembleDiagonal(op->opfallback, assembled,
10189e9210b8SJeremy L Thompson              request); CeedChk(ierr);
10199e9210b8SJeremy L Thompson     } else {
10209e9210b8SJeremy L Thompson       ierr = CeedVectorSetValue(assembled, 0.0); CeedChk(ierr);
10219e9210b8SJeremy L Thompson       return CeedOperatorLinearAssembleAddDiagonal(op, assembled, request);
10229e9210b8SJeremy L Thompson     }
10239e9210b8SJeremy L Thompson   }
10249e9210b8SJeremy L Thompson 
10259e9210b8SJeremy L Thompson   return 0;
10269e9210b8SJeremy L Thompson }
10279e9210b8SJeremy L Thompson 
10289e9210b8SJeremy L Thompson /**
10299e9210b8SJeremy L Thompson   @brief Assemble the diagonal of a square linear CeedOperator
10309e9210b8SJeremy L Thompson 
10319e9210b8SJeremy L Thompson   This sums into a CeedVector the diagonal of a linear CeedOperator.
10329e9210b8SJeremy L Thompson 
10339e9210b8SJeremy L Thompson   Note: Currently only non-composite CeedOperators with a single field and
10349e9210b8SJeremy L Thompson           composite CeedOperators with single field sub-operators are supported.
10359e9210b8SJeremy L Thompson 
10369e9210b8SJeremy L Thompson   @param op             CeedOperator to assemble CeedQFunction
10379e9210b8SJeremy L Thompson   @param[out] assembled CeedVector to store assembled CeedOperator diagonal
10389e9210b8SJeremy L Thompson   @param request        Address of CeedRequest for non-blocking completion, else
10399e9210b8SJeremy L Thompson                           @ref CEED_REQUEST_IMMEDIATE
10409e9210b8SJeremy L Thompson 
10419e9210b8SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
10429e9210b8SJeremy L Thompson 
10439e9210b8SJeremy L Thompson   @ref User
10449e9210b8SJeremy L Thompson **/
10459e9210b8SJeremy L Thompson int CeedOperatorLinearAssembleAddDiagonal(CeedOperator op, CeedVector assembled,
10469e9210b8SJeremy L Thompson     CeedRequest *request) {
10479e9210b8SJeremy L Thompson   int ierr;
10489e9210b8SJeremy L Thompson   Ceed ceed = op->ceed;
10499e9210b8SJeremy L Thompson   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
10509e9210b8SJeremy L Thompson 
10519e9210b8SJeremy L Thompson   // Use backend version, if available
10529e9210b8SJeremy L Thompson   if (op->LinearAssembleAddDiagonal) {
10539e9210b8SJeremy L Thompson     ierr = op->LinearAssembleAddDiagonal(op, assembled, request); CeedChk(ierr);
10547172caadSjeremylt   } else {
10557172caadSjeremylt     // Fallback to reference Ceed
10567172caadSjeremylt     if (!op->opfallback) {
10577172caadSjeremylt       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
1058b7ec98d8SJeremy L Thompson     }
10597172caadSjeremylt     // Assemble
10602bba3ffaSJeremy L Thompson     ierr = CeedVectorSetValue(assembled, 0.0); CeedChk(ierr);
10619e9210b8SJeremy L Thompson     ierr = op->opfallback->LinearAssembleAddDiagonal(op->opfallback, assembled,
10627172caadSjeremylt            request); CeedChk(ierr);
1063b7ec98d8SJeremy L Thompson   }
1064b7ec98d8SJeremy L Thompson 
1065b7ec98d8SJeremy L Thompson   return 0;
1066b7ec98d8SJeremy L Thompson }
1067b7ec98d8SJeremy L Thompson 
1068b7ec98d8SJeremy L Thompson /**
1069d965c7a7SJeremy L Thompson   @brief Assemble the point block diagonal of a square linear CeedOperator
1070d965c7a7SJeremy L Thompson 
10719e9210b8SJeremy L Thompson   This overwrites a CeedVector with the point block diagonal of a linear
1072d965c7a7SJeremy L Thompson     CeedOperator.
1073d965c7a7SJeremy L Thompson 
1074c04a41a7SJeremy L Thompson   Note: Currently only non-composite CeedOperators with a single field and
1075c04a41a7SJeremy L Thompson           composite CeedOperators with single field sub-operators are supported.
1076d965c7a7SJeremy L Thompson 
1077d965c7a7SJeremy L Thompson   @param op             CeedOperator to assemble CeedQFunction
1078d965c7a7SJeremy L Thompson   @param[out] assembled CeedVector to store assembled CeedOperator point block
1079d965c7a7SJeremy L Thompson                           diagonal, provided in row-major form with an
1080d965c7a7SJeremy L Thompson                           @a ncomp * @a ncomp block at each node. The dimensions
1081d965c7a7SJeremy L Thompson                           of this vector are derived from the active vector
1082d965c7a7SJeremy L Thompson                           for the CeedOperator. The array has shape
1083d965c7a7SJeremy L Thompson                           [nodes, component out, component in].
1084d965c7a7SJeremy L Thompson   @param request        Address of CeedRequest for non-blocking completion, else
1085d965c7a7SJeremy L Thompson                           CEED_REQUEST_IMMEDIATE
1086d965c7a7SJeremy L Thompson 
1087d965c7a7SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1088d965c7a7SJeremy L Thompson 
1089d965c7a7SJeremy L Thompson   @ref User
1090d965c7a7SJeremy L Thompson **/
109180ac2e43SJeremy L Thompson int CeedOperatorLinearAssemblePointBlockDiagonal(CeedOperator op,
10922bba3ffaSJeremy L Thompson     CeedVector assembled, CeedRequest *request) {
1093d965c7a7SJeremy L Thompson   int ierr;
1094d965c7a7SJeremy L Thompson   Ceed ceed = op->ceed;
1095d965c7a7SJeremy L Thompson   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
1096d965c7a7SJeremy L Thompson 
1097d965c7a7SJeremy L Thompson   // Use backend version, if available
109880ac2e43SJeremy L Thompson   if (op->LinearAssemblePointBlockDiagonal) {
109980ac2e43SJeremy L Thompson     ierr = op->LinearAssemblePointBlockDiagonal(op, assembled, request);
1100d965c7a7SJeremy L Thompson     CeedChk(ierr);
11019e9210b8SJeremy L Thompson   } else if (op->LinearAssembleAddPointBlockDiagonal) {
11029e9210b8SJeremy L Thompson     ierr = CeedVectorSetValue(assembled, 0.0); CeedChk(ierr);
11039e9210b8SJeremy L Thompson     return CeedOperatorLinearAssembleAddPointBlockDiagonal(op, assembled,
11049e9210b8SJeremy L Thompson            request);
1105d965c7a7SJeremy L Thompson   } else {
1106d965c7a7SJeremy L Thompson     // Fallback to reference Ceed
1107d965c7a7SJeremy L Thompson     if (!op->opfallback) {
1108d965c7a7SJeremy L Thompson       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
1109d965c7a7SJeremy L Thompson     }
1110d965c7a7SJeremy L Thompson     // Assemble
11119e9210b8SJeremy L Thompson     if (op->opfallback->LinearAssemblePointBlockDiagonal) {
111280ac2e43SJeremy L Thompson       ierr = op->opfallback->LinearAssemblePointBlockDiagonal(op->opfallback,
1113d965c7a7SJeremy L Thompson              assembled, request); CeedChk(ierr);
11149e9210b8SJeremy L Thompson     } else {
11159e9210b8SJeremy L Thompson       ierr = CeedVectorSetValue(assembled, 0.0); CeedChk(ierr);
11169e9210b8SJeremy L Thompson       return CeedOperatorLinearAssembleAddPointBlockDiagonal(op, assembled,
11179e9210b8SJeremy L Thompson              request);
11189e9210b8SJeremy L Thompson     }
11199e9210b8SJeremy L Thompson   }
11209e9210b8SJeremy L Thompson 
11219e9210b8SJeremy L Thompson   return 0;
11229e9210b8SJeremy L Thompson }
11239e9210b8SJeremy L Thompson 
11249e9210b8SJeremy L Thompson /**
11259e9210b8SJeremy L Thompson   @brief Assemble the point block diagonal of a square linear CeedOperator
11269e9210b8SJeremy L Thompson 
11279e9210b8SJeremy L Thompson   This sums into a CeedVector with the point block diagonal of a linear
11289e9210b8SJeremy L Thompson     CeedOperator.
11299e9210b8SJeremy L Thompson 
11309e9210b8SJeremy L Thompson   Note: Currently only non-composite CeedOperators with a single field and
11319e9210b8SJeremy L Thompson           composite CeedOperators with single field sub-operators are supported.
11329e9210b8SJeremy L Thompson 
11339e9210b8SJeremy L Thompson   @param op             CeedOperator to assemble CeedQFunction
11349e9210b8SJeremy L Thompson   @param[out] assembled CeedVector to store assembled CeedOperator point block
11359e9210b8SJeremy L Thompson                           diagonal, provided in row-major form with an
11369e9210b8SJeremy L Thompson                           @a ncomp * @a ncomp block at each node. The dimensions
11379e9210b8SJeremy L Thompson                           of this vector are derived from the active vector
11389e9210b8SJeremy L Thompson                           for the CeedOperator. The array has shape
11399e9210b8SJeremy L Thompson                           [nodes, component out, component in].
11409e9210b8SJeremy L Thompson   @param request        Address of CeedRequest for non-blocking completion, else
11419e9210b8SJeremy L Thompson                           CEED_REQUEST_IMMEDIATE
11429e9210b8SJeremy L Thompson 
11439e9210b8SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
11449e9210b8SJeremy L Thompson 
11459e9210b8SJeremy L Thompson   @ref User
11469e9210b8SJeremy L Thompson **/
11479e9210b8SJeremy L Thompson int CeedOperatorLinearAssembleAddPointBlockDiagonal(CeedOperator op,
11489e9210b8SJeremy L Thompson     CeedVector assembled, CeedRequest *request) {
11499e9210b8SJeremy L Thompson   int ierr;
11509e9210b8SJeremy L Thompson   Ceed ceed = op->ceed;
11519e9210b8SJeremy L Thompson   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
11529e9210b8SJeremy L Thompson 
11539e9210b8SJeremy L Thompson   // Use backend version, if available
11549e9210b8SJeremy L Thompson   if (op->LinearAssembleAddPointBlockDiagonal) {
11559e9210b8SJeremy L Thompson     ierr = op->LinearAssembleAddPointBlockDiagonal(op, assembled, request);
11569e9210b8SJeremy L Thompson     CeedChk(ierr);
11579e9210b8SJeremy L Thompson   } else {
11589e9210b8SJeremy L Thompson     // Fallback to reference Ceed
11599e9210b8SJeremy L Thompson     if (!op->opfallback) {
11609e9210b8SJeremy L Thompson       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
11619e9210b8SJeremy L Thompson     }
11629e9210b8SJeremy L Thompson     // Assemble
11639e9210b8SJeremy L Thompson     ierr = op->opfallback->LinearAssembleAddPointBlockDiagonal(op->opfallback,
11649e9210b8SJeremy L Thompson            assembled, request); CeedChk(ierr);
1165d965c7a7SJeremy L Thompson   }
1166d965c7a7SJeremy L Thompson 
1167d965c7a7SJeremy L Thompson   return 0;
1168d965c7a7SJeremy L Thompson }
1169d965c7a7SJeremy L Thompson 
1170d965c7a7SJeremy L Thompson /**
1171*d99fa3c5SJeremy L Thompson   @brief Create a multigrid coarse operator and level transfer operators
1172*d99fa3c5SJeremy L Thompson            for a CeedOperator, creating the prolongation basis from the
1173*d99fa3c5SJeremy L Thompson            fine and coarse grid interpolation
1174*d99fa3c5SJeremy L Thompson 
1175*d99fa3c5SJeremy L Thompson   @param[in] opFine       Fine grid operator
1176*d99fa3c5SJeremy L Thompson   @param[in] PMultFine    L-vector multiplicity in parallel gather/scatter
1177*d99fa3c5SJeremy L Thompson   @param[in] rstrCoarse   Coarse grid restriction
1178*d99fa3c5SJeremy L Thompson   @param[in] basisCoarse  Coarse grid active vector basis
1179*d99fa3c5SJeremy L Thompson   @param[out] opCoarse    Coarse grid operator
1180*d99fa3c5SJeremy L Thompson   @param[out] opProlong   Coarse to fine operator
1181*d99fa3c5SJeremy L Thompson   @param[out] opRestrict  Fine to coarse operator
1182*d99fa3c5SJeremy L Thompson 
1183*d99fa3c5SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1184*d99fa3c5SJeremy L Thompson 
1185*d99fa3c5SJeremy L Thompson   @ref User
1186*d99fa3c5SJeremy L Thompson **/
1187*d99fa3c5SJeremy L Thompson int CeedOperatorMultigridLevelCreate(CeedOperator opFine, CeedVector PMultFine,
1188*d99fa3c5SJeremy L Thompson                                      CeedElemRestriction rstrCoarse, CeedBasis basisCoarse,
1189*d99fa3c5SJeremy L Thompson                                      CeedOperator *opCoarse, CeedOperator *opProlong, CeedOperator *opRestrict) {
1190*d99fa3c5SJeremy L Thompson   int ierr;
1191*d99fa3c5SJeremy L Thompson   Ceed ceed;
1192*d99fa3c5SJeremy L Thompson   ierr = CeedOperatorGetCeed(opFine, &ceed); CeedChk(ierr);
1193*d99fa3c5SJeremy L Thompson 
1194*d99fa3c5SJeremy L Thompson   // Check for compatible quadrature spaces
1195*d99fa3c5SJeremy L Thompson   CeedBasis basisFine;
1196*d99fa3c5SJeremy L Thompson   ierr = CeedOperatorGetActiveBasis(opFine, &basisFine); CeedChk(ierr);
1197*d99fa3c5SJeremy L Thompson   CeedInt Qf, Qc;
1198*d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumQuadraturePoints(basisFine, &Qf); CeedChk(ierr);
1199*d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumQuadraturePoints(basisCoarse, &Qc); CeedChk(ierr);
1200*d99fa3c5SJeremy L Thompson   if (Qf != Qc)
1201*d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
1202*d99fa3c5SJeremy L Thompson     return CeedError(ceed, 1, "Bases must have compatible quadrature spaces");
1203*d99fa3c5SJeremy L Thompson   // LCOV_EXCL_STOP
1204*d99fa3c5SJeremy L Thompson 
1205*d99fa3c5SJeremy L Thompson   // Coarse to fine basis
1206*d99fa3c5SJeremy L Thompson   CeedInt Pf, Pc, Q = Qf;
1207*d99fa3c5SJeremy L Thompson   bool isTensorF, isTensorC;
1208*d99fa3c5SJeremy L Thompson   ierr = CeedBasisIsTensor(basisFine, &isTensorF); CeedChk(ierr);
1209*d99fa3c5SJeremy L Thompson   ierr = CeedBasisIsTensor(basisCoarse, &isTensorC); CeedChk(ierr);
1210*d99fa3c5SJeremy L Thompson   CeedScalar *interpC, *interpF, *interpCtoF, *tau;
1211*d99fa3c5SJeremy L Thompson   if (isTensorF && isTensorC) {
1212*d99fa3c5SJeremy L Thompson     ierr = CeedBasisGetNumNodes1D(basisFine, &Pf); CeedChk(ierr);
1213*d99fa3c5SJeremy L Thompson     ierr = CeedBasisGetNumNodes1D(basisCoarse, &Pc); CeedChk(ierr);
1214*d99fa3c5SJeremy L Thompson     ierr = CeedBasisGetNumQuadraturePoints1D(basisCoarse, &Q); CeedChk(ierr);
1215*d99fa3c5SJeremy L Thompson   } else if (!isTensorF && !isTensorC) {
1216*d99fa3c5SJeremy L Thompson     ierr = CeedBasisGetNumNodes(basisFine, &Pf); CeedChk(ierr);
1217*d99fa3c5SJeremy L Thompson     ierr = CeedBasisGetNumNodes(basisCoarse, &Pc); CeedChk(ierr);
1218*d99fa3c5SJeremy L Thompson   } else {
1219*d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
1220*d99fa3c5SJeremy L Thompson     return CeedError(ceed, 1, "Bases must both be tensor or non-tensor");
1221*d99fa3c5SJeremy L Thompson     // LCOV_EXCL_STOP
1222*d99fa3c5SJeremy L Thompson   }
1223*d99fa3c5SJeremy L Thompson 
1224*d99fa3c5SJeremy L Thompson   ierr = CeedMalloc(Q*Pf, &interpF); CeedChk(ierr);
1225*d99fa3c5SJeremy L Thompson   ierr = CeedMalloc(Q*Pc, &interpC); CeedChk(ierr);
1226*d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(Pc*Pf, &interpCtoF); CeedChk(ierr);
1227*d99fa3c5SJeremy L Thompson   ierr = CeedMalloc(Q, &tau); CeedChk(ierr);
1228*d99fa3c5SJeremy L Thompson   if (isTensorF) {
1229*d99fa3c5SJeremy L Thompson     memcpy(interpF, basisFine->interp1d, Q*Pf*sizeof basisFine->interp1d[0]);
1230*d99fa3c5SJeremy L Thompson     memcpy(interpC, basisCoarse->interp1d, Q*Pc*sizeof basisCoarse->interp1d[0]);
1231*d99fa3c5SJeremy L Thompson   } else {
1232*d99fa3c5SJeremy L Thompson     memcpy(interpF, basisFine->interp, Q*Pf*sizeof basisFine->interp[0]);
1233*d99fa3c5SJeremy L Thompson     memcpy(interpC, basisCoarse->interp, Q*Pc*sizeof basisCoarse->interp[0]);
1234*d99fa3c5SJeremy L Thompson   }
1235*d99fa3c5SJeremy L Thompson 
1236*d99fa3c5SJeremy L Thompson   // -- QR Factorization, interpF = Q R
1237*d99fa3c5SJeremy L Thompson   ierr = CeedQRFactorization(ceed, interpF, tau, Q, Pf); CeedChk(ierr);
1238*d99fa3c5SJeremy L Thompson 
1239*d99fa3c5SJeremy L Thompson   // -- Apply Qtranspose, interpC = Qtranspose interpC
1240*d99fa3c5SJeremy L Thompson   CeedHouseholderApplyQ(interpC, interpF, tau, CEED_TRANSPOSE,
1241*d99fa3c5SJeremy L Thompson                         Q, Pc, Pf, Pc, 1);
1242*d99fa3c5SJeremy L Thompson 
1243*d99fa3c5SJeremy L Thompson   // -- Apply Rinv, interpCtoF = Rinv interpC
1244*d99fa3c5SJeremy L Thompson   for (CeedInt j=0; j<Pc; j++) { // Column j
1245*d99fa3c5SJeremy L Thompson     interpCtoF[j+Pc*(Pf-1)] = interpC[j+Pc*(Pf-1)]/interpF[Pf*Pf-1];
1246*d99fa3c5SJeremy L Thompson     for (CeedInt i=Pf-2; i>=0; i--) { // Row i
1247*d99fa3c5SJeremy L Thompson       interpCtoF[j+Pc*i] = interpC[j+Pc*i];
1248*d99fa3c5SJeremy L Thompson       for (CeedInt k=i+1; k<Pf; k++)
1249*d99fa3c5SJeremy L Thompson         interpCtoF[j+Pc*i] -= interpF[k+Pf*i]*interpCtoF[j+Pc*k];
1250*d99fa3c5SJeremy L Thompson       interpCtoF[j+Pc*i] /= interpF[i+Pf*i];
1251*d99fa3c5SJeremy L Thompson     }
1252*d99fa3c5SJeremy L Thompson   }
1253*d99fa3c5SJeremy L Thompson   ierr = CeedFree(&tau); CeedChk(ierr);
1254*d99fa3c5SJeremy L Thompson   ierr = CeedFree(&interpC); CeedChk(ierr);
1255*d99fa3c5SJeremy L Thompson   ierr = CeedFree(&interpF); CeedChk(ierr);
1256*d99fa3c5SJeremy L Thompson 
1257*d99fa3c5SJeremy L Thompson   // Fallback to interpCtoF versions of code
1258*d99fa3c5SJeremy L Thompson   if (isTensorF) {
1259*d99fa3c5SJeremy L Thompson     ierr = CeedOperatorMultigridLevelCreateTensorH1(opFine, PMultFine,
1260*d99fa3c5SJeremy L Thompson            rstrCoarse, basisCoarse, interpCtoF, opCoarse, opProlong, opRestrict);
1261*d99fa3c5SJeremy L Thompson     CeedChk(ierr);
1262*d99fa3c5SJeremy L Thompson   } else {
1263*d99fa3c5SJeremy L Thompson     ierr = CeedOperatorMultigridLevelCreateH1(opFine, PMultFine,
1264*d99fa3c5SJeremy L Thompson            rstrCoarse, basisCoarse, interpCtoF, opCoarse, opProlong, opRestrict);
1265*d99fa3c5SJeremy L Thompson     CeedChk(ierr);
1266*d99fa3c5SJeremy L Thompson   }
1267*d99fa3c5SJeremy L Thompson 
1268*d99fa3c5SJeremy L Thompson   // Cleanup
1269*d99fa3c5SJeremy L Thompson   ierr = CeedFree(&interpCtoF); CeedChk(ierr);
1270*d99fa3c5SJeremy L Thompson   return 0;
1271*d99fa3c5SJeremy L Thompson }
1272*d99fa3c5SJeremy L Thompson 
1273*d99fa3c5SJeremy L Thompson /**
1274*d99fa3c5SJeremy L Thompson   @brief Create a multigrid coarse operator and level transfer operators
1275*d99fa3c5SJeremy L Thompson            for a CeedOperator with a tensor basis for the active basis
1276*d99fa3c5SJeremy L Thompson 
1277*d99fa3c5SJeremy L Thompson   @param[in] opFine       Fine grid operator
1278*d99fa3c5SJeremy L Thompson   @param[in] PMultFine    L-vector multiplicity in parallel gather/scatter
1279*d99fa3c5SJeremy L Thompson   @param[in] rstrCoarse   Coarse grid restriction
1280*d99fa3c5SJeremy L Thompson   @param[in] basisCoarse  Coarse grid active vector basis
1281*d99fa3c5SJeremy L Thompson   @param[in] interpCtoF   Matrix for coarse to fine interpolation
1282*d99fa3c5SJeremy L Thompson   @param[out] opCoarse    Coarse grid operator
1283*d99fa3c5SJeremy L Thompson   @param[out] opProlong   Coarse to fine operator
1284*d99fa3c5SJeremy L Thompson   @param[out] opRestrict  Fine to coarse operator
1285*d99fa3c5SJeremy L Thompson 
1286*d99fa3c5SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1287*d99fa3c5SJeremy L Thompson 
1288*d99fa3c5SJeremy L Thompson   @ref User
1289*d99fa3c5SJeremy L Thompson **/
1290*d99fa3c5SJeremy L Thompson int CeedOperatorMultigridLevelCreateTensorH1(CeedOperator opFine,
1291*d99fa3c5SJeremy L Thompson     CeedVector PMultFine, CeedElemRestriction rstrCoarse, CeedBasis basisCoarse,
1292*d99fa3c5SJeremy L Thompson     const CeedScalar *interpCtoF, CeedOperator *opCoarse,
1293*d99fa3c5SJeremy L Thompson     CeedOperator *opProlong, CeedOperator *opRestrict) {
1294*d99fa3c5SJeremy L Thompson   int ierr;
1295*d99fa3c5SJeremy L Thompson   Ceed ceed;
1296*d99fa3c5SJeremy L Thompson   ierr = CeedOperatorGetCeed(opFine, &ceed); CeedChk(ierr);
1297*d99fa3c5SJeremy L Thompson 
1298*d99fa3c5SJeremy L Thompson   // Check for compatible quadrature spaces
1299*d99fa3c5SJeremy L Thompson   CeedBasis basisFine;
1300*d99fa3c5SJeremy L Thompson   ierr = CeedOperatorGetActiveBasis(opFine, &basisFine); CeedChk(ierr);
1301*d99fa3c5SJeremy L Thompson   CeedInt Qf, Qc;
1302*d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumQuadraturePoints(basisFine, &Qf); CeedChk(ierr);
1303*d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumQuadraturePoints(basisCoarse, &Qc); CeedChk(ierr);
1304*d99fa3c5SJeremy L Thompson   if (Qf != Qc)
1305*d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
1306*d99fa3c5SJeremy L Thompson     return CeedError(ceed, 1, "Bases must have compatible quadrature spaces");
1307*d99fa3c5SJeremy L Thompson   // LCOV_EXCL_STOP
1308*d99fa3c5SJeremy L Thompson 
1309*d99fa3c5SJeremy L Thompson   // Coarse to fine basis
1310*d99fa3c5SJeremy L Thompson   CeedInt dim, ncomp, nnodesCoarse, P1dFine, P1dCoarse;
1311*d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetDimension(basisFine, &dim); CeedChk(ierr);
1312*d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumComponents(basisFine, &ncomp); CeedChk(ierr);
1313*d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumNodes1D(basisFine, &P1dFine); CeedChk(ierr);
1314*d99fa3c5SJeremy L Thompson   ierr = CeedElemRestrictionGetElementSize(rstrCoarse, &nnodesCoarse);
1315*d99fa3c5SJeremy L Thompson   CeedChk(ierr);
1316*d99fa3c5SJeremy L Thompson   P1dCoarse = dim == 1 ? nnodesCoarse :
1317*d99fa3c5SJeremy L Thompson               dim == 2 ? sqrt(nnodesCoarse) :
1318*d99fa3c5SJeremy L Thompson               cbrt(nnodesCoarse);
1319*d99fa3c5SJeremy L Thompson   CeedScalar *qref, *qweight, *grad;
1320*d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(P1dFine, &qref); CeedChk(ierr);
1321*d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(P1dFine, &qweight); CeedChk(ierr);
1322*d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(P1dFine*P1dCoarse*dim, &grad); CeedChk(ierr);
1323*d99fa3c5SJeremy L Thompson   CeedBasis basisCtoF;
1324*d99fa3c5SJeremy L Thompson   ierr = CeedBasisCreateTensorH1(ceed, dim, ncomp, P1dCoarse, P1dFine,
1325*d99fa3c5SJeremy L Thompson                                  interpCtoF, grad, qref, qweight, &basisCtoF);
1326*d99fa3c5SJeremy L Thompson   CeedChk(ierr);
1327*d99fa3c5SJeremy L Thompson   ierr = CeedFree(&qref); CeedChk(ierr);
1328*d99fa3c5SJeremy L Thompson   ierr = CeedFree(&qweight); CeedChk(ierr);
1329*d99fa3c5SJeremy L Thompson   ierr = CeedFree(&grad); CeedChk(ierr);
1330*d99fa3c5SJeremy L Thompson 
1331*d99fa3c5SJeremy L Thompson   // Core code
1332*d99fa3c5SJeremy L Thompson   ierr = CeedOperatorMultigridLevel_Core(opFine, PMultFine, rstrCoarse,
1333*d99fa3c5SJeremy L Thompson                                          basisCoarse, basisCtoF, opCoarse,
1334*d99fa3c5SJeremy L Thompson                                          opProlong, opRestrict);
1335*d99fa3c5SJeremy L Thompson   CeedChk(ierr);
1336*d99fa3c5SJeremy L Thompson   return 0;
1337*d99fa3c5SJeremy L Thompson }
1338*d99fa3c5SJeremy L Thompson 
1339*d99fa3c5SJeremy L Thompson /**
1340*d99fa3c5SJeremy L Thompson   @brief Create a multigrid coarse operator and level transfer operators
1341*d99fa3c5SJeremy L Thompson            for a CeedOperator with a non-tensor basis for the active vector
1342*d99fa3c5SJeremy L Thompson 
1343*d99fa3c5SJeremy L Thompson   @param[in] opFine       Fine grid operator
1344*d99fa3c5SJeremy L Thompson   @param[in] PMultFine    L-vector multiplicity in parallel gather/scatter
1345*d99fa3c5SJeremy L Thompson   @param[in] rstrCoarse   Coarse grid restriction
1346*d99fa3c5SJeremy L Thompson   @param[in] basisCoarse  Coarse grid active vector basis
1347*d99fa3c5SJeremy L Thompson   @param[in] interpCtoF   Matrix for coarse to fine interpolation
1348*d99fa3c5SJeremy L Thompson   @param[out] opCoarse    Coarse grid operator
1349*d99fa3c5SJeremy L Thompson   @param[out] opProlong   Coarse to fine operator
1350*d99fa3c5SJeremy L Thompson   @param[out] opRestrict  Fine to coarse operator
1351*d99fa3c5SJeremy L Thompson 
1352*d99fa3c5SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1353*d99fa3c5SJeremy L Thompson 
1354*d99fa3c5SJeremy L Thompson   @ref User
1355*d99fa3c5SJeremy L Thompson **/
1356*d99fa3c5SJeremy L Thompson int CeedOperatorMultigridLevelCreateH1(CeedOperator opFine,
1357*d99fa3c5SJeremy L Thompson                                        CeedVector PMultFine,
1358*d99fa3c5SJeremy L Thompson                                        CeedElemRestriction rstrCoarse,
1359*d99fa3c5SJeremy L Thompson                                        CeedBasis basisCoarse,
1360*d99fa3c5SJeremy L Thompson                                        const CeedScalar *interpCtoF,
1361*d99fa3c5SJeremy L Thompson                                        CeedOperator *opCoarse,
1362*d99fa3c5SJeremy L Thompson                                        CeedOperator *opProlong,
1363*d99fa3c5SJeremy L Thompson                                        CeedOperator *opRestrict) {
1364*d99fa3c5SJeremy L Thompson   int ierr;
1365*d99fa3c5SJeremy L Thompson   Ceed ceed;
1366*d99fa3c5SJeremy L Thompson   ierr = CeedOperatorGetCeed(opFine, &ceed); CeedChk(ierr);
1367*d99fa3c5SJeremy L Thompson 
1368*d99fa3c5SJeremy L Thompson   // Check for compatible quadrature spaces
1369*d99fa3c5SJeremy L Thompson   CeedBasis basisFine;
1370*d99fa3c5SJeremy L Thompson   ierr = CeedOperatorGetActiveBasis(opFine, &basisFine); CeedChk(ierr);
1371*d99fa3c5SJeremy L Thompson   CeedInt Qf, Qc;
1372*d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumQuadraturePoints(basisFine, &Qf); CeedChk(ierr);
1373*d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumQuadraturePoints(basisCoarse, &Qc); CeedChk(ierr);
1374*d99fa3c5SJeremy L Thompson   if (Qf != Qc)
1375*d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
1376*d99fa3c5SJeremy L Thompson     return CeedError(ceed, 1, "Bases must have compatible quadrature spaces");
1377*d99fa3c5SJeremy L Thompson   // LCOV_EXCL_STOP
1378*d99fa3c5SJeremy L Thompson 
1379*d99fa3c5SJeremy L Thompson   // Coarse to fine basis
1380*d99fa3c5SJeremy L Thompson   CeedElemTopology topo;
1381*d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetTopology(basisFine, &topo); CeedChk(ierr);
1382*d99fa3c5SJeremy L Thompson   CeedInt dim, ncomp, nnodesCoarse, nnodesFine;
1383*d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetDimension(basisFine, &dim); CeedChk(ierr);
1384*d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumComponents(basisFine, &ncomp); CeedChk(ierr);
1385*d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumNodes(basisFine, &nnodesFine); CeedChk(ierr);
1386*d99fa3c5SJeremy L Thompson   ierr = CeedElemRestrictionGetElementSize(rstrCoarse, &nnodesCoarse);
1387*d99fa3c5SJeremy L Thompson   CeedChk(ierr);
1388*d99fa3c5SJeremy L Thompson   CeedScalar *qref, *qweight, *grad;
1389*d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(nnodesFine, &qref); CeedChk(ierr);
1390*d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(nnodesFine, &qweight); CeedChk(ierr);
1391*d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(nnodesFine*nnodesCoarse*dim, &grad); CeedChk(ierr);
1392*d99fa3c5SJeremy L Thompson   CeedBasis basisCtoF;
1393*d99fa3c5SJeremy L Thompson   ierr = CeedBasisCreateH1(ceed, topo, ncomp, nnodesCoarse, nnodesFine,
1394*d99fa3c5SJeremy L Thompson                            interpCtoF, grad, qref, qweight, &basisCtoF);
1395*d99fa3c5SJeremy L Thompson   CeedChk(ierr);
1396*d99fa3c5SJeremy L Thompson   ierr = CeedFree(&qref); CeedChk(ierr);
1397*d99fa3c5SJeremy L Thompson   ierr = CeedFree(&qweight); CeedChk(ierr);
1398*d99fa3c5SJeremy L Thompson   ierr = CeedFree(&grad); CeedChk(ierr);
1399*d99fa3c5SJeremy L Thompson 
1400*d99fa3c5SJeremy L Thompson   // Core code
1401*d99fa3c5SJeremy L Thompson   ierr = CeedOperatorMultigridLevel_Core(opFine, PMultFine, rstrCoarse,
1402*d99fa3c5SJeremy L Thompson                                          basisCoarse, basisCtoF, opCoarse,
1403*d99fa3c5SJeremy L Thompson                                          opProlong, opRestrict);
1404*d99fa3c5SJeremy L Thompson   CeedChk(ierr);
1405*d99fa3c5SJeremy L Thompson   return 0;
1406*d99fa3c5SJeremy L Thompson }
1407*d99fa3c5SJeremy L Thompson 
1408*d99fa3c5SJeremy L Thompson /**
14093bd813ffSjeremylt   @brief Build a FDM based approximate inverse for each element for a
14103bd813ffSjeremylt            CeedOperator
14113bd813ffSjeremylt 
14123bd813ffSjeremylt   This returns a CeedOperator and CeedVector to apply a Fast Diagonalization
14133bd813ffSjeremylt     Method based approximate inverse. This function obtains the simultaneous
14143bd813ffSjeremylt     diagonalization for the 1D mass and Laplacian operators,
14153bd813ffSjeremylt       M = V^T V, K = V^T S V.
14163bd813ffSjeremylt     The assembled QFunction is used to modify the eigenvalues from simultaneous
14173bd813ffSjeremylt     diagonalization and obtain an approximate inverse of the form
14183bd813ffSjeremylt       V^T S^hat V. The CeedOperator must be linear and non-composite. The
14193bd813ffSjeremylt     associated CeedQFunction must therefore also be linear.
14203bd813ffSjeremylt 
14213bd813ffSjeremylt   @param op             CeedOperator to create element inverses
14223bd813ffSjeremylt   @param[out] fdminv    CeedOperator to apply the action of a FDM based inverse
14233bd813ffSjeremylt                           for each element
14243bd813ffSjeremylt   @param request        Address of CeedRequest for non-blocking completion, else
14254cc79fe7SJed Brown                           @ref CEED_REQUEST_IMMEDIATE
14263bd813ffSjeremylt 
14273bd813ffSjeremylt   @return An error code: 0 - success, otherwise - failure
14283bd813ffSjeremylt 
14297a982d89SJeremy L. Thompson   @ref Backend
14303bd813ffSjeremylt **/
14313bd813ffSjeremylt int CeedOperatorCreateFDMElementInverse(CeedOperator op, CeedOperator *fdminv,
14323bd813ffSjeremylt                                         CeedRequest *request) {
14333bd813ffSjeremylt   int ierr;
14343bd813ffSjeremylt   Ceed ceed = op->ceed;
1435713f43c3Sjeremylt   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
14363bd813ffSjeremylt 
1437713f43c3Sjeremylt   // Use backend version, if available
1438713f43c3Sjeremylt   if (op->CreateFDMElementInverse) {
1439713f43c3Sjeremylt     ierr = op->CreateFDMElementInverse(op, fdminv, request); CeedChk(ierr);
1440713f43c3Sjeremylt   } else {
1441713f43c3Sjeremylt     // Fallback to reference Ceed
1442713f43c3Sjeremylt     if (!op->opfallback) {
1443713f43c3Sjeremylt       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
14443bd813ffSjeremylt     }
1445713f43c3Sjeremylt     // Assemble
1446713f43c3Sjeremylt     ierr = op->opfallback->CreateFDMElementInverse(op->opfallback, fdminv,
14473bd813ffSjeremylt            request); CeedChk(ierr);
14483bd813ffSjeremylt   }
14493bd813ffSjeremylt 
14503bd813ffSjeremylt   return 0;
14513bd813ffSjeremylt }
14523bd813ffSjeremylt 
14537a982d89SJeremy L. Thompson /**
14547a982d89SJeremy L. Thompson   @brief View a CeedOperator
14557a982d89SJeremy L. Thompson 
14567a982d89SJeremy L. Thompson   @param[in] op     CeedOperator to view
14577a982d89SJeremy L. Thompson   @param[in] stream Stream to write; typically stdout/stderr or a file
14587a982d89SJeremy L. Thompson 
14597a982d89SJeremy L. Thompson   @return Error code: 0 - success, otherwise - failure
14607a982d89SJeremy L. Thompson 
14617a982d89SJeremy L. Thompson   @ref User
14627a982d89SJeremy L. Thompson **/
14637a982d89SJeremy L. Thompson int CeedOperatorView(CeedOperator op, FILE *stream) {
14647a982d89SJeremy L. Thompson   int ierr;
14657a982d89SJeremy L. Thompson 
14667a982d89SJeremy L. Thompson   if (op->composite) {
14677a982d89SJeremy L. Thompson     fprintf(stream, "Composite CeedOperator\n");
14687a982d89SJeremy L. Thompson 
14697a982d89SJeremy L. Thompson     for (CeedInt i=0; i<op->numsub; i++) {
14707a982d89SJeremy L. Thompson       fprintf(stream, "  SubOperator [%d]:\n", i);
14717a982d89SJeremy L. Thompson       ierr = CeedOperatorSingleView(op->suboperators[i], 1, stream);
14727a982d89SJeremy L. Thompson       CeedChk(ierr);
14737a982d89SJeremy L. Thompson     }
14747a982d89SJeremy L. Thompson   } else {
14757a982d89SJeremy L. Thompson     fprintf(stream, "CeedOperator\n");
14767a982d89SJeremy L. Thompson     ierr = CeedOperatorSingleView(op, 0, stream); CeedChk(ierr);
14777a982d89SJeremy L. Thompson   }
14787a982d89SJeremy L. Thompson 
14797a982d89SJeremy L. Thompson   return 0;
14807a982d89SJeremy L. Thompson }
14813bd813ffSjeremylt 
14823bd813ffSjeremylt /**
14833bd813ffSjeremylt   @brief Apply CeedOperator to a vector
1484d7b241e6Sjeremylt 
1485d7b241e6Sjeremylt   This computes the action of the operator on the specified (active) input,
1486d7b241e6Sjeremylt   yielding its (active) output.  All inputs and outputs must be specified using
1487d7b241e6Sjeremylt   CeedOperatorSetField().
1488d7b241e6Sjeremylt 
1489d7b241e6Sjeremylt   @param op        CeedOperator to apply
14904cc79fe7SJed Brown   @param[in] in    CeedVector containing input state or @ref CEED_VECTOR_NONE if
149134138859Sjeremylt                   there are no active inputs
1492b11c1e72Sjeremylt   @param[out] out  CeedVector to store result of applying operator (must be
14934cc79fe7SJed Brown                      distinct from @a in) or @ref CEED_VECTOR_NONE if there are no
149434138859Sjeremylt                      active outputs
1495d7b241e6Sjeremylt   @param request   Address of CeedRequest for non-blocking completion, else
14964cc79fe7SJed Brown                      @ref CEED_REQUEST_IMMEDIATE
1497b11c1e72Sjeremylt 
1498b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
1499dfdf5a53Sjeremylt 
15007a982d89SJeremy L. Thompson   @ref User
1501b11c1e72Sjeremylt **/
1502692c2638Sjeremylt int CeedOperatorApply(CeedOperator op, CeedVector in, CeedVector out,
1503692c2638Sjeremylt                       CeedRequest *request) {
1504d7b241e6Sjeremylt   int ierr;
1505d7b241e6Sjeremylt   Ceed ceed = op->ceed;
1506250756a7Sjeremylt   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
1507d7b241e6Sjeremylt 
1508250756a7Sjeremylt   if (op->numelements)  {
1509250756a7Sjeremylt     // Standard Operator
1510cae8b89aSjeremylt     if (op->Apply) {
1511250756a7Sjeremylt       ierr = op->Apply(op, in, out, request); CeedChk(ierr);
1512cae8b89aSjeremylt     } else {
1513cae8b89aSjeremylt       // Zero all output vectors
1514250756a7Sjeremylt       CeedQFunction qf = op->qf;
1515cae8b89aSjeremylt       for (CeedInt i=0; i<qf->numoutputfields; i++) {
1516cae8b89aSjeremylt         CeedVector vec = op->outputfields[i]->vec;
1517cae8b89aSjeremylt         if (vec == CEED_VECTOR_ACTIVE)
1518cae8b89aSjeremylt           vec = out;
1519cae8b89aSjeremylt         if (vec != CEED_VECTOR_NONE) {
1520cae8b89aSjeremylt           ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr);
1521cae8b89aSjeremylt         }
1522cae8b89aSjeremylt       }
1523250756a7Sjeremylt       // Apply
1524250756a7Sjeremylt       ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr);
1525250756a7Sjeremylt     }
1526250756a7Sjeremylt   } else if (op->composite) {
1527250756a7Sjeremylt     // Composite Operator
1528250756a7Sjeremylt     if (op->ApplyComposite) {
1529250756a7Sjeremylt       ierr = op->ApplyComposite(op, in, out, request); CeedChk(ierr);
1530250756a7Sjeremylt     } else {
1531250756a7Sjeremylt       CeedInt numsub;
1532250756a7Sjeremylt       ierr = CeedOperatorGetNumSub(op, &numsub); CeedChk(ierr);
1533250756a7Sjeremylt       CeedOperator *suboperators;
1534250756a7Sjeremylt       ierr = CeedOperatorGetSubList(op, &suboperators); CeedChk(ierr);
1535250756a7Sjeremylt 
1536250756a7Sjeremylt       // Zero all output vectors
1537250756a7Sjeremylt       if (out != CEED_VECTOR_NONE) {
1538cae8b89aSjeremylt         ierr = CeedVectorSetValue(out, 0.0); CeedChk(ierr);
1539cae8b89aSjeremylt       }
1540250756a7Sjeremylt       for (CeedInt i=0; i<numsub; i++) {
1541250756a7Sjeremylt         for (CeedInt j=0; j<suboperators[i]->qf->numoutputfields; j++) {
1542250756a7Sjeremylt           CeedVector vec = suboperators[i]->outputfields[j]->vec;
1543250756a7Sjeremylt           if (vec != CEED_VECTOR_ACTIVE && vec != CEED_VECTOR_NONE) {
1544250756a7Sjeremylt             ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr);
1545250756a7Sjeremylt           }
1546250756a7Sjeremylt         }
1547250756a7Sjeremylt       }
1548250756a7Sjeremylt       // Apply
1549250756a7Sjeremylt       for (CeedInt i=0; i<op->numsub; i++) {
1550250756a7Sjeremylt         ierr = CeedOperatorApplyAdd(op->suboperators[i], in, out, request);
1551cae8b89aSjeremylt         CeedChk(ierr);
1552cae8b89aSjeremylt       }
1553cae8b89aSjeremylt     }
1554250756a7Sjeremylt   }
1555250756a7Sjeremylt 
1556cae8b89aSjeremylt   return 0;
1557cae8b89aSjeremylt }
1558cae8b89aSjeremylt 
1559cae8b89aSjeremylt /**
1560cae8b89aSjeremylt   @brief Apply CeedOperator to a vector and add result to output vector
1561cae8b89aSjeremylt 
1562cae8b89aSjeremylt   This computes the action of the operator on the specified (active) input,
1563cae8b89aSjeremylt   yielding its (active) output.  All inputs and outputs must be specified using
1564cae8b89aSjeremylt   CeedOperatorSetField().
1565cae8b89aSjeremylt 
1566cae8b89aSjeremylt   @param op        CeedOperator to apply
1567cae8b89aSjeremylt   @param[in] in    CeedVector containing input state or NULL if there are no
1568cae8b89aSjeremylt                      active inputs
1569cae8b89aSjeremylt   @param[out] out  CeedVector to sum in result of applying operator (must be
1570cae8b89aSjeremylt                      distinct from @a in) or NULL if there are no active outputs
1571cae8b89aSjeremylt   @param request   Address of CeedRequest for non-blocking completion, else
15724cc79fe7SJed Brown                      @ref CEED_REQUEST_IMMEDIATE
1573cae8b89aSjeremylt 
1574cae8b89aSjeremylt   @return An error code: 0 - success, otherwise - failure
1575cae8b89aSjeremylt 
15767a982d89SJeremy L. Thompson   @ref User
1577cae8b89aSjeremylt **/
1578cae8b89aSjeremylt int CeedOperatorApplyAdd(CeedOperator op, CeedVector in, CeedVector out,
1579cae8b89aSjeremylt                          CeedRequest *request) {
1580cae8b89aSjeremylt   int ierr;
1581cae8b89aSjeremylt   Ceed ceed = op->ceed;
1582250756a7Sjeremylt   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
1583cae8b89aSjeremylt 
1584250756a7Sjeremylt   if (op->numelements)  {
1585250756a7Sjeremylt     // Standard Operator
1586250756a7Sjeremylt     ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr);
1587250756a7Sjeremylt   } else if (op->composite) {
1588250756a7Sjeremylt     // Composite Operator
1589250756a7Sjeremylt     if (op->ApplyAddComposite) {
1590250756a7Sjeremylt       ierr = op->ApplyAddComposite(op, in, out, request); CeedChk(ierr);
1591cae8b89aSjeremylt     } else {
1592250756a7Sjeremylt       CeedInt numsub;
1593250756a7Sjeremylt       ierr = CeedOperatorGetNumSub(op, &numsub); CeedChk(ierr);
1594250756a7Sjeremylt       CeedOperator *suboperators;
1595250756a7Sjeremylt       ierr = CeedOperatorGetSubList(op, &suboperators); CeedChk(ierr);
1596250756a7Sjeremylt 
1597250756a7Sjeremylt       for (CeedInt i=0; i<numsub; i++) {
1598250756a7Sjeremylt         ierr = CeedOperatorApplyAdd(suboperators[i], in, out, request);
1599cae8b89aSjeremylt         CeedChk(ierr);
16001d7d2407SJeremy L Thompson       }
1601250756a7Sjeremylt     }
1602250756a7Sjeremylt   }
1603250756a7Sjeremylt 
1604d7b241e6Sjeremylt   return 0;
1605d7b241e6Sjeremylt }
1606d7b241e6Sjeremylt 
1607d7b241e6Sjeremylt /**
1608b11c1e72Sjeremylt   @brief Destroy a CeedOperator
1609d7b241e6Sjeremylt 
1610d7b241e6Sjeremylt   @param op CeedOperator to destroy
1611b11c1e72Sjeremylt 
1612b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
1613dfdf5a53Sjeremylt 
16147a982d89SJeremy L. Thompson   @ref User
1615b11c1e72Sjeremylt **/
1616d7b241e6Sjeremylt int CeedOperatorDestroy(CeedOperator *op) {
1617d7b241e6Sjeremylt   int ierr;
1618d7b241e6Sjeremylt 
1619d7b241e6Sjeremylt   if (!*op || --(*op)->refcount > 0) return 0;
1620d7b241e6Sjeremylt   if ((*op)->Destroy) {
1621d7b241e6Sjeremylt     ierr = (*op)->Destroy(*op); CeedChk(ierr);
1622d7b241e6Sjeremylt   }
1623fe2413ffSjeremylt   ierr = CeedDestroy(&(*op)->ceed); CeedChk(ierr);
1624fe2413ffSjeremylt   // Free fields
16251d102b48SJeremy L Thompson   for (int i=0; i<(*op)->nfields; i++)
162652d6035fSJeremy L Thompson     if ((*op)->inputfields[i]) {
162715910d16Sjeremylt       if ((*op)->inputfields[i]->Erestrict != CEED_ELEMRESTRICTION_NONE) {
162871352a93Sjeremylt         ierr = CeedElemRestrictionDestroy(&(*op)->inputfields[i]->Erestrict);
162971352a93Sjeremylt         CeedChk(ierr);
163015910d16Sjeremylt       }
163171352a93Sjeremylt       if ((*op)->inputfields[i]->basis != CEED_BASIS_COLLOCATED) {
163271352a93Sjeremylt         ierr = CeedBasisDestroy(&(*op)->inputfields[i]->basis); CeedChk(ierr);
163371352a93Sjeremylt       }
163471352a93Sjeremylt       if ((*op)->inputfields[i]->vec != CEED_VECTOR_ACTIVE &&
163571352a93Sjeremylt           (*op)->inputfields[i]->vec != CEED_VECTOR_NONE ) {
163671352a93Sjeremylt         ierr = CeedVectorDestroy(&(*op)->inputfields[i]->vec); CeedChk(ierr);
163771352a93Sjeremylt       }
1638*d99fa3c5SJeremy L Thompson       ierr = CeedFree(&(*op)->inputfields[i]->fieldname); CeedChk(ierr);
1639fe2413ffSjeremylt       ierr = CeedFree(&(*op)->inputfields[i]); CeedChk(ierr);
1640fe2413ffSjeremylt     }
16411d102b48SJeremy L Thompson   for (int i=0; i<(*op)->nfields; i++)
1642d0eb30a5Sjeremylt     if ((*op)->outputfields[i]) {
164371352a93Sjeremylt       ierr = CeedElemRestrictionDestroy(&(*op)->outputfields[i]->Erestrict);
164471352a93Sjeremylt       CeedChk(ierr);
164571352a93Sjeremylt       if ((*op)->outputfields[i]->basis != CEED_BASIS_COLLOCATED) {
164671352a93Sjeremylt         ierr = CeedBasisDestroy(&(*op)->outputfields[i]->basis); CeedChk(ierr);
164771352a93Sjeremylt       }
164871352a93Sjeremylt       if ((*op)->outputfields[i]->vec != CEED_VECTOR_ACTIVE &&
164971352a93Sjeremylt           (*op)->outputfields[i]->vec != CEED_VECTOR_NONE ) {
165071352a93Sjeremylt         ierr = CeedVectorDestroy(&(*op)->outputfields[i]->vec); CeedChk(ierr);
165171352a93Sjeremylt       }
1652*d99fa3c5SJeremy L Thompson       ierr = CeedFree(&(*op)->outputfields[i]->fieldname); CeedChk(ierr);
1653fe2413ffSjeremylt       ierr = CeedFree(&(*op)->outputfields[i]); CeedChk(ierr);
1654fe2413ffSjeremylt     }
165552d6035fSJeremy L Thompson   // Destroy suboperators
16561d102b48SJeremy L Thompson   for (int i=0; i<(*op)->numsub; i++)
165752d6035fSJeremy L Thompson     if ((*op)->suboperators[i]) {
165852d6035fSJeremy L Thompson       ierr = CeedOperatorDestroy(&(*op)->suboperators[i]); CeedChk(ierr);
165952d6035fSJeremy L Thompson     }
1660d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->qf); CeedChk(ierr);
1661d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->dqf); CeedChk(ierr);
1662d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->dqfT); CeedChk(ierr);
1663fe2413ffSjeremylt 
16645107b09fSJeremy L Thompson   // Destroy fallback
16655107b09fSJeremy L Thompson   if ((*op)->opfallback) {
16665107b09fSJeremy L Thompson     ierr = (*op)->qffallback->Destroy((*op)->qffallback); CeedChk(ierr);
16675107b09fSJeremy L Thompson     ierr = CeedFree(&(*op)->qffallback); CeedChk(ierr);
16685107b09fSJeremy L Thompson     ierr = (*op)->opfallback->Destroy((*op)->opfallback); CeedChk(ierr);
16695107b09fSJeremy L Thompson     ierr = CeedFree(&(*op)->opfallback); CeedChk(ierr);
16705107b09fSJeremy L Thompson   }
16715107b09fSJeremy L Thompson 
1672fe2413ffSjeremylt   ierr = CeedFree(&(*op)->inputfields); CeedChk(ierr);
1673fe2413ffSjeremylt   ierr = CeedFree(&(*op)->outputfields); CeedChk(ierr);
167452d6035fSJeremy L Thompson   ierr = CeedFree(&(*op)->suboperators); CeedChk(ierr);
1675d7b241e6Sjeremylt   ierr = CeedFree(op); CeedChk(ierr);
1676d7b241e6Sjeremylt   return 0;
1677d7b241e6Sjeremylt }
1678d7b241e6Sjeremylt 
1679d7b241e6Sjeremylt /// @}
1680