xref: /libCEED/interface/ceed-operator.c (revision 3bd813ff881321d63f499fd87a0d6e6a47c6a2dc)
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>
20*3bd813ffSjeremylt #include <math.h>
21d7b241e6Sjeremylt 
22dfdf5a53Sjeremylt /// @file
23dfdf5a53Sjeremylt /// Implementation of public CeedOperator interfaces
24dfdf5a53Sjeremylt ///
25dfdf5a53Sjeremylt /// @addtogroup CeedOperator
26dfdf5a53Sjeremylt ///   @{
27d7b241e6Sjeremylt 
28d7b241e6Sjeremylt /**
290219ea01SJeremy L Thompson   @brief Create a CeedOperator and associate a CeedQFunction. A CeedBasis and
300219ea01SJeremy L Thompson            CeedElemRestriction can be associated with CeedQFunction fields with
310219ea01SJeremy L Thompson            \ref CeedOperatorSetField.
32d7b241e6Sjeremylt 
33b11c1e72Sjeremylt   @param ceed    A Ceed object where the CeedOperator will be created
34d7b241e6Sjeremylt   @param qf      QFunction defining the action of the operator at quadrature points
3534138859Sjeremylt   @param dqf     QFunction defining the action of the Jacobian of @a qf (or
3634138859Sjeremylt                    CEED_QFUNCTION_NONE)
37d7b241e6Sjeremylt   @param dqfT    QFunction defining the action of the transpose of the Jacobian
3834138859Sjeremylt                    of @a qf (or CEED_QFUNCTION_NONE)
39b11c1e72Sjeremylt   @param[out] op Address of the variable where the newly created
40b11c1e72Sjeremylt                      CeedOperator will be stored
41b11c1e72Sjeremylt 
42b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
43dfdf5a53Sjeremylt 
44dfdf5a53Sjeremylt   @ref Basic
45d7b241e6Sjeremylt  */
46d7b241e6Sjeremylt int CeedOperatorCreate(Ceed ceed, CeedQFunction qf, CeedQFunction dqf,
47d7b241e6Sjeremylt                        CeedQFunction dqfT, CeedOperator *op) {
48d7b241e6Sjeremylt   int ierr;
49d7b241e6Sjeremylt 
505fe0d4faSjeremylt   if (!ceed->OperatorCreate) {
515fe0d4faSjeremylt     Ceed delegate;
52aefd8378Sjeremylt     ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr);
535fe0d4faSjeremylt 
545fe0d4faSjeremylt     if (!delegate)
55c042f62fSJeremy L Thompson       // LCOV_EXCL_START
565fe0d4faSjeremylt       return CeedError(ceed, 1, "Backend does not support OperatorCreate");
57c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
585fe0d4faSjeremylt 
595fe0d4faSjeremylt     ierr = CeedOperatorCreate(delegate, qf, dqf, dqfT, op); CeedChk(ierr);
605fe0d4faSjeremylt     return 0;
615fe0d4faSjeremylt   }
625fe0d4faSjeremylt 
63d7b241e6Sjeremylt   ierr = CeedCalloc(1, op); CeedChk(ierr);
64d7b241e6Sjeremylt   (*op)->ceed = ceed;
65d7b241e6Sjeremylt   ceed->refcount++;
66d7b241e6Sjeremylt   (*op)->refcount = 1;
67442e7f0bSjeremylt   if (qf == CEED_QFUNCTION_NONE)
68442e7f0bSjeremylt     // LCOV_EXCL_START
69442e7f0bSjeremylt     return CeedError(ceed, 1, "Operator must have a valid QFunction.");
70442e7f0bSjeremylt   // LCOV_EXCL_STOP
71d7b241e6Sjeremylt   (*op)->qf = qf;
72d7b241e6Sjeremylt   qf->refcount++;
73442e7f0bSjeremylt   if (dqf && dqf != CEED_QFUNCTION_NONE) {
74d7b241e6Sjeremylt     (*op)->dqf = dqf;
75442e7f0bSjeremylt     dqf->refcount++;
76442e7f0bSjeremylt   }
77442e7f0bSjeremylt   if (dqfT && dqfT != CEED_QFUNCTION_NONE) {
78d7b241e6Sjeremylt     (*op)->dqfT = dqfT;
79442e7f0bSjeremylt     dqfT->refcount++;
80442e7f0bSjeremylt   }
81fe2413ffSjeremylt   ierr = CeedCalloc(16, &(*op)->inputfields); CeedChk(ierr);
82fe2413ffSjeremylt   ierr = CeedCalloc(16, &(*op)->outputfields); CeedChk(ierr);
83d7b241e6Sjeremylt   ierr = ceed->OperatorCreate(*op); CeedChk(ierr);
84d7b241e6Sjeremylt   return 0;
85d7b241e6Sjeremylt }
86d7b241e6Sjeremylt 
87d7b241e6Sjeremylt /**
8852d6035fSJeremy L Thompson   @brief Create an operator that composes the action of several operators
8952d6035fSJeremy L Thompson 
9052d6035fSJeremy L Thompson   @param ceed    A Ceed object where the CeedOperator will be created
9152d6035fSJeremy L Thompson   @param[out] op Address of the variable where the newly created
9252d6035fSJeremy L Thompson                      Composite CeedOperator will be stored
9352d6035fSJeremy L Thompson 
9452d6035fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
9552d6035fSJeremy L Thompson 
9652d6035fSJeremy L Thompson   @ref Basic
9752d6035fSJeremy L Thompson  */
9852d6035fSJeremy L Thompson int CeedCompositeOperatorCreate(Ceed ceed, CeedOperator *op) {
9952d6035fSJeremy L Thompson   int ierr;
10052d6035fSJeremy L Thompson 
10152d6035fSJeremy L Thompson   if (!ceed->CompositeOperatorCreate) {
10252d6035fSJeremy L Thompson     Ceed delegate;
103aefd8378Sjeremylt     ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr);
10452d6035fSJeremy L Thompson 
105250756a7Sjeremylt     if (delegate) {
10652d6035fSJeremy L Thompson       ierr = CeedCompositeOperatorCreate(delegate, op); CeedChk(ierr);
10752d6035fSJeremy L Thompson       return 0;
10852d6035fSJeremy L Thompson     }
109250756a7Sjeremylt   }
11052d6035fSJeremy L Thompson 
11152d6035fSJeremy L Thompson   ierr = CeedCalloc(1, op); CeedChk(ierr);
11252d6035fSJeremy L Thompson   (*op)->ceed = ceed;
11352d6035fSJeremy L Thompson   ceed->refcount++;
11452d6035fSJeremy L Thompson   (*op)->composite = true;
11552d6035fSJeremy L Thompson   ierr = CeedCalloc(16, &(*op)->suboperators); CeedChk(ierr);
116250756a7Sjeremylt 
117250756a7Sjeremylt   if (ceed->CompositeOperatorCreate) {
11852d6035fSJeremy L Thompson     ierr = ceed->CompositeOperatorCreate(*op); CeedChk(ierr);
119250756a7Sjeremylt   }
12052d6035fSJeremy L Thompson   return 0;
12152d6035fSJeremy L Thompson }
12252d6035fSJeremy L Thompson 
12352d6035fSJeremy L Thompson /**
124b11c1e72Sjeremylt   @brief Provide a field to a CeedOperator for use by its CeedQFunction
125d7b241e6Sjeremylt 
126d7b241e6Sjeremylt   This function is used to specify both active and passive fields to a
127d7b241e6Sjeremylt   CeedOperator.  For passive fields, a vector @arg v must be provided.  Passive
128d7b241e6Sjeremylt   fields can inputs or outputs (updated in-place when operator is applied).
129d7b241e6Sjeremylt 
130d7b241e6Sjeremylt   Active fields must be specified using this function, but their data (in a
131d7b241e6Sjeremylt   CeedVector) is passed in CeedOperatorApply().  There can be at most one active
132d7b241e6Sjeremylt   input and at most one active output.
133d7b241e6Sjeremylt 
1348c91a0c9SJeremy L Thompson   @param op         CeedOperator on which to provide the field
1358795c945Sjeremylt   @param fieldname  Name of the field (to be matched with the name used by
1368795c945Sjeremylt                       CeedQFunction)
137b11c1e72Sjeremylt   @param r          CeedElemRestriction
138b0e29e78Sjeremylt   @param lmode      CeedTransposeMode which specifies the ordering of the
139b0e29e78Sjeremylt                       components of the l-vector used by this CeedOperatorField,
140b0e29e78Sjeremylt                       CEED_NOTRANSPOSE indicates the component is the
141b0e29e78Sjeremylt                       outermost index and CEED_TRANSPOSE indicates the component
142b0e29e78Sjeremylt                       is the innermost index in ordering of the l-vector
143783c99b3SValeria Barra   @param b          CeedBasis in which the field resides or CEED_BASIS_COLLOCATED
144b11c1e72Sjeremylt                       if collocated with quadrature points
145b11c1e72Sjeremylt   @param v          CeedVector to be used by CeedOperator or CEED_VECTOR_ACTIVE
146b11c1e72Sjeremylt                       if field is active or CEED_VECTOR_NONE if using
1478c91a0c9SJeremy L Thompson                       CEED_EVAL_WEIGHT in the QFunction
148b11c1e72Sjeremylt 
149b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
150dfdf5a53Sjeremylt 
151dfdf5a53Sjeremylt   @ref Basic
152b11c1e72Sjeremylt **/
153d7b241e6Sjeremylt int CeedOperatorSetField(CeedOperator op, const char *fieldname,
1544dccadb6Sjeremylt                          CeedElemRestriction r, CeedTransposeMode lmode,
1554dccadb6Sjeremylt                          CeedBasis b, CeedVector v) {
156d7b241e6Sjeremylt   int ierr;
15752d6035fSJeremy L Thompson   if (op->composite)
158c042f62fSJeremy L Thompson     // LCOV_EXCL_START
15952d6035fSJeremy L Thompson     return CeedError(op->ceed, 1, "Cannot add field to composite operator.");
160c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
1618b067b84SJed Brown   if (!r)
162c042f62fSJeremy L Thompson     // LCOV_EXCL_START
163c042f62fSJeremy L Thompson     return CeedError(op->ceed, 1,
164c042f62fSJeremy L Thompson                      "ElemRestriction r for field \"%s\" must be non-NULL.",
165c042f62fSJeremy L Thompson                      fieldname);
166c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
1678b067b84SJed Brown   if (!b)
168c042f62fSJeremy L Thompson     // LCOV_EXCL_START
169c042f62fSJeremy L Thompson     return CeedError(op->ceed, 1, "Basis b for field \"%s\" must be non-NULL.",
170c042f62fSJeremy L Thompson                      fieldname);
171c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
1728b067b84SJed Brown   if (!v)
173c042f62fSJeremy L Thompson     // LCOV_EXCL_START
174c042f62fSJeremy L Thompson     return CeedError(op->ceed, 1, "Vector v for field \"%s\" must be non-NULL.",
175c042f62fSJeremy L Thompson                      fieldname);
176c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
17752d6035fSJeremy L Thompson 
178d7b241e6Sjeremylt   CeedInt numelements;
179d7b241e6Sjeremylt   ierr = CeedElemRestrictionGetNumElements(r, &numelements); CeedChk(ierr);
1802cb0afc5Sjeremylt   if (op->hasrestriction && op->numelements != numelements)
181c042f62fSJeremy L Thompson     // LCOV_EXCL_START
182d7b241e6Sjeremylt     return CeedError(op->ceed, 1,
1831d102b48SJeremy L Thompson                      "ElemRestriction with %d elements incompatible with prior "
1841d102b48SJeremy L Thompson                      "%d elements", numelements, op->numelements);
185c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
186d7b241e6Sjeremylt   op->numelements = numelements;
1872cb0afc5Sjeremylt   op->hasrestriction = true; // Restriction set, but numelements may be 0
188d7b241e6Sjeremylt 
189783c99b3SValeria Barra   if (b != CEED_BASIS_COLLOCATED) {
190d7b241e6Sjeremylt     CeedInt numqpoints;
191d7b241e6Sjeremylt     ierr = CeedBasisGetNumQuadraturePoints(b, &numqpoints); CeedChk(ierr);
192d7b241e6Sjeremylt     if (op->numqpoints && op->numqpoints != numqpoints)
193c042f62fSJeremy L Thompson       // LCOV_EXCL_START
1941d102b48SJeremy L Thompson       return CeedError(op->ceed, 1, "Basis with %d quadrature points "
1951d102b48SJeremy L Thompson                        "incompatible with prior %d points", numqpoints,
1961d102b48SJeremy L Thompson                        op->numqpoints);
197c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
198d7b241e6Sjeremylt     op->numqpoints = numqpoints;
199d7b241e6Sjeremylt   }
200d1bcdac9Sjeremylt   CeedOperatorField *ofield;
201d7b241e6Sjeremylt   for (CeedInt i=0; i<op->qf->numinputfields; i++) {
202fe2413ffSjeremylt     if (!strcmp(fieldname, (*op->qf->inputfields[i]).fieldname)) {
203d7b241e6Sjeremylt       ofield = &op->inputfields[i];
204d7b241e6Sjeremylt       goto found;
205d7b241e6Sjeremylt     }
206d7b241e6Sjeremylt   }
207d7b241e6Sjeremylt   for (CeedInt i=0; i<op->qf->numoutputfields; i++) {
208fe2413ffSjeremylt     if (!strcmp(fieldname, (*op->qf->outputfields[i]).fieldname)) {
209d7b241e6Sjeremylt       ofield = &op->outputfields[i];
210d7b241e6Sjeremylt       goto found;
211d7b241e6Sjeremylt     }
212d7b241e6Sjeremylt   }
213c042f62fSJeremy L Thompson   // LCOV_EXCL_START
214d7b241e6Sjeremylt   return CeedError(op->ceed, 1, "QFunction has no knowledge of field '%s'",
215d7b241e6Sjeremylt                    fieldname);
216c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
217d7b241e6Sjeremylt found:
218fe2413ffSjeremylt   ierr = CeedCalloc(1, ofield); CeedChk(ierr);
219fe2413ffSjeremylt   (*ofield)->Erestrict = r;
22071352a93Sjeremylt   r->refcount += 1;
221fe2413ffSjeremylt   (*ofield)->lmode = lmode;
222fe2413ffSjeremylt   (*ofield)->basis = b;
22371352a93Sjeremylt   if (b != CEED_BASIS_COLLOCATED)
22471352a93Sjeremylt     b->refcount += 1;
225fe2413ffSjeremylt   (*ofield)->vec = v;
22671352a93Sjeremylt   if (v != CEED_VECTOR_ACTIVE && v != CEED_VECTOR_NONE)
22771352a93Sjeremylt     v->refcount += 1;
228d7b241e6Sjeremylt   op->nfields += 1;
229d7b241e6Sjeremylt   return 0;
230d7b241e6Sjeremylt }
231d7b241e6Sjeremylt 
232d7b241e6Sjeremylt /**
23352d6035fSJeremy L Thompson   @brief Add a sub-operator to a composite CeedOperator
234288c0443SJeremy L Thompson 
23534138859Sjeremylt   @param[out] compositeop Composite CeedOperator
23634138859Sjeremylt   @param      subop       Sub-operator CeedOperator
23752d6035fSJeremy L Thompson 
23852d6035fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
23952d6035fSJeremy L Thompson 
24052d6035fSJeremy L Thompson   @ref Basic
24152d6035fSJeremy L Thompson  */
242692c2638Sjeremylt int CeedCompositeOperatorAddSub(CeedOperator compositeop, CeedOperator subop) {
24352d6035fSJeremy L Thompson   if (!compositeop->composite)
244c042f62fSJeremy L Thompson     // LCOV_EXCL_START
2451d102b48SJeremy L Thompson     return CeedError(compositeop->ceed, 1, "CeedOperator is not a composite "
2461d102b48SJeremy L Thompson                      "operator");
247c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
24852d6035fSJeremy L Thompson 
24952d6035fSJeremy L Thompson   if (compositeop->numsub == CEED_COMPOSITE_MAX)
250c042f62fSJeremy L Thompson     // LCOV_EXCL_START
2511d102b48SJeremy L Thompson     return CeedError(compositeop->ceed, 1, "Cannot add additional suboperators");
252c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
25352d6035fSJeremy L Thompson 
25452d6035fSJeremy L Thompson   compositeop->suboperators[compositeop->numsub] = subop;
25552d6035fSJeremy L Thompson   subop->refcount++;
25652d6035fSJeremy L Thompson   compositeop->numsub++;
25752d6035fSJeremy L Thompson   return 0;
25852d6035fSJeremy L Thompson }
25952d6035fSJeremy L Thompson 
26052d6035fSJeremy L Thompson /**
2615107b09fSJeremy L Thompson   @brief Duplicate a CeedOperator with a reference Ceed to fallback for advanced
2625107b09fSJeremy L Thompson            CeedOperator functionality
2635107b09fSJeremy L Thompson 
2645107b09fSJeremy L Thompson   @param op           CeedOperator to create fallback for
2655107b09fSJeremy L Thompson 
2665107b09fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
2675107b09fSJeremy L Thompson 
2685107b09fSJeremy L Thompson   @ref Developer
2695107b09fSJeremy L Thompson **/
2705107b09fSJeremy L Thompson int CeedOperatorCreateFallback(CeedOperator op) {
2715107b09fSJeremy L Thompson   int ierr;
2725107b09fSJeremy L Thompson 
2735107b09fSJeremy L Thompson   // Fallback Ceed
2745107b09fSJeremy L Thompson   const char *resource, *fallbackresource;
2755107b09fSJeremy L Thompson   ierr = CeedGetResource(op->ceed, &resource); CeedChk(ierr);
2765107b09fSJeremy L Thompson   ierr = CeedGetOperatorFallbackResource(op->ceed, &fallbackresource);
2775107b09fSJeremy L Thompson   CeedChk(ierr);
2785107b09fSJeremy L Thompson   if (!strcmp(resource, fallbackresource))
2795107b09fSJeremy L Thompson     // LCOV_EXCL_START
2805107b09fSJeremy L Thompson     return CeedError(op->ceed, 1, "Backend %s cannot create an operator"
2815107b09fSJeremy L Thompson                      "fallback to resource %s", resource, fallbackresource);
2825107b09fSJeremy L Thompson   // LCOV_EXCL_STOP
2835107b09fSJeremy L Thompson 
2845107b09fSJeremy L Thompson   Ceed ceedref;
2855107b09fSJeremy L Thompson   ierr = CeedInit(fallbackresource, &ceedref); CeedChk(ierr);
2865107b09fSJeremy L Thompson   ceedref->opfallbackparent = op->ceed;
2875107b09fSJeremy L Thompson   op->ceed->opfallbackceed = ceedref;
2885107b09fSJeremy L Thompson 
2895107b09fSJeremy L Thompson   // Clone Op
2905107b09fSJeremy L Thompson   CeedOperator opref;
2915107b09fSJeremy L Thompson   ierr = CeedCalloc(1, &opref); CeedChk(ierr);
2925107b09fSJeremy L Thompson   memcpy(opref, op, sizeof(*opref)); CeedChk(ierr);
2935107b09fSJeremy L Thompson   opref->data = NULL;
2945107b09fSJeremy L Thompson   opref->setupdone = 0;
2955107b09fSJeremy L Thompson   opref->ceed = ceedref;
2965107b09fSJeremy L Thompson   ierr = ceedref->OperatorCreate(opref); CeedChk(ierr);
2975107b09fSJeremy L Thompson   op->opfallback = opref;
2985107b09fSJeremy L Thompson 
2995107b09fSJeremy L Thompson   // Clone QF
3005107b09fSJeremy L Thompson   CeedQFunction qfref;
3015107b09fSJeremy L Thompson   ierr = CeedCalloc(1, &qfref); CeedChk(ierr);
3025107b09fSJeremy L Thompson   memcpy(qfref, (op->qf), sizeof(*qfref)); CeedChk(ierr);
3035107b09fSJeremy L Thompson   qfref->data = NULL;
3045107b09fSJeremy L Thompson   qfref->ceed = ceedref;
3055107b09fSJeremy L Thompson   ierr = ceedref->QFunctionCreate(qfref); CeedChk(ierr);
3065107b09fSJeremy L Thompson   opref->qf = qfref;
3075107b09fSJeremy L Thompson   op->qffallback = qfref;
3085107b09fSJeremy L Thompson 
3095107b09fSJeremy L Thompson   return 0;
3105107b09fSJeremy L Thompson }
3115107b09fSJeremy L Thompson 
3125107b09fSJeremy L Thompson /**
313250756a7Sjeremylt   @brief Check if a CeedOperator is ready to be used.
314250756a7Sjeremylt 
315250756a7Sjeremylt   @param[in] ceed Ceed object for error handling
316250756a7Sjeremylt   @param[in] op   CeedOperator to check
317250756a7Sjeremylt 
318250756a7Sjeremylt   @return An error code: 0 - success, otherwise - failure
319250756a7Sjeremylt 
320250756a7Sjeremylt   @ref Basic
321250756a7Sjeremylt **/
322250756a7Sjeremylt static int CeedOperatorCheckReady(Ceed ceed, CeedOperator op) {
323250756a7Sjeremylt   CeedQFunction qf = op->qf;
324250756a7Sjeremylt 
325250756a7Sjeremylt   if (op->composite) {
326250756a7Sjeremylt     if (!op->numsub)
327250756a7Sjeremylt       // LCOV_EXCL_START
328250756a7Sjeremylt       return CeedError(ceed, 1, "No suboperators set");
329250756a7Sjeremylt     // LCOV_EXCL_STOP
330250756a7Sjeremylt   } else {
331250756a7Sjeremylt     if (op->nfields == 0)
332250756a7Sjeremylt       // LCOV_EXCL_START
333250756a7Sjeremylt       return CeedError(ceed, 1, "No operator fields set");
334250756a7Sjeremylt     // LCOV_EXCL_STOP
335250756a7Sjeremylt     if (op->nfields < qf->numinputfields + qf->numoutputfields)
336250756a7Sjeremylt       // LCOV_EXCL_START
337250756a7Sjeremylt       return CeedError(ceed, 1, "Not all operator fields set");
338250756a7Sjeremylt     // LCOV_EXCL_STOP
339250756a7Sjeremylt     if (!op->hasrestriction)
340250756a7Sjeremylt       // LCOV_EXCL_START
341250756a7Sjeremylt       return CeedError(ceed, 1,"At least one restriction required");
342250756a7Sjeremylt     // LCOV_EXCL_STOP
343250756a7Sjeremylt     if (op->numqpoints == 0)
344250756a7Sjeremylt       // LCOV_EXCL_START
345250756a7Sjeremylt       return CeedError(ceed, 1,"At least one non-collocated basis required");
346250756a7Sjeremylt     // LCOV_EXCL_STOP
347250756a7Sjeremylt   }
348250756a7Sjeremylt 
349250756a7Sjeremylt   return 0;
350250756a7Sjeremylt }
351250756a7Sjeremylt 
352250756a7Sjeremylt /**
3531d102b48SJeremy L Thompson   @brief Assemble a linear CeedQFunction associated with a CeedOperator
3541d102b48SJeremy L Thompson 
3551d102b48SJeremy L Thompson   This returns a CeedVector containing a matrix at each quadrature point
3561d102b48SJeremy L Thompson     providing the action of the CeedQFunction associated with the CeedOperator.
3571d102b48SJeremy L Thompson     The vector 'assembled' is of shape
3581d102b48SJeremy L Thompson       [num_elements, num_input_fields, num_output_fields, num_quad_points]
3591d102b48SJeremy L Thompson     and contains column-major matrices representing the action of the
3601d102b48SJeremy L Thompson     CeedQFunction for a corresponding quadrature point on an element. Inputs and
3611d102b48SJeremy L Thompson     outputs are in the order provided by the user when adding CeedOperator fields.
3621d102b48SJeremy L Thompson     For example, a QFunction with inputs 'u' and 'gradu' and outputs 'gradv' and
3631d102b48SJeremy L Thompson     'v', provided in that order, would result in an assembled QFunction that
3641d102b48SJeremy L Thompson     consists of (1 + dim) x (dim + 1) matrices at each quadrature point acting
3651d102b48SJeremy L Thompson     on the input [u, du_0, du_1] and producing the output [dv_0, dv_1, v].
3661d102b48SJeremy L Thompson 
3671d102b48SJeremy L Thompson   @param op             CeedOperator to assemble CeedQFunction
3681d102b48SJeremy L Thompson   @param[out] assembled CeedVector to store assembled CeedQFunction at
3691d102b48SJeremy L Thompson                           quadrature points
3701d102b48SJeremy L Thompson   @param[out] rstr      CeedElemRestriction for CeedVector containing assembled
3711d102b48SJeremy L Thompson                           CeedQFunction
3721d102b48SJeremy L Thompson   @param request        Address of CeedRequest for non-blocking completion, else
3731d102b48SJeremy L Thompson                           CEED_REQUEST_IMMEDIATE
3741d102b48SJeremy L Thompson 
3751d102b48SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
3761d102b48SJeremy L Thompson 
377b7ec98d8SJeremy L Thompson   @ref Basic
3781d102b48SJeremy L Thompson **/
3791d102b48SJeremy L Thompson int CeedOperatorAssembleLinearQFunction(CeedOperator op, CeedVector *assembled,
3807f823360Sjeremylt                                         CeedElemRestriction *rstr,
3817f823360Sjeremylt                                         CeedRequest *request) {
3821d102b48SJeremy L Thompson   int ierr;
3831d102b48SJeremy L Thompson   Ceed ceed = op->ceed;
384250756a7Sjeremylt   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
3851d102b48SJeremy L Thompson 
3865107b09fSJeremy L Thompson   if (op->AssembleLinearQFunction) {
3871d102b48SJeremy L Thompson     ierr = op->AssembleLinearQFunction(op, assembled, rstr, request);
3881d102b48SJeremy L Thompson     CeedChk(ierr);
3895107b09fSJeremy L Thompson   } else {
3905107b09fSJeremy L Thompson     // Fallback to reference Ceed
3915107b09fSJeremy L Thompson     if (!op->opfallback) {
3925107b09fSJeremy L Thompson       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
3935107b09fSJeremy L Thompson     }
3945107b09fSJeremy L Thompson     // Assemble
3955107b09fSJeremy L Thompson     ierr = op->opfallback->AssembleLinearQFunction(op->opfallback, assembled,
3965107b09fSJeremy L Thompson            rstr, request); CeedChk(ierr);
3975107b09fSJeremy L Thompson   }
398250756a7Sjeremylt 
3991d102b48SJeremy L Thompson   return 0;
4001d102b48SJeremy L Thompson }
4011d102b48SJeremy L Thompson 
4021d102b48SJeremy L Thompson /**
403b7ec98d8SJeremy L Thompson   @brief Assemble the diagonal of a square linear Operator
404b7ec98d8SJeremy L Thompson 
405b7ec98d8SJeremy L Thompson   This returns a CeedVector containing the diagonal of a linear CeedOperator.
406b7ec98d8SJeremy L Thompson 
407b7ec98d8SJeremy L Thompson   @param op             CeedOperator to assemble CeedQFunction
408b7ec98d8SJeremy L Thompson   @param[out] assembled CeedVector to store assembled CeedOperator diagonal
409b7ec98d8SJeremy L Thompson   @param request        Address of CeedRequest for non-blocking completion, else
410b7ec98d8SJeremy L Thompson                           CEED_REQUEST_IMMEDIATE
411b7ec98d8SJeremy L Thompson 
412b7ec98d8SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
413b7ec98d8SJeremy L Thompson 
414b7ec98d8SJeremy L Thompson   @ref Basic
415b7ec98d8SJeremy L Thompson **/
4167f823360Sjeremylt int CeedOperatorAssembleLinearDiagonal(CeedOperator op, CeedVector *assembled,
4177f823360Sjeremylt                                        CeedRequest *request) {
418b7ec98d8SJeremy L Thompson   int ierr;
419b7ec98d8SJeremy L Thompson   Ceed ceed = op->ceed;
420250756a7Sjeremylt   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
421b7ec98d8SJeremy L Thompson 
422b7ec98d8SJeremy L Thompson   // Use backend version, if available
423b7ec98d8SJeremy L Thompson   if (op->AssembleLinearDiagonal) {
424b7ec98d8SJeremy L Thompson     ierr = op->AssembleLinearDiagonal(op, assembled, request); CeedChk(ierr);
425b7ec98d8SJeremy L Thompson     return 0;
426b7ec98d8SJeremy L Thompson   }
427b7ec98d8SJeremy L Thompson 
428b7ec98d8SJeremy L Thompson   // Assemble QFunction
429250756a7Sjeremylt   CeedQFunction qf = op->qf;
430b7ec98d8SJeremy L Thompson   CeedVector assembledqf;
431b7ec98d8SJeremy L Thompson   CeedElemRestriction rstr;
432b7ec98d8SJeremy L Thompson   ierr = CeedOperatorAssembleLinearQFunction(op,  &assembledqf, &rstr, request);
433b7ec98d8SJeremy L Thompson   CeedChk(ierr);
434b7ec98d8SJeremy L Thompson   ierr = CeedElemRestrictionDestroy(&rstr); CeedChk(ierr);
435b7ec98d8SJeremy L Thompson 
436b7ec98d8SJeremy L Thompson   // Determine active input basis
437112e3f70Sjeremylt   CeedInt numemodein = 0, ncomp, dim = 1;
438b7ec98d8SJeremy L Thompson   CeedEvalMode *emodein = NULL;
439112e3f70Sjeremylt   CeedBasis basisin = NULL;
440112e3f70Sjeremylt   CeedElemRestriction rstrin = NULL;
441b7ec98d8SJeremy L Thompson   for (CeedInt i=0; i<qf->numinputfields; i++)
442b7ec98d8SJeremy L Thompson     if (op->inputfields[i]->vec == CEED_VECTOR_ACTIVE) {
443b7ec98d8SJeremy L Thompson       ierr = CeedOperatorFieldGetBasis(op->inputfields[i], &basisin);
444b7ec98d8SJeremy L Thompson       CeedChk(ierr);
445b7ec98d8SJeremy L Thompson       ierr = CeedBasisGetNumComponents(basisin, &ncomp); CeedChk(ierr);
446b7ec98d8SJeremy L Thompson       ierr = CeedBasisGetDimension(basisin, &dim); CeedChk(ierr);
447b7ec98d8SJeremy L Thompson       ierr = CeedOperatorFieldGetElemRestriction(op->inputfields[i], &rstrin);
448b7ec98d8SJeremy L Thompson       CeedChk(ierr);
449b7ec98d8SJeremy L Thompson       CeedEvalMode emode;
450b7ec98d8SJeremy L Thompson       ierr = CeedQFunctionFieldGetEvalMode(qf->inputfields[i], &emode);
451b7ec98d8SJeremy L Thompson       CeedChk(ierr);
452b7ec98d8SJeremy L Thompson       switch (emode) {
453b7ec98d8SJeremy L Thompson       case CEED_EVAL_NONE:
454b7ec98d8SJeremy L Thompson       case CEED_EVAL_INTERP:
455b7ec98d8SJeremy L Thompson         ierr = CeedRealloc(numemodein + 1, &emodein); CeedChk(ierr);
456b7ec98d8SJeremy L Thompson         emodein[numemodein] = emode;
457b7ec98d8SJeremy L Thompson         numemodein += 1;
458b7ec98d8SJeremy L Thompson         break;
459b7ec98d8SJeremy L Thompson       case CEED_EVAL_GRAD:
460b7ec98d8SJeremy L Thompson         ierr = CeedRealloc(numemodein + dim, &emodein); CeedChk(ierr);
461b7ec98d8SJeremy L Thompson         for (CeedInt d=0; d<dim; d++)
462b7ec98d8SJeremy L Thompson           emodein[numemodein+d] = emode;
463b7ec98d8SJeremy L Thompson         numemodein += dim;
464b7ec98d8SJeremy L Thompson         break;
465b7ec98d8SJeremy L Thompson       case CEED_EVAL_WEIGHT:
466b7ec98d8SJeremy L Thompson       case CEED_EVAL_DIV:
467b7ec98d8SJeremy L Thompson       case CEED_EVAL_CURL:
468b7ec98d8SJeremy L Thompson         break; // Caught by QF Assembly
469b7ec98d8SJeremy L Thompson       }
470b7ec98d8SJeremy L Thompson     }
471b7ec98d8SJeremy L Thompson 
472b7ec98d8SJeremy L Thompson   // Determine active output basis
473b7ec98d8SJeremy L Thompson   CeedInt numemodeout = 0;
474b7ec98d8SJeremy L Thompson   CeedEvalMode *emodeout = NULL;
475112e3f70Sjeremylt   CeedBasis basisout = NULL;
476112e3f70Sjeremylt   CeedElemRestriction rstrout = NULL;
477112e3f70Sjeremylt   CeedTransposeMode lmodeout = CEED_NOTRANSPOSE;
478b7ec98d8SJeremy L Thompson   for (CeedInt i=0; i<qf->numoutputfields; i++)
479b7ec98d8SJeremy L Thompson     if (op->outputfields[i]->vec == CEED_VECTOR_ACTIVE) {
480b7ec98d8SJeremy L Thompson       ierr = CeedOperatorFieldGetBasis(op->outputfields[i], &basisout);
481b7ec98d8SJeremy L Thompson       CeedChk(ierr);
482b7ec98d8SJeremy L Thompson       ierr = CeedOperatorFieldGetElemRestriction(op->outputfields[i], &rstrout);
483b7ec98d8SJeremy L Thompson       CeedChk(ierr);
484b7ec98d8SJeremy L Thompson       ierr = CeedOperatorFieldGetLMode(op->outputfields[i], &lmodeout);
485b7ec98d8SJeremy L Thompson       CeedChk(ierr);
486b7ec98d8SJeremy L Thompson       CeedEvalMode emode;
487b7ec98d8SJeremy L Thompson       ierr = CeedQFunctionFieldGetEvalMode(qf->outputfields[i], &emode);
488b7ec98d8SJeremy L Thompson       CeedChk(ierr);
489b7ec98d8SJeremy L Thompson       switch (emode) {
490b7ec98d8SJeremy L Thompson       case CEED_EVAL_NONE:
491b7ec98d8SJeremy L Thompson       case CEED_EVAL_INTERP:
492b7ec98d8SJeremy L Thompson         ierr = CeedRealloc(numemodeout + 1, &emodeout); CeedChk(ierr);
493b7ec98d8SJeremy L Thompson         emodeout[numemodeout] = emode;
494b7ec98d8SJeremy L Thompson         numemodeout += 1;
495b7ec98d8SJeremy L Thompson         break;
496b7ec98d8SJeremy L Thompson       case CEED_EVAL_GRAD:
497b7ec98d8SJeremy L Thompson         ierr = CeedRealloc(numemodeout + dim, &emodeout); CeedChk(ierr);
498b7ec98d8SJeremy L Thompson         for (CeedInt d=0; d<dim; d++)
499b7ec98d8SJeremy L Thompson           emodeout[numemodeout+d] = emode;
500b7ec98d8SJeremy L Thompson         numemodeout += dim;
501b7ec98d8SJeremy L Thompson         break;
502b7ec98d8SJeremy L Thompson       case CEED_EVAL_WEIGHT:
503b7ec98d8SJeremy L Thompson       case CEED_EVAL_DIV:
504b7ec98d8SJeremy L Thompson       case CEED_EVAL_CURL:
505b7ec98d8SJeremy L Thompson         break; // Caught by QF Assembly
506b7ec98d8SJeremy L Thompson       }
507b7ec98d8SJeremy L Thompson     }
508b7ec98d8SJeremy L Thompson 
509b7ec98d8SJeremy L Thompson   // Create diagonal vector
510b7ec98d8SJeremy L Thompson   CeedVector elemdiag;
511b7ec98d8SJeremy L Thompson   ierr = CeedElemRestrictionCreateVector(rstrin, assembled, &elemdiag);
512b7ec98d8SJeremy L Thompson   CeedChk(ierr);
513b7ec98d8SJeremy L Thompson 
514b7ec98d8SJeremy L Thompson   // Assemble element operator diagonals
515b7ec98d8SJeremy L Thompson   CeedScalar *elemdiagarray, *assembledqfarray;
516b7ec98d8SJeremy L Thompson   ierr = CeedVectorSetValue(elemdiag, 0.0); CeedChk(ierr);
517b7ec98d8SJeremy L Thompson   ierr = CeedVectorGetArray(elemdiag, CEED_MEM_HOST, &elemdiagarray);
518b7ec98d8SJeremy L Thompson   CeedChk(ierr);
519b7ec98d8SJeremy L Thompson   ierr = CeedVectorGetArray(assembledqf, CEED_MEM_HOST, &assembledqfarray);
520b7ec98d8SJeremy L Thompson   CeedChk(ierr);
521b7ec98d8SJeremy L Thompson   CeedInt nelem, nnodes, nqpts;
522b7ec98d8SJeremy L Thompson   ierr = CeedElemRestrictionGetNumElements(rstrin, &nelem); CeedChk(ierr);
523b7ec98d8SJeremy L Thompson   ierr = CeedBasisGetNumNodes(basisin, &nnodes); CeedChk(ierr);
524b7ec98d8SJeremy L Thompson   ierr = CeedBasisGetNumQuadraturePoints(basisin, &nqpts); CeedChk(ierr);
525b7ec98d8SJeremy L Thompson   // Compute the diagonal of B^T D B
526b7ec98d8SJeremy L Thompson   // Each node, qpt pair
527b7ec98d8SJeremy L Thompson   for (CeedInt n=0; n<nnodes; n++)
528b7ec98d8SJeremy L Thompson     for (CeedInt q=0; q<nqpts; q++) {
529b7ec98d8SJeremy L Thompson       CeedInt dout = -1;
530b7ec98d8SJeremy L Thompson       // Each basis eval mode pair
531b7ec98d8SJeremy L Thompson       for (CeedInt eout=0; eout<numemodeout; eout++) {
532b7ec98d8SJeremy L Thompson         CeedScalar bt = 1.0;
533b7ec98d8SJeremy L Thompson         if (emodeout[eout] == CEED_EVAL_GRAD)
534b7ec98d8SJeremy L Thompson           dout += 1;
535b7ec98d8SJeremy L Thompson         ierr = CeedBasisGetValue(basisout, emodeout[eout], q, n, dout, &bt);
536b7ec98d8SJeremy L Thompson         CeedChk(ierr);
537b7ec98d8SJeremy L Thompson         CeedInt din = -1;
538b7ec98d8SJeremy L Thompson         for (CeedInt ein=0; ein<numemodein; ein++) {
539b7ec98d8SJeremy L Thompson           CeedScalar b = 0.0;
540b7ec98d8SJeremy L Thompson           if (emodein[ein] == CEED_EVAL_GRAD)
541b7ec98d8SJeremy L Thompson             din += 1;
542b7ec98d8SJeremy L Thompson           ierr = CeedBasisGetValue(basisin, emodein[ein], q, n, din, &b);
543b7ec98d8SJeremy L Thompson           CeedChk(ierr);
544b7ec98d8SJeremy L Thompson           // Each element and component
545b7ec98d8SJeremy L Thompson           for (CeedInt e=0; e<nelem; e++)
546b7ec98d8SJeremy L Thompson             for (CeedInt cout=0; cout<ncomp; cout++) {
547b7ec98d8SJeremy L Thompson               CeedScalar db = 0.0;
548b7ec98d8SJeremy L Thompson               for (CeedInt cin=0; cin<ncomp; cin++)
549b7ec98d8SJeremy L Thompson                 db += assembledqfarray[((((e*numemodein+ein)*ncomp+cin)*
550b7ec98d8SJeremy L Thompson                                          numemodeout+eout)*ncomp+cout)*nqpts+q]*b;
551b7ec98d8SJeremy L Thompson               elemdiagarray[(e*ncomp+cout)*nnodes+n] += bt * db;
552b7ec98d8SJeremy L Thompson             }
553b7ec98d8SJeremy L Thompson         }
554b7ec98d8SJeremy L Thompson       }
555b7ec98d8SJeremy L Thompson     }
556b7ec98d8SJeremy L Thompson 
557b7ec98d8SJeremy L Thompson   ierr = CeedVectorRestoreArray(elemdiag, &elemdiagarray); CeedChk(ierr);
558b7ec98d8SJeremy L Thompson   ierr = CeedVectorRestoreArray(assembledqf, &assembledqfarray); CeedChk(ierr);
559b7ec98d8SJeremy L Thompson 
560b7ec98d8SJeremy L Thompson   // Assemble local operator diagonal
561b7ec98d8SJeremy L Thompson   ierr = CeedVectorSetValue(*assembled, 0.0); CeedChk(ierr);
562b7ec98d8SJeremy L Thompson   ierr = CeedElemRestrictionApply(rstrout, CEED_TRANSPOSE, lmodeout, elemdiag,
563b7ec98d8SJeremy L Thompson                                   *assembled, request); CeedChk(ierr);
564b7ec98d8SJeremy L Thompson 
565b7ec98d8SJeremy L Thompson   // Cleanup
566b7ec98d8SJeremy L Thompson   ierr = CeedVectorDestroy(&assembledqf); CeedChk(ierr);
567b7ec98d8SJeremy L Thompson   ierr = CeedVectorDestroy(&elemdiag); CeedChk(ierr);
568b7ec98d8SJeremy L Thompson   ierr = CeedFree(&emodein); CeedChk(ierr);
569b7ec98d8SJeremy L Thompson   ierr = CeedFree(&emodeout); CeedChk(ierr);
570b7ec98d8SJeremy L Thompson 
571b7ec98d8SJeremy L Thompson   return 0;
572b7ec98d8SJeremy L Thompson }
573b7ec98d8SJeremy L Thompson 
574b7ec98d8SJeremy L Thompson /**
575*3bd813ffSjeremylt   @brief Build a FDM based approximate inverse for each element for a
576*3bd813ffSjeremylt            CeedOperator
577*3bd813ffSjeremylt 
578*3bd813ffSjeremylt   This returns a CeedOperator and CeedVector to apply a Fast Diagonalization
579*3bd813ffSjeremylt     Method based approximate inverse. This function obtains the simultaneous
580*3bd813ffSjeremylt     diagonalization for the 1D mass and Laplacian operators,
581*3bd813ffSjeremylt       M = V^T V, K = V^T S V.
582*3bd813ffSjeremylt     The assembled QFunction is used to modify the eigenvalues from simultaneous
583*3bd813ffSjeremylt     diagonalization and obtain an approximate inverse of the form
584*3bd813ffSjeremylt       V^T S^hat V. The CeedOperator must be linear and non-composite. The
585*3bd813ffSjeremylt     associated CeedQFunction must therefore also be linear.
586*3bd813ffSjeremylt 
587*3bd813ffSjeremylt   @param op             CeedOperator to create element inverses
588*3bd813ffSjeremylt   @param[out] fdminv    CeedOperator to apply the action of a FDM based inverse
589*3bd813ffSjeremylt                           for each element
590*3bd813ffSjeremylt   @param[out] qdata     CeedVector to hold qdata for fdminv
591*3bd813ffSjeremylt   @param request        Address of CeedRequest for non-blocking completion, else
592*3bd813ffSjeremylt                           CEED_REQUEST_IMMEDIATE
593*3bd813ffSjeremylt 
594*3bd813ffSjeremylt   @return An error code: 0 - success, otherwise - failure
595*3bd813ffSjeremylt 
596*3bd813ffSjeremylt   @ref Advanced
597*3bd813ffSjeremylt **/
598*3bd813ffSjeremylt int CeedOperatorCreateFDMElementInverse(CeedOperator op, CeedOperator *fdminv,
599*3bd813ffSjeremylt     CeedRequest *request) {
600*3bd813ffSjeremylt   int ierr;
601*3bd813ffSjeremylt   Ceed ceed = op->ceed;
602*3bd813ffSjeremylt 
603*3bd813ffSjeremylt   // Determine active input basis
604*3bd813ffSjeremylt   bool interp = false, grad = false;
605*3bd813ffSjeremylt   CeedBasis basis = NULL;
606*3bd813ffSjeremylt   CeedElemRestriction rstr = NULL;
607*3bd813ffSjeremylt   for (CeedInt i=0; i<op->qf->numinputfields; i++)
608*3bd813ffSjeremylt     if (op->inputfields[i] && op->inputfields[i]->vec == CEED_VECTOR_ACTIVE) {
609*3bd813ffSjeremylt       basis = op->inputfields[i]->basis;
610*3bd813ffSjeremylt       interp = interp || op->qf->inputfields[i]->emode == CEED_EVAL_INTERP;
611*3bd813ffSjeremylt       grad = grad || op->qf->inputfields[i]->emode == CEED_EVAL_GRAD;
612*3bd813ffSjeremylt       rstr = op->inputfields[i]->Erestrict;
613*3bd813ffSjeremylt     }
614*3bd813ffSjeremylt   if (!basis)
615*3bd813ffSjeremylt     return CeedError(ceed, 1, "No active field set");
616*3bd813ffSjeremylt   CeedInt P1d, Q1d, elemsize, nqpts, dim, ncomp = 1, nelem = 1, nnodes = 1;
617*3bd813ffSjeremylt   ierr = CeedBasisGetNumNodes1D(basis, &P1d); CeedChk(ierr);
618*3bd813ffSjeremylt   ierr = CeedBasisGetNumNodes(basis, &elemsize); CeedChk(ierr);
619*3bd813ffSjeremylt   ierr = CeedBasisGetNumQuadraturePoints1D(basis, &Q1d); CeedChk(ierr);
620*3bd813ffSjeremylt   ierr = CeedBasisGetNumQuadraturePoints(basis, &nqpts); CeedChk(ierr);
621*3bd813ffSjeremylt   ierr = CeedBasisGetDimension(basis, &dim); CeedChk(ierr);
622*3bd813ffSjeremylt   ierr = CeedBasisGetNumComponents(basis, &ncomp); CeedChk(ierr);
623*3bd813ffSjeremylt   ierr = CeedElemRestrictionGetNumElements(rstr, &nelem); CeedChk(ierr);
624*3bd813ffSjeremylt   ierr = CeedElemRestrictionGetNumNodes(rstr, &nnodes); CeedChk(ierr);
625*3bd813ffSjeremylt 
626*3bd813ffSjeremylt   // Build and diagonalize 1D Mass and Laplacian
627*3bd813ffSjeremylt   if (!basis->tensorbasis)
628*3bd813ffSjeremylt     return CeedError(ceed, 1, "FDMElementInverse only supported for tensor "
629*3bd813ffSjeremylt                      "bases");
630*3bd813ffSjeremylt   CeedScalar *work, *mass, *laplace, *x, *x2, *lambda;
631*3bd813ffSjeremylt   ierr = CeedMalloc(Q1d*P1d, &work); CeedChk(ierr);
632*3bd813ffSjeremylt   ierr = CeedMalloc(P1d*P1d, &mass); CeedChk(ierr);
633*3bd813ffSjeremylt   ierr = CeedMalloc(P1d*P1d, &laplace); CeedChk(ierr);
634*3bd813ffSjeremylt   ierr = CeedMalloc(P1d*P1d, &x); CeedChk(ierr);
635*3bd813ffSjeremylt   ierr = CeedMalloc(P1d*P1d, &x2); CeedChk(ierr);
636*3bd813ffSjeremylt   ierr = CeedMalloc(P1d, &lambda); CeedChk(ierr);
637*3bd813ffSjeremylt   // -- Mass
638*3bd813ffSjeremylt   for (CeedInt i=0; i<Q1d; i++)
639*3bd813ffSjeremylt     for (CeedInt j=0; j<P1d; j++)
640*3bd813ffSjeremylt       work[i+j*Q1d] = basis->interp1d[i*P1d+j]*basis->qweight1d[i];
641*3bd813ffSjeremylt   ierr = CeedMatrixMultiply(ceed, work, basis->interp1d, mass, P1d, P1d, Q1d);
642*3bd813ffSjeremylt   CeedChk(ierr);
643*3bd813ffSjeremylt   // -- Laplacian
644*3bd813ffSjeremylt   for (CeedInt i=0; i<Q1d; i++)
645*3bd813ffSjeremylt     for (CeedInt j=0; j<P1d; j++)
646*3bd813ffSjeremylt       work[i+j*Q1d] = basis->grad1d[i*P1d+j]*basis->qweight1d[i];
647*3bd813ffSjeremylt   ierr = CeedMatrixMultiply(ceed, work, basis->grad1d, laplace, P1d, P1d, Q1d);
648*3bd813ffSjeremylt   CeedChk(ierr);
649*3bd813ffSjeremylt   // -- Diagonalize
650*3bd813ffSjeremylt   ierr = CeedSimultaneousDiagonalization(ceed, laplace, mass, x, lambda, P1d);
651*3bd813ffSjeremylt   CeedChk(ierr);
652*3bd813ffSjeremylt   ierr = CeedFree(&work); CeedChk(ierr);
653*3bd813ffSjeremylt   ierr = CeedFree(&mass); CeedChk(ierr);
654*3bd813ffSjeremylt   ierr = CeedFree(&laplace); CeedChk(ierr);
655*3bd813ffSjeremylt   for (CeedInt i=0; i<P1d; i++)
656*3bd813ffSjeremylt     for (CeedInt j=0; j<P1d; j++)
657*3bd813ffSjeremylt     x2[i+j*P1d] = x[j+i*P1d];
658*3bd813ffSjeremylt   ierr = CeedFree(&x); CeedChk(ierr);
659*3bd813ffSjeremylt 
660*3bd813ffSjeremylt   // Assemble QFunction
661*3bd813ffSjeremylt   CeedVector assembled;
662*3bd813ffSjeremylt   CeedElemRestriction rstr_qf;
663*3bd813ffSjeremylt   ierr =  CeedOperatorAssembleLinearQFunction(op, &assembled, &rstr_qf,
664*3bd813ffSjeremylt                                               request); CeedChk(ierr);
665*3bd813ffSjeremylt   ierr = CeedElemRestrictionDestroy(&rstr_qf); CeedChk(ierr);
666*3bd813ffSjeremylt 
667*3bd813ffSjeremylt   // Calculate element averages
668*3bd813ffSjeremylt   CeedInt nfields = ((interp?1:0) + (grad?dim:0))*((interp?1:0) + (grad?dim:0));
669*3bd813ffSjeremylt   CeedScalar *elemavg;
670*3bd813ffSjeremylt   const CeedScalar *assembledarray, *qweightsarray;
671*3bd813ffSjeremylt   CeedVector qweights;
672*3bd813ffSjeremylt   ierr = CeedVectorCreate(ceed, nqpts, &qweights); CeedChk(ierr);
673*3bd813ffSjeremylt   ierr = CeedBasisApply(basis, 1, CEED_NOTRANSPOSE, CEED_EVAL_WEIGHT,
674*3bd813ffSjeremylt                         CEED_VECTOR_NONE, qweights); CeedChk(ierr);
675*3bd813ffSjeremylt   ierr = CeedVectorGetArrayRead(assembled, CEED_MEM_HOST, &assembledarray);
676*3bd813ffSjeremylt   CeedChk(ierr);
677*3bd813ffSjeremylt   ierr = CeedVectorGetArrayRead(qweights, CEED_MEM_HOST, &qweightsarray);
678*3bd813ffSjeremylt   CeedChk(ierr);
679*3bd813ffSjeremylt   ierr = CeedCalloc(nelem, &elemavg); CeedChk(ierr);
680*3bd813ffSjeremylt   for (CeedInt e=0; e<nelem; e++) {
681*3bd813ffSjeremylt     CeedInt count = 0;
682*3bd813ffSjeremylt       for (CeedInt q=0; q<nqpts; q++)
683*3bd813ffSjeremylt         for (CeedInt i=0; i<ncomp*ncomp*nfields; i++)
684*3bd813ffSjeremylt           if (fabs(assembledarray[e*nelem*nqpts*ncomp*ncomp*nfields +
685*3bd813ffSjeremylt                                   i*nqpts + q]) > 1e-15) {
686*3bd813ffSjeremylt             elemavg[e] += assembledarray[e*nelem*nqpts*ncomp*ncomp*nfields +
687*3bd813ffSjeremylt                                          i*nqpts + q] / qweightsarray[q];
688*3bd813ffSjeremylt             count++;
689*3bd813ffSjeremylt           }
690*3bd813ffSjeremylt     if (count)
691*3bd813ffSjeremylt       elemavg[e] /= count;
692*3bd813ffSjeremylt   }
693*3bd813ffSjeremylt   ierr = CeedVectorRestoreArrayRead(assembled, &assembledarray); CeedChk(ierr);
694*3bd813ffSjeremylt   ierr = CeedVectorDestroy(&assembled); CeedChk(ierr);
695*3bd813ffSjeremylt   ierr = CeedVectorRestoreArrayRead(qweights, &qweightsarray); CeedChk(ierr);
696*3bd813ffSjeremylt   ierr = CeedVectorDestroy(&qweights); CeedChk(ierr);
697*3bd813ffSjeremylt 
698*3bd813ffSjeremylt   // Build FDM diagonal
699*3bd813ffSjeremylt   CeedVector qdata;
700*3bd813ffSjeremylt   CeedScalar *qdataarray;
701*3bd813ffSjeremylt   ierr = CeedVectorCreate(ceed, nelem*ncomp*nnodes, &qdata); CeedChk(ierr);
702*3bd813ffSjeremylt   ierr = CeedVectorSetArray(qdata, CEED_MEM_HOST, CEED_COPY_VALUES, NULL);
703*3bd813ffSjeremylt   CeedChk(ierr);
704*3bd813ffSjeremylt   ierr = CeedVectorGetArray(qdata, CEED_MEM_HOST, &qdataarray); CeedChk(ierr);
705*3bd813ffSjeremylt   for (CeedInt e=0; e<nelem; e++)
706*3bd813ffSjeremylt     for (CeedInt c=0; c<ncomp; c++)
707*3bd813ffSjeremylt       for (CeedInt n=0; n<nnodes; n++) {
708*3bd813ffSjeremylt         if (interp)
709*3bd813ffSjeremylt           qdataarray[(e*ncomp+c)*nnodes+n] = 1;
710*3bd813ffSjeremylt         if (grad)
711*3bd813ffSjeremylt           for (CeedInt d=0; d<dim; d++) {
712*3bd813ffSjeremylt             CeedInt i = (n / CeedIntPow(P1d, d)) % P1d;
713*3bd813ffSjeremylt             qdataarray[(e*ncomp+c)*nnodes+n] += lambda[i];
714*3bd813ffSjeremylt           }
715*3bd813ffSjeremylt         qdataarray[(e*ncomp+c)*nnodes+n] = 1 / (elemavg[e] *
716*3bd813ffSjeremylt                                            qdataarray[(e*ncomp+c)*nnodes+n]);
717*3bd813ffSjeremylt       }
718*3bd813ffSjeremylt   ierr = CeedFree(&elemavg); CeedChk(ierr);
719*3bd813ffSjeremylt   ierr = CeedVectorRestoreArray(qdata, &qdataarray); CeedChk(ierr);
720*3bd813ffSjeremylt 
721*3bd813ffSjeremylt   // Setup FDM operator
722*3bd813ffSjeremylt   // -- Basis
723*3bd813ffSjeremylt   CeedBasis fdm_basis;
724*3bd813ffSjeremylt   CeedScalar *graddummy, *qrefdummy, *qweightdummy;
725*3bd813ffSjeremylt   ierr = CeedCalloc(P1d*P1d, &graddummy); CeedChk(ierr);
726*3bd813ffSjeremylt   ierr = CeedCalloc(P1d, &qrefdummy); CeedChk(ierr);
727*3bd813ffSjeremylt   ierr = CeedCalloc(P1d, &qweightdummy); CeedChk(ierr);
728*3bd813ffSjeremylt   ierr = CeedBasisCreateTensorH1(ceed, dim, ncomp, P1d, P1d, x2, graddummy,
729*3bd813ffSjeremylt                                  qrefdummy, qweightdummy, &fdm_basis);
730*3bd813ffSjeremylt   CeedChk(ierr);
731*3bd813ffSjeremylt   ierr = CeedFree(&graddummy); CeedChk(ierr);
732*3bd813ffSjeremylt   ierr = CeedFree(&qrefdummy); CeedChk(ierr);
733*3bd813ffSjeremylt   ierr = CeedFree(&qweightdummy); CeedChk(ierr);
734*3bd813ffSjeremylt   ierr = CeedFree(&x2); CeedChk(ierr);
735*3bd813ffSjeremylt   ierr = CeedFree(&lambda); CeedChk(ierr);
736*3bd813ffSjeremylt 
737*3bd813ffSjeremylt   // -- Restriction
738*3bd813ffSjeremylt   CeedElemRestriction rstr_i;
739*3bd813ffSjeremylt   ierr = CeedElemRestrictionCreateIdentity(ceed, nelem, nnodes, nnodes*nelem,
740*3bd813ffSjeremylt                                            ncomp, &rstr_i); CeedChk(ierr);
741*3bd813ffSjeremylt   // -- QFunction
742*3bd813ffSjeremylt   CeedQFunction mass_qf;
743*3bd813ffSjeremylt   ierr = CeedQFunctionCreateInteriorByName(ceed, "MassApply", &mass_qf);
744*3bd813ffSjeremylt   CeedChk(ierr);
745*3bd813ffSjeremylt   // -- Operator
746*3bd813ffSjeremylt   ierr = CeedOperatorCreate(ceed, mass_qf, NULL, NULL, fdminv); CeedChk(ierr);
747*3bd813ffSjeremylt   CeedOperatorSetField(*fdminv, "u", rstr_i, CEED_NOTRANSPOSE,
748*3bd813ffSjeremylt                        fdm_basis, CEED_VECTOR_ACTIVE); CeedChk(ierr);
749*3bd813ffSjeremylt   CeedOperatorSetField(*fdminv, "qdata", rstr_i, CEED_NOTRANSPOSE,
750*3bd813ffSjeremylt                        CEED_BASIS_COLLOCATED, qdata); CeedChk(ierr);
751*3bd813ffSjeremylt   CeedOperatorSetField(*fdminv, "v", rstr_i, CEED_NOTRANSPOSE,
752*3bd813ffSjeremylt                        fdm_basis, CEED_VECTOR_ACTIVE); CeedChk(ierr);
753*3bd813ffSjeremylt 
754*3bd813ffSjeremylt   // Cleanup
755*3bd813ffSjeremylt   ierr = CeedVectorDestroy(&qdata); CeedChk(ierr);
756*3bd813ffSjeremylt   ierr = CeedBasisDestroy(&fdm_basis); CeedChk(ierr);
757*3bd813ffSjeremylt   ierr = CeedElemRestrictionDestroy(&rstr_i); CeedChk(ierr);
758*3bd813ffSjeremylt   ierr = CeedQFunctionDestroy(&mass_qf); CeedChk(ierr);
759*3bd813ffSjeremylt 
760*3bd813ffSjeremylt   return 0;
761*3bd813ffSjeremylt }
762*3bd813ffSjeremylt 
763*3bd813ffSjeremylt 
764*3bd813ffSjeremylt /**
765*3bd813ffSjeremylt   @brief Apply CeedOperator to a vector
766d7b241e6Sjeremylt 
767d7b241e6Sjeremylt   This computes the action of the operator on the specified (active) input,
768d7b241e6Sjeremylt   yielding its (active) output.  All inputs and outputs must be specified using
769d7b241e6Sjeremylt   CeedOperatorSetField().
770d7b241e6Sjeremylt 
771d7b241e6Sjeremylt   @param op        CeedOperator to apply
77234138859Sjeremylt   @param[in] in    CeedVector containing input state or CEED_VECTOR_NONE if
77334138859Sjeremylt                   there are no active inputs
774b11c1e72Sjeremylt   @param[out] out  CeedVector to store result of applying operator (must be
77534138859Sjeremylt                      distinct from @a in) or CEED_VECTOR_NONE if there are no
77634138859Sjeremylt                      active outputs
777d7b241e6Sjeremylt   @param request   Address of CeedRequest for non-blocking completion, else
778d7b241e6Sjeremylt                      CEED_REQUEST_IMMEDIATE
779b11c1e72Sjeremylt 
780b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
781dfdf5a53Sjeremylt 
782dfdf5a53Sjeremylt   @ref Basic
783b11c1e72Sjeremylt **/
784692c2638Sjeremylt int CeedOperatorApply(CeedOperator op, CeedVector in, CeedVector out,
785692c2638Sjeremylt                       CeedRequest *request) {
786d7b241e6Sjeremylt   int ierr;
787d7b241e6Sjeremylt   Ceed ceed = op->ceed;
788250756a7Sjeremylt   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
789d7b241e6Sjeremylt 
790250756a7Sjeremylt   if (op->numelements)  {
791250756a7Sjeremylt     // Standard Operator
792cae8b89aSjeremylt     if (op->Apply) {
793250756a7Sjeremylt       ierr = op->Apply(op, in, out, request); CeedChk(ierr);
794cae8b89aSjeremylt     } else {
795cae8b89aSjeremylt       // Zero all output vectors
796250756a7Sjeremylt       CeedQFunction qf = op->qf;
797cae8b89aSjeremylt       for (CeedInt i=0; i<qf->numoutputfields; i++) {
798cae8b89aSjeremylt         CeedVector vec = op->outputfields[i]->vec;
799cae8b89aSjeremylt         if (vec == CEED_VECTOR_ACTIVE)
800cae8b89aSjeremylt           vec = out;
801cae8b89aSjeremylt         if (vec != CEED_VECTOR_NONE) {
802cae8b89aSjeremylt           ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr);
803cae8b89aSjeremylt         }
804cae8b89aSjeremylt       }
805250756a7Sjeremylt       // Apply
806250756a7Sjeremylt       ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr);
807250756a7Sjeremylt     }
808250756a7Sjeremylt   } else if (op->composite) {
809250756a7Sjeremylt     // Composite Operator
810250756a7Sjeremylt     if (op->ApplyComposite) {
811250756a7Sjeremylt       ierr = op->ApplyComposite(op, in, out, request); CeedChk(ierr);
812250756a7Sjeremylt     } else {
813250756a7Sjeremylt       CeedInt numsub;
814250756a7Sjeremylt       ierr = CeedOperatorGetNumSub(op, &numsub); CeedChk(ierr);
815250756a7Sjeremylt       CeedOperator *suboperators;
816250756a7Sjeremylt       ierr = CeedOperatorGetSubList(op, &suboperators); CeedChk(ierr);
817250756a7Sjeremylt 
818250756a7Sjeremylt       // Zero all output vectors
819250756a7Sjeremylt       if (out != CEED_VECTOR_NONE) {
820cae8b89aSjeremylt         ierr = CeedVectorSetValue(out, 0.0); CeedChk(ierr);
821cae8b89aSjeremylt       }
822250756a7Sjeremylt       for (CeedInt i=0; i<numsub; i++) {
823250756a7Sjeremylt         for (CeedInt j=0; j<suboperators[i]->qf->numoutputfields; j++) {
824250756a7Sjeremylt           CeedVector vec = suboperators[i]->outputfields[j]->vec;
825250756a7Sjeremylt           if (vec != CEED_VECTOR_ACTIVE && vec != CEED_VECTOR_NONE) {
826250756a7Sjeremylt             ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr);
827250756a7Sjeremylt           }
828250756a7Sjeremylt         }
829250756a7Sjeremylt       }
830250756a7Sjeremylt       // Apply
831250756a7Sjeremylt       for (CeedInt i=0; i<op->numsub; i++) {
832250756a7Sjeremylt         ierr = CeedOperatorApplyAdd(op->suboperators[i], in, out, request);
833cae8b89aSjeremylt         CeedChk(ierr);
834cae8b89aSjeremylt       }
835cae8b89aSjeremylt     }
836250756a7Sjeremylt   }
837250756a7Sjeremylt 
838cae8b89aSjeremylt   return 0;
839cae8b89aSjeremylt }
840cae8b89aSjeremylt 
841cae8b89aSjeremylt /**
842cae8b89aSjeremylt   @brief Apply CeedOperator to a vector and add result to output vector
843cae8b89aSjeremylt 
844cae8b89aSjeremylt   This computes the action of the operator on the specified (active) input,
845cae8b89aSjeremylt   yielding its (active) output.  All inputs and outputs must be specified using
846cae8b89aSjeremylt   CeedOperatorSetField().
847cae8b89aSjeremylt 
848cae8b89aSjeremylt   @param op        CeedOperator to apply
849cae8b89aSjeremylt   @param[in] in    CeedVector containing input state or NULL if there are no
850cae8b89aSjeremylt                      active inputs
851cae8b89aSjeremylt   @param[out] out  CeedVector to sum in result of applying operator (must be
852cae8b89aSjeremylt                      distinct from @a in) or NULL if there are no active outputs
853cae8b89aSjeremylt   @param request   Address of CeedRequest for non-blocking completion, else
854cae8b89aSjeremylt                      CEED_REQUEST_IMMEDIATE
855cae8b89aSjeremylt 
856cae8b89aSjeremylt   @return An error code: 0 - success, otherwise - failure
857cae8b89aSjeremylt 
858cae8b89aSjeremylt   @ref Basic
859cae8b89aSjeremylt **/
860cae8b89aSjeremylt int CeedOperatorApplyAdd(CeedOperator op, CeedVector in, CeedVector out,
861cae8b89aSjeremylt                          CeedRequest *request) {
862cae8b89aSjeremylt   int ierr;
863cae8b89aSjeremylt   Ceed ceed = op->ceed;
864250756a7Sjeremylt   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
865cae8b89aSjeremylt 
866250756a7Sjeremylt   if (op->numelements)  {
867250756a7Sjeremylt     // Standard Operator
868250756a7Sjeremylt     ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr);
869250756a7Sjeremylt   } else if (op->composite) {
870250756a7Sjeremylt     // Composite Operator
871250756a7Sjeremylt     if (op->ApplyAddComposite) {
872250756a7Sjeremylt       ierr = op->ApplyAddComposite(op, in, out, request); CeedChk(ierr);
873cae8b89aSjeremylt     } else {
874250756a7Sjeremylt       CeedInt numsub;
875250756a7Sjeremylt       ierr = CeedOperatorGetNumSub(op, &numsub); CeedChk(ierr);
876250756a7Sjeremylt       CeedOperator *suboperators;
877250756a7Sjeremylt       ierr = CeedOperatorGetSubList(op, &suboperators); CeedChk(ierr);
878250756a7Sjeremylt 
879250756a7Sjeremylt       for (CeedInt i=0; i<numsub; i++) {
880250756a7Sjeremylt         ierr = CeedOperatorApplyAdd(suboperators[i], in, out, request);
881cae8b89aSjeremylt         CeedChk(ierr);
8821d7d2407SJeremy L Thompson       }
883250756a7Sjeremylt     }
884250756a7Sjeremylt   }
885250756a7Sjeremylt 
886d7b241e6Sjeremylt   return 0;
887d7b241e6Sjeremylt }
888d7b241e6Sjeremylt 
889d7b241e6Sjeremylt /**
8904ce2993fSjeremylt   @brief Get the Ceed associated with a CeedOperator
8914ce2993fSjeremylt 
8924ce2993fSjeremylt   @param op              CeedOperator
8934ce2993fSjeremylt   @param[out] ceed       Variable to store Ceed
8944ce2993fSjeremylt 
8954ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
8964ce2993fSjeremylt 
89723617272Sjeremylt   @ref Advanced
8984ce2993fSjeremylt **/
8994ce2993fSjeremylt 
9004ce2993fSjeremylt int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) {
9014ce2993fSjeremylt   *ceed = op->ceed;
9024ce2993fSjeremylt   return 0;
9034ce2993fSjeremylt }
9044ce2993fSjeremylt 
9054ce2993fSjeremylt /**
9064ce2993fSjeremylt   @brief Get the number of elements associated with a CeedOperator
9074ce2993fSjeremylt 
9084ce2993fSjeremylt   @param op              CeedOperator
9094ce2993fSjeremylt   @param[out] numelem    Variable to store number of elements
9104ce2993fSjeremylt 
9114ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
9124ce2993fSjeremylt 
91323617272Sjeremylt   @ref Advanced
9144ce2993fSjeremylt **/
9154ce2993fSjeremylt 
9164ce2993fSjeremylt int CeedOperatorGetNumElements(CeedOperator op, CeedInt *numelem) {
91752d6035fSJeremy L Thompson   if (op->composite)
918c042f62fSJeremy L Thompson     // LCOV_EXCL_START
91952d6035fSJeremy L Thompson     return CeedError(op->ceed, 1, "Not defined for composite operator");
920c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
92152d6035fSJeremy L Thompson 
9224ce2993fSjeremylt   *numelem = op->numelements;
9234ce2993fSjeremylt   return 0;
9244ce2993fSjeremylt }
9254ce2993fSjeremylt 
9264ce2993fSjeremylt /**
9274ce2993fSjeremylt   @brief Get the number of quadrature points associated with a CeedOperator
9284ce2993fSjeremylt 
9294ce2993fSjeremylt   @param op              CeedOperator
9304ce2993fSjeremylt   @param[out] numqpts    Variable to store vector number of quadrature points
9314ce2993fSjeremylt 
9324ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
9334ce2993fSjeremylt 
93423617272Sjeremylt   @ref Advanced
9354ce2993fSjeremylt **/
9364ce2993fSjeremylt 
9374ce2993fSjeremylt int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *numqpts) {
93852d6035fSJeremy L Thompson   if (op->composite)
939c042f62fSJeremy L Thompson     // LCOV_EXCL_START
94052d6035fSJeremy L Thompson     return CeedError(op->ceed, 1, "Not defined for composite operator");
941c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
94252d6035fSJeremy L Thompson 
9434ce2993fSjeremylt   *numqpts = op->numqpoints;
9444ce2993fSjeremylt   return 0;
9454ce2993fSjeremylt }
9464ce2993fSjeremylt 
9474ce2993fSjeremylt /**
9484ce2993fSjeremylt   @brief Get the number of arguments associated with a CeedOperator
9494ce2993fSjeremylt 
9504ce2993fSjeremylt   @param op              CeedOperator
9514ce2993fSjeremylt   @param[out] numargs    Variable to store vector number of arguments
9524ce2993fSjeremylt 
9534ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
9544ce2993fSjeremylt 
95523617272Sjeremylt   @ref Advanced
9564ce2993fSjeremylt **/
9574ce2993fSjeremylt 
9584ce2993fSjeremylt int CeedOperatorGetNumArgs(CeedOperator op, CeedInt *numargs) {
95952d6035fSJeremy L Thompson   if (op->composite)
960c042f62fSJeremy L Thompson     // LCOV_EXCL_START
96152d6035fSJeremy L Thompson     return CeedError(op->ceed, 1, "Not defined for composite operators");
962c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
963c042f62fSJeremy L Thompson 
9644ce2993fSjeremylt   *numargs = op->nfields;
9654ce2993fSjeremylt   return 0;
9664ce2993fSjeremylt }
9674ce2993fSjeremylt 
9684ce2993fSjeremylt /**
9694ce2993fSjeremylt   @brief Get the setup status of a CeedOperator
9704ce2993fSjeremylt 
9714ce2993fSjeremylt   @param op             CeedOperator
972288c0443SJeremy L Thompson   @param[out] setupdone Variable to store setup status
9734ce2993fSjeremylt 
9744ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
9754ce2993fSjeremylt 
97623617272Sjeremylt   @ref Advanced
9774ce2993fSjeremylt **/
9784ce2993fSjeremylt 
9794ce2993fSjeremylt int CeedOperatorGetSetupStatus(CeedOperator op, bool *setupdone) {
9804ce2993fSjeremylt   *setupdone = op->setupdone;
9814ce2993fSjeremylt   return 0;
9824ce2993fSjeremylt }
9834ce2993fSjeremylt 
9844ce2993fSjeremylt /**
9854ce2993fSjeremylt   @brief Get the QFunction associated with a CeedOperator
9864ce2993fSjeremylt 
9874ce2993fSjeremylt   @param op              CeedOperator
9888c91a0c9SJeremy L Thompson   @param[out] qf         Variable to store QFunction
9894ce2993fSjeremylt 
9904ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
9914ce2993fSjeremylt 
99223617272Sjeremylt   @ref Advanced
9934ce2993fSjeremylt **/
9944ce2993fSjeremylt 
9954ce2993fSjeremylt int CeedOperatorGetQFunction(CeedOperator op, CeedQFunction *qf) {
99652d6035fSJeremy L Thompson   if (op->composite)
997c042f62fSJeremy L Thompson     // LCOV_EXCL_START
99852d6035fSJeremy L Thompson     return CeedError(op->ceed, 1, "Not defined for composite operator");
999c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
100052d6035fSJeremy L Thompson 
10014ce2993fSjeremylt   *qf = op->qf;
10024ce2993fSjeremylt   return 0;
10034ce2993fSjeremylt }
10044ce2993fSjeremylt 
10054ce2993fSjeremylt /**
100652d6035fSJeremy L Thompson   @brief Get the number of suboperators associated with a CeedOperator
100752d6035fSJeremy L Thompson 
100852d6035fSJeremy L Thompson   @param op              CeedOperator
100952d6035fSJeremy L Thompson   @param[out] numsub     Variable to store number of suboperators
101052d6035fSJeremy L Thompson 
101152d6035fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
101252d6035fSJeremy L Thompson 
101352d6035fSJeremy L Thompson   @ref Advanced
101452d6035fSJeremy L Thompson **/
101552d6035fSJeremy L Thompson 
101652d6035fSJeremy L Thompson int CeedOperatorGetNumSub(CeedOperator op, CeedInt *numsub) {
1017c042f62fSJeremy L Thompson   if (!op->composite)
1018c042f62fSJeremy L Thompson     // LCOV_EXCL_START
1019c042f62fSJeremy L Thompson     return CeedError(op->ceed, 1, "Not a composite operator");
1020c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
102152d6035fSJeremy L Thompson 
102252d6035fSJeremy L Thompson   *numsub = op->numsub;
102352d6035fSJeremy L Thompson   return 0;
102452d6035fSJeremy L Thompson }
102552d6035fSJeremy L Thompson 
102652d6035fSJeremy L Thompson /**
102752d6035fSJeremy L Thompson   @brief Get the list of suboperators associated with a CeedOperator
102852d6035fSJeremy L Thompson 
102952d6035fSJeremy L Thompson   @param op                CeedOperator
103052d6035fSJeremy L Thompson   @param[out] suboperators Variable to store list of suboperators
103152d6035fSJeremy L Thompson 
103252d6035fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
103352d6035fSJeremy L Thompson 
103452d6035fSJeremy L Thompson   @ref Advanced
103552d6035fSJeremy L Thompson **/
103652d6035fSJeremy L Thompson 
103752d6035fSJeremy L Thompson int CeedOperatorGetSubList(CeedOperator op, CeedOperator **suboperators) {
1038c042f62fSJeremy L Thompson   if (!op->composite)
1039c042f62fSJeremy L Thompson     // LCOV_EXCL_START
1040c042f62fSJeremy L Thompson     return CeedError(op->ceed, 1, "Not a composite operator");
1041c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
104252d6035fSJeremy L Thompson 
104352d6035fSJeremy L Thompson   *suboperators = op->suboperators;
104452d6035fSJeremy L Thompson   return 0;
104552d6035fSJeremy L Thompson }
104652d6035fSJeremy L Thompson 
104752d6035fSJeremy L Thompson /**
1048fe2413ffSjeremylt   @brief Set the backend data of a CeedOperator
1049fe2413ffSjeremylt 
1050fe2413ffSjeremylt   @param[out] op         CeedOperator
1051fe2413ffSjeremylt   @param data            Data to set
1052fe2413ffSjeremylt 
1053fe2413ffSjeremylt   @return An error code: 0 - success, otherwise - failure
1054fe2413ffSjeremylt 
1055fe2413ffSjeremylt   @ref Advanced
1056fe2413ffSjeremylt **/
1057fe2413ffSjeremylt 
1058fe2413ffSjeremylt int CeedOperatorSetData(CeedOperator op, void **data) {
1059fe2413ffSjeremylt   op->data = *data;
1060fe2413ffSjeremylt   return 0;
1061fe2413ffSjeremylt }
1062fe2413ffSjeremylt 
1063fe2413ffSjeremylt /**
10644ce2993fSjeremylt   @brief Get the backend data of a CeedOperator
10654ce2993fSjeremylt 
10664ce2993fSjeremylt   @param op              CeedOperator
10674ce2993fSjeremylt   @param[out] data       Variable to store data
10684ce2993fSjeremylt 
10694ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
10704ce2993fSjeremylt 
107123617272Sjeremylt   @ref Advanced
10724ce2993fSjeremylt **/
10734ce2993fSjeremylt 
10744ce2993fSjeremylt int CeedOperatorGetData(CeedOperator op, void **data) {
10754ce2993fSjeremylt   *data = op->data;
10764ce2993fSjeremylt   return 0;
10774ce2993fSjeremylt }
10784ce2993fSjeremylt 
10794ce2993fSjeremylt /**
10804ce2993fSjeremylt   @brief Set the setup flag of a CeedOperator to True
10814ce2993fSjeremylt 
10824ce2993fSjeremylt   @param op              CeedOperator
10834ce2993fSjeremylt 
10844ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
10854ce2993fSjeremylt 
108623617272Sjeremylt   @ref Advanced
10874ce2993fSjeremylt **/
10884ce2993fSjeremylt 
10894ce2993fSjeremylt int CeedOperatorSetSetupDone(CeedOperator op) {
10904ce2993fSjeremylt   op->setupdone = 1;
10914ce2993fSjeremylt   return 0;
10924ce2993fSjeremylt }
10934ce2993fSjeremylt 
10944ce2993fSjeremylt /**
10952ebaca42Sjeremylt   @brief View a field of a CeedOperator
10962ebaca42Sjeremylt 
10972ebaca42Sjeremylt   @param[in] field       Operator field to view
10982ebaca42Sjeremylt   @param[in] fieldnumber Number of field being viewed
10992ebaca42Sjeremylt   @param[in] stream      Stream to view to, e.g., stdout
11002ebaca42Sjeremylt 
11012ebaca42Sjeremylt   @return An error code: 0 - success, otherwise - failure
11022ebaca42Sjeremylt 
11032ebaca42Sjeremylt   @ref Utility
11042ebaca42Sjeremylt **/
11052ebaca42Sjeremylt static int CeedOperatorFieldView(CeedOperatorField field,
11062ebaca42Sjeremylt                                  CeedQFunctionField qffield,
11072da88da5Sjeremylt                                  CeedInt fieldnumber, bool sub, bool in,
11082da88da5Sjeremylt                                  FILE *stream) {
11092ebaca42Sjeremylt   const char *pre = sub ? "  " : "";
11102da88da5Sjeremylt   const char *inout = in ? "Input" : "Output";
11112ebaca42Sjeremylt 
11122da88da5Sjeremylt   fprintf(stream, "%s    %s Field [%d]:\n"
11132da88da5Sjeremylt           "%s      Name: \"%s\"\n"
11142da88da5Sjeremylt           "%s      Lmode: \"%s\"\n",
11152da88da5Sjeremylt           pre, inout, fieldnumber, pre, qffield->fieldname,
11162ebaca42Sjeremylt           pre, CeedTransposeModes[field->lmode]);
11172ebaca42Sjeremylt 
11182ebaca42Sjeremylt   if (field->basis == CEED_BASIS_COLLOCATED)
11192ebaca42Sjeremylt     fprintf(stream, "%s      Collocated basis\n", pre);
11202ebaca42Sjeremylt 
11212ebaca42Sjeremylt   if (field->vec == CEED_VECTOR_ACTIVE)
11222ebaca42Sjeremylt     fprintf(stream, "%s      Active vector\n", pre);
11232ebaca42Sjeremylt   else if (field->vec == CEED_VECTOR_NONE)
11242ebaca42Sjeremylt     fprintf(stream, "%s      No vector\n", pre);
11252ebaca42Sjeremylt 
11262ebaca42Sjeremylt   return 0;
11272ebaca42Sjeremylt }
11282ebaca42Sjeremylt 
11292ebaca42Sjeremylt /**
11302ebaca42Sjeremylt   @brief View a single CeedOperator
11312ebaca42Sjeremylt 
11322ebaca42Sjeremylt   @param[in] op     CeedOperator to view
11332ebaca42Sjeremylt   @param[in] stream Stream to write; typically stdout/stderr or a file
11342ebaca42Sjeremylt 
11352ebaca42Sjeremylt   @return Error code: 0 - success, otherwise - failure
11362ebaca42Sjeremylt 
11372ebaca42Sjeremylt   @ref Utility
11382ebaca42Sjeremylt **/
11392ebaca42Sjeremylt int CeedOperatorSingleView(CeedOperator op, bool sub, FILE *stream) {
11402ebaca42Sjeremylt   int ierr;
11412ebaca42Sjeremylt   const char *pre = sub ? "  " : "";
11422ebaca42Sjeremylt 
11432ebaca42Sjeremylt   CeedInt totalfields;
11442ebaca42Sjeremylt   ierr = CeedOperatorGetNumArgs(op, &totalfields); CeedChk(ierr);
11452da88da5Sjeremylt 
11462ebaca42Sjeremylt   fprintf(stream, "%s  %d Field%s\n", pre, totalfields, totalfields>1 ? "s" : "");
11472ebaca42Sjeremylt 
11482da88da5Sjeremylt   fprintf(stream, "%s  %d Input Field%s:\n", pre, op->qf->numinputfields,
11492ebaca42Sjeremylt           op->qf->numinputfields>1 ? "s" : "");
11502ebaca42Sjeremylt   for (CeedInt i=0; i<op->qf->numinputfields; i++) {
11512ebaca42Sjeremylt     ierr = CeedOperatorFieldView(op->inputfields[i], op->qf->inputfields[i],
11522da88da5Sjeremylt                                  i, sub, 1, stream); CeedChk(ierr);
11532ebaca42Sjeremylt   }
11542ebaca42Sjeremylt 
11552da88da5Sjeremylt   fprintf(stream, "%s  %d Output Field%s:\n", pre, op->qf->numoutputfields,
11562ebaca42Sjeremylt           op->qf->numoutputfields>1 ? "s" : "");
11572ebaca42Sjeremylt   for (CeedInt i=0; i<op->qf->numoutputfields; i++) {
11582ebaca42Sjeremylt     ierr = CeedOperatorFieldView(op->outputfields[i], op->qf->inputfields[i],
11592da88da5Sjeremylt                                  i, sub, 0, stream); CeedChk(ierr);
11602ebaca42Sjeremylt   }
11612ebaca42Sjeremylt 
11622ebaca42Sjeremylt   return 0;
11632ebaca42Sjeremylt }
11642ebaca42Sjeremylt 
11652ebaca42Sjeremylt /**
11662ebaca42Sjeremylt   @brief View a CeedOperator
11672ebaca42Sjeremylt 
11682ebaca42Sjeremylt   @param[in] op     CeedOperator to view
11692ebaca42Sjeremylt   @param[in] stream Stream to write; typically stdout/stderr or a file
11702ebaca42Sjeremylt 
11712ebaca42Sjeremylt   @return Error code: 0 - success, otherwise - failure
11722ebaca42Sjeremylt 
11732ebaca42Sjeremylt   @ref Utility
11742ebaca42Sjeremylt **/
11752ebaca42Sjeremylt int CeedOperatorView(CeedOperator op, FILE *stream) {
11762ebaca42Sjeremylt   int ierr;
11772ebaca42Sjeremylt 
11782ebaca42Sjeremylt   if (op->composite) {
11792ebaca42Sjeremylt     fprintf(stream, "Composite CeedOperator\n");
11802ebaca42Sjeremylt 
11812ebaca42Sjeremylt     for (CeedInt i=0; i<op->numsub; i++) {
11822da88da5Sjeremylt       fprintf(stream, "  SubOperator [%d]:\n", i);
11832ebaca42Sjeremylt       ierr = CeedOperatorSingleView(op->suboperators[i], 1, stream);
11842ebaca42Sjeremylt       CeedChk(ierr);
11852ebaca42Sjeremylt     }
11862ebaca42Sjeremylt   } else {
11872ebaca42Sjeremylt     fprintf(stream, "CeedOperator\n");
11882ebaca42Sjeremylt     ierr = CeedOperatorSingleView(op, 0, stream); CeedChk(ierr);
11892ebaca42Sjeremylt   }
11902ebaca42Sjeremylt 
11912ebaca42Sjeremylt   return 0;
11922ebaca42Sjeremylt }
11932ebaca42Sjeremylt 
11942ebaca42Sjeremylt /**
1195d1bcdac9Sjeremylt   @brief Get the CeedOperatorFields of a CeedOperator
1196d1bcdac9Sjeremylt 
1197d1bcdac9Sjeremylt   @param op                 CeedOperator
1198d1bcdac9Sjeremylt   @param[out] inputfields   Variable to store inputfields
1199d1bcdac9Sjeremylt   @param[out] outputfields  Variable to store outputfields
1200d1bcdac9Sjeremylt 
1201d1bcdac9Sjeremylt   @return An error code: 0 - success, otherwise - failure
1202d1bcdac9Sjeremylt 
1203d1bcdac9Sjeremylt   @ref Advanced
1204d1bcdac9Sjeremylt **/
1205d1bcdac9Sjeremylt 
1206692c2638Sjeremylt int CeedOperatorGetFields(CeedOperator op, CeedOperatorField **inputfields,
1207d1bcdac9Sjeremylt                           CeedOperatorField **outputfields) {
120852d6035fSJeremy L Thompson   if (op->composite)
1209c042f62fSJeremy L Thompson     // LCOV_EXCL_START
121052d6035fSJeremy L Thompson     return CeedError(op->ceed, 1, "Not defined for composite operator");
1211c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
121252d6035fSJeremy L Thompson 
1213d1bcdac9Sjeremylt   if (inputfields) *inputfields = op->inputfields;
1214d1bcdac9Sjeremylt   if (outputfields) *outputfields = op->outputfields;
1215d1bcdac9Sjeremylt   return 0;
1216d1bcdac9Sjeremylt }
1217d1bcdac9Sjeremylt 
1218d1bcdac9Sjeremylt /**
12194dccadb6Sjeremylt   @brief Get the L vector CeedTransposeMode of a CeedOperatorField
12204dccadb6Sjeremylt 
12214dccadb6Sjeremylt   @param opfield         CeedOperatorField
12224dccadb6Sjeremylt   @param[out] lmode      Variable to store CeedTransposeMode
12234dccadb6Sjeremylt 
12244dccadb6Sjeremylt   @return An error code: 0 - success, otherwise - failure
12254dccadb6Sjeremylt 
12264dccadb6Sjeremylt   @ref Advanced
12274dccadb6Sjeremylt **/
12284dccadb6Sjeremylt 
12294dccadb6Sjeremylt int CeedOperatorFieldGetLMode(CeedOperatorField opfield,
12304dccadb6Sjeremylt                               CeedTransposeMode *lmode) {
1231fe2413ffSjeremylt   *lmode = opfield->lmode;
12324dccadb6Sjeremylt   return 0;
12332b8e417aSjeremylt }
12342b8e417aSjeremylt 
12352b8e417aSjeremylt /**
1236d1bcdac9Sjeremylt   @brief Get the CeedElemRestriction of a CeedOperatorField
1237d1bcdac9Sjeremylt 
1238d1bcdac9Sjeremylt   @param opfield         CeedOperatorField
1239d1bcdac9Sjeremylt   @param[out] rstr       Variable to store CeedElemRestriction
1240d1bcdac9Sjeremylt 
1241d1bcdac9Sjeremylt   @return An error code: 0 - success, otherwise - failure
1242d1bcdac9Sjeremylt 
1243d1bcdac9Sjeremylt   @ref Advanced
1244d1bcdac9Sjeremylt **/
1245d1bcdac9Sjeremylt 
1246d1bcdac9Sjeremylt int CeedOperatorFieldGetElemRestriction(CeedOperatorField opfield,
1247d1bcdac9Sjeremylt                                         CeedElemRestriction *rstr) {
1248fe2413ffSjeremylt   *rstr = opfield->Erestrict;
1249d1bcdac9Sjeremylt   return 0;
1250d1bcdac9Sjeremylt }
1251d1bcdac9Sjeremylt 
1252d1bcdac9Sjeremylt /**
1253d1bcdac9Sjeremylt   @brief Get the CeedBasis of a CeedOperatorField
1254d1bcdac9Sjeremylt 
1255d1bcdac9Sjeremylt   @param opfield         CeedOperatorField
1256d1bcdac9Sjeremylt   @param[out] basis      Variable to store CeedBasis
1257d1bcdac9Sjeremylt 
1258d1bcdac9Sjeremylt   @return An error code: 0 - success, otherwise - failure
1259d1bcdac9Sjeremylt 
1260d1bcdac9Sjeremylt   @ref Advanced
1261d1bcdac9Sjeremylt **/
1262d1bcdac9Sjeremylt 
1263692c2638Sjeremylt int CeedOperatorFieldGetBasis(CeedOperatorField opfield, CeedBasis *basis) {
1264fe2413ffSjeremylt   *basis = opfield->basis;
1265d1bcdac9Sjeremylt   return 0;
1266d1bcdac9Sjeremylt }
1267d1bcdac9Sjeremylt 
1268d1bcdac9Sjeremylt /**
1269d1bcdac9Sjeremylt   @brief Get the CeedVector of a CeedOperatorField
1270d1bcdac9Sjeremylt 
1271d1bcdac9Sjeremylt   @param opfield         CeedOperatorField
1272d1bcdac9Sjeremylt   @param[out] vec        Variable to store CeedVector
1273d1bcdac9Sjeremylt 
1274d1bcdac9Sjeremylt   @return An error code: 0 - success, otherwise - failure
1275d1bcdac9Sjeremylt 
1276d1bcdac9Sjeremylt   @ref Advanced
1277d1bcdac9Sjeremylt **/
1278d1bcdac9Sjeremylt 
1279692c2638Sjeremylt int CeedOperatorFieldGetVector(CeedOperatorField opfield, CeedVector *vec) {
1280fe2413ffSjeremylt   *vec = opfield->vec;
1281d1bcdac9Sjeremylt   return 0;
1282d1bcdac9Sjeremylt }
1283d1bcdac9Sjeremylt 
1284d1bcdac9Sjeremylt /**
1285b11c1e72Sjeremylt   @brief Destroy a CeedOperator
1286d7b241e6Sjeremylt 
1287d7b241e6Sjeremylt   @param op CeedOperator to destroy
1288b11c1e72Sjeremylt 
1289b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
1290dfdf5a53Sjeremylt 
1291dfdf5a53Sjeremylt   @ref Basic
1292b11c1e72Sjeremylt **/
1293d7b241e6Sjeremylt int CeedOperatorDestroy(CeedOperator *op) {
1294d7b241e6Sjeremylt   int ierr;
1295d7b241e6Sjeremylt 
1296d7b241e6Sjeremylt   if (!*op || --(*op)->refcount > 0) return 0;
1297d7b241e6Sjeremylt   if ((*op)->Destroy) {
1298d7b241e6Sjeremylt     ierr = (*op)->Destroy(*op); CeedChk(ierr);
1299d7b241e6Sjeremylt   }
1300fe2413ffSjeremylt   ierr = CeedDestroy(&(*op)->ceed); CeedChk(ierr);
1301fe2413ffSjeremylt   // Free fields
13021d102b48SJeremy L Thompson   for (int i=0; i<(*op)->nfields; i++)
130352d6035fSJeremy L Thompson     if ((*op)->inputfields[i]) {
130471352a93Sjeremylt       ierr = CeedElemRestrictionDestroy(&(*op)->inputfields[i]->Erestrict);
130571352a93Sjeremylt       CeedChk(ierr);
130671352a93Sjeremylt       if ((*op)->inputfields[i]->basis != CEED_BASIS_COLLOCATED) {
130771352a93Sjeremylt         ierr = CeedBasisDestroy(&(*op)->inputfields[i]->basis); CeedChk(ierr);
130871352a93Sjeremylt       }
130971352a93Sjeremylt       if ((*op)->inputfields[i]->vec != CEED_VECTOR_ACTIVE &&
131071352a93Sjeremylt           (*op)->inputfields[i]->vec != CEED_VECTOR_NONE ) {
131171352a93Sjeremylt         ierr = CeedVectorDestroy(&(*op)->inputfields[i]->vec); CeedChk(ierr);
131271352a93Sjeremylt       }
1313fe2413ffSjeremylt       ierr = CeedFree(&(*op)->inputfields[i]); CeedChk(ierr);
1314fe2413ffSjeremylt     }
13151d102b48SJeremy L Thompson   for (int i=0; i<(*op)->nfields; i++)
1316d0eb30a5Sjeremylt     if ((*op)->outputfields[i]) {
131771352a93Sjeremylt       ierr = CeedElemRestrictionDestroy(&(*op)->outputfields[i]->Erestrict);
131871352a93Sjeremylt       CeedChk(ierr);
131971352a93Sjeremylt       if ((*op)->outputfields[i]->basis != CEED_BASIS_COLLOCATED) {
132071352a93Sjeremylt         ierr = CeedBasisDestroy(&(*op)->outputfields[i]->basis); CeedChk(ierr);
132171352a93Sjeremylt       }
132271352a93Sjeremylt       if ((*op)->outputfields[i]->vec != CEED_VECTOR_ACTIVE &&
132371352a93Sjeremylt           (*op)->outputfields[i]->vec != CEED_VECTOR_NONE ) {
132471352a93Sjeremylt         ierr = CeedVectorDestroy(&(*op)->outputfields[i]->vec); CeedChk(ierr);
132571352a93Sjeremylt       }
1326fe2413ffSjeremylt       ierr = CeedFree(&(*op)->outputfields[i]); CeedChk(ierr);
1327fe2413ffSjeremylt     }
132852d6035fSJeremy L Thompson   // Destroy suboperators
13291d102b48SJeremy L Thompson   for (int i=0; i<(*op)->numsub; i++)
133052d6035fSJeremy L Thompson     if ((*op)->suboperators[i]) {
133152d6035fSJeremy L Thompson       ierr = CeedOperatorDestroy(&(*op)->suboperators[i]); CeedChk(ierr);
133252d6035fSJeremy L Thompson     }
1333d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->qf); CeedChk(ierr);
1334d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->dqf); CeedChk(ierr);
1335d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->dqfT); CeedChk(ierr);
1336fe2413ffSjeremylt 
13375107b09fSJeremy L Thompson   // Destroy fallback
13385107b09fSJeremy L Thompson   if ((*op)->opfallback) {
13395107b09fSJeremy L Thompson     ierr = (*op)->qffallback->Destroy((*op)->qffallback); CeedChk(ierr);
13405107b09fSJeremy L Thompson     ierr = CeedFree(&(*op)->qffallback); CeedChk(ierr);
13415107b09fSJeremy L Thompson     ierr = (*op)->opfallback->Destroy((*op)->opfallback); CeedChk(ierr);
13425107b09fSJeremy L Thompson     ierr = CeedFree(&(*op)->opfallback); CeedChk(ierr);
13435107b09fSJeremy L Thompson   }
13445107b09fSJeremy L Thompson 
1345fe2413ffSjeremylt   ierr = CeedFree(&(*op)->inputfields); CeedChk(ierr);
1346fe2413ffSjeremylt   ierr = CeedFree(&(*op)->outputfields); CeedChk(ierr);
134752d6035fSJeremy L Thompson   ierr = CeedFree(&(*op)->suboperators); CeedChk(ierr);
1348d7b241e6Sjeremylt   ierr = CeedFree(op); CeedChk(ierr);
1349d7b241e6Sjeremylt   return 0;
1350d7b241e6Sjeremylt }
1351d7b241e6Sjeremylt 
1352d7b241e6Sjeremylt /// @}
1353