xref: /libCEED/interface/ceed-operator.c (revision 2da88da50ad5f664e15c7b66fa20f214e60b302b)
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
34d7b241e6Sjeremylt   @param dqf     QFunction defining the action of the Jacobian of @a qf (or NULL)
35d7b241e6Sjeremylt   @param dqfT    QFunction defining the action of the transpose of the Jacobian
36d7b241e6Sjeremylt                    of @a qf (or NULL)
37b11c1e72Sjeremylt   @param[out] op Address of the variable where the newly created
38b11c1e72Sjeremylt                      CeedOperator will be stored
39b11c1e72Sjeremylt 
40b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
41dfdf5a53Sjeremylt 
42dfdf5a53Sjeremylt   @ref Basic
43d7b241e6Sjeremylt  */
44d7b241e6Sjeremylt int CeedOperatorCreate(Ceed ceed, CeedQFunction qf, CeedQFunction dqf,
45d7b241e6Sjeremylt                        CeedQFunction dqfT, CeedOperator *op) {
46d7b241e6Sjeremylt   int ierr;
47d7b241e6Sjeremylt 
485fe0d4faSjeremylt   if (!ceed->OperatorCreate) {
495fe0d4faSjeremylt     Ceed delegate;
50aefd8378Sjeremylt     ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr);
515fe0d4faSjeremylt 
525fe0d4faSjeremylt     if (!delegate)
53c042f62fSJeremy L Thompson       // LCOV_EXCL_START
545fe0d4faSjeremylt       return CeedError(ceed, 1, "Backend does not support OperatorCreate");
55c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
565fe0d4faSjeremylt 
575fe0d4faSjeremylt     ierr = CeedOperatorCreate(delegate, qf, dqf, dqfT, op); CeedChk(ierr);
585fe0d4faSjeremylt     return 0;
595fe0d4faSjeremylt   }
605fe0d4faSjeremylt 
61d7b241e6Sjeremylt   ierr = CeedCalloc(1,op); CeedChk(ierr);
62d7b241e6Sjeremylt   (*op)->ceed = ceed;
63d7b241e6Sjeremylt   ceed->refcount++;
64d7b241e6Sjeremylt   (*op)->refcount = 1;
65442e7f0bSjeremylt   if (qf == CEED_QFUNCTION_NONE)
66442e7f0bSjeremylt     // LCOV_EXCL_START
67442e7f0bSjeremylt     return CeedError(ceed, 1, "Operator must have a valid QFunction.");
68442e7f0bSjeremylt   // LCOV_EXCL_STOP
69d7b241e6Sjeremylt   (*op)->qf = qf;
70d7b241e6Sjeremylt   qf->refcount++;
71442e7f0bSjeremylt   if (dqf && dqf != CEED_QFUNCTION_NONE) {
72d7b241e6Sjeremylt     (*op)->dqf = dqf;
73442e7f0bSjeremylt     dqf->refcount++;
74442e7f0bSjeremylt   }
75442e7f0bSjeremylt   if (dqfT && dqfT != CEED_QFUNCTION_NONE) {
76d7b241e6Sjeremylt     (*op)->dqfT = dqfT;
77442e7f0bSjeremylt     dqfT->refcount++;
78442e7f0bSjeremylt   }
79fe2413ffSjeremylt   ierr = CeedCalloc(16, &(*op)->inputfields); CeedChk(ierr);
80fe2413ffSjeremylt   ierr = CeedCalloc(16, &(*op)->outputfields); CeedChk(ierr);
81d7b241e6Sjeremylt   ierr = ceed->OperatorCreate(*op); CeedChk(ierr);
82d7b241e6Sjeremylt   return 0;
83d7b241e6Sjeremylt }
84d7b241e6Sjeremylt 
85d7b241e6Sjeremylt /**
8652d6035fSJeremy L Thompson   @brief Create an operator that composes the action of several operators
8752d6035fSJeremy L Thompson 
8852d6035fSJeremy L Thompson   @param ceed    A Ceed object where the CeedOperator will be created
8952d6035fSJeremy L Thompson   @param[out] op Address of the variable where the newly created
9052d6035fSJeremy L Thompson                      Composite CeedOperator will be stored
9152d6035fSJeremy L Thompson 
9252d6035fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
9352d6035fSJeremy L Thompson 
9452d6035fSJeremy L Thompson   @ref Basic
9552d6035fSJeremy L Thompson  */
9652d6035fSJeremy L Thompson int CeedCompositeOperatorCreate(Ceed ceed, CeedOperator *op) {
9752d6035fSJeremy L Thompson   int ierr;
9852d6035fSJeremy L Thompson 
9952d6035fSJeremy L Thompson   if (!ceed->CompositeOperatorCreate) {
10052d6035fSJeremy L Thompson     Ceed delegate;
101aefd8378Sjeremylt     ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr);
10252d6035fSJeremy L Thompson 
10352d6035fSJeremy L Thompson     if (!delegate)
104c042f62fSJeremy L Thompson       // LCOV_EXCL_START
1051d102b48SJeremy L Thompson       return CeedError(ceed, 1, "Backend does not support "
1061d102b48SJeremy L Thompson                        "CompositeOperatorCreate");
107c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
10852d6035fSJeremy L Thompson 
10952d6035fSJeremy L Thompson     ierr = CeedCompositeOperatorCreate(delegate, op); CeedChk(ierr);
11052d6035fSJeremy L Thompson     return 0;
11152d6035fSJeremy L Thompson   }
11252d6035fSJeremy L Thompson 
11352d6035fSJeremy L Thompson   ierr = CeedCalloc(1,op); CeedChk(ierr);
11452d6035fSJeremy L Thompson   (*op)->ceed = ceed;
11552d6035fSJeremy L Thompson   ceed->refcount++;
11652d6035fSJeremy L Thompson   (*op)->composite = true;
11752d6035fSJeremy L Thompson   ierr = CeedCalloc(16, &(*op)->suboperators); CeedChk(ierr);
11852d6035fSJeremy L Thompson   ierr = ceed->CompositeOperatorCreate(*op); CeedChk(ierr);
11952d6035fSJeremy L Thompson   return 0;
12052d6035fSJeremy L Thompson }
12152d6035fSJeremy L Thompson 
12252d6035fSJeremy L Thompson /**
123b11c1e72Sjeremylt   @brief Provide a field to a CeedOperator for use by its CeedQFunction
124d7b241e6Sjeremylt 
125d7b241e6Sjeremylt   This function is used to specify both active and passive fields to a
126d7b241e6Sjeremylt   CeedOperator.  For passive fields, a vector @arg v must be provided.  Passive
127d7b241e6Sjeremylt   fields can inputs or outputs (updated in-place when operator is applied).
128d7b241e6Sjeremylt 
129d7b241e6Sjeremylt   Active fields must be specified using this function, but their data (in a
130d7b241e6Sjeremylt   CeedVector) is passed in CeedOperatorApply().  There can be at most one active
131d7b241e6Sjeremylt   input and at most one active output.
132d7b241e6Sjeremylt 
1338c91a0c9SJeremy L Thompson   @param op         CeedOperator on which to provide the field
1348795c945Sjeremylt   @param fieldname  Name of the field (to be matched with the name used by
1358795c945Sjeremylt                       CeedQFunction)
136b11c1e72Sjeremylt   @param r          CeedElemRestriction
137b0e29e78Sjeremylt   @param lmode      CeedTransposeMode which specifies the ordering of the
138b0e29e78Sjeremylt                       components of the l-vector used by this CeedOperatorField,
139b0e29e78Sjeremylt                       CEED_NOTRANSPOSE indicates the component is the
140b0e29e78Sjeremylt                       outermost index and CEED_TRANSPOSE indicates the component
141b0e29e78Sjeremylt                       is the innermost index in ordering of the l-vector
142783c99b3SValeria Barra   @param b          CeedBasis in which the field resides or CEED_BASIS_COLLOCATED
143b11c1e72Sjeremylt                       if collocated with quadrature points
144b11c1e72Sjeremylt   @param v          CeedVector to be used by CeedOperator or CEED_VECTOR_ACTIVE
145b11c1e72Sjeremylt                       if field is active or CEED_VECTOR_NONE if using
1468c91a0c9SJeremy L Thompson                       CEED_EVAL_WEIGHT in the QFunction
147b11c1e72Sjeremylt 
148b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
149dfdf5a53Sjeremylt 
150dfdf5a53Sjeremylt   @ref Basic
151b11c1e72Sjeremylt **/
152d7b241e6Sjeremylt int CeedOperatorSetField(CeedOperator op, const char *fieldname,
1534dccadb6Sjeremylt                          CeedElemRestriction r, CeedTransposeMode lmode,
1544dccadb6Sjeremylt                          CeedBasis b, CeedVector v) {
155d7b241e6Sjeremylt   int ierr;
15652d6035fSJeremy L Thompson   if (op->composite)
157c042f62fSJeremy L Thompson     // LCOV_EXCL_START
15852d6035fSJeremy L Thompson     return CeedError(op->ceed, 1, "Cannot add field to composite operator.");
159c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
1608b067b84SJed Brown   if (!r)
161c042f62fSJeremy L Thompson     // LCOV_EXCL_START
162c042f62fSJeremy L Thompson     return CeedError(op->ceed, 1,
163c042f62fSJeremy L Thompson                      "ElemRestriction r for field \"%s\" must be non-NULL.",
164c042f62fSJeremy L Thompson                      fieldname);
165c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
1668b067b84SJed Brown   if (!b)
167c042f62fSJeremy L Thompson     // LCOV_EXCL_START
168c042f62fSJeremy L Thompson     return CeedError(op->ceed, 1, "Basis b for field \"%s\" must be non-NULL.",
169c042f62fSJeremy L Thompson                      fieldname);
170c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
1718b067b84SJed Brown   if (!v)
172c042f62fSJeremy L Thompson     // LCOV_EXCL_START
173c042f62fSJeremy L Thompson     return CeedError(op->ceed, 1, "Vector v for field \"%s\" must be non-NULL.",
174c042f62fSJeremy L Thompson                      fieldname);
175c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
17652d6035fSJeremy L Thompson 
177d7b241e6Sjeremylt   CeedInt numelements;
178d7b241e6Sjeremylt   ierr = CeedElemRestrictionGetNumElements(r, &numelements); CeedChk(ierr);
1792cb0afc5Sjeremylt   if (op->hasrestriction && op->numelements != numelements)
180c042f62fSJeremy L Thompson     // LCOV_EXCL_START
181d7b241e6Sjeremylt     return CeedError(op->ceed, 1,
1821d102b48SJeremy L Thompson                      "ElemRestriction with %d elements incompatible with prior "
1831d102b48SJeremy L Thompson                      "%d elements", numelements, op->numelements);
184c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
185d7b241e6Sjeremylt   op->numelements = numelements;
1862cb0afc5Sjeremylt   op->hasrestriction = true; // Restriction set, but numelements may be 0
187d7b241e6Sjeremylt 
188783c99b3SValeria Barra   if (b != CEED_BASIS_COLLOCATED) {
189d7b241e6Sjeremylt     CeedInt numqpoints;
190d7b241e6Sjeremylt     ierr = CeedBasisGetNumQuadraturePoints(b, &numqpoints); CeedChk(ierr);
191d7b241e6Sjeremylt     if (op->numqpoints && op->numqpoints != numqpoints)
192c042f62fSJeremy L Thompson       // LCOV_EXCL_START
1931d102b48SJeremy L Thompson       return CeedError(op->ceed, 1, "Basis with %d quadrature points "
1941d102b48SJeremy L Thompson                        "incompatible with prior %d points", numqpoints,
1951d102b48SJeremy L Thompson                        op->numqpoints);
196c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
197d7b241e6Sjeremylt     op->numqpoints = numqpoints;
198d7b241e6Sjeremylt   }
199d1bcdac9Sjeremylt   CeedOperatorField *ofield;
200d7b241e6Sjeremylt   for (CeedInt i=0; i<op->qf->numinputfields; i++) {
201fe2413ffSjeremylt     if (!strcmp(fieldname, (*op->qf->inputfields[i]).fieldname)) {
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)) {
208d7b241e6Sjeremylt       ofield = &op->outputfields[i];
209d7b241e6Sjeremylt       goto found;
210d7b241e6Sjeremylt     }
211d7b241e6Sjeremylt   }
212c042f62fSJeremy L Thompson   // LCOV_EXCL_START
213d7b241e6Sjeremylt   return CeedError(op->ceed, 1, "QFunction has no knowledge of field '%s'",
214d7b241e6Sjeremylt                    fieldname);
215c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
216d7b241e6Sjeremylt found:
217fe2413ffSjeremylt   ierr = CeedCalloc(1, ofield); CeedChk(ierr);
218fe2413ffSjeremylt   (*ofield)->Erestrict = r;
21971352a93Sjeremylt   r->refcount += 1;
220fe2413ffSjeremylt   (*ofield)->lmode = lmode;
221fe2413ffSjeremylt   (*ofield)->basis = b;
22271352a93Sjeremylt   if (b != CEED_BASIS_COLLOCATED)
22371352a93Sjeremylt     b->refcount += 1;
224fe2413ffSjeremylt   (*ofield)->vec = v;
22571352a93Sjeremylt   if (v != CEED_VECTOR_ACTIVE && v != CEED_VECTOR_NONE)
22671352a93Sjeremylt     v->refcount += 1;
227d7b241e6Sjeremylt   op->nfields += 1;
228d7b241e6Sjeremylt   return 0;
229d7b241e6Sjeremylt }
230d7b241e6Sjeremylt 
231d7b241e6Sjeremylt /**
23252d6035fSJeremy L Thompson   @brief Add a sub-operator to a composite CeedOperator
233288c0443SJeremy L Thompson 
234288c0443SJeremy L Thompson   @param[out] compositeop Address of the composite CeedOperator
235288c0443SJeremy L Thompson   @param      subop       Address of the sub-operator CeedOperator
23652d6035fSJeremy L Thompson 
23752d6035fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
23852d6035fSJeremy L Thompson 
23952d6035fSJeremy L Thompson   @ref Basic
24052d6035fSJeremy L Thompson  */
241692c2638Sjeremylt int CeedCompositeOperatorAddSub(CeedOperator compositeop, CeedOperator subop) {
24252d6035fSJeremy L Thompson   if (!compositeop->composite)
243c042f62fSJeremy L Thompson     // LCOV_EXCL_START
2441d102b48SJeremy L Thompson     return CeedError(compositeop->ceed, 1, "CeedOperator is not a composite "
2451d102b48SJeremy L Thompson                      "operator");
246c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
24752d6035fSJeremy L Thompson 
24852d6035fSJeremy L Thompson   if (compositeop->numsub == CEED_COMPOSITE_MAX)
249c042f62fSJeremy L Thompson     // LCOV_EXCL_START
2501d102b48SJeremy L Thompson     return CeedError(compositeop->ceed, 1, "Cannot add additional suboperators");
251c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
25252d6035fSJeremy L Thompson 
25352d6035fSJeremy L Thompson   compositeop->suboperators[compositeop->numsub] = subop;
25452d6035fSJeremy L Thompson   subop->refcount++;
25552d6035fSJeremy L Thompson   compositeop->numsub++;
25652d6035fSJeremy L Thompson   return 0;
25752d6035fSJeremy L Thompson }
25852d6035fSJeremy L Thompson 
25952d6035fSJeremy L Thompson /**
2601d102b48SJeremy L Thompson   @brief Assemble a linear CeedQFunction associated with a CeedOperator
2611d102b48SJeremy L Thompson 
2621d102b48SJeremy L Thompson   This returns a CeedVector containing a matrix at each quadrature point
2631d102b48SJeremy L Thompson     providing the action of the CeedQFunction associated with the CeedOperator.
2641d102b48SJeremy L Thompson     The vector 'assembled' is of shape
2651d102b48SJeremy L Thompson       [num_elements, num_input_fields, num_output_fields, num_quad_points]
2661d102b48SJeremy L Thompson     and contains column-major matrices representing the action of the
2671d102b48SJeremy L Thompson     CeedQFunction for a corresponding quadrature point on an element. Inputs and
2681d102b48SJeremy L Thompson     outputs are in the order provided by the user when adding CeedOperator fields.
2691d102b48SJeremy L Thompson     For example, a QFunction with inputs 'u' and 'gradu' and outputs 'gradv' and
2701d102b48SJeremy L Thompson     'v', provided in that order, would result in an assembled QFunction that
2711d102b48SJeremy L Thompson     consists of (1 + dim) x (dim + 1) matrices at each quadrature point acting
2721d102b48SJeremy L Thompson     on the input [u, du_0, du_1] and producing the output [dv_0, dv_1, v].
2731d102b48SJeremy L Thompson 
2741d102b48SJeremy L Thompson   @param op             CeedOperator to assemble CeedQFunction
2751d102b48SJeremy L Thompson   @param[out] assembled CeedVector to store assembled CeedQFunction at
2761d102b48SJeremy L Thompson                           quadrature points
2771d102b48SJeremy L Thompson   @param[out] rstr      CeedElemRestriction for CeedVector containing assembled
2781d102b48SJeremy L Thompson                           CeedQFunction
2791d102b48SJeremy L Thompson   @param request        Address of CeedRequest for non-blocking completion, else
2801d102b48SJeremy L Thompson                           CEED_REQUEST_IMMEDIATE
2811d102b48SJeremy L Thompson 
2821d102b48SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
2831d102b48SJeremy L Thompson 
284b7ec98d8SJeremy L Thompson   @ref Basic
2851d102b48SJeremy L Thompson **/
2861d102b48SJeremy L Thompson int CeedOperatorAssembleLinearQFunction(CeedOperator op, CeedVector *assembled,
2877f823360Sjeremylt                                         CeedElemRestriction *rstr,
2887f823360Sjeremylt                                         CeedRequest *request) {
2891d102b48SJeremy L Thompson   int ierr;
2901d102b48SJeremy L Thompson   Ceed ceed = op->ceed;
2911d102b48SJeremy L Thompson   CeedQFunction qf = op->qf;
2921d102b48SJeremy L Thompson 
2931d102b48SJeremy L Thompson   if (op->composite) {
294138d4072Sjeremylt     // LCOV_EXCL_START
2951d102b48SJeremy L Thompson     return CeedError(ceed, 1, "Cannot assemble QFunction for composite operator");
296138d4072Sjeremylt     // LCOV_EXCL_STOP
2971d102b48SJeremy L Thompson   } else {
2981d102b48SJeremy L Thompson     if (op->nfields == 0)
299138d4072Sjeremylt       // LCOV_EXCL_START
3001d102b48SJeremy L Thompson       return CeedError(ceed, 1, "No operator fields set");
301138d4072Sjeremylt     // LCOV_EXCL_STOP
3021d102b48SJeremy L Thompson     if (op->nfields < qf->numinputfields + qf->numoutputfields)
303138d4072Sjeremylt       // LCOV_EXCL_START
3041d102b48SJeremy L Thompson       return CeedError( ceed, 1, "Not all operator fields set");
305138d4072Sjeremylt     // LCOV_EXCL_STOP
3062cb0afc5Sjeremylt     if (!op->hasrestriction)
307138d4072Sjeremylt       // LCOV_EXCL_START
3081d102b48SJeremy L Thompson       return CeedError(ceed, 1, "At least one restriction required");
309138d4072Sjeremylt     // LCOV_EXCL_STOP
3101d102b48SJeremy L Thompson     if (op->numqpoints == 0)
311138d4072Sjeremylt       // LCOV_EXCL_START
3121d102b48SJeremy L Thompson       return CeedError(ceed, 1, "At least one non-collocated basis required");
313138d4072Sjeremylt     // LCOV_EXCL_STOP
3141d102b48SJeremy L Thompson   }
3151d102b48SJeremy L Thompson   ierr = op->AssembleLinearQFunction(op, assembled, rstr, request);
3161d102b48SJeremy L Thompson   CeedChk(ierr);
3171d102b48SJeremy L Thompson   return 0;
3181d102b48SJeremy L Thompson }
3191d102b48SJeremy L Thompson 
3201d102b48SJeremy L Thompson /**
321b7ec98d8SJeremy L Thompson   @brief Assemble the diagonal of a square linear Operator
322b7ec98d8SJeremy L Thompson 
323b7ec98d8SJeremy L Thompson   This returns a CeedVector containing the diagonal of a linear CeedOperator.
324b7ec98d8SJeremy L Thompson 
325b7ec98d8SJeremy L Thompson   @param op             CeedOperator to assemble CeedQFunction
326b7ec98d8SJeremy L Thompson   @param[out] assembled CeedVector to store assembled CeedOperator diagonal
327b7ec98d8SJeremy L Thompson   @param request        Address of CeedRequest for non-blocking completion, else
328b7ec98d8SJeremy L Thompson                           CEED_REQUEST_IMMEDIATE
329b7ec98d8SJeremy L Thompson 
330b7ec98d8SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
331b7ec98d8SJeremy L Thompson 
332b7ec98d8SJeremy L Thompson   @ref Basic
333b7ec98d8SJeremy L Thompson **/
3347f823360Sjeremylt int CeedOperatorAssembleLinearDiagonal(CeedOperator op, CeedVector *assembled,
3357f823360Sjeremylt                                        CeedRequest *request) {
336b7ec98d8SJeremy L Thompson   int ierr;
337b7ec98d8SJeremy L Thompson   Ceed ceed = op->ceed;
338b7ec98d8SJeremy L Thompson   CeedQFunction qf = op->qf;
339b7ec98d8SJeremy L Thompson 
340b7ec98d8SJeremy L Thompson   if (op->composite) {
341b7ec98d8SJeremy L Thompson     // LCOV_EXCL_START
342b7ec98d8SJeremy L Thompson     return CeedError(ceed, 1, "Cannot assemble QFunction for composite operator");
343b7ec98d8SJeremy L Thompson     // LCOV_EXCL_STOP
344b7ec98d8SJeremy L Thompson   } else {
345b7ec98d8SJeremy L Thompson     if (op->nfields == 0)
346b7ec98d8SJeremy L Thompson       // LCOV_EXCL_START
347b7ec98d8SJeremy L Thompson       return CeedError(ceed, 1, "No operator fields set");
348b7ec98d8SJeremy L Thompson     // LCOV_EXCL_STOP
349b7ec98d8SJeremy L Thompson     if (op->nfields < qf->numinputfields + qf->numoutputfields)
350b7ec98d8SJeremy L Thompson       // LCOV_EXCL_START
351b7ec98d8SJeremy L Thompson       return CeedError( ceed, 1, "Not all operator fields set");
352b7ec98d8SJeremy L Thompson     // LCOV_EXCL_STOP
3532cb0afc5Sjeremylt     if (!op->hasrestriction)
354b7ec98d8SJeremy L Thompson       // LCOV_EXCL_START
355b7ec98d8SJeremy L Thompson       return CeedError(ceed, 1, "At least one restriction required");
356b7ec98d8SJeremy L Thompson     // LCOV_EXCL_STOP
357b7ec98d8SJeremy L Thompson     if (op->numqpoints == 0)
358b7ec98d8SJeremy L Thompson       // LCOV_EXCL_START
359b7ec98d8SJeremy L Thompson       return CeedError(ceed, 1, "At least one non-collocated basis required");
360b7ec98d8SJeremy L Thompson     // LCOV_EXCL_STOP
361b7ec98d8SJeremy L Thompson   }
362b7ec98d8SJeremy L Thompson 
363b7ec98d8SJeremy L Thompson   // Use backend version, if available
364b7ec98d8SJeremy L Thompson   if (op->AssembleLinearDiagonal) {
365b7ec98d8SJeremy L Thompson     ierr = op->AssembleLinearDiagonal(op, assembled, request); CeedChk(ierr);
366b7ec98d8SJeremy L Thompson     return 0;
367b7ec98d8SJeremy L Thompson   }
368b7ec98d8SJeremy L Thompson 
369b7ec98d8SJeremy L Thompson   // Assemble QFunction
370b7ec98d8SJeremy L Thompson   CeedVector assembledqf;
371b7ec98d8SJeremy L Thompson   CeedElemRestriction rstr;
372b7ec98d8SJeremy L Thompson   ierr = CeedOperatorAssembleLinearQFunction(op,  &assembledqf, &rstr, request);
373b7ec98d8SJeremy L Thompson   CeedChk(ierr);
374b7ec98d8SJeremy L Thompson   ierr = CeedElemRestrictionDestroy(&rstr); CeedChk(ierr);
375b7ec98d8SJeremy L Thompson 
376b7ec98d8SJeremy L Thompson   // Determine active input basis
377112e3f70Sjeremylt   CeedInt numemodein = 0, ncomp, dim = 1;
378b7ec98d8SJeremy L Thompson   CeedEvalMode *emodein = NULL;
379112e3f70Sjeremylt   CeedBasis basisin = NULL;
380112e3f70Sjeremylt   CeedElemRestriction rstrin = NULL;
381b7ec98d8SJeremy L Thompson   for (CeedInt i=0; i<qf->numinputfields; i++)
382b7ec98d8SJeremy L Thompson     if (op->inputfields[i]->vec == CEED_VECTOR_ACTIVE) {
383b7ec98d8SJeremy L Thompson       ierr = CeedOperatorFieldGetBasis(op->inputfields[i], &basisin);
384b7ec98d8SJeremy L Thompson       CeedChk(ierr);
385b7ec98d8SJeremy L Thompson       ierr = CeedBasisGetNumComponents(basisin, &ncomp); CeedChk(ierr);
386b7ec98d8SJeremy L Thompson       ierr = CeedBasisGetDimension(basisin, &dim); CeedChk(ierr);
387b7ec98d8SJeremy L Thompson       ierr = CeedOperatorFieldGetElemRestriction(op->inputfields[i], &rstrin);
388b7ec98d8SJeremy L Thompson       CeedChk(ierr);
389b7ec98d8SJeremy L Thompson       CeedEvalMode emode;
390b7ec98d8SJeremy L Thompson       ierr = CeedQFunctionFieldGetEvalMode(qf->inputfields[i], &emode);
391b7ec98d8SJeremy L Thompson       CeedChk(ierr);
392b7ec98d8SJeremy L Thompson       switch (emode) {
393b7ec98d8SJeremy L Thompson       case CEED_EVAL_NONE:
394b7ec98d8SJeremy L Thompson       case CEED_EVAL_INTERP:
395b7ec98d8SJeremy L Thompson         ierr = CeedRealloc(numemodein + 1, &emodein); CeedChk(ierr);
396b7ec98d8SJeremy L Thompson         emodein[numemodein] = emode;
397b7ec98d8SJeremy L Thompson         numemodein += 1;
398b7ec98d8SJeremy L Thompson         break;
399b7ec98d8SJeremy L Thompson       case CEED_EVAL_GRAD:
400b7ec98d8SJeremy L Thompson         ierr = CeedRealloc(numemodein + dim, &emodein); CeedChk(ierr);
401b7ec98d8SJeremy L Thompson         for (CeedInt d=0; d<dim; d++)
402b7ec98d8SJeremy L Thompson           emodein[numemodein+d] = emode;
403b7ec98d8SJeremy L Thompson         numemodein += dim;
404b7ec98d8SJeremy L Thompson         break;
405b7ec98d8SJeremy L Thompson       case CEED_EVAL_WEIGHT:
406b7ec98d8SJeremy L Thompson       case CEED_EVAL_DIV:
407b7ec98d8SJeremy L Thompson       case CEED_EVAL_CURL:
408b7ec98d8SJeremy L Thompson         break; // Caught by QF Assembly
409b7ec98d8SJeremy L Thompson       }
410b7ec98d8SJeremy L Thompson     }
411b7ec98d8SJeremy L Thompson 
412b7ec98d8SJeremy L Thompson   // Determine active output basis
413b7ec98d8SJeremy L Thompson   CeedInt numemodeout = 0;
414b7ec98d8SJeremy L Thompson   CeedEvalMode *emodeout = NULL;
415112e3f70Sjeremylt   CeedBasis basisout = NULL;
416112e3f70Sjeremylt   CeedElemRestriction rstrout = NULL;
417112e3f70Sjeremylt   CeedTransposeMode lmodeout = CEED_NOTRANSPOSE;
418b7ec98d8SJeremy L Thompson   for (CeedInt i=0; i<qf->numoutputfields; i++)
419b7ec98d8SJeremy L Thompson     if (op->outputfields[i]->vec == CEED_VECTOR_ACTIVE) {
420b7ec98d8SJeremy L Thompson       ierr = CeedOperatorFieldGetBasis(op->outputfields[i], &basisout);
421b7ec98d8SJeremy L Thompson       CeedChk(ierr);
422b7ec98d8SJeremy L Thompson       ierr = CeedOperatorFieldGetElemRestriction(op->outputfields[i], &rstrout);
423b7ec98d8SJeremy L Thompson       CeedChk(ierr);
424b7ec98d8SJeremy L Thompson       ierr = CeedOperatorFieldGetLMode(op->outputfields[i], &lmodeout);
425b7ec98d8SJeremy L Thompson       CeedChk(ierr);
426b7ec98d8SJeremy L Thompson       CeedEvalMode emode;
427b7ec98d8SJeremy L Thompson       ierr = CeedQFunctionFieldGetEvalMode(qf->outputfields[i], &emode);
428b7ec98d8SJeremy L Thompson       CeedChk(ierr);
429b7ec98d8SJeremy L Thompson       switch (emode) {
430b7ec98d8SJeremy L Thompson       case CEED_EVAL_NONE:
431b7ec98d8SJeremy L Thompson       case CEED_EVAL_INTERP:
432b7ec98d8SJeremy L Thompson         ierr = CeedRealloc(numemodeout + 1, &emodeout); CeedChk(ierr);
433b7ec98d8SJeremy L Thompson         emodeout[numemodeout] = emode;
434b7ec98d8SJeremy L Thompson         numemodeout += 1;
435b7ec98d8SJeremy L Thompson         break;
436b7ec98d8SJeremy L Thompson       case CEED_EVAL_GRAD:
437b7ec98d8SJeremy L Thompson         ierr = CeedRealloc(numemodeout + dim, &emodeout); CeedChk(ierr);
438b7ec98d8SJeremy L Thompson         for (CeedInt d=0; d<dim; d++)
439b7ec98d8SJeremy L Thompson           emodeout[numemodeout+d] = emode;
440b7ec98d8SJeremy L Thompson         numemodeout += dim;
441b7ec98d8SJeremy L Thompson         break;
442b7ec98d8SJeremy L Thompson       case CEED_EVAL_WEIGHT:
443b7ec98d8SJeremy L Thompson       case CEED_EVAL_DIV:
444b7ec98d8SJeremy L Thompson       case CEED_EVAL_CURL:
445b7ec98d8SJeremy L Thompson         break; // Caught by QF Assembly
446b7ec98d8SJeremy L Thompson       }
447b7ec98d8SJeremy L Thompson     }
448b7ec98d8SJeremy L Thompson 
449b7ec98d8SJeremy L Thompson   // Create diagonal vector
450b7ec98d8SJeremy L Thompson   CeedVector elemdiag;
451b7ec98d8SJeremy L Thompson   ierr = CeedElemRestrictionCreateVector(rstrin, assembled, &elemdiag);
452b7ec98d8SJeremy L Thompson   CeedChk(ierr);
453b7ec98d8SJeremy L Thompson 
454b7ec98d8SJeremy L Thompson   // Assemble element operator diagonals
455b7ec98d8SJeremy L Thompson   CeedScalar *elemdiagarray, *assembledqfarray;
456b7ec98d8SJeremy L Thompson   ierr = CeedVectorSetValue(elemdiag, 0.0); CeedChk(ierr);
457b7ec98d8SJeremy L Thompson   ierr = CeedVectorGetArray(elemdiag, CEED_MEM_HOST, &elemdiagarray);
458b7ec98d8SJeremy L Thompson   CeedChk(ierr);
459b7ec98d8SJeremy L Thompson   ierr = CeedVectorGetArray(assembledqf, CEED_MEM_HOST, &assembledqfarray);
460b7ec98d8SJeremy L Thompson   CeedChk(ierr);
461b7ec98d8SJeremy L Thompson   CeedInt nelem, nnodes, nqpts;
462b7ec98d8SJeremy L Thompson   ierr = CeedElemRestrictionGetNumElements(rstrin, &nelem); CeedChk(ierr);
463b7ec98d8SJeremy L Thompson   ierr = CeedBasisGetNumNodes(basisin, &nnodes); CeedChk(ierr);
464b7ec98d8SJeremy L Thompson   ierr = CeedBasisGetNumQuadraturePoints(basisin, &nqpts); CeedChk(ierr);
465b7ec98d8SJeremy L Thompson   // Compute the diagonal of B^T D B
466b7ec98d8SJeremy L Thompson   // Each node, qpt pair
467b7ec98d8SJeremy L Thompson   for (CeedInt n=0; n<nnodes; n++)
468b7ec98d8SJeremy L Thompson     for (CeedInt q=0; q<nqpts; q++) {
469b7ec98d8SJeremy L Thompson       CeedInt dout = -1;
470b7ec98d8SJeremy L Thompson       // Each basis eval mode pair
471b7ec98d8SJeremy L Thompson       for (CeedInt eout=0; eout<numemodeout; eout++) {
472b7ec98d8SJeremy L Thompson         CeedScalar bt = 1.0;
473b7ec98d8SJeremy L Thompson         if (emodeout[eout] == CEED_EVAL_GRAD)
474b7ec98d8SJeremy L Thompson           dout += 1;
475b7ec98d8SJeremy L Thompson         ierr = CeedBasisGetValue(basisout, emodeout[eout], q, n, dout, &bt);
476b7ec98d8SJeremy L Thompson         CeedChk(ierr);
477b7ec98d8SJeremy L Thompson         CeedInt din = -1;
478b7ec98d8SJeremy L Thompson         for (CeedInt ein=0; ein<numemodein; ein++) {
479b7ec98d8SJeremy L Thompson           CeedScalar b = 0.0;
480b7ec98d8SJeremy L Thompson           if (emodein[ein] == CEED_EVAL_GRAD)
481b7ec98d8SJeremy L Thompson             din += 1;
482b7ec98d8SJeremy L Thompson           ierr = CeedBasisGetValue(basisin, emodein[ein], q, n, din, &b);
483b7ec98d8SJeremy L Thompson           CeedChk(ierr);
484b7ec98d8SJeremy L Thompson           // Each element and component
485b7ec98d8SJeremy L Thompson           for (CeedInt e=0; e<nelem; e++)
486b7ec98d8SJeremy L Thompson             for (CeedInt cout=0; cout<ncomp; cout++) {
487b7ec98d8SJeremy L Thompson               CeedScalar db = 0.0;
488b7ec98d8SJeremy L Thompson               for (CeedInt cin=0; cin<ncomp; cin++)
489b7ec98d8SJeremy L Thompson                 db += assembledqfarray[((((e*numemodein+ein)*ncomp+cin)*
490b7ec98d8SJeremy L Thompson                                          numemodeout+eout)*ncomp+cout)*nqpts+q]*b;
491b7ec98d8SJeremy L Thompson               elemdiagarray[(e*ncomp+cout)*nnodes+n] += bt * db;
492b7ec98d8SJeremy L Thompson             }
493b7ec98d8SJeremy L Thompson         }
494b7ec98d8SJeremy L Thompson       }
495b7ec98d8SJeremy L Thompson     }
496b7ec98d8SJeremy L Thompson 
497b7ec98d8SJeremy L Thompson   ierr = CeedVectorRestoreArray(elemdiag, &elemdiagarray); CeedChk(ierr);
498b7ec98d8SJeremy L Thompson   ierr = CeedVectorRestoreArray(assembledqf, &assembledqfarray); CeedChk(ierr);
499b7ec98d8SJeremy L Thompson 
500b7ec98d8SJeremy L Thompson   // Assemble local operator diagonal
501b7ec98d8SJeremy L Thompson   ierr = CeedVectorSetValue(*assembled, 0.0); CeedChk(ierr);
502b7ec98d8SJeremy L Thompson   ierr = CeedElemRestrictionApply(rstrout, CEED_TRANSPOSE, lmodeout, elemdiag,
503b7ec98d8SJeremy L Thompson                                   *assembled, request); CeedChk(ierr);
504b7ec98d8SJeremy L Thompson 
505b7ec98d8SJeremy L Thompson   // Cleanup
506b7ec98d8SJeremy L Thompson   ierr = CeedVectorDestroy(&assembledqf); CeedChk(ierr);
507b7ec98d8SJeremy L Thompson   ierr = CeedVectorDestroy(&elemdiag); CeedChk(ierr);
508b7ec98d8SJeremy L Thompson   ierr = CeedFree(&emodein); CeedChk(ierr);
509b7ec98d8SJeremy L Thompson   ierr = CeedFree(&emodeout); CeedChk(ierr);
510b7ec98d8SJeremy L Thompson 
511b7ec98d8SJeremy L Thompson   return 0;
512b7ec98d8SJeremy L Thompson }
513b7ec98d8SJeremy L Thompson 
514b7ec98d8SJeremy L Thompson /**
515b11c1e72Sjeremylt   @brief Apply CeedOperator to a vector
516d7b241e6Sjeremylt 
517d7b241e6Sjeremylt   This computes the action of the operator on the specified (active) input,
518d7b241e6Sjeremylt   yielding its (active) output.  All inputs and outputs must be specified using
519d7b241e6Sjeremylt   CeedOperatorSetField().
520d7b241e6Sjeremylt 
521d7b241e6Sjeremylt   @param op        CeedOperator to apply
522b11c1e72Sjeremylt   @param[in] in    CeedVector containing input state or NULL if there are no
523b11c1e72Sjeremylt                      active inputs
524b11c1e72Sjeremylt   @param[out] out  CeedVector to store result of applying operator (must be
525d7b241e6Sjeremylt                      distinct from @a in) or NULL if there are no active outputs
526d7b241e6Sjeremylt   @param request   Address of CeedRequest for non-blocking completion, else
527d7b241e6Sjeremylt                      CEED_REQUEST_IMMEDIATE
528b11c1e72Sjeremylt 
529b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
530dfdf5a53Sjeremylt 
531dfdf5a53Sjeremylt   @ref Basic
532b11c1e72Sjeremylt **/
533692c2638Sjeremylt int CeedOperatorApply(CeedOperator op, CeedVector in, CeedVector out,
534692c2638Sjeremylt                       CeedRequest *request) {
535d7b241e6Sjeremylt   int ierr;
536d7b241e6Sjeremylt   Ceed ceed = op->ceed;
537d7b241e6Sjeremylt   CeedQFunction qf = op->qf;
538d7b241e6Sjeremylt 
53952d6035fSJeremy L Thompson   if (op->composite) {
540c042f62fSJeremy L Thompson     if (!op->numsub)
541c042f62fSJeremy L Thompson       // LCOV_EXCL_START
542c042f62fSJeremy L Thompson       return CeedError(ceed, 1, "No suboperators set");
543c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
54452d6035fSJeremy L Thompson   } else {
545c042f62fSJeremy L Thompson     if (op->nfields == 0)
546c042f62fSJeremy L Thompson       // LCOV_EXCL_START
547c042f62fSJeremy L Thompson       return CeedError(ceed, 1, "No operator fields set");
548c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
549c042f62fSJeremy L Thompson     if (op->nfields < qf->numinputfields + qf->numoutputfields)
550c042f62fSJeremy L Thompson       // LCOV_EXCL_START
551c042f62fSJeremy L Thompson       return CeedError(ceed, 1, "Not all operator fields set");
552c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
5532cb0afc5Sjeremylt     if (!op->hasrestriction)
554c042f62fSJeremy L Thompson       // LCOV_EXCL_START
555c042f62fSJeremy L Thompson       return CeedError(ceed, 1,"At least one restriction required");
556c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
557c042f62fSJeremy L Thompson     if (op->numqpoints == 0)
558c042f62fSJeremy L Thompson       // LCOV_EXCL_START
559c042f62fSJeremy L Thompson       return CeedError(ceed, 1,"At least one non-collocated basis required");
560c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
56152d6035fSJeremy L Thompson   }
5621d7d2407SJeremy L Thompson   if (op->numelements || op->composite) {
563e97ff134Sjeremylt     ierr = op->Apply(op, in != CEED_VECTOR_NONE ? in : NULL,
564e97ff134Sjeremylt                      out != CEED_VECTOR_NONE ? out : NULL, request);
565e97ff134Sjeremylt     CeedChk(ierr);
5661d7d2407SJeremy L Thompson   }
567d7b241e6Sjeremylt   return 0;
568d7b241e6Sjeremylt }
569d7b241e6Sjeremylt 
570d7b241e6Sjeremylt /**
5714ce2993fSjeremylt   @brief Get the Ceed associated with a CeedOperator
5724ce2993fSjeremylt 
5734ce2993fSjeremylt   @param op              CeedOperator
5744ce2993fSjeremylt   @param[out] ceed       Variable to store Ceed
5754ce2993fSjeremylt 
5764ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
5774ce2993fSjeremylt 
57823617272Sjeremylt   @ref Advanced
5794ce2993fSjeremylt **/
5804ce2993fSjeremylt 
5814ce2993fSjeremylt int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) {
5824ce2993fSjeremylt   *ceed = op->ceed;
5834ce2993fSjeremylt   return 0;
5844ce2993fSjeremylt }
5854ce2993fSjeremylt 
5864ce2993fSjeremylt /**
5874ce2993fSjeremylt   @brief Get the number of elements associated with a CeedOperator
5884ce2993fSjeremylt 
5894ce2993fSjeremylt   @param op              CeedOperator
5904ce2993fSjeremylt   @param[out] numelem    Variable to store number of elements
5914ce2993fSjeremylt 
5924ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
5934ce2993fSjeremylt 
59423617272Sjeremylt   @ref Advanced
5954ce2993fSjeremylt **/
5964ce2993fSjeremylt 
5974ce2993fSjeremylt int CeedOperatorGetNumElements(CeedOperator op, CeedInt *numelem) {
59852d6035fSJeremy L Thompson   if (op->composite)
599c042f62fSJeremy L Thompson     // LCOV_EXCL_START
60052d6035fSJeremy L Thompson     return CeedError(op->ceed, 1, "Not defined for composite operator");
601c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
60252d6035fSJeremy L Thompson 
6034ce2993fSjeremylt   *numelem = op->numelements;
6044ce2993fSjeremylt   return 0;
6054ce2993fSjeremylt }
6064ce2993fSjeremylt 
6074ce2993fSjeremylt /**
6084ce2993fSjeremylt   @brief Get the number of quadrature points associated with a CeedOperator
6094ce2993fSjeremylt 
6104ce2993fSjeremylt   @param op              CeedOperator
6114ce2993fSjeremylt   @param[out] numqpts    Variable to store vector number of quadrature points
6124ce2993fSjeremylt 
6134ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
6144ce2993fSjeremylt 
61523617272Sjeremylt   @ref Advanced
6164ce2993fSjeremylt **/
6174ce2993fSjeremylt 
6184ce2993fSjeremylt int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *numqpts) {
61952d6035fSJeremy L Thompson   if (op->composite)
620c042f62fSJeremy L Thompson     // LCOV_EXCL_START
62152d6035fSJeremy L Thompson     return CeedError(op->ceed, 1, "Not defined for composite operator");
622c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
62352d6035fSJeremy L Thompson 
6244ce2993fSjeremylt   *numqpts = op->numqpoints;
6254ce2993fSjeremylt   return 0;
6264ce2993fSjeremylt }
6274ce2993fSjeremylt 
6284ce2993fSjeremylt /**
6294ce2993fSjeremylt   @brief Get the number of arguments associated with a CeedOperator
6304ce2993fSjeremylt 
6314ce2993fSjeremylt   @param op              CeedOperator
6324ce2993fSjeremylt   @param[out] numargs    Variable to store vector number of arguments
6334ce2993fSjeremylt 
6344ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
6354ce2993fSjeremylt 
63623617272Sjeremylt   @ref Advanced
6374ce2993fSjeremylt **/
6384ce2993fSjeremylt 
6394ce2993fSjeremylt int CeedOperatorGetNumArgs(CeedOperator op, CeedInt *numargs) {
64052d6035fSJeremy L Thompson   if (op->composite)
641c042f62fSJeremy L Thompson     // LCOV_EXCL_START
64252d6035fSJeremy L Thompson     return CeedError(op->ceed, 1, "Not defined for composite operators");
643c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
644c042f62fSJeremy L Thompson 
6454ce2993fSjeremylt   *numargs = op->nfields;
6464ce2993fSjeremylt   return 0;
6474ce2993fSjeremylt }
6484ce2993fSjeremylt 
6494ce2993fSjeremylt /**
6504ce2993fSjeremylt   @brief Get the setup status of a CeedOperator
6514ce2993fSjeremylt 
6524ce2993fSjeremylt   @param op             CeedOperator
653288c0443SJeremy L Thompson   @param[out] setupdone Variable to store setup status
6544ce2993fSjeremylt 
6554ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
6564ce2993fSjeremylt 
65723617272Sjeremylt   @ref Advanced
6584ce2993fSjeremylt **/
6594ce2993fSjeremylt 
6604ce2993fSjeremylt int CeedOperatorGetSetupStatus(CeedOperator op, bool *setupdone) {
6614ce2993fSjeremylt   *setupdone = op->setupdone;
6624ce2993fSjeremylt   return 0;
6634ce2993fSjeremylt }
6644ce2993fSjeremylt 
6654ce2993fSjeremylt /**
6664ce2993fSjeremylt   @brief Get the QFunction associated with a CeedOperator
6674ce2993fSjeremylt 
6684ce2993fSjeremylt   @param op              CeedOperator
6698c91a0c9SJeremy L Thompson   @param[out] qf         Variable to store QFunction
6704ce2993fSjeremylt 
6714ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
6724ce2993fSjeremylt 
67323617272Sjeremylt   @ref Advanced
6744ce2993fSjeremylt **/
6754ce2993fSjeremylt 
6764ce2993fSjeremylt int CeedOperatorGetQFunction(CeedOperator op, CeedQFunction *qf) {
67752d6035fSJeremy L Thompson   if (op->composite)
678c042f62fSJeremy L Thompson     // LCOV_EXCL_START
67952d6035fSJeremy L Thompson     return CeedError(op->ceed, 1, "Not defined for composite operator");
680c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
68152d6035fSJeremy L Thompson 
6824ce2993fSjeremylt   *qf = op->qf;
6834ce2993fSjeremylt   return 0;
6844ce2993fSjeremylt }
6854ce2993fSjeremylt 
6864ce2993fSjeremylt /**
68752d6035fSJeremy L Thompson   @brief Get the number of suboperators associated with a CeedOperator
68852d6035fSJeremy L Thompson 
68952d6035fSJeremy L Thompson   @param op              CeedOperator
69052d6035fSJeremy L Thompson   @param[out] numsub     Variable to store number of suboperators
69152d6035fSJeremy L Thompson 
69252d6035fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
69352d6035fSJeremy L Thompson 
69452d6035fSJeremy L Thompson   @ref Advanced
69552d6035fSJeremy L Thompson **/
69652d6035fSJeremy L Thompson 
69752d6035fSJeremy L Thompson int CeedOperatorGetNumSub(CeedOperator op, CeedInt *numsub) {
698c042f62fSJeremy L Thompson   if (!op->composite)
699c042f62fSJeremy L Thompson     // LCOV_EXCL_START
700c042f62fSJeremy L Thompson     return CeedError(op->ceed, 1, "Not a composite operator");
701c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
70252d6035fSJeremy L Thompson 
70352d6035fSJeremy L Thompson   *numsub = op->numsub;
70452d6035fSJeremy L Thompson   return 0;
70552d6035fSJeremy L Thompson }
70652d6035fSJeremy L Thompson 
70752d6035fSJeremy L Thompson /**
70852d6035fSJeremy L Thompson   @brief Get the list of suboperators associated with a CeedOperator
70952d6035fSJeremy L Thompson 
71052d6035fSJeremy L Thompson   @param op                CeedOperator
71152d6035fSJeremy L Thompson   @param[out] suboperators Variable to store list of suboperators
71252d6035fSJeremy L Thompson 
71352d6035fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
71452d6035fSJeremy L Thompson 
71552d6035fSJeremy L Thompson   @ref Advanced
71652d6035fSJeremy L Thompson **/
71752d6035fSJeremy L Thompson 
71852d6035fSJeremy L Thompson int CeedOperatorGetSubList(CeedOperator op, CeedOperator **suboperators) {
719c042f62fSJeremy L Thompson   if (!op->composite)
720c042f62fSJeremy L Thompson     // LCOV_EXCL_START
721c042f62fSJeremy L Thompson     return CeedError(op->ceed, 1, "Not a composite operator");
722c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
72352d6035fSJeremy L Thompson 
72452d6035fSJeremy L Thompson   *suboperators = op->suboperators;
72552d6035fSJeremy L Thompson   return 0;
72652d6035fSJeremy L Thompson }
72752d6035fSJeremy L Thompson 
72852d6035fSJeremy L Thompson /**
729fe2413ffSjeremylt   @brief Set the backend data of a CeedOperator
730fe2413ffSjeremylt 
731fe2413ffSjeremylt   @param[out] op         CeedOperator
732fe2413ffSjeremylt   @param data            Data to set
733fe2413ffSjeremylt 
734fe2413ffSjeremylt   @return An error code: 0 - success, otherwise - failure
735fe2413ffSjeremylt 
736fe2413ffSjeremylt   @ref Advanced
737fe2413ffSjeremylt **/
738fe2413ffSjeremylt 
739fe2413ffSjeremylt int CeedOperatorSetData(CeedOperator op, void **data) {
740fe2413ffSjeremylt   op->data = *data;
741fe2413ffSjeremylt   return 0;
742fe2413ffSjeremylt }
743fe2413ffSjeremylt 
744fe2413ffSjeremylt /**
7454ce2993fSjeremylt   @brief Get the backend data of a CeedOperator
7464ce2993fSjeremylt 
7474ce2993fSjeremylt   @param op              CeedOperator
7484ce2993fSjeremylt   @param[out] data       Variable to store data
7494ce2993fSjeremylt 
7504ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
7514ce2993fSjeremylt 
75223617272Sjeremylt   @ref Advanced
7534ce2993fSjeremylt **/
7544ce2993fSjeremylt 
7554ce2993fSjeremylt int CeedOperatorGetData(CeedOperator op, void **data) {
7564ce2993fSjeremylt   *data = op->data;
7574ce2993fSjeremylt   return 0;
7584ce2993fSjeremylt }
7594ce2993fSjeremylt 
7604ce2993fSjeremylt /**
7614ce2993fSjeremylt   @brief Set the setup flag of a CeedOperator to True
7624ce2993fSjeremylt 
7634ce2993fSjeremylt   @param op              CeedOperator
7644ce2993fSjeremylt 
7654ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
7664ce2993fSjeremylt 
76723617272Sjeremylt   @ref Advanced
7684ce2993fSjeremylt **/
7694ce2993fSjeremylt 
7704ce2993fSjeremylt int CeedOperatorSetSetupDone(CeedOperator op) {
7714ce2993fSjeremylt   op->setupdone = 1;
7724ce2993fSjeremylt   return 0;
7734ce2993fSjeremylt }
7744ce2993fSjeremylt 
7754ce2993fSjeremylt /**
7762ebaca42Sjeremylt   @brief View a field of a CeedOperator
7772ebaca42Sjeremylt 
7782ebaca42Sjeremylt   @param[in] field       Operator field to view
7792ebaca42Sjeremylt   @param[in] fieldnumber Number of field being viewed
7802ebaca42Sjeremylt   @param[in] stream      Stream to view to, e.g., stdout
7812ebaca42Sjeremylt 
7822ebaca42Sjeremylt   @return An error code: 0 - success, otherwise - failure
7832ebaca42Sjeremylt 
7842ebaca42Sjeremylt   @ref Utility
7852ebaca42Sjeremylt **/
7862ebaca42Sjeremylt static int CeedOperatorFieldView(CeedOperatorField field,
7872ebaca42Sjeremylt                                  CeedQFunctionField qffield,
788*2da88da5Sjeremylt                                  CeedInt fieldnumber, bool sub, bool in,
789*2da88da5Sjeremylt                                  FILE *stream) {
7902ebaca42Sjeremylt   const char* pre = sub ? "  " : "";
791*2da88da5Sjeremylt   const char* inout = in ? "Input" : "Output";
7922ebaca42Sjeremylt 
793*2da88da5Sjeremylt   fprintf(stream, "%s    %s Field [%d]:\n"
794*2da88da5Sjeremylt                   "%s      Name: \"%s\"\n"
795*2da88da5Sjeremylt                   "%s      Lmode: \"%s\"\n",
796*2da88da5Sjeremylt                   pre, inout, fieldnumber, pre, qffield->fieldname,
7972ebaca42Sjeremylt                   pre, CeedTransposeModes[field->lmode]);
7982ebaca42Sjeremylt 
7992ebaca42Sjeremylt   if (field->basis == CEED_BASIS_COLLOCATED)
8002ebaca42Sjeremylt     fprintf(stream, "%s      Collocated basis\n", pre);
8012ebaca42Sjeremylt 
8022ebaca42Sjeremylt   if (field->vec == CEED_VECTOR_ACTIVE)
8032ebaca42Sjeremylt     fprintf(stream, "%s      Active vector\n", pre);
8042ebaca42Sjeremylt   else if (field->vec == CEED_VECTOR_NONE)
8052ebaca42Sjeremylt     fprintf(stream, "%s      No vector\n", pre);
8062ebaca42Sjeremylt 
8072ebaca42Sjeremylt   return 0;
8082ebaca42Sjeremylt }
8092ebaca42Sjeremylt 
8102ebaca42Sjeremylt /**
8112ebaca42Sjeremylt   @brief View a single CeedOperator
8122ebaca42Sjeremylt 
8132ebaca42Sjeremylt   @param[in] op     CeedOperator to view
8142ebaca42Sjeremylt   @param[in] stream Stream to write; typically stdout/stderr or a file
8152ebaca42Sjeremylt 
8162ebaca42Sjeremylt   @return Error code: 0 - success, otherwise - failure
8172ebaca42Sjeremylt 
8182ebaca42Sjeremylt   @ref Utility
8192ebaca42Sjeremylt **/
8202ebaca42Sjeremylt int CeedOperatorSingleView(CeedOperator op, bool sub, FILE *stream) {
8212ebaca42Sjeremylt   int ierr;
8222ebaca42Sjeremylt   const char* pre = sub ? "  " : "";
8232ebaca42Sjeremylt 
8242ebaca42Sjeremylt   CeedInt totalfields;
8252ebaca42Sjeremylt   ierr = CeedOperatorGetNumArgs(op, &totalfields); CeedChk(ierr);
826*2da88da5Sjeremylt 
8272ebaca42Sjeremylt   fprintf(stream, "%s  %d Field%s\n", pre, totalfields, totalfields>1 ? "s" : "");
8282ebaca42Sjeremylt 
829*2da88da5Sjeremylt   fprintf(stream, "%s  %d Input Field%s:\n", pre, op->qf->numinputfields,
8302ebaca42Sjeremylt           op->qf->numinputfields>1 ? "s" : "");
8312ebaca42Sjeremylt   for (CeedInt i=0; i<op->qf->numinputfields; i++) {
8322ebaca42Sjeremylt     ierr = CeedOperatorFieldView(op->inputfields[i], op->qf->inputfields[i],
833*2da88da5Sjeremylt                                  i, sub, 1, stream); CeedChk(ierr);
8342ebaca42Sjeremylt   }
8352ebaca42Sjeremylt 
836*2da88da5Sjeremylt   fprintf(stream, "%s  %d Output Field%s:\n", pre, op->qf->numoutputfields,
8372ebaca42Sjeremylt           op->qf->numoutputfields>1 ? "s" : "");
8382ebaca42Sjeremylt   for (CeedInt i=0; i<op->qf->numoutputfields; i++) {
8392ebaca42Sjeremylt     ierr = CeedOperatorFieldView(op->outputfields[i], op->qf->inputfields[i],
840*2da88da5Sjeremylt                                  i, sub, 0, stream); CeedChk(ierr);
8412ebaca42Sjeremylt   }
8422ebaca42Sjeremylt 
8432ebaca42Sjeremylt   return 0;
8442ebaca42Sjeremylt }
8452ebaca42Sjeremylt 
8462ebaca42Sjeremylt /**
8472ebaca42Sjeremylt   @brief View a CeedOperator
8482ebaca42Sjeremylt 
8492ebaca42Sjeremylt   @param[in] op     CeedOperator to view
8502ebaca42Sjeremylt   @param[in] stream Stream to write; typically stdout/stderr or a file
8512ebaca42Sjeremylt 
8522ebaca42Sjeremylt   @return Error code: 0 - success, otherwise - failure
8532ebaca42Sjeremylt 
8542ebaca42Sjeremylt   @ref Utility
8552ebaca42Sjeremylt **/
8562ebaca42Sjeremylt int CeedOperatorView(CeedOperator op, FILE *stream) {
8572ebaca42Sjeremylt   int ierr;
8582ebaca42Sjeremylt 
8592ebaca42Sjeremylt   if (op->composite) {
8602ebaca42Sjeremylt     fprintf(stream, "Composite CeedOperator\n");
8612ebaca42Sjeremylt 
8622ebaca42Sjeremylt     for (CeedInt i=0; i<op->numsub; i++) {
863*2da88da5Sjeremylt       fprintf(stream, "  SubOperator [%d]:\n", i);
8642ebaca42Sjeremylt       ierr = CeedOperatorSingleView(op->suboperators[i], 1, stream);
8652ebaca42Sjeremylt       CeedChk(ierr);
8662ebaca42Sjeremylt     }
8672ebaca42Sjeremylt   } else {
8682ebaca42Sjeremylt     fprintf(stream, "CeedOperator\n");
8692ebaca42Sjeremylt     ierr = CeedOperatorSingleView(op, 0, stream); CeedChk(ierr);
8702ebaca42Sjeremylt   }
8712ebaca42Sjeremylt 
8722ebaca42Sjeremylt   return 0;
8732ebaca42Sjeremylt }
8742ebaca42Sjeremylt 
8752ebaca42Sjeremylt /**
876d1bcdac9Sjeremylt   @brief Get the CeedOperatorFields of a CeedOperator
877d1bcdac9Sjeremylt 
878d1bcdac9Sjeremylt   @param op                 CeedOperator
879d1bcdac9Sjeremylt   @param[out] inputfields   Variable to store inputfields
880d1bcdac9Sjeremylt   @param[out] outputfields  Variable to store outputfields
881d1bcdac9Sjeremylt 
882d1bcdac9Sjeremylt   @return An error code: 0 - success, otherwise - failure
883d1bcdac9Sjeremylt 
884d1bcdac9Sjeremylt   @ref Advanced
885d1bcdac9Sjeremylt **/
886d1bcdac9Sjeremylt 
887692c2638Sjeremylt int CeedOperatorGetFields(CeedOperator op, CeedOperatorField **inputfields,
888d1bcdac9Sjeremylt                           CeedOperatorField **outputfields) {
88952d6035fSJeremy L Thompson   if (op->composite)
890c042f62fSJeremy L Thompson     // LCOV_EXCL_START
89152d6035fSJeremy L Thompson     return CeedError(op->ceed, 1, "Not defined for composite operator");
892c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
89352d6035fSJeremy L Thompson 
894d1bcdac9Sjeremylt   if (inputfields) *inputfields = op->inputfields;
895d1bcdac9Sjeremylt   if (outputfields) *outputfields = op->outputfields;
896d1bcdac9Sjeremylt   return 0;
897d1bcdac9Sjeremylt }
898d1bcdac9Sjeremylt 
899d1bcdac9Sjeremylt /**
9004dccadb6Sjeremylt   @brief Get the L vector CeedTransposeMode of a CeedOperatorField
9014dccadb6Sjeremylt 
9024dccadb6Sjeremylt   @param opfield         CeedOperatorField
9034dccadb6Sjeremylt   @param[out] lmode      Variable to store CeedTransposeMode
9044dccadb6Sjeremylt 
9054dccadb6Sjeremylt   @return An error code: 0 - success, otherwise - failure
9064dccadb6Sjeremylt 
9074dccadb6Sjeremylt   @ref Advanced
9084dccadb6Sjeremylt **/
9094dccadb6Sjeremylt 
9104dccadb6Sjeremylt int CeedOperatorFieldGetLMode(CeedOperatorField opfield,
9114dccadb6Sjeremylt                               CeedTransposeMode *lmode) {
912fe2413ffSjeremylt   *lmode = opfield->lmode;
9134dccadb6Sjeremylt   return 0;
9142b8e417aSjeremylt }
9152b8e417aSjeremylt 
9162b8e417aSjeremylt /**
917d1bcdac9Sjeremylt   @brief Get the CeedElemRestriction of a CeedOperatorField
918d1bcdac9Sjeremylt 
919d1bcdac9Sjeremylt   @param opfield         CeedOperatorField
920d1bcdac9Sjeremylt   @param[out] rstr       Variable to store CeedElemRestriction
921d1bcdac9Sjeremylt 
922d1bcdac9Sjeremylt   @return An error code: 0 - success, otherwise - failure
923d1bcdac9Sjeremylt 
924d1bcdac9Sjeremylt   @ref Advanced
925d1bcdac9Sjeremylt **/
926d1bcdac9Sjeremylt 
927d1bcdac9Sjeremylt int CeedOperatorFieldGetElemRestriction(CeedOperatorField opfield,
928d1bcdac9Sjeremylt                                         CeedElemRestriction *rstr) {
929fe2413ffSjeremylt   *rstr = opfield->Erestrict;
930d1bcdac9Sjeremylt   return 0;
931d1bcdac9Sjeremylt }
932d1bcdac9Sjeremylt 
933d1bcdac9Sjeremylt /**
934d1bcdac9Sjeremylt   @brief Get the CeedBasis of a CeedOperatorField
935d1bcdac9Sjeremylt 
936d1bcdac9Sjeremylt   @param opfield         CeedOperatorField
937d1bcdac9Sjeremylt   @param[out] basis      Variable to store CeedBasis
938d1bcdac9Sjeremylt 
939d1bcdac9Sjeremylt   @return An error code: 0 - success, otherwise - failure
940d1bcdac9Sjeremylt 
941d1bcdac9Sjeremylt   @ref Advanced
942d1bcdac9Sjeremylt **/
943d1bcdac9Sjeremylt 
944692c2638Sjeremylt int CeedOperatorFieldGetBasis(CeedOperatorField opfield, CeedBasis *basis) {
945fe2413ffSjeremylt   *basis = opfield->basis;
946d1bcdac9Sjeremylt   return 0;
947d1bcdac9Sjeremylt }
948d1bcdac9Sjeremylt 
949d1bcdac9Sjeremylt /**
950d1bcdac9Sjeremylt   @brief Get the CeedVector of a CeedOperatorField
951d1bcdac9Sjeremylt 
952d1bcdac9Sjeremylt   @param opfield         CeedOperatorField
953d1bcdac9Sjeremylt   @param[out] vec        Variable to store CeedVector
954d1bcdac9Sjeremylt 
955d1bcdac9Sjeremylt   @return An error code: 0 - success, otherwise - failure
956d1bcdac9Sjeremylt 
957d1bcdac9Sjeremylt   @ref Advanced
958d1bcdac9Sjeremylt **/
959d1bcdac9Sjeremylt 
960692c2638Sjeremylt int CeedOperatorFieldGetVector(CeedOperatorField opfield, CeedVector *vec) {
961fe2413ffSjeremylt   *vec = opfield->vec;
962d1bcdac9Sjeremylt   return 0;
963d1bcdac9Sjeremylt }
964d1bcdac9Sjeremylt 
965d1bcdac9Sjeremylt /**
966b11c1e72Sjeremylt   @brief Destroy a CeedOperator
967d7b241e6Sjeremylt 
968d7b241e6Sjeremylt   @param op CeedOperator to destroy
969b11c1e72Sjeremylt 
970b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
971dfdf5a53Sjeremylt 
972dfdf5a53Sjeremylt   @ref Basic
973b11c1e72Sjeremylt **/
974d7b241e6Sjeremylt int CeedOperatorDestroy(CeedOperator *op) {
975d7b241e6Sjeremylt   int ierr;
976d7b241e6Sjeremylt 
977d7b241e6Sjeremylt   if (!*op || --(*op)->refcount > 0) return 0;
978d7b241e6Sjeremylt   if ((*op)->Destroy) {
979d7b241e6Sjeremylt     ierr = (*op)->Destroy(*op); CeedChk(ierr);
980d7b241e6Sjeremylt   }
981fe2413ffSjeremylt   ierr = CeedDestroy(&(*op)->ceed); CeedChk(ierr);
982fe2413ffSjeremylt   // Free fields
9831d102b48SJeremy L Thompson   for (int i=0; i<(*op)->nfields; i++)
98452d6035fSJeremy L Thompson     if ((*op)->inputfields[i]) {
98571352a93Sjeremylt       ierr = CeedElemRestrictionDestroy(&(*op)->inputfields[i]->Erestrict);
98671352a93Sjeremylt       CeedChk(ierr);
98771352a93Sjeremylt       if ((*op)->inputfields[i]->basis != CEED_BASIS_COLLOCATED) {
98871352a93Sjeremylt         ierr = CeedBasisDestroy(&(*op)->inputfields[i]->basis); CeedChk(ierr);
98971352a93Sjeremylt       }
99071352a93Sjeremylt       if ((*op)->inputfields[i]->vec != CEED_VECTOR_ACTIVE &&
99171352a93Sjeremylt           (*op)->inputfields[i]->vec != CEED_VECTOR_NONE ) {
99271352a93Sjeremylt         ierr = CeedVectorDestroy(&(*op)->inputfields[i]->vec); CeedChk(ierr);
99371352a93Sjeremylt       }
994fe2413ffSjeremylt       ierr = CeedFree(&(*op)->inputfields[i]); CeedChk(ierr);
995fe2413ffSjeremylt     }
9961d102b48SJeremy L Thompson   for (int i=0; i<(*op)->nfields; i++)
997d0eb30a5Sjeremylt     if ((*op)->outputfields[i]) {
99871352a93Sjeremylt       ierr = CeedElemRestrictionDestroy(&(*op)->outputfields[i]->Erestrict);
99971352a93Sjeremylt       CeedChk(ierr);
100071352a93Sjeremylt       if ((*op)->outputfields[i]->basis != CEED_BASIS_COLLOCATED) {
100171352a93Sjeremylt         ierr = CeedBasisDestroy(&(*op)->outputfields[i]->basis); CeedChk(ierr);
100271352a93Sjeremylt       }
100371352a93Sjeremylt       if ((*op)->outputfields[i]->vec != CEED_VECTOR_ACTIVE &&
100471352a93Sjeremylt           (*op)->outputfields[i]->vec != CEED_VECTOR_NONE ) {
100571352a93Sjeremylt         ierr = CeedVectorDestroy(&(*op)->outputfields[i]->vec); CeedChk(ierr);
100671352a93Sjeremylt       }
1007fe2413ffSjeremylt       ierr = CeedFree(&(*op)->outputfields[i]); CeedChk(ierr);
1008fe2413ffSjeremylt     }
100952d6035fSJeremy L Thompson   // Destroy suboperators
10101d102b48SJeremy L Thompson   for (int i=0; i<(*op)->numsub; i++)
101152d6035fSJeremy L Thompson     if ((*op)->suboperators[i]) {
101252d6035fSJeremy L Thompson       ierr = CeedOperatorDestroy(&(*op)->suboperators[i]); CeedChk(ierr);
101352d6035fSJeremy L Thompson     }
1014d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->qf); CeedChk(ierr);
1015d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->dqf); CeedChk(ierr);
1016d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->dqfT); CeedChk(ierr);
1017fe2413ffSjeremylt 
1018fe2413ffSjeremylt   ierr = CeedFree(&(*op)->inputfields); CeedChk(ierr);
1019fe2413ffSjeremylt   ierr = CeedFree(&(*op)->outputfields); CeedChk(ierr);
102052d6035fSJeremy L Thompson   ierr = CeedFree(&(*op)->suboperators); CeedChk(ierr);
1021d7b241e6Sjeremylt   ierr = CeedFree(op); CeedChk(ierr);
1022d7b241e6Sjeremylt   return 0;
1023d7b241e6Sjeremylt }
1024d7b241e6Sjeremylt 
1025d7b241e6Sjeremylt /// @}
1026