xref: /libCEED/interface/ceed-operator.c (revision f0d2f928220c74787e2a8b65d655802dcef082ab)
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,
234                                 CeedOperator subop) {
235   if (!compositeop->composite)
236     // LCOV_EXCL_START
237     return CeedError(compositeop->ceed, 1, "CeedOperator is not a composite "
238                      "operator");
239   // LCOV_EXCL_STOP
240 
241   if (compositeop->numsub == CEED_COMPOSITE_MAX)
242     // LCOV_EXCL_START
243     return CeedError(compositeop->ceed, 1, "Cannot add additional suboperators");
244   // LCOV_EXCL_STOP
245 
246   compositeop->suboperators[compositeop->numsub] = subop;
247   subop->refcount++;
248   compositeop->numsub++;
249   return 0;
250 }
251 
252 /**
253   @brief Assemble a linear CeedQFunction associated with a CeedOperator
254 
255   This returns a CeedVector containing a matrix at each quadrature point
256     providing the action of the CeedQFunction associated with the CeedOperator.
257     The vector 'assembled' is of shape
258       [num_elements, num_input_fields, num_output_fields, num_quad_points]
259     and contains column-major matrices representing the action of the
260     CeedQFunction for a corresponding quadrature point on an element. Inputs and
261     outputs are in the order provided by the user when adding CeedOperator fields.
262     For example, a QFunction with inputs 'u' and 'gradu' and outputs 'gradv' and
263     'v', provided in that order, would result in an assembled QFunction that
264     consists of (1 + dim) x (dim + 1) matrices at each quadrature point acting
265     on the input [u, du_0, du_1] and producing the output [dv_0, dv_1, v].
266 
267   @param op             CeedOperator to assemble CeedQFunction
268   @param[out] assembled CeedVector to store assembled CeedQFunction at
269                           quadrature points
270   @param[out] rstr      CeedElemRestriction for CeedVector containing assembled
271                           CeedQFunction
272   @param request        Address of CeedRequest for non-blocking completion, else
273                           CEED_REQUEST_IMMEDIATE
274 
275   @return An error code: 0 - success, otherwise - failure
276 
277   @ref Basic
278 **/
279 int CeedOperatorAssembleLinearQFunction(CeedOperator op, CeedVector *assembled,
280                                         CeedElemRestriction *rstr,
281                                         CeedRequest *request) {
282   int ierr;
283   Ceed ceed = op->ceed;
284   CeedQFunction qf = op->qf;
285 
286   if (op->composite) {
287     // LCOV_EXCL_START
288     return CeedError(ceed, 1, "Cannot assemble QFunction for composite operator");
289     // LCOV_EXCL_STOP
290   } else {
291     if (op->nfields == 0)
292       // LCOV_EXCL_START
293       return CeedError(ceed, 1, "No operator fields set");
294     // LCOV_EXCL_STOP
295     if (op->nfields < qf->numinputfields + qf->numoutputfields)
296       // LCOV_EXCL_START
297       return CeedError( ceed, 1, "Not all operator fields set");
298     // LCOV_EXCL_STOP
299     if (!op->hasrestriction)
300       // LCOV_EXCL_START
301       return CeedError(ceed, 1, "At least one restriction required");
302     // LCOV_EXCL_STOP
303     if (op->numqpoints == 0)
304       // LCOV_EXCL_START
305       return CeedError(ceed, 1, "At least one non-collocated basis required");
306     // LCOV_EXCL_STOP
307   }
308   ierr = op->AssembleLinearQFunction(op, assembled, rstr, request);
309   CeedChk(ierr);
310   return 0;
311 }
312 
313 /**
314   @brief Assemble the diagonal of a square linear Operator
315 
316   This returns a CeedVector containing the diagonal of a linear CeedOperator.
317 
318   @param op             CeedOperator to assemble CeedQFunction
319   @param[out] assembled CeedVector to store assembled CeedOperator diagonal
320   @param request        Address of CeedRequest for non-blocking completion, else
321                           CEED_REQUEST_IMMEDIATE
322 
323   @return An error code: 0 - success, otherwise - failure
324 
325   @ref Basic
326 **/
327 int CeedOperatorAssembleLinearDiagonal(CeedOperator op, CeedVector *assembled,
328                                        CeedRequest *request) {
329   int ierr;
330   Ceed ceed = op->ceed;
331   CeedQFunction qf = op->qf;
332 
333   if (op->composite) {
334     // LCOV_EXCL_START
335     return CeedError(ceed, 1, "Cannot assemble QFunction for composite operator");
336     // LCOV_EXCL_STOP
337   } else {
338     if (op->nfields == 0)
339       // LCOV_EXCL_START
340       return CeedError(ceed, 1, "No operator fields set");
341     // LCOV_EXCL_STOP
342     if (op->nfields < qf->numinputfields + qf->numoutputfields)
343       // LCOV_EXCL_START
344       return CeedError( ceed, 1, "Not all operator fields set");
345     // LCOV_EXCL_STOP
346     if (!op->hasrestriction)
347       // LCOV_EXCL_START
348       return CeedError(ceed, 1, "At least one restriction required");
349     // LCOV_EXCL_STOP
350     if (op->numqpoints == 0)
351       // LCOV_EXCL_START
352       return CeedError(ceed, 1, "At least one non-collocated basis required");
353     // LCOV_EXCL_STOP
354   }
355 
356   // Use backend version, if available
357   if (op->AssembleLinearDiagonal) {
358     ierr = op->AssembleLinearDiagonal(op, assembled, request); CeedChk(ierr);
359     return 0;
360   }
361 
362   // Assemble QFunction
363   CeedVector assembledqf;
364   CeedElemRestriction rstr;
365   ierr = CeedOperatorAssembleLinearQFunction(op,  &assembledqf, &rstr, request);
366   CeedChk(ierr);
367   ierr = CeedElemRestrictionDestroy(&rstr); CeedChk(ierr);
368 
369   // Determine active input basis
370   CeedInt numemodein = 0, ncomp, dim = 1;
371   CeedEvalMode *emodein = NULL;
372   CeedBasis basisin = NULL;
373   CeedElemRestriction rstrin = NULL;
374   for (CeedInt i=0; i<qf->numinputfields; i++)
375     if (op->inputfields[i]->vec == CEED_VECTOR_ACTIVE) {
376       ierr = CeedOperatorFieldGetBasis(op->inputfields[i], &basisin);
377       CeedChk(ierr);
378       ierr = CeedBasisGetNumComponents(basisin, &ncomp); CeedChk(ierr);
379       ierr = CeedBasisGetDimension(basisin, &dim); CeedChk(ierr);
380       ierr = CeedOperatorFieldGetElemRestriction(op->inputfields[i], &rstrin);
381       CeedChk(ierr);
382       CeedEvalMode emode;
383       ierr = CeedQFunctionFieldGetEvalMode(qf->inputfields[i], &emode);
384       CeedChk(ierr);
385       switch (emode) {
386       case CEED_EVAL_NONE:
387       case CEED_EVAL_INTERP:
388         ierr = CeedRealloc(numemodein + 1, &emodein); CeedChk(ierr);
389         emodein[numemodein] = emode;
390         numemodein += 1;
391         break;
392       case CEED_EVAL_GRAD:
393         ierr = CeedRealloc(numemodein + dim, &emodein); CeedChk(ierr);
394         for (CeedInt d=0; d<dim; d++)
395           emodein[numemodein+d] = emode;
396         numemodein += dim;
397         break;
398       case CEED_EVAL_WEIGHT:
399       case CEED_EVAL_DIV:
400       case CEED_EVAL_CURL:
401         break; // Caught by QF Assembly
402       }
403     }
404 
405   // Determine active output basis
406   CeedInt numemodeout = 0;
407   CeedEvalMode *emodeout = NULL;
408   CeedBasis basisout = NULL;
409   CeedElemRestriction rstrout = NULL;
410   CeedTransposeMode lmodeout = CEED_NOTRANSPOSE;
411   for (CeedInt i=0; i<qf->numoutputfields; i++)
412     if (op->outputfields[i]->vec == CEED_VECTOR_ACTIVE) {
413       ierr = CeedOperatorFieldGetBasis(op->outputfields[i], &basisout);
414       CeedChk(ierr);
415       ierr = CeedOperatorFieldGetElemRestriction(op->outputfields[i], &rstrout);
416       CeedChk(ierr);
417       ierr = CeedOperatorFieldGetLMode(op->outputfields[i], &lmodeout);
418       CeedChk(ierr);
419       CeedEvalMode emode;
420       ierr = CeedQFunctionFieldGetEvalMode(qf->outputfields[i], &emode);
421       CeedChk(ierr);
422       switch (emode) {
423       case CEED_EVAL_NONE:
424       case CEED_EVAL_INTERP:
425         ierr = CeedRealloc(numemodeout + 1, &emodeout); CeedChk(ierr);
426         emodeout[numemodeout] = emode;
427         numemodeout += 1;
428         break;
429       case CEED_EVAL_GRAD:
430         ierr = CeedRealloc(numemodeout + dim, &emodeout); CeedChk(ierr);
431         for (CeedInt d=0; d<dim; d++)
432           emodeout[numemodeout+d] = emode;
433         numemodeout += dim;
434         break;
435       case CEED_EVAL_WEIGHT:
436       case CEED_EVAL_DIV:
437       case CEED_EVAL_CURL:
438         break; // Caught by QF Assembly
439       }
440     }
441 
442   // Create diagonal vector
443   CeedVector elemdiag;
444   ierr = CeedElemRestrictionCreateVector(rstrin, assembled, &elemdiag);
445   CeedChk(ierr);
446 
447   // Assemble element operator diagonals
448   CeedScalar *elemdiagarray, *assembledqfarray;
449   ierr = CeedVectorSetValue(elemdiag, 0.0); CeedChk(ierr);
450   ierr = CeedVectorGetArray(elemdiag, CEED_MEM_HOST, &elemdiagarray);
451   CeedChk(ierr);
452   ierr = CeedVectorGetArray(assembledqf, CEED_MEM_HOST, &assembledqfarray);
453   CeedChk(ierr);
454   CeedInt nelem, nnodes, nqpts;
455   ierr = CeedElemRestrictionGetNumElements(rstrin, &nelem); CeedChk(ierr);
456   ierr = CeedBasisGetNumNodes(basisin, &nnodes); CeedChk(ierr);
457   ierr = CeedBasisGetNumQuadraturePoints(basisin, &nqpts); CeedChk(ierr);
458   // Compute the diagonal of B^T D B
459   // Each node, qpt pair
460   for (CeedInt n=0; n<nnodes; n++)
461     for (CeedInt q=0; q<nqpts; q++) {
462       CeedInt dout = -1;
463       // Each basis eval mode pair
464       for (CeedInt eout=0; eout<numemodeout; eout++) {
465         CeedScalar bt = 1.0;
466         if (emodeout[eout] == CEED_EVAL_GRAD)
467           dout += 1;
468         ierr = CeedBasisGetValue(basisout, emodeout[eout], q, n, dout, &bt);
469         CeedChk(ierr);
470         CeedInt din = -1;
471         for (CeedInt ein=0; ein<numemodein; ein++) {
472           CeedScalar b = 0.0;
473           if (emodein[ein] == CEED_EVAL_GRAD)
474             din += 1;
475           ierr = CeedBasisGetValue(basisin, emodein[ein], q, n, din, &b);
476           CeedChk(ierr);
477           // Each element and component
478           for (CeedInt e=0; e<nelem; e++)
479             for (CeedInt cout=0; cout<ncomp; cout++) {
480               CeedScalar db = 0.0;
481               for (CeedInt cin=0; cin<ncomp; cin++)
482                 db += assembledqfarray[((((e*numemodein+ein)*ncomp+cin)*
483                                          numemodeout+eout)*ncomp+cout)*nqpts+q]*b;
484               elemdiagarray[(e*ncomp+cout)*nnodes+n] += bt * db;
485             }
486         }
487       }
488     }
489 
490   ierr = CeedVectorRestoreArray(elemdiag, &elemdiagarray); CeedChk(ierr);
491   ierr = CeedVectorRestoreArray(assembledqf, &assembledqfarray); CeedChk(ierr);
492 
493   // Assemble local operator diagonal
494   ierr = CeedVectorSetValue(*assembled, 0.0); CeedChk(ierr);
495   ierr = CeedElemRestrictionApply(rstrout, CEED_TRANSPOSE, lmodeout, elemdiag,
496                                   *assembled, request); CeedChk(ierr);
497 
498   // Cleanup
499   ierr = CeedVectorDestroy(&assembledqf); CeedChk(ierr);
500   ierr = CeedVectorDestroy(&elemdiag); CeedChk(ierr);
501   ierr = CeedFree(&emodein); CeedChk(ierr);
502   ierr = CeedFree(&emodeout); CeedChk(ierr);
503 
504   return 0;
505 }
506 
507 /**
508   @brief Apply CeedOperator to a vector
509 
510   This computes the action of the operator on the specified (active) input,
511   yielding its (active) output.  All inputs and outputs must be specified using
512   CeedOperatorSetField().
513 
514   @param op        CeedOperator to apply
515   @param[in] in    CeedVector containing input state or NULL if there are no
516                      active inputs
517   @param[out] out  CeedVector to store result of applying operator (must be
518                      distinct from @a in) or NULL if there are no active outputs
519   @param request   Address of CeedRequest for non-blocking completion, else
520                      CEED_REQUEST_IMMEDIATE
521 
522   @return An error code: 0 - success, otherwise - failure
523 
524   @ref Basic
525 **/
526 int CeedOperatorApply(CeedOperator op, CeedVector in,
527                       CeedVector out, CeedRequest *request) {
528   int ierr;
529   Ceed ceed = op->ceed;
530   CeedQFunction qf = op->qf;
531 
532   if (op->composite) {
533     if (!op->numsub)
534       // LCOV_EXCL_START
535       return CeedError(ceed, 1, "No suboperators set");
536     // LCOV_EXCL_STOP
537   } else {
538     if (op->nfields == 0)
539       // LCOV_EXCL_START
540       return CeedError(ceed, 1, "No operator fields set");
541     // LCOV_EXCL_STOP
542     if (op->nfields < qf->numinputfields + qf->numoutputfields)
543       // LCOV_EXCL_START
544       return CeedError(ceed, 1, "Not all operator fields set");
545     // LCOV_EXCL_STOP
546     if (!op->hasrestriction)
547       // LCOV_EXCL_START
548       return CeedError(ceed, 1,"At least one restriction required");
549     // LCOV_EXCL_STOP
550     if (op->numqpoints == 0)
551       // LCOV_EXCL_START
552       return CeedError(ceed, 1,"At least one non-collocated basis required");
553     // LCOV_EXCL_STOP
554   }
555   if (op->numelements || op->composite) {
556     ierr = op->Apply(op, in, out, request); CeedChk(ierr);
557   }
558   return 0;
559 }
560 
561 /**
562   @brief Get the Ceed associated with a CeedOperator
563 
564   @param op              CeedOperator
565   @param[out] ceed       Variable to store Ceed
566 
567   @return An error code: 0 - success, otherwise - failure
568 
569   @ref Advanced
570 **/
571 
572 int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) {
573   *ceed = op->ceed;
574   return 0;
575 }
576 
577 /**
578   @brief Get the number of elements associated with a CeedOperator
579 
580   @param op              CeedOperator
581   @param[out] numelem    Variable to store number of elements
582 
583   @return An error code: 0 - success, otherwise - failure
584 
585   @ref Advanced
586 **/
587 
588 int CeedOperatorGetNumElements(CeedOperator op, CeedInt *numelem) {
589   if (op->composite)
590     // LCOV_EXCL_START
591     return CeedError(op->ceed, 1, "Not defined for composite operator");
592   // LCOV_EXCL_STOP
593 
594   *numelem = op->numelements;
595   return 0;
596 }
597 
598 /**
599   @brief Get the number of quadrature points associated with a CeedOperator
600 
601   @param op              CeedOperator
602   @param[out] numqpts    Variable to store vector number of quadrature points
603 
604   @return An error code: 0 - success, otherwise - failure
605 
606   @ref Advanced
607 **/
608 
609 int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *numqpts) {
610   if (op->composite)
611     // LCOV_EXCL_START
612     return CeedError(op->ceed, 1, "Not defined for composite operator");
613   // LCOV_EXCL_STOP
614 
615   *numqpts = op->numqpoints;
616   return 0;
617 }
618 
619 /**
620   @brief Get the number of arguments associated with a CeedOperator
621 
622   @param op              CeedOperator
623   @param[out] numargs    Variable to store vector number of arguments
624 
625   @return An error code: 0 - success, otherwise - failure
626 
627   @ref Advanced
628 **/
629 
630 int CeedOperatorGetNumArgs(CeedOperator op, CeedInt *numargs) {
631   if (op->composite)
632     // LCOV_EXCL_START
633     return CeedError(op->ceed, 1, "Not defined for composite operators");
634   // LCOV_EXCL_STOP
635 
636   *numargs = op->nfields;
637   return 0;
638 }
639 
640 /**
641   @brief Get the setup status of a CeedOperator
642 
643   @param op             CeedOperator
644   @param[out] setupdone Variable to store setup status
645 
646   @return An error code: 0 - success, otherwise - failure
647 
648   @ref Advanced
649 **/
650 
651 int CeedOperatorGetSetupStatus(CeedOperator op, bool *setupdone) {
652   *setupdone = op->setupdone;
653   return 0;
654 }
655 
656 /**
657   @brief Get the QFunction associated with a CeedOperator
658 
659   @param op              CeedOperator
660   @param[out] qf         Variable to store QFunction
661 
662   @return An error code: 0 - success, otherwise - failure
663 
664   @ref Advanced
665 **/
666 
667 int CeedOperatorGetQFunction(CeedOperator op, CeedQFunction *qf) {
668   if (op->composite)
669     // LCOV_EXCL_START
670     return CeedError(op->ceed, 1, "Not defined for composite operator");
671   // LCOV_EXCL_STOP
672 
673   *qf = op->qf;
674   return 0;
675 }
676 
677 /**
678   @brief Get the number of suboperators associated with a CeedOperator
679 
680   @param op              CeedOperator
681   @param[out] numsub     Variable to store number of suboperators
682 
683   @return An error code: 0 - success, otherwise - failure
684 
685   @ref Advanced
686 **/
687 
688 int CeedOperatorGetNumSub(CeedOperator op, CeedInt *numsub) {
689   if (!op->composite)
690     // LCOV_EXCL_START
691     return CeedError(op->ceed, 1, "Not a composite operator");
692   // LCOV_EXCL_STOP
693 
694   *numsub = op->numsub;
695   return 0;
696 }
697 
698 /**
699   @brief Get the list of suboperators associated with a CeedOperator
700 
701   @param op                CeedOperator
702   @param[out] suboperators Variable to store list of suboperators
703 
704   @return An error code: 0 - success, otherwise - failure
705 
706   @ref Advanced
707 **/
708 
709 int CeedOperatorGetSubList(CeedOperator op, CeedOperator* *suboperators) {
710   if (!op->composite)
711     // LCOV_EXCL_START
712     return CeedError(op->ceed, 1, "Not a composite operator");
713   // LCOV_EXCL_STOP
714 
715   *suboperators = op->suboperators;
716   return 0;
717 }
718 
719 /**
720   @brief Set the backend data of a CeedOperator
721 
722   @param[out] op         CeedOperator
723   @param data            Data to set
724 
725   @return An error code: 0 - success, otherwise - failure
726 
727   @ref Advanced
728 **/
729 
730 int CeedOperatorSetData(CeedOperator op, void* *data) {
731   op->data = *data;
732   return 0;
733 }
734 
735 /**
736   @brief Get the backend data of a CeedOperator
737 
738   @param op              CeedOperator
739   @param[out] data       Variable to store data
740 
741   @return An error code: 0 - success, otherwise - failure
742 
743   @ref Advanced
744 **/
745 
746 int CeedOperatorGetData(CeedOperator op, void* *data) {
747   *data = op->data;
748   return 0;
749 }
750 
751 /**
752   @brief Set the setup flag of a CeedOperator to True
753 
754   @param op              CeedOperator
755 
756   @return An error code: 0 - success, otherwise - failure
757 
758   @ref Advanced
759 **/
760 
761 int CeedOperatorSetSetupDone(CeedOperator op) {
762   op->setupdone = 1;
763   return 0;
764 }
765 
766 /**
767   @brief Get the CeedOperatorFields of a CeedOperator
768 
769   @param op                 CeedOperator
770   @param[out] inputfields   Variable to store inputfields
771   @param[out] outputfields  Variable to store outputfields
772 
773   @return An error code: 0 - success, otherwise - failure
774 
775   @ref Advanced
776 **/
777 
778 int CeedOperatorGetFields(CeedOperator op,
779                           CeedOperatorField* *inputfields,
780                           CeedOperatorField* *outputfields) {
781   if (op->composite)
782     // LCOV_EXCL_START
783     return CeedError(op->ceed, 1, "Not defined for composite operator");
784   // LCOV_EXCL_STOP
785 
786   if (inputfields) *inputfields = op->inputfields;
787   if (outputfields) *outputfields = op->outputfields;
788   return 0;
789 }
790 
791 /**
792   @brief Get the L vector CeedTransposeMode of a CeedOperatorField
793 
794   @param opfield         CeedOperatorField
795   @param[out] lmode      Variable to store CeedTransposeMode
796 
797   @return An error code: 0 - success, otherwise - failure
798 
799   @ref Advanced
800 **/
801 
802 int CeedOperatorFieldGetLMode(CeedOperatorField opfield,
803                               CeedTransposeMode *lmode) {
804   *lmode = opfield->lmode;
805   return 0;
806 }
807 
808 /**
809   @brief Get the CeedElemRestriction of a CeedOperatorField
810 
811   @param opfield         CeedOperatorField
812   @param[out] rstr       Variable to store CeedElemRestriction
813 
814   @return An error code: 0 - success, otherwise - failure
815 
816   @ref Advanced
817 **/
818 
819 int CeedOperatorFieldGetElemRestriction(CeedOperatorField opfield,
820                                         CeedElemRestriction *rstr) {
821   *rstr = opfield->Erestrict;
822   return 0;
823 }
824 
825 /**
826   @brief Get the CeedBasis of a CeedOperatorField
827 
828   @param opfield         CeedOperatorField
829   @param[out] basis      Variable to store CeedBasis
830 
831   @return An error code: 0 - success, otherwise - failure
832 
833   @ref Advanced
834 **/
835 
836 int CeedOperatorFieldGetBasis(CeedOperatorField opfield,
837                               CeedBasis *basis) {
838   *basis = opfield->basis;
839   return 0;
840 }
841 
842 /**
843   @brief Get the CeedVector of a CeedOperatorField
844 
845   @param opfield         CeedOperatorField
846   @param[out] vec        Variable to store CeedVector
847 
848   @return An error code: 0 - success, otherwise - failure
849 
850   @ref Advanced
851 **/
852 
853 int CeedOperatorFieldGetVector(CeedOperatorField opfield,
854                                CeedVector *vec) {
855   *vec = opfield->vec;
856   return 0;
857 }
858 
859 /**
860   @brief Destroy a CeedOperator
861 
862   @param op CeedOperator to destroy
863 
864   @return An error code: 0 - success, otherwise - failure
865 
866   @ref Basic
867 **/
868 int CeedOperatorDestroy(CeedOperator *op) {
869   int ierr;
870 
871   if (!*op || --(*op)->refcount > 0) return 0;
872   if ((*op)->Destroy) {
873     ierr = (*op)->Destroy(*op); CeedChk(ierr);
874   }
875   ierr = CeedDestroy(&(*op)->ceed); CeedChk(ierr);
876   // Free fields
877   for (int i=0; i<(*op)->nfields; i++)
878     if ((*op)->inputfields[i]) {
879       ierr = CeedElemRestrictionDestroy(&(*op)->inputfields[i]->Erestrict);
880       CeedChk(ierr);
881       if ((*op)->inputfields[i]->basis != CEED_BASIS_COLLOCATED) {
882         ierr = CeedBasisDestroy(&(*op)->inputfields[i]->basis); CeedChk(ierr);
883       }
884       if ((*op)->inputfields[i]->vec != CEED_VECTOR_ACTIVE &&
885           (*op)->inputfields[i]->vec != CEED_VECTOR_NONE ) {
886         ierr = CeedVectorDestroy(&(*op)->inputfields[i]->vec); CeedChk(ierr);
887       }
888       ierr = CeedFree(&(*op)->inputfields[i]); CeedChk(ierr);
889     }
890   for (int i=0; i<(*op)->nfields; i++)
891     if ((*op)->outputfields[i]) {
892       ierr = CeedElemRestrictionDestroy(&(*op)->outputfields[i]->Erestrict);
893       CeedChk(ierr);
894       if ((*op)->outputfields[i]->basis != CEED_BASIS_COLLOCATED) {
895         ierr = CeedBasisDestroy(&(*op)->outputfields[i]->basis); CeedChk(ierr);
896       }
897       if ((*op)->outputfields[i]->vec != CEED_VECTOR_ACTIVE &&
898           (*op)->outputfields[i]->vec != CEED_VECTOR_NONE ) {
899         ierr = CeedVectorDestroy(&(*op)->outputfields[i]->vec); CeedChk(ierr);
900       }
901       ierr = CeedFree(&(*op)->outputfields[i]); CeedChk(ierr);
902     }
903   // Destroy suboperators
904   for (int i=0; i<(*op)->numsub; i++)
905     if ((*op)->suboperators[i]) {
906       ierr = CeedOperatorDestroy(&(*op)->suboperators[i]); CeedChk(ierr);
907     }
908   ierr = CeedQFunctionDestroy(&(*op)->qf); CeedChk(ierr);
909   ierr = CeedQFunctionDestroy(&(*op)->dqf); CeedChk(ierr);
910   ierr = CeedQFunctionDestroy(&(*op)->dqfT); CeedChk(ierr);
911 
912   ierr = CeedFree(&(*op)->inputfields); CeedChk(ierr);
913   ierr = CeedFree(&(*op)->outputfields); CeedChk(ierr);
914   ierr = CeedFree(&(*op)->suboperators); CeedChk(ierr);
915   ierr = CeedFree(op); CeedChk(ierr);
916   return 0;
917 }
918 
919 /// @}
920