xref: /libCEED/interface/ceed-operator.c (revision 36de5dbf48990ea8531ad6af338dc02f7a058d7a)
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 #include <math.h>
21 
22 /// @file
23 /// Implementation of public CeedOperator interfaces
24 ///
25 /// @addtogroup CeedOperator
26 ///   @{
27 
28 /**
29   @brief Create a CeedOperator and associate a CeedQFunction. A CeedBasis and
30            CeedElemRestriction can be associated with CeedQFunction fields with
31            \ref CeedOperatorSetField.
32 
33   @param ceed    A Ceed object where the CeedOperator will be created
34   @param qf      QFunction defining the action of the operator at quadrature points
35   @param dqf     QFunction defining the action of the Jacobian of @a qf (or
36                    CEED_QFUNCTION_NONE)
37   @param dqfT    QFunction defining the action of the transpose of the Jacobian
38                    of @a qf (or CEED_QFUNCTION_NONE)
39   @param[out] op Address of the variable where the newly created
40                      CeedOperator will be stored
41 
42   @return An error code: 0 - success, otherwise - failure
43 
44   @ref Basic
45  */
46 int CeedOperatorCreate(Ceed ceed, CeedQFunction qf, CeedQFunction dqf,
47                        CeedQFunction dqfT, CeedOperator *op) {
48   int ierr;
49 
50   if (!ceed->OperatorCreate) {
51     Ceed delegate;
52     ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr);
53 
54     if (!delegate)
55       // LCOV_EXCL_START
56       return CeedError(ceed, 1, "Backend does not support OperatorCreate");
57     // LCOV_EXCL_STOP
58 
59     ierr = CeedOperatorCreate(delegate, qf, dqf, dqfT, op); CeedChk(ierr);
60     return 0;
61   }
62 
63   ierr = CeedCalloc(1, op); CeedChk(ierr);
64   (*op)->ceed = ceed;
65   ceed->refcount++;
66   (*op)->refcount = 1;
67   if (qf == CEED_QFUNCTION_NONE)
68     // LCOV_EXCL_START
69     return CeedError(ceed, 1, "Operator must have a valid QFunction.");
70   // LCOV_EXCL_STOP
71   (*op)->qf = qf;
72   qf->refcount++;
73   if (dqf && dqf != CEED_QFUNCTION_NONE) {
74     (*op)->dqf = dqf;
75     dqf->refcount++;
76   }
77   if (dqfT && dqfT != CEED_QFUNCTION_NONE) {
78     (*op)->dqfT = dqfT;
79     dqfT->refcount++;
80   }
81   ierr = CeedCalloc(16, &(*op)->inputfields); CeedChk(ierr);
82   ierr = CeedCalloc(16, &(*op)->outputfields); CeedChk(ierr);
83   ierr = ceed->OperatorCreate(*op); CeedChk(ierr);
84   return 0;
85 }
86 
87 /**
88   @brief Create an operator that composes the action of several operators
89 
90   @param ceed    A Ceed object where the CeedOperator will be created
91   @param[out] op Address of the variable where the newly created
92                      Composite CeedOperator will be stored
93 
94   @return An error code: 0 - success, otherwise - failure
95 
96   @ref Basic
97  */
98 int CeedCompositeOperatorCreate(Ceed ceed, CeedOperator *op) {
99   int ierr;
100 
101   if (!ceed->CompositeOperatorCreate) {
102     Ceed delegate;
103     ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr);
104 
105     if (delegate) {
106       ierr = CeedCompositeOperatorCreate(delegate, op); CeedChk(ierr);
107       return 0;
108     }
109   }
110 
111   ierr = CeedCalloc(1, op); CeedChk(ierr);
112   (*op)->ceed = ceed;
113   ceed->refcount++;
114   (*op)->composite = true;
115   ierr = CeedCalloc(16, &(*op)->suboperators); CeedChk(ierr);
116 
117   if (ceed->CompositeOperatorCreate) {
118     ierr = ceed->CompositeOperatorCreate(*op); CeedChk(ierr);
119   }
120   return 0;
121 }
122 
123 /**
124   @brief Provide a field to a CeedOperator for use by its CeedQFunction
125 
126   This function is used to specify both active and passive fields to a
127   CeedOperator.  For passive fields, a vector @arg v must be provided.  Passive
128   fields can inputs or outputs (updated in-place when operator is applied).
129 
130   Active fields must be specified using this function, but their data (in a
131   CeedVector) is passed in CeedOperatorApply().  There can be at most one active
132   input and at most one active output.
133 
134   @param op         CeedOperator on which to provide the field
135   @param fieldname  Name of the field (to be matched with the name used by
136                       CeedQFunction)
137   @param r          CeedElemRestriction
138   @param lmode      CeedTransposeMode which specifies the ordering of the
139                       components of the l-vector used by this CeedOperatorField,
140                       CEED_NOTRANSPOSE indicates the component is the
141                       outermost index and CEED_TRANSPOSE indicates the component
142                       is the innermost index in ordering of the l-vector
143   @param b          CeedBasis in which the field resides or CEED_BASIS_COLLOCATED
144                       if collocated with quadrature points
145   @param v          CeedVector to be used by CeedOperator or CEED_VECTOR_ACTIVE
146                       if field is active or CEED_VECTOR_NONE if using
147                       CEED_EVAL_WEIGHT in the QFunction
148 
149   @return An error code: 0 - success, otherwise - failure
150 
151   @ref Basic
152 **/
153 int CeedOperatorSetField(CeedOperator op, const char *fieldname,
154                          CeedElemRestriction r, CeedTransposeMode lmode,
155                          CeedBasis b, CeedVector v) {
156   int ierr;
157   if (op->composite)
158     // LCOV_EXCL_START
159     return CeedError(op->ceed, 1, "Cannot add field to composite operator.");
160   // LCOV_EXCL_STOP
161   if (!r)
162     // LCOV_EXCL_START
163     return CeedError(op->ceed, 1,
164                      "ElemRestriction r for field \"%s\" must be non-NULL.",
165                      fieldname);
166   // LCOV_EXCL_STOP
167   if (!b)
168     // LCOV_EXCL_START
169     return CeedError(op->ceed, 1, "Basis b for field \"%s\" must be non-NULL.",
170                      fieldname);
171   // LCOV_EXCL_STOP
172   if (!v)
173     // LCOV_EXCL_START
174     return CeedError(op->ceed, 1, "Vector v for field \"%s\" must be non-NULL.",
175                      fieldname);
176   // LCOV_EXCL_STOP
177 
178   CeedInt numelements;
179   ierr = CeedElemRestrictionGetNumElements(r, &numelements); CeedChk(ierr);
180   if (op->hasrestriction && op->numelements != numelements)
181     // LCOV_EXCL_START
182     return CeedError(op->ceed, 1,
183                      "ElemRestriction with %d elements incompatible with prior "
184                      "%d elements", numelements, op->numelements);
185   // LCOV_EXCL_STOP
186   op->numelements = numelements;
187   op->hasrestriction = true; // Restriction set, but numelements may be 0
188 
189   if (b != CEED_BASIS_COLLOCATED) {
190     CeedInt numqpoints;
191     ierr = CeedBasisGetNumQuadraturePoints(b, &numqpoints); CeedChk(ierr);
192     if (op->numqpoints && op->numqpoints != numqpoints)
193       // LCOV_EXCL_START
194       return CeedError(op->ceed, 1, "Basis with %d quadrature points "
195                        "incompatible with prior %d points", numqpoints,
196                        op->numqpoints);
197     // LCOV_EXCL_STOP
198     op->numqpoints = numqpoints;
199   }
200   CeedOperatorField *ofield;
201   for (CeedInt i=0; i<op->qf->numinputfields; i++) {
202     if (!strcmp(fieldname, (*op->qf->inputfields[i]).fieldname)) {
203       ofield = &op->inputfields[i];
204       goto found;
205     }
206   }
207   for (CeedInt i=0; i<op->qf->numoutputfields; i++) {
208     if (!strcmp(fieldname, (*op->qf->outputfields[i]).fieldname)) {
209       ofield = &op->outputfields[i];
210       goto found;
211     }
212   }
213   // LCOV_EXCL_START
214   return CeedError(op->ceed, 1, "QFunction has no knowledge of field '%s'",
215                    fieldname);
216   // LCOV_EXCL_STOP
217 found:
218   ierr = CeedCalloc(1, ofield); CeedChk(ierr);
219   (*ofield)->Erestrict = r;
220   r->refcount += 1;
221   (*ofield)->lmode = lmode;
222   (*ofield)->basis = b;
223   if (b != CEED_BASIS_COLLOCATED)
224     b->refcount += 1;
225   (*ofield)->vec = v;
226   if (v != CEED_VECTOR_ACTIVE && v != CEED_VECTOR_NONE)
227     v->refcount += 1;
228   op->nfields += 1;
229   return 0;
230 }
231 
232 /**
233   @brief Add a sub-operator to a composite CeedOperator
234 
235   @param[out] compositeop Composite CeedOperator
236   @param      subop       Sub-operator CeedOperator
237 
238   @return An error code: 0 - success, otherwise - failure
239 
240   @ref Basic
241  */
242 int CeedCompositeOperatorAddSub(CeedOperator compositeop, CeedOperator subop) {
243   if (!compositeop->composite)
244     // LCOV_EXCL_START
245     return CeedError(compositeop->ceed, 1, "CeedOperator is not a composite "
246                      "operator");
247   // LCOV_EXCL_STOP
248 
249   if (compositeop->numsub == CEED_COMPOSITE_MAX)
250     // LCOV_EXCL_START
251     return CeedError(compositeop->ceed, 1, "Cannot add additional suboperators");
252   // LCOV_EXCL_STOP
253 
254   compositeop->suboperators[compositeop->numsub] = subop;
255   subop->refcount++;
256   compositeop->numsub++;
257   return 0;
258 }
259 
260 /**
261   @brief Duplicate a CeedOperator with a reference Ceed to fallback for advanced
262            CeedOperator functionality
263 
264   @param op           CeedOperator to create fallback for
265 
266   @return An error code: 0 - success, otherwise - failure
267 
268   @ref Developer
269 **/
270 int CeedOperatorCreateFallback(CeedOperator op) {
271   int ierr;
272 
273   // Fallback Ceed
274   const char *resource, *fallbackresource;
275   ierr = CeedGetResource(op->ceed, &resource); CeedChk(ierr);
276   ierr = CeedGetOperatorFallbackResource(op->ceed, &fallbackresource);
277   CeedChk(ierr);
278   if (!strcmp(resource, fallbackresource))
279     // LCOV_EXCL_START
280     return CeedError(op->ceed, 1, "Backend %s cannot create an operator"
281                      "fallback to resource %s", resource, fallbackresource);
282   // LCOV_EXCL_STOP
283 
284   // Fallback Ceed
285   Ceed ceedref;
286   if (!op->ceed->opfallbackceed) {
287     ierr = CeedInit(fallbackresource, &ceedref); CeedChk(ierr);
288     ceedref->opfallbackparent = op->ceed;
289     op->ceed->opfallbackceed = ceedref;
290   }
291   ceedref = op->ceed->opfallbackceed;
292 
293   // Clone Op
294   CeedOperator opref;
295   ierr = CeedCalloc(1, &opref); CeedChk(ierr);
296   memcpy(opref, op, sizeof(*opref)); CeedChk(ierr);
297   opref->data = NULL;
298   opref->setupdone = 0;
299   opref->ceed = ceedref;
300   ierr = ceedref->OperatorCreate(opref); CeedChk(ierr);
301   op->opfallback = opref;
302 
303   // Clone QF
304   CeedQFunction qfref;
305   ierr = CeedCalloc(1, &qfref); CeedChk(ierr);
306   memcpy(qfref, (op->qf), sizeof(*qfref)); CeedChk(ierr);
307   qfref->data = NULL;
308   qfref->ceed = ceedref;
309   ierr = ceedref->QFunctionCreate(qfref); CeedChk(ierr);
310   opref->qf = qfref;
311   op->qffallback = qfref;
312 
313   return 0;
314 }
315 
316 /**
317   @brief Check if a CeedOperator is ready to be used.
318 
319   @param[in] ceed Ceed object for error handling
320   @param[in] op   CeedOperator to check
321 
322   @return An error code: 0 - success, otherwise - failure
323 
324   @ref Basic
325 **/
326 static int CeedOperatorCheckReady(Ceed ceed, CeedOperator op) {
327   CeedQFunction qf = op->qf;
328 
329   if (op->composite) {
330     if (!op->numsub)
331       // LCOV_EXCL_START
332       return CeedError(ceed, 1, "No suboperators set");
333     // LCOV_EXCL_STOP
334   } else {
335     if (op->nfields == 0)
336       // LCOV_EXCL_START
337       return CeedError(ceed, 1, "No operator fields set");
338     // LCOV_EXCL_STOP
339     if (op->nfields < qf->numinputfields + qf->numoutputfields)
340       // LCOV_EXCL_START
341       return CeedError(ceed, 1, "Not all operator fields set");
342     // LCOV_EXCL_STOP
343     if (!op->hasrestriction)
344       // LCOV_EXCL_START
345       return CeedError(ceed, 1,"At least one restriction required");
346     // LCOV_EXCL_STOP
347     if (op->numqpoints == 0)
348       // LCOV_EXCL_START
349       return CeedError(ceed, 1,"At least one non-collocated basis required");
350     // LCOV_EXCL_STOP
351   }
352 
353   return 0;
354 }
355 
356 /**
357   @brief Assemble a linear CeedQFunction associated with a CeedOperator
358 
359   This returns a CeedVector containing a matrix at each quadrature point
360     providing the action of the CeedQFunction associated with the CeedOperator.
361     The vector 'assembled' is of shape
362       [num_elements, num_input_fields, num_output_fields, num_quad_points]
363     and contains column-major matrices representing the action of the
364     CeedQFunction for a corresponding quadrature point on an element. Inputs and
365     outputs are in the order provided by the user when adding CeedOperator fields.
366     For example, a QFunction with inputs 'u' and 'gradu' and outputs 'gradv' and
367     'v', provided in that order, would result in an assembled QFunction that
368     consists of (1 + dim) x (dim + 1) matrices at each quadrature point acting
369     on the input [u, du_0, du_1] and producing the output [dv_0, dv_1, v].
370 
371   @param op             CeedOperator to assemble CeedQFunction
372   @param[out] assembled CeedVector to store assembled CeedQFunction at
373                           quadrature points
374   @param[out] rstr      CeedElemRestriction for CeedVector containing assembled
375                           CeedQFunction
376   @param request        Address of CeedRequest for non-blocking completion, else
377                           CEED_REQUEST_IMMEDIATE
378 
379   @return An error code: 0 - success, otherwise - failure
380 
381   @ref Basic
382 **/
383 int CeedOperatorAssembleLinearQFunction(CeedOperator op, CeedVector *assembled,
384                                         CeedElemRestriction *rstr,
385                                         CeedRequest *request) {
386   int ierr;
387   Ceed ceed = op->ceed;
388   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
389 
390   // Backend version
391   if (op->AssembleLinearQFunction) {
392     ierr = op->AssembleLinearQFunction(op, assembled, rstr, request);
393     CeedChk(ierr);
394   } else {
395     // Fallback to reference Ceed
396     if (!op->opfallback) {
397       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
398     }
399     // Assemble
400     ierr = op->opfallback->AssembleLinearQFunction(op->opfallback, assembled,
401            rstr, request); CeedChk(ierr);
402   }
403 
404   return 0;
405 }
406 
407 /**
408   @brief Assemble the diagonal of a square linear Operator
409 
410   This returns a CeedVector containing the diagonal of a linear CeedOperator.
411 
412   @param op             CeedOperator to assemble CeedQFunction
413   @param[out] assembled CeedVector to store assembled CeedOperator diagonal
414   @param request        Address of CeedRequest for non-blocking completion, else
415                           CEED_REQUEST_IMMEDIATE
416 
417   @return An error code: 0 - success, otherwise - failure
418 
419   @ref Basic
420 **/
421 int CeedOperatorAssembleLinearDiagonal(CeedOperator op, CeedVector *assembled,
422                                        CeedRequest *request) {
423   int ierr;
424   Ceed ceed = op->ceed;
425   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
426 
427   // Use backend version, if available
428   if (op->AssembleLinearDiagonal) {
429     ierr = op->AssembleLinearDiagonal(op, assembled, request); CeedChk(ierr);
430   } else {
431     // Fallback to reference Ceed
432     if (!op->opfallback) {
433       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
434     }
435     // Assemble
436     ierr = op->opfallback->AssembleLinearDiagonal(op->opfallback, assembled,
437            request); CeedChk(ierr);
438   }
439 
440   return 0;
441 }
442 
443 /**
444   @brief Build a FDM based approximate inverse for each element for a
445            CeedOperator
446 
447   This returns a CeedOperator and CeedVector to apply a Fast Diagonalization
448     Method based approximate inverse. This function obtains the simultaneous
449     diagonalization for the 1D mass and Laplacian operators,
450       M = V^T V, K = V^T S V.
451     The assembled QFunction is used to modify the eigenvalues from simultaneous
452     diagonalization and obtain an approximate inverse of the form
453       V^T S^hat V. The CeedOperator must be linear and non-composite. The
454     associated CeedQFunction must therefore also be linear.
455 
456   @param op             CeedOperator to create element inverses
457   @param[out] fdminv    CeedOperator to apply the action of a FDM based inverse
458                           for each element
459   @param request        Address of CeedRequest for non-blocking completion, else
460                           CEED_REQUEST_IMMEDIATE
461 
462   @return An error code: 0 - success, otherwise - failure
463 
464   @ref Advanced
465 **/
466 int CeedOperatorCreateFDMElementInverse(CeedOperator op, CeedOperator *fdminv,
467                                         CeedRequest *request) {
468   int ierr;
469   Ceed ceed = op->ceed;
470   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
471 
472   // Use backend version, if available
473   if (op->CreateFDMElementInverse) {
474     ierr = op->CreateFDMElementInverse(op, fdminv, request); CeedChk(ierr);
475   } else {
476     // Fallback to reference Ceed
477     if (!op->opfallback) {
478       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
479     }
480     // Assemble
481     ierr = op->opfallback->CreateFDMElementInverse(op->opfallback, fdminv,
482            request); CeedChk(ierr);
483   }
484 
485   return 0;
486 }
487 
488 
489 /**
490   @brief Apply CeedOperator to a vector
491 
492   This computes the action of the operator on the specified (active) input,
493   yielding its (active) output.  All inputs and outputs must be specified using
494   CeedOperatorSetField().
495 
496   @param op        CeedOperator to apply
497   @param[in] in    CeedVector containing input state or CEED_VECTOR_NONE if
498                   there are no active inputs
499   @param[out] out  CeedVector to store result of applying operator (must be
500                      distinct from @a in) or CEED_VECTOR_NONE if there are no
501                      active outputs
502   @param request   Address of CeedRequest for non-blocking completion, else
503                      CEED_REQUEST_IMMEDIATE
504 
505   @return An error code: 0 - success, otherwise - failure
506 
507   @ref Basic
508 **/
509 int CeedOperatorApply(CeedOperator op, CeedVector in, CeedVector out,
510                       CeedRequest *request) {
511   int ierr;
512   Ceed ceed = op->ceed;
513   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
514 
515   if (op->numelements)  {
516     // Standard Operator
517     if (op->Apply) {
518       ierr = op->Apply(op, in, out, request); CeedChk(ierr);
519     } else {
520       // Zero all output vectors
521       CeedQFunction qf = op->qf;
522       for (CeedInt i=0; i<qf->numoutputfields; i++) {
523         CeedVector vec = op->outputfields[i]->vec;
524         if (vec == CEED_VECTOR_ACTIVE)
525           vec = out;
526         if (vec != CEED_VECTOR_NONE) {
527           ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr);
528         }
529       }
530       // Apply
531       ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr);
532     }
533   } else if (op->composite) {
534     // Composite Operator
535     if (op->ApplyComposite) {
536       ierr = op->ApplyComposite(op, in, out, request); CeedChk(ierr);
537     } else {
538       CeedInt numsub;
539       ierr = CeedOperatorGetNumSub(op, &numsub); CeedChk(ierr);
540       CeedOperator *suboperators;
541       ierr = CeedOperatorGetSubList(op, &suboperators); CeedChk(ierr);
542 
543       // Zero all output vectors
544       if (out != CEED_VECTOR_NONE) {
545         ierr = CeedVectorSetValue(out, 0.0); CeedChk(ierr);
546       }
547       for (CeedInt i=0; i<numsub; i++) {
548         for (CeedInt j=0; j<suboperators[i]->qf->numoutputfields; j++) {
549           CeedVector vec = suboperators[i]->outputfields[j]->vec;
550           if (vec != CEED_VECTOR_ACTIVE && vec != CEED_VECTOR_NONE) {
551             ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr);
552           }
553         }
554       }
555       // Apply
556       for (CeedInt i=0; i<op->numsub; i++) {
557         ierr = CeedOperatorApplyAdd(op->suboperators[i], in, out, request);
558         CeedChk(ierr);
559       }
560     }
561   }
562 
563   return 0;
564 }
565 
566 /**
567   @brief Apply CeedOperator to a vector and add result to output vector
568 
569   This computes the action of the operator on the specified (active) input,
570   yielding its (active) output.  All inputs and outputs must be specified using
571   CeedOperatorSetField().
572 
573   @param op        CeedOperator to apply
574   @param[in] in    CeedVector containing input state or NULL if there are no
575                      active inputs
576   @param[out] out  CeedVector to sum in result of applying operator (must be
577                      distinct from @a in) or NULL if there are no active outputs
578   @param request   Address of CeedRequest for non-blocking completion, else
579                      CEED_REQUEST_IMMEDIATE
580 
581   @return An error code: 0 - success, otherwise - failure
582 
583   @ref Basic
584 **/
585 int CeedOperatorApplyAdd(CeedOperator op, CeedVector in, CeedVector out,
586                          CeedRequest *request) {
587   int ierr;
588   Ceed ceed = op->ceed;
589   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
590 
591   if (op->numelements)  {
592     // Standard Operator
593     ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr);
594   } else if (op->composite) {
595     // Composite Operator
596     if (op->ApplyAddComposite) {
597       ierr = op->ApplyAddComposite(op, in, out, request); CeedChk(ierr);
598     } else {
599       CeedInt numsub;
600       ierr = CeedOperatorGetNumSub(op, &numsub); CeedChk(ierr);
601       CeedOperator *suboperators;
602       ierr = CeedOperatorGetSubList(op, &suboperators); CeedChk(ierr);
603 
604       for (CeedInt i=0; i<numsub; i++) {
605         ierr = CeedOperatorApplyAdd(suboperators[i], in, out, request);
606         CeedChk(ierr);
607       }
608     }
609   }
610 
611   return 0;
612 }
613 
614 /**
615   @brief Get the Ceed associated with a CeedOperator
616 
617   @param op              CeedOperator
618   @param[out] ceed       Variable to store Ceed
619 
620   @return An error code: 0 - success, otherwise - failure
621 
622   @ref Advanced
623 **/
624 
625 int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) {
626   *ceed = op->ceed;
627   return 0;
628 }
629 
630 /**
631   @brief Get the number of elements associated with a CeedOperator
632 
633   @param op              CeedOperator
634   @param[out] numelem    Variable to store number of elements
635 
636   @return An error code: 0 - success, otherwise - failure
637 
638   @ref Advanced
639 **/
640 
641 int CeedOperatorGetNumElements(CeedOperator op, CeedInt *numelem) {
642   if (op->composite)
643     // LCOV_EXCL_START
644     return CeedError(op->ceed, 1, "Not defined for composite operator");
645   // LCOV_EXCL_STOP
646 
647   *numelem = op->numelements;
648   return 0;
649 }
650 
651 /**
652   @brief Get the number of quadrature points associated with a CeedOperator
653 
654   @param op              CeedOperator
655   @param[out] numqpts    Variable to store vector number of quadrature points
656 
657   @return An error code: 0 - success, otherwise - failure
658 
659   @ref Advanced
660 **/
661 
662 int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *numqpts) {
663   if (op->composite)
664     // LCOV_EXCL_START
665     return CeedError(op->ceed, 1, "Not defined for composite operator");
666   // LCOV_EXCL_STOP
667 
668   *numqpts = op->numqpoints;
669   return 0;
670 }
671 
672 /**
673   @brief Get the number of arguments associated with a CeedOperator
674 
675   @param op              CeedOperator
676   @param[out] numargs    Variable to store vector number of arguments
677 
678   @return An error code: 0 - success, otherwise - failure
679 
680   @ref Advanced
681 **/
682 
683 int CeedOperatorGetNumArgs(CeedOperator op, CeedInt *numargs) {
684   if (op->composite)
685     // LCOV_EXCL_START
686     return CeedError(op->ceed, 1, "Not defined for composite operators");
687   // LCOV_EXCL_STOP
688 
689   *numargs = op->nfields;
690   return 0;
691 }
692 
693 /**
694   @brief Get the setup status of a CeedOperator
695 
696   @param op             CeedOperator
697   @param[out] setupdone Variable to store setup status
698 
699   @return An error code: 0 - success, otherwise - failure
700 
701   @ref Advanced
702 **/
703 
704 int CeedOperatorGetSetupStatus(CeedOperator op, bool *setupdone) {
705   *setupdone = op->setupdone;
706   return 0;
707 }
708 
709 /**
710   @brief Get the QFunction associated with a CeedOperator
711 
712   @param op              CeedOperator
713   @param[out] qf         Variable to store QFunction
714 
715   @return An error code: 0 - success, otherwise - failure
716 
717   @ref Advanced
718 **/
719 
720 int CeedOperatorGetQFunction(CeedOperator op, CeedQFunction *qf) {
721   if (op->composite)
722     // LCOV_EXCL_START
723     return CeedError(op->ceed, 1, "Not defined for composite operator");
724   // LCOV_EXCL_STOP
725 
726   *qf = op->qf;
727   return 0;
728 }
729 
730 /**
731   @brief Get the number of suboperators associated with a CeedOperator
732 
733   @param op              CeedOperator
734   @param[out] numsub     Variable to store number of suboperators
735 
736   @return An error code: 0 - success, otherwise - failure
737 
738   @ref Advanced
739 **/
740 
741 int CeedOperatorGetNumSub(CeedOperator op, CeedInt *numsub) {
742   if (!op->composite)
743     // LCOV_EXCL_START
744     return CeedError(op->ceed, 1, "Not a composite operator");
745   // LCOV_EXCL_STOP
746 
747   *numsub = op->numsub;
748   return 0;
749 }
750 
751 /**
752   @brief Get the list of suboperators associated with a CeedOperator
753 
754   @param op                CeedOperator
755   @param[out] suboperators Variable to store list of suboperators
756 
757   @return An error code: 0 - success, otherwise - failure
758 
759   @ref Advanced
760 **/
761 
762 int CeedOperatorGetSubList(CeedOperator op, CeedOperator **suboperators) {
763   if (!op->composite)
764     // LCOV_EXCL_START
765     return CeedError(op->ceed, 1, "Not a composite operator");
766   // LCOV_EXCL_STOP
767 
768   *suboperators = op->suboperators;
769   return 0;
770 }
771 
772 /**
773   @brief Set the backend data of a CeedOperator
774 
775   @param[out] op         CeedOperator
776   @param data            Data to set
777 
778   @return An error code: 0 - success, otherwise - failure
779 
780   @ref Advanced
781 **/
782 
783 int CeedOperatorSetData(CeedOperator op, void **data) {
784   op->data = *data;
785   return 0;
786 }
787 
788 /**
789   @brief Get the backend data of a CeedOperator
790 
791   @param op              CeedOperator
792   @param[out] data       Variable to store data
793 
794   @return An error code: 0 - success, otherwise - failure
795 
796   @ref Advanced
797 **/
798 
799 int CeedOperatorGetData(CeedOperator op, void **data) {
800   *data = op->data;
801   return 0;
802 }
803 
804 /**
805   @brief Set the setup flag of a CeedOperator to True
806 
807   @param op              CeedOperator
808 
809   @return An error code: 0 - success, otherwise - failure
810 
811   @ref Advanced
812 **/
813 
814 int CeedOperatorSetSetupDone(CeedOperator op) {
815   op->setupdone = 1;
816   return 0;
817 }
818 
819 /**
820   @brief View a field of a CeedOperator
821 
822   @param[in] field       Operator field to view
823   @param[in] fieldnumber Number of field being viewed
824   @param[in] stream      Stream to view to, e.g., stdout
825 
826   @return An error code: 0 - success, otherwise - failure
827 
828   @ref Utility
829 **/
830 static int CeedOperatorFieldView(CeedOperatorField field,
831                                  CeedQFunctionField qffield,
832                                  CeedInt fieldnumber, bool sub, bool in,
833                                  FILE *stream) {
834   const char *pre = sub ? "  " : "";
835   const char *inout = in ? "Input" : "Output";
836 
837   fprintf(stream, "%s    %s Field [%d]:\n"
838           "%s      Name: \"%s\"\n"
839           "%s      Lmode: \"%s\"\n",
840           pre, inout, fieldnumber, pre, qffield->fieldname,
841           pre, CeedTransposeModes[field->lmode]);
842 
843   if (field->basis == CEED_BASIS_COLLOCATED)
844     fprintf(stream, "%s      Collocated basis\n", pre);
845 
846   if (field->vec == CEED_VECTOR_ACTIVE)
847     fprintf(stream, "%s      Active vector\n", pre);
848   else if (field->vec == CEED_VECTOR_NONE)
849     fprintf(stream, "%s      No vector\n", pre);
850 
851   return 0;
852 }
853 
854 /**
855   @brief View a single CeedOperator
856 
857   @param[in] op     CeedOperator to view
858   @param[in] sub    Boolean flag for sub-operator
859   @param[in] stream Stream to write; typically stdout/stderr or a file
860 
861   @return Error code: 0 - success, otherwise - failure
862 
863   @ref Utility
864 **/
865 int CeedOperatorSingleView(CeedOperator op, bool sub, FILE *stream) {
866   int ierr;
867   const char *pre = sub ? "  " : "";
868 
869   CeedInt totalfields;
870   ierr = CeedOperatorGetNumArgs(op, &totalfields); CeedChk(ierr);
871 
872   fprintf(stream, "%s  %d Field%s\n", pre, totalfields, totalfields>1 ? "s" : "");
873 
874   fprintf(stream, "%s  %d Input Field%s:\n", pre, op->qf->numinputfields,
875           op->qf->numinputfields>1 ? "s" : "");
876   for (CeedInt i=0; i<op->qf->numinputfields; i++) {
877     ierr = CeedOperatorFieldView(op->inputfields[i], op->qf->inputfields[i],
878                                  i, sub, 1, stream); CeedChk(ierr);
879   }
880 
881   fprintf(stream, "%s  %d Output Field%s:\n", pre, op->qf->numoutputfields,
882           op->qf->numoutputfields>1 ? "s" : "");
883   for (CeedInt i=0; i<op->qf->numoutputfields; i++) {
884     ierr = CeedOperatorFieldView(op->outputfields[i], op->qf->inputfields[i],
885                                  i, sub, 0, stream); CeedChk(ierr);
886   }
887 
888   return 0;
889 }
890 
891 /**
892   @brief View a CeedOperator
893 
894   @param[in] op     CeedOperator to view
895   @param[in] stream Stream to write; typically stdout/stderr or a file
896 
897   @return Error code: 0 - success, otherwise - failure
898 
899   @ref Utility
900 **/
901 int CeedOperatorView(CeedOperator op, FILE *stream) {
902   int ierr;
903 
904   if (op->composite) {
905     fprintf(stream, "Composite CeedOperator\n");
906 
907     for (CeedInt i=0; i<op->numsub; i++) {
908       fprintf(stream, "  SubOperator [%d]:\n", i);
909       ierr = CeedOperatorSingleView(op->suboperators[i], 1, stream);
910       CeedChk(ierr);
911     }
912   } else {
913     fprintf(stream, "CeedOperator\n");
914     ierr = CeedOperatorSingleView(op, 0, stream); CeedChk(ierr);
915   }
916 
917   return 0;
918 }
919 
920 /**
921   @brief Get the CeedOperatorFields of a CeedOperator
922 
923   @param op                 CeedOperator
924   @param[out] inputfields   Variable to store inputfields
925   @param[out] outputfields  Variable to store outputfields
926 
927   @return An error code: 0 - success, otherwise - failure
928 
929   @ref Advanced
930 **/
931 
932 int CeedOperatorGetFields(CeedOperator op, CeedOperatorField **inputfields,
933                           CeedOperatorField **outputfields) {
934   if (op->composite)
935     // LCOV_EXCL_START
936     return CeedError(op->ceed, 1, "Not defined for composite operator");
937   // LCOV_EXCL_STOP
938 
939   if (inputfields) *inputfields = op->inputfields;
940   if (outputfields) *outputfields = op->outputfields;
941   return 0;
942 }
943 
944 /**
945   @brief Get the L vector CeedTransposeMode of a CeedOperatorField
946 
947   @param opfield         CeedOperatorField
948   @param[out] lmode      Variable to store CeedTransposeMode
949 
950   @return An error code: 0 - success, otherwise - failure
951 
952   @ref Advanced
953 **/
954 
955 int CeedOperatorFieldGetLMode(CeedOperatorField opfield,
956                               CeedTransposeMode *lmode) {
957   *lmode = opfield->lmode;
958   return 0;
959 }
960 
961 /**
962   @brief Get the CeedElemRestriction of a CeedOperatorField
963 
964   @param opfield         CeedOperatorField
965   @param[out] rstr       Variable to store CeedElemRestriction
966 
967   @return An error code: 0 - success, otherwise - failure
968 
969   @ref Advanced
970 **/
971 
972 int CeedOperatorFieldGetElemRestriction(CeedOperatorField opfield,
973                                         CeedElemRestriction *rstr) {
974   *rstr = opfield->Erestrict;
975   return 0;
976 }
977 
978 /**
979   @brief Get the CeedBasis of a CeedOperatorField
980 
981   @param opfield         CeedOperatorField
982   @param[out] basis      Variable to store CeedBasis
983 
984   @return An error code: 0 - success, otherwise - failure
985 
986   @ref Advanced
987 **/
988 
989 int CeedOperatorFieldGetBasis(CeedOperatorField opfield, CeedBasis *basis) {
990   *basis = opfield->basis;
991   return 0;
992 }
993 
994 /**
995   @brief Get the CeedVector of a CeedOperatorField
996 
997   @param opfield         CeedOperatorField
998   @param[out] vec        Variable to store CeedVector
999 
1000   @return An error code: 0 - success, otherwise - failure
1001 
1002   @ref Advanced
1003 **/
1004 
1005 int CeedOperatorFieldGetVector(CeedOperatorField opfield, CeedVector *vec) {
1006   *vec = opfield->vec;
1007   return 0;
1008 }
1009 
1010 /**
1011   @brief Destroy a CeedOperator
1012 
1013   @param op CeedOperator to destroy
1014 
1015   @return An error code: 0 - success, otherwise - failure
1016 
1017   @ref Basic
1018 **/
1019 int CeedOperatorDestroy(CeedOperator *op) {
1020   int ierr;
1021 
1022   if (!*op || --(*op)->refcount > 0) return 0;
1023   if ((*op)->Destroy) {
1024     ierr = (*op)->Destroy(*op); CeedChk(ierr);
1025   }
1026   ierr = CeedDestroy(&(*op)->ceed); CeedChk(ierr);
1027   // Free fields
1028   for (int i=0; i<(*op)->nfields; i++)
1029     if ((*op)->inputfields[i]) {
1030       ierr = CeedElemRestrictionDestroy(&(*op)->inputfields[i]->Erestrict);
1031       CeedChk(ierr);
1032       if ((*op)->inputfields[i]->basis != CEED_BASIS_COLLOCATED) {
1033         ierr = CeedBasisDestroy(&(*op)->inputfields[i]->basis); CeedChk(ierr);
1034       }
1035       if ((*op)->inputfields[i]->vec != CEED_VECTOR_ACTIVE &&
1036           (*op)->inputfields[i]->vec != CEED_VECTOR_NONE ) {
1037         ierr = CeedVectorDestroy(&(*op)->inputfields[i]->vec); CeedChk(ierr);
1038       }
1039       ierr = CeedFree(&(*op)->inputfields[i]); CeedChk(ierr);
1040     }
1041   for (int i=0; i<(*op)->nfields; i++)
1042     if ((*op)->outputfields[i]) {
1043       ierr = CeedElemRestrictionDestroy(&(*op)->outputfields[i]->Erestrict);
1044       CeedChk(ierr);
1045       if ((*op)->outputfields[i]->basis != CEED_BASIS_COLLOCATED) {
1046         ierr = CeedBasisDestroy(&(*op)->outputfields[i]->basis); CeedChk(ierr);
1047       }
1048       if ((*op)->outputfields[i]->vec != CEED_VECTOR_ACTIVE &&
1049           (*op)->outputfields[i]->vec != CEED_VECTOR_NONE ) {
1050         ierr = CeedVectorDestroy(&(*op)->outputfields[i]->vec); CeedChk(ierr);
1051       }
1052       ierr = CeedFree(&(*op)->outputfields[i]); CeedChk(ierr);
1053     }
1054   // Destroy suboperators
1055   for (int i=0; i<(*op)->numsub; i++)
1056     if ((*op)->suboperators[i]) {
1057       ierr = CeedOperatorDestroy(&(*op)->suboperators[i]); CeedChk(ierr);
1058     }
1059   ierr = CeedQFunctionDestroy(&(*op)->qf); CeedChk(ierr);
1060   ierr = CeedQFunctionDestroy(&(*op)->dqf); CeedChk(ierr);
1061   ierr = CeedQFunctionDestroy(&(*op)->dqfT); CeedChk(ierr);
1062 
1063   // Destroy fallback
1064   if ((*op)->opfallback) {
1065     ierr = (*op)->qffallback->Destroy((*op)->qffallback); CeedChk(ierr);
1066     ierr = CeedFree(&(*op)->qffallback); CeedChk(ierr);
1067     ierr = (*op)->opfallback->Destroy((*op)->opfallback); CeedChk(ierr);
1068     ierr = CeedFree(&(*op)->opfallback); CeedChk(ierr);
1069   }
1070 
1071   ierr = CeedFree(&(*op)->inputfields); CeedChk(ierr);
1072   ierr = CeedFree(&(*op)->outputfields); CeedChk(ierr);
1073   ierr = CeedFree(&(*op)->suboperators); CeedChk(ierr);
1074   ierr = CeedFree(op); CeedChk(ierr);
1075   return 0;
1076 }
1077 
1078 /// @}
1079