xref: /libCEED/interface/ceed-operator.c (revision 16911fdad6ca4b1dd37f9d3206958ee664667dbe)
1 // Copyright (c) 2017, Lawrence Livermore National Security, LLC. Produced at
2 // the Lawrence Livermore National Laboratory. LLNL-CODE-734707. All Rights
3 // reserved. See files LICENSE and NOTICE for details.
4 //
5 // This file is part of CEED, a collection of benchmarks, miniapps, software
6 // libraries and APIs for efficient high-order finite element and spectral
7 // element discretizations for exascale applications. For more information and
8 // source code availability see http://github.com/ceed.
9 //
10 // The CEED research is supported by the Exascale Computing Project 17-SC-20-SC,
11 // a collaborative effort of two U.S. Department of Energy organizations (Office
12 // of Science and the National Nuclear Security Administration) responsible for
13 // the planning and preparation of a capable exascale ecosystem, including
14 // software, applications, hardware, advanced system engineering and early
15 // testbed platforms, in support of the nation's exascale computing imperative.
16 
17 #include <ceed-impl.h>
18 #include <ceed-backend.h>
19 #include <string.h>
20 
21 /// @file
22 /// Implementation of public CeedOperator interfaces
23 ///
24 /// @addtogroup CeedOperator
25 ///   @{
26 
27 /**
28   @brief Create a CeedOperator and associate a CeedQFunction. A CeedBasis and
29            CeedElemRestriction can be associated with CeedQFunction fields with
30            \ref CeedOperatorSetField.
31 
32   @param ceed    A Ceed object where the CeedOperator will be created
33   @param qf      QFunction defining the action of the operator at quadrature points
34   @param dqf     QFunction defining the action of the Jacobian of @a qf (or NULL)
35   @param dqfT    QFunction defining the action of the transpose of the Jacobian
36                    of @a qf (or NULL)
37   @param[out] op Address of the variable where the newly created
38                      CeedOperator will be stored
39 
40   @return An error code: 0 - success, otherwise - failure
41 
42   @ref Basic
43  */
44 int CeedOperatorCreate(Ceed ceed, CeedQFunction qf, CeedQFunction dqf,
45                        CeedQFunction dqfT, CeedOperator *op) {
46   int ierr;
47 
48   if (!ceed->OperatorCreate) {
49     Ceed delegate;
50     ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr);
51 
52     if (!delegate)
53       // LCOV_EXCL_START
54       return CeedError(ceed, 1, "Backend does not support OperatorCreate");
55     // LCOV_EXCL_STOP
56 
57     ierr = CeedOperatorCreate(delegate, qf, dqf, dqfT, op); CeedChk(ierr);
58     return 0;
59   }
60 
61   ierr = CeedCalloc(1,op); CeedChk(ierr);
62   (*op)->ceed = ceed;
63   ceed->refcount++;
64   (*op)->refcount = 1;
65   (*op)->qf = qf;
66   qf->refcount++;
67   (*op)->dqf = dqf;
68   if (dqf) dqf->refcount++;
69   (*op)->dqfT = dqfT;
70   if (dqfT) dqfT->refcount++;
71   ierr = CeedCalloc(16, &(*op)->inputfields); CeedChk(ierr);
72   ierr = CeedCalloc(16, &(*op)->outputfields); CeedChk(ierr);
73   ierr = ceed->OperatorCreate(*op); CeedChk(ierr);
74   return 0;
75 }
76 
77 /**
78   @brief Create an operator that composes the action of several operators
79 
80   @param ceed    A Ceed object where the CeedOperator will be created
81   @param[out] op Address of the variable where the newly created
82                      Composite CeedOperator will be stored
83 
84   @return An error code: 0 - success, otherwise - failure
85 
86   @ref Basic
87  */
88 int CeedCompositeOperatorCreate(Ceed ceed, CeedOperator *op) {
89   int ierr;
90 
91   if (!ceed->CompositeOperatorCreate) {
92     Ceed delegate;
93     ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr);
94 
95     if (!delegate)
96       // LCOV_EXCL_START
97       return CeedError(ceed, 1, "Backend does not support "
98                        "CompositeOperatorCreate");
99     // LCOV_EXCL_STOP
100 
101     ierr = CeedCompositeOperatorCreate(delegate, op); CeedChk(ierr);
102     return 0;
103   }
104 
105   ierr = CeedCalloc(1,op); CeedChk(ierr);
106   (*op)->ceed = ceed;
107   ceed->refcount++;
108   (*op)->composite = true;
109   ierr = CeedCalloc(16, &(*op)->suboperators); CeedChk(ierr);
110   ierr = ceed->CompositeOperatorCreate(*op); CeedChk(ierr);
111   return 0;
112 }
113 
114 /**
115   @brief Provide a field to a CeedOperator for use by its CeedQFunction
116 
117   This function is used to specify both active and passive fields to a
118   CeedOperator.  For passive fields, a vector @arg v must be provided.  Passive
119   fields can inputs or outputs (updated in-place when operator is applied).
120 
121   Active fields must be specified using this function, but their data (in a
122   CeedVector) is passed in CeedOperatorApply().  There can be at most one active
123   input and at most one active output.
124 
125   @param op         CeedOperator on which to provide the field
126   @param fieldname  Name of the field (to be matched with the name used by
127                       CeedQFunction)
128   @param r          CeedElemRestriction
129   @param lmode      CeedTransposeMode which specifies the ordering of the
130                       components of the l-vector used by this CeedOperatorField,
131                       CEED_NOTRANSPOSE indicates the component is the
132                       outermost index and CEED_TRANSPOSE indicates the component
133                       is the innermost index in ordering of the l-vector
134   @param b          CeedBasis in which the field resides or CEED_BASIS_COLLOCATED
135                       if collocated with quadrature points
136   @param v          CeedVector to be used by CeedOperator or CEED_VECTOR_ACTIVE
137                       if field is active or CEED_VECTOR_NONE if using
138                       CEED_EVAL_WEIGHT in the QFunction
139 
140   @return An error code: 0 - success, otherwise - failure
141 
142   @ref Basic
143 **/
144 int CeedOperatorSetField(CeedOperator op, const char *fieldname,
145                          CeedElemRestriction r, CeedTransposeMode lmode,
146                          CeedBasis b, CeedVector v) {
147   int ierr;
148   if (op->composite)
149     // LCOV_EXCL_START
150     return CeedError(op->ceed, 1, "Cannot add field to composite operator.");
151   // LCOV_EXCL_STOP
152   if (!r)
153     // LCOV_EXCL_START
154     return CeedError(op->ceed, 1,
155                      "ElemRestriction r for field \"%s\" must be non-NULL.",
156                      fieldname);
157   // LCOV_EXCL_STOP
158   if (!b)
159     // LCOV_EXCL_START
160     return CeedError(op->ceed, 1, "Basis b for field \"%s\" must be non-NULL.",
161                      fieldname);
162   // LCOV_EXCL_STOP
163   if (!v)
164     // LCOV_EXCL_START
165     return CeedError(op->ceed, 1, "Vector v for field \"%s\" must be non-NULL.",
166                      fieldname);
167   // LCOV_EXCL_STOP
168 
169   CeedInt numelements;
170   ierr = CeedElemRestrictionGetNumElements(r, &numelements); CeedChk(ierr);
171   if (op->hasrestriction && op->numelements != numelements)
172     // LCOV_EXCL_START
173     return CeedError(op->ceed, 1,
174                      "ElemRestriction with %d elements incompatible with prior "
175                      "%d elements", numelements, op->numelements);
176   // LCOV_EXCL_STOP
177   op->numelements = numelements;
178   op->hasrestriction = true; // Restriction set, but numelements may be 0
179 
180   if (b != CEED_BASIS_COLLOCATED) {
181     CeedInt numqpoints;
182     ierr = CeedBasisGetNumQuadraturePoints(b, &numqpoints); CeedChk(ierr);
183     if (op->numqpoints && op->numqpoints != numqpoints)
184       // LCOV_EXCL_START
185       return CeedError(op->ceed, 1, "Basis with %d quadrature points "
186                        "incompatible with prior %d points", numqpoints,
187                        op->numqpoints);
188     // LCOV_EXCL_STOP
189     op->numqpoints = numqpoints;
190   }
191   CeedOperatorField *ofield;
192   for (CeedInt i=0; i<op->qf->numinputfields; i++) {
193     if (!strcmp(fieldname, (*op->qf->inputfields[i]).fieldname)) {
194       ofield = &op->inputfields[i];
195       goto found;
196     }
197   }
198   for (CeedInt i=0; i<op->qf->numoutputfields; i++) {
199     if (!strcmp(fieldname, (*op->qf->outputfields[i]).fieldname)) {
200       ofield = &op->outputfields[i];
201       goto found;
202     }
203   }
204   // LCOV_EXCL_START
205   return CeedError(op->ceed, 1, "QFunction has no knowledge of field '%s'",
206                    fieldname);
207   // LCOV_EXCL_STOP
208 found:
209   ierr = CeedCalloc(1, ofield); CeedChk(ierr);
210   (*ofield)->Erestrict = r;
211   r->refcount += 1;
212   (*ofield)->lmode = lmode;
213   (*ofield)->basis = b;
214   if (b != CEED_BASIS_COLLOCATED)
215     b->refcount += 1;
216   (*ofield)->vec = v;
217   if (v != CEED_VECTOR_ACTIVE && v != CEED_VECTOR_NONE)
218     v->refcount += 1;
219   op->nfields += 1;
220   return 0;
221 }
222 
223 /**
224   @brief Add a sub-operator to a composite CeedOperator
225 
226   @param[out] compositeop Address of the composite CeedOperator
227   @param      subop       Address of the sub-operator CeedOperator
228 
229   @return An error code: 0 - success, otherwise - failure
230 
231   @ref Basic
232  */
233 int CeedCompositeOperatorAddSub(CeedOperator compositeop, CeedOperator subop) {
234   if (!compositeop->composite)
235     // LCOV_EXCL_START
236     return CeedError(compositeop->ceed, 1, "CeedOperator is not a composite "
237                      "operator");
238   // LCOV_EXCL_STOP
239 
240   if (compositeop->numsub == CEED_COMPOSITE_MAX)
241     // LCOV_EXCL_START
242     return CeedError(compositeop->ceed, 1, "Cannot add additional suboperators");
243   // LCOV_EXCL_STOP
244 
245   compositeop->suboperators[compositeop->numsub] = subop;
246   subop->refcount++;
247   compositeop->numsub++;
248   return 0;
249 }
250 
251 /**
252   @brief Assemble a linear CeedQFunction associated with a CeedOperator
253 
254   This returns a CeedVector containing a matrix at each quadrature point
255     providing the action of the CeedQFunction associated with the CeedOperator.
256     The vector 'assembled' is of shape
257       [num_elements, num_input_fields, num_output_fields, num_quad_points]
258     and contains column-major matrices representing the action of the
259     CeedQFunction for a corresponding quadrature point on an element. Inputs and
260     outputs are in the order provided by the user when adding CeedOperator fields.
261     For example, a QFunction with inputs 'u' and 'gradu' and outputs 'gradv' and
262     'v', provided in that order, would result in an assembled QFunction that
263     consists of (1 + dim) x (dim + 1) matrices at each quadrature point acting
264     on the input [u, du_0, du_1] and producing the output [dv_0, dv_1, v].
265 
266   @param op             CeedOperator to assemble CeedQFunction
267   @param[out] assembled CeedVector to store assembled CeedQFunction at
268                           quadrature points
269   @param[out] rstr      CeedElemRestriction for CeedVector containing assembled
270                           CeedQFunction
271   @param request        Address of CeedRequest for non-blocking completion, else
272                           CEED_REQUEST_IMMEDIATE
273 
274   @return An error code: 0 - success, otherwise - failure
275 
276   @ref Basic
277 **/
278 int CeedOperatorAssembleLinearQFunction(CeedOperator op, CeedVector *assembled,
279                                         CeedElemRestriction *rstr,
280                                         CeedRequest *request) {
281   int ierr;
282   Ceed ceed = op->ceed;
283   CeedQFunction qf = op->qf;
284 
285   if (op->composite) {
286     // LCOV_EXCL_START
287     return CeedError(ceed, 1, "Cannot assemble QFunction for composite operator");
288     // LCOV_EXCL_STOP
289   } else {
290     if (op->nfields == 0)
291       // LCOV_EXCL_START
292       return CeedError(ceed, 1, "No operator fields set");
293     // LCOV_EXCL_STOP
294     if (op->nfields < qf->numinputfields + qf->numoutputfields)
295       // LCOV_EXCL_START
296       return CeedError( ceed, 1, "Not all operator fields set");
297     // LCOV_EXCL_STOP
298     if (!op->hasrestriction)
299       // LCOV_EXCL_START
300       return CeedError(ceed, 1, "At least one restriction required");
301     // LCOV_EXCL_STOP
302     if (op->numqpoints == 0)
303       // LCOV_EXCL_START
304       return CeedError(ceed, 1, "At least one non-collocated basis required");
305     // LCOV_EXCL_STOP
306   }
307   ierr = op->AssembleLinearQFunction(op, assembled, rstr, request);
308   CeedChk(ierr);
309   return 0;
310 }
311 
312 /**
313   @brief Assemble the diagonal of a square linear Operator
314 
315   This returns a CeedVector containing the diagonal of a linear CeedOperator.
316 
317   @param op             CeedOperator to assemble CeedQFunction
318   @param[out] assembled CeedVector to store assembled CeedOperator diagonal
319   @param request        Address of CeedRequest for non-blocking completion, else
320                           CEED_REQUEST_IMMEDIATE
321 
322   @return An error code: 0 - success, otherwise - failure
323 
324   @ref Basic
325 **/
326 int CeedOperatorAssembleLinearDiagonal(CeedOperator op, CeedVector *assembled,
327                                        CeedRequest *request) {
328   int ierr;
329   Ceed ceed = op->ceed;
330   CeedQFunction qf = op->qf;
331 
332   if (op->composite) {
333     // LCOV_EXCL_START
334     return CeedError(ceed, 1, "Cannot assemble QFunction for composite operator");
335     // LCOV_EXCL_STOP
336   } else {
337     if (op->nfields == 0)
338       // LCOV_EXCL_START
339       return CeedError(ceed, 1, "No operator fields set");
340     // LCOV_EXCL_STOP
341     if (op->nfields < qf->numinputfields + qf->numoutputfields)
342       // LCOV_EXCL_START
343       return CeedError( ceed, 1, "Not all operator fields set");
344     // LCOV_EXCL_STOP
345     if (!op->hasrestriction)
346       // LCOV_EXCL_START
347       return CeedError(ceed, 1, "At least one restriction required");
348     // LCOV_EXCL_STOP
349     if (op->numqpoints == 0)
350       // LCOV_EXCL_START
351       return CeedError(ceed, 1, "At least one non-collocated basis required");
352     // LCOV_EXCL_STOP
353   }
354 
355   // Use backend version, if available
356   if (op->AssembleLinearDiagonal) {
357     ierr = op->AssembleLinearDiagonal(op, assembled, request); CeedChk(ierr);
358     return 0;
359   }
360 
361   // Assemble QFunction
362   CeedVector assembledqf;
363   CeedElemRestriction rstr;
364   ierr = CeedOperatorAssembleLinearQFunction(op,  &assembledqf, &rstr, request);
365   CeedChk(ierr);
366   ierr = CeedElemRestrictionDestroy(&rstr); CeedChk(ierr);
367 
368   // Determine active input basis
369   CeedInt numemodein = 0, ncomp, dim = 1;
370   CeedEvalMode *emodein = NULL;
371   CeedBasis basisin = NULL;
372   CeedElemRestriction rstrin = NULL;
373   for (CeedInt i=0; i<qf->numinputfields; i++)
374     if (op->inputfields[i]->vec == CEED_VECTOR_ACTIVE) {
375       ierr = CeedOperatorFieldGetBasis(op->inputfields[i], &basisin);
376       CeedChk(ierr);
377       ierr = CeedBasisGetNumComponents(basisin, &ncomp); CeedChk(ierr);
378       ierr = CeedBasisGetDimension(basisin, &dim); CeedChk(ierr);
379       ierr = CeedOperatorFieldGetElemRestriction(op->inputfields[i], &rstrin);
380       CeedChk(ierr);
381       CeedEvalMode emode;
382       ierr = CeedQFunctionFieldGetEvalMode(qf->inputfields[i], &emode);
383       CeedChk(ierr);
384       switch (emode) {
385       case CEED_EVAL_NONE:
386       case CEED_EVAL_INTERP:
387         ierr = CeedRealloc(numemodein + 1, &emodein); CeedChk(ierr);
388         emodein[numemodein] = emode;
389         numemodein += 1;
390         break;
391       case CEED_EVAL_GRAD:
392         ierr = CeedRealloc(numemodein + dim, &emodein); CeedChk(ierr);
393         for (CeedInt d=0; d<dim; d++)
394           emodein[numemodein+d] = emode;
395         numemodein += dim;
396         break;
397       case CEED_EVAL_WEIGHT:
398       case CEED_EVAL_DIV:
399       case CEED_EVAL_CURL:
400         break; // Caught by QF Assembly
401       }
402     }
403 
404   // Determine active output basis
405   CeedInt numemodeout = 0;
406   CeedEvalMode *emodeout = NULL;
407   CeedBasis basisout = NULL;
408   CeedElemRestriction rstrout = NULL;
409   CeedTransposeMode lmodeout = CEED_NOTRANSPOSE;
410   for (CeedInt i=0; i<qf->numoutputfields; i++)
411     if (op->outputfields[i]->vec == CEED_VECTOR_ACTIVE) {
412       ierr = CeedOperatorFieldGetBasis(op->outputfields[i], &basisout);
413       CeedChk(ierr);
414       ierr = CeedOperatorFieldGetElemRestriction(op->outputfields[i], &rstrout);
415       CeedChk(ierr);
416       ierr = CeedOperatorFieldGetLMode(op->outputfields[i], &lmodeout);
417       CeedChk(ierr);
418       CeedEvalMode emode;
419       ierr = CeedQFunctionFieldGetEvalMode(qf->outputfields[i], &emode);
420       CeedChk(ierr);
421       switch (emode) {
422       case CEED_EVAL_NONE:
423       case CEED_EVAL_INTERP:
424         ierr = CeedRealloc(numemodeout + 1, &emodeout); CeedChk(ierr);
425         emodeout[numemodeout] = emode;
426         numemodeout += 1;
427         break;
428       case CEED_EVAL_GRAD:
429         ierr = CeedRealloc(numemodeout + dim, &emodeout); CeedChk(ierr);
430         for (CeedInt d=0; d<dim; d++)
431           emodeout[numemodeout+d] = emode;
432         numemodeout += dim;
433         break;
434       case CEED_EVAL_WEIGHT:
435       case CEED_EVAL_DIV:
436       case CEED_EVAL_CURL:
437         break; // Caught by QF Assembly
438       }
439     }
440 
441   // Create diagonal vector
442   CeedVector elemdiag;
443   ierr = CeedElemRestrictionCreateVector(rstrin, assembled, &elemdiag);
444   CeedChk(ierr);
445 
446   // Assemble element operator diagonals
447   CeedScalar *elemdiagarray, *assembledqfarray;
448   ierr = CeedVectorSetValue(elemdiag, 0.0); CeedChk(ierr);
449   ierr = CeedVectorGetArray(elemdiag, CEED_MEM_HOST, &elemdiagarray);
450   CeedChk(ierr);
451   ierr = CeedVectorGetArray(assembledqf, CEED_MEM_HOST, &assembledqfarray);
452   CeedChk(ierr);
453   CeedInt nelem, nnodes, nqpts;
454   ierr = CeedElemRestrictionGetNumElements(rstrin, &nelem); CeedChk(ierr);
455   ierr = CeedBasisGetNumNodes(basisin, &nnodes); CeedChk(ierr);
456   ierr = CeedBasisGetNumQuadraturePoints(basisin, &nqpts); CeedChk(ierr);
457   // Compute the diagonal of B^T D B
458   // Each node, qpt pair
459   for (CeedInt n=0; n<nnodes; n++)
460     for (CeedInt q=0; q<nqpts; q++) {
461       CeedInt dout = -1;
462       // Each basis eval mode pair
463       for (CeedInt eout=0; eout<numemodeout; eout++) {
464         CeedScalar bt = 1.0;
465         if (emodeout[eout] == CEED_EVAL_GRAD)
466           dout += 1;
467         ierr = CeedBasisGetValue(basisout, emodeout[eout], q, n, dout, &bt);
468         CeedChk(ierr);
469         CeedInt din = -1;
470         for (CeedInt ein=0; ein<numemodein; ein++) {
471           CeedScalar b = 0.0;
472           if (emodein[ein] == CEED_EVAL_GRAD)
473             din += 1;
474           ierr = CeedBasisGetValue(basisin, emodein[ein], q, n, din, &b);
475           CeedChk(ierr);
476           // Each element and component
477           for (CeedInt e=0; e<nelem; e++)
478             for (CeedInt cout=0; cout<ncomp; cout++) {
479               CeedScalar db = 0.0;
480               for (CeedInt cin=0; cin<ncomp; cin++)
481                 db += assembledqfarray[((((e*numemodein+ein)*ncomp+cin)*
482                                          numemodeout+eout)*ncomp+cout)*nqpts+q]*b;
483               elemdiagarray[(e*ncomp+cout)*nnodes+n] += bt * db;
484             }
485         }
486       }
487     }
488 
489   ierr = CeedVectorRestoreArray(elemdiag, &elemdiagarray); CeedChk(ierr);
490   ierr = CeedVectorRestoreArray(assembledqf, &assembledqfarray); CeedChk(ierr);
491 
492   // Assemble local operator diagonal
493   ierr = CeedVectorSetValue(*assembled, 0.0); CeedChk(ierr);
494   ierr = CeedElemRestrictionApply(rstrout, CEED_TRANSPOSE, lmodeout, elemdiag,
495                                   *assembled, request); CeedChk(ierr);
496 
497   // Cleanup
498   ierr = CeedVectorDestroy(&assembledqf); CeedChk(ierr);
499   ierr = CeedVectorDestroy(&elemdiag); CeedChk(ierr);
500   ierr = CeedFree(&emodein); CeedChk(ierr);
501   ierr = CeedFree(&emodeout); CeedChk(ierr);
502 
503   return 0;
504 }
505 
506 /**
507   @brief Apply CeedOperator to a vector
508 
509   This computes the action of the operator on the specified (active) input,
510   yielding its (active) output.  All inputs and outputs must be specified using
511   CeedOperatorSetField().
512 
513   @param op        CeedOperator to apply
514   @param[in] in    CeedVector containing input state or NULL if there are no
515                      active inputs
516   @param[out] out  CeedVector to store result of applying operator (must be
517                      distinct from @a in) or NULL if there are no active outputs
518   @param request   Address of CeedRequest for non-blocking completion, else
519                      CEED_REQUEST_IMMEDIATE
520 
521   @return An error code: 0 - success, otherwise - failure
522 
523   @ref Basic
524 **/
525 int CeedOperatorApply(CeedOperator op, CeedVector in, CeedVector out,
526                       CeedRequest *request) {
527   int ierr;
528   Ceed ceed = op->ceed;
529   CeedQFunction qf = op->qf;
530 
531   if (op->composite) {
532     if (!op->numsub)
533       // LCOV_EXCL_START
534       return CeedError(ceed, 1, "No suboperators set");
535     // LCOV_EXCL_STOP
536   } else {
537     if (op->nfields == 0)
538       // LCOV_EXCL_START
539       return CeedError(ceed, 1, "No operator fields set");
540     // LCOV_EXCL_STOP
541     if (op->nfields < qf->numinputfields + qf->numoutputfields)
542       // LCOV_EXCL_START
543       return CeedError(ceed, 1, "Not all operator fields set");
544     // LCOV_EXCL_STOP
545     if (!op->hasrestriction)
546       // LCOV_EXCL_START
547       return CeedError(ceed, 1,"At least one restriction required");
548     // LCOV_EXCL_STOP
549     if (op->numqpoints == 0)
550       // LCOV_EXCL_START
551       return CeedError(ceed, 1,"At least one non-collocated basis required");
552     // LCOV_EXCL_STOP
553   }
554   if (op->numelements || op->composite) {
555     ierr = op->Apply(op, in, out, request); CeedChk(ierr);
556   }
557   return 0;
558 }
559 
560 /**
561   @brief Get the Ceed associated with a CeedOperator
562 
563   @param op              CeedOperator
564   @param[out] ceed       Variable to store Ceed
565 
566   @return An error code: 0 - success, otherwise - failure
567 
568   @ref Advanced
569 **/
570 
571 int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) {
572   *ceed = op->ceed;
573   return 0;
574 }
575 
576 /**
577   @brief Get the number of elements associated with a CeedOperator
578 
579   @param op              CeedOperator
580   @param[out] numelem    Variable to store number of elements
581 
582   @return An error code: 0 - success, otherwise - failure
583 
584   @ref Advanced
585 **/
586 
587 int CeedOperatorGetNumElements(CeedOperator op, CeedInt *numelem) {
588   if (op->composite)
589     // LCOV_EXCL_START
590     return CeedError(op->ceed, 1, "Not defined for composite operator");
591   // LCOV_EXCL_STOP
592 
593   *numelem = op->numelements;
594   return 0;
595 }
596 
597 /**
598   @brief Get the number of quadrature points associated with a CeedOperator
599 
600   @param op              CeedOperator
601   @param[out] numqpts    Variable to store vector number of quadrature points
602 
603   @return An error code: 0 - success, otherwise - failure
604 
605   @ref Advanced
606 **/
607 
608 int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *numqpts) {
609   if (op->composite)
610     // LCOV_EXCL_START
611     return CeedError(op->ceed, 1, "Not defined for composite operator");
612   // LCOV_EXCL_STOP
613 
614   *numqpts = op->numqpoints;
615   return 0;
616 }
617 
618 /**
619   @brief Get the number of arguments associated with a CeedOperator
620 
621   @param op              CeedOperator
622   @param[out] numargs    Variable to store vector number of arguments
623 
624   @return An error code: 0 - success, otherwise - failure
625 
626   @ref Advanced
627 **/
628 
629 int CeedOperatorGetNumArgs(CeedOperator op, CeedInt *numargs) {
630   if (op->composite)
631     // LCOV_EXCL_START
632     return CeedError(op->ceed, 1, "Not defined for composite operators");
633   // LCOV_EXCL_STOP
634 
635   *numargs = op->nfields;
636   return 0;
637 }
638 
639 /**
640   @brief Get the setup status of a CeedOperator
641 
642   @param op             CeedOperator
643   @param[out] setupdone Variable to store setup status
644 
645   @return An error code: 0 - success, otherwise - failure
646 
647   @ref Advanced
648 **/
649 
650 int CeedOperatorGetSetupStatus(CeedOperator op, bool *setupdone) {
651   *setupdone = op->setupdone;
652   return 0;
653 }
654 
655 /**
656   @brief Get the QFunction associated with a CeedOperator
657 
658   @param op              CeedOperator
659   @param[out] qf         Variable to store QFunction
660 
661   @return An error code: 0 - success, otherwise - failure
662 
663   @ref Advanced
664 **/
665 
666 int CeedOperatorGetQFunction(CeedOperator op, CeedQFunction *qf) {
667   if (op->composite)
668     // LCOV_EXCL_START
669     return CeedError(op->ceed, 1, "Not defined for composite operator");
670   // LCOV_EXCL_STOP
671 
672   *qf = op->qf;
673   return 0;
674 }
675 
676 /**
677   @brief Get the number of suboperators associated with a CeedOperator
678 
679   @param op              CeedOperator
680   @param[out] numsub     Variable to store number of suboperators
681 
682   @return An error code: 0 - success, otherwise - failure
683 
684   @ref Advanced
685 **/
686 
687 int CeedOperatorGetNumSub(CeedOperator op, CeedInt *numsub) {
688   if (!op->composite)
689     // LCOV_EXCL_START
690     return CeedError(op->ceed, 1, "Not a composite operator");
691   // LCOV_EXCL_STOP
692 
693   *numsub = op->numsub;
694   return 0;
695 }
696 
697 /**
698   @brief Get the list of suboperators associated with a CeedOperator
699 
700   @param op                CeedOperator
701   @param[out] suboperators Variable to store list of suboperators
702 
703   @return An error code: 0 - success, otherwise - failure
704 
705   @ref Advanced
706 **/
707 
708 int CeedOperatorGetSubList(CeedOperator op, CeedOperator **suboperators) {
709   if (!op->composite)
710     // LCOV_EXCL_START
711     return CeedError(op->ceed, 1, "Not a composite operator");
712   // LCOV_EXCL_STOP
713 
714   *suboperators = op->suboperators;
715   return 0;
716 }
717 
718 /**
719   @brief Set the backend data of a CeedOperator
720 
721   @param[out] op         CeedOperator
722   @param data            Data to set
723 
724   @return An error code: 0 - success, otherwise - failure
725 
726   @ref Advanced
727 **/
728 
729 int CeedOperatorSetData(CeedOperator op, void **data) {
730   op->data = *data;
731   return 0;
732 }
733 
734 /**
735   @brief Get the backend data of a CeedOperator
736 
737   @param op              CeedOperator
738   @param[out] data       Variable to store data
739 
740   @return An error code: 0 - success, otherwise - failure
741 
742   @ref Advanced
743 **/
744 
745 int CeedOperatorGetData(CeedOperator op, void **data) {
746   *data = op->data;
747   return 0;
748 }
749 
750 /**
751   @brief Set the setup flag of a CeedOperator to True
752 
753   @param op              CeedOperator
754 
755   @return An error code: 0 - success, otherwise - failure
756 
757   @ref Advanced
758 **/
759 
760 int CeedOperatorSetSetupDone(CeedOperator op) {
761   op->setupdone = 1;
762   return 0;
763 }
764 
765 /**
766   @brief Get the CeedOperatorFields of a CeedOperator
767 
768   @param op                 CeedOperator
769   @param[out] inputfields   Variable to store inputfields
770   @param[out] outputfields  Variable to store outputfields
771 
772   @return An error code: 0 - success, otherwise - failure
773 
774   @ref Advanced
775 **/
776 
777 int CeedOperatorGetFields(CeedOperator op, CeedOperatorField **inputfields,
778                           CeedOperatorField **outputfields) {
779   if (op->composite)
780     // LCOV_EXCL_START
781     return CeedError(op->ceed, 1, "Not defined for composite operator");
782   // LCOV_EXCL_STOP
783 
784   if (inputfields) *inputfields = op->inputfields;
785   if (outputfields) *outputfields = op->outputfields;
786   return 0;
787 }
788 
789 /**
790   @brief Get the L vector CeedTransposeMode of a CeedOperatorField
791 
792   @param opfield         CeedOperatorField
793   @param[out] lmode      Variable to store CeedTransposeMode
794 
795   @return An error code: 0 - success, otherwise - failure
796 
797   @ref Advanced
798 **/
799 
800 int CeedOperatorFieldGetLMode(CeedOperatorField opfield,
801                               CeedTransposeMode *lmode) {
802   *lmode = opfield->lmode;
803   return 0;
804 }
805 
806 /**
807   @brief Get the CeedElemRestriction of a CeedOperatorField
808 
809   @param opfield         CeedOperatorField
810   @param[out] rstr       Variable to store CeedElemRestriction
811 
812   @return An error code: 0 - success, otherwise - failure
813 
814   @ref Advanced
815 **/
816 
817 int CeedOperatorFieldGetElemRestriction(CeedOperatorField opfield,
818                                         CeedElemRestriction *rstr) {
819   *rstr = opfield->Erestrict;
820   return 0;
821 }
822 
823 /**
824   @brief Get the CeedBasis of a CeedOperatorField
825 
826   @param opfield         CeedOperatorField
827   @param[out] basis      Variable to store CeedBasis
828 
829   @return An error code: 0 - success, otherwise - failure
830 
831   @ref Advanced
832 **/
833 
834 int CeedOperatorFieldGetBasis(CeedOperatorField opfield, CeedBasis *basis) {
835   *basis = opfield->basis;
836   return 0;
837 }
838 
839 /**
840   @brief Get the CeedVector of a CeedOperatorField
841 
842   @param opfield         CeedOperatorField
843   @param[out] vec        Variable to store CeedVector
844 
845   @return An error code: 0 - success, otherwise - failure
846 
847   @ref Advanced
848 **/
849 
850 int CeedOperatorFieldGetVector(CeedOperatorField opfield, CeedVector *vec) {
851   *vec = opfield->vec;
852   return 0;
853 }
854 
855 /**
856   @brief Destroy a CeedOperator
857 
858   @param op CeedOperator to destroy
859 
860   @return An error code: 0 - success, otherwise - failure
861 
862   @ref Basic
863 **/
864 int CeedOperatorDestroy(CeedOperator *op) {
865   int ierr;
866 
867   if (!*op || --(*op)->refcount > 0) return 0;
868   if ((*op)->Destroy) {
869     ierr = (*op)->Destroy(*op); CeedChk(ierr);
870   }
871   ierr = CeedDestroy(&(*op)->ceed); CeedChk(ierr);
872   // Free fields
873   for (int i=0; i<(*op)->nfields; i++)
874     if ((*op)->inputfields[i]) {
875       ierr = CeedElemRestrictionDestroy(&(*op)->inputfields[i]->Erestrict);
876       CeedChk(ierr);
877       if ((*op)->inputfields[i]->basis != CEED_BASIS_COLLOCATED) {
878         ierr = CeedBasisDestroy(&(*op)->inputfields[i]->basis); CeedChk(ierr);
879       }
880       if ((*op)->inputfields[i]->vec != CEED_VECTOR_ACTIVE &&
881           (*op)->inputfields[i]->vec != CEED_VECTOR_NONE ) {
882         ierr = CeedVectorDestroy(&(*op)->inputfields[i]->vec); CeedChk(ierr);
883       }
884       ierr = CeedFree(&(*op)->inputfields[i]); CeedChk(ierr);
885     }
886   for (int i=0; i<(*op)->nfields; i++)
887     if ((*op)->outputfields[i]) {
888       ierr = CeedElemRestrictionDestroy(&(*op)->outputfields[i]->Erestrict);
889       CeedChk(ierr);
890       if ((*op)->outputfields[i]->basis != CEED_BASIS_COLLOCATED) {
891         ierr = CeedBasisDestroy(&(*op)->outputfields[i]->basis); CeedChk(ierr);
892       }
893       if ((*op)->outputfields[i]->vec != CEED_VECTOR_ACTIVE &&
894           (*op)->outputfields[i]->vec != CEED_VECTOR_NONE ) {
895         ierr = CeedVectorDestroy(&(*op)->outputfields[i]->vec); CeedChk(ierr);
896       }
897       ierr = CeedFree(&(*op)->outputfields[i]); CeedChk(ierr);
898     }
899   // Destroy suboperators
900   for (int i=0; i<(*op)->numsub; i++)
901     if ((*op)->suboperators[i]) {
902       ierr = CeedOperatorDestroy(&(*op)->suboperators[i]); CeedChk(ierr);
903     }
904   ierr = CeedQFunctionDestroy(&(*op)->qf); CeedChk(ierr);
905   ierr = CeedQFunctionDestroy(&(*op)->dqf); CeedChk(ierr);
906   ierr = CeedQFunctionDestroy(&(*op)->dqfT); CeedChk(ierr);
907 
908   ierr = CeedFree(&(*op)->inputfields); CeedChk(ierr);
909   ierr = CeedFree(&(*op)->outputfields); CeedChk(ierr);
910   ierr = CeedFree(&(*op)->suboperators); CeedChk(ierr);
911   ierr = CeedFree(op); CeedChk(ierr);
912   return 0;
913 }
914 
915 /// @}
916