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