xref: /libCEED/interface/ceed-operator.c (revision b7ec98d8959851803d838dd4fd11ad111e0096dd)
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->numelements && 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 
179   if (b != CEED_BASIS_COLLOCATED) {
180     CeedInt numqpoints;
181     ierr = CeedBasisGetNumQuadraturePoints(b, &numqpoints); CeedChk(ierr);
182     if (op->numqpoints && op->numqpoints != numqpoints)
183       // LCOV_EXCL_START
184       return CeedError(op->ceed, 1, "Basis with %d quadrature points "
185                        "incompatible with prior %d points", numqpoints,
186                        op->numqpoints);
187     // LCOV_EXCL_STOP
188     op->numqpoints = numqpoints;
189   }
190   CeedOperatorField *ofield;
191   for (CeedInt i=0; i<op->qf->numinputfields; i++) {
192     if (!strcmp(fieldname, (*op->qf->inputfields[i]).fieldname)) {
193       ofield = &op->inputfields[i];
194       goto found;
195     }
196   }
197   for (CeedInt i=0; i<op->qf->numoutputfields; i++) {
198     if (!strcmp(fieldname, (*op->qf->outputfields[i]).fieldname)) {
199       ofield = &op->outputfields[i];
200       goto found;
201     }
202   }
203   // LCOV_EXCL_START
204   return CeedError(op->ceed, 1, "QFunction has no knowledge of field '%s'",
205                    fieldname);
206   // LCOV_EXCL_STOP
207 found:
208   ierr = CeedCalloc(1, ofield); CeedChk(ierr);
209   (*ofield)->Erestrict = r;
210   r->refcount += 1;
211   (*ofield)->lmode = lmode;
212   (*ofield)->basis = b;
213   if (b != CEED_BASIS_COLLOCATED)
214     b->refcount += 1;
215   (*ofield)->vec = v;
216   if (v != CEED_VECTOR_ACTIVE && v != CEED_VECTOR_NONE)
217     v->refcount += 1;
218   op->nfields += 1;
219   return 0;
220 }
221 
222 /**
223   @brief Add a sub-operator to a composite CeedOperator
224 
225   @param[out] compositeop Address of the composite CeedOperator
226   @param      subop       Address of the sub-operator CeedOperator
227 
228   @return An error code: 0 - success, otherwise - failure
229 
230   @ref Basic
231  */
232 int CeedCompositeOperatorAddSub(CeedOperator compositeop,
233                                 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, CeedRequest *request) {
280   int ierr;
281   Ceed ceed = op->ceed;
282   CeedQFunction qf = op->qf;
283 
284   if (op->composite) {
285     // LCOV_EXCL_START
286     return CeedError(ceed, 1, "Cannot assemble QFunction for composite operator");
287     // LCOV_EXCL_STOP
288   } else {
289     if (op->nfields == 0)
290       // LCOV_EXCL_START
291       return CeedError(ceed, 1, "No operator fields set");
292       // LCOV_EXCL_STOP
293     if (op->nfields < qf->numinputfields + qf->numoutputfields)
294       // LCOV_EXCL_START
295       return CeedError( ceed, 1, "Not all operator fields set");
296     // LCOV_EXCL_STOP
297     if (op->numelements == 0)
298       // LCOV_EXCL_START
299       return CeedError(ceed, 1, "At least one restriction required");
300     // LCOV_EXCL_STOP
301     if (op->numqpoints == 0)
302       // LCOV_EXCL_START
303       return CeedError(ceed, 1, "At least one non-collocated basis required");
304     // LCOV_EXCL_STOP
305   }
306   ierr = op->AssembleLinearQFunction(op, assembled, rstr, request);
307   CeedChk(ierr);
308   return 0;
309 }
310 
311 /**
312   @brief Assemble the diagonal of a square linear Operator
313 
314   This returns a CeedVector containing the diagonal of a linear CeedOperator.
315 
316   @param op             CeedOperator to assemble CeedQFunction
317   @param[out] assembled CeedVector to store assembled CeedOperator diagonal
318   @param request        Address of CeedRequest for non-blocking completion, else
319                           CEED_REQUEST_IMMEDIATE
320 
321   @return An error code: 0 - success, otherwise - failure
322 
323   @ref Basic
324 **/
325 int CeedOperatorAssembleLinearDiagonal(CeedOperator op,
326     CeedVector *assembled, CeedRequest *request) {
327   int ierr;
328   Ceed ceed = op->ceed;
329   CeedQFunction qf = op->qf;
330 
331   if (op->composite) {
332     // LCOV_EXCL_START
333     return CeedError(ceed, 1, "Cannot assemble QFunction for composite operator");
334   // LCOV_EXCL_STOP
335   } else {
336     if (op->nfields == 0)
337       // LCOV_EXCL_START
338       return CeedError(ceed, 1, "No operator fields set");
339     // LCOV_EXCL_STOP
340     if (op->nfields < qf->numinputfields + qf->numoutputfields)
341       // LCOV_EXCL_START
342       return CeedError( ceed, 1, "Not all operator fields set");
343     // LCOV_EXCL_STOP
344     if (op->numelements == 0)
345       // LCOV_EXCL_START
346       return CeedError(ceed, 1, "At least one restriction required");
347     // LCOV_EXCL_STOP
348     if (op->numqpoints == 0)
349       // LCOV_EXCL_START
350       return CeedError(ceed, 1, "At least one non-collocated basis required");
351     // LCOV_EXCL_STOP
352   }
353 
354   // Use backend version, if available
355   if (op->AssembleLinearDiagonal) {
356     ierr = op->AssembleLinearDiagonal(op, assembled, request); CeedChk(ierr);
357     return 0;
358   }
359 
360   // Assemble QFunction
361   CeedVector assembledqf;
362   CeedElemRestriction rstr;
363   ierr = CeedOperatorAssembleLinearQFunction(op,  &assembledqf, &rstr, request);
364   CeedChk(ierr);
365   ierr = CeedElemRestrictionDestroy(&rstr); CeedChk(ierr);
366 
367   // Determine active input basis
368   CeedInt numemodein = 0, ncomp, dim;
369   CeedEvalMode *emodein = NULL;
370   CeedBasis basisin;
371   CeedElemRestriction rstrin;
372   for (CeedInt i=0; i<qf->numinputfields; i++)
373     if (op->inputfields[i]->vec == CEED_VECTOR_ACTIVE) {
374       ierr = CeedOperatorFieldGetBasis(op->inputfields[i], &basisin);
375       CeedChk(ierr);
376       ierr = CeedBasisGetNumComponents(basisin, &ncomp); CeedChk(ierr);
377       ierr = CeedBasisGetDimension(basisin, &dim); CeedChk(ierr);
378       ierr = CeedOperatorFieldGetElemRestriction(op->inputfields[i], &rstrin);
379       CeedChk(ierr);
380       CeedEvalMode emode;
381       ierr = CeedQFunctionFieldGetEvalMode(qf->inputfields[i], &emode);
382       CeedChk(ierr);
383       switch (emode) {
384       case CEED_EVAL_NONE:
385       case CEED_EVAL_INTERP:
386         ierr = CeedRealloc(numemodein + 1, &emodein); CeedChk(ierr);
387         emodein[numemodein] = emode;
388         numemodein += 1;
389         break;
390       case CEED_EVAL_GRAD:
391         ierr = CeedRealloc(numemodein + dim, &emodein); CeedChk(ierr);
392         for (CeedInt d=0; d<dim; d++)
393           emodein[numemodein+d] = emode;
394         numemodein += dim;
395         break;
396       case CEED_EVAL_WEIGHT:
397       case CEED_EVAL_DIV:
398       case CEED_EVAL_CURL:
399         break; // Caught by QF Assembly
400       }
401     }
402 
403   // Determine active output basis
404   CeedInt numemodeout = 0;
405   CeedEvalMode *emodeout = NULL;
406   CeedBasis basisout;
407   CeedElemRestriction rstrout;
408   CeedTransposeMode lmodeout;
409   for (CeedInt i=0; i<qf->numoutputfields; i++)
410     if (op->outputfields[i]->vec == CEED_VECTOR_ACTIVE) {
411       ierr = CeedOperatorFieldGetBasis(op->outputfields[i], &basisout);
412       CeedChk(ierr);
413       ierr = CeedOperatorFieldGetElemRestriction(op->outputfields[i], &rstrout);
414       CeedChk(ierr);
415       ierr = CeedOperatorFieldGetLMode(op->outputfields[i], &lmodeout);
416       CeedChk(ierr);
417       CeedEvalMode emode;
418       ierr = CeedQFunctionFieldGetEvalMode(qf->outputfields[i], &emode);
419       CeedChk(ierr);
420       switch (emode) {
421       case CEED_EVAL_NONE:
422       case CEED_EVAL_INTERP:
423         ierr = CeedRealloc(numemodeout + 1, &emodeout); CeedChk(ierr);
424         emodeout[numemodeout] = emode;
425         numemodeout += 1;
426         break;
427       case CEED_EVAL_GRAD:
428         ierr = CeedRealloc(numemodeout + dim, &emodeout); CeedChk(ierr);
429         for (CeedInt d=0; d<dim; d++)
430           emodeout[numemodeout+d] = emode;
431         numemodeout += dim;
432         break;
433       case CEED_EVAL_WEIGHT:
434       case CEED_EVAL_DIV:
435       case CEED_EVAL_CURL:
436         break; // Caught by QF Assembly
437       }
438     }
439 
440   // Create diagonal vector
441   CeedVector elemdiag;
442   ierr = CeedElemRestrictionCreateVector(rstrin, assembled, &elemdiag);
443   CeedChk(ierr);
444 
445   // Assemble element operator diagonals
446   CeedScalar *elemdiagarray, *assembledqfarray;
447   ierr = CeedVectorSetValue(elemdiag, 0.0); CeedChk(ierr);
448   ierr = CeedVectorGetArray(elemdiag, CEED_MEM_HOST, &elemdiagarray);
449   CeedChk(ierr);
450   ierr = CeedVectorGetArray(assembledqf, CEED_MEM_HOST, &assembledqfarray);
451   CeedChk(ierr);
452   CeedInt nelem, nnodes, nqpts;
453   ierr = CeedElemRestrictionGetNumElements(rstrin, &nelem); CeedChk(ierr);
454   ierr = CeedBasisGetNumNodes(basisin, &nnodes); CeedChk(ierr);
455   ierr = CeedBasisGetNumQuadraturePoints(basisin, &nqpts); CeedChk(ierr);
456   // Compute the diagonal of B^T D B
457   // Each node, qpt pair
458   for (CeedInt n=0; n<nnodes; n++)
459     for (CeedInt q=0; q<nqpts; q++) {
460       CeedInt dout = -1;
461       // Each basis eval mode pair
462       for (CeedInt eout=0; eout<numemodeout; eout++) {
463         CeedScalar bt = 1.0;
464         if (emodeout[eout] == CEED_EVAL_GRAD)
465           dout += 1;
466         ierr = CeedBasisGetValue(basisout, emodeout[eout], q, n, dout, &bt);
467         CeedChk(ierr);
468         CeedInt din = -1;
469         for (CeedInt ein=0; ein<numemodein; ein++) {
470           CeedScalar b = 0.0;
471           if (emodein[ein] == CEED_EVAL_GRAD)
472             din += 1;
473           ierr = CeedBasisGetValue(basisin, emodein[ein], q, n, din, &b);
474           CeedChk(ierr);
475           // Each element and component
476           for (CeedInt e=0; e<nelem; e++)
477             for (CeedInt cout=0; cout<ncomp; cout++) {
478               CeedScalar db = 0.0;
479               for (CeedInt cin=0; cin<ncomp; cin++)
480                 db += assembledqfarray[((((e*numemodein+ein)*ncomp+cin)*
481                                        numemodeout+eout)*ncomp+cout)*nqpts+q]*b;
482               elemdiagarray[(e*ncomp+cout)*nnodes+n] += bt * db;
483             }
484         }
485       }
486     }
487 
488   ierr = CeedVectorRestoreArray(elemdiag, &elemdiagarray); CeedChk(ierr);
489   ierr = CeedVectorRestoreArray(assembledqf, &assembledqfarray); CeedChk(ierr);
490 
491   // Assemble local operator diagonal
492   ierr = CeedVectorSetValue(*assembled, 0.0); CeedChk(ierr);
493   ierr = CeedElemRestrictionApply(rstrout, CEED_TRANSPOSE, lmodeout, elemdiag,
494                                   *assembled, request); CeedChk(ierr);
495 
496   // Cleanup
497   ierr = CeedVectorDestroy(&assembledqf); CeedChk(ierr);
498   ierr = CeedVectorDestroy(&elemdiag); CeedChk(ierr);
499   ierr = CeedFree(&emodein); CeedChk(ierr);
500   ierr = CeedFree(&emodeout); CeedChk(ierr);
501 
502   return 0;
503 }
504 
505 /**
506   @brief Apply CeedOperator to a vector
507 
508   This computes the action of the operator on the specified (active) input,
509   yielding its (active) output.  All inputs and outputs must be specified using
510   CeedOperatorSetField().
511 
512   @param op        CeedOperator to apply
513   @param[in] in    CeedVector containing input state or NULL if there are no
514                      active inputs
515   @param[out] out  CeedVector to store result of applying operator (must be
516                      distinct from @a in) or NULL if there are no active outputs
517   @param request   Address of CeedRequest for non-blocking completion, else
518                      CEED_REQUEST_IMMEDIATE
519 
520   @return An error code: 0 - success, otherwise - failure
521 
522   @ref Basic
523 **/
524 int CeedOperatorApply(CeedOperator op, CeedVector in,
525                       CeedVector out, CeedRequest *request) {
526   int ierr;
527   Ceed ceed = op->ceed;
528   CeedQFunction qf = op->qf;
529 
530   if (op->composite) {
531     if (!op->numsub)
532       // LCOV_EXCL_START
533       return CeedError(ceed, 1, "No suboperators set");
534     // LCOV_EXCL_STOP
535   } else {
536     if (op->nfields == 0)
537       // LCOV_EXCL_START
538       return CeedError(ceed, 1, "No operator fields set");
539     // LCOV_EXCL_STOP
540     if (op->nfields < qf->numinputfields + qf->numoutputfields)
541       // LCOV_EXCL_START
542       return CeedError(ceed, 1, "Not all operator fields set");
543     // LCOV_EXCL_STOP
544     if (op->numelements == 0)
545       // LCOV_EXCL_START
546       return CeedError(ceed, 1,"At least one restriction required");
547     // LCOV_EXCL_STOP
548     if (op->numqpoints == 0)
549       // LCOV_EXCL_START
550       return CeedError(ceed, 1,"At least one non-collocated basis required");
551     // LCOV_EXCL_STOP
552   }
553   ierr = op->Apply(op, in, out, request); CeedChk(ierr);
554   return 0;
555 }
556 
557 /**
558   @brief Get the Ceed associated with a CeedOperator
559 
560   @param op              CeedOperator
561   @param[out] ceed       Variable to store Ceed
562 
563   @return An error code: 0 - success, otherwise - failure
564 
565   @ref Advanced
566 **/
567 
568 int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) {
569   *ceed = op->ceed;
570   return 0;
571 }
572 
573 /**
574   @brief Get the number of elements associated with a CeedOperator
575 
576   @param op              CeedOperator
577   @param[out] numelem    Variable to store number of elements
578 
579   @return An error code: 0 - success, otherwise - failure
580 
581   @ref Advanced
582 **/
583 
584 int CeedOperatorGetNumElements(CeedOperator op, CeedInt *numelem) {
585   if (op->composite)
586     // LCOV_EXCL_START
587     return CeedError(op->ceed, 1, "Not defined for composite operator");
588   // LCOV_EXCL_STOP
589 
590   *numelem = op->numelements;
591   return 0;
592 }
593 
594 /**
595   @brief Get the number of quadrature points associated with a CeedOperator
596 
597   @param op              CeedOperator
598   @param[out] numqpts    Variable to store vector number of quadrature points
599 
600   @return An error code: 0 - success, otherwise - failure
601 
602   @ref Advanced
603 **/
604 
605 int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *numqpts) {
606   if (op->composite)
607     // LCOV_EXCL_START
608     return CeedError(op->ceed, 1, "Not defined for composite operator");
609   // LCOV_EXCL_STOP
610 
611   *numqpts = op->numqpoints;
612   return 0;
613 }
614 
615 /**
616   @brief Get the number of arguments associated with a CeedOperator
617 
618   @param op              CeedOperator
619   @param[out] numargs    Variable to store vector number of arguments
620 
621   @return An error code: 0 - success, otherwise - failure
622 
623   @ref Advanced
624 **/
625 
626 int CeedOperatorGetNumArgs(CeedOperator op, CeedInt *numargs) {
627   if (op->composite)
628     // LCOV_EXCL_START
629     return CeedError(op->ceed, 1, "Not defined for composite operators");
630   // LCOV_EXCL_STOP
631 
632   *numargs = op->nfields;
633   return 0;
634 }
635 
636 /**
637   @brief Get the setup status of a CeedOperator
638 
639   @param op             CeedOperator
640   @param[out] setupdone Variable to store setup status
641 
642   @return An error code: 0 - success, otherwise - failure
643 
644   @ref Advanced
645 **/
646 
647 int CeedOperatorGetSetupStatus(CeedOperator op, bool *setupdone) {
648   *setupdone = op->setupdone;
649   return 0;
650 }
651 
652 /**
653   @brief Get the QFunction associated with a CeedOperator
654 
655   @param op              CeedOperator
656   @param[out] qf         Variable to store QFunction
657 
658   @return An error code: 0 - success, otherwise - failure
659 
660   @ref Advanced
661 **/
662 
663 int CeedOperatorGetQFunction(CeedOperator op, CeedQFunction *qf) {
664   if (op->composite)
665     // LCOV_EXCL_START
666     return CeedError(op->ceed, 1, "Not defined for composite operator");
667   // LCOV_EXCL_STOP
668 
669   *qf = op->qf;
670   return 0;
671 }
672 
673 /**
674   @brief Get the number of suboperators associated with a CeedOperator
675 
676   @param op              CeedOperator
677   @param[out] numsub     Variable to store number of suboperators
678 
679   @return An error code: 0 - success, otherwise - failure
680 
681   @ref Advanced
682 **/
683 
684 int CeedOperatorGetNumSub(CeedOperator op, CeedInt *numsub) {
685   if (!op->composite)
686     // LCOV_EXCL_START
687     return CeedError(op->ceed, 1, "Not a composite operator");
688   // LCOV_EXCL_STOP
689 
690   *numsub = op->numsub;
691   return 0;
692 }
693 
694 /**
695   @brief Get the list of suboperators associated with a CeedOperator
696 
697   @param op                CeedOperator
698   @param[out] suboperators Variable to store list of suboperators
699 
700   @return An error code: 0 - success, otherwise - failure
701 
702   @ref Advanced
703 **/
704 
705 int CeedOperatorGetSubList(CeedOperator op, CeedOperator* *suboperators) {
706   if (!op->composite)
707     // LCOV_EXCL_START
708     return CeedError(op->ceed, 1, "Not a composite operator");
709   // LCOV_EXCL_STOP
710 
711   *suboperators = op->suboperators;
712   return 0;
713 }
714 
715 /**
716   @brief Set the backend data of a CeedOperator
717 
718   @param[out] op         CeedOperator
719   @param data            Data to set
720 
721   @return An error code: 0 - success, otherwise - failure
722 
723   @ref Advanced
724 **/
725 
726 int CeedOperatorSetData(CeedOperator op, void* *data) {
727   op->data = *data;
728   return 0;
729 }
730 
731 /**
732   @brief Get the backend data of a CeedOperator
733 
734   @param op              CeedOperator
735   @param[out] data       Variable to store data
736 
737   @return An error code: 0 - success, otherwise - failure
738 
739   @ref Advanced
740 **/
741 
742 int CeedOperatorGetData(CeedOperator op, void* *data) {
743   *data = op->data;
744   return 0;
745 }
746 
747 /**
748   @brief Set the setup flag of a CeedOperator to True
749 
750   @param op              CeedOperator
751 
752   @return An error code: 0 - success, otherwise - failure
753 
754   @ref Advanced
755 **/
756 
757 int CeedOperatorSetSetupDone(CeedOperator op) {
758   op->setupdone = 1;
759   return 0;
760 }
761 
762 /**
763   @brief Get the CeedOperatorFields of a CeedOperator
764 
765   @param op                 CeedOperator
766   @param[out] inputfields   Variable to store inputfields
767   @param[out] outputfields  Variable to store outputfields
768 
769   @return An error code: 0 - success, otherwise - failure
770 
771   @ref Advanced
772 **/
773 
774 int CeedOperatorGetFields(CeedOperator op,
775                           CeedOperatorField* *inputfields,
776                           CeedOperatorField* *outputfields) {
777   if (op->composite)
778     // LCOV_EXCL_START
779     return CeedError(op->ceed, 1, "Not defined for composite operator");
780   // LCOV_EXCL_STOP
781 
782   if (inputfields) *inputfields = op->inputfields;
783   if (outputfields) *outputfields = op->outputfields;
784   return 0;
785 }
786 
787 /**
788   @brief Get the L vector CeedTransposeMode of a CeedOperatorField
789 
790   @param opfield         CeedOperatorField
791   @param[out] lmode      Variable to store CeedTransposeMode
792 
793   @return An error code: 0 - success, otherwise - failure
794 
795   @ref Advanced
796 **/
797 
798 int CeedOperatorFieldGetLMode(CeedOperatorField opfield,
799                               CeedTransposeMode *lmode) {
800   *lmode = opfield->lmode;
801   return 0;
802 }
803 
804 /**
805   @brief Get the CeedElemRestriction of a CeedOperatorField
806 
807   @param opfield         CeedOperatorField
808   @param[out] rstr       Variable to store CeedElemRestriction
809 
810   @return An error code: 0 - success, otherwise - failure
811 
812   @ref Advanced
813 **/
814 
815 int CeedOperatorFieldGetElemRestriction(CeedOperatorField opfield,
816                                         CeedElemRestriction *rstr) {
817   *rstr = opfield->Erestrict;
818   return 0;
819 }
820 
821 /**
822   @brief Get the CeedBasis of a CeedOperatorField
823 
824   @param opfield         CeedOperatorField
825   @param[out] basis      Variable to store CeedBasis
826 
827   @return An error code: 0 - success, otherwise - failure
828 
829   @ref Advanced
830 **/
831 
832 int CeedOperatorFieldGetBasis(CeedOperatorField opfield,
833                               CeedBasis *basis) {
834   *basis = opfield->basis;
835   return 0;
836 }
837 
838 /**
839   @brief Get the CeedVector of a CeedOperatorField
840 
841   @param opfield         CeedOperatorField
842   @param[out] vec        Variable to store CeedVector
843 
844   @return An error code: 0 - success, otherwise - failure
845 
846   @ref Advanced
847 **/
848 
849 int CeedOperatorFieldGetVector(CeedOperatorField opfield,
850                                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