xref: /libCEED/interface/ceed-operator.c (revision 1ef3f58f08373cfc32eb1b7a8e437c0dd90bedcd)
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 != CEED_VECTOR_NONE ? in : NULL,
564                      out != CEED_VECTOR_NONE ? out : NULL, request);
565     CeedChk(ierr);
566   }
567   return 0;
568 }
569 
570 /**
571   @brief Get the Ceed associated with a CeedOperator
572 
573   @param op              CeedOperator
574   @param[out] ceed       Variable to store Ceed
575 
576   @return An error code: 0 - success, otherwise - failure
577 
578   @ref Advanced
579 **/
580 
581 int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) {
582   *ceed = op->ceed;
583   return 0;
584 }
585 
586 /**
587   @brief Get the number of elements associated with a CeedOperator
588 
589   @param op              CeedOperator
590   @param[out] numelem    Variable to store number of elements
591 
592   @return An error code: 0 - success, otherwise - failure
593 
594   @ref Advanced
595 **/
596 
597 int CeedOperatorGetNumElements(CeedOperator op, CeedInt *numelem) {
598   if (op->composite)
599     // LCOV_EXCL_START
600     return CeedError(op->ceed, 1, "Not defined for composite operator");
601   // LCOV_EXCL_STOP
602 
603   *numelem = op->numelements;
604   return 0;
605 }
606 
607 /**
608   @brief Get the number of quadrature points associated with a CeedOperator
609 
610   @param op              CeedOperator
611   @param[out] numqpts    Variable to store vector number of quadrature points
612 
613   @return An error code: 0 - success, otherwise - failure
614 
615   @ref Advanced
616 **/
617 
618 int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *numqpts) {
619   if (op->composite)
620     // LCOV_EXCL_START
621     return CeedError(op->ceed, 1, "Not defined for composite operator");
622   // LCOV_EXCL_STOP
623 
624   *numqpts = op->numqpoints;
625   return 0;
626 }
627 
628 /**
629   @brief Get the number of arguments associated with a CeedOperator
630 
631   @param op              CeedOperator
632   @param[out] numargs    Variable to store vector number of arguments
633 
634   @return An error code: 0 - success, otherwise - failure
635 
636   @ref Advanced
637 **/
638 
639 int CeedOperatorGetNumArgs(CeedOperator op, CeedInt *numargs) {
640   if (op->composite)
641     // LCOV_EXCL_START
642     return CeedError(op->ceed, 1, "Not defined for composite operators");
643   // LCOV_EXCL_STOP
644 
645   *numargs = op->nfields;
646   return 0;
647 }
648 
649 /**
650   @brief Get the setup status of a CeedOperator
651 
652   @param op             CeedOperator
653   @param[out] setupdone Variable to store setup status
654 
655   @return An error code: 0 - success, otherwise - failure
656 
657   @ref Advanced
658 **/
659 
660 int CeedOperatorGetSetupStatus(CeedOperator op, bool *setupdone) {
661   *setupdone = op->setupdone;
662   return 0;
663 }
664 
665 /**
666   @brief Get the QFunction associated with a CeedOperator
667 
668   @param op              CeedOperator
669   @param[out] qf         Variable to store QFunction
670 
671   @return An error code: 0 - success, otherwise - failure
672 
673   @ref Advanced
674 **/
675 
676 int CeedOperatorGetQFunction(CeedOperator op, CeedQFunction *qf) {
677   if (op->composite)
678     // LCOV_EXCL_START
679     return CeedError(op->ceed, 1, "Not defined for composite operator");
680   // LCOV_EXCL_STOP
681 
682   *qf = op->qf;
683   return 0;
684 }
685 
686 /**
687   @brief Get the number of suboperators associated with a CeedOperator
688 
689   @param op              CeedOperator
690   @param[out] numsub     Variable to store number of suboperators
691 
692   @return An error code: 0 - success, otherwise - failure
693 
694   @ref Advanced
695 **/
696 
697 int CeedOperatorGetNumSub(CeedOperator op, CeedInt *numsub) {
698   if (!op->composite)
699     // LCOV_EXCL_START
700     return CeedError(op->ceed, 1, "Not a composite operator");
701   // LCOV_EXCL_STOP
702 
703   *numsub = op->numsub;
704   return 0;
705 }
706 
707 /**
708   @brief Get the list of suboperators associated with a CeedOperator
709 
710   @param op                CeedOperator
711   @param[out] suboperators Variable to store list of suboperators
712 
713   @return An error code: 0 - success, otherwise - failure
714 
715   @ref Advanced
716 **/
717 
718 int CeedOperatorGetSubList(CeedOperator op, CeedOperator **suboperators) {
719   if (!op->composite)
720     // LCOV_EXCL_START
721     return CeedError(op->ceed, 1, "Not a composite operator");
722   // LCOV_EXCL_STOP
723 
724   *suboperators = op->suboperators;
725   return 0;
726 }
727 
728 /**
729   @brief Set the backend data of a CeedOperator
730 
731   @param[out] op         CeedOperator
732   @param data            Data to set
733 
734   @return An error code: 0 - success, otherwise - failure
735 
736   @ref Advanced
737 **/
738 
739 int CeedOperatorSetData(CeedOperator op, void **data) {
740   op->data = *data;
741   return 0;
742 }
743 
744 /**
745   @brief Get the backend data of a CeedOperator
746 
747   @param op              CeedOperator
748   @param[out] data       Variable to store data
749 
750   @return An error code: 0 - success, otherwise - failure
751 
752   @ref Advanced
753 **/
754 
755 int CeedOperatorGetData(CeedOperator op, void **data) {
756   *data = op->data;
757   return 0;
758 }
759 
760 /**
761   @brief Set the setup flag of a CeedOperator to True
762 
763   @param op              CeedOperator
764 
765   @return An error code: 0 - success, otherwise - failure
766 
767   @ref Advanced
768 **/
769 
770 int CeedOperatorSetSetupDone(CeedOperator op) {
771   op->setupdone = 1;
772   return 0;
773 }
774 
775 /**
776   @brief Get the CeedOperatorFields of a CeedOperator
777 
778   @param op                 CeedOperator
779   @param[out] inputfields   Variable to store inputfields
780   @param[out] outputfields  Variable to store outputfields
781 
782   @return An error code: 0 - success, otherwise - failure
783 
784   @ref Advanced
785 **/
786 
787 int CeedOperatorGetFields(CeedOperator op, CeedOperatorField **inputfields,
788                           CeedOperatorField **outputfields) {
789   if (op->composite)
790     // LCOV_EXCL_START
791     return CeedError(op->ceed, 1, "Not defined for composite operator");
792   // LCOV_EXCL_STOP
793 
794   if (inputfields) *inputfields = op->inputfields;
795   if (outputfields) *outputfields = op->outputfields;
796   return 0;
797 }
798 
799 /**
800   @brief Get the L vector CeedTransposeMode of a CeedOperatorField
801 
802   @param opfield         CeedOperatorField
803   @param[out] lmode      Variable to store CeedTransposeMode
804 
805   @return An error code: 0 - success, otherwise - failure
806 
807   @ref Advanced
808 **/
809 
810 int CeedOperatorFieldGetLMode(CeedOperatorField opfield,
811                               CeedTransposeMode *lmode) {
812   *lmode = opfield->lmode;
813   return 0;
814 }
815 
816 /**
817   @brief Get the CeedElemRestriction of a CeedOperatorField
818 
819   @param opfield         CeedOperatorField
820   @param[out] rstr       Variable to store CeedElemRestriction
821 
822   @return An error code: 0 - success, otherwise - failure
823 
824   @ref Advanced
825 **/
826 
827 int CeedOperatorFieldGetElemRestriction(CeedOperatorField opfield,
828                                         CeedElemRestriction *rstr) {
829   *rstr = opfield->Erestrict;
830   return 0;
831 }
832 
833 /**
834   @brief Get the CeedBasis of a CeedOperatorField
835 
836   @param opfield         CeedOperatorField
837   @param[out] basis      Variable to store CeedBasis
838 
839   @return An error code: 0 - success, otherwise - failure
840 
841   @ref Advanced
842 **/
843 
844 int CeedOperatorFieldGetBasis(CeedOperatorField opfield, CeedBasis *basis) {
845   *basis = opfield->basis;
846   return 0;
847 }
848 
849 /**
850   @brief Get the CeedVector of a CeedOperatorField
851 
852   @param opfield         CeedOperatorField
853   @param[out] vec        Variable to store CeedVector
854 
855   @return An error code: 0 - success, otherwise - failure
856 
857   @ref Advanced
858 **/
859 
860 int CeedOperatorFieldGetVector(CeedOperatorField opfield, CeedVector *vec) {
861   *vec = opfield->vec;
862   return 0;
863 }
864 
865 /**
866   @brief Destroy a CeedOperator
867 
868   @param op CeedOperator to destroy
869 
870   @return An error code: 0 - success, otherwise - failure
871 
872   @ref Basic
873 **/
874 int CeedOperatorDestroy(CeedOperator *op) {
875   int ierr;
876 
877   if (!*op || --(*op)->refcount > 0) return 0;
878   if ((*op)->Destroy) {
879     ierr = (*op)->Destroy(*op); CeedChk(ierr);
880   }
881   ierr = CeedDestroy(&(*op)->ceed); CeedChk(ierr);
882   // Free fields
883   for (int i=0; i<(*op)->nfields; i++)
884     if ((*op)->inputfields[i]) {
885       ierr = CeedElemRestrictionDestroy(&(*op)->inputfields[i]->Erestrict);
886       CeedChk(ierr);
887       if ((*op)->inputfields[i]->basis != CEED_BASIS_COLLOCATED) {
888         ierr = CeedBasisDestroy(&(*op)->inputfields[i]->basis); CeedChk(ierr);
889       }
890       if ((*op)->inputfields[i]->vec != CEED_VECTOR_ACTIVE &&
891           (*op)->inputfields[i]->vec != CEED_VECTOR_NONE ) {
892         ierr = CeedVectorDestroy(&(*op)->inputfields[i]->vec); CeedChk(ierr);
893       }
894       ierr = CeedFree(&(*op)->inputfields[i]); CeedChk(ierr);
895     }
896   for (int i=0; i<(*op)->nfields; i++)
897     if ((*op)->outputfields[i]) {
898       ierr = CeedElemRestrictionDestroy(&(*op)->outputfields[i]->Erestrict);
899       CeedChk(ierr);
900       if ((*op)->outputfields[i]->basis != CEED_BASIS_COLLOCATED) {
901         ierr = CeedBasisDestroy(&(*op)->outputfields[i]->basis); CeedChk(ierr);
902       }
903       if ((*op)->outputfields[i]->vec != CEED_VECTOR_ACTIVE &&
904           (*op)->outputfields[i]->vec != CEED_VECTOR_NONE ) {
905         ierr = CeedVectorDestroy(&(*op)->outputfields[i]->vec); CeedChk(ierr);
906       }
907       ierr = CeedFree(&(*op)->outputfields[i]); CeedChk(ierr);
908     }
909   // Destroy suboperators
910   for (int i=0; i<(*op)->numsub; i++)
911     if ((*op)->suboperators[i]) {
912       ierr = CeedOperatorDestroy(&(*op)->suboperators[i]); CeedChk(ierr);
913     }
914   ierr = CeedQFunctionDestroy(&(*op)->qf); CeedChk(ierr);
915   ierr = CeedQFunctionDestroy(&(*op)->dqf); CeedChk(ierr);
916   ierr = CeedQFunctionDestroy(&(*op)->dqfT); CeedChk(ierr);
917 
918   ierr = CeedFree(&(*op)->inputfields); CeedChk(ierr);
919   ierr = CeedFree(&(*op)->outputfields); CeedChk(ierr);
920   ierr = CeedFree(&(*op)->suboperators); CeedChk(ierr);
921   ierr = CeedFree(op); CeedChk(ierr);
922   return 0;
923 }
924 
925 /// @}
926