xref: /libCEED/rust/libceed-sys/c-src/interface/ceed-operator.c (revision 34138859218ba2ce39a42cdecc70f28818628fe8)
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>
20d7b241e6Sjeremylt 
21dfdf5a53Sjeremylt /// @file
22dfdf5a53Sjeremylt /// Implementation of public CeedOperator interfaces
23dfdf5a53Sjeremylt ///
24dfdf5a53Sjeremylt /// @addtogroup CeedOperator
25dfdf5a53Sjeremylt ///   @{
26d7b241e6Sjeremylt 
27d7b241e6Sjeremylt /**
280219ea01SJeremy L Thompson   @brief Create a CeedOperator and associate a CeedQFunction. A CeedBasis and
290219ea01SJeremy L Thompson            CeedElemRestriction can be associated with CeedQFunction fields with
300219ea01SJeremy L Thompson            \ref CeedOperatorSetField.
31d7b241e6Sjeremylt 
32b11c1e72Sjeremylt   @param ceed    A Ceed object where the CeedOperator will be created
33d7b241e6Sjeremylt   @param qf      QFunction defining the action of the operator at quadrature points
34*34138859Sjeremylt   @param dqf     QFunction defining the action of the Jacobian of @a qf (or
35*34138859Sjeremylt                    CEED_QFUNCTION_NONE)
36d7b241e6Sjeremylt   @param dqfT    QFunction defining the action of the transpose of the Jacobian
37*34138859Sjeremylt                    of @a qf (or CEED_QFUNCTION_NONE)
38b11c1e72Sjeremylt   @param[out] op Address of the variable where the newly created
39b11c1e72Sjeremylt                      CeedOperator will be stored
40b11c1e72Sjeremylt 
41b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
42dfdf5a53Sjeremylt 
43dfdf5a53Sjeremylt   @ref Basic
44d7b241e6Sjeremylt  */
45d7b241e6Sjeremylt int CeedOperatorCreate(Ceed ceed, CeedQFunction qf, CeedQFunction dqf,
46d7b241e6Sjeremylt                        CeedQFunction dqfT, CeedOperator *op) {
47d7b241e6Sjeremylt   int ierr;
48d7b241e6Sjeremylt 
495fe0d4faSjeremylt   if (!ceed->OperatorCreate) {
505fe0d4faSjeremylt     Ceed delegate;
51aefd8378Sjeremylt     ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr);
525fe0d4faSjeremylt 
535fe0d4faSjeremylt     if (!delegate)
54c042f62fSJeremy L Thompson       // LCOV_EXCL_START
555fe0d4faSjeremylt       return CeedError(ceed, 1, "Backend does not support OperatorCreate");
56c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
575fe0d4faSjeremylt 
585fe0d4faSjeremylt     ierr = CeedOperatorCreate(delegate, qf, dqf, dqfT, op); CeedChk(ierr);
595fe0d4faSjeremylt     return 0;
605fe0d4faSjeremylt   }
615fe0d4faSjeremylt 
62d7b241e6Sjeremylt   ierr = CeedCalloc(1, op); CeedChk(ierr);
63d7b241e6Sjeremylt   (*op)->ceed = ceed;
64d7b241e6Sjeremylt   ceed->refcount++;
65d7b241e6Sjeremylt   (*op)->refcount = 1;
66442e7f0bSjeremylt   if (qf == CEED_QFUNCTION_NONE)
67442e7f0bSjeremylt     // LCOV_EXCL_START
68442e7f0bSjeremylt     return CeedError(ceed, 1, "Operator must have a valid QFunction.");
69442e7f0bSjeremylt   // LCOV_EXCL_STOP
70d7b241e6Sjeremylt   (*op)->qf = qf;
71d7b241e6Sjeremylt   qf->refcount++;
72442e7f0bSjeremylt   if (dqf && dqf != CEED_QFUNCTION_NONE) {
73d7b241e6Sjeremylt     (*op)->dqf = dqf;
74442e7f0bSjeremylt     dqf->refcount++;
75442e7f0bSjeremylt   }
76442e7f0bSjeremylt   if (dqfT && dqfT != CEED_QFUNCTION_NONE) {
77d7b241e6Sjeremylt     (*op)->dqfT = dqfT;
78442e7f0bSjeremylt     dqfT->refcount++;
79442e7f0bSjeremylt   }
80fe2413ffSjeremylt   ierr = CeedCalloc(16, &(*op)->inputfields); CeedChk(ierr);
81fe2413ffSjeremylt   ierr = CeedCalloc(16, &(*op)->outputfields); CeedChk(ierr);
82d7b241e6Sjeremylt   ierr = ceed->OperatorCreate(*op); CeedChk(ierr);
83d7b241e6Sjeremylt   return 0;
84d7b241e6Sjeremylt }
85d7b241e6Sjeremylt 
86d7b241e6Sjeremylt /**
8752d6035fSJeremy L Thompson   @brief Create an operator that composes the action of several operators
8852d6035fSJeremy L Thompson 
8952d6035fSJeremy L Thompson   @param ceed    A Ceed object where the CeedOperator will be created
9052d6035fSJeremy L Thompson   @param[out] op Address of the variable where the newly created
9152d6035fSJeremy L Thompson                      Composite CeedOperator will be stored
9252d6035fSJeremy L Thompson 
9352d6035fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
9452d6035fSJeremy L Thompson 
9552d6035fSJeremy L Thompson   @ref Basic
9652d6035fSJeremy L Thompson  */
9752d6035fSJeremy L Thompson int CeedCompositeOperatorCreate(Ceed ceed, CeedOperator *op) {
9852d6035fSJeremy L Thompson   int ierr;
9952d6035fSJeremy L Thompson 
10052d6035fSJeremy L Thompson   if (!ceed->CompositeOperatorCreate) {
10152d6035fSJeremy L Thompson     Ceed delegate;
102aefd8378Sjeremylt     ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr);
10352d6035fSJeremy L Thompson 
10452d6035fSJeremy L Thompson     if (!delegate)
105c042f62fSJeremy L Thompson       // LCOV_EXCL_START
1061d102b48SJeremy L Thompson       return CeedError(ceed, 1, "Backend does not support "
1071d102b48SJeremy L Thompson                        "CompositeOperatorCreate");
108c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
10952d6035fSJeremy L Thompson 
11052d6035fSJeremy L Thompson     ierr = CeedCompositeOperatorCreate(delegate, op); CeedChk(ierr);
11152d6035fSJeremy L Thompson     return 0;
11252d6035fSJeremy L Thompson   }
11352d6035fSJeremy L Thompson 
11452d6035fSJeremy L Thompson   ierr = CeedCalloc(1,op); CeedChk(ierr);
11552d6035fSJeremy L Thompson   (*op)->ceed = ceed;
11652d6035fSJeremy L Thompson   ceed->refcount++;
11752d6035fSJeremy L Thompson   (*op)->composite = true;
11852d6035fSJeremy L Thompson   ierr = CeedCalloc(16, &(*op)->suboperators); CeedChk(ierr);
11952d6035fSJeremy L Thompson   ierr = ceed->CompositeOperatorCreate(*op); CeedChk(ierr);
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 
235*34138859Sjeremylt   @param[out] compositeop Composite CeedOperator
236*34138859Sjeremylt   @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 /**
3131d102b48SJeremy L Thompson   @brief Assemble a linear CeedQFunction associated with a CeedOperator
3141d102b48SJeremy L Thompson 
3151d102b48SJeremy L Thompson   This returns a CeedVector containing a matrix at each quadrature point
3161d102b48SJeremy L Thompson     providing the action of the CeedQFunction associated with the CeedOperator.
3171d102b48SJeremy L Thompson     The vector 'assembled' is of shape
3181d102b48SJeremy L Thompson       [num_elements, num_input_fields, num_output_fields, num_quad_points]
3191d102b48SJeremy L Thompson     and contains column-major matrices representing the action of the
3201d102b48SJeremy L Thompson     CeedQFunction for a corresponding quadrature point on an element. Inputs and
3211d102b48SJeremy L Thompson     outputs are in the order provided by the user when adding CeedOperator fields.
3221d102b48SJeremy L Thompson     For example, a QFunction with inputs 'u' and 'gradu' and outputs 'gradv' and
3231d102b48SJeremy L Thompson     'v', provided in that order, would result in an assembled QFunction that
3241d102b48SJeremy L Thompson     consists of (1 + dim) x (dim + 1) matrices at each quadrature point acting
3251d102b48SJeremy L Thompson     on the input [u, du_0, du_1] and producing the output [dv_0, dv_1, v].
3261d102b48SJeremy L Thompson 
3271d102b48SJeremy L Thompson   @param op             CeedOperator to assemble CeedQFunction
3281d102b48SJeremy L Thompson   @param[out] assembled CeedVector to store assembled CeedQFunction at
3291d102b48SJeremy L Thompson                           quadrature points
3301d102b48SJeremy L Thompson   @param[out] rstr      CeedElemRestriction for CeedVector containing assembled
3311d102b48SJeremy L Thompson                           CeedQFunction
3321d102b48SJeremy L Thompson   @param request        Address of CeedRequest for non-blocking completion, else
3331d102b48SJeremy L Thompson                           CEED_REQUEST_IMMEDIATE
3341d102b48SJeremy L Thompson 
3351d102b48SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
3361d102b48SJeremy L Thompson 
337b7ec98d8SJeremy L Thompson   @ref Basic
3381d102b48SJeremy L Thompson **/
3391d102b48SJeremy L Thompson int CeedOperatorAssembleLinearQFunction(CeedOperator op, CeedVector *assembled,
3407f823360Sjeremylt                                         CeedElemRestriction *rstr,
3417f823360Sjeremylt                                         CeedRequest *request) {
3421d102b48SJeremy L Thompson   int ierr;
3431d102b48SJeremy L Thompson   Ceed ceed = op->ceed;
3441d102b48SJeremy L Thompson   CeedQFunction qf = op->qf;
3451d102b48SJeremy L Thompson 
3461d102b48SJeremy L Thompson   if (op->composite) {
347138d4072Sjeremylt     // LCOV_EXCL_START
3481d102b48SJeremy L Thompson     return CeedError(ceed, 1, "Cannot assemble QFunction for composite operator");
349138d4072Sjeremylt     // LCOV_EXCL_STOP
3501d102b48SJeremy L Thompson   } else {
3511d102b48SJeremy L Thompson     if (op->nfields == 0)
352138d4072Sjeremylt       // LCOV_EXCL_START
3531d102b48SJeremy L Thompson       return CeedError(ceed, 1, "No operator fields set");
354138d4072Sjeremylt     // LCOV_EXCL_STOP
3551d102b48SJeremy L Thompson     if (op->nfields < qf->numinputfields + qf->numoutputfields)
356138d4072Sjeremylt       // LCOV_EXCL_START
3571d102b48SJeremy L Thompson       return CeedError( ceed, 1, "Not all operator fields set");
358138d4072Sjeremylt     // LCOV_EXCL_STOP
3592cb0afc5Sjeremylt     if (!op->hasrestriction)
360138d4072Sjeremylt       // LCOV_EXCL_START
3611d102b48SJeremy L Thompson       return CeedError(ceed, 1, "At least one restriction required");
362138d4072Sjeremylt     // LCOV_EXCL_STOP
3631d102b48SJeremy L Thompson     if (op->numqpoints == 0)
364138d4072Sjeremylt       // LCOV_EXCL_START
3651d102b48SJeremy L Thompson       return CeedError(ceed, 1, "At least one non-collocated basis required");
366138d4072Sjeremylt     // LCOV_EXCL_STOP
3671d102b48SJeremy L Thompson   }
3685107b09fSJeremy L Thompson   if (op->AssembleLinearQFunction) {
3691d102b48SJeremy L Thompson     ierr = op->AssembleLinearQFunction(op, assembled, rstr, request);
3701d102b48SJeremy L Thompson     CeedChk(ierr);
3715107b09fSJeremy L Thompson   } else {
3725107b09fSJeremy L Thompson     // Fallback to reference Ceed
3735107b09fSJeremy L Thompson     if (!op->opfallback) {
3745107b09fSJeremy L Thompson       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
3755107b09fSJeremy L Thompson     }
3765107b09fSJeremy L Thompson     // Assemble
3775107b09fSJeremy L Thompson     ierr = op->opfallback->AssembleLinearQFunction(op->opfallback, assembled,
3785107b09fSJeremy L Thompson            rstr, request); CeedChk(ierr);
3795107b09fSJeremy L Thompson   }
3801d102b48SJeremy L Thompson   return 0;
3811d102b48SJeremy L Thompson }
3821d102b48SJeremy L Thompson 
3831d102b48SJeremy L Thompson /**
384b7ec98d8SJeremy L Thompson   @brief Assemble the diagonal of a square linear Operator
385b7ec98d8SJeremy L Thompson 
386b7ec98d8SJeremy L Thompson   This returns a CeedVector containing the diagonal of a linear CeedOperator.
387b7ec98d8SJeremy L Thompson 
388b7ec98d8SJeremy L Thompson   @param op             CeedOperator to assemble CeedQFunction
389b7ec98d8SJeremy L Thompson   @param[out] assembled CeedVector to store assembled CeedOperator diagonal
390b7ec98d8SJeremy L Thompson   @param request        Address of CeedRequest for non-blocking completion, else
391b7ec98d8SJeremy L Thompson                           CEED_REQUEST_IMMEDIATE
392b7ec98d8SJeremy L Thompson 
393b7ec98d8SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
394b7ec98d8SJeremy L Thompson 
395b7ec98d8SJeremy L Thompson   @ref Basic
396b7ec98d8SJeremy L Thompson **/
3977f823360Sjeremylt int CeedOperatorAssembleLinearDiagonal(CeedOperator op, CeedVector *assembled,
3987f823360Sjeremylt                                        CeedRequest *request) {
399b7ec98d8SJeremy L Thompson   int ierr;
400b7ec98d8SJeremy L Thompson   Ceed ceed = op->ceed;
401b7ec98d8SJeremy L Thompson   CeedQFunction qf = op->qf;
402b7ec98d8SJeremy L Thompson 
403b7ec98d8SJeremy L Thompson   if (op->composite) {
404b7ec98d8SJeremy L Thompson     // LCOV_EXCL_START
405b7ec98d8SJeremy L Thompson     return CeedError(ceed, 1, "Cannot assemble QFunction for composite operator");
406b7ec98d8SJeremy L Thompson     // LCOV_EXCL_STOP
407b7ec98d8SJeremy L Thompson   } else {
408b7ec98d8SJeremy L Thompson     if (op->nfields == 0)
409b7ec98d8SJeremy L Thompson       // LCOV_EXCL_START
410b7ec98d8SJeremy L Thompson       return CeedError(ceed, 1, "No operator fields set");
411b7ec98d8SJeremy L Thompson     // LCOV_EXCL_STOP
412b7ec98d8SJeremy L Thompson     if (op->nfields < qf->numinputfields + qf->numoutputfields)
413b7ec98d8SJeremy L Thompson       // LCOV_EXCL_START
414b7ec98d8SJeremy L Thompson       return CeedError( ceed, 1, "Not all operator fields set");
415b7ec98d8SJeremy L Thompson     // LCOV_EXCL_STOP
4162cb0afc5Sjeremylt     if (!op->hasrestriction)
417b7ec98d8SJeremy L Thompson       // LCOV_EXCL_START
418b7ec98d8SJeremy L Thompson       return CeedError(ceed, 1, "At least one restriction required");
419b7ec98d8SJeremy L Thompson     // LCOV_EXCL_STOP
420b7ec98d8SJeremy L Thompson     if (op->numqpoints == 0)
421b7ec98d8SJeremy L Thompson       // LCOV_EXCL_START
422b7ec98d8SJeremy L Thompson       return CeedError(ceed, 1, "At least one non-collocated basis required");
423b7ec98d8SJeremy L Thompson     // LCOV_EXCL_STOP
424b7ec98d8SJeremy L Thompson   }
425b7ec98d8SJeremy L Thompson 
426b7ec98d8SJeremy L Thompson   // Use backend version, if available
427b7ec98d8SJeremy L Thompson   if (op->AssembleLinearDiagonal) {
428b7ec98d8SJeremy L Thompson     ierr = op->AssembleLinearDiagonal(op, assembled, request); CeedChk(ierr);
429b7ec98d8SJeremy L Thompson     return 0;
430b7ec98d8SJeremy L Thompson   }
431b7ec98d8SJeremy L Thompson 
432b7ec98d8SJeremy L Thompson   // Assemble QFunction
433b7ec98d8SJeremy L Thompson   CeedVector assembledqf;
434b7ec98d8SJeremy L Thompson   CeedElemRestriction rstr;
435b7ec98d8SJeremy L Thompson   ierr = CeedOperatorAssembleLinearQFunction(op,  &assembledqf, &rstr, request);
436b7ec98d8SJeremy L Thompson   CeedChk(ierr);
437b7ec98d8SJeremy L Thompson   ierr = CeedElemRestrictionDestroy(&rstr); CeedChk(ierr);
438b7ec98d8SJeremy L Thompson 
439b7ec98d8SJeremy L Thompson   // Determine active input basis
440112e3f70Sjeremylt   CeedInt numemodein = 0, ncomp, dim = 1;
441b7ec98d8SJeremy L Thompson   CeedEvalMode *emodein = NULL;
442112e3f70Sjeremylt   CeedBasis basisin = NULL;
443112e3f70Sjeremylt   CeedElemRestriction rstrin = NULL;
444b7ec98d8SJeremy L Thompson   for (CeedInt i=0; i<qf->numinputfields; i++)
445b7ec98d8SJeremy L Thompson     if (op->inputfields[i]->vec == CEED_VECTOR_ACTIVE) {
446b7ec98d8SJeremy L Thompson       ierr = CeedOperatorFieldGetBasis(op->inputfields[i], &basisin);
447b7ec98d8SJeremy L Thompson       CeedChk(ierr);
448b7ec98d8SJeremy L Thompson       ierr = CeedBasisGetNumComponents(basisin, &ncomp); CeedChk(ierr);
449b7ec98d8SJeremy L Thompson       ierr = CeedBasisGetDimension(basisin, &dim); CeedChk(ierr);
450b7ec98d8SJeremy L Thompson       ierr = CeedOperatorFieldGetElemRestriction(op->inputfields[i], &rstrin);
451b7ec98d8SJeremy L Thompson       CeedChk(ierr);
452b7ec98d8SJeremy L Thompson       CeedEvalMode emode;
453b7ec98d8SJeremy L Thompson       ierr = CeedQFunctionFieldGetEvalMode(qf->inputfields[i], &emode);
454b7ec98d8SJeremy L Thompson       CeedChk(ierr);
455b7ec98d8SJeremy L Thompson       switch (emode) {
456b7ec98d8SJeremy L Thompson       case CEED_EVAL_NONE:
457b7ec98d8SJeremy L Thompson       case CEED_EVAL_INTERP:
458b7ec98d8SJeremy L Thompson         ierr = CeedRealloc(numemodein + 1, &emodein); CeedChk(ierr);
459b7ec98d8SJeremy L Thompson         emodein[numemodein] = emode;
460b7ec98d8SJeremy L Thompson         numemodein += 1;
461b7ec98d8SJeremy L Thompson         break;
462b7ec98d8SJeremy L Thompson       case CEED_EVAL_GRAD:
463b7ec98d8SJeremy L Thompson         ierr = CeedRealloc(numemodein + dim, &emodein); CeedChk(ierr);
464b7ec98d8SJeremy L Thompson         for (CeedInt d=0; d<dim; d++)
465b7ec98d8SJeremy L Thompson           emodein[numemodein+d] = emode;
466b7ec98d8SJeremy L Thompson         numemodein += dim;
467b7ec98d8SJeremy L Thompson         break;
468b7ec98d8SJeremy L Thompson       case CEED_EVAL_WEIGHT:
469b7ec98d8SJeremy L Thompson       case CEED_EVAL_DIV:
470b7ec98d8SJeremy L Thompson       case CEED_EVAL_CURL:
471b7ec98d8SJeremy L Thompson         break; // Caught by QF Assembly
472b7ec98d8SJeremy L Thompson       }
473b7ec98d8SJeremy L Thompson     }
474b7ec98d8SJeremy L Thompson 
475b7ec98d8SJeremy L Thompson   // Determine active output basis
476b7ec98d8SJeremy L Thompson   CeedInt numemodeout = 0;
477b7ec98d8SJeremy L Thompson   CeedEvalMode *emodeout = NULL;
478112e3f70Sjeremylt   CeedBasis basisout = NULL;
479112e3f70Sjeremylt   CeedElemRestriction rstrout = NULL;
480112e3f70Sjeremylt   CeedTransposeMode lmodeout = CEED_NOTRANSPOSE;
481b7ec98d8SJeremy L Thompson   for (CeedInt i=0; i<qf->numoutputfields; i++)
482b7ec98d8SJeremy L Thompson     if (op->outputfields[i]->vec == CEED_VECTOR_ACTIVE) {
483b7ec98d8SJeremy L Thompson       ierr = CeedOperatorFieldGetBasis(op->outputfields[i], &basisout);
484b7ec98d8SJeremy L Thompson       CeedChk(ierr);
485b7ec98d8SJeremy L Thompson       ierr = CeedOperatorFieldGetElemRestriction(op->outputfields[i], &rstrout);
486b7ec98d8SJeremy L Thompson       CeedChk(ierr);
487b7ec98d8SJeremy L Thompson       ierr = CeedOperatorFieldGetLMode(op->outputfields[i], &lmodeout);
488b7ec98d8SJeremy L Thompson       CeedChk(ierr);
489b7ec98d8SJeremy L Thompson       CeedEvalMode emode;
490b7ec98d8SJeremy L Thompson       ierr = CeedQFunctionFieldGetEvalMode(qf->outputfields[i], &emode);
491b7ec98d8SJeremy L Thompson       CeedChk(ierr);
492b7ec98d8SJeremy L Thompson       switch (emode) {
493b7ec98d8SJeremy L Thompson       case CEED_EVAL_NONE:
494b7ec98d8SJeremy L Thompson       case CEED_EVAL_INTERP:
495b7ec98d8SJeremy L Thompson         ierr = CeedRealloc(numemodeout + 1, &emodeout); CeedChk(ierr);
496b7ec98d8SJeremy L Thompson         emodeout[numemodeout] = emode;
497b7ec98d8SJeremy L Thompson         numemodeout += 1;
498b7ec98d8SJeremy L Thompson         break;
499b7ec98d8SJeremy L Thompson       case CEED_EVAL_GRAD:
500b7ec98d8SJeremy L Thompson         ierr = CeedRealloc(numemodeout + dim, &emodeout); CeedChk(ierr);
501b7ec98d8SJeremy L Thompson         for (CeedInt d=0; d<dim; d++)
502b7ec98d8SJeremy L Thompson           emodeout[numemodeout+d] = emode;
503b7ec98d8SJeremy L Thompson         numemodeout += dim;
504b7ec98d8SJeremy L Thompson         break;
505b7ec98d8SJeremy L Thompson       case CEED_EVAL_WEIGHT:
506b7ec98d8SJeremy L Thompson       case CEED_EVAL_DIV:
507b7ec98d8SJeremy L Thompson       case CEED_EVAL_CURL:
508b7ec98d8SJeremy L Thompson         break; // Caught by QF Assembly
509b7ec98d8SJeremy L Thompson       }
510b7ec98d8SJeremy L Thompson     }
511b7ec98d8SJeremy L Thompson 
512b7ec98d8SJeremy L Thompson   // Create diagonal vector
513b7ec98d8SJeremy L Thompson   CeedVector elemdiag;
514b7ec98d8SJeremy L Thompson   ierr = CeedElemRestrictionCreateVector(rstrin, assembled, &elemdiag);
515b7ec98d8SJeremy L Thompson   CeedChk(ierr);
516b7ec98d8SJeremy L Thompson 
517b7ec98d8SJeremy L Thompson   // Assemble element operator diagonals
518b7ec98d8SJeremy L Thompson   CeedScalar *elemdiagarray, *assembledqfarray;
519b7ec98d8SJeremy L Thompson   ierr = CeedVectorSetValue(elemdiag, 0.0); CeedChk(ierr);
520b7ec98d8SJeremy L Thompson   ierr = CeedVectorGetArray(elemdiag, CEED_MEM_HOST, &elemdiagarray);
521b7ec98d8SJeremy L Thompson   CeedChk(ierr);
522b7ec98d8SJeremy L Thompson   ierr = CeedVectorGetArray(assembledqf, CEED_MEM_HOST, &assembledqfarray);
523b7ec98d8SJeremy L Thompson   CeedChk(ierr);
524b7ec98d8SJeremy L Thompson   CeedInt nelem, nnodes, nqpts;
525b7ec98d8SJeremy L Thompson   ierr = CeedElemRestrictionGetNumElements(rstrin, &nelem); CeedChk(ierr);
526b7ec98d8SJeremy L Thompson   ierr = CeedBasisGetNumNodes(basisin, &nnodes); CeedChk(ierr);
527b7ec98d8SJeremy L Thompson   ierr = CeedBasisGetNumQuadraturePoints(basisin, &nqpts); CeedChk(ierr);
528b7ec98d8SJeremy L Thompson   // Compute the diagonal of B^T D B
529b7ec98d8SJeremy L Thompson   // Each node, qpt pair
530b7ec98d8SJeremy L Thompson   for (CeedInt n=0; n<nnodes; n++)
531b7ec98d8SJeremy L Thompson     for (CeedInt q=0; q<nqpts; q++) {
532b7ec98d8SJeremy L Thompson       CeedInt dout = -1;
533b7ec98d8SJeremy L Thompson       // Each basis eval mode pair
534b7ec98d8SJeremy L Thompson       for (CeedInt eout=0; eout<numemodeout; eout++) {
535b7ec98d8SJeremy L Thompson         CeedScalar bt = 1.0;
536b7ec98d8SJeremy L Thompson         if (emodeout[eout] == CEED_EVAL_GRAD)
537b7ec98d8SJeremy L Thompson           dout += 1;
538b7ec98d8SJeremy L Thompson         ierr = CeedBasisGetValue(basisout, emodeout[eout], q, n, dout, &bt);
539b7ec98d8SJeremy L Thompson         CeedChk(ierr);
540b7ec98d8SJeremy L Thompson         CeedInt din = -1;
541b7ec98d8SJeremy L Thompson         for (CeedInt ein=0; ein<numemodein; ein++) {
542b7ec98d8SJeremy L Thompson           CeedScalar b = 0.0;
543b7ec98d8SJeremy L Thompson           if (emodein[ein] == CEED_EVAL_GRAD)
544b7ec98d8SJeremy L Thompson             din += 1;
545b7ec98d8SJeremy L Thompson           ierr = CeedBasisGetValue(basisin, emodein[ein], q, n, din, &b);
546b7ec98d8SJeremy L Thompson           CeedChk(ierr);
547b7ec98d8SJeremy L Thompson           // Each element and component
548b7ec98d8SJeremy L Thompson           for (CeedInt e=0; e<nelem; e++)
549b7ec98d8SJeremy L Thompson             for (CeedInt cout=0; cout<ncomp; cout++) {
550b7ec98d8SJeremy L Thompson               CeedScalar db = 0.0;
551b7ec98d8SJeremy L Thompson               for (CeedInt cin=0; cin<ncomp; cin++)
552b7ec98d8SJeremy L Thompson                 db += assembledqfarray[((((e*numemodein+ein)*ncomp+cin)*
553b7ec98d8SJeremy L Thompson                                          numemodeout+eout)*ncomp+cout)*nqpts+q]*b;
554b7ec98d8SJeremy L Thompson               elemdiagarray[(e*ncomp+cout)*nnodes+n] += bt * db;
555b7ec98d8SJeremy L Thompson             }
556b7ec98d8SJeremy L Thompson         }
557b7ec98d8SJeremy L Thompson       }
558b7ec98d8SJeremy L Thompson     }
559b7ec98d8SJeremy L Thompson 
560b7ec98d8SJeremy L Thompson   ierr = CeedVectorRestoreArray(elemdiag, &elemdiagarray); CeedChk(ierr);
561b7ec98d8SJeremy L Thompson   ierr = CeedVectorRestoreArray(assembledqf, &assembledqfarray); CeedChk(ierr);
562b7ec98d8SJeremy L Thompson 
563b7ec98d8SJeremy L Thompson   // Assemble local operator diagonal
564b7ec98d8SJeremy L Thompson   ierr = CeedVectorSetValue(*assembled, 0.0); CeedChk(ierr);
565b7ec98d8SJeremy L Thompson   ierr = CeedElemRestrictionApply(rstrout, CEED_TRANSPOSE, lmodeout, elemdiag,
566b7ec98d8SJeremy L Thompson                                   *assembled, request); CeedChk(ierr);
567b7ec98d8SJeremy L Thompson 
568b7ec98d8SJeremy L Thompson   // Cleanup
569b7ec98d8SJeremy L Thompson   ierr = CeedVectorDestroy(&assembledqf); CeedChk(ierr);
570b7ec98d8SJeremy L Thompson   ierr = CeedVectorDestroy(&elemdiag); CeedChk(ierr);
571b7ec98d8SJeremy L Thompson   ierr = CeedFree(&emodein); CeedChk(ierr);
572b7ec98d8SJeremy L Thompson   ierr = CeedFree(&emodeout); CeedChk(ierr);
573b7ec98d8SJeremy L Thompson 
574b7ec98d8SJeremy L Thompson   return 0;
575b7ec98d8SJeremy L Thompson }
576b7ec98d8SJeremy L Thompson 
577b7ec98d8SJeremy L Thompson /**
578b11c1e72Sjeremylt   @brief Apply CeedOperator to a vector
579d7b241e6Sjeremylt 
580d7b241e6Sjeremylt   This computes the action of the operator on the specified (active) input,
581d7b241e6Sjeremylt   yielding its (active) output.  All inputs and outputs must be specified using
582d7b241e6Sjeremylt   CeedOperatorSetField().
583d7b241e6Sjeremylt 
584d7b241e6Sjeremylt   @param op        CeedOperator to apply
585*34138859Sjeremylt   @param[in] in    CeedVector containing input state or CEED_VECTOR_NONE if
586*34138859Sjeremylt                   there are no active inputs
587b11c1e72Sjeremylt   @param[out] out  CeedVector to store result of applying operator (must be
588*34138859Sjeremylt                      distinct from @a in) or CEED_VECTOR_NONE if there are no
589*34138859Sjeremylt                      active outputs
590d7b241e6Sjeremylt   @param request   Address of CeedRequest for non-blocking completion, else
591d7b241e6Sjeremylt                      CEED_REQUEST_IMMEDIATE
592b11c1e72Sjeremylt 
593b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
594dfdf5a53Sjeremylt 
595dfdf5a53Sjeremylt   @ref Basic
596b11c1e72Sjeremylt **/
597692c2638Sjeremylt int CeedOperatorApply(CeedOperator op, CeedVector in, CeedVector out,
598692c2638Sjeremylt                       CeedRequest *request) {
599d7b241e6Sjeremylt   int ierr;
600d7b241e6Sjeremylt   Ceed ceed = op->ceed;
601d7b241e6Sjeremylt   CeedQFunction qf = op->qf;
602d7b241e6Sjeremylt 
60352d6035fSJeremy L Thompson   if (op->composite) {
604c042f62fSJeremy L Thompson     if (!op->numsub)
605c042f62fSJeremy L Thompson       // LCOV_EXCL_START
606c042f62fSJeremy L Thompson       return CeedError(ceed, 1, "No suboperators set");
607c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
60852d6035fSJeremy L Thompson   } else {
609c042f62fSJeremy L Thompson     if (op->nfields == 0)
610c042f62fSJeremy L Thompson       // LCOV_EXCL_START
611c042f62fSJeremy L Thompson       return CeedError(ceed, 1, "No operator fields set");
612c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
613c042f62fSJeremy L Thompson     if (op->nfields < qf->numinputfields + qf->numoutputfields)
614c042f62fSJeremy L Thompson       // LCOV_EXCL_START
615c042f62fSJeremy L Thompson       return CeedError(ceed, 1, "Not all operator fields set");
616c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
6172cb0afc5Sjeremylt     if (!op->hasrestriction)
618c042f62fSJeremy L Thompson       // LCOV_EXCL_START
619c042f62fSJeremy L Thompson       return CeedError(ceed, 1,"At least one restriction required");
620c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
621c042f62fSJeremy L Thompson     if (op->numqpoints == 0)
622c042f62fSJeremy L Thompson       // LCOV_EXCL_START
623c042f62fSJeremy L Thompson       return CeedError(ceed, 1,"At least one non-collocated basis required");
624c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
62552d6035fSJeremy L Thompson   }
6261d7d2407SJeremy L Thompson   if (op->numelements || op->composite) {
627e97ff134Sjeremylt     ierr = op->Apply(op, in != CEED_VECTOR_NONE ? in : NULL,
628e97ff134Sjeremylt                      out != CEED_VECTOR_NONE ? out : NULL, request);
629e97ff134Sjeremylt     CeedChk(ierr);
6301d7d2407SJeremy L Thompson   }
631d7b241e6Sjeremylt   return 0;
632d7b241e6Sjeremylt }
633d7b241e6Sjeremylt 
634d7b241e6Sjeremylt /**
6354ce2993fSjeremylt   @brief Get the Ceed associated with a CeedOperator
6364ce2993fSjeremylt 
6374ce2993fSjeremylt   @param op              CeedOperator
6384ce2993fSjeremylt   @param[out] ceed       Variable to store Ceed
6394ce2993fSjeremylt 
6404ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
6414ce2993fSjeremylt 
64223617272Sjeremylt   @ref Advanced
6434ce2993fSjeremylt **/
6444ce2993fSjeremylt 
6454ce2993fSjeremylt int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) {
6464ce2993fSjeremylt   *ceed = op->ceed;
6474ce2993fSjeremylt   return 0;
6484ce2993fSjeremylt }
6494ce2993fSjeremylt 
6504ce2993fSjeremylt /**
6514ce2993fSjeremylt   @brief Get the number of elements associated with a CeedOperator
6524ce2993fSjeremylt 
6534ce2993fSjeremylt   @param op              CeedOperator
6544ce2993fSjeremylt   @param[out] numelem    Variable to store number of elements
6554ce2993fSjeremylt 
6564ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
6574ce2993fSjeremylt 
65823617272Sjeremylt   @ref Advanced
6594ce2993fSjeremylt **/
6604ce2993fSjeremylt 
6614ce2993fSjeremylt int CeedOperatorGetNumElements(CeedOperator op, CeedInt *numelem) {
66252d6035fSJeremy L Thompson   if (op->composite)
663c042f62fSJeremy L Thompson     // LCOV_EXCL_START
66452d6035fSJeremy L Thompson     return CeedError(op->ceed, 1, "Not defined for composite operator");
665c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
66652d6035fSJeremy L Thompson 
6674ce2993fSjeremylt   *numelem = op->numelements;
6684ce2993fSjeremylt   return 0;
6694ce2993fSjeremylt }
6704ce2993fSjeremylt 
6714ce2993fSjeremylt /**
6724ce2993fSjeremylt   @brief Get the number of quadrature points associated with a CeedOperator
6734ce2993fSjeremylt 
6744ce2993fSjeremylt   @param op              CeedOperator
6754ce2993fSjeremylt   @param[out] numqpts    Variable to store vector number of quadrature points
6764ce2993fSjeremylt 
6774ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
6784ce2993fSjeremylt 
67923617272Sjeremylt   @ref Advanced
6804ce2993fSjeremylt **/
6814ce2993fSjeremylt 
6824ce2993fSjeremylt int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *numqpts) {
68352d6035fSJeremy L Thompson   if (op->composite)
684c042f62fSJeremy L Thompson     // LCOV_EXCL_START
68552d6035fSJeremy L Thompson     return CeedError(op->ceed, 1, "Not defined for composite operator");
686c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
68752d6035fSJeremy L Thompson 
6884ce2993fSjeremylt   *numqpts = op->numqpoints;
6894ce2993fSjeremylt   return 0;
6904ce2993fSjeremylt }
6914ce2993fSjeremylt 
6924ce2993fSjeremylt /**
6934ce2993fSjeremylt   @brief Get the number of arguments associated with a CeedOperator
6944ce2993fSjeremylt 
6954ce2993fSjeremylt   @param op              CeedOperator
6964ce2993fSjeremylt   @param[out] numargs    Variable to store vector number of arguments
6974ce2993fSjeremylt 
6984ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
6994ce2993fSjeremylt 
70023617272Sjeremylt   @ref Advanced
7014ce2993fSjeremylt **/
7024ce2993fSjeremylt 
7034ce2993fSjeremylt int CeedOperatorGetNumArgs(CeedOperator op, CeedInt *numargs) {
70452d6035fSJeremy L Thompson   if (op->composite)
705c042f62fSJeremy L Thompson     // LCOV_EXCL_START
70652d6035fSJeremy L Thompson     return CeedError(op->ceed, 1, "Not defined for composite operators");
707c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
708c042f62fSJeremy L Thompson 
7094ce2993fSjeremylt   *numargs = op->nfields;
7104ce2993fSjeremylt   return 0;
7114ce2993fSjeremylt }
7124ce2993fSjeremylt 
7134ce2993fSjeremylt /**
7144ce2993fSjeremylt   @brief Get the setup status of a CeedOperator
7154ce2993fSjeremylt 
7164ce2993fSjeremylt   @param op             CeedOperator
717288c0443SJeremy L Thompson   @param[out] setupdone Variable to store setup status
7184ce2993fSjeremylt 
7194ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
7204ce2993fSjeremylt 
72123617272Sjeremylt   @ref Advanced
7224ce2993fSjeremylt **/
7234ce2993fSjeremylt 
7244ce2993fSjeremylt int CeedOperatorGetSetupStatus(CeedOperator op, bool *setupdone) {
7254ce2993fSjeremylt   *setupdone = op->setupdone;
7264ce2993fSjeremylt   return 0;
7274ce2993fSjeremylt }
7284ce2993fSjeremylt 
7294ce2993fSjeremylt /**
7304ce2993fSjeremylt   @brief Get the QFunction associated with a CeedOperator
7314ce2993fSjeremylt 
7324ce2993fSjeremylt   @param op              CeedOperator
7338c91a0c9SJeremy L Thompson   @param[out] qf         Variable to store QFunction
7344ce2993fSjeremylt 
7354ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
7364ce2993fSjeremylt 
73723617272Sjeremylt   @ref Advanced
7384ce2993fSjeremylt **/
7394ce2993fSjeremylt 
7404ce2993fSjeremylt int CeedOperatorGetQFunction(CeedOperator op, CeedQFunction *qf) {
74152d6035fSJeremy L Thompson   if (op->composite)
742c042f62fSJeremy L Thompson     // LCOV_EXCL_START
74352d6035fSJeremy L Thompson     return CeedError(op->ceed, 1, "Not defined for composite operator");
744c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
74552d6035fSJeremy L Thompson 
7464ce2993fSjeremylt   *qf = op->qf;
7474ce2993fSjeremylt   return 0;
7484ce2993fSjeremylt }
7494ce2993fSjeremylt 
7504ce2993fSjeremylt /**
75152d6035fSJeremy L Thompson   @brief Get the number of suboperators associated with a CeedOperator
75252d6035fSJeremy L Thompson 
75352d6035fSJeremy L Thompson   @param op              CeedOperator
75452d6035fSJeremy L Thompson   @param[out] numsub     Variable to store number of suboperators
75552d6035fSJeremy L Thompson 
75652d6035fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
75752d6035fSJeremy L Thompson 
75852d6035fSJeremy L Thompson   @ref Advanced
75952d6035fSJeremy L Thompson **/
76052d6035fSJeremy L Thompson 
76152d6035fSJeremy L Thompson int CeedOperatorGetNumSub(CeedOperator op, CeedInt *numsub) {
762c042f62fSJeremy L Thompson   if (!op->composite)
763c042f62fSJeremy L Thompson     // LCOV_EXCL_START
764c042f62fSJeremy L Thompson     return CeedError(op->ceed, 1, "Not a composite operator");
765c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
76652d6035fSJeremy L Thompson 
76752d6035fSJeremy L Thompson   *numsub = op->numsub;
76852d6035fSJeremy L Thompson   return 0;
76952d6035fSJeremy L Thompson }
77052d6035fSJeremy L Thompson 
77152d6035fSJeremy L Thompson /**
77252d6035fSJeremy L Thompson   @brief Get the list of suboperators associated with a CeedOperator
77352d6035fSJeremy L Thompson 
77452d6035fSJeremy L Thompson   @param op                CeedOperator
77552d6035fSJeremy L Thompson   @param[out] suboperators Variable to store list of suboperators
77652d6035fSJeremy L Thompson 
77752d6035fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
77852d6035fSJeremy L Thompson 
77952d6035fSJeremy L Thompson   @ref Advanced
78052d6035fSJeremy L Thompson **/
78152d6035fSJeremy L Thompson 
78252d6035fSJeremy L Thompson int CeedOperatorGetSubList(CeedOperator op, CeedOperator **suboperators) {
783c042f62fSJeremy L Thompson   if (!op->composite)
784c042f62fSJeremy L Thompson     // LCOV_EXCL_START
785c042f62fSJeremy L Thompson     return CeedError(op->ceed, 1, "Not a composite operator");
786c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
78752d6035fSJeremy L Thompson 
78852d6035fSJeremy L Thompson   *suboperators = op->suboperators;
78952d6035fSJeremy L Thompson   return 0;
79052d6035fSJeremy L Thompson }
79152d6035fSJeremy L Thompson 
79252d6035fSJeremy L Thompson /**
793fe2413ffSjeremylt   @brief Set the backend data of a CeedOperator
794fe2413ffSjeremylt 
795fe2413ffSjeremylt   @param[out] op         CeedOperator
796fe2413ffSjeremylt   @param data            Data to set
797fe2413ffSjeremylt 
798fe2413ffSjeremylt   @return An error code: 0 - success, otherwise - failure
799fe2413ffSjeremylt 
800fe2413ffSjeremylt   @ref Advanced
801fe2413ffSjeremylt **/
802fe2413ffSjeremylt 
803fe2413ffSjeremylt int CeedOperatorSetData(CeedOperator op, void **data) {
804fe2413ffSjeremylt   op->data = *data;
805fe2413ffSjeremylt   return 0;
806fe2413ffSjeremylt }
807fe2413ffSjeremylt 
808fe2413ffSjeremylt /**
8094ce2993fSjeremylt   @brief Get the backend data of a CeedOperator
8104ce2993fSjeremylt 
8114ce2993fSjeremylt   @param op              CeedOperator
8124ce2993fSjeremylt   @param[out] data       Variable to store data
8134ce2993fSjeremylt 
8144ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
8154ce2993fSjeremylt 
81623617272Sjeremylt   @ref Advanced
8174ce2993fSjeremylt **/
8184ce2993fSjeremylt 
8194ce2993fSjeremylt int CeedOperatorGetData(CeedOperator op, void **data) {
8204ce2993fSjeremylt   *data = op->data;
8214ce2993fSjeremylt   return 0;
8224ce2993fSjeremylt }
8234ce2993fSjeremylt 
8244ce2993fSjeremylt /**
8254ce2993fSjeremylt   @brief Set the setup flag of a CeedOperator to True
8264ce2993fSjeremylt 
8274ce2993fSjeremylt   @param op              CeedOperator
8284ce2993fSjeremylt 
8294ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
8304ce2993fSjeremylt 
83123617272Sjeremylt   @ref Advanced
8324ce2993fSjeremylt **/
8334ce2993fSjeremylt 
8344ce2993fSjeremylt int CeedOperatorSetSetupDone(CeedOperator op) {
8354ce2993fSjeremylt   op->setupdone = 1;
8364ce2993fSjeremylt   return 0;
8374ce2993fSjeremylt }
8384ce2993fSjeremylt 
8394ce2993fSjeremylt /**
8402ebaca42Sjeremylt   @brief View a field of a CeedOperator
8412ebaca42Sjeremylt 
8422ebaca42Sjeremylt   @param[in] field       Operator field to view
8432ebaca42Sjeremylt   @param[in] fieldnumber Number of field being viewed
8442ebaca42Sjeremylt   @param[in] stream      Stream to view to, e.g., stdout
8452ebaca42Sjeremylt 
8462ebaca42Sjeremylt   @return An error code: 0 - success, otherwise - failure
8472ebaca42Sjeremylt 
8482ebaca42Sjeremylt   @ref Utility
8492ebaca42Sjeremylt **/
8502ebaca42Sjeremylt static int CeedOperatorFieldView(CeedOperatorField field,
8512ebaca42Sjeremylt                                  CeedQFunctionField qffield,
8522da88da5Sjeremylt                                  CeedInt fieldnumber, bool sub, bool in,
8532da88da5Sjeremylt                                  FILE *stream) {
8542ebaca42Sjeremylt   const char *pre = sub ? "  " : "";
8552da88da5Sjeremylt   const char *inout = in ? "Input" : "Output";
8562ebaca42Sjeremylt 
8572da88da5Sjeremylt   fprintf(stream, "%s    %s Field [%d]:\n"
8582da88da5Sjeremylt           "%s      Name: \"%s\"\n"
8592da88da5Sjeremylt           "%s      Lmode: \"%s\"\n",
8602da88da5Sjeremylt           pre, inout, fieldnumber, pre, qffield->fieldname,
8612ebaca42Sjeremylt           pre, CeedTransposeModes[field->lmode]);
8622ebaca42Sjeremylt 
8632ebaca42Sjeremylt   if (field->basis == CEED_BASIS_COLLOCATED)
8642ebaca42Sjeremylt     fprintf(stream, "%s      Collocated basis\n", pre);
8652ebaca42Sjeremylt 
8662ebaca42Sjeremylt   if (field->vec == CEED_VECTOR_ACTIVE)
8672ebaca42Sjeremylt     fprintf(stream, "%s      Active vector\n", pre);
8682ebaca42Sjeremylt   else if (field->vec == CEED_VECTOR_NONE)
8692ebaca42Sjeremylt     fprintf(stream, "%s      No vector\n", pre);
8702ebaca42Sjeremylt 
8712ebaca42Sjeremylt   return 0;
8722ebaca42Sjeremylt }
8732ebaca42Sjeremylt 
8742ebaca42Sjeremylt /**
8752ebaca42Sjeremylt   @brief View a single CeedOperator
8762ebaca42Sjeremylt 
8772ebaca42Sjeremylt   @param[in] op     CeedOperator to view
8782ebaca42Sjeremylt   @param[in] stream Stream to write; typically stdout/stderr or a file
8792ebaca42Sjeremylt 
8802ebaca42Sjeremylt   @return Error code: 0 - success, otherwise - failure
8812ebaca42Sjeremylt 
8822ebaca42Sjeremylt   @ref Utility
8832ebaca42Sjeremylt **/
8842ebaca42Sjeremylt int CeedOperatorSingleView(CeedOperator op, bool sub, FILE *stream) {
8852ebaca42Sjeremylt   int ierr;
8862ebaca42Sjeremylt   const char *pre = sub ? "  " : "";
8872ebaca42Sjeremylt 
8882ebaca42Sjeremylt   CeedInt totalfields;
8892ebaca42Sjeremylt   ierr = CeedOperatorGetNumArgs(op, &totalfields); CeedChk(ierr);
8902da88da5Sjeremylt 
8912ebaca42Sjeremylt   fprintf(stream, "%s  %d Field%s\n", pre, totalfields, totalfields>1 ? "s" : "");
8922ebaca42Sjeremylt 
8932da88da5Sjeremylt   fprintf(stream, "%s  %d Input Field%s:\n", pre, op->qf->numinputfields,
8942ebaca42Sjeremylt           op->qf->numinputfields>1 ? "s" : "");
8952ebaca42Sjeremylt   for (CeedInt i=0; i<op->qf->numinputfields; i++) {
8962ebaca42Sjeremylt     ierr = CeedOperatorFieldView(op->inputfields[i], op->qf->inputfields[i],
8972da88da5Sjeremylt                                  i, sub, 1, stream); CeedChk(ierr);
8982ebaca42Sjeremylt   }
8992ebaca42Sjeremylt 
9002da88da5Sjeremylt   fprintf(stream, "%s  %d Output Field%s:\n", pre, op->qf->numoutputfields,
9012ebaca42Sjeremylt           op->qf->numoutputfields>1 ? "s" : "");
9022ebaca42Sjeremylt   for (CeedInt i=0; i<op->qf->numoutputfields; i++) {
9032ebaca42Sjeremylt     ierr = CeedOperatorFieldView(op->outputfields[i], op->qf->inputfields[i],
9042da88da5Sjeremylt                                  i, sub, 0, stream); CeedChk(ierr);
9052ebaca42Sjeremylt   }
9062ebaca42Sjeremylt 
9072ebaca42Sjeremylt   return 0;
9082ebaca42Sjeremylt }
9092ebaca42Sjeremylt 
9102ebaca42Sjeremylt /**
9112ebaca42Sjeremylt   @brief View a CeedOperator
9122ebaca42Sjeremylt 
9132ebaca42Sjeremylt   @param[in] op     CeedOperator to view
9142ebaca42Sjeremylt   @param[in] stream Stream to write; typically stdout/stderr or a file
9152ebaca42Sjeremylt 
9162ebaca42Sjeremylt   @return Error code: 0 - success, otherwise - failure
9172ebaca42Sjeremylt 
9182ebaca42Sjeremylt   @ref Utility
9192ebaca42Sjeremylt **/
9202ebaca42Sjeremylt int CeedOperatorView(CeedOperator op, FILE *stream) {
9212ebaca42Sjeremylt   int ierr;
9222ebaca42Sjeremylt 
9232ebaca42Sjeremylt   if (op->composite) {
9242ebaca42Sjeremylt     fprintf(stream, "Composite CeedOperator\n");
9252ebaca42Sjeremylt 
9262ebaca42Sjeremylt     for (CeedInt i=0; i<op->numsub; i++) {
9272da88da5Sjeremylt       fprintf(stream, "  SubOperator [%d]:\n", i);
9282ebaca42Sjeremylt       ierr = CeedOperatorSingleView(op->suboperators[i], 1, stream);
9292ebaca42Sjeremylt       CeedChk(ierr);
9302ebaca42Sjeremylt     }
9312ebaca42Sjeremylt   } else {
9322ebaca42Sjeremylt     fprintf(stream, "CeedOperator\n");
9332ebaca42Sjeremylt     ierr = CeedOperatorSingleView(op, 0, stream); CeedChk(ierr);
9342ebaca42Sjeremylt   }
9352ebaca42Sjeremylt 
9362ebaca42Sjeremylt   return 0;
9372ebaca42Sjeremylt }
9382ebaca42Sjeremylt 
9392ebaca42Sjeremylt /**
940d1bcdac9Sjeremylt   @brief Get the CeedOperatorFields of a CeedOperator
941d1bcdac9Sjeremylt 
942d1bcdac9Sjeremylt   @param op                 CeedOperator
943d1bcdac9Sjeremylt   @param[out] inputfields   Variable to store inputfields
944d1bcdac9Sjeremylt   @param[out] outputfields  Variable to store outputfields
945d1bcdac9Sjeremylt 
946d1bcdac9Sjeremylt   @return An error code: 0 - success, otherwise - failure
947d1bcdac9Sjeremylt 
948d1bcdac9Sjeremylt   @ref Advanced
949d1bcdac9Sjeremylt **/
950d1bcdac9Sjeremylt 
951692c2638Sjeremylt int CeedOperatorGetFields(CeedOperator op, CeedOperatorField **inputfields,
952d1bcdac9Sjeremylt                           CeedOperatorField **outputfields) {
95352d6035fSJeremy L Thompson   if (op->composite)
954c042f62fSJeremy L Thompson     // LCOV_EXCL_START
95552d6035fSJeremy L Thompson     return CeedError(op->ceed, 1, "Not defined for composite operator");
956c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
95752d6035fSJeremy L Thompson 
958d1bcdac9Sjeremylt   if (inputfields) *inputfields = op->inputfields;
959d1bcdac9Sjeremylt   if (outputfields) *outputfields = op->outputfields;
960d1bcdac9Sjeremylt   return 0;
961d1bcdac9Sjeremylt }
962d1bcdac9Sjeremylt 
963d1bcdac9Sjeremylt /**
9644dccadb6Sjeremylt   @brief Get the L vector CeedTransposeMode of a CeedOperatorField
9654dccadb6Sjeremylt 
9664dccadb6Sjeremylt   @param opfield         CeedOperatorField
9674dccadb6Sjeremylt   @param[out] lmode      Variable to store CeedTransposeMode
9684dccadb6Sjeremylt 
9694dccadb6Sjeremylt   @return An error code: 0 - success, otherwise - failure
9704dccadb6Sjeremylt 
9714dccadb6Sjeremylt   @ref Advanced
9724dccadb6Sjeremylt **/
9734dccadb6Sjeremylt 
9744dccadb6Sjeremylt int CeedOperatorFieldGetLMode(CeedOperatorField opfield,
9754dccadb6Sjeremylt                               CeedTransposeMode *lmode) {
976fe2413ffSjeremylt   *lmode = opfield->lmode;
9774dccadb6Sjeremylt   return 0;
9782b8e417aSjeremylt }
9792b8e417aSjeremylt 
9802b8e417aSjeremylt /**
981d1bcdac9Sjeremylt   @brief Get the CeedElemRestriction of a CeedOperatorField
982d1bcdac9Sjeremylt 
983d1bcdac9Sjeremylt   @param opfield         CeedOperatorField
984d1bcdac9Sjeremylt   @param[out] rstr       Variable to store CeedElemRestriction
985d1bcdac9Sjeremylt 
986d1bcdac9Sjeremylt   @return An error code: 0 - success, otherwise - failure
987d1bcdac9Sjeremylt 
988d1bcdac9Sjeremylt   @ref Advanced
989d1bcdac9Sjeremylt **/
990d1bcdac9Sjeremylt 
991d1bcdac9Sjeremylt int CeedOperatorFieldGetElemRestriction(CeedOperatorField opfield,
992d1bcdac9Sjeremylt                                         CeedElemRestriction *rstr) {
993fe2413ffSjeremylt   *rstr = opfield->Erestrict;
994d1bcdac9Sjeremylt   return 0;
995d1bcdac9Sjeremylt }
996d1bcdac9Sjeremylt 
997d1bcdac9Sjeremylt /**
998d1bcdac9Sjeremylt   @brief Get the CeedBasis of a CeedOperatorField
999d1bcdac9Sjeremylt 
1000d1bcdac9Sjeremylt   @param opfield         CeedOperatorField
1001d1bcdac9Sjeremylt   @param[out] basis      Variable to store CeedBasis
1002d1bcdac9Sjeremylt 
1003d1bcdac9Sjeremylt   @return An error code: 0 - success, otherwise - failure
1004d1bcdac9Sjeremylt 
1005d1bcdac9Sjeremylt   @ref Advanced
1006d1bcdac9Sjeremylt **/
1007d1bcdac9Sjeremylt 
1008692c2638Sjeremylt int CeedOperatorFieldGetBasis(CeedOperatorField opfield, CeedBasis *basis) {
1009fe2413ffSjeremylt   *basis = opfield->basis;
1010d1bcdac9Sjeremylt   return 0;
1011d1bcdac9Sjeremylt }
1012d1bcdac9Sjeremylt 
1013d1bcdac9Sjeremylt /**
1014d1bcdac9Sjeremylt   @brief Get the CeedVector of a CeedOperatorField
1015d1bcdac9Sjeremylt 
1016d1bcdac9Sjeremylt   @param opfield         CeedOperatorField
1017d1bcdac9Sjeremylt   @param[out] vec        Variable to store CeedVector
1018d1bcdac9Sjeremylt 
1019d1bcdac9Sjeremylt   @return An error code: 0 - success, otherwise - failure
1020d1bcdac9Sjeremylt 
1021d1bcdac9Sjeremylt   @ref Advanced
1022d1bcdac9Sjeremylt **/
1023d1bcdac9Sjeremylt 
1024692c2638Sjeremylt int CeedOperatorFieldGetVector(CeedOperatorField opfield, CeedVector *vec) {
1025fe2413ffSjeremylt   *vec = opfield->vec;
1026d1bcdac9Sjeremylt   return 0;
1027d1bcdac9Sjeremylt }
1028d1bcdac9Sjeremylt 
1029d1bcdac9Sjeremylt /**
1030b11c1e72Sjeremylt   @brief Destroy a CeedOperator
1031d7b241e6Sjeremylt 
1032d7b241e6Sjeremylt   @param op CeedOperator to destroy
1033b11c1e72Sjeremylt 
1034b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
1035dfdf5a53Sjeremylt 
1036dfdf5a53Sjeremylt   @ref Basic
1037b11c1e72Sjeremylt **/
1038d7b241e6Sjeremylt int CeedOperatorDestroy(CeedOperator *op) {
1039d7b241e6Sjeremylt   int ierr;
1040d7b241e6Sjeremylt 
1041d7b241e6Sjeremylt   if (!*op || --(*op)->refcount > 0) return 0;
1042d7b241e6Sjeremylt   if ((*op)->Destroy) {
1043d7b241e6Sjeremylt     ierr = (*op)->Destroy(*op); CeedChk(ierr);
1044d7b241e6Sjeremylt   }
1045fe2413ffSjeremylt   ierr = CeedDestroy(&(*op)->ceed); CeedChk(ierr);
1046fe2413ffSjeremylt   // Free fields
10471d102b48SJeremy L Thompson   for (int i=0; i<(*op)->nfields; i++)
104852d6035fSJeremy L Thompson     if ((*op)->inputfields[i]) {
104971352a93Sjeremylt       ierr = CeedElemRestrictionDestroy(&(*op)->inputfields[i]->Erestrict);
105071352a93Sjeremylt       CeedChk(ierr);
105171352a93Sjeremylt       if ((*op)->inputfields[i]->basis != CEED_BASIS_COLLOCATED) {
105271352a93Sjeremylt         ierr = CeedBasisDestroy(&(*op)->inputfields[i]->basis); CeedChk(ierr);
105371352a93Sjeremylt       }
105471352a93Sjeremylt       if ((*op)->inputfields[i]->vec != CEED_VECTOR_ACTIVE &&
105571352a93Sjeremylt           (*op)->inputfields[i]->vec != CEED_VECTOR_NONE ) {
105671352a93Sjeremylt         ierr = CeedVectorDestroy(&(*op)->inputfields[i]->vec); CeedChk(ierr);
105771352a93Sjeremylt       }
1058fe2413ffSjeremylt       ierr = CeedFree(&(*op)->inputfields[i]); CeedChk(ierr);
1059fe2413ffSjeremylt     }
10601d102b48SJeremy L Thompson   for (int i=0; i<(*op)->nfields; i++)
1061d0eb30a5Sjeremylt     if ((*op)->outputfields[i]) {
106271352a93Sjeremylt       ierr = CeedElemRestrictionDestroy(&(*op)->outputfields[i]->Erestrict);
106371352a93Sjeremylt       CeedChk(ierr);
106471352a93Sjeremylt       if ((*op)->outputfields[i]->basis != CEED_BASIS_COLLOCATED) {
106571352a93Sjeremylt         ierr = CeedBasisDestroy(&(*op)->outputfields[i]->basis); CeedChk(ierr);
106671352a93Sjeremylt       }
106771352a93Sjeremylt       if ((*op)->outputfields[i]->vec != CEED_VECTOR_ACTIVE &&
106871352a93Sjeremylt           (*op)->outputfields[i]->vec != CEED_VECTOR_NONE ) {
106971352a93Sjeremylt         ierr = CeedVectorDestroy(&(*op)->outputfields[i]->vec); CeedChk(ierr);
107071352a93Sjeremylt       }
1071fe2413ffSjeremylt       ierr = CeedFree(&(*op)->outputfields[i]); CeedChk(ierr);
1072fe2413ffSjeremylt     }
107352d6035fSJeremy L Thompson   // Destroy suboperators
10741d102b48SJeremy L Thompson   for (int i=0; i<(*op)->numsub; i++)
107552d6035fSJeremy L Thompson     if ((*op)->suboperators[i]) {
107652d6035fSJeremy L Thompson       ierr = CeedOperatorDestroy(&(*op)->suboperators[i]); CeedChk(ierr);
107752d6035fSJeremy L Thompson     }
1078d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->qf); CeedChk(ierr);
1079d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->dqf); CeedChk(ierr);
1080d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->dqfT); CeedChk(ierr);
1081fe2413ffSjeremylt 
10825107b09fSJeremy L Thompson   // Destroy fallback
10835107b09fSJeremy L Thompson   if ((*op)->opfallback) {
10845107b09fSJeremy L Thompson     ierr = (*op)->qffallback->Destroy((*op)->qffallback); CeedChk(ierr);
10855107b09fSJeremy L Thompson     ierr = CeedFree(&(*op)->qffallback); CeedChk(ierr);
10865107b09fSJeremy L Thompson     ierr = (*op)->opfallback->Destroy((*op)->opfallback); CeedChk(ierr);
10875107b09fSJeremy L Thompson     ierr = CeedFree(&(*op)->opfallback); CeedChk(ierr);
10885107b09fSJeremy L Thompson   }
10895107b09fSJeremy L Thompson 
1090fe2413ffSjeremylt   ierr = CeedFree(&(*op)->inputfields); CeedChk(ierr);
1091fe2413ffSjeremylt   ierr = CeedFree(&(*op)->outputfields); CeedChk(ierr);
109252d6035fSJeremy L Thompson   ierr = CeedFree(&(*op)->suboperators); CeedChk(ierr);
1093d7b241e6Sjeremylt   ierr = CeedFree(op); CeedChk(ierr);
1094d7b241e6Sjeremylt   return 0;
1095d7b241e6Sjeremylt }
1096d7b241e6Sjeremylt 
1097d7b241e6Sjeremylt /// @}
1098