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