xref: /libCEED/interface/ceed-operator.c (revision 250756a76b2acceb2cdef2724c516e6a2de7752e)
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 
103*250756a7Sjeremylt     if (delegate) {
10452d6035fSJeremy L Thompson       ierr = CeedCompositeOperatorCreate(delegate, op); CeedChk(ierr);
10552d6035fSJeremy L Thompson       return 0;
10652d6035fSJeremy L Thompson     }
107*250756a7Sjeremylt   }
10852d6035fSJeremy L Thompson 
10952d6035fSJeremy L Thompson   ierr = CeedCalloc(1, op); CeedChk(ierr);
11052d6035fSJeremy L Thompson   (*op)->ceed = ceed;
11152d6035fSJeremy L Thompson   ceed->refcount++;
11252d6035fSJeremy L Thompson   (*op)->composite = true;
11352d6035fSJeremy L Thompson   ierr = CeedCalloc(16, &(*op)->suboperators); CeedChk(ierr);
114*250756a7Sjeremylt 
115*250756a7Sjeremylt   if (ceed->CompositeOperatorCreate) {
11652d6035fSJeremy L Thompson     ierr = ceed->CompositeOperatorCreate(*op); CeedChk(ierr);
117*250756a7Sjeremylt   }
11852d6035fSJeremy L Thompson   return 0;
11952d6035fSJeremy L Thompson }
12052d6035fSJeremy L Thompson 
12152d6035fSJeremy L Thompson /**
122b11c1e72Sjeremylt   @brief Provide a field to a CeedOperator for use by its CeedQFunction
123d7b241e6Sjeremylt 
124d7b241e6Sjeremylt   This function is used to specify both active and passive fields to a
125d7b241e6Sjeremylt   CeedOperator.  For passive fields, a vector @arg v must be provided.  Passive
126d7b241e6Sjeremylt   fields can inputs or outputs (updated in-place when operator is applied).
127d7b241e6Sjeremylt 
128d7b241e6Sjeremylt   Active fields must be specified using this function, but their data (in a
129d7b241e6Sjeremylt   CeedVector) is passed in CeedOperatorApply().  There can be at most one active
130d7b241e6Sjeremylt   input and at most one active output.
131d7b241e6Sjeremylt 
1328c91a0c9SJeremy L Thompson   @param op         CeedOperator on which to provide the field
1338795c945Sjeremylt   @param fieldname  Name of the field (to be matched with the name used by
1348795c945Sjeremylt                       CeedQFunction)
135b11c1e72Sjeremylt   @param r          CeedElemRestriction
136b0e29e78Sjeremylt   @param lmode      CeedTransposeMode which specifies the ordering of the
137b0e29e78Sjeremylt                       components of the l-vector used by this CeedOperatorField,
138b0e29e78Sjeremylt                       CEED_NOTRANSPOSE indicates the component is the
139b0e29e78Sjeremylt                       outermost index and CEED_TRANSPOSE indicates the component
140b0e29e78Sjeremylt                       is the innermost index in ordering of the l-vector
141783c99b3SValeria Barra   @param b          CeedBasis in which the field resides or CEED_BASIS_COLLOCATED
142b11c1e72Sjeremylt                       if collocated with quadrature points
143b11c1e72Sjeremylt   @param v          CeedVector to be used by CeedOperator or CEED_VECTOR_ACTIVE
144b11c1e72Sjeremylt                       if field is active or CEED_VECTOR_NONE if using
1458c91a0c9SJeremy L Thompson                       CEED_EVAL_WEIGHT in the QFunction
146b11c1e72Sjeremylt 
147b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
148dfdf5a53Sjeremylt 
149dfdf5a53Sjeremylt   @ref Basic
150b11c1e72Sjeremylt **/
151d7b241e6Sjeremylt int CeedOperatorSetField(CeedOperator op, const char *fieldname,
1524dccadb6Sjeremylt                          CeedElemRestriction r, CeedTransposeMode lmode,
1534dccadb6Sjeremylt                          CeedBasis b, CeedVector v) {
154d7b241e6Sjeremylt   int ierr;
15552d6035fSJeremy L Thompson   if (op->composite)
156c042f62fSJeremy L Thompson     // LCOV_EXCL_START
15752d6035fSJeremy L Thompson     return CeedError(op->ceed, 1, "Cannot add field to composite operator.");
158c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
1598b067b84SJed Brown   if (!r)
160c042f62fSJeremy L Thompson     // LCOV_EXCL_START
161c042f62fSJeremy L Thompson     return CeedError(op->ceed, 1,
162c042f62fSJeremy L Thompson                      "ElemRestriction r for field \"%s\" must be non-NULL.",
163c042f62fSJeremy L Thompson                      fieldname);
164c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
1658b067b84SJed Brown   if (!b)
166c042f62fSJeremy L Thompson     // LCOV_EXCL_START
167c042f62fSJeremy L Thompson     return CeedError(op->ceed, 1, "Basis b for field \"%s\" must be non-NULL.",
168c042f62fSJeremy L Thompson                      fieldname);
169c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
1708b067b84SJed Brown   if (!v)
171c042f62fSJeremy L Thompson     // LCOV_EXCL_START
172c042f62fSJeremy L Thompson     return CeedError(op->ceed, 1, "Vector v for field \"%s\" must be non-NULL.",
173c042f62fSJeremy L Thompson                      fieldname);
174c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
17552d6035fSJeremy L Thompson 
176d7b241e6Sjeremylt   CeedInt numelements;
177d7b241e6Sjeremylt   ierr = CeedElemRestrictionGetNumElements(r, &numelements); CeedChk(ierr);
1782cb0afc5Sjeremylt   if (op->hasrestriction && op->numelements != numelements)
179c042f62fSJeremy L Thompson     // LCOV_EXCL_START
180d7b241e6Sjeremylt     return CeedError(op->ceed, 1,
1811d102b48SJeremy L Thompson                      "ElemRestriction with %d elements incompatible with prior "
1821d102b48SJeremy L Thompson                      "%d elements", numelements, op->numelements);
183c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
184d7b241e6Sjeremylt   op->numelements = numelements;
1852cb0afc5Sjeremylt   op->hasrestriction = true; // Restriction set, but numelements may be 0
186d7b241e6Sjeremylt 
187783c99b3SValeria Barra   if (b != CEED_BASIS_COLLOCATED) {
188d7b241e6Sjeremylt     CeedInt numqpoints;
189d7b241e6Sjeremylt     ierr = CeedBasisGetNumQuadraturePoints(b, &numqpoints); CeedChk(ierr);
190d7b241e6Sjeremylt     if (op->numqpoints && op->numqpoints != numqpoints)
191c042f62fSJeremy L Thompson       // LCOV_EXCL_START
1921d102b48SJeremy L Thompson       return CeedError(op->ceed, 1, "Basis with %d quadrature points "
1931d102b48SJeremy L Thompson                        "incompatible with prior %d points", numqpoints,
1941d102b48SJeremy L Thompson                        op->numqpoints);
195c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
196d7b241e6Sjeremylt     op->numqpoints = numqpoints;
197d7b241e6Sjeremylt   }
198d1bcdac9Sjeremylt   CeedOperatorField *ofield;
199d7b241e6Sjeremylt   for (CeedInt i=0; i<op->qf->numinputfields; i++) {
200fe2413ffSjeremylt     if (!strcmp(fieldname, (*op->qf->inputfields[i]).fieldname)) {
201d7b241e6Sjeremylt       ofield = &op->inputfields[i];
202d7b241e6Sjeremylt       goto found;
203d7b241e6Sjeremylt     }
204d7b241e6Sjeremylt   }
205d7b241e6Sjeremylt   for (CeedInt i=0; i<op->qf->numoutputfields; i++) {
206fe2413ffSjeremylt     if (!strcmp(fieldname, (*op->qf->outputfields[i]).fieldname)) {
207d7b241e6Sjeremylt       ofield = &op->outputfields[i];
208d7b241e6Sjeremylt       goto found;
209d7b241e6Sjeremylt     }
210d7b241e6Sjeremylt   }
211c042f62fSJeremy L Thompson   // LCOV_EXCL_START
212d7b241e6Sjeremylt   return CeedError(op->ceed, 1, "QFunction has no knowledge of field '%s'",
213d7b241e6Sjeremylt                    fieldname);
214c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
215d7b241e6Sjeremylt found:
216fe2413ffSjeremylt   ierr = CeedCalloc(1, ofield); CeedChk(ierr);
217fe2413ffSjeremylt   (*ofield)->Erestrict = r;
21871352a93Sjeremylt   r->refcount += 1;
219fe2413ffSjeremylt   (*ofield)->lmode = lmode;
220fe2413ffSjeremylt   (*ofield)->basis = b;
22171352a93Sjeremylt   if (b != CEED_BASIS_COLLOCATED)
22271352a93Sjeremylt     b->refcount += 1;
223fe2413ffSjeremylt   (*ofield)->vec = v;
22471352a93Sjeremylt   if (v != CEED_VECTOR_ACTIVE && v != CEED_VECTOR_NONE)
22571352a93Sjeremylt     v->refcount += 1;
226d7b241e6Sjeremylt   op->nfields += 1;
227d7b241e6Sjeremylt   return 0;
228d7b241e6Sjeremylt }
229d7b241e6Sjeremylt 
230d7b241e6Sjeremylt /**
23152d6035fSJeremy L Thompson   @brief Add a sub-operator to a composite CeedOperator
232288c0443SJeremy L Thompson 
233288c0443SJeremy L Thompson   @param[out] compositeop Address of the composite CeedOperator
234288c0443SJeremy L Thompson   @param      subop       Address of the sub-operator CeedOperator
23552d6035fSJeremy L Thompson 
23652d6035fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
23752d6035fSJeremy L Thompson 
23852d6035fSJeremy L Thompson   @ref Basic
23952d6035fSJeremy L Thompson  */
240692c2638Sjeremylt int CeedCompositeOperatorAddSub(CeedOperator compositeop, CeedOperator subop) {
24152d6035fSJeremy L Thompson   if (!compositeop->composite)
242c042f62fSJeremy L Thompson     // LCOV_EXCL_START
2431d102b48SJeremy L Thompson     return CeedError(compositeop->ceed, 1, "CeedOperator is not a composite "
2441d102b48SJeremy L Thompson                      "operator");
245c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
24652d6035fSJeremy L Thompson 
24752d6035fSJeremy L Thompson   if (compositeop->numsub == CEED_COMPOSITE_MAX)
248c042f62fSJeremy L Thompson     // LCOV_EXCL_START
2491d102b48SJeremy L Thompson     return CeedError(compositeop->ceed, 1, "Cannot add additional suboperators");
250c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
25152d6035fSJeremy L Thompson 
25252d6035fSJeremy L Thompson   compositeop->suboperators[compositeop->numsub] = subop;
25352d6035fSJeremy L Thompson   subop->refcount++;
25452d6035fSJeremy L Thompson   compositeop->numsub++;
25552d6035fSJeremy L Thompson   return 0;
25652d6035fSJeremy L Thompson }
25752d6035fSJeremy L Thompson 
25852d6035fSJeremy L Thompson /**
2595107b09fSJeremy L Thompson   @brief Duplicate a CeedOperator with a reference Ceed to fallback for advanced
2605107b09fSJeremy L Thompson            CeedOperator functionality
2615107b09fSJeremy L Thompson 
2625107b09fSJeremy L Thompson   @param op           CeedOperator to create fallback for
2635107b09fSJeremy L Thompson 
2645107b09fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
2655107b09fSJeremy L Thompson 
2665107b09fSJeremy L Thompson   @ref Developer
2675107b09fSJeremy L Thompson **/
2685107b09fSJeremy L Thompson int CeedOperatorCreateFallback(CeedOperator op) {
2695107b09fSJeremy L Thompson   int ierr;
2705107b09fSJeremy L Thompson 
2715107b09fSJeremy L Thompson   // Fallback Ceed
2725107b09fSJeremy L Thompson   const char *resource, *fallbackresource;
2735107b09fSJeremy L Thompson   ierr = CeedGetResource(op->ceed, &resource); CeedChk(ierr);
2745107b09fSJeremy L Thompson   ierr = CeedGetOperatorFallbackResource(op->ceed, &fallbackresource);
2755107b09fSJeremy L Thompson   CeedChk(ierr);
2765107b09fSJeremy L Thompson   if (!strcmp(resource, fallbackresource))
2775107b09fSJeremy L Thompson     // LCOV_EXCL_START
2785107b09fSJeremy L Thompson     return CeedError(op->ceed, 1, "Backend %s cannot create an operator"
2795107b09fSJeremy L Thompson                      "fallback to resource %s", resource, fallbackresource);
2805107b09fSJeremy L Thompson   // LCOV_EXCL_STOP
2815107b09fSJeremy L Thompson 
2825107b09fSJeremy L Thompson   Ceed ceedref;
2835107b09fSJeremy L Thompson   ierr = CeedInit(fallbackresource, &ceedref); CeedChk(ierr);
2845107b09fSJeremy L Thompson   ceedref->opfallbackparent = op->ceed;
2855107b09fSJeremy L Thompson   op->ceed->opfallbackceed = ceedref;
2865107b09fSJeremy L Thompson 
2875107b09fSJeremy L Thompson   // Clone Op
2885107b09fSJeremy L Thompson   CeedOperator opref;
2895107b09fSJeremy L Thompson   ierr = CeedCalloc(1, &opref); CeedChk(ierr);
2905107b09fSJeremy L Thompson   memcpy(opref, op, sizeof(*opref)); CeedChk(ierr);
2915107b09fSJeremy L Thompson   opref->data = NULL;
2925107b09fSJeremy L Thompson   opref->setupdone = 0;
2935107b09fSJeremy L Thompson   opref->ceed = ceedref;
2945107b09fSJeremy L Thompson   ierr = ceedref->OperatorCreate(opref); CeedChk(ierr);
2955107b09fSJeremy L Thompson   op->opfallback = opref;
2965107b09fSJeremy L Thompson 
2975107b09fSJeremy L Thompson   // Clone QF
2985107b09fSJeremy L Thompson   CeedQFunction qfref;
2995107b09fSJeremy L Thompson   ierr = CeedCalloc(1, &qfref); CeedChk(ierr);
3005107b09fSJeremy L Thompson   memcpy(qfref, (op->qf), sizeof(*qfref)); CeedChk(ierr);
3015107b09fSJeremy L Thompson   qfref->data = NULL;
3025107b09fSJeremy L Thompson   qfref->ceed = ceedref;
3035107b09fSJeremy L Thompson   ierr = ceedref->QFunctionCreate(qfref); CeedChk(ierr);
3045107b09fSJeremy L Thompson   opref->qf = qfref;
3055107b09fSJeremy L Thompson   op->qffallback = qfref;
3065107b09fSJeremy L Thompson 
3075107b09fSJeremy L Thompson   return 0;
3085107b09fSJeremy L Thompson }
3095107b09fSJeremy L Thompson 
3105107b09fSJeremy L Thompson /**
311*250756a7Sjeremylt   @brief Check if a CeedOperator is ready to be used.
312*250756a7Sjeremylt 
313*250756a7Sjeremylt   @param[in] ceed Ceed object for error handling
314*250756a7Sjeremylt   @param[in] op   CeedOperator to check
315*250756a7Sjeremylt 
316*250756a7Sjeremylt   @return An error code: 0 - success, otherwise - failure
317*250756a7Sjeremylt 
318*250756a7Sjeremylt   @ref Basic
319*250756a7Sjeremylt **/
320*250756a7Sjeremylt static int CeedOperatorCheckReady(Ceed ceed, CeedOperator op) {
321*250756a7Sjeremylt   CeedQFunction qf = op->qf;
322*250756a7Sjeremylt 
323*250756a7Sjeremylt   if (op->composite) {
324*250756a7Sjeremylt     if (!op->numsub)
325*250756a7Sjeremylt       // LCOV_EXCL_START
326*250756a7Sjeremylt       return CeedError(ceed, 1, "No suboperators set");
327*250756a7Sjeremylt     // LCOV_EXCL_STOP
328*250756a7Sjeremylt   } else {
329*250756a7Sjeremylt     if (op->nfields == 0)
330*250756a7Sjeremylt       // LCOV_EXCL_START
331*250756a7Sjeremylt       return CeedError(ceed, 1, "No operator fields set");
332*250756a7Sjeremylt     // LCOV_EXCL_STOP
333*250756a7Sjeremylt     if (op->nfields < qf->numinputfields + qf->numoutputfields)
334*250756a7Sjeremylt       // LCOV_EXCL_START
335*250756a7Sjeremylt       return CeedError(ceed, 1, "Not all operator fields set");
336*250756a7Sjeremylt     // LCOV_EXCL_STOP
337*250756a7Sjeremylt     if (!op->hasrestriction)
338*250756a7Sjeremylt       // LCOV_EXCL_START
339*250756a7Sjeremylt       return CeedError(ceed, 1,"At least one restriction required");
340*250756a7Sjeremylt     // LCOV_EXCL_STOP
341*250756a7Sjeremylt     if (op->numqpoints == 0)
342*250756a7Sjeremylt       // LCOV_EXCL_START
343*250756a7Sjeremylt       return CeedError(ceed, 1,"At least one non-collocated basis required");
344*250756a7Sjeremylt     // LCOV_EXCL_STOP
345*250756a7Sjeremylt   }
346*250756a7Sjeremylt 
347*250756a7Sjeremylt   return 0;
348*250756a7Sjeremylt }
349*250756a7Sjeremylt 
350*250756a7Sjeremylt /**
3511d102b48SJeremy L Thompson   @brief Assemble a linear CeedQFunction associated with a CeedOperator
3521d102b48SJeremy L Thompson 
3531d102b48SJeremy L Thompson   This returns a CeedVector containing a matrix at each quadrature point
3541d102b48SJeremy L Thompson     providing the action of the CeedQFunction associated with the CeedOperator.
3551d102b48SJeremy L Thompson     The vector 'assembled' is of shape
3561d102b48SJeremy L Thompson       [num_elements, num_input_fields, num_output_fields, num_quad_points]
3571d102b48SJeremy L Thompson     and contains column-major matrices representing the action of the
3581d102b48SJeremy L Thompson     CeedQFunction for a corresponding quadrature point on an element. Inputs and
3591d102b48SJeremy L Thompson     outputs are in the order provided by the user when adding CeedOperator fields.
3601d102b48SJeremy L Thompson     For example, a QFunction with inputs 'u' and 'gradu' and outputs 'gradv' and
3611d102b48SJeremy L Thompson     'v', provided in that order, would result in an assembled QFunction that
3621d102b48SJeremy L Thompson     consists of (1 + dim) x (dim + 1) matrices at each quadrature point acting
3631d102b48SJeremy L Thompson     on the input [u, du_0, du_1] and producing the output [dv_0, dv_1, v].
3641d102b48SJeremy L Thompson 
3651d102b48SJeremy L Thompson   @param op             CeedOperator to assemble CeedQFunction
3661d102b48SJeremy L Thompson   @param[out] assembled CeedVector to store assembled CeedQFunction at
3671d102b48SJeremy L Thompson                           quadrature points
3681d102b48SJeremy L Thompson   @param[out] rstr      CeedElemRestriction for CeedVector containing assembled
3691d102b48SJeremy L Thompson                           CeedQFunction
3701d102b48SJeremy L Thompson   @param request        Address of CeedRequest for non-blocking completion, else
3711d102b48SJeremy L Thompson                           CEED_REQUEST_IMMEDIATE
3721d102b48SJeremy L Thompson 
3731d102b48SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
3741d102b48SJeremy L Thompson 
375b7ec98d8SJeremy L Thompson   @ref Basic
3761d102b48SJeremy L Thompson **/
3771d102b48SJeremy L Thompson int CeedOperatorAssembleLinearQFunction(CeedOperator op, CeedVector *assembled,
3787f823360Sjeremylt                                         CeedElemRestriction *rstr,
3797f823360Sjeremylt                                         CeedRequest *request) {
3801d102b48SJeremy L Thompson   int ierr;
3811d102b48SJeremy L Thompson   Ceed ceed = op->ceed;
382*250756a7Sjeremylt   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
3831d102b48SJeremy L Thompson 
3845107b09fSJeremy L Thompson   if (op->AssembleLinearQFunction) {
3851d102b48SJeremy L Thompson     ierr = op->AssembleLinearQFunction(op, assembled, rstr, request);
3861d102b48SJeremy L Thompson     CeedChk(ierr);
3875107b09fSJeremy L Thompson   } else {
3885107b09fSJeremy L Thompson     // Fallback to reference Ceed
3895107b09fSJeremy L Thompson     if (!op->opfallback) {
3905107b09fSJeremy L Thompson       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
3915107b09fSJeremy L Thompson     }
3925107b09fSJeremy L Thompson     // Assemble
3935107b09fSJeremy L Thompson     ierr = op->opfallback->AssembleLinearQFunction(op->opfallback, assembled,
3945107b09fSJeremy L Thompson            rstr, request); CeedChk(ierr);
3955107b09fSJeremy L Thompson   }
396*250756a7Sjeremylt 
3971d102b48SJeremy L Thompson   return 0;
3981d102b48SJeremy L Thompson }
3991d102b48SJeremy L Thompson 
4001d102b48SJeremy L Thompson /**
401b7ec98d8SJeremy L Thompson   @brief Assemble the diagonal of a square linear Operator
402b7ec98d8SJeremy L Thompson 
403b7ec98d8SJeremy L Thompson   This returns a CeedVector containing the diagonal of a linear CeedOperator.
404b7ec98d8SJeremy L Thompson 
405b7ec98d8SJeremy L Thompson   @param op             CeedOperator to assemble CeedQFunction
406b7ec98d8SJeremy L Thompson   @param[out] assembled CeedVector to store assembled CeedOperator diagonal
407b7ec98d8SJeremy L Thompson   @param request        Address of CeedRequest for non-blocking completion, else
408b7ec98d8SJeremy L Thompson                           CEED_REQUEST_IMMEDIATE
409b7ec98d8SJeremy L Thompson 
410b7ec98d8SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
411b7ec98d8SJeremy L Thompson 
412b7ec98d8SJeremy L Thompson   @ref Basic
413b7ec98d8SJeremy L Thompson **/
4147f823360Sjeremylt int CeedOperatorAssembleLinearDiagonal(CeedOperator op, CeedVector *assembled,
4157f823360Sjeremylt                                        CeedRequest *request) {
416b7ec98d8SJeremy L Thompson   int ierr;
417b7ec98d8SJeremy L Thompson   Ceed ceed = op->ceed;
418*250756a7Sjeremylt   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
419b7ec98d8SJeremy L Thompson 
420b7ec98d8SJeremy L Thompson   // Use backend version, if available
421b7ec98d8SJeremy L Thompson   if (op->AssembleLinearDiagonal) {
422b7ec98d8SJeremy L Thompson     ierr = op->AssembleLinearDiagonal(op, assembled, request); CeedChk(ierr);
423b7ec98d8SJeremy L Thompson     return 0;
424b7ec98d8SJeremy L Thompson   }
425b7ec98d8SJeremy L Thompson 
426b7ec98d8SJeremy L Thompson   // Assemble QFunction
427*250756a7Sjeremylt   CeedQFunction qf = op->qf;
428b7ec98d8SJeremy L Thompson   CeedVector assembledqf;
429b7ec98d8SJeremy L Thompson   CeedElemRestriction rstr;
430b7ec98d8SJeremy L Thompson   ierr = CeedOperatorAssembleLinearQFunction(op,  &assembledqf, &rstr, request);
431b7ec98d8SJeremy L Thompson   CeedChk(ierr);
432b7ec98d8SJeremy L Thompson   ierr = CeedElemRestrictionDestroy(&rstr); CeedChk(ierr);
433b7ec98d8SJeremy L Thompson 
434b7ec98d8SJeremy L Thompson   // Determine active input basis
435112e3f70Sjeremylt   CeedInt numemodein = 0, ncomp, dim = 1;
436b7ec98d8SJeremy L Thompson   CeedEvalMode *emodein = NULL;
437112e3f70Sjeremylt   CeedBasis basisin = NULL;
438112e3f70Sjeremylt   CeedElemRestriction rstrin = NULL;
439b7ec98d8SJeremy L Thompson   for (CeedInt i=0; i<qf->numinputfields; i++)
440b7ec98d8SJeremy L Thompson     if (op->inputfields[i]->vec == CEED_VECTOR_ACTIVE) {
441b7ec98d8SJeremy L Thompson       ierr = CeedOperatorFieldGetBasis(op->inputfields[i], &basisin);
442b7ec98d8SJeremy L Thompson       CeedChk(ierr);
443b7ec98d8SJeremy L Thompson       ierr = CeedBasisGetNumComponents(basisin, &ncomp); CeedChk(ierr);
444b7ec98d8SJeremy L Thompson       ierr = CeedBasisGetDimension(basisin, &dim); CeedChk(ierr);
445b7ec98d8SJeremy L Thompson       ierr = CeedOperatorFieldGetElemRestriction(op->inputfields[i], &rstrin);
446b7ec98d8SJeremy L Thompson       CeedChk(ierr);
447b7ec98d8SJeremy L Thompson       CeedEvalMode emode;
448b7ec98d8SJeremy L Thompson       ierr = CeedQFunctionFieldGetEvalMode(qf->inputfields[i], &emode);
449b7ec98d8SJeremy L Thompson       CeedChk(ierr);
450b7ec98d8SJeremy L Thompson       switch (emode) {
451b7ec98d8SJeremy L Thompson       case CEED_EVAL_NONE:
452b7ec98d8SJeremy L Thompson       case CEED_EVAL_INTERP:
453b7ec98d8SJeremy L Thompson         ierr = CeedRealloc(numemodein + 1, &emodein); CeedChk(ierr);
454b7ec98d8SJeremy L Thompson         emodein[numemodein] = emode;
455b7ec98d8SJeremy L Thompson         numemodein += 1;
456b7ec98d8SJeremy L Thompson         break;
457b7ec98d8SJeremy L Thompson       case CEED_EVAL_GRAD:
458b7ec98d8SJeremy L Thompson         ierr = CeedRealloc(numemodein + dim, &emodein); CeedChk(ierr);
459b7ec98d8SJeremy L Thompson         for (CeedInt d=0; d<dim; d++)
460b7ec98d8SJeremy L Thompson           emodein[numemodein+d] = emode;
461b7ec98d8SJeremy L Thompson         numemodein += dim;
462b7ec98d8SJeremy L Thompson         break;
463b7ec98d8SJeremy L Thompson       case CEED_EVAL_WEIGHT:
464b7ec98d8SJeremy L Thompson       case CEED_EVAL_DIV:
465b7ec98d8SJeremy L Thompson       case CEED_EVAL_CURL:
466b7ec98d8SJeremy L Thompson         break; // Caught by QF Assembly
467b7ec98d8SJeremy L Thompson       }
468b7ec98d8SJeremy L Thompson     }
469b7ec98d8SJeremy L Thompson 
470b7ec98d8SJeremy L Thompson   // Determine active output basis
471b7ec98d8SJeremy L Thompson   CeedInt numemodeout = 0;
472b7ec98d8SJeremy L Thompson   CeedEvalMode *emodeout = NULL;
473112e3f70Sjeremylt   CeedBasis basisout = NULL;
474112e3f70Sjeremylt   CeedElemRestriction rstrout = NULL;
475112e3f70Sjeremylt   CeedTransposeMode lmodeout = CEED_NOTRANSPOSE;
476b7ec98d8SJeremy L Thompson   for (CeedInt i=0; i<qf->numoutputfields; i++)
477b7ec98d8SJeremy L Thompson     if (op->outputfields[i]->vec == CEED_VECTOR_ACTIVE) {
478b7ec98d8SJeremy L Thompson       ierr = CeedOperatorFieldGetBasis(op->outputfields[i], &basisout);
479b7ec98d8SJeremy L Thompson       CeedChk(ierr);
480b7ec98d8SJeremy L Thompson       ierr = CeedOperatorFieldGetElemRestriction(op->outputfields[i], &rstrout);
481b7ec98d8SJeremy L Thompson       CeedChk(ierr);
482b7ec98d8SJeremy L Thompson       ierr = CeedOperatorFieldGetLMode(op->outputfields[i], &lmodeout);
483b7ec98d8SJeremy L Thompson       CeedChk(ierr);
484b7ec98d8SJeremy L Thompson       CeedEvalMode emode;
485b7ec98d8SJeremy L Thompson       ierr = CeedQFunctionFieldGetEvalMode(qf->outputfields[i], &emode);
486b7ec98d8SJeremy L Thompson       CeedChk(ierr);
487b7ec98d8SJeremy L Thompson       switch (emode) {
488b7ec98d8SJeremy L Thompson       case CEED_EVAL_NONE:
489b7ec98d8SJeremy L Thompson       case CEED_EVAL_INTERP:
490b7ec98d8SJeremy L Thompson         ierr = CeedRealloc(numemodeout + 1, &emodeout); CeedChk(ierr);
491b7ec98d8SJeremy L Thompson         emodeout[numemodeout] = emode;
492b7ec98d8SJeremy L Thompson         numemodeout += 1;
493b7ec98d8SJeremy L Thompson         break;
494b7ec98d8SJeremy L Thompson       case CEED_EVAL_GRAD:
495b7ec98d8SJeremy L Thompson         ierr = CeedRealloc(numemodeout + dim, &emodeout); CeedChk(ierr);
496b7ec98d8SJeremy L Thompson         for (CeedInt d=0; d<dim; d++)
497b7ec98d8SJeremy L Thompson           emodeout[numemodeout+d] = emode;
498b7ec98d8SJeremy L Thompson         numemodeout += dim;
499b7ec98d8SJeremy L Thompson         break;
500b7ec98d8SJeremy L Thompson       case CEED_EVAL_WEIGHT:
501b7ec98d8SJeremy L Thompson       case CEED_EVAL_DIV:
502b7ec98d8SJeremy L Thompson       case CEED_EVAL_CURL:
503b7ec98d8SJeremy L Thompson         break; // Caught by QF Assembly
504b7ec98d8SJeremy L Thompson       }
505b7ec98d8SJeremy L Thompson     }
506b7ec98d8SJeremy L Thompson 
507b7ec98d8SJeremy L Thompson   // Create diagonal vector
508b7ec98d8SJeremy L Thompson   CeedVector elemdiag;
509b7ec98d8SJeremy L Thompson   ierr = CeedElemRestrictionCreateVector(rstrin, assembled, &elemdiag);
510b7ec98d8SJeremy L Thompson   CeedChk(ierr);
511b7ec98d8SJeremy L Thompson 
512b7ec98d8SJeremy L Thompson   // Assemble element operator diagonals
513b7ec98d8SJeremy L Thompson   CeedScalar *elemdiagarray, *assembledqfarray;
514b7ec98d8SJeremy L Thompson   ierr = CeedVectorSetValue(elemdiag, 0.0); CeedChk(ierr);
515b7ec98d8SJeremy L Thompson   ierr = CeedVectorGetArray(elemdiag, CEED_MEM_HOST, &elemdiagarray);
516b7ec98d8SJeremy L Thompson   CeedChk(ierr);
517b7ec98d8SJeremy L Thompson   ierr = CeedVectorGetArray(assembledqf, CEED_MEM_HOST, &assembledqfarray);
518b7ec98d8SJeremy L Thompson   CeedChk(ierr);
519b7ec98d8SJeremy L Thompson   CeedInt nelem, nnodes, nqpts;
520b7ec98d8SJeremy L Thompson   ierr = CeedElemRestrictionGetNumElements(rstrin, &nelem); CeedChk(ierr);
521b7ec98d8SJeremy L Thompson   ierr = CeedBasisGetNumNodes(basisin, &nnodes); CeedChk(ierr);
522b7ec98d8SJeremy L Thompson   ierr = CeedBasisGetNumQuadraturePoints(basisin, &nqpts); CeedChk(ierr);
523b7ec98d8SJeremy L Thompson   // Compute the diagonal of B^T D B
524b7ec98d8SJeremy L Thompson   // Each node, qpt pair
525b7ec98d8SJeremy L Thompson   for (CeedInt n=0; n<nnodes; n++)
526b7ec98d8SJeremy L Thompson     for (CeedInt q=0; q<nqpts; q++) {
527b7ec98d8SJeremy L Thompson       CeedInt dout = -1;
528b7ec98d8SJeremy L Thompson       // Each basis eval mode pair
529b7ec98d8SJeremy L Thompson       for (CeedInt eout=0; eout<numemodeout; eout++) {
530b7ec98d8SJeremy L Thompson         CeedScalar bt = 1.0;
531b7ec98d8SJeremy L Thompson         if (emodeout[eout] == CEED_EVAL_GRAD)
532b7ec98d8SJeremy L Thompson           dout += 1;
533b7ec98d8SJeremy L Thompson         ierr = CeedBasisGetValue(basisout, emodeout[eout], q, n, dout, &bt);
534b7ec98d8SJeremy L Thompson         CeedChk(ierr);
535b7ec98d8SJeremy L Thompson         CeedInt din = -1;
536b7ec98d8SJeremy L Thompson         for (CeedInt ein=0; ein<numemodein; ein++) {
537b7ec98d8SJeremy L Thompson           CeedScalar b = 0.0;
538b7ec98d8SJeremy L Thompson           if (emodein[ein] == CEED_EVAL_GRAD)
539b7ec98d8SJeremy L Thompson             din += 1;
540b7ec98d8SJeremy L Thompson           ierr = CeedBasisGetValue(basisin, emodein[ein], q, n, din, &b);
541b7ec98d8SJeremy L Thompson           CeedChk(ierr);
542b7ec98d8SJeremy L Thompson           // Each element and component
543b7ec98d8SJeremy L Thompson           for (CeedInt e=0; e<nelem; e++)
544b7ec98d8SJeremy L Thompson             for (CeedInt cout=0; cout<ncomp; cout++) {
545b7ec98d8SJeremy L Thompson               CeedScalar db = 0.0;
546b7ec98d8SJeremy L Thompson               for (CeedInt cin=0; cin<ncomp; cin++)
547b7ec98d8SJeremy L Thompson                 db += assembledqfarray[((((e*numemodein+ein)*ncomp+cin)*
548b7ec98d8SJeremy L Thompson                                          numemodeout+eout)*ncomp+cout)*nqpts+q]*b;
549b7ec98d8SJeremy L Thompson               elemdiagarray[(e*ncomp+cout)*nnodes+n] += bt * db;
550b7ec98d8SJeremy L Thompson             }
551b7ec98d8SJeremy L Thompson         }
552b7ec98d8SJeremy L Thompson       }
553b7ec98d8SJeremy L Thompson     }
554b7ec98d8SJeremy L Thompson 
555b7ec98d8SJeremy L Thompson   ierr = CeedVectorRestoreArray(elemdiag, &elemdiagarray); CeedChk(ierr);
556b7ec98d8SJeremy L Thompson   ierr = CeedVectorRestoreArray(assembledqf, &assembledqfarray); CeedChk(ierr);
557b7ec98d8SJeremy L Thompson 
558b7ec98d8SJeremy L Thompson   // Assemble local operator diagonal
559b7ec98d8SJeremy L Thompson   ierr = CeedVectorSetValue(*assembled, 0.0); CeedChk(ierr);
560b7ec98d8SJeremy L Thompson   ierr = CeedElemRestrictionApply(rstrout, CEED_TRANSPOSE, lmodeout, elemdiag,
561b7ec98d8SJeremy L Thompson                                   *assembled, request); CeedChk(ierr);
562b7ec98d8SJeremy L Thompson 
563b7ec98d8SJeremy L Thompson   // Cleanup
564b7ec98d8SJeremy L Thompson   ierr = CeedVectorDestroy(&assembledqf); CeedChk(ierr);
565b7ec98d8SJeremy L Thompson   ierr = CeedVectorDestroy(&elemdiag); CeedChk(ierr);
566b7ec98d8SJeremy L Thompson   ierr = CeedFree(&emodein); CeedChk(ierr);
567b7ec98d8SJeremy L Thompson   ierr = CeedFree(&emodeout); CeedChk(ierr);
568b7ec98d8SJeremy L Thompson 
569b7ec98d8SJeremy L Thompson   return 0;
570b7ec98d8SJeremy L Thompson }
571b7ec98d8SJeremy L Thompson 
572b7ec98d8SJeremy L Thompson /**
573cae8b89aSjeremylt   @brief Apply CeedOperator to a vector and overwrite output vector
574d7b241e6Sjeremylt 
575d7b241e6Sjeremylt   This computes the action of the operator on the specified (active) input,
576d7b241e6Sjeremylt   yielding its (active) output.  All inputs and outputs must be specified using
577d7b241e6Sjeremylt   CeedOperatorSetField().
578d7b241e6Sjeremylt 
579d7b241e6Sjeremylt   @param op        CeedOperator to apply
580b11c1e72Sjeremylt   @param[in] in    CeedVector containing input state or NULL if there are no
581b11c1e72Sjeremylt                      active inputs
582b11c1e72Sjeremylt   @param[out] out  CeedVector to store result of applying operator (must be
583d7b241e6Sjeremylt                      distinct from @a in) or NULL if there are no active outputs
584d7b241e6Sjeremylt   @param request   Address of CeedRequest for non-blocking completion, else
585d7b241e6Sjeremylt                      CEED_REQUEST_IMMEDIATE
586b11c1e72Sjeremylt 
587b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
588dfdf5a53Sjeremylt 
589dfdf5a53Sjeremylt   @ref Basic
590b11c1e72Sjeremylt **/
591692c2638Sjeremylt int CeedOperatorApply(CeedOperator op, CeedVector in, CeedVector out,
592692c2638Sjeremylt                       CeedRequest *request) {
593d7b241e6Sjeremylt   int ierr;
594d7b241e6Sjeremylt   Ceed ceed = op->ceed;
595*250756a7Sjeremylt   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
596d7b241e6Sjeremylt 
597*250756a7Sjeremylt   if (op->numelements)  {
598*250756a7Sjeremylt     // Standard Operator
599cae8b89aSjeremylt     if (op->Apply) {
600*250756a7Sjeremylt       ierr = op->Apply(op, in, out, request); CeedChk(ierr);
601cae8b89aSjeremylt     } else {
602cae8b89aSjeremylt       // Zero all output vectors
603*250756a7Sjeremylt       CeedQFunction qf = op->qf;
604cae8b89aSjeremylt       for (CeedInt i=0; i<qf->numoutputfields; i++) {
605cae8b89aSjeremylt         CeedVector vec = op->outputfields[i]->vec;
606cae8b89aSjeremylt         if (vec == CEED_VECTOR_ACTIVE)
607cae8b89aSjeremylt           vec = out;
608cae8b89aSjeremylt         if (vec != CEED_VECTOR_NONE) {
609cae8b89aSjeremylt           ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr);
610cae8b89aSjeremylt         }
611cae8b89aSjeremylt       }
612*250756a7Sjeremylt       // Apply
613*250756a7Sjeremylt       ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr);
614*250756a7Sjeremylt     }
615*250756a7Sjeremylt   } else if (op->composite) {
616*250756a7Sjeremylt     // Composite Operator
617*250756a7Sjeremylt     if (op->ApplyComposite) {
618*250756a7Sjeremylt       ierr = op->ApplyComposite(op, in, out, request); CeedChk(ierr);
619*250756a7Sjeremylt     } else {
620*250756a7Sjeremylt       CeedInt numsub;
621*250756a7Sjeremylt       ierr = CeedOperatorGetNumSub(op, &numsub); CeedChk(ierr);
622*250756a7Sjeremylt       CeedOperator *suboperators;
623*250756a7Sjeremylt       ierr = CeedOperatorGetSubList(op, &suboperators); CeedChk(ierr);
624*250756a7Sjeremylt 
625*250756a7Sjeremylt       // Zero all output vectors
626*250756a7Sjeremylt       if (out != CEED_VECTOR_NONE) {
627cae8b89aSjeremylt         ierr = CeedVectorSetValue(out, 0.0); CeedChk(ierr);
628cae8b89aSjeremylt       }
629*250756a7Sjeremylt       for (CeedInt i=0; i<numsub; i++) {
630*250756a7Sjeremylt         for (CeedInt j=0; j<suboperators[i]->qf->numoutputfields; j++) {
631*250756a7Sjeremylt           CeedVector vec = suboperators[i]->outputfields[j]->vec;
632*250756a7Sjeremylt           if (vec != CEED_VECTOR_ACTIVE && vec != CEED_VECTOR_NONE) {
633*250756a7Sjeremylt             ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr);
634*250756a7Sjeremylt           }
635*250756a7Sjeremylt         }
636*250756a7Sjeremylt       }
637*250756a7Sjeremylt       // Apply
638*250756a7Sjeremylt       for (CeedInt i=0; i<op->numsub; i++) {
639*250756a7Sjeremylt         ierr = CeedOperatorApplyAdd(op->suboperators[i], in, out, request);
640cae8b89aSjeremylt         CeedChk(ierr);
641cae8b89aSjeremylt       }
642cae8b89aSjeremylt     }
643*250756a7Sjeremylt   }
644*250756a7Sjeremylt 
645cae8b89aSjeremylt   return 0;
646cae8b89aSjeremylt }
647cae8b89aSjeremylt 
648cae8b89aSjeremylt /**
649cae8b89aSjeremylt   @brief Apply CeedOperator to a vector and add result to output vector
650cae8b89aSjeremylt 
651cae8b89aSjeremylt   This computes the action of the operator on the specified (active) input,
652cae8b89aSjeremylt   yielding its (active) output.  All inputs and outputs must be specified using
653cae8b89aSjeremylt   CeedOperatorSetField().
654cae8b89aSjeremylt 
655cae8b89aSjeremylt   @param op        CeedOperator to apply
656cae8b89aSjeremylt   @param[in] in    CeedVector containing input state or NULL if there are no
657cae8b89aSjeremylt                      active inputs
658cae8b89aSjeremylt   @param[out] out  CeedVector to sum in result of applying operator (must be
659cae8b89aSjeremylt                      distinct from @a in) or NULL if there are no active outputs
660cae8b89aSjeremylt   @param request   Address of CeedRequest for non-blocking completion, else
661cae8b89aSjeremylt                      CEED_REQUEST_IMMEDIATE
662cae8b89aSjeremylt 
663cae8b89aSjeremylt   @return An error code: 0 - success, otherwise - failure
664cae8b89aSjeremylt 
665cae8b89aSjeremylt   @ref Basic
666cae8b89aSjeremylt **/
667cae8b89aSjeremylt int CeedOperatorApplyAdd(CeedOperator op, CeedVector in, CeedVector out,
668cae8b89aSjeremylt                          CeedRequest *request) {
669cae8b89aSjeremylt   int ierr;
670cae8b89aSjeremylt   Ceed ceed = op->ceed;
671*250756a7Sjeremylt   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
672cae8b89aSjeremylt 
673*250756a7Sjeremylt   if (op->numelements)  {
674*250756a7Sjeremylt     // Standard Operator
675*250756a7Sjeremylt     ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr);
676*250756a7Sjeremylt   } else if (op->composite) {
677*250756a7Sjeremylt     // Composite Operator
678*250756a7Sjeremylt     if (op->ApplyAddComposite) {
679*250756a7Sjeremylt       ierr = op->ApplyAddComposite(op, in, out, request); CeedChk(ierr);
680cae8b89aSjeremylt     } else {
681*250756a7Sjeremylt       CeedInt numsub;
682*250756a7Sjeremylt       ierr = CeedOperatorGetNumSub(op, &numsub); CeedChk(ierr);
683*250756a7Sjeremylt       CeedOperator *suboperators;
684*250756a7Sjeremylt       ierr = CeedOperatorGetSubList(op, &suboperators); CeedChk(ierr);
685*250756a7Sjeremylt 
686*250756a7Sjeremylt       for (CeedInt i=0; i<numsub; i++) {
687*250756a7Sjeremylt         ierr = CeedOperatorApplyAdd(suboperators[i], in, out, request);
688cae8b89aSjeremylt         CeedChk(ierr);
6891d7d2407SJeremy L Thompson       }
690*250756a7Sjeremylt     }
691*250756a7Sjeremylt   }
692*250756a7Sjeremylt 
693d7b241e6Sjeremylt   return 0;
694d7b241e6Sjeremylt }
695d7b241e6Sjeremylt 
696d7b241e6Sjeremylt /**
6974ce2993fSjeremylt   @brief Get the Ceed associated with a CeedOperator
6984ce2993fSjeremylt 
6994ce2993fSjeremylt   @param op              CeedOperator
7004ce2993fSjeremylt   @param[out] ceed       Variable to store Ceed
7014ce2993fSjeremylt 
7024ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
7034ce2993fSjeremylt 
70423617272Sjeremylt   @ref Advanced
7054ce2993fSjeremylt **/
7064ce2993fSjeremylt 
7074ce2993fSjeremylt int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) {
7084ce2993fSjeremylt   *ceed = op->ceed;
7094ce2993fSjeremylt   return 0;
7104ce2993fSjeremylt }
7114ce2993fSjeremylt 
7124ce2993fSjeremylt /**
7134ce2993fSjeremylt   @brief Get the number of elements associated with a CeedOperator
7144ce2993fSjeremylt 
7154ce2993fSjeremylt   @param op              CeedOperator
7164ce2993fSjeremylt   @param[out] numelem    Variable to store number of elements
7174ce2993fSjeremylt 
7184ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
7194ce2993fSjeremylt 
72023617272Sjeremylt   @ref Advanced
7214ce2993fSjeremylt **/
7224ce2993fSjeremylt 
7234ce2993fSjeremylt int CeedOperatorGetNumElements(CeedOperator op, CeedInt *numelem) {
72452d6035fSJeremy L Thompson   if (op->composite)
725c042f62fSJeremy L Thompson     // LCOV_EXCL_START
72652d6035fSJeremy L Thompson     return CeedError(op->ceed, 1, "Not defined for composite operator");
727c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
72852d6035fSJeremy L Thompson 
7294ce2993fSjeremylt   *numelem = op->numelements;
7304ce2993fSjeremylt   return 0;
7314ce2993fSjeremylt }
7324ce2993fSjeremylt 
7334ce2993fSjeremylt /**
7344ce2993fSjeremylt   @brief Get the number of quadrature points associated with a CeedOperator
7354ce2993fSjeremylt 
7364ce2993fSjeremylt   @param op              CeedOperator
7374ce2993fSjeremylt   @param[out] numqpts    Variable to store vector number of quadrature points
7384ce2993fSjeremylt 
7394ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
7404ce2993fSjeremylt 
74123617272Sjeremylt   @ref Advanced
7424ce2993fSjeremylt **/
7434ce2993fSjeremylt 
7444ce2993fSjeremylt int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *numqpts) {
74552d6035fSJeremy L Thompson   if (op->composite)
746c042f62fSJeremy L Thompson     // LCOV_EXCL_START
74752d6035fSJeremy L Thompson     return CeedError(op->ceed, 1, "Not defined for composite operator");
748c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
74952d6035fSJeremy L Thompson 
7504ce2993fSjeremylt   *numqpts = op->numqpoints;
7514ce2993fSjeremylt   return 0;
7524ce2993fSjeremylt }
7534ce2993fSjeremylt 
7544ce2993fSjeremylt /**
7554ce2993fSjeremylt   @brief Get the number of arguments associated with a CeedOperator
7564ce2993fSjeremylt 
7574ce2993fSjeremylt   @param op              CeedOperator
7584ce2993fSjeremylt   @param[out] numargs    Variable to store vector number of arguments
7594ce2993fSjeremylt 
7604ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
7614ce2993fSjeremylt 
76223617272Sjeremylt   @ref Advanced
7634ce2993fSjeremylt **/
7644ce2993fSjeremylt 
7654ce2993fSjeremylt int CeedOperatorGetNumArgs(CeedOperator op, CeedInt *numargs) {
76652d6035fSJeremy L Thompson   if (op->composite)
767c042f62fSJeremy L Thompson     // LCOV_EXCL_START
76852d6035fSJeremy L Thompson     return CeedError(op->ceed, 1, "Not defined for composite operators");
769c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
770c042f62fSJeremy L Thompson 
7714ce2993fSjeremylt   *numargs = op->nfields;
7724ce2993fSjeremylt   return 0;
7734ce2993fSjeremylt }
7744ce2993fSjeremylt 
7754ce2993fSjeremylt /**
7764ce2993fSjeremylt   @brief Get the setup status of a CeedOperator
7774ce2993fSjeremylt 
7784ce2993fSjeremylt   @param op             CeedOperator
779288c0443SJeremy L Thompson   @param[out] setupdone Variable to store setup status
7804ce2993fSjeremylt 
7814ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
7824ce2993fSjeremylt 
78323617272Sjeremylt   @ref Advanced
7844ce2993fSjeremylt **/
7854ce2993fSjeremylt 
7864ce2993fSjeremylt int CeedOperatorGetSetupStatus(CeedOperator op, bool *setupdone) {
7874ce2993fSjeremylt   *setupdone = op->setupdone;
7884ce2993fSjeremylt   return 0;
7894ce2993fSjeremylt }
7904ce2993fSjeremylt 
7914ce2993fSjeremylt /**
7924ce2993fSjeremylt   @brief Get the QFunction associated with a CeedOperator
7934ce2993fSjeremylt 
7944ce2993fSjeremylt   @param op              CeedOperator
7958c91a0c9SJeremy L Thompson   @param[out] qf         Variable to store QFunction
7964ce2993fSjeremylt 
7974ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
7984ce2993fSjeremylt 
79923617272Sjeremylt   @ref Advanced
8004ce2993fSjeremylt **/
8014ce2993fSjeremylt 
8024ce2993fSjeremylt int CeedOperatorGetQFunction(CeedOperator op, CeedQFunction *qf) {
80352d6035fSJeremy L Thompson   if (op->composite)
804c042f62fSJeremy L Thompson     // LCOV_EXCL_START
80552d6035fSJeremy L Thompson     return CeedError(op->ceed, 1, "Not defined for composite operator");
806c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
80752d6035fSJeremy L Thompson 
8084ce2993fSjeremylt   *qf = op->qf;
8094ce2993fSjeremylt   return 0;
8104ce2993fSjeremylt }
8114ce2993fSjeremylt 
8124ce2993fSjeremylt /**
81352d6035fSJeremy L Thompson   @brief Get the number of suboperators associated with a CeedOperator
81452d6035fSJeremy L Thompson 
81552d6035fSJeremy L Thompson   @param op              CeedOperator
81652d6035fSJeremy L Thompson   @param[out] numsub     Variable to store number of suboperators
81752d6035fSJeremy L Thompson 
81852d6035fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
81952d6035fSJeremy L Thompson 
82052d6035fSJeremy L Thompson   @ref Advanced
82152d6035fSJeremy L Thompson **/
82252d6035fSJeremy L Thompson 
82352d6035fSJeremy L Thompson int CeedOperatorGetNumSub(CeedOperator op, CeedInt *numsub) {
824c042f62fSJeremy L Thompson   if (!op->composite)
825c042f62fSJeremy L Thompson     // LCOV_EXCL_START
826c042f62fSJeremy L Thompson     return CeedError(op->ceed, 1, "Not a composite operator");
827c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
82852d6035fSJeremy L Thompson 
82952d6035fSJeremy L Thompson   *numsub = op->numsub;
83052d6035fSJeremy L Thompson   return 0;
83152d6035fSJeremy L Thompson }
83252d6035fSJeremy L Thompson 
83352d6035fSJeremy L Thompson /**
83452d6035fSJeremy L Thompson   @brief Get the list of suboperators associated with a CeedOperator
83552d6035fSJeremy L Thompson 
83652d6035fSJeremy L Thompson   @param op                CeedOperator
83752d6035fSJeremy L Thompson   @param[out] suboperators Variable to store list of suboperators
83852d6035fSJeremy L Thompson 
83952d6035fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
84052d6035fSJeremy L Thompson 
84152d6035fSJeremy L Thompson   @ref Advanced
84252d6035fSJeremy L Thompson **/
84352d6035fSJeremy L Thompson 
84452d6035fSJeremy L Thompson int CeedOperatorGetSubList(CeedOperator op, CeedOperator **suboperators) {
845c042f62fSJeremy L Thompson   if (!op->composite)
846c042f62fSJeremy L Thompson     // LCOV_EXCL_START
847c042f62fSJeremy L Thompson     return CeedError(op->ceed, 1, "Not a composite operator");
848c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
84952d6035fSJeremy L Thompson 
85052d6035fSJeremy L Thompson   *suboperators = op->suboperators;
85152d6035fSJeremy L Thompson   return 0;
85252d6035fSJeremy L Thompson }
85352d6035fSJeremy L Thompson 
85452d6035fSJeremy L Thompson /**
855fe2413ffSjeremylt   @brief Set the backend data of a CeedOperator
856fe2413ffSjeremylt 
857fe2413ffSjeremylt   @param[out] op         CeedOperator
858fe2413ffSjeremylt   @param data            Data to set
859fe2413ffSjeremylt 
860fe2413ffSjeremylt   @return An error code: 0 - success, otherwise - failure
861fe2413ffSjeremylt 
862fe2413ffSjeremylt   @ref Advanced
863fe2413ffSjeremylt **/
864fe2413ffSjeremylt 
865fe2413ffSjeremylt int CeedOperatorSetData(CeedOperator op, void **data) {
866fe2413ffSjeremylt   op->data = *data;
867fe2413ffSjeremylt   return 0;
868fe2413ffSjeremylt }
869fe2413ffSjeremylt 
870fe2413ffSjeremylt /**
8714ce2993fSjeremylt   @brief Get the backend data of a CeedOperator
8724ce2993fSjeremylt 
8734ce2993fSjeremylt   @param op              CeedOperator
8744ce2993fSjeremylt   @param[out] data       Variable to store data
8754ce2993fSjeremylt 
8764ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
8774ce2993fSjeremylt 
87823617272Sjeremylt   @ref Advanced
8794ce2993fSjeremylt **/
8804ce2993fSjeremylt 
8814ce2993fSjeremylt int CeedOperatorGetData(CeedOperator op, void **data) {
8824ce2993fSjeremylt   *data = op->data;
8834ce2993fSjeremylt   return 0;
8844ce2993fSjeremylt }
8854ce2993fSjeremylt 
8864ce2993fSjeremylt /**
8874ce2993fSjeremylt   @brief Set the setup flag of a CeedOperator to True
8884ce2993fSjeremylt 
8894ce2993fSjeremylt   @param op              CeedOperator
8904ce2993fSjeremylt 
8914ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
8924ce2993fSjeremylt 
89323617272Sjeremylt   @ref Advanced
8944ce2993fSjeremylt **/
8954ce2993fSjeremylt 
8964ce2993fSjeremylt int CeedOperatorSetSetupDone(CeedOperator op) {
8974ce2993fSjeremylt   op->setupdone = 1;
8984ce2993fSjeremylt   return 0;
8994ce2993fSjeremylt }
9004ce2993fSjeremylt 
9014ce2993fSjeremylt /**
9022ebaca42Sjeremylt   @brief View a field of a CeedOperator
9032ebaca42Sjeremylt 
9042ebaca42Sjeremylt   @param[in] field       Operator field to view
9052ebaca42Sjeremylt   @param[in] fieldnumber Number of field being viewed
9062ebaca42Sjeremylt   @param[in] stream      Stream to view to, e.g., stdout
9072ebaca42Sjeremylt 
9082ebaca42Sjeremylt   @return An error code: 0 - success, otherwise - failure
9092ebaca42Sjeremylt 
9102ebaca42Sjeremylt   @ref Utility
9112ebaca42Sjeremylt **/
9122ebaca42Sjeremylt static int CeedOperatorFieldView(CeedOperatorField field,
9132ebaca42Sjeremylt                                  CeedQFunctionField qffield,
9142da88da5Sjeremylt                                  CeedInt fieldnumber, bool sub, bool in,
9152da88da5Sjeremylt                                  FILE *stream) {
9162ebaca42Sjeremylt   const char *pre = sub ? "  " : "";
9172da88da5Sjeremylt   const char *inout = in ? "Input" : "Output";
9182ebaca42Sjeremylt 
9192da88da5Sjeremylt   fprintf(stream, "%s    %s Field [%d]:\n"
9202da88da5Sjeremylt           "%s      Name: \"%s\"\n"
9212da88da5Sjeremylt           "%s      Lmode: \"%s\"\n",
9222da88da5Sjeremylt           pre, inout, fieldnumber, pre, qffield->fieldname,
9232ebaca42Sjeremylt           pre, CeedTransposeModes[field->lmode]);
9242ebaca42Sjeremylt 
9252ebaca42Sjeremylt   if (field->basis == CEED_BASIS_COLLOCATED)
9262ebaca42Sjeremylt     fprintf(stream, "%s      Collocated basis\n", pre);
9272ebaca42Sjeremylt 
9282ebaca42Sjeremylt   if (field->vec == CEED_VECTOR_ACTIVE)
9292ebaca42Sjeremylt     fprintf(stream, "%s      Active vector\n", pre);
9302ebaca42Sjeremylt   else if (field->vec == CEED_VECTOR_NONE)
9312ebaca42Sjeremylt     fprintf(stream, "%s      No vector\n", pre);
9322ebaca42Sjeremylt 
9332ebaca42Sjeremylt   return 0;
9342ebaca42Sjeremylt }
9352ebaca42Sjeremylt 
9362ebaca42Sjeremylt /**
9372ebaca42Sjeremylt   @brief View a single CeedOperator
9382ebaca42Sjeremylt 
9392ebaca42Sjeremylt   @param[in] op     CeedOperator to view
9402ebaca42Sjeremylt   @param[in] stream Stream to write; typically stdout/stderr or a file
9412ebaca42Sjeremylt 
9422ebaca42Sjeremylt   @return Error code: 0 - success, otherwise - failure
9432ebaca42Sjeremylt 
9442ebaca42Sjeremylt   @ref Utility
9452ebaca42Sjeremylt **/
9462ebaca42Sjeremylt int CeedOperatorSingleView(CeedOperator op, bool sub, FILE *stream) {
9472ebaca42Sjeremylt   int ierr;
9482ebaca42Sjeremylt   const char *pre = sub ? "  " : "";
9492ebaca42Sjeremylt 
9502ebaca42Sjeremylt   CeedInt totalfields;
9512ebaca42Sjeremylt   ierr = CeedOperatorGetNumArgs(op, &totalfields); CeedChk(ierr);
9522da88da5Sjeremylt 
9532ebaca42Sjeremylt   fprintf(stream, "%s  %d Field%s\n", pre, totalfields, totalfields>1 ? "s" : "");
9542ebaca42Sjeremylt 
9552da88da5Sjeremylt   fprintf(stream, "%s  %d Input Field%s:\n", pre, op->qf->numinputfields,
9562ebaca42Sjeremylt           op->qf->numinputfields>1 ? "s" : "");
9572ebaca42Sjeremylt   for (CeedInt i=0; i<op->qf->numinputfields; i++) {
9582ebaca42Sjeremylt     ierr = CeedOperatorFieldView(op->inputfields[i], op->qf->inputfields[i],
9592da88da5Sjeremylt                                  i, sub, 1, stream); CeedChk(ierr);
9602ebaca42Sjeremylt   }
9612ebaca42Sjeremylt 
9622da88da5Sjeremylt   fprintf(stream, "%s  %d Output Field%s:\n", pre, op->qf->numoutputfields,
9632ebaca42Sjeremylt           op->qf->numoutputfields>1 ? "s" : "");
9642ebaca42Sjeremylt   for (CeedInt i=0; i<op->qf->numoutputfields; i++) {
9652ebaca42Sjeremylt     ierr = CeedOperatorFieldView(op->outputfields[i], op->qf->inputfields[i],
9662da88da5Sjeremylt                                  i, sub, 0, stream); CeedChk(ierr);
9672ebaca42Sjeremylt   }
9682ebaca42Sjeremylt 
9692ebaca42Sjeremylt   return 0;
9702ebaca42Sjeremylt }
9712ebaca42Sjeremylt 
9722ebaca42Sjeremylt /**
9732ebaca42Sjeremylt   @brief View a CeedOperator
9742ebaca42Sjeremylt 
9752ebaca42Sjeremylt   @param[in] op     CeedOperator to view
9762ebaca42Sjeremylt   @param[in] stream Stream to write; typically stdout/stderr or a file
9772ebaca42Sjeremylt 
9782ebaca42Sjeremylt   @return Error code: 0 - success, otherwise - failure
9792ebaca42Sjeremylt 
9802ebaca42Sjeremylt   @ref Utility
9812ebaca42Sjeremylt **/
9822ebaca42Sjeremylt int CeedOperatorView(CeedOperator op, FILE *stream) {
9832ebaca42Sjeremylt   int ierr;
9842ebaca42Sjeremylt 
9852ebaca42Sjeremylt   if (op->composite) {
9862ebaca42Sjeremylt     fprintf(stream, "Composite CeedOperator\n");
9872ebaca42Sjeremylt 
9882ebaca42Sjeremylt     for (CeedInt i=0; i<op->numsub; i++) {
9892da88da5Sjeremylt       fprintf(stream, "  SubOperator [%d]:\n", i);
9902ebaca42Sjeremylt       ierr = CeedOperatorSingleView(op->suboperators[i], 1, stream);
9912ebaca42Sjeremylt       CeedChk(ierr);
9922ebaca42Sjeremylt     }
9932ebaca42Sjeremylt   } else {
9942ebaca42Sjeremylt     fprintf(stream, "CeedOperator\n");
9952ebaca42Sjeremylt     ierr = CeedOperatorSingleView(op, 0, stream); CeedChk(ierr);
9962ebaca42Sjeremylt   }
9972ebaca42Sjeremylt 
9982ebaca42Sjeremylt   return 0;
9992ebaca42Sjeremylt }
10002ebaca42Sjeremylt 
10012ebaca42Sjeremylt /**
1002d1bcdac9Sjeremylt   @brief Get the CeedOperatorFields of a CeedOperator
1003d1bcdac9Sjeremylt 
1004d1bcdac9Sjeremylt   @param op                 CeedOperator
1005d1bcdac9Sjeremylt   @param[out] inputfields   Variable to store inputfields
1006d1bcdac9Sjeremylt   @param[out] outputfields  Variable to store outputfields
1007d1bcdac9Sjeremylt 
1008d1bcdac9Sjeremylt   @return An error code: 0 - success, otherwise - failure
1009d1bcdac9Sjeremylt 
1010d1bcdac9Sjeremylt   @ref Advanced
1011d1bcdac9Sjeremylt **/
1012d1bcdac9Sjeremylt 
1013692c2638Sjeremylt int CeedOperatorGetFields(CeedOperator op, CeedOperatorField **inputfields,
1014d1bcdac9Sjeremylt                           CeedOperatorField **outputfields) {
101552d6035fSJeremy L Thompson   if (op->composite)
1016c042f62fSJeremy L Thompson     // LCOV_EXCL_START
101752d6035fSJeremy L Thompson     return CeedError(op->ceed, 1, "Not defined for composite operator");
1018c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
101952d6035fSJeremy L Thompson 
1020d1bcdac9Sjeremylt   if (inputfields) *inputfields = op->inputfields;
1021d1bcdac9Sjeremylt   if (outputfields) *outputfields = op->outputfields;
1022d1bcdac9Sjeremylt   return 0;
1023d1bcdac9Sjeremylt }
1024d1bcdac9Sjeremylt 
1025d1bcdac9Sjeremylt /**
10264dccadb6Sjeremylt   @brief Get the L vector CeedTransposeMode of a CeedOperatorField
10274dccadb6Sjeremylt 
10284dccadb6Sjeremylt   @param opfield         CeedOperatorField
10294dccadb6Sjeremylt   @param[out] lmode      Variable to store CeedTransposeMode
10304dccadb6Sjeremylt 
10314dccadb6Sjeremylt   @return An error code: 0 - success, otherwise - failure
10324dccadb6Sjeremylt 
10334dccadb6Sjeremylt   @ref Advanced
10344dccadb6Sjeremylt **/
10354dccadb6Sjeremylt 
10364dccadb6Sjeremylt int CeedOperatorFieldGetLMode(CeedOperatorField opfield,
10374dccadb6Sjeremylt                               CeedTransposeMode *lmode) {
1038fe2413ffSjeremylt   *lmode = opfield->lmode;
10394dccadb6Sjeremylt   return 0;
10402b8e417aSjeremylt }
10412b8e417aSjeremylt 
10422b8e417aSjeremylt /**
1043d1bcdac9Sjeremylt   @brief Get the CeedElemRestriction of a CeedOperatorField
1044d1bcdac9Sjeremylt 
1045d1bcdac9Sjeremylt   @param opfield         CeedOperatorField
1046d1bcdac9Sjeremylt   @param[out] rstr       Variable to store CeedElemRestriction
1047d1bcdac9Sjeremylt 
1048d1bcdac9Sjeremylt   @return An error code: 0 - success, otherwise - failure
1049d1bcdac9Sjeremylt 
1050d1bcdac9Sjeremylt   @ref Advanced
1051d1bcdac9Sjeremylt **/
1052d1bcdac9Sjeremylt 
1053d1bcdac9Sjeremylt int CeedOperatorFieldGetElemRestriction(CeedOperatorField opfield,
1054d1bcdac9Sjeremylt                                         CeedElemRestriction *rstr) {
1055fe2413ffSjeremylt   *rstr = opfield->Erestrict;
1056d1bcdac9Sjeremylt   return 0;
1057d1bcdac9Sjeremylt }
1058d1bcdac9Sjeremylt 
1059d1bcdac9Sjeremylt /**
1060d1bcdac9Sjeremylt   @brief Get the CeedBasis of a CeedOperatorField
1061d1bcdac9Sjeremylt 
1062d1bcdac9Sjeremylt   @param opfield         CeedOperatorField
1063d1bcdac9Sjeremylt   @param[out] basis      Variable to store CeedBasis
1064d1bcdac9Sjeremylt 
1065d1bcdac9Sjeremylt   @return An error code: 0 - success, otherwise - failure
1066d1bcdac9Sjeremylt 
1067d1bcdac9Sjeremylt   @ref Advanced
1068d1bcdac9Sjeremylt **/
1069d1bcdac9Sjeremylt 
1070692c2638Sjeremylt int CeedOperatorFieldGetBasis(CeedOperatorField opfield, CeedBasis *basis) {
1071fe2413ffSjeremylt   *basis = opfield->basis;
1072d1bcdac9Sjeremylt   return 0;
1073d1bcdac9Sjeremylt }
1074d1bcdac9Sjeremylt 
1075d1bcdac9Sjeremylt /**
1076d1bcdac9Sjeremylt   @brief Get the CeedVector of a CeedOperatorField
1077d1bcdac9Sjeremylt 
1078d1bcdac9Sjeremylt   @param opfield         CeedOperatorField
1079d1bcdac9Sjeremylt   @param[out] vec        Variable to store CeedVector
1080d1bcdac9Sjeremylt 
1081d1bcdac9Sjeremylt   @return An error code: 0 - success, otherwise - failure
1082d1bcdac9Sjeremylt 
1083d1bcdac9Sjeremylt   @ref Advanced
1084d1bcdac9Sjeremylt **/
1085d1bcdac9Sjeremylt 
1086692c2638Sjeremylt int CeedOperatorFieldGetVector(CeedOperatorField opfield, CeedVector *vec) {
1087fe2413ffSjeremylt   *vec = opfield->vec;
1088d1bcdac9Sjeremylt   return 0;
1089d1bcdac9Sjeremylt }
1090d1bcdac9Sjeremylt 
1091d1bcdac9Sjeremylt /**
1092b11c1e72Sjeremylt   @brief Destroy a CeedOperator
1093d7b241e6Sjeremylt 
1094d7b241e6Sjeremylt   @param op CeedOperator to destroy
1095b11c1e72Sjeremylt 
1096b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
1097dfdf5a53Sjeremylt 
1098dfdf5a53Sjeremylt   @ref Basic
1099b11c1e72Sjeremylt **/
1100d7b241e6Sjeremylt int CeedOperatorDestroy(CeedOperator *op) {
1101d7b241e6Sjeremylt   int ierr;
1102d7b241e6Sjeremylt 
1103d7b241e6Sjeremylt   if (!*op || --(*op)->refcount > 0) return 0;
1104d7b241e6Sjeremylt   if ((*op)->Destroy) {
1105d7b241e6Sjeremylt     ierr = (*op)->Destroy(*op); CeedChk(ierr);
1106d7b241e6Sjeremylt   }
1107fe2413ffSjeremylt   ierr = CeedDestroy(&(*op)->ceed); CeedChk(ierr);
1108fe2413ffSjeremylt   // Free fields
11091d102b48SJeremy L Thompson   for (int i=0; i<(*op)->nfields; i++)
111052d6035fSJeremy L Thompson     if ((*op)->inputfields[i]) {
111171352a93Sjeremylt       ierr = CeedElemRestrictionDestroy(&(*op)->inputfields[i]->Erestrict);
111271352a93Sjeremylt       CeedChk(ierr);
111371352a93Sjeremylt       if ((*op)->inputfields[i]->basis != CEED_BASIS_COLLOCATED) {
111471352a93Sjeremylt         ierr = CeedBasisDestroy(&(*op)->inputfields[i]->basis); CeedChk(ierr);
111571352a93Sjeremylt       }
111671352a93Sjeremylt       if ((*op)->inputfields[i]->vec != CEED_VECTOR_ACTIVE &&
111771352a93Sjeremylt           (*op)->inputfields[i]->vec != CEED_VECTOR_NONE ) {
111871352a93Sjeremylt         ierr = CeedVectorDestroy(&(*op)->inputfields[i]->vec); CeedChk(ierr);
111971352a93Sjeremylt       }
1120fe2413ffSjeremylt       ierr = CeedFree(&(*op)->inputfields[i]); CeedChk(ierr);
1121fe2413ffSjeremylt     }
11221d102b48SJeremy L Thompson   for (int i=0; i<(*op)->nfields; i++)
1123d0eb30a5Sjeremylt     if ((*op)->outputfields[i]) {
112471352a93Sjeremylt       ierr = CeedElemRestrictionDestroy(&(*op)->outputfields[i]->Erestrict);
112571352a93Sjeremylt       CeedChk(ierr);
112671352a93Sjeremylt       if ((*op)->outputfields[i]->basis != CEED_BASIS_COLLOCATED) {
112771352a93Sjeremylt         ierr = CeedBasisDestroy(&(*op)->outputfields[i]->basis); CeedChk(ierr);
112871352a93Sjeremylt       }
112971352a93Sjeremylt       if ((*op)->outputfields[i]->vec != CEED_VECTOR_ACTIVE &&
113071352a93Sjeremylt           (*op)->outputfields[i]->vec != CEED_VECTOR_NONE ) {
113171352a93Sjeremylt         ierr = CeedVectorDestroy(&(*op)->outputfields[i]->vec); CeedChk(ierr);
113271352a93Sjeremylt       }
1133fe2413ffSjeremylt       ierr = CeedFree(&(*op)->outputfields[i]); CeedChk(ierr);
1134fe2413ffSjeremylt     }
113552d6035fSJeremy L Thompson   // Destroy suboperators
11361d102b48SJeremy L Thompson   for (int i=0; i<(*op)->numsub; i++)
113752d6035fSJeremy L Thompson     if ((*op)->suboperators[i]) {
113852d6035fSJeremy L Thompson       ierr = CeedOperatorDestroy(&(*op)->suboperators[i]); CeedChk(ierr);
113952d6035fSJeremy L Thompson     }
1140d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->qf); CeedChk(ierr);
1141d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->dqf); CeedChk(ierr);
1142d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->dqfT); CeedChk(ierr);
1143fe2413ffSjeremylt 
11445107b09fSJeremy L Thompson   // Destroy fallback
11455107b09fSJeremy L Thompson   if ((*op)->opfallback) {
11465107b09fSJeremy L Thompson     ierr = (*op)->qffallback->Destroy((*op)->qffallback); CeedChk(ierr);
11475107b09fSJeremy L Thompson     ierr = CeedFree(&(*op)->qffallback); CeedChk(ierr);
11485107b09fSJeremy L Thompson     ierr = (*op)->opfallback->Destroy((*op)->opfallback); CeedChk(ierr);
11495107b09fSJeremy L Thompson     ierr = CeedFree(&(*op)->opfallback); CeedChk(ierr);
11505107b09fSJeremy L Thompson   }
11515107b09fSJeremy L Thompson 
1152fe2413ffSjeremylt   ierr = CeedFree(&(*op)->inputfields); CeedChk(ierr);
1153fe2413ffSjeremylt   ierr = CeedFree(&(*op)->outputfields); CeedChk(ierr);
115452d6035fSJeremy L Thompson   ierr = CeedFree(&(*op)->suboperators); CeedChk(ierr);
1155d7b241e6Sjeremylt   ierr = CeedFree(op); CeedChk(ierr);
1156d7b241e6Sjeremylt   return 0;
1157d7b241e6Sjeremylt }
1158d7b241e6Sjeremylt 
1159d7b241e6Sjeremylt /// @}
1160