xref: /libCEED/rust/libceed-sys/c-src/interface/ceed-operator.c (revision 7172caad75bd388183c6aa46b2472fa01d320a20)
1d7b241e6Sjeremylt // Copyright (c) 2017, Lawrence Livermore National Security, LLC. Produced at
2d7b241e6Sjeremylt // the Lawrence Livermore National Laboratory. LLNL-CODE-734707. All Rights
3d7b241e6Sjeremylt // reserved. See files LICENSE and NOTICE for details.
4d7b241e6Sjeremylt //
5d7b241e6Sjeremylt // This file is part of CEED, a collection of benchmarks, miniapps, software
6d7b241e6Sjeremylt // libraries and APIs for efficient high-order finite element and spectral
7d7b241e6Sjeremylt // element discretizations for exascale applications. For more information and
8d7b241e6Sjeremylt // source code availability see http://github.com/ceed.
9d7b241e6Sjeremylt //
10d7b241e6Sjeremylt // The CEED research is supported by the Exascale Computing Project 17-SC-20-SC,
11d7b241e6Sjeremylt // a collaborative effort of two U.S. Department of Energy organizations (Office
12d7b241e6Sjeremylt // of Science and the National Nuclear Security Administration) responsible for
13d7b241e6Sjeremylt // the planning and preparation of a capable exascale ecosystem, including
14d7b241e6Sjeremylt // software, applications, hardware, advanced system engineering and early
15d7b241e6Sjeremylt // testbed platforms, in support of the nation's exascale computing imperative.
16d7b241e6Sjeremylt 
17d7b241e6Sjeremylt #include <ceed-impl.h>
18d863ab9bSjeremylt #include <ceed-backend.h>
19d7b241e6Sjeremylt #include <string.h>
203bd813ffSjeremylt #include <math.h>
21d7b241e6Sjeremylt 
22dfdf5a53Sjeremylt /// @file
23dfdf5a53Sjeremylt /// Implementation of public CeedOperator interfaces
24dfdf5a53Sjeremylt ///
25dfdf5a53Sjeremylt /// @addtogroup CeedOperator
26dfdf5a53Sjeremylt ///   @{
27d7b241e6Sjeremylt 
28d7b241e6Sjeremylt /**
290219ea01SJeremy L Thompson   @brief Create a CeedOperator and associate a CeedQFunction. A CeedBasis and
300219ea01SJeremy L Thompson            CeedElemRestriction can be associated with CeedQFunction fields with
310219ea01SJeremy L Thompson            \ref CeedOperatorSetField.
32d7b241e6Sjeremylt 
33b11c1e72Sjeremylt   @param ceed    A Ceed object where the CeedOperator will be created
34d7b241e6Sjeremylt   @param qf      QFunction defining the action of the operator at quadrature points
3534138859Sjeremylt   @param dqf     QFunction defining the action of the Jacobian of @a qf (or
3634138859Sjeremylt                    CEED_QFUNCTION_NONE)
37d7b241e6Sjeremylt   @param dqfT    QFunction defining the action of the transpose of the Jacobian
3834138859Sjeremylt                    of @a qf (or CEED_QFUNCTION_NONE)
39b11c1e72Sjeremylt   @param[out] op Address of the variable where the newly created
40b11c1e72Sjeremylt                      CeedOperator will be stored
41b11c1e72Sjeremylt 
42b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
43dfdf5a53Sjeremylt 
44dfdf5a53Sjeremylt   @ref Basic
45d7b241e6Sjeremylt  */
46d7b241e6Sjeremylt int CeedOperatorCreate(Ceed ceed, CeedQFunction qf, CeedQFunction dqf,
47d7b241e6Sjeremylt                        CeedQFunction dqfT, CeedOperator *op) {
48d7b241e6Sjeremylt   int ierr;
49d7b241e6Sjeremylt 
505fe0d4faSjeremylt   if (!ceed->OperatorCreate) {
515fe0d4faSjeremylt     Ceed delegate;
52aefd8378Sjeremylt     ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr);
535fe0d4faSjeremylt 
545fe0d4faSjeremylt     if (!delegate)
55c042f62fSJeremy L Thompson       // LCOV_EXCL_START
565fe0d4faSjeremylt       return CeedError(ceed, 1, "Backend does not support OperatorCreate");
57c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
585fe0d4faSjeremylt 
595fe0d4faSjeremylt     ierr = CeedOperatorCreate(delegate, qf, dqf, dqfT, op); CeedChk(ierr);
605fe0d4faSjeremylt     return 0;
615fe0d4faSjeremylt   }
625fe0d4faSjeremylt 
63d7b241e6Sjeremylt   ierr = CeedCalloc(1, op); CeedChk(ierr);
64d7b241e6Sjeremylt   (*op)->ceed = ceed;
65d7b241e6Sjeremylt   ceed->refcount++;
66d7b241e6Sjeremylt   (*op)->refcount = 1;
67442e7f0bSjeremylt   if (qf == CEED_QFUNCTION_NONE)
68442e7f0bSjeremylt     // LCOV_EXCL_START
69442e7f0bSjeremylt     return CeedError(ceed, 1, "Operator must have a valid QFunction.");
70442e7f0bSjeremylt   // LCOV_EXCL_STOP
71d7b241e6Sjeremylt   (*op)->qf = qf;
72d7b241e6Sjeremylt   qf->refcount++;
73442e7f0bSjeremylt   if (dqf && dqf != CEED_QFUNCTION_NONE) {
74d7b241e6Sjeremylt     (*op)->dqf = dqf;
75442e7f0bSjeremylt     dqf->refcount++;
76442e7f0bSjeremylt   }
77442e7f0bSjeremylt   if (dqfT && dqfT != CEED_QFUNCTION_NONE) {
78d7b241e6Sjeremylt     (*op)->dqfT = dqfT;
79442e7f0bSjeremylt     dqfT->refcount++;
80442e7f0bSjeremylt   }
81fe2413ffSjeremylt   ierr = CeedCalloc(16, &(*op)->inputfields); CeedChk(ierr);
82fe2413ffSjeremylt   ierr = CeedCalloc(16, &(*op)->outputfields); CeedChk(ierr);
83d7b241e6Sjeremylt   ierr = ceed->OperatorCreate(*op); CeedChk(ierr);
84d7b241e6Sjeremylt   return 0;
85d7b241e6Sjeremylt }
86d7b241e6Sjeremylt 
87d7b241e6Sjeremylt /**
8852d6035fSJeremy L Thompson   @brief Create an operator that composes the action of several operators
8952d6035fSJeremy L Thompson 
9052d6035fSJeremy L Thompson   @param ceed    A Ceed object where the CeedOperator will be created
9152d6035fSJeremy L Thompson   @param[out] op Address of the variable where the newly created
9252d6035fSJeremy L Thompson                      Composite CeedOperator will be stored
9352d6035fSJeremy L Thompson 
9452d6035fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
9552d6035fSJeremy L Thompson 
9652d6035fSJeremy L Thompson   @ref Basic
9752d6035fSJeremy L Thompson  */
9852d6035fSJeremy L Thompson int CeedCompositeOperatorCreate(Ceed ceed, CeedOperator *op) {
9952d6035fSJeremy L Thompson   int ierr;
10052d6035fSJeremy L Thompson 
10152d6035fSJeremy L Thompson   if (!ceed->CompositeOperatorCreate) {
10252d6035fSJeremy L Thompson     Ceed delegate;
103aefd8378Sjeremylt     ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr);
10452d6035fSJeremy L Thompson 
105250756a7Sjeremylt     if (delegate) {
10652d6035fSJeremy L Thompson       ierr = CeedCompositeOperatorCreate(delegate, op); CeedChk(ierr);
10752d6035fSJeremy L Thompson       return 0;
10852d6035fSJeremy L Thompson     }
109250756a7Sjeremylt   }
11052d6035fSJeremy L Thompson 
11152d6035fSJeremy L Thompson   ierr = CeedCalloc(1, op); CeedChk(ierr);
11252d6035fSJeremy L Thompson   (*op)->ceed = ceed;
11352d6035fSJeremy L Thompson   ceed->refcount++;
11452d6035fSJeremy L Thompson   (*op)->composite = true;
11552d6035fSJeremy L Thompson   ierr = CeedCalloc(16, &(*op)->suboperators); CeedChk(ierr);
116250756a7Sjeremylt 
117250756a7Sjeremylt   if (ceed->CompositeOperatorCreate) {
11852d6035fSJeremy L Thompson     ierr = ceed->CompositeOperatorCreate(*op); CeedChk(ierr);
119250756a7Sjeremylt   }
12052d6035fSJeremy L Thompson   return 0;
12152d6035fSJeremy L Thompson }
12252d6035fSJeremy L Thompson 
12352d6035fSJeremy L Thompson /**
124b11c1e72Sjeremylt   @brief Provide a field to a CeedOperator for use by its CeedQFunction
125d7b241e6Sjeremylt 
126d7b241e6Sjeremylt   This function is used to specify both active and passive fields to a
127d7b241e6Sjeremylt   CeedOperator.  For passive fields, a vector @arg v must be provided.  Passive
128d7b241e6Sjeremylt   fields can inputs or outputs (updated in-place when operator is applied).
129d7b241e6Sjeremylt 
130d7b241e6Sjeremylt   Active fields must be specified using this function, but their data (in a
131d7b241e6Sjeremylt   CeedVector) is passed in CeedOperatorApply().  There can be at most one active
132d7b241e6Sjeremylt   input and at most one active output.
133d7b241e6Sjeremylt 
1348c91a0c9SJeremy L Thompson   @param op         CeedOperator on which to provide the field
1358795c945Sjeremylt   @param fieldname  Name of the field (to be matched with the name used by
1368795c945Sjeremylt                       CeedQFunction)
137b11c1e72Sjeremylt   @param r          CeedElemRestriction
138b0e29e78Sjeremylt   @param lmode      CeedTransposeMode which specifies the ordering of the
139b0e29e78Sjeremylt                       components of the l-vector used by this CeedOperatorField,
140b0e29e78Sjeremylt                       CEED_NOTRANSPOSE indicates the component is the
141b0e29e78Sjeremylt                       outermost index and CEED_TRANSPOSE indicates the component
142b0e29e78Sjeremylt                       is the innermost index in ordering of the l-vector
143783c99b3SValeria Barra   @param b          CeedBasis in which the field resides or CEED_BASIS_COLLOCATED
144b11c1e72Sjeremylt                       if collocated with quadrature points
145b11c1e72Sjeremylt   @param v          CeedVector to be used by CeedOperator or CEED_VECTOR_ACTIVE
146b11c1e72Sjeremylt                       if field is active or CEED_VECTOR_NONE if using
1478c91a0c9SJeremy L Thompson                       CEED_EVAL_WEIGHT in the QFunction
148b11c1e72Sjeremylt 
149b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
150dfdf5a53Sjeremylt 
151dfdf5a53Sjeremylt   @ref Basic
152b11c1e72Sjeremylt **/
153d7b241e6Sjeremylt int CeedOperatorSetField(CeedOperator op, const char *fieldname,
1544dccadb6Sjeremylt                          CeedElemRestriction r, CeedTransposeMode lmode,
1554dccadb6Sjeremylt                          CeedBasis b, CeedVector v) {
156d7b241e6Sjeremylt   int ierr;
15752d6035fSJeremy L Thompson   if (op->composite)
158c042f62fSJeremy L Thompson     // LCOV_EXCL_START
15952d6035fSJeremy L Thompson     return CeedError(op->ceed, 1, "Cannot add field to composite operator.");
160c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
1618b067b84SJed Brown   if (!r)
162c042f62fSJeremy L Thompson     // LCOV_EXCL_START
163c042f62fSJeremy L Thompson     return CeedError(op->ceed, 1,
164c042f62fSJeremy L Thompson                      "ElemRestriction r for field \"%s\" must be non-NULL.",
165c042f62fSJeremy L Thompson                      fieldname);
166c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
1678b067b84SJed Brown   if (!b)
168c042f62fSJeremy L Thompson     // LCOV_EXCL_START
169c042f62fSJeremy L Thompson     return CeedError(op->ceed, 1, "Basis b for field \"%s\" must be non-NULL.",
170c042f62fSJeremy L Thompson                      fieldname);
171c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
1728b067b84SJed Brown   if (!v)
173c042f62fSJeremy L Thompson     // LCOV_EXCL_START
174c042f62fSJeremy L Thompson     return CeedError(op->ceed, 1, "Vector v for field \"%s\" must be non-NULL.",
175c042f62fSJeremy L Thompson                      fieldname);
176c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
17752d6035fSJeremy L Thompson 
178d7b241e6Sjeremylt   CeedInt numelements;
179d7b241e6Sjeremylt   ierr = CeedElemRestrictionGetNumElements(r, &numelements); CeedChk(ierr);
1802cb0afc5Sjeremylt   if (op->hasrestriction && op->numelements != numelements)
181c042f62fSJeremy L Thompson     // LCOV_EXCL_START
182d7b241e6Sjeremylt     return CeedError(op->ceed, 1,
1831d102b48SJeremy L Thompson                      "ElemRestriction with %d elements incompatible with prior "
1841d102b48SJeremy L Thompson                      "%d elements", numelements, op->numelements);
185c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
186d7b241e6Sjeremylt   op->numelements = numelements;
1872cb0afc5Sjeremylt   op->hasrestriction = true; // Restriction set, but numelements may be 0
188d7b241e6Sjeremylt 
189783c99b3SValeria Barra   if (b != CEED_BASIS_COLLOCATED) {
190d7b241e6Sjeremylt     CeedInt numqpoints;
191d7b241e6Sjeremylt     ierr = CeedBasisGetNumQuadraturePoints(b, &numqpoints); CeedChk(ierr);
192d7b241e6Sjeremylt     if (op->numqpoints && op->numqpoints != numqpoints)
193c042f62fSJeremy L Thompson       // LCOV_EXCL_START
1941d102b48SJeremy L Thompson       return CeedError(op->ceed, 1, "Basis with %d quadrature points "
1951d102b48SJeremy L Thompson                        "incompatible with prior %d points", numqpoints,
1961d102b48SJeremy L Thompson                        op->numqpoints);
197c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
198d7b241e6Sjeremylt     op->numqpoints = numqpoints;
199d7b241e6Sjeremylt   }
200d1bcdac9Sjeremylt   CeedOperatorField *ofield;
201d7b241e6Sjeremylt   for (CeedInt i=0; i<op->qf->numinputfields; i++) {
202fe2413ffSjeremylt     if (!strcmp(fieldname, (*op->qf->inputfields[i]).fieldname)) {
203d7b241e6Sjeremylt       ofield = &op->inputfields[i];
204d7b241e6Sjeremylt       goto found;
205d7b241e6Sjeremylt     }
206d7b241e6Sjeremylt   }
207d7b241e6Sjeremylt   for (CeedInt i=0; i<op->qf->numoutputfields; i++) {
208fe2413ffSjeremylt     if (!strcmp(fieldname, (*op->qf->outputfields[i]).fieldname)) {
209d7b241e6Sjeremylt       ofield = &op->outputfields[i];
210d7b241e6Sjeremylt       goto found;
211d7b241e6Sjeremylt     }
212d7b241e6Sjeremylt   }
213c042f62fSJeremy L Thompson   // LCOV_EXCL_START
214d7b241e6Sjeremylt   return CeedError(op->ceed, 1, "QFunction has no knowledge of field '%s'",
215d7b241e6Sjeremylt                    fieldname);
216c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
217d7b241e6Sjeremylt found:
218fe2413ffSjeremylt   ierr = CeedCalloc(1, ofield); CeedChk(ierr);
219fe2413ffSjeremylt   (*ofield)->Erestrict = r;
22071352a93Sjeremylt   r->refcount += 1;
221fe2413ffSjeremylt   (*ofield)->lmode = lmode;
222fe2413ffSjeremylt   (*ofield)->basis = b;
22371352a93Sjeremylt   if (b != CEED_BASIS_COLLOCATED)
22471352a93Sjeremylt     b->refcount += 1;
225fe2413ffSjeremylt   (*ofield)->vec = v;
22671352a93Sjeremylt   if (v != CEED_VECTOR_ACTIVE && v != CEED_VECTOR_NONE)
22771352a93Sjeremylt     v->refcount += 1;
228d7b241e6Sjeremylt   op->nfields += 1;
229d7b241e6Sjeremylt   return 0;
230d7b241e6Sjeremylt }
231d7b241e6Sjeremylt 
232d7b241e6Sjeremylt /**
23352d6035fSJeremy L Thompson   @brief Add a sub-operator to a composite CeedOperator
234288c0443SJeremy L Thompson 
23534138859Sjeremylt   @param[out] compositeop Composite CeedOperator
23634138859Sjeremylt   @param      subop       Sub-operator CeedOperator
23752d6035fSJeremy L Thompson 
23852d6035fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
23952d6035fSJeremy L Thompson 
24052d6035fSJeremy L Thompson   @ref Basic
24152d6035fSJeremy L Thompson  */
242692c2638Sjeremylt int CeedCompositeOperatorAddSub(CeedOperator compositeop, CeedOperator subop) {
24352d6035fSJeremy L Thompson   if (!compositeop->composite)
244c042f62fSJeremy L Thompson     // LCOV_EXCL_START
2451d102b48SJeremy L Thompson     return CeedError(compositeop->ceed, 1, "CeedOperator is not a composite "
2461d102b48SJeremy L Thompson                      "operator");
247c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
24852d6035fSJeremy L Thompson 
24952d6035fSJeremy L Thompson   if (compositeop->numsub == CEED_COMPOSITE_MAX)
250c042f62fSJeremy L Thompson     // LCOV_EXCL_START
2511d102b48SJeremy L Thompson     return CeedError(compositeop->ceed, 1, "Cannot add additional suboperators");
252c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
25352d6035fSJeremy L Thompson 
25452d6035fSJeremy L Thompson   compositeop->suboperators[compositeop->numsub] = subop;
25552d6035fSJeremy L Thompson   subop->refcount++;
25652d6035fSJeremy L Thompson   compositeop->numsub++;
25752d6035fSJeremy L Thompson   return 0;
25852d6035fSJeremy L Thompson }
25952d6035fSJeremy L Thompson 
26052d6035fSJeremy L Thompson /**
2615107b09fSJeremy L Thompson   @brief Duplicate a CeedOperator with a reference Ceed to fallback for advanced
2625107b09fSJeremy L Thompson            CeedOperator functionality
2635107b09fSJeremy L Thompson 
2645107b09fSJeremy L Thompson   @param op           CeedOperator to create fallback for
2655107b09fSJeremy L Thompson 
2665107b09fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
2675107b09fSJeremy L Thompson 
2685107b09fSJeremy L Thompson   @ref Developer
2695107b09fSJeremy L Thompson **/
2705107b09fSJeremy L Thompson int CeedOperatorCreateFallback(CeedOperator op) {
2715107b09fSJeremy L Thompson   int ierr;
2725107b09fSJeremy L Thompson 
2735107b09fSJeremy L Thompson   // Fallback Ceed
2745107b09fSJeremy L Thompson   const char *resource, *fallbackresource;
2755107b09fSJeremy L Thompson   ierr = CeedGetResource(op->ceed, &resource); CeedChk(ierr);
2765107b09fSJeremy L Thompson   ierr = CeedGetOperatorFallbackResource(op->ceed, &fallbackresource);
2775107b09fSJeremy L Thompson   CeedChk(ierr);
2785107b09fSJeremy L Thompson   if (!strcmp(resource, fallbackresource))
2795107b09fSJeremy L Thompson     // LCOV_EXCL_START
2805107b09fSJeremy L Thompson     return CeedError(op->ceed, 1, "Backend %s cannot create an operator"
2815107b09fSJeremy L Thompson                      "fallback to resource %s", resource, fallbackresource);
2825107b09fSJeremy L Thompson   // LCOV_EXCL_STOP
2835107b09fSJeremy L Thompson 
2845107b09fSJeremy L Thompson   Ceed ceedref;
2855107b09fSJeremy L Thompson   ierr = CeedInit(fallbackresource, &ceedref); CeedChk(ierr);
2865107b09fSJeremy L Thompson   ceedref->opfallbackparent = op->ceed;
2875107b09fSJeremy L Thompson   op->ceed->opfallbackceed = ceedref;
2885107b09fSJeremy L Thompson 
2895107b09fSJeremy L Thompson   // Clone Op
2905107b09fSJeremy L Thompson   CeedOperator opref;
2915107b09fSJeremy L Thompson   ierr = CeedCalloc(1, &opref); CeedChk(ierr);
2925107b09fSJeremy L Thompson   memcpy(opref, op, sizeof(*opref)); CeedChk(ierr);
2935107b09fSJeremy L Thompson   opref->data = NULL;
2945107b09fSJeremy L Thompson   opref->setupdone = 0;
2955107b09fSJeremy L Thompson   opref->ceed = ceedref;
2965107b09fSJeremy L Thompson   ierr = ceedref->OperatorCreate(opref); CeedChk(ierr);
2975107b09fSJeremy L Thompson   op->opfallback = opref;
2985107b09fSJeremy L Thompson 
2995107b09fSJeremy L Thompson   // Clone QF
3005107b09fSJeremy L Thompson   CeedQFunction qfref;
3015107b09fSJeremy L Thompson   ierr = CeedCalloc(1, &qfref); CeedChk(ierr);
3025107b09fSJeremy L Thompson   memcpy(qfref, (op->qf), sizeof(*qfref)); CeedChk(ierr);
3035107b09fSJeremy L Thompson   qfref->data = NULL;
3045107b09fSJeremy L Thompson   qfref->ceed = ceedref;
3055107b09fSJeremy L Thompson   ierr = ceedref->QFunctionCreate(qfref); CeedChk(ierr);
3065107b09fSJeremy L Thompson   opref->qf = qfref;
3075107b09fSJeremy L Thompson   op->qffallback = qfref;
3085107b09fSJeremy L Thompson 
3095107b09fSJeremy L Thompson   return 0;
3105107b09fSJeremy L Thompson }
3115107b09fSJeremy L Thompson 
3125107b09fSJeremy L Thompson /**
313250756a7Sjeremylt   @brief Check if a CeedOperator is ready to be used.
314250756a7Sjeremylt 
315250756a7Sjeremylt   @param[in] ceed Ceed object for error handling
316250756a7Sjeremylt   @param[in] op   CeedOperator to check
317250756a7Sjeremylt 
318250756a7Sjeremylt   @return An error code: 0 - success, otherwise - failure
319250756a7Sjeremylt 
320250756a7Sjeremylt   @ref Basic
321250756a7Sjeremylt **/
322250756a7Sjeremylt static int CeedOperatorCheckReady(Ceed ceed, CeedOperator op) {
323250756a7Sjeremylt   CeedQFunction qf = op->qf;
324250756a7Sjeremylt 
325250756a7Sjeremylt   if (op->composite) {
326250756a7Sjeremylt     if (!op->numsub)
327250756a7Sjeremylt       // LCOV_EXCL_START
328250756a7Sjeremylt       return CeedError(ceed, 1, "No suboperators set");
329250756a7Sjeremylt     // LCOV_EXCL_STOP
330250756a7Sjeremylt   } else {
331250756a7Sjeremylt     if (op->nfields == 0)
332250756a7Sjeremylt       // LCOV_EXCL_START
333250756a7Sjeremylt       return CeedError(ceed, 1, "No operator fields set");
334250756a7Sjeremylt     // LCOV_EXCL_STOP
335250756a7Sjeremylt     if (op->nfields < qf->numinputfields + qf->numoutputfields)
336250756a7Sjeremylt       // LCOV_EXCL_START
337250756a7Sjeremylt       return CeedError(ceed, 1, "Not all operator fields set");
338250756a7Sjeremylt     // LCOV_EXCL_STOP
339250756a7Sjeremylt     if (!op->hasrestriction)
340250756a7Sjeremylt       // LCOV_EXCL_START
341250756a7Sjeremylt       return CeedError(ceed, 1,"At least one restriction required");
342250756a7Sjeremylt     // LCOV_EXCL_STOP
343250756a7Sjeremylt     if (op->numqpoints == 0)
344250756a7Sjeremylt       // LCOV_EXCL_START
345250756a7Sjeremylt       return CeedError(ceed, 1,"At least one non-collocated basis required");
346250756a7Sjeremylt     // LCOV_EXCL_STOP
347250756a7Sjeremylt   }
348250756a7Sjeremylt 
349250756a7Sjeremylt   return 0;
350250756a7Sjeremylt }
351250756a7Sjeremylt 
352250756a7Sjeremylt /**
3531d102b48SJeremy L Thompson   @brief Assemble a linear CeedQFunction associated with a CeedOperator
3541d102b48SJeremy L Thompson 
3551d102b48SJeremy L Thompson   This returns a CeedVector containing a matrix at each quadrature point
3561d102b48SJeremy L Thompson     providing the action of the CeedQFunction associated with the CeedOperator.
3571d102b48SJeremy L Thompson     The vector 'assembled' is of shape
3581d102b48SJeremy L Thompson       [num_elements, num_input_fields, num_output_fields, num_quad_points]
3591d102b48SJeremy L Thompson     and contains column-major matrices representing the action of the
3601d102b48SJeremy L Thompson     CeedQFunction for a corresponding quadrature point on an element. Inputs and
3611d102b48SJeremy L Thompson     outputs are in the order provided by the user when adding CeedOperator fields.
3621d102b48SJeremy L Thompson     For example, a QFunction with inputs 'u' and 'gradu' and outputs 'gradv' and
3631d102b48SJeremy L Thompson     'v', provided in that order, would result in an assembled QFunction that
3641d102b48SJeremy L Thompson     consists of (1 + dim) x (dim + 1) matrices at each quadrature point acting
3651d102b48SJeremy L Thompson     on the input [u, du_0, du_1] and producing the output [dv_0, dv_1, v].
3661d102b48SJeremy L Thompson 
3671d102b48SJeremy L Thompson   @param op             CeedOperator to assemble CeedQFunction
3681d102b48SJeremy L Thompson   @param[out] assembled CeedVector to store assembled CeedQFunction at
3691d102b48SJeremy L Thompson                           quadrature points
3701d102b48SJeremy L Thompson   @param[out] rstr      CeedElemRestriction for CeedVector containing assembled
3711d102b48SJeremy L Thompson                           CeedQFunction
3721d102b48SJeremy L Thompson   @param request        Address of CeedRequest for non-blocking completion, else
3731d102b48SJeremy L Thompson                           CEED_REQUEST_IMMEDIATE
3741d102b48SJeremy L Thompson 
3751d102b48SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
3761d102b48SJeremy L Thompson 
377b7ec98d8SJeremy L Thompson   @ref Basic
3781d102b48SJeremy L Thompson **/
3791d102b48SJeremy L Thompson int CeedOperatorAssembleLinearQFunction(CeedOperator op, CeedVector *assembled,
3807f823360Sjeremylt                                         CeedElemRestriction *rstr,
3817f823360Sjeremylt                                         CeedRequest *request) {
3821d102b48SJeremy L Thompson   int ierr;
3831d102b48SJeremy L Thompson   Ceed ceed = op->ceed;
384250756a7Sjeremylt   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
3851d102b48SJeremy L Thompson 
386*7172caadSjeremylt   // Backend version
3875107b09fSJeremy L Thompson   if (op->AssembleLinearQFunction) {
3881d102b48SJeremy L Thompson     ierr = op->AssembleLinearQFunction(op, assembled, rstr, request);
3891d102b48SJeremy L Thompson     CeedChk(ierr);
3905107b09fSJeremy L Thompson   } else {
3915107b09fSJeremy L Thompson     // Fallback to reference Ceed
3925107b09fSJeremy L Thompson     if (!op->opfallback) {
3935107b09fSJeremy L Thompson       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
3945107b09fSJeremy L Thompson     }
3955107b09fSJeremy L Thompson     // Assemble
3965107b09fSJeremy L Thompson     ierr = op->opfallback->AssembleLinearQFunction(op->opfallback, assembled,
3975107b09fSJeremy L Thompson            rstr, request); CeedChk(ierr);
3985107b09fSJeremy L Thompson   }
399250756a7Sjeremylt 
4001d102b48SJeremy L Thompson   return 0;
4011d102b48SJeremy L Thompson }
4021d102b48SJeremy L Thompson 
4031d102b48SJeremy L Thompson /**
404b7ec98d8SJeremy L Thompson   @brief Assemble the diagonal of a square linear Operator
405b7ec98d8SJeremy L Thompson 
406b7ec98d8SJeremy L Thompson   This returns a CeedVector containing the diagonal of a linear CeedOperator.
407b7ec98d8SJeremy L Thompson 
408b7ec98d8SJeremy L Thompson   @param op             CeedOperator to assemble CeedQFunction
409b7ec98d8SJeremy L Thompson   @param[out] assembled CeedVector to store assembled CeedOperator diagonal
410b7ec98d8SJeremy L Thompson   @param request        Address of CeedRequest for non-blocking completion, else
411b7ec98d8SJeremy L Thompson                           CEED_REQUEST_IMMEDIATE
412b7ec98d8SJeremy L Thompson 
413b7ec98d8SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
414b7ec98d8SJeremy L Thompson 
415b7ec98d8SJeremy L Thompson   @ref Basic
416b7ec98d8SJeremy L Thompson **/
4177f823360Sjeremylt int CeedOperatorAssembleLinearDiagonal(CeedOperator op, CeedVector *assembled,
4187f823360Sjeremylt                                        CeedRequest *request) {
419b7ec98d8SJeremy L Thompson   int ierr;
420b7ec98d8SJeremy L Thompson   Ceed ceed = op->ceed;
421250756a7Sjeremylt   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
422b7ec98d8SJeremy L Thompson 
423b7ec98d8SJeremy L Thompson   // Use backend version, if available
424b7ec98d8SJeremy L Thompson   if (op->AssembleLinearDiagonal) {
425b7ec98d8SJeremy L Thompson     ierr = op->AssembleLinearDiagonal(op, assembled, request); CeedChk(ierr);
426*7172caadSjeremylt   } else {
427*7172caadSjeremylt     // Fallback to reference Ceed
428*7172caadSjeremylt     if (!op->opfallback) {
429*7172caadSjeremylt       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
430b7ec98d8SJeremy L Thompson     }
431*7172caadSjeremylt     // Assemble
432*7172caadSjeremylt     ierr = op->opfallback->AssembleLinearDiagonal(op->opfallback, assembled,
433*7172caadSjeremylt            request); CeedChk(ierr);
434b7ec98d8SJeremy L Thompson   }
435b7ec98d8SJeremy L Thompson 
436b7ec98d8SJeremy L Thompson   return 0;
437b7ec98d8SJeremy L Thompson }
438b7ec98d8SJeremy L Thompson 
439b7ec98d8SJeremy L Thompson /**
4403bd813ffSjeremylt   @brief Build a FDM based approximate inverse for each element for a
4413bd813ffSjeremylt            CeedOperator
4423bd813ffSjeremylt 
4433bd813ffSjeremylt   This returns a CeedOperator and CeedVector to apply a Fast Diagonalization
4443bd813ffSjeremylt     Method based approximate inverse. This function obtains the simultaneous
4453bd813ffSjeremylt     diagonalization for the 1D mass and Laplacian operators,
4463bd813ffSjeremylt       M = V^T V, K = V^T S V.
4473bd813ffSjeremylt     The assembled QFunction is used to modify the eigenvalues from simultaneous
4483bd813ffSjeremylt     diagonalization and obtain an approximate inverse of the form
4493bd813ffSjeremylt       V^T S^hat V. The CeedOperator must be linear and non-composite. The
4503bd813ffSjeremylt     associated CeedQFunction must therefore also be linear.
4513bd813ffSjeremylt 
4523bd813ffSjeremylt   @param op             CeedOperator to create element inverses
4533bd813ffSjeremylt   @param[out] fdminv    CeedOperator to apply the action of a FDM based inverse
4543bd813ffSjeremylt                           for each element
4553bd813ffSjeremylt   @param[out] qdata     CeedVector to hold qdata for fdminv
4563bd813ffSjeremylt   @param request        Address of CeedRequest for non-blocking completion, else
4573bd813ffSjeremylt                           CEED_REQUEST_IMMEDIATE
4583bd813ffSjeremylt 
4593bd813ffSjeremylt   @return An error code: 0 - success, otherwise - failure
4603bd813ffSjeremylt 
4613bd813ffSjeremylt   @ref Advanced
4623bd813ffSjeremylt **/
4633bd813ffSjeremylt int CeedOperatorCreateFDMElementInverse(CeedOperator op, CeedOperator *fdminv,
4643bd813ffSjeremylt                                         CeedRequest *request) {
4653bd813ffSjeremylt   int ierr;
4663bd813ffSjeremylt   Ceed ceed = op->ceed;
4673bd813ffSjeremylt 
4683bd813ffSjeremylt   // Determine active input basis
4693bd813ffSjeremylt   bool interp = false, grad = false;
4703bd813ffSjeremylt   CeedBasis basis = NULL;
4713bd813ffSjeremylt   CeedElemRestriction rstr = NULL;
4723bd813ffSjeremylt   for (CeedInt i=0; i<op->qf->numinputfields; i++)
4733bd813ffSjeremylt     if (op->inputfields[i] && op->inputfields[i]->vec == CEED_VECTOR_ACTIVE) {
4743bd813ffSjeremylt       basis = op->inputfields[i]->basis;
4753bd813ffSjeremylt       interp = interp || op->qf->inputfields[i]->emode == CEED_EVAL_INTERP;
4763bd813ffSjeremylt       grad = grad || op->qf->inputfields[i]->emode == CEED_EVAL_GRAD;
4773bd813ffSjeremylt       rstr = op->inputfields[i]->Erestrict;
4783bd813ffSjeremylt     }
4793bd813ffSjeremylt   if (!basis)
4803bd813ffSjeremylt     return CeedError(ceed, 1, "No active field set");
4813bd813ffSjeremylt   CeedInt P1d, Q1d, elemsize, nqpts, dim, ncomp = 1, nelem = 1, nnodes = 1;
4823bd813ffSjeremylt   ierr = CeedBasisGetNumNodes1D(basis, &P1d); CeedChk(ierr);
4833bd813ffSjeremylt   ierr = CeedBasisGetNumNodes(basis, &elemsize); CeedChk(ierr);
4843bd813ffSjeremylt   ierr = CeedBasisGetNumQuadraturePoints1D(basis, &Q1d); CeedChk(ierr);
4853bd813ffSjeremylt   ierr = CeedBasisGetNumQuadraturePoints(basis, &nqpts); CeedChk(ierr);
4863bd813ffSjeremylt   ierr = CeedBasisGetDimension(basis, &dim); CeedChk(ierr);
4873bd813ffSjeremylt   ierr = CeedBasisGetNumComponents(basis, &ncomp); CeedChk(ierr);
4883bd813ffSjeremylt   ierr = CeedElemRestrictionGetNumElements(rstr, &nelem); CeedChk(ierr);
4893bd813ffSjeremylt   ierr = CeedElemRestrictionGetNumNodes(rstr, &nnodes); CeedChk(ierr);
4903bd813ffSjeremylt 
4913bd813ffSjeremylt   // Build and diagonalize 1D Mass and Laplacian
4923bd813ffSjeremylt   if (!basis->tensorbasis)
4933bd813ffSjeremylt     return CeedError(ceed, 1, "FDMElementInverse only supported for tensor "
4943bd813ffSjeremylt                      "bases");
4953bd813ffSjeremylt   CeedScalar *work, *mass, *laplace, *x, *x2, *lambda;
4963bd813ffSjeremylt   ierr = CeedMalloc(Q1d*P1d, &work); CeedChk(ierr);
4973bd813ffSjeremylt   ierr = CeedMalloc(P1d*P1d, &mass); CeedChk(ierr);
4983bd813ffSjeremylt   ierr = CeedMalloc(P1d*P1d, &laplace); CeedChk(ierr);
4993bd813ffSjeremylt   ierr = CeedMalloc(P1d*P1d, &x); CeedChk(ierr);
5003bd813ffSjeremylt   ierr = CeedMalloc(P1d*P1d, &x2); CeedChk(ierr);
5013bd813ffSjeremylt   ierr = CeedMalloc(P1d, &lambda); CeedChk(ierr);
5023bd813ffSjeremylt   // -- Mass
5033bd813ffSjeremylt   for (CeedInt i=0; i<Q1d; i++)
5043bd813ffSjeremylt     for (CeedInt j=0; j<P1d; j++)
5053bd813ffSjeremylt       work[i+j*Q1d] = basis->interp1d[i*P1d+j]*basis->qweight1d[i];
5063bd813ffSjeremylt   ierr = CeedMatrixMultiply(ceed, work, basis->interp1d, mass, P1d, P1d, Q1d);
5073bd813ffSjeremylt   CeedChk(ierr);
5083bd813ffSjeremylt   // -- Laplacian
5093bd813ffSjeremylt   for (CeedInt i=0; i<Q1d; i++)
5103bd813ffSjeremylt     for (CeedInt j=0; j<P1d; j++)
5113bd813ffSjeremylt       work[i+j*Q1d] = basis->grad1d[i*P1d+j]*basis->qweight1d[i];
5123bd813ffSjeremylt   ierr = CeedMatrixMultiply(ceed, work, basis->grad1d, laplace, P1d, P1d, Q1d);
5133bd813ffSjeremylt   CeedChk(ierr);
5143bd813ffSjeremylt   // -- Diagonalize
5153bd813ffSjeremylt   ierr = CeedSimultaneousDiagonalization(ceed, laplace, mass, x, lambda, P1d);
5163bd813ffSjeremylt   CeedChk(ierr);
5173bd813ffSjeremylt   ierr = CeedFree(&work); CeedChk(ierr);
5183bd813ffSjeremylt   ierr = CeedFree(&mass); CeedChk(ierr);
5193bd813ffSjeremylt   ierr = CeedFree(&laplace); CeedChk(ierr);
5203bd813ffSjeremylt   for (CeedInt i=0; i<P1d; i++)
5213bd813ffSjeremylt     for (CeedInt j=0; j<P1d; j++)
5223bd813ffSjeremylt       x2[i+j*P1d] = x[j+i*P1d];
5233bd813ffSjeremylt   ierr = CeedFree(&x); CeedChk(ierr);
5243bd813ffSjeremylt 
5253bd813ffSjeremylt   // Assemble QFunction
5263bd813ffSjeremylt   CeedVector assembled;
5273bd813ffSjeremylt   CeedElemRestriction rstr_qf;
5283bd813ffSjeremylt   ierr =  CeedOperatorAssembleLinearQFunction(op, &assembled, &rstr_qf,
5293bd813ffSjeremylt           request); CeedChk(ierr);
5303bd813ffSjeremylt   ierr = CeedElemRestrictionDestroy(&rstr_qf); CeedChk(ierr);
5313bd813ffSjeremylt 
5323bd813ffSjeremylt   // Calculate element averages
5333bd813ffSjeremylt   CeedInt nfields = ((interp?1:0) + (grad?dim:0))*((interp?1:0) + (grad?dim:0));
5343bd813ffSjeremylt   CeedScalar *elemavg;
5353bd813ffSjeremylt   const CeedScalar *assembledarray, *qweightsarray;
5363bd813ffSjeremylt   CeedVector qweights;
5373bd813ffSjeremylt   ierr = CeedVectorCreate(ceed, nqpts, &qweights); CeedChk(ierr);
5383bd813ffSjeremylt   ierr = CeedBasisApply(basis, 1, CEED_NOTRANSPOSE, CEED_EVAL_WEIGHT,
5393bd813ffSjeremylt                         CEED_VECTOR_NONE, qweights); CeedChk(ierr);
5403bd813ffSjeremylt   ierr = CeedVectorGetArrayRead(assembled, CEED_MEM_HOST, &assembledarray);
5413bd813ffSjeremylt   CeedChk(ierr);
5423bd813ffSjeremylt   ierr = CeedVectorGetArrayRead(qweights, CEED_MEM_HOST, &qweightsarray);
5433bd813ffSjeremylt   CeedChk(ierr);
5443bd813ffSjeremylt   ierr = CeedCalloc(nelem, &elemavg); CeedChk(ierr);
5453bd813ffSjeremylt   for (CeedInt e=0; e<nelem; e++) {
5463bd813ffSjeremylt     CeedInt count = 0;
5473bd813ffSjeremylt     for (CeedInt q=0; q<nqpts; q++)
5483bd813ffSjeremylt       for (CeedInt i=0; i<ncomp*ncomp*nfields; i++)
5493bd813ffSjeremylt         if (fabs(assembledarray[e*nelem*nqpts*ncomp*ncomp*nfields +
5500e4d4210Sjeremylt                                                                   i*nqpts + q]) > CEED_EPSILON) {
5513bd813ffSjeremylt           elemavg[e] += assembledarray[e*nelem*nqpts*ncomp*ncomp*nfields +
5523bd813ffSjeremylt                                        i*nqpts + q] / qweightsarray[q];
5533bd813ffSjeremylt           count++;
5543bd813ffSjeremylt         }
5553bd813ffSjeremylt     if (count)
5563bd813ffSjeremylt       elemavg[e] /= count;
5573bd813ffSjeremylt   }
5583bd813ffSjeremylt   ierr = CeedVectorRestoreArrayRead(assembled, &assembledarray); CeedChk(ierr);
5593bd813ffSjeremylt   ierr = CeedVectorDestroy(&assembled); CeedChk(ierr);
5603bd813ffSjeremylt   ierr = CeedVectorRestoreArrayRead(qweights, &qweightsarray); CeedChk(ierr);
5613bd813ffSjeremylt   ierr = CeedVectorDestroy(&qweights); CeedChk(ierr);
5623bd813ffSjeremylt 
5633bd813ffSjeremylt   // Build FDM diagonal
5643bd813ffSjeremylt   CeedVector qdata;
5653bd813ffSjeremylt   CeedScalar *qdataarray;
5663bd813ffSjeremylt   ierr = CeedVectorCreate(ceed, nelem*ncomp*nnodes, &qdata); CeedChk(ierr);
5673bd813ffSjeremylt   ierr = CeedVectorSetArray(qdata, CEED_MEM_HOST, CEED_COPY_VALUES, NULL);
5683bd813ffSjeremylt   CeedChk(ierr);
5693bd813ffSjeremylt   ierr = CeedVectorGetArray(qdata, CEED_MEM_HOST, &qdataarray); CeedChk(ierr);
5703bd813ffSjeremylt   for (CeedInt e=0; e<nelem; e++)
5713bd813ffSjeremylt     for (CeedInt c=0; c<ncomp; c++)
5723bd813ffSjeremylt       for (CeedInt n=0; n<nnodes; n++) {
5733bd813ffSjeremylt         if (interp)
5743bd813ffSjeremylt           qdataarray[(e*ncomp+c)*nnodes+n] = 1;
5753bd813ffSjeremylt         if (grad)
5763bd813ffSjeremylt           for (CeedInt d=0; d<dim; d++) {
5773bd813ffSjeremylt             CeedInt i = (n / CeedIntPow(P1d, d)) % P1d;
5783bd813ffSjeremylt             qdataarray[(e*ncomp+c)*nnodes+n] += lambda[i];
5793bd813ffSjeremylt           }
5803bd813ffSjeremylt         qdataarray[(e*ncomp+c)*nnodes+n] = 1 / (elemavg[e] *
5813bd813ffSjeremylt                                                 qdataarray[(e*ncomp+c)*nnodes+n]);
5823bd813ffSjeremylt       }
5833bd813ffSjeremylt   ierr = CeedFree(&elemavg); CeedChk(ierr);
5843bd813ffSjeremylt   ierr = CeedVectorRestoreArray(qdata, &qdataarray); CeedChk(ierr);
5853bd813ffSjeremylt 
5863bd813ffSjeremylt   // Setup FDM operator
5873bd813ffSjeremylt   // -- Basis
5883bd813ffSjeremylt   CeedBasis fdm_basis;
5893bd813ffSjeremylt   CeedScalar *graddummy, *qrefdummy, *qweightdummy;
5903bd813ffSjeremylt   ierr = CeedCalloc(P1d*P1d, &graddummy); CeedChk(ierr);
5913bd813ffSjeremylt   ierr = CeedCalloc(P1d, &qrefdummy); CeedChk(ierr);
5923bd813ffSjeremylt   ierr = CeedCalloc(P1d, &qweightdummy); CeedChk(ierr);
5933bd813ffSjeremylt   ierr = CeedBasisCreateTensorH1(ceed, dim, ncomp, P1d, P1d, x2, graddummy,
5943bd813ffSjeremylt                                  qrefdummy, qweightdummy, &fdm_basis);
5953bd813ffSjeremylt   CeedChk(ierr);
5963bd813ffSjeremylt   ierr = CeedFree(&graddummy); CeedChk(ierr);
5973bd813ffSjeremylt   ierr = CeedFree(&qrefdummy); CeedChk(ierr);
5983bd813ffSjeremylt   ierr = CeedFree(&qweightdummy); CeedChk(ierr);
5993bd813ffSjeremylt   ierr = CeedFree(&x2); CeedChk(ierr);
6003bd813ffSjeremylt   ierr = CeedFree(&lambda); CeedChk(ierr);
6013bd813ffSjeremylt 
6023bd813ffSjeremylt   // -- Restriction
6033bd813ffSjeremylt   CeedElemRestriction rstr_i;
6043bd813ffSjeremylt   ierr = CeedElemRestrictionCreateIdentity(ceed, nelem, nnodes, nnodes*nelem,
6053bd813ffSjeremylt          ncomp, &rstr_i); CeedChk(ierr);
6063bd813ffSjeremylt   // -- QFunction
6073bd813ffSjeremylt   CeedQFunction mass_qf;
6083bd813ffSjeremylt   ierr = CeedQFunctionCreateInteriorByName(ceed, "MassApply", &mass_qf);
6093bd813ffSjeremylt   CeedChk(ierr);
6103bd813ffSjeremylt   // -- Operator
6113bd813ffSjeremylt   ierr = CeedOperatorCreate(ceed, mass_qf, NULL, NULL, fdminv); CeedChk(ierr);
6123bd813ffSjeremylt   CeedOperatorSetField(*fdminv, "u", rstr_i, CEED_NOTRANSPOSE,
6133bd813ffSjeremylt                        fdm_basis, CEED_VECTOR_ACTIVE); CeedChk(ierr);
6143bd813ffSjeremylt   CeedOperatorSetField(*fdminv, "qdata", rstr_i, CEED_NOTRANSPOSE,
6153bd813ffSjeremylt                        CEED_BASIS_COLLOCATED, qdata); CeedChk(ierr);
6163bd813ffSjeremylt   CeedOperatorSetField(*fdminv, "v", rstr_i, CEED_NOTRANSPOSE,
6173bd813ffSjeremylt                        fdm_basis, CEED_VECTOR_ACTIVE); CeedChk(ierr);
6183bd813ffSjeremylt 
6193bd813ffSjeremylt   // Cleanup
6203bd813ffSjeremylt   ierr = CeedVectorDestroy(&qdata); CeedChk(ierr);
6213bd813ffSjeremylt   ierr = CeedBasisDestroy(&fdm_basis); CeedChk(ierr);
6223bd813ffSjeremylt   ierr = CeedElemRestrictionDestroy(&rstr_i); CeedChk(ierr);
6233bd813ffSjeremylt   ierr = CeedQFunctionDestroy(&mass_qf); CeedChk(ierr);
6243bd813ffSjeremylt 
6253bd813ffSjeremylt   return 0;
6263bd813ffSjeremylt }
6273bd813ffSjeremylt 
6283bd813ffSjeremylt 
6293bd813ffSjeremylt /**
6303bd813ffSjeremylt   @brief Apply CeedOperator to a vector
631d7b241e6Sjeremylt 
632d7b241e6Sjeremylt   This computes the action of the operator on the specified (active) input,
633d7b241e6Sjeremylt   yielding its (active) output.  All inputs and outputs must be specified using
634d7b241e6Sjeremylt   CeedOperatorSetField().
635d7b241e6Sjeremylt 
636d7b241e6Sjeremylt   @param op        CeedOperator to apply
63734138859Sjeremylt   @param[in] in    CeedVector containing input state or CEED_VECTOR_NONE if
63834138859Sjeremylt                   there are no active inputs
639b11c1e72Sjeremylt   @param[out] out  CeedVector to store result of applying operator (must be
64034138859Sjeremylt                      distinct from @a in) or CEED_VECTOR_NONE if there are no
64134138859Sjeremylt                      active outputs
642d7b241e6Sjeremylt   @param request   Address of CeedRequest for non-blocking completion, else
643d7b241e6Sjeremylt                      CEED_REQUEST_IMMEDIATE
644b11c1e72Sjeremylt 
645b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
646dfdf5a53Sjeremylt 
647dfdf5a53Sjeremylt   @ref Basic
648b11c1e72Sjeremylt **/
649692c2638Sjeremylt int CeedOperatorApply(CeedOperator op, CeedVector in, CeedVector out,
650692c2638Sjeremylt                       CeedRequest *request) {
651d7b241e6Sjeremylt   int ierr;
652d7b241e6Sjeremylt   Ceed ceed = op->ceed;
653250756a7Sjeremylt   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
654d7b241e6Sjeremylt 
655250756a7Sjeremylt   if (op->numelements)  {
656250756a7Sjeremylt     // Standard Operator
657cae8b89aSjeremylt     if (op->Apply) {
658250756a7Sjeremylt       ierr = op->Apply(op, in, out, request); CeedChk(ierr);
659cae8b89aSjeremylt     } else {
660cae8b89aSjeremylt       // Zero all output vectors
661250756a7Sjeremylt       CeedQFunction qf = op->qf;
662cae8b89aSjeremylt       for (CeedInt i=0; i<qf->numoutputfields; i++) {
663cae8b89aSjeremylt         CeedVector vec = op->outputfields[i]->vec;
664cae8b89aSjeremylt         if (vec == CEED_VECTOR_ACTIVE)
665cae8b89aSjeremylt           vec = out;
666cae8b89aSjeremylt         if (vec != CEED_VECTOR_NONE) {
667cae8b89aSjeremylt           ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr);
668cae8b89aSjeremylt         }
669cae8b89aSjeremylt       }
670250756a7Sjeremylt       // Apply
671250756a7Sjeremylt       ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr);
672250756a7Sjeremylt     }
673250756a7Sjeremylt   } else if (op->composite) {
674250756a7Sjeremylt     // Composite Operator
675250756a7Sjeremylt     if (op->ApplyComposite) {
676250756a7Sjeremylt       ierr = op->ApplyComposite(op, in, out, request); CeedChk(ierr);
677250756a7Sjeremylt     } else {
678250756a7Sjeremylt       CeedInt numsub;
679250756a7Sjeremylt       ierr = CeedOperatorGetNumSub(op, &numsub); CeedChk(ierr);
680250756a7Sjeremylt       CeedOperator *suboperators;
681250756a7Sjeremylt       ierr = CeedOperatorGetSubList(op, &suboperators); CeedChk(ierr);
682250756a7Sjeremylt 
683250756a7Sjeremylt       // Zero all output vectors
684250756a7Sjeremylt       if (out != CEED_VECTOR_NONE) {
685cae8b89aSjeremylt         ierr = CeedVectorSetValue(out, 0.0); CeedChk(ierr);
686cae8b89aSjeremylt       }
687250756a7Sjeremylt       for (CeedInt i=0; i<numsub; i++) {
688250756a7Sjeremylt         for (CeedInt j=0; j<suboperators[i]->qf->numoutputfields; j++) {
689250756a7Sjeremylt           CeedVector vec = suboperators[i]->outputfields[j]->vec;
690250756a7Sjeremylt           if (vec != CEED_VECTOR_ACTIVE && vec != CEED_VECTOR_NONE) {
691250756a7Sjeremylt             ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr);
692250756a7Sjeremylt           }
693250756a7Sjeremylt         }
694250756a7Sjeremylt       }
695250756a7Sjeremylt       // Apply
696250756a7Sjeremylt       for (CeedInt i=0; i<op->numsub; i++) {
697250756a7Sjeremylt         ierr = CeedOperatorApplyAdd(op->suboperators[i], in, out, request);
698cae8b89aSjeremylt         CeedChk(ierr);
699cae8b89aSjeremylt       }
700cae8b89aSjeremylt     }
701250756a7Sjeremylt   }
702250756a7Sjeremylt 
703cae8b89aSjeremylt   return 0;
704cae8b89aSjeremylt }
705cae8b89aSjeremylt 
706cae8b89aSjeremylt /**
707cae8b89aSjeremylt   @brief Apply CeedOperator to a vector and add result to output vector
708cae8b89aSjeremylt 
709cae8b89aSjeremylt   This computes the action of the operator on the specified (active) input,
710cae8b89aSjeremylt   yielding its (active) output.  All inputs and outputs must be specified using
711cae8b89aSjeremylt   CeedOperatorSetField().
712cae8b89aSjeremylt 
713cae8b89aSjeremylt   @param op        CeedOperator to apply
714cae8b89aSjeremylt   @param[in] in    CeedVector containing input state or NULL if there are no
715cae8b89aSjeremylt                      active inputs
716cae8b89aSjeremylt   @param[out] out  CeedVector to sum in result of applying operator (must be
717cae8b89aSjeremylt                      distinct from @a in) or NULL if there are no active outputs
718cae8b89aSjeremylt   @param request   Address of CeedRequest for non-blocking completion, else
719cae8b89aSjeremylt                      CEED_REQUEST_IMMEDIATE
720cae8b89aSjeremylt 
721cae8b89aSjeremylt   @return An error code: 0 - success, otherwise - failure
722cae8b89aSjeremylt 
723cae8b89aSjeremylt   @ref Basic
724cae8b89aSjeremylt **/
725cae8b89aSjeremylt int CeedOperatorApplyAdd(CeedOperator op, CeedVector in, CeedVector out,
726cae8b89aSjeremylt                          CeedRequest *request) {
727cae8b89aSjeremylt   int ierr;
728cae8b89aSjeremylt   Ceed ceed = op->ceed;
729250756a7Sjeremylt   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
730cae8b89aSjeremylt 
731250756a7Sjeremylt   if (op->numelements)  {
732250756a7Sjeremylt     // Standard Operator
733250756a7Sjeremylt     ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr);
734250756a7Sjeremylt   } else if (op->composite) {
735250756a7Sjeremylt     // Composite Operator
736250756a7Sjeremylt     if (op->ApplyAddComposite) {
737250756a7Sjeremylt       ierr = op->ApplyAddComposite(op, in, out, request); CeedChk(ierr);
738cae8b89aSjeremylt     } else {
739250756a7Sjeremylt       CeedInt numsub;
740250756a7Sjeremylt       ierr = CeedOperatorGetNumSub(op, &numsub); CeedChk(ierr);
741250756a7Sjeremylt       CeedOperator *suboperators;
742250756a7Sjeremylt       ierr = CeedOperatorGetSubList(op, &suboperators); CeedChk(ierr);
743250756a7Sjeremylt 
744250756a7Sjeremylt       for (CeedInt i=0; i<numsub; i++) {
745250756a7Sjeremylt         ierr = CeedOperatorApplyAdd(suboperators[i], in, out, request);
746cae8b89aSjeremylt         CeedChk(ierr);
7471d7d2407SJeremy L Thompson       }
748250756a7Sjeremylt     }
749250756a7Sjeremylt   }
750250756a7Sjeremylt 
751d7b241e6Sjeremylt   return 0;
752d7b241e6Sjeremylt }
753d7b241e6Sjeremylt 
754d7b241e6Sjeremylt /**
7554ce2993fSjeremylt   @brief Get the Ceed associated with a CeedOperator
7564ce2993fSjeremylt 
7574ce2993fSjeremylt   @param op              CeedOperator
7584ce2993fSjeremylt   @param[out] ceed       Variable to store Ceed
7594ce2993fSjeremylt 
7604ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
7614ce2993fSjeremylt 
76223617272Sjeremylt   @ref Advanced
7634ce2993fSjeremylt **/
7644ce2993fSjeremylt 
7654ce2993fSjeremylt int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) {
7664ce2993fSjeremylt   *ceed = op->ceed;
7674ce2993fSjeremylt   return 0;
7684ce2993fSjeremylt }
7694ce2993fSjeremylt 
7704ce2993fSjeremylt /**
7714ce2993fSjeremylt   @brief Get the number of elements associated with a CeedOperator
7724ce2993fSjeremylt 
7734ce2993fSjeremylt   @param op              CeedOperator
7744ce2993fSjeremylt   @param[out] numelem    Variable to store number of elements
7754ce2993fSjeremylt 
7764ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
7774ce2993fSjeremylt 
77823617272Sjeremylt   @ref Advanced
7794ce2993fSjeremylt **/
7804ce2993fSjeremylt 
7814ce2993fSjeremylt int CeedOperatorGetNumElements(CeedOperator op, CeedInt *numelem) {
78252d6035fSJeremy L Thompson   if (op->composite)
783c042f62fSJeremy L Thompson     // LCOV_EXCL_START
78452d6035fSJeremy L Thompson     return CeedError(op->ceed, 1, "Not defined for composite operator");
785c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
78652d6035fSJeremy L Thompson 
7874ce2993fSjeremylt   *numelem = op->numelements;
7884ce2993fSjeremylt   return 0;
7894ce2993fSjeremylt }
7904ce2993fSjeremylt 
7914ce2993fSjeremylt /**
7924ce2993fSjeremylt   @brief Get the number of quadrature points associated with a CeedOperator
7934ce2993fSjeremylt 
7944ce2993fSjeremylt   @param op              CeedOperator
7954ce2993fSjeremylt   @param[out] numqpts    Variable to store vector number of quadrature points
7964ce2993fSjeremylt 
7974ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
7984ce2993fSjeremylt 
79923617272Sjeremylt   @ref Advanced
8004ce2993fSjeremylt **/
8014ce2993fSjeremylt 
8024ce2993fSjeremylt int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *numqpts) {
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   *numqpts = op->numqpoints;
8094ce2993fSjeremylt   return 0;
8104ce2993fSjeremylt }
8114ce2993fSjeremylt 
8124ce2993fSjeremylt /**
8134ce2993fSjeremylt   @brief Get the number of arguments associated with a CeedOperator
8144ce2993fSjeremylt 
8154ce2993fSjeremylt   @param op              CeedOperator
8164ce2993fSjeremylt   @param[out] numargs    Variable to store vector number of arguments
8174ce2993fSjeremylt 
8184ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
8194ce2993fSjeremylt 
82023617272Sjeremylt   @ref Advanced
8214ce2993fSjeremylt **/
8224ce2993fSjeremylt 
8234ce2993fSjeremylt int CeedOperatorGetNumArgs(CeedOperator op, CeedInt *numargs) {
82452d6035fSJeremy L Thompson   if (op->composite)
825c042f62fSJeremy L Thompson     // LCOV_EXCL_START
82652d6035fSJeremy L Thompson     return CeedError(op->ceed, 1, "Not defined for composite operators");
827c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
828c042f62fSJeremy L Thompson 
8294ce2993fSjeremylt   *numargs = op->nfields;
8304ce2993fSjeremylt   return 0;
8314ce2993fSjeremylt }
8324ce2993fSjeremylt 
8334ce2993fSjeremylt /**
8344ce2993fSjeremylt   @brief Get the setup status of a CeedOperator
8354ce2993fSjeremylt 
8364ce2993fSjeremylt   @param op             CeedOperator
837288c0443SJeremy L Thompson   @param[out] setupdone Variable to store setup status
8384ce2993fSjeremylt 
8394ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
8404ce2993fSjeremylt 
84123617272Sjeremylt   @ref Advanced
8424ce2993fSjeremylt **/
8434ce2993fSjeremylt 
8444ce2993fSjeremylt int CeedOperatorGetSetupStatus(CeedOperator op, bool *setupdone) {
8454ce2993fSjeremylt   *setupdone = op->setupdone;
8464ce2993fSjeremylt   return 0;
8474ce2993fSjeremylt }
8484ce2993fSjeremylt 
8494ce2993fSjeremylt /**
8504ce2993fSjeremylt   @brief Get the QFunction associated with a CeedOperator
8514ce2993fSjeremylt 
8524ce2993fSjeremylt   @param op              CeedOperator
8538c91a0c9SJeremy L Thompson   @param[out] qf         Variable to store QFunction
8544ce2993fSjeremylt 
8554ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
8564ce2993fSjeremylt 
85723617272Sjeremylt   @ref Advanced
8584ce2993fSjeremylt **/
8594ce2993fSjeremylt 
8604ce2993fSjeremylt int CeedOperatorGetQFunction(CeedOperator op, CeedQFunction *qf) {
86152d6035fSJeremy L Thompson   if (op->composite)
862c042f62fSJeremy L Thompson     // LCOV_EXCL_START
86352d6035fSJeremy L Thompson     return CeedError(op->ceed, 1, "Not defined for composite operator");
864c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
86552d6035fSJeremy L Thompson 
8664ce2993fSjeremylt   *qf = op->qf;
8674ce2993fSjeremylt   return 0;
8684ce2993fSjeremylt }
8694ce2993fSjeremylt 
8704ce2993fSjeremylt /**
87152d6035fSJeremy L Thompson   @brief Get the number of suboperators associated with a CeedOperator
87252d6035fSJeremy L Thompson 
87352d6035fSJeremy L Thompson   @param op              CeedOperator
87452d6035fSJeremy L Thompson   @param[out] numsub     Variable to store number of suboperators
87552d6035fSJeremy L Thompson 
87652d6035fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
87752d6035fSJeremy L Thompson 
87852d6035fSJeremy L Thompson   @ref Advanced
87952d6035fSJeremy L Thompson **/
88052d6035fSJeremy L Thompson 
88152d6035fSJeremy L Thompson int CeedOperatorGetNumSub(CeedOperator op, CeedInt *numsub) {
882c042f62fSJeremy L Thompson   if (!op->composite)
883c042f62fSJeremy L Thompson     // LCOV_EXCL_START
884c042f62fSJeremy L Thompson     return CeedError(op->ceed, 1, "Not a composite operator");
885c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
88652d6035fSJeremy L Thompson 
88752d6035fSJeremy L Thompson   *numsub = op->numsub;
88852d6035fSJeremy L Thompson   return 0;
88952d6035fSJeremy L Thompson }
89052d6035fSJeremy L Thompson 
89152d6035fSJeremy L Thompson /**
89252d6035fSJeremy L Thompson   @brief Get the list of suboperators associated with a CeedOperator
89352d6035fSJeremy L Thompson 
89452d6035fSJeremy L Thompson   @param op                CeedOperator
89552d6035fSJeremy L Thompson   @param[out] suboperators Variable to store list of suboperators
89652d6035fSJeremy L Thompson 
89752d6035fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
89852d6035fSJeremy L Thompson 
89952d6035fSJeremy L Thompson   @ref Advanced
90052d6035fSJeremy L Thompson **/
90152d6035fSJeremy L Thompson 
90252d6035fSJeremy L Thompson int CeedOperatorGetSubList(CeedOperator op, CeedOperator **suboperators) {
903c042f62fSJeremy L Thompson   if (!op->composite)
904c042f62fSJeremy L Thompson     // LCOV_EXCL_START
905c042f62fSJeremy L Thompson     return CeedError(op->ceed, 1, "Not a composite operator");
906c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
90752d6035fSJeremy L Thompson 
90852d6035fSJeremy L Thompson   *suboperators = op->suboperators;
90952d6035fSJeremy L Thompson   return 0;
91052d6035fSJeremy L Thompson }
91152d6035fSJeremy L Thompson 
91252d6035fSJeremy L Thompson /**
913fe2413ffSjeremylt   @brief Set the backend data of a CeedOperator
914fe2413ffSjeremylt 
915fe2413ffSjeremylt   @param[out] op         CeedOperator
916fe2413ffSjeremylt   @param data            Data to set
917fe2413ffSjeremylt 
918fe2413ffSjeremylt   @return An error code: 0 - success, otherwise - failure
919fe2413ffSjeremylt 
920fe2413ffSjeremylt   @ref Advanced
921fe2413ffSjeremylt **/
922fe2413ffSjeremylt 
923fe2413ffSjeremylt int CeedOperatorSetData(CeedOperator op, void **data) {
924fe2413ffSjeremylt   op->data = *data;
925fe2413ffSjeremylt   return 0;
926fe2413ffSjeremylt }
927fe2413ffSjeremylt 
928fe2413ffSjeremylt /**
9294ce2993fSjeremylt   @brief Get the backend data of a CeedOperator
9304ce2993fSjeremylt 
9314ce2993fSjeremylt   @param op              CeedOperator
9324ce2993fSjeremylt   @param[out] data       Variable to store data
9334ce2993fSjeremylt 
9344ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
9354ce2993fSjeremylt 
93623617272Sjeremylt   @ref Advanced
9374ce2993fSjeremylt **/
9384ce2993fSjeremylt 
9394ce2993fSjeremylt int CeedOperatorGetData(CeedOperator op, void **data) {
9404ce2993fSjeremylt   *data = op->data;
9414ce2993fSjeremylt   return 0;
9424ce2993fSjeremylt }
9434ce2993fSjeremylt 
9444ce2993fSjeremylt /**
9454ce2993fSjeremylt   @brief Set the setup flag of a CeedOperator to True
9464ce2993fSjeremylt 
9474ce2993fSjeremylt   @param op              CeedOperator
9484ce2993fSjeremylt 
9494ce2993fSjeremylt   @return An error code: 0 - success, otherwise - failure
9504ce2993fSjeremylt 
95123617272Sjeremylt   @ref Advanced
9524ce2993fSjeremylt **/
9534ce2993fSjeremylt 
9544ce2993fSjeremylt int CeedOperatorSetSetupDone(CeedOperator op) {
9554ce2993fSjeremylt   op->setupdone = 1;
9564ce2993fSjeremylt   return 0;
9574ce2993fSjeremylt }
9584ce2993fSjeremylt 
9594ce2993fSjeremylt /**
9602ebaca42Sjeremylt   @brief View a field of a CeedOperator
9612ebaca42Sjeremylt 
9622ebaca42Sjeremylt   @param[in] field       Operator field to view
9632ebaca42Sjeremylt   @param[in] fieldnumber Number of field being viewed
9642ebaca42Sjeremylt   @param[in] stream      Stream to view to, e.g., stdout
9652ebaca42Sjeremylt 
9662ebaca42Sjeremylt   @return An error code: 0 - success, otherwise - failure
9672ebaca42Sjeremylt 
9682ebaca42Sjeremylt   @ref Utility
9692ebaca42Sjeremylt **/
9702ebaca42Sjeremylt static int CeedOperatorFieldView(CeedOperatorField field,
9712ebaca42Sjeremylt                                  CeedQFunctionField qffield,
9722da88da5Sjeremylt                                  CeedInt fieldnumber, bool sub, bool in,
9732da88da5Sjeremylt                                  FILE *stream) {
9742ebaca42Sjeremylt   const char *pre = sub ? "  " : "";
9752da88da5Sjeremylt   const char *inout = in ? "Input" : "Output";
9762ebaca42Sjeremylt 
9772da88da5Sjeremylt   fprintf(stream, "%s    %s Field [%d]:\n"
9782da88da5Sjeremylt           "%s      Name: \"%s\"\n"
9792da88da5Sjeremylt           "%s      Lmode: \"%s\"\n",
9802da88da5Sjeremylt           pre, inout, fieldnumber, pre, qffield->fieldname,
9812ebaca42Sjeremylt           pre, CeedTransposeModes[field->lmode]);
9822ebaca42Sjeremylt 
9832ebaca42Sjeremylt   if (field->basis == CEED_BASIS_COLLOCATED)
9842ebaca42Sjeremylt     fprintf(stream, "%s      Collocated basis\n", pre);
9852ebaca42Sjeremylt 
9862ebaca42Sjeremylt   if (field->vec == CEED_VECTOR_ACTIVE)
9872ebaca42Sjeremylt     fprintf(stream, "%s      Active vector\n", pre);
9882ebaca42Sjeremylt   else if (field->vec == CEED_VECTOR_NONE)
9892ebaca42Sjeremylt     fprintf(stream, "%s      No vector\n", pre);
9902ebaca42Sjeremylt 
9912ebaca42Sjeremylt   return 0;
9922ebaca42Sjeremylt }
9932ebaca42Sjeremylt 
9942ebaca42Sjeremylt /**
9952ebaca42Sjeremylt   @brief View a single CeedOperator
9962ebaca42Sjeremylt 
9972ebaca42Sjeremylt   @param[in] op     CeedOperator to view
9982ebaca42Sjeremylt   @param[in] stream Stream to write; typically stdout/stderr or a file
9992ebaca42Sjeremylt 
10002ebaca42Sjeremylt   @return Error code: 0 - success, otherwise - failure
10012ebaca42Sjeremylt 
10022ebaca42Sjeremylt   @ref Utility
10032ebaca42Sjeremylt **/
10042ebaca42Sjeremylt int CeedOperatorSingleView(CeedOperator op, bool sub, FILE *stream) {
10052ebaca42Sjeremylt   int ierr;
10062ebaca42Sjeremylt   const char *pre = sub ? "  " : "";
10072ebaca42Sjeremylt 
10082ebaca42Sjeremylt   CeedInt totalfields;
10092ebaca42Sjeremylt   ierr = CeedOperatorGetNumArgs(op, &totalfields); CeedChk(ierr);
10102da88da5Sjeremylt 
10112ebaca42Sjeremylt   fprintf(stream, "%s  %d Field%s\n", pre, totalfields, totalfields>1 ? "s" : "");
10122ebaca42Sjeremylt 
10132da88da5Sjeremylt   fprintf(stream, "%s  %d Input Field%s:\n", pre, op->qf->numinputfields,
10142ebaca42Sjeremylt           op->qf->numinputfields>1 ? "s" : "");
10152ebaca42Sjeremylt   for (CeedInt i=0; i<op->qf->numinputfields; i++) {
10162ebaca42Sjeremylt     ierr = CeedOperatorFieldView(op->inputfields[i], op->qf->inputfields[i],
10172da88da5Sjeremylt                                  i, sub, 1, stream); CeedChk(ierr);
10182ebaca42Sjeremylt   }
10192ebaca42Sjeremylt 
10202da88da5Sjeremylt   fprintf(stream, "%s  %d Output Field%s:\n", pre, op->qf->numoutputfields,
10212ebaca42Sjeremylt           op->qf->numoutputfields>1 ? "s" : "");
10222ebaca42Sjeremylt   for (CeedInt i=0; i<op->qf->numoutputfields; i++) {
10232ebaca42Sjeremylt     ierr = CeedOperatorFieldView(op->outputfields[i], op->qf->inputfields[i],
10242da88da5Sjeremylt                                  i, sub, 0, stream); CeedChk(ierr);
10252ebaca42Sjeremylt   }
10262ebaca42Sjeremylt 
10272ebaca42Sjeremylt   return 0;
10282ebaca42Sjeremylt }
10292ebaca42Sjeremylt 
10302ebaca42Sjeremylt /**
10312ebaca42Sjeremylt   @brief View a CeedOperator
10322ebaca42Sjeremylt 
10332ebaca42Sjeremylt   @param[in] op     CeedOperator to view
10342ebaca42Sjeremylt   @param[in] stream Stream to write; typically stdout/stderr or a file
10352ebaca42Sjeremylt 
10362ebaca42Sjeremylt   @return Error code: 0 - success, otherwise - failure
10372ebaca42Sjeremylt 
10382ebaca42Sjeremylt   @ref Utility
10392ebaca42Sjeremylt **/
10402ebaca42Sjeremylt int CeedOperatorView(CeedOperator op, FILE *stream) {
10412ebaca42Sjeremylt   int ierr;
10422ebaca42Sjeremylt 
10432ebaca42Sjeremylt   if (op->composite) {
10442ebaca42Sjeremylt     fprintf(stream, "Composite CeedOperator\n");
10452ebaca42Sjeremylt 
10462ebaca42Sjeremylt     for (CeedInt i=0; i<op->numsub; i++) {
10472da88da5Sjeremylt       fprintf(stream, "  SubOperator [%d]:\n", i);
10482ebaca42Sjeremylt       ierr = CeedOperatorSingleView(op->suboperators[i], 1, stream);
10492ebaca42Sjeremylt       CeedChk(ierr);
10502ebaca42Sjeremylt     }
10512ebaca42Sjeremylt   } else {
10522ebaca42Sjeremylt     fprintf(stream, "CeedOperator\n");
10532ebaca42Sjeremylt     ierr = CeedOperatorSingleView(op, 0, stream); CeedChk(ierr);
10542ebaca42Sjeremylt   }
10552ebaca42Sjeremylt 
10562ebaca42Sjeremylt   return 0;
10572ebaca42Sjeremylt }
10582ebaca42Sjeremylt 
10592ebaca42Sjeremylt /**
1060d1bcdac9Sjeremylt   @brief Get the CeedOperatorFields of a CeedOperator
1061d1bcdac9Sjeremylt 
1062d1bcdac9Sjeremylt   @param op                 CeedOperator
1063d1bcdac9Sjeremylt   @param[out] inputfields   Variable to store inputfields
1064d1bcdac9Sjeremylt   @param[out] outputfields  Variable to store outputfields
1065d1bcdac9Sjeremylt 
1066d1bcdac9Sjeremylt   @return An error code: 0 - success, otherwise - failure
1067d1bcdac9Sjeremylt 
1068d1bcdac9Sjeremylt   @ref Advanced
1069d1bcdac9Sjeremylt **/
1070d1bcdac9Sjeremylt 
1071692c2638Sjeremylt int CeedOperatorGetFields(CeedOperator op, CeedOperatorField **inputfields,
1072d1bcdac9Sjeremylt                           CeedOperatorField **outputfields) {
107352d6035fSJeremy L Thompson   if (op->composite)
1074c042f62fSJeremy L Thompson     // LCOV_EXCL_START
107552d6035fSJeremy L Thompson     return CeedError(op->ceed, 1, "Not defined for composite operator");
1076c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
107752d6035fSJeremy L Thompson 
1078d1bcdac9Sjeremylt   if (inputfields) *inputfields = op->inputfields;
1079d1bcdac9Sjeremylt   if (outputfields) *outputfields = op->outputfields;
1080d1bcdac9Sjeremylt   return 0;
1081d1bcdac9Sjeremylt }
1082d1bcdac9Sjeremylt 
1083d1bcdac9Sjeremylt /**
10844dccadb6Sjeremylt   @brief Get the L vector CeedTransposeMode of a CeedOperatorField
10854dccadb6Sjeremylt 
10864dccadb6Sjeremylt   @param opfield         CeedOperatorField
10874dccadb6Sjeremylt   @param[out] lmode      Variable to store CeedTransposeMode
10884dccadb6Sjeremylt 
10894dccadb6Sjeremylt   @return An error code: 0 - success, otherwise - failure
10904dccadb6Sjeremylt 
10914dccadb6Sjeremylt   @ref Advanced
10924dccadb6Sjeremylt **/
10934dccadb6Sjeremylt 
10944dccadb6Sjeremylt int CeedOperatorFieldGetLMode(CeedOperatorField opfield,
10954dccadb6Sjeremylt                               CeedTransposeMode *lmode) {
1096fe2413ffSjeremylt   *lmode = opfield->lmode;
10974dccadb6Sjeremylt   return 0;
10982b8e417aSjeremylt }
10992b8e417aSjeremylt 
11002b8e417aSjeremylt /**
1101d1bcdac9Sjeremylt   @brief Get the CeedElemRestriction of a CeedOperatorField
1102d1bcdac9Sjeremylt 
1103d1bcdac9Sjeremylt   @param opfield         CeedOperatorField
1104d1bcdac9Sjeremylt   @param[out] rstr       Variable to store CeedElemRestriction
1105d1bcdac9Sjeremylt 
1106d1bcdac9Sjeremylt   @return An error code: 0 - success, otherwise - failure
1107d1bcdac9Sjeremylt 
1108d1bcdac9Sjeremylt   @ref Advanced
1109d1bcdac9Sjeremylt **/
1110d1bcdac9Sjeremylt 
1111d1bcdac9Sjeremylt int CeedOperatorFieldGetElemRestriction(CeedOperatorField opfield,
1112d1bcdac9Sjeremylt                                         CeedElemRestriction *rstr) {
1113fe2413ffSjeremylt   *rstr = opfield->Erestrict;
1114d1bcdac9Sjeremylt   return 0;
1115d1bcdac9Sjeremylt }
1116d1bcdac9Sjeremylt 
1117d1bcdac9Sjeremylt /**
1118d1bcdac9Sjeremylt   @brief Get the CeedBasis of a CeedOperatorField
1119d1bcdac9Sjeremylt 
1120d1bcdac9Sjeremylt   @param opfield         CeedOperatorField
1121d1bcdac9Sjeremylt   @param[out] basis      Variable to store CeedBasis
1122d1bcdac9Sjeremylt 
1123d1bcdac9Sjeremylt   @return An error code: 0 - success, otherwise - failure
1124d1bcdac9Sjeremylt 
1125d1bcdac9Sjeremylt   @ref Advanced
1126d1bcdac9Sjeremylt **/
1127d1bcdac9Sjeremylt 
1128692c2638Sjeremylt int CeedOperatorFieldGetBasis(CeedOperatorField opfield, CeedBasis *basis) {
1129fe2413ffSjeremylt   *basis = opfield->basis;
1130d1bcdac9Sjeremylt   return 0;
1131d1bcdac9Sjeremylt }
1132d1bcdac9Sjeremylt 
1133d1bcdac9Sjeremylt /**
1134d1bcdac9Sjeremylt   @brief Get the CeedVector of a CeedOperatorField
1135d1bcdac9Sjeremylt 
1136d1bcdac9Sjeremylt   @param opfield         CeedOperatorField
1137d1bcdac9Sjeremylt   @param[out] vec        Variable to store CeedVector
1138d1bcdac9Sjeremylt 
1139d1bcdac9Sjeremylt   @return An error code: 0 - success, otherwise - failure
1140d1bcdac9Sjeremylt 
1141d1bcdac9Sjeremylt   @ref Advanced
1142d1bcdac9Sjeremylt **/
1143d1bcdac9Sjeremylt 
1144692c2638Sjeremylt int CeedOperatorFieldGetVector(CeedOperatorField opfield, CeedVector *vec) {
1145fe2413ffSjeremylt   *vec = opfield->vec;
1146d1bcdac9Sjeremylt   return 0;
1147d1bcdac9Sjeremylt }
1148d1bcdac9Sjeremylt 
1149d1bcdac9Sjeremylt /**
1150b11c1e72Sjeremylt   @brief Destroy a CeedOperator
1151d7b241e6Sjeremylt 
1152d7b241e6Sjeremylt   @param op CeedOperator to destroy
1153b11c1e72Sjeremylt 
1154b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
1155dfdf5a53Sjeremylt 
1156dfdf5a53Sjeremylt   @ref Basic
1157b11c1e72Sjeremylt **/
1158d7b241e6Sjeremylt int CeedOperatorDestroy(CeedOperator *op) {
1159d7b241e6Sjeremylt   int ierr;
1160d7b241e6Sjeremylt 
1161d7b241e6Sjeremylt   if (!*op || --(*op)->refcount > 0) return 0;
1162d7b241e6Sjeremylt   if ((*op)->Destroy) {
1163d7b241e6Sjeremylt     ierr = (*op)->Destroy(*op); CeedChk(ierr);
1164d7b241e6Sjeremylt   }
1165fe2413ffSjeremylt   ierr = CeedDestroy(&(*op)->ceed); CeedChk(ierr);
1166fe2413ffSjeremylt   // Free fields
11671d102b48SJeremy L Thompson   for (int i=0; i<(*op)->nfields; i++)
116852d6035fSJeremy L Thompson     if ((*op)->inputfields[i]) {
116971352a93Sjeremylt       ierr = CeedElemRestrictionDestroy(&(*op)->inputfields[i]->Erestrict);
117071352a93Sjeremylt       CeedChk(ierr);
117171352a93Sjeremylt       if ((*op)->inputfields[i]->basis != CEED_BASIS_COLLOCATED) {
117271352a93Sjeremylt         ierr = CeedBasisDestroy(&(*op)->inputfields[i]->basis); CeedChk(ierr);
117371352a93Sjeremylt       }
117471352a93Sjeremylt       if ((*op)->inputfields[i]->vec != CEED_VECTOR_ACTIVE &&
117571352a93Sjeremylt           (*op)->inputfields[i]->vec != CEED_VECTOR_NONE ) {
117671352a93Sjeremylt         ierr = CeedVectorDestroy(&(*op)->inputfields[i]->vec); CeedChk(ierr);
117771352a93Sjeremylt       }
1178fe2413ffSjeremylt       ierr = CeedFree(&(*op)->inputfields[i]); CeedChk(ierr);
1179fe2413ffSjeremylt     }
11801d102b48SJeremy L Thompson   for (int i=0; i<(*op)->nfields; i++)
1181d0eb30a5Sjeremylt     if ((*op)->outputfields[i]) {
118271352a93Sjeremylt       ierr = CeedElemRestrictionDestroy(&(*op)->outputfields[i]->Erestrict);
118371352a93Sjeremylt       CeedChk(ierr);
118471352a93Sjeremylt       if ((*op)->outputfields[i]->basis != CEED_BASIS_COLLOCATED) {
118571352a93Sjeremylt         ierr = CeedBasisDestroy(&(*op)->outputfields[i]->basis); CeedChk(ierr);
118671352a93Sjeremylt       }
118771352a93Sjeremylt       if ((*op)->outputfields[i]->vec != CEED_VECTOR_ACTIVE &&
118871352a93Sjeremylt           (*op)->outputfields[i]->vec != CEED_VECTOR_NONE ) {
118971352a93Sjeremylt         ierr = CeedVectorDestroy(&(*op)->outputfields[i]->vec); CeedChk(ierr);
119071352a93Sjeremylt       }
1191fe2413ffSjeremylt       ierr = CeedFree(&(*op)->outputfields[i]); CeedChk(ierr);
1192fe2413ffSjeremylt     }
119352d6035fSJeremy L Thompson   // Destroy suboperators
11941d102b48SJeremy L Thompson   for (int i=0; i<(*op)->numsub; i++)
119552d6035fSJeremy L Thompson     if ((*op)->suboperators[i]) {
119652d6035fSJeremy L Thompson       ierr = CeedOperatorDestroy(&(*op)->suboperators[i]); CeedChk(ierr);
119752d6035fSJeremy L Thompson     }
1198d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->qf); CeedChk(ierr);
1199d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->dqf); CeedChk(ierr);
1200d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->dqfT); CeedChk(ierr);
1201fe2413ffSjeremylt 
12025107b09fSJeremy L Thompson   // Destroy fallback
12035107b09fSJeremy L Thompson   if ((*op)->opfallback) {
12045107b09fSJeremy L Thompson     ierr = (*op)->qffallback->Destroy((*op)->qffallback); CeedChk(ierr);
12055107b09fSJeremy L Thompson     ierr = CeedFree(&(*op)->qffallback); CeedChk(ierr);
12065107b09fSJeremy L Thompson     ierr = (*op)->opfallback->Destroy((*op)->opfallback); CeedChk(ierr);
12075107b09fSJeremy L Thompson     ierr = CeedFree(&(*op)->opfallback); CeedChk(ierr);
12085107b09fSJeremy L Thompson   }
12095107b09fSJeremy L Thompson 
1210fe2413ffSjeremylt   ierr = CeedFree(&(*op)->inputfields); CeedChk(ierr);
1211fe2413ffSjeremylt   ierr = CeedFree(&(*op)->outputfields); CeedChk(ierr);
121252d6035fSJeremy L Thompson   ierr = CeedFree(&(*op)->suboperators); CeedChk(ierr);
1213d7b241e6Sjeremylt   ierr = CeedFree(op); CeedChk(ierr);
1214d7b241e6Sjeremylt   return 0;
1215d7b241e6Sjeremylt }
1216d7b241e6Sjeremylt 
1217d7b241e6Sjeremylt /// @}
1218