xref: /libCEED/interface/ceed-operator.c (revision 15910d16b955338d1102d4e730fc58bca8f202b9)
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
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
138783c99b3SValeria Barra   @param b          CeedBasis in which the field resides or CEED_BASIS_COLLOCATED
139b11c1e72Sjeremylt                       if collocated with quadrature points
140b11c1e72Sjeremylt   @param v          CeedVector to be used by CeedOperator or CEED_VECTOR_ACTIVE
141b11c1e72Sjeremylt                       if field is active or CEED_VECTOR_NONE if using
1428c91a0c9SJeremy L Thompson                       CEED_EVAL_WEIGHT in the QFunction
143b11c1e72Sjeremylt 
144b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
145dfdf5a53Sjeremylt 
146dfdf5a53Sjeremylt   @ref Basic
147b11c1e72Sjeremylt **/
148d7b241e6Sjeremylt int CeedOperatorSetField(CeedOperator op, const char *fieldname,
149a8d32208Sjeremylt                          CeedElemRestriction r, CeedBasis b, CeedVector v) {
150d7b241e6Sjeremylt   int ierr;
15152d6035fSJeremy L Thompson   if (op->composite)
152c042f62fSJeremy L Thompson     // LCOV_EXCL_START
15352d6035fSJeremy L Thompson     return CeedError(op->ceed, 1, "Cannot add field to composite operator.");
154c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
1558b067b84SJed Brown   if (!r)
156c042f62fSJeremy L Thompson     // LCOV_EXCL_START
157c042f62fSJeremy L Thompson     return CeedError(op->ceed, 1,
158c042f62fSJeremy L Thompson                      "ElemRestriction r for field \"%s\" must be non-NULL.",
159c042f62fSJeremy L Thompson                      fieldname);
160c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
1618b067b84SJed Brown   if (!b)
162c042f62fSJeremy L Thompson     // LCOV_EXCL_START
163c042f62fSJeremy L Thompson     return CeedError(op->ceed, 1, "Basis b for field \"%s\" must be non-NULL.",
164c042f62fSJeremy L Thompson                      fieldname);
165c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
1668b067b84SJed Brown   if (!v)
167c042f62fSJeremy L Thompson     // LCOV_EXCL_START
168c042f62fSJeremy L Thompson     return CeedError(op->ceed, 1, "Vector v for field \"%s\" must be non-NULL.",
169c042f62fSJeremy L Thompson                      fieldname);
170c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
17152d6035fSJeremy L Thompson 
172d7b241e6Sjeremylt   CeedInt numelements;
173d7b241e6Sjeremylt   ierr = CeedElemRestrictionGetNumElements(r, &numelements); CeedChk(ierr);
174*15910d16Sjeremylt   if (r != CEED_ELEMRESTRICTION_NONE && op->hasrestriction &&
175*15910d16Sjeremylt       op->numelements != numelements)
176c042f62fSJeremy L Thompson     // LCOV_EXCL_START
177d7b241e6Sjeremylt     return CeedError(op->ceed, 1,
1781d102b48SJeremy L Thompson                      "ElemRestriction with %d elements incompatible with prior "
1791d102b48SJeremy L Thompson                      "%d elements", numelements, op->numelements);
180c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
181*15910d16Sjeremylt   if (r != CEED_ELEMRESTRICTION_NONE) {
182d7b241e6Sjeremylt     op->numelements = numelements;
1832cb0afc5Sjeremylt     op->hasrestriction = true; // Restriction set, but numelements may be 0
184*15910d16Sjeremylt   }
185d7b241e6Sjeremylt 
186783c99b3SValeria Barra   if (b != CEED_BASIS_COLLOCATED) {
187d7b241e6Sjeremylt     CeedInt numqpoints;
188d7b241e6Sjeremylt     ierr = CeedBasisGetNumQuadraturePoints(b, &numqpoints); CeedChk(ierr);
189d7b241e6Sjeremylt     if (op->numqpoints && op->numqpoints != numqpoints)
190c042f62fSJeremy L Thompson       // LCOV_EXCL_START
1911d102b48SJeremy L Thompson       return CeedError(op->ceed, 1, "Basis with %d quadrature points "
1921d102b48SJeremy L Thompson                        "incompatible with prior %d points", numqpoints,
1931d102b48SJeremy L Thompson                        op->numqpoints);
194c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
195d7b241e6Sjeremylt     op->numqpoints = numqpoints;
196d7b241e6Sjeremylt   }
197*15910d16Sjeremylt   CeedQFunctionField qfield;
198d1bcdac9Sjeremylt   CeedOperatorField *ofield;
199d7b241e6Sjeremylt   for (CeedInt i=0; i<op->qf->numinputfields; i++) {
200fe2413ffSjeremylt     if (!strcmp(fieldname, (*op->qf->inputfields[i]).fieldname)) {
201*15910d16Sjeremylt       qfield = op->qf->inputfields[i];
202d7b241e6Sjeremylt       ofield = &op->inputfields[i];
203d7b241e6Sjeremylt       goto found;
204d7b241e6Sjeremylt     }
205d7b241e6Sjeremylt   }
206d7b241e6Sjeremylt   for (CeedInt i=0; i<op->qf->numoutputfields; i++) {
207fe2413ffSjeremylt     if (!strcmp(fieldname, (*op->qf->outputfields[i]).fieldname)) {
208*15910d16Sjeremylt       qfield = op->qf->inputfields[i];
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:
218*15910d16Sjeremylt   if (r == CEED_ELEMRESTRICTION_NONE && qfield->emode != CEED_EVAL_WEIGHT)
219*15910d16Sjeremylt     return CeedError(op->ceed, 1, "CEED_ELEMRESTRICTION_NONE can only be used "
220*15910d16Sjeremylt                      "for a field with eval mode CEED_EVAL_WEIGHT");
221fe2413ffSjeremylt   ierr = CeedCalloc(1, ofield); CeedChk(ierr);
222fe2413ffSjeremylt   (*ofield)->Erestrict = r;
22371352a93Sjeremylt   r->refcount += 1;
224fe2413ffSjeremylt   (*ofield)->basis = b;
22571352a93Sjeremylt   if (b != CEED_BASIS_COLLOCATED)
22671352a93Sjeremylt     b->refcount += 1;
227fe2413ffSjeremylt   (*ofield)->vec = v;
22871352a93Sjeremylt   if (v != CEED_VECTOR_ACTIVE && v != CEED_VECTOR_NONE)
22971352a93Sjeremylt     v->refcount += 1;
230d7b241e6Sjeremylt   op->nfields += 1;
231d7b241e6Sjeremylt   return 0;
232d7b241e6Sjeremylt }
233d7b241e6Sjeremylt 
234d7b241e6Sjeremylt /**
23552d6035fSJeremy L Thompson   @brief Add a sub-operator to a composite CeedOperator
236288c0443SJeremy L Thompson 
23734138859Sjeremylt   @param[out] compositeop Composite CeedOperator
23834138859Sjeremylt   @param      subop       Sub-operator CeedOperator
23952d6035fSJeremy L Thompson 
24052d6035fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
24152d6035fSJeremy L Thompson 
24252d6035fSJeremy L Thompson   @ref Basic
24352d6035fSJeremy L Thompson  */
244692c2638Sjeremylt int CeedCompositeOperatorAddSub(CeedOperator compositeop, CeedOperator subop) {
24552d6035fSJeremy L Thompson   if (!compositeop->composite)
246c042f62fSJeremy L Thompson     // LCOV_EXCL_START
2471d102b48SJeremy L Thompson     return CeedError(compositeop->ceed, 1, "CeedOperator is not a composite "
2481d102b48SJeremy L Thompson                      "operator");
249c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
25052d6035fSJeremy L Thompson 
25152d6035fSJeremy L Thompson   if (compositeop->numsub == CEED_COMPOSITE_MAX)
252c042f62fSJeremy L Thompson     // LCOV_EXCL_START
2531d102b48SJeremy L Thompson     return CeedError(compositeop->ceed, 1, "Cannot add additional suboperators");
254c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
25552d6035fSJeremy L Thompson 
25652d6035fSJeremy L Thompson   compositeop->suboperators[compositeop->numsub] = subop;
25752d6035fSJeremy L Thompson   subop->refcount++;
25852d6035fSJeremy L Thompson   compositeop->numsub++;
25952d6035fSJeremy L Thompson   return 0;
26052d6035fSJeremy L Thompson }
26152d6035fSJeremy L Thompson 
26252d6035fSJeremy L Thompson /**
2635107b09fSJeremy L Thompson   @brief Duplicate a CeedOperator with a reference Ceed to fallback for advanced
2645107b09fSJeremy L Thompson            CeedOperator functionality
2655107b09fSJeremy L Thompson 
2665107b09fSJeremy L Thompson   @param op           CeedOperator to create fallback for
2675107b09fSJeremy L Thompson 
2685107b09fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
2695107b09fSJeremy L Thompson 
2705107b09fSJeremy L Thompson   @ref Developer
2715107b09fSJeremy L Thompson **/
2725107b09fSJeremy L Thompson int CeedOperatorCreateFallback(CeedOperator op) {
2735107b09fSJeremy L Thompson   int ierr;
2745107b09fSJeremy L Thompson 
2755107b09fSJeremy L Thompson   // Fallback Ceed
2765107b09fSJeremy L Thompson   const char *resource, *fallbackresource;
2775107b09fSJeremy L Thompson   ierr = CeedGetResource(op->ceed, &resource); CeedChk(ierr);
2785107b09fSJeremy L Thompson   ierr = CeedGetOperatorFallbackResource(op->ceed, &fallbackresource);
2795107b09fSJeremy L Thompson   CeedChk(ierr);
2805107b09fSJeremy L Thompson   if (!strcmp(resource, fallbackresource))
2815107b09fSJeremy L Thompson     // LCOV_EXCL_START
2825107b09fSJeremy L Thompson     return CeedError(op->ceed, 1, "Backend %s cannot create an operator"
2835107b09fSJeremy L Thompson                      "fallback to resource %s", resource, fallbackresource);
2845107b09fSJeremy L Thompson   // LCOV_EXCL_STOP
2855107b09fSJeremy L Thompson 
2860ace9bf2Sjeremylt   // Fallback Ceed
2875107b09fSJeremy L Thompson   Ceed ceedref;
2880ace9bf2Sjeremylt   if (!op->ceed->opfallbackceed) {
2895107b09fSJeremy L Thompson     ierr = CeedInit(fallbackresource, &ceedref); CeedChk(ierr);
2905107b09fSJeremy L Thompson     ceedref->opfallbackparent = op->ceed;
2915107b09fSJeremy L Thompson     op->ceed->opfallbackceed = ceedref;
2920ace9bf2Sjeremylt   }
2930ace9bf2Sjeremylt   ceedref = op->ceed->opfallbackceed;
2945107b09fSJeremy L Thompson 
2955107b09fSJeremy L Thompson   // Clone Op
2965107b09fSJeremy L Thompson   CeedOperator opref;
2975107b09fSJeremy L Thompson   ierr = CeedCalloc(1, &opref); CeedChk(ierr);
2985107b09fSJeremy L Thompson   memcpy(opref, op, sizeof(*opref)); CeedChk(ierr);
2995107b09fSJeremy L Thompson   opref->data = NULL;
3005107b09fSJeremy L Thompson   opref->setupdone = 0;
3015107b09fSJeremy L Thompson   opref->ceed = ceedref;
3025107b09fSJeremy L Thompson   ierr = ceedref->OperatorCreate(opref); CeedChk(ierr);
3035107b09fSJeremy L Thompson   op->opfallback = opref;
3045107b09fSJeremy L Thompson 
3055107b09fSJeremy L Thompson   // Clone QF
3065107b09fSJeremy L Thompson   CeedQFunction qfref;
3075107b09fSJeremy L Thompson   ierr = CeedCalloc(1, &qfref); CeedChk(ierr);
3085107b09fSJeremy L Thompson   memcpy(qfref, (op->qf), sizeof(*qfref)); CeedChk(ierr);
3095107b09fSJeremy L Thompson   qfref->data = NULL;
3105107b09fSJeremy L Thompson   qfref->ceed = ceedref;
3115107b09fSJeremy L Thompson   ierr = ceedref->QFunctionCreate(qfref); CeedChk(ierr);
3125107b09fSJeremy L Thompson   opref->qf = qfref;
3135107b09fSJeremy L Thompson   op->qffallback = qfref;
3145107b09fSJeremy L Thompson 
3155107b09fSJeremy L Thompson   return 0;
3165107b09fSJeremy L Thompson }
3175107b09fSJeremy L Thompson 
3185107b09fSJeremy L Thompson /**
319250756a7Sjeremylt   @brief Check if a CeedOperator is ready to be used.
320250756a7Sjeremylt 
321250756a7Sjeremylt   @param[in] ceed Ceed object for error handling
322250756a7Sjeremylt   @param[in] op   CeedOperator to check
323250756a7Sjeremylt 
324250756a7Sjeremylt   @return An error code: 0 - success, otherwise - failure
325250756a7Sjeremylt 
326250756a7Sjeremylt   @ref Basic
327250756a7Sjeremylt **/
328250756a7Sjeremylt static int CeedOperatorCheckReady(Ceed ceed, CeedOperator op) {
329250756a7Sjeremylt   CeedQFunction qf = op->qf;
330250756a7Sjeremylt 
331250756a7Sjeremylt   if (op->composite) {
332250756a7Sjeremylt     if (!op->numsub)
333250756a7Sjeremylt       // LCOV_EXCL_START
334250756a7Sjeremylt       return CeedError(ceed, 1, "No suboperators set");
335250756a7Sjeremylt     // LCOV_EXCL_STOP
336250756a7Sjeremylt   } else {
337250756a7Sjeremylt     if (op->nfields == 0)
338250756a7Sjeremylt       // LCOV_EXCL_START
339250756a7Sjeremylt       return CeedError(ceed, 1, "No operator fields set");
340250756a7Sjeremylt     // LCOV_EXCL_STOP
341250756a7Sjeremylt     if (op->nfields < qf->numinputfields + qf->numoutputfields)
342250756a7Sjeremylt       // LCOV_EXCL_START
343250756a7Sjeremylt       return CeedError(ceed, 1, "Not all operator fields set");
344250756a7Sjeremylt     // LCOV_EXCL_STOP
345250756a7Sjeremylt     if (!op->hasrestriction)
346250756a7Sjeremylt       // LCOV_EXCL_START
347250756a7Sjeremylt       return CeedError(ceed, 1,"At least one restriction required");
348250756a7Sjeremylt     // LCOV_EXCL_STOP
349250756a7Sjeremylt     if (op->numqpoints == 0)
350250756a7Sjeremylt       // LCOV_EXCL_START
351250756a7Sjeremylt       return CeedError(ceed, 1,"At least one non-collocated basis required");
352250756a7Sjeremylt     // LCOV_EXCL_STOP
353250756a7Sjeremylt   }
354250756a7Sjeremylt 
355250756a7Sjeremylt   return 0;
356250756a7Sjeremylt }
357250756a7Sjeremylt 
358250756a7Sjeremylt /**
3591d102b48SJeremy L Thompson   @brief Assemble a linear CeedQFunction associated with a CeedOperator
3601d102b48SJeremy L Thompson 
3611d102b48SJeremy L Thompson   This returns a CeedVector containing a matrix at each quadrature point
3621d102b48SJeremy L Thompson     providing the action of the CeedQFunction associated with the CeedOperator.
3631d102b48SJeremy L Thompson     The vector 'assembled' is of shape
3641d102b48SJeremy L Thompson       [num_elements, num_input_fields, num_output_fields, num_quad_points]
3651d102b48SJeremy L Thompson     and contains column-major matrices representing the action of the
3661d102b48SJeremy L Thompson     CeedQFunction for a corresponding quadrature point on an element. Inputs and
3671d102b48SJeremy L Thompson     outputs are in the order provided by the user when adding CeedOperator fields.
3681d102b48SJeremy L Thompson     For example, a QFunction with inputs 'u' and 'gradu' and outputs 'gradv' and
3691d102b48SJeremy L Thompson     'v', provided in that order, would result in an assembled QFunction that
3701d102b48SJeremy L Thompson     consists of (1 + dim) x (dim + 1) matrices at each quadrature point acting
3711d102b48SJeremy L Thompson     on the input [u, du_0, du_1] and producing the output [dv_0, dv_1, v].
3721d102b48SJeremy L Thompson 
3731d102b48SJeremy L Thompson   @param op             CeedOperator to assemble CeedQFunction
3741d102b48SJeremy L Thompson   @param[out] assembled CeedVector to store assembled CeedQFunction at
3751d102b48SJeremy L Thompson                           quadrature points
3761d102b48SJeremy L Thompson   @param[out] rstr      CeedElemRestriction for CeedVector containing assembled
3771d102b48SJeremy L Thompson                           CeedQFunction
3781d102b48SJeremy L Thompson   @param request        Address of CeedRequest for non-blocking completion, else
3791d102b48SJeremy L Thompson                           CEED_REQUEST_IMMEDIATE
3801d102b48SJeremy L Thompson 
3811d102b48SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
3821d102b48SJeremy L Thompson 
383b7ec98d8SJeremy L Thompson   @ref Basic
3841d102b48SJeremy L Thompson **/
3851d102b48SJeremy L Thompson int CeedOperatorAssembleLinearQFunction(CeedOperator op, CeedVector *assembled,
3867f823360Sjeremylt                                         CeedElemRestriction *rstr,
3877f823360Sjeremylt                                         CeedRequest *request) {
3881d102b48SJeremy L Thompson   int ierr;
3891d102b48SJeremy L Thompson   Ceed ceed = op->ceed;
390250756a7Sjeremylt   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
3911d102b48SJeremy L Thompson 
3927172caadSjeremylt   // Backend version
3935107b09fSJeremy L Thompson   if (op->AssembleLinearQFunction) {
3941d102b48SJeremy L Thompson     ierr = op->AssembleLinearQFunction(op, assembled, rstr, request);
3951d102b48SJeremy L Thompson     CeedChk(ierr);
3965107b09fSJeremy L Thompson   } else {
3975107b09fSJeremy L Thompson     // Fallback to reference Ceed
3985107b09fSJeremy L Thompson     if (!op->opfallback) {
3995107b09fSJeremy L Thompson       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
4005107b09fSJeremy L Thompson     }
4015107b09fSJeremy L Thompson     // Assemble
4025107b09fSJeremy L Thompson     ierr = op->opfallback->AssembleLinearQFunction(op->opfallback, assembled,
4035107b09fSJeremy L Thompson            rstr, request); CeedChk(ierr);
4045107b09fSJeremy L Thompson   }
405250756a7Sjeremylt 
4061d102b48SJeremy L Thompson   return 0;
4071d102b48SJeremy L Thompson }
4081d102b48SJeremy L Thompson 
4091d102b48SJeremy L Thompson /**
410b7ec98d8SJeremy L Thompson   @brief Assemble the diagonal of a square linear Operator
411b7ec98d8SJeremy L Thompson 
412b7ec98d8SJeremy L Thompson   This returns a CeedVector containing the diagonal of a linear CeedOperator.
413b7ec98d8SJeremy L Thompson 
414b7ec98d8SJeremy L Thompson   @param op             CeedOperator to assemble CeedQFunction
415b7ec98d8SJeremy L Thompson   @param[out] assembled CeedVector to store assembled CeedOperator diagonal
416b7ec98d8SJeremy L Thompson   @param request        Address of CeedRequest for non-blocking completion, else
417b7ec98d8SJeremy L Thompson                           CEED_REQUEST_IMMEDIATE
418b7ec98d8SJeremy L Thompson 
419b7ec98d8SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
420b7ec98d8SJeremy L Thompson 
421b7ec98d8SJeremy L Thompson   @ref Basic
422b7ec98d8SJeremy L Thompson **/
4237f823360Sjeremylt int CeedOperatorAssembleLinearDiagonal(CeedOperator op, CeedVector *assembled,
4247f823360Sjeremylt                                        CeedRequest *request) {
425b7ec98d8SJeremy L Thompson   int ierr;
426b7ec98d8SJeremy L Thompson   Ceed ceed = op->ceed;
427250756a7Sjeremylt   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
428b7ec98d8SJeremy L Thompson 
429b7ec98d8SJeremy L Thompson   // Use backend version, if available
430b7ec98d8SJeremy L Thompson   if (op->AssembleLinearDiagonal) {
431b7ec98d8SJeremy L Thompson     ierr = op->AssembleLinearDiagonal(op, assembled, request); CeedChk(ierr);
4327172caadSjeremylt   } else {
4337172caadSjeremylt     // Fallback to reference Ceed
4347172caadSjeremylt     if (!op->opfallback) {
4357172caadSjeremylt       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
436b7ec98d8SJeremy L Thompson     }
4377172caadSjeremylt     // Assemble
4387172caadSjeremylt     ierr = op->opfallback->AssembleLinearDiagonal(op->opfallback, assembled,
4397172caadSjeremylt            request); CeedChk(ierr);
440b7ec98d8SJeremy L Thompson   }
441b7ec98d8SJeremy L Thompson 
442b7ec98d8SJeremy L Thompson   return 0;
443b7ec98d8SJeremy L Thompson }
444b7ec98d8SJeremy L Thompson 
445b7ec98d8SJeremy L Thompson /**
4463bd813ffSjeremylt   @brief Build a FDM based approximate inverse for each element for a
4473bd813ffSjeremylt            CeedOperator
4483bd813ffSjeremylt 
4493bd813ffSjeremylt   This returns a CeedOperator and CeedVector to apply a Fast Diagonalization
4503bd813ffSjeremylt     Method based approximate inverse. This function obtains the simultaneous
4513bd813ffSjeremylt     diagonalization for the 1D mass and Laplacian operators,
4523bd813ffSjeremylt       M = V^T V, K = V^T S V.
4533bd813ffSjeremylt     The assembled QFunction is used to modify the eigenvalues from simultaneous
4543bd813ffSjeremylt     diagonalization and obtain an approximate inverse of the form
4553bd813ffSjeremylt       V^T S^hat V. The CeedOperator must be linear and non-composite. The
4563bd813ffSjeremylt     associated CeedQFunction must therefore also be linear.
4573bd813ffSjeremylt 
4583bd813ffSjeremylt   @param op             CeedOperator to create element inverses
4593bd813ffSjeremylt   @param[out] fdminv    CeedOperator to apply the action of a FDM based inverse
4603bd813ffSjeremylt                           for each element
4613bd813ffSjeremylt   @param request        Address of CeedRequest for non-blocking completion, else
4623bd813ffSjeremylt                           CEED_REQUEST_IMMEDIATE
4633bd813ffSjeremylt 
4643bd813ffSjeremylt   @return An error code: 0 - success, otherwise - failure
4653bd813ffSjeremylt 
4663bd813ffSjeremylt   @ref Advanced
4673bd813ffSjeremylt **/
4683bd813ffSjeremylt int CeedOperatorCreateFDMElementInverse(CeedOperator op, CeedOperator *fdminv,
4693bd813ffSjeremylt                                         CeedRequest *request) {
4703bd813ffSjeremylt   int ierr;
4713bd813ffSjeremylt   Ceed ceed = op->ceed;
472713f43c3Sjeremylt   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
4733bd813ffSjeremylt 
474713f43c3Sjeremylt   // Use backend version, if available
475713f43c3Sjeremylt   if (op->CreateFDMElementInverse) {
476713f43c3Sjeremylt     ierr = op->CreateFDMElementInverse(op, fdminv, request); CeedChk(ierr);
477713f43c3Sjeremylt   } else {
478713f43c3Sjeremylt     // Fallback to reference Ceed
479713f43c3Sjeremylt     if (!op->opfallback) {
480713f43c3Sjeremylt       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
4813bd813ffSjeremylt     }
482713f43c3Sjeremylt     // Assemble
483713f43c3Sjeremylt     ierr = op->opfallback->CreateFDMElementInverse(op->opfallback, fdminv,
4843bd813ffSjeremylt            request); CeedChk(ierr);
4853bd813ffSjeremylt   }
4863bd813ffSjeremylt 
4873bd813ffSjeremylt   return 0;
4883bd813ffSjeremylt }
4893bd813ffSjeremylt 
4903bd813ffSjeremylt 
4913bd813ffSjeremylt /**
4923bd813ffSjeremylt   @brief Apply CeedOperator to a vector
493d7b241e6Sjeremylt 
494d7b241e6Sjeremylt   This computes the action of the operator on the specified (active) input,
495d7b241e6Sjeremylt   yielding its (active) output.  All inputs and outputs must be specified using
496d7b241e6Sjeremylt   CeedOperatorSetField().
497d7b241e6Sjeremylt 
498d7b241e6Sjeremylt   @param op        CeedOperator to apply
49934138859Sjeremylt   @param[in] in    CeedVector containing input state or CEED_VECTOR_NONE if
50034138859Sjeremylt                   there are no active inputs
501b11c1e72Sjeremylt   @param[out] out  CeedVector to store result of applying operator (must be
50234138859Sjeremylt                      distinct from @a in) or CEED_VECTOR_NONE if there are no
50334138859Sjeremylt                      active outputs
504d7b241e6Sjeremylt   @param request   Address of CeedRequest for non-blocking completion, else
505d7b241e6Sjeremylt                      CEED_REQUEST_IMMEDIATE
506b11c1e72Sjeremylt 
507b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
508dfdf5a53Sjeremylt 
509dfdf5a53Sjeremylt   @ref Basic
510b11c1e72Sjeremylt **/
511692c2638Sjeremylt int CeedOperatorApply(CeedOperator op, CeedVector in, CeedVector out,
512692c2638Sjeremylt                       CeedRequest *request) {
513d7b241e6Sjeremylt   int ierr;
514d7b241e6Sjeremylt   Ceed ceed = op->ceed;
515250756a7Sjeremylt   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
516d7b241e6Sjeremylt 
517250756a7Sjeremylt   if (op->numelements)  {
518250756a7Sjeremylt     // Standard Operator
519cae8b89aSjeremylt     if (op->Apply) {
520250756a7Sjeremylt       ierr = op->Apply(op, in, out, request); CeedChk(ierr);
521cae8b89aSjeremylt     } else {
522cae8b89aSjeremylt       // Zero all output vectors
523250756a7Sjeremylt       CeedQFunction qf = op->qf;
524cae8b89aSjeremylt       for (CeedInt i=0; i<qf->numoutputfields; i++) {
525cae8b89aSjeremylt         CeedVector vec = op->outputfields[i]->vec;
526cae8b89aSjeremylt         if (vec == CEED_VECTOR_ACTIVE)
527cae8b89aSjeremylt           vec = out;
528cae8b89aSjeremylt         if (vec != CEED_VECTOR_NONE) {
529cae8b89aSjeremylt           ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr);
530cae8b89aSjeremylt         }
531cae8b89aSjeremylt       }
532250756a7Sjeremylt       // Apply
533250756a7Sjeremylt       ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr);
534250756a7Sjeremylt     }
535250756a7Sjeremylt   } else if (op->composite) {
536250756a7Sjeremylt     // Composite Operator
537250756a7Sjeremylt     if (op->ApplyComposite) {
538250756a7Sjeremylt       ierr = op->ApplyComposite(op, in, out, request); CeedChk(ierr);
539250756a7Sjeremylt     } else {
540250756a7Sjeremylt       CeedInt numsub;
541250756a7Sjeremylt       ierr = CeedOperatorGetNumSub(op, &numsub); CeedChk(ierr);
542250756a7Sjeremylt       CeedOperator *suboperators;
543250756a7Sjeremylt       ierr = CeedOperatorGetSubList(op, &suboperators); CeedChk(ierr);
544250756a7Sjeremylt 
545250756a7Sjeremylt       // Zero all output vectors
546250756a7Sjeremylt       if (out != CEED_VECTOR_NONE) {
547cae8b89aSjeremylt         ierr = CeedVectorSetValue(out, 0.0); CeedChk(ierr);
548cae8b89aSjeremylt       }
549250756a7Sjeremylt       for (CeedInt i=0; i<numsub; i++) {
550250756a7Sjeremylt         for (CeedInt j=0; j<suboperators[i]->qf->numoutputfields; j++) {
551250756a7Sjeremylt           CeedVector vec = suboperators[i]->outputfields[j]->vec;
552250756a7Sjeremylt           if (vec != CEED_VECTOR_ACTIVE && vec != CEED_VECTOR_NONE) {
553250756a7Sjeremylt             ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr);
554250756a7Sjeremylt           }
555250756a7Sjeremylt         }
556250756a7Sjeremylt       }
557250756a7Sjeremylt       // Apply
558250756a7Sjeremylt       for (CeedInt i=0; i<op->numsub; i++) {
559250756a7Sjeremylt         ierr = CeedOperatorApplyAdd(op->suboperators[i], in, out, request);
560cae8b89aSjeremylt         CeedChk(ierr);
561cae8b89aSjeremylt       }
562cae8b89aSjeremylt     }
563250756a7Sjeremylt   }
564250756a7Sjeremylt 
565cae8b89aSjeremylt   return 0;
566cae8b89aSjeremylt }
567cae8b89aSjeremylt 
568cae8b89aSjeremylt /**
569cae8b89aSjeremylt   @brief Apply CeedOperator to a vector and add result to output vector
570cae8b89aSjeremylt 
571cae8b89aSjeremylt   This computes the action of the operator on the specified (active) input,
572cae8b89aSjeremylt   yielding its (active) output.  All inputs and outputs must be specified using
573cae8b89aSjeremylt   CeedOperatorSetField().
574cae8b89aSjeremylt 
575cae8b89aSjeremylt   @param op        CeedOperator to apply
576cae8b89aSjeremylt   @param[in] in    CeedVector containing input state or NULL if there are no
577cae8b89aSjeremylt                      active inputs
578cae8b89aSjeremylt   @param[out] out  CeedVector to sum in result of applying operator (must be
579cae8b89aSjeremylt                      distinct from @a in) or NULL if there are no active outputs
580cae8b89aSjeremylt   @param request   Address of CeedRequest for non-blocking completion, else
581cae8b89aSjeremylt                      CEED_REQUEST_IMMEDIATE
582cae8b89aSjeremylt 
583cae8b89aSjeremylt   @return An error code: 0 - success, otherwise - failure
584cae8b89aSjeremylt 
585cae8b89aSjeremylt   @ref Basic
586cae8b89aSjeremylt **/
587cae8b89aSjeremylt int CeedOperatorApplyAdd(CeedOperator op, CeedVector in, CeedVector out,
588cae8b89aSjeremylt                          CeedRequest *request) {
589cae8b89aSjeremylt   int ierr;
590cae8b89aSjeremylt   Ceed ceed = op->ceed;
591250756a7Sjeremylt   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
592cae8b89aSjeremylt 
593250756a7Sjeremylt   if (op->numelements)  {
594250756a7Sjeremylt     // Standard Operator
595250756a7Sjeremylt     ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr);
596250756a7Sjeremylt   } else if (op->composite) {
597250756a7Sjeremylt     // Composite Operator
598250756a7Sjeremylt     if (op->ApplyAddComposite) {
599250756a7Sjeremylt       ierr = op->ApplyAddComposite(op, in, out, request); CeedChk(ierr);
600cae8b89aSjeremylt     } else {
601250756a7Sjeremylt       CeedInt numsub;
602250756a7Sjeremylt       ierr = CeedOperatorGetNumSub(op, &numsub); CeedChk(ierr);
603250756a7Sjeremylt       CeedOperator *suboperators;
604250756a7Sjeremylt       ierr = CeedOperatorGetSubList(op, &suboperators); CeedChk(ierr);
605250756a7Sjeremylt 
606250756a7Sjeremylt       for (CeedInt i=0; i<numsub; i++) {
607250756a7Sjeremylt         ierr = CeedOperatorApplyAdd(suboperators[i], in, out, request);
608cae8b89aSjeremylt         CeedChk(ierr);
6091d7d2407SJeremy L Thompson       }
610250756a7Sjeremylt     }
611250756a7Sjeremylt   }
612250756a7Sjeremylt 
613d7b241e6Sjeremylt   return 0;
614d7b241e6Sjeremylt }
615d7b241e6Sjeremylt 
616d7b241e6Sjeremylt /**
6174ce2993fSjeremylt   @brief Get the Ceed associated with a CeedOperator
6184ce2993fSjeremylt 
6194ce2993fSjeremylt   @param op              CeedOperator
6204ce2993fSjeremylt   @param[out] ceed       Variable to store Ceed
6214ce2993fSjeremylt 
6224ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
6234ce2993fSjeremylt 
62423617272Sjeremylt   @ref Advanced
6254ce2993fSjeremylt **/
6264ce2993fSjeremylt 
6274ce2993fSjeremylt int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) {
6284ce2993fSjeremylt   *ceed = op->ceed;
6294ce2993fSjeremylt   return 0;
6304ce2993fSjeremylt }
6314ce2993fSjeremylt 
6324ce2993fSjeremylt /**
6334ce2993fSjeremylt   @brief Get the number of elements associated with a CeedOperator
6344ce2993fSjeremylt 
6354ce2993fSjeremylt   @param op              CeedOperator
6364ce2993fSjeremylt   @param[out] numelem    Variable to store number of elements
6374ce2993fSjeremylt 
6384ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
6394ce2993fSjeremylt 
64023617272Sjeremylt   @ref Advanced
6414ce2993fSjeremylt **/
6424ce2993fSjeremylt 
6434ce2993fSjeremylt int CeedOperatorGetNumElements(CeedOperator op, CeedInt *numelem) {
64452d6035fSJeremy L Thompson   if (op->composite)
645c042f62fSJeremy L Thompson     // LCOV_EXCL_START
64652d6035fSJeremy L Thompson     return CeedError(op->ceed, 1, "Not defined for composite operator");
647c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
64852d6035fSJeremy L Thompson 
6494ce2993fSjeremylt   *numelem = op->numelements;
6504ce2993fSjeremylt   return 0;
6514ce2993fSjeremylt }
6524ce2993fSjeremylt 
6534ce2993fSjeremylt /**
6544ce2993fSjeremylt   @brief Get the number of quadrature points associated with a CeedOperator
6554ce2993fSjeremylt 
6564ce2993fSjeremylt   @param op              CeedOperator
6574ce2993fSjeremylt   @param[out] numqpts    Variable to store vector number of quadrature points
6584ce2993fSjeremylt 
6594ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
6604ce2993fSjeremylt 
66123617272Sjeremylt   @ref Advanced
6624ce2993fSjeremylt **/
6634ce2993fSjeremylt 
6644ce2993fSjeremylt int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *numqpts) {
66552d6035fSJeremy L Thompson   if (op->composite)
666c042f62fSJeremy L Thompson     // LCOV_EXCL_START
66752d6035fSJeremy L Thompson     return CeedError(op->ceed, 1, "Not defined for composite operator");
668c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
66952d6035fSJeremy L Thompson 
6704ce2993fSjeremylt   *numqpts = op->numqpoints;
6714ce2993fSjeremylt   return 0;
6724ce2993fSjeremylt }
6734ce2993fSjeremylt 
6744ce2993fSjeremylt /**
6754ce2993fSjeremylt   @brief Get the number of arguments associated with a CeedOperator
6764ce2993fSjeremylt 
6774ce2993fSjeremylt   @param op              CeedOperator
6784ce2993fSjeremylt   @param[out] numargs    Variable to store vector number of arguments
6794ce2993fSjeremylt 
6804ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
6814ce2993fSjeremylt 
68223617272Sjeremylt   @ref Advanced
6834ce2993fSjeremylt **/
6844ce2993fSjeremylt 
6854ce2993fSjeremylt int CeedOperatorGetNumArgs(CeedOperator op, CeedInt *numargs) {
68652d6035fSJeremy L Thompson   if (op->composite)
687c042f62fSJeremy L Thompson     // LCOV_EXCL_START
68852d6035fSJeremy L Thompson     return CeedError(op->ceed, 1, "Not defined for composite operators");
689c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
690c042f62fSJeremy L Thompson 
6914ce2993fSjeremylt   *numargs = op->nfields;
6924ce2993fSjeremylt   return 0;
6934ce2993fSjeremylt }
6944ce2993fSjeremylt 
6954ce2993fSjeremylt /**
6964ce2993fSjeremylt   @brief Get the setup status of a CeedOperator
6974ce2993fSjeremylt 
6984ce2993fSjeremylt   @param op             CeedOperator
699288c0443SJeremy L Thompson   @param[out] setupdone Variable to store setup status
7004ce2993fSjeremylt 
7014ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
7024ce2993fSjeremylt 
70323617272Sjeremylt   @ref Advanced
7044ce2993fSjeremylt **/
7054ce2993fSjeremylt 
7064ce2993fSjeremylt int CeedOperatorGetSetupStatus(CeedOperator op, bool *setupdone) {
7074ce2993fSjeremylt   *setupdone = op->setupdone;
7084ce2993fSjeremylt   return 0;
7094ce2993fSjeremylt }
7104ce2993fSjeremylt 
7114ce2993fSjeremylt /**
7124ce2993fSjeremylt   @brief Get the QFunction associated with a CeedOperator
7134ce2993fSjeremylt 
7144ce2993fSjeremylt   @param op              CeedOperator
7158c91a0c9SJeremy L Thompson   @param[out] qf         Variable to store QFunction
7164ce2993fSjeremylt 
7174ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
7184ce2993fSjeremylt 
71923617272Sjeremylt   @ref Advanced
7204ce2993fSjeremylt **/
7214ce2993fSjeremylt 
7224ce2993fSjeremylt int CeedOperatorGetQFunction(CeedOperator op, CeedQFunction *qf) {
72352d6035fSJeremy L Thompson   if (op->composite)
724c042f62fSJeremy L Thompson     // LCOV_EXCL_START
72552d6035fSJeremy L Thompson     return CeedError(op->ceed, 1, "Not defined for composite operator");
726c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
72752d6035fSJeremy L Thompson 
7284ce2993fSjeremylt   *qf = op->qf;
7294ce2993fSjeremylt   return 0;
7304ce2993fSjeremylt }
7314ce2993fSjeremylt 
7324ce2993fSjeremylt /**
73352d6035fSJeremy L Thompson   @brief Get the number of suboperators associated with a CeedOperator
73452d6035fSJeremy L Thompson 
73552d6035fSJeremy L Thompson   @param op              CeedOperator
73652d6035fSJeremy L Thompson   @param[out] numsub     Variable to store number of suboperators
73752d6035fSJeremy L Thompson 
73852d6035fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
73952d6035fSJeremy L Thompson 
74052d6035fSJeremy L Thompson   @ref Advanced
74152d6035fSJeremy L Thompson **/
74252d6035fSJeremy L Thompson 
74352d6035fSJeremy L Thompson int CeedOperatorGetNumSub(CeedOperator op, CeedInt *numsub) {
744c042f62fSJeremy L Thompson   if (!op->composite)
745c042f62fSJeremy L Thompson     // LCOV_EXCL_START
746c042f62fSJeremy L Thompson     return CeedError(op->ceed, 1, "Not a composite operator");
747c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
74852d6035fSJeremy L Thompson 
74952d6035fSJeremy L Thompson   *numsub = op->numsub;
75052d6035fSJeremy L Thompson   return 0;
75152d6035fSJeremy L Thompson }
75252d6035fSJeremy L Thompson 
75352d6035fSJeremy L Thompson /**
75452d6035fSJeremy L Thompson   @brief Get the list of suboperators associated with a CeedOperator
75552d6035fSJeremy L Thompson 
75652d6035fSJeremy L Thompson   @param op                CeedOperator
75752d6035fSJeremy L Thompson   @param[out] suboperators Variable to store list of suboperators
75852d6035fSJeremy L Thompson 
75952d6035fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
76052d6035fSJeremy L Thompson 
76152d6035fSJeremy L Thompson   @ref Advanced
76252d6035fSJeremy L Thompson **/
76352d6035fSJeremy L Thompson 
76452d6035fSJeremy L Thompson int CeedOperatorGetSubList(CeedOperator op, CeedOperator **suboperators) {
765c042f62fSJeremy L Thompson   if (!op->composite)
766c042f62fSJeremy L Thompson     // LCOV_EXCL_START
767c042f62fSJeremy L Thompson     return CeedError(op->ceed, 1, "Not a composite operator");
768c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
76952d6035fSJeremy L Thompson 
77052d6035fSJeremy L Thompson   *suboperators = op->suboperators;
77152d6035fSJeremy L Thompson   return 0;
77252d6035fSJeremy L Thompson }
77352d6035fSJeremy L Thompson 
77452d6035fSJeremy L Thompson /**
775fe2413ffSjeremylt   @brief Set the backend data of a CeedOperator
776fe2413ffSjeremylt 
777fe2413ffSjeremylt   @param[out] op         CeedOperator
778fe2413ffSjeremylt   @param data            Data to set
779fe2413ffSjeremylt 
780fe2413ffSjeremylt   @return An error code: 0 - success, otherwise - failure
781fe2413ffSjeremylt 
782fe2413ffSjeremylt   @ref Advanced
783fe2413ffSjeremylt **/
784fe2413ffSjeremylt 
785fe2413ffSjeremylt int CeedOperatorSetData(CeedOperator op, void **data) {
786fe2413ffSjeremylt   op->data = *data;
787fe2413ffSjeremylt   return 0;
788fe2413ffSjeremylt }
789fe2413ffSjeremylt 
790fe2413ffSjeremylt /**
7914ce2993fSjeremylt   @brief Get the backend data of a CeedOperator
7924ce2993fSjeremylt 
7934ce2993fSjeremylt   @param op              CeedOperator
7944ce2993fSjeremylt   @param[out] data       Variable to store data
7954ce2993fSjeremylt 
7964ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
7974ce2993fSjeremylt 
79823617272Sjeremylt   @ref Advanced
7994ce2993fSjeremylt **/
8004ce2993fSjeremylt 
8014ce2993fSjeremylt int CeedOperatorGetData(CeedOperator op, void **data) {
8024ce2993fSjeremylt   *data = op->data;
8034ce2993fSjeremylt   return 0;
8044ce2993fSjeremylt }
8054ce2993fSjeremylt 
8064ce2993fSjeremylt /**
8074ce2993fSjeremylt   @brief Set the setup flag of a CeedOperator to True
8084ce2993fSjeremylt 
8094ce2993fSjeremylt   @param op              CeedOperator
8104ce2993fSjeremylt 
8114ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
8124ce2993fSjeremylt 
81323617272Sjeremylt   @ref Advanced
8144ce2993fSjeremylt **/
8154ce2993fSjeremylt 
8164ce2993fSjeremylt int CeedOperatorSetSetupDone(CeedOperator op) {
8174ce2993fSjeremylt   op->setupdone = 1;
8184ce2993fSjeremylt   return 0;
8194ce2993fSjeremylt }
8204ce2993fSjeremylt 
8214ce2993fSjeremylt /**
8222ebaca42Sjeremylt   @brief View a field of a CeedOperator
8232ebaca42Sjeremylt 
8242ebaca42Sjeremylt   @param[in] field       Operator field to view
8252ebaca42Sjeremylt   @param[in] fieldnumber Number of field being viewed
8262ebaca42Sjeremylt   @param[in] stream      Stream to view to, e.g., stdout
8272ebaca42Sjeremylt 
8282ebaca42Sjeremylt   @return An error code: 0 - success, otherwise - failure
8292ebaca42Sjeremylt 
8302ebaca42Sjeremylt   @ref Utility
8312ebaca42Sjeremylt **/
8322ebaca42Sjeremylt static int CeedOperatorFieldView(CeedOperatorField field,
8332ebaca42Sjeremylt                                  CeedQFunctionField qffield,
8342da88da5Sjeremylt                                  CeedInt fieldnumber, bool sub, bool in,
8352da88da5Sjeremylt                                  FILE *stream) {
8362ebaca42Sjeremylt   const char *pre = sub ? "  " : "";
8372da88da5Sjeremylt   const char *inout = in ? "Input" : "Output";
8382ebaca42Sjeremylt 
8392da88da5Sjeremylt   fprintf(stream, "%s    %s Field [%d]:\n"
840a8d32208Sjeremylt           "%s      Name: \"%s\"\n",
841a8d32208Sjeremylt           pre, inout, fieldnumber, pre, qffield->fieldname);
8422ebaca42Sjeremylt 
8432ebaca42Sjeremylt   if (field->basis == CEED_BASIS_COLLOCATED)
8442ebaca42Sjeremylt     fprintf(stream, "%s      Collocated basis\n", pre);
8452ebaca42Sjeremylt 
8462ebaca42Sjeremylt   if (field->vec == CEED_VECTOR_ACTIVE)
8472ebaca42Sjeremylt     fprintf(stream, "%s      Active vector\n", pre);
8482ebaca42Sjeremylt   else if (field->vec == CEED_VECTOR_NONE)
8492ebaca42Sjeremylt     fprintf(stream, "%s      No vector\n", pre);
8502ebaca42Sjeremylt 
8512ebaca42Sjeremylt   return 0;
8522ebaca42Sjeremylt }
8532ebaca42Sjeremylt 
8542ebaca42Sjeremylt /**
8552ebaca42Sjeremylt   @brief View a single CeedOperator
8562ebaca42Sjeremylt 
8572ebaca42Sjeremylt   @param[in] op     CeedOperator to view
85877645d7bSjeremylt   @param[in] sub    Boolean flag for sub-operator
8592ebaca42Sjeremylt   @param[in] stream Stream to write; typically stdout/stderr or a file
8602ebaca42Sjeremylt 
8612ebaca42Sjeremylt   @return Error code: 0 - success, otherwise - failure
8622ebaca42Sjeremylt 
8632ebaca42Sjeremylt   @ref Utility
8642ebaca42Sjeremylt **/
8652ebaca42Sjeremylt int CeedOperatorSingleView(CeedOperator op, bool sub, FILE *stream) {
8662ebaca42Sjeremylt   int ierr;
8672ebaca42Sjeremylt   const char *pre = sub ? "  " : "";
8682ebaca42Sjeremylt 
8692ebaca42Sjeremylt   CeedInt totalfields;
8702ebaca42Sjeremylt   ierr = CeedOperatorGetNumArgs(op, &totalfields); CeedChk(ierr);
8712da88da5Sjeremylt 
8722ebaca42Sjeremylt   fprintf(stream, "%s  %d Field%s\n", pre, totalfields, totalfields>1 ? "s" : "");
8732ebaca42Sjeremylt 
8742da88da5Sjeremylt   fprintf(stream, "%s  %d Input Field%s:\n", pre, op->qf->numinputfields,
8752ebaca42Sjeremylt           op->qf->numinputfields>1 ? "s" : "");
8762ebaca42Sjeremylt   for (CeedInt i=0; i<op->qf->numinputfields; i++) {
8772ebaca42Sjeremylt     ierr = CeedOperatorFieldView(op->inputfields[i], op->qf->inputfields[i],
8782da88da5Sjeremylt                                  i, sub, 1, stream); CeedChk(ierr);
8792ebaca42Sjeremylt   }
8802ebaca42Sjeremylt 
8812da88da5Sjeremylt   fprintf(stream, "%s  %d Output Field%s:\n", pre, op->qf->numoutputfields,
8822ebaca42Sjeremylt           op->qf->numoutputfields>1 ? "s" : "");
8832ebaca42Sjeremylt   for (CeedInt i=0; i<op->qf->numoutputfields; i++) {
8842ebaca42Sjeremylt     ierr = CeedOperatorFieldView(op->outputfields[i], op->qf->inputfields[i],
8852da88da5Sjeremylt                                  i, sub, 0, stream); CeedChk(ierr);
8862ebaca42Sjeremylt   }
8872ebaca42Sjeremylt 
8882ebaca42Sjeremylt   return 0;
8892ebaca42Sjeremylt }
8902ebaca42Sjeremylt 
8912ebaca42Sjeremylt /**
8922ebaca42Sjeremylt   @brief View a CeedOperator
8932ebaca42Sjeremylt 
8942ebaca42Sjeremylt   @param[in] op     CeedOperator to view
8952ebaca42Sjeremylt   @param[in] stream Stream to write; typically stdout/stderr or a file
8962ebaca42Sjeremylt 
8972ebaca42Sjeremylt   @return Error code: 0 - success, otherwise - failure
8982ebaca42Sjeremylt 
8992ebaca42Sjeremylt   @ref Utility
9002ebaca42Sjeremylt **/
9012ebaca42Sjeremylt int CeedOperatorView(CeedOperator op, FILE *stream) {
9022ebaca42Sjeremylt   int ierr;
9032ebaca42Sjeremylt 
9042ebaca42Sjeremylt   if (op->composite) {
9052ebaca42Sjeremylt     fprintf(stream, "Composite CeedOperator\n");
9062ebaca42Sjeremylt 
9072ebaca42Sjeremylt     for (CeedInt i=0; i<op->numsub; i++) {
9082da88da5Sjeremylt       fprintf(stream, "  SubOperator [%d]:\n", i);
9092ebaca42Sjeremylt       ierr = CeedOperatorSingleView(op->suboperators[i], 1, stream);
9102ebaca42Sjeremylt       CeedChk(ierr);
9112ebaca42Sjeremylt     }
9122ebaca42Sjeremylt   } else {
9132ebaca42Sjeremylt     fprintf(stream, "CeedOperator\n");
9142ebaca42Sjeremylt     ierr = CeedOperatorSingleView(op, 0, stream); CeedChk(ierr);
9152ebaca42Sjeremylt   }
9162ebaca42Sjeremylt 
9172ebaca42Sjeremylt   return 0;
9182ebaca42Sjeremylt }
9192ebaca42Sjeremylt 
9202ebaca42Sjeremylt /**
921d1bcdac9Sjeremylt   @brief Get the CeedOperatorFields of a CeedOperator
922d1bcdac9Sjeremylt 
923d1bcdac9Sjeremylt   @param op                 CeedOperator
924d1bcdac9Sjeremylt   @param[out] inputfields   Variable to store inputfields
925d1bcdac9Sjeremylt   @param[out] outputfields  Variable to store outputfields
926d1bcdac9Sjeremylt 
927d1bcdac9Sjeremylt   @return An error code: 0 - success, otherwise - failure
928d1bcdac9Sjeremylt 
929d1bcdac9Sjeremylt   @ref Advanced
930d1bcdac9Sjeremylt **/
931d1bcdac9Sjeremylt 
932692c2638Sjeremylt int CeedOperatorGetFields(CeedOperator op, CeedOperatorField **inputfields,
933d1bcdac9Sjeremylt                           CeedOperatorField **outputfields) {
93452d6035fSJeremy L Thompson   if (op->composite)
935c042f62fSJeremy L Thompson     // LCOV_EXCL_START
93652d6035fSJeremy L Thompson     return CeedError(op->ceed, 1, "Not defined for composite operator");
937c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
93852d6035fSJeremy L Thompson 
939d1bcdac9Sjeremylt   if (inputfields) *inputfields = op->inputfields;
940d1bcdac9Sjeremylt   if (outputfields) *outputfields = op->outputfields;
941d1bcdac9Sjeremylt   return 0;
942d1bcdac9Sjeremylt }
943d1bcdac9Sjeremylt 
944d1bcdac9Sjeremylt /**
945d1bcdac9Sjeremylt   @brief Get the CeedElemRestriction of a CeedOperatorField
946d1bcdac9Sjeremylt 
947d1bcdac9Sjeremylt   @param opfield         CeedOperatorField
948d1bcdac9Sjeremylt   @param[out] rstr       Variable to store CeedElemRestriction
949d1bcdac9Sjeremylt 
950d1bcdac9Sjeremylt   @return An error code: 0 - success, otherwise - failure
951d1bcdac9Sjeremylt 
952d1bcdac9Sjeremylt   @ref Advanced
953d1bcdac9Sjeremylt **/
954d1bcdac9Sjeremylt 
955d1bcdac9Sjeremylt int CeedOperatorFieldGetElemRestriction(CeedOperatorField opfield,
956d1bcdac9Sjeremylt                                         CeedElemRestriction *rstr) {
957fe2413ffSjeremylt   *rstr = opfield->Erestrict;
958d1bcdac9Sjeremylt   return 0;
959d1bcdac9Sjeremylt }
960d1bcdac9Sjeremylt 
961d1bcdac9Sjeremylt /**
962d1bcdac9Sjeremylt   @brief Get the CeedBasis of a CeedOperatorField
963d1bcdac9Sjeremylt 
964d1bcdac9Sjeremylt   @param opfield         CeedOperatorField
965d1bcdac9Sjeremylt   @param[out] basis      Variable to store CeedBasis
966d1bcdac9Sjeremylt 
967d1bcdac9Sjeremylt   @return An error code: 0 - success, otherwise - failure
968d1bcdac9Sjeremylt 
969d1bcdac9Sjeremylt   @ref Advanced
970d1bcdac9Sjeremylt **/
971d1bcdac9Sjeremylt 
972692c2638Sjeremylt int CeedOperatorFieldGetBasis(CeedOperatorField opfield, CeedBasis *basis) {
973fe2413ffSjeremylt   *basis = opfield->basis;
974d1bcdac9Sjeremylt   return 0;
975d1bcdac9Sjeremylt }
976d1bcdac9Sjeremylt 
977d1bcdac9Sjeremylt /**
978d1bcdac9Sjeremylt   @brief Get the CeedVector of a CeedOperatorField
979d1bcdac9Sjeremylt 
980d1bcdac9Sjeremylt   @param opfield         CeedOperatorField
981d1bcdac9Sjeremylt   @param[out] vec        Variable to store CeedVector
982d1bcdac9Sjeremylt 
983d1bcdac9Sjeremylt   @return An error code: 0 - success, otherwise - failure
984d1bcdac9Sjeremylt 
985d1bcdac9Sjeremylt   @ref Advanced
986d1bcdac9Sjeremylt **/
987d1bcdac9Sjeremylt 
988692c2638Sjeremylt int CeedOperatorFieldGetVector(CeedOperatorField opfield, CeedVector *vec) {
989fe2413ffSjeremylt   *vec = opfield->vec;
990d1bcdac9Sjeremylt   return 0;
991d1bcdac9Sjeremylt }
992d1bcdac9Sjeremylt 
993d1bcdac9Sjeremylt /**
994b11c1e72Sjeremylt   @brief Destroy a CeedOperator
995d7b241e6Sjeremylt 
996d7b241e6Sjeremylt   @param op CeedOperator to destroy
997b11c1e72Sjeremylt 
998b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
999dfdf5a53Sjeremylt 
1000dfdf5a53Sjeremylt   @ref Basic
1001b11c1e72Sjeremylt **/
1002d7b241e6Sjeremylt int CeedOperatorDestroy(CeedOperator *op) {
1003d7b241e6Sjeremylt   int ierr;
1004d7b241e6Sjeremylt 
1005d7b241e6Sjeremylt   if (!*op || --(*op)->refcount > 0) return 0;
1006d7b241e6Sjeremylt   if ((*op)->Destroy) {
1007d7b241e6Sjeremylt     ierr = (*op)->Destroy(*op); CeedChk(ierr);
1008d7b241e6Sjeremylt   }
1009fe2413ffSjeremylt   ierr = CeedDestroy(&(*op)->ceed); CeedChk(ierr);
1010fe2413ffSjeremylt   // Free fields
10111d102b48SJeremy L Thompson   for (int i=0; i<(*op)->nfields; i++)
101252d6035fSJeremy L Thompson     if ((*op)->inputfields[i]) {
1013*15910d16Sjeremylt       if ((*op)->inputfields[i]->Erestrict != CEED_ELEMRESTRICTION_NONE) {
101471352a93Sjeremylt         ierr = CeedElemRestrictionDestroy(&(*op)->inputfields[i]->Erestrict);
101571352a93Sjeremylt         CeedChk(ierr);
1016*15910d16Sjeremylt       }
101771352a93Sjeremylt       if ((*op)->inputfields[i]->basis != CEED_BASIS_COLLOCATED) {
101871352a93Sjeremylt         ierr = CeedBasisDestroy(&(*op)->inputfields[i]->basis); CeedChk(ierr);
101971352a93Sjeremylt       }
102071352a93Sjeremylt       if ((*op)->inputfields[i]->vec != CEED_VECTOR_ACTIVE &&
102171352a93Sjeremylt           (*op)->inputfields[i]->vec != CEED_VECTOR_NONE ) {
102271352a93Sjeremylt         ierr = CeedVectorDestroy(&(*op)->inputfields[i]->vec); CeedChk(ierr);
102371352a93Sjeremylt       }
1024fe2413ffSjeremylt       ierr = CeedFree(&(*op)->inputfields[i]); CeedChk(ierr);
1025fe2413ffSjeremylt     }
10261d102b48SJeremy L Thompson   for (int i=0; i<(*op)->nfields; i++)
1027d0eb30a5Sjeremylt     if ((*op)->outputfields[i]) {
102871352a93Sjeremylt       ierr = CeedElemRestrictionDestroy(&(*op)->outputfields[i]->Erestrict);
102971352a93Sjeremylt       CeedChk(ierr);
103071352a93Sjeremylt       if ((*op)->outputfields[i]->basis != CEED_BASIS_COLLOCATED) {
103171352a93Sjeremylt         ierr = CeedBasisDestroy(&(*op)->outputfields[i]->basis); CeedChk(ierr);
103271352a93Sjeremylt       }
103371352a93Sjeremylt       if ((*op)->outputfields[i]->vec != CEED_VECTOR_ACTIVE &&
103471352a93Sjeremylt           (*op)->outputfields[i]->vec != CEED_VECTOR_NONE ) {
103571352a93Sjeremylt         ierr = CeedVectorDestroy(&(*op)->outputfields[i]->vec); CeedChk(ierr);
103671352a93Sjeremylt       }
1037fe2413ffSjeremylt       ierr = CeedFree(&(*op)->outputfields[i]); CeedChk(ierr);
1038fe2413ffSjeremylt     }
103952d6035fSJeremy L Thompson   // Destroy suboperators
10401d102b48SJeremy L Thompson   for (int i=0; i<(*op)->numsub; i++)
104152d6035fSJeremy L Thompson     if ((*op)->suboperators[i]) {
104252d6035fSJeremy L Thompson       ierr = CeedOperatorDestroy(&(*op)->suboperators[i]); CeedChk(ierr);
104352d6035fSJeremy L Thompson     }
1044d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->qf); CeedChk(ierr);
1045d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->dqf); CeedChk(ierr);
1046d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->dqfT); CeedChk(ierr);
1047fe2413ffSjeremylt 
10485107b09fSJeremy L Thompson   // Destroy fallback
10495107b09fSJeremy L Thompson   if ((*op)->opfallback) {
10505107b09fSJeremy L Thompson     ierr = (*op)->qffallback->Destroy((*op)->qffallback); CeedChk(ierr);
10515107b09fSJeremy L Thompson     ierr = CeedFree(&(*op)->qffallback); CeedChk(ierr);
10525107b09fSJeremy L Thompson     ierr = (*op)->opfallback->Destroy((*op)->opfallback); CeedChk(ierr);
10535107b09fSJeremy L Thompson     ierr = CeedFree(&(*op)->opfallback); CeedChk(ierr);
10545107b09fSJeremy L Thompson   }
10555107b09fSJeremy L Thompson 
1056fe2413ffSjeremylt   ierr = CeedFree(&(*op)->inputfields); CeedChk(ierr);
1057fe2413ffSjeremylt   ierr = CeedFree(&(*op)->outputfields); CeedChk(ierr);
105852d6035fSJeremy L Thompson   ierr = CeedFree(&(*op)->suboperators); CeedChk(ierr);
1059d7b241e6Sjeremylt   ierr = CeedFree(op); CeedChk(ierr);
1060d7b241e6Sjeremylt   return 0;
1061d7b241e6Sjeremylt }
1062d7b241e6Sjeremylt 
1063d7b241e6Sjeremylt /// @}
1064