xref: /libCEED/interface/ceed-operator.c (revision f10650af6497af6d0949b45f2eee824400fc9b71)
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   Ceed ceedref;
285   ierr = CeedInit(fallbackresource, &ceedref); CeedChk(ierr);
286   ceedref->opfallbackparent = op->ceed;
287   op->ceed->opfallbackceed = ceedref;
288 
289   // Clone Op
290   CeedOperator opref;
291   ierr = CeedCalloc(1, &opref); CeedChk(ierr);
292   memcpy(opref, op, sizeof(*opref)); CeedChk(ierr);
293   opref->data = NULL;
294   opref->setupdone = 0;
295   opref->ceed = ceedref;
296   ierr = ceedref->OperatorCreate(opref); CeedChk(ierr);
297   op->opfallback = opref;
298 
299   // Clone QF
300   CeedQFunction qfref;
301   ierr = CeedCalloc(1, &qfref); CeedChk(ierr);
302   memcpy(qfref, (op->qf), sizeof(*qfref)); CeedChk(ierr);
303   qfref->data = NULL;
304   qfref->ceed = ceedref;
305   ierr = ceedref->QFunctionCreate(qfref); CeedChk(ierr);
306   opref->qf = qfref;
307   op->qffallback = qfref;
308 
309   return 0;
310 }
311 
312 /**
313   @brief Check if a CeedOperator is ready to be used.
314 
315   @param[in] ceed Ceed object for error handling
316   @param[in] op   CeedOperator to check
317 
318   @return An error code: 0 - success, otherwise - failure
319 
320   @ref Basic
321 **/
322 static int CeedOperatorCheckReady(Ceed ceed, CeedOperator op) {
323   CeedQFunction qf = op->qf;
324 
325   if (op->composite) {
326     if (!op->numsub)
327       // LCOV_EXCL_START
328       return CeedError(ceed, 1, "No suboperators set");
329     // LCOV_EXCL_STOP
330   } else {
331     if (op->nfields == 0)
332       // LCOV_EXCL_START
333       return CeedError(ceed, 1, "No operator fields set");
334     // LCOV_EXCL_STOP
335     if (op->nfields < qf->numinputfields + qf->numoutputfields)
336       // LCOV_EXCL_START
337       return CeedError(ceed, 1, "Not all operator fields set");
338     // LCOV_EXCL_STOP
339     if (!op->hasrestriction)
340       // LCOV_EXCL_START
341       return CeedError(ceed, 1,"At least one restriction required");
342     // LCOV_EXCL_STOP
343     if (op->numqpoints == 0)
344       // LCOV_EXCL_START
345       return CeedError(ceed, 1,"At least one non-collocated basis required");
346     // LCOV_EXCL_STOP
347   }
348 
349   return 0;
350 }
351 
352 /**
353   @brief Assemble a linear CeedQFunction associated with a CeedOperator
354 
355   This returns a CeedVector containing a matrix at each quadrature point
356     providing the action of the CeedQFunction associated with the CeedOperator.
357     The vector 'assembled' is of shape
358       [num_elements, num_input_fields, num_output_fields, num_quad_points]
359     and contains column-major matrices representing the action of the
360     CeedQFunction for a corresponding quadrature point on an element. Inputs and
361     outputs are in the order provided by the user when adding CeedOperator fields.
362     For example, a QFunction with inputs 'u' and 'gradu' and outputs 'gradv' and
363     'v', provided in that order, would result in an assembled QFunction that
364     consists of (1 + dim) x (dim + 1) matrices at each quadrature point acting
365     on the input [u, du_0, du_1] and producing the output [dv_0, dv_1, v].
366 
367   @param op             CeedOperator to assemble CeedQFunction
368   @param[out] assembled CeedVector to store assembled CeedQFunction at
369                           quadrature points
370   @param[out] rstr      CeedElemRestriction for CeedVector containing assembled
371                           CeedQFunction
372   @param request        Address of CeedRequest for non-blocking completion, else
373                           CEED_REQUEST_IMMEDIATE
374 
375   @return An error code: 0 - success, otherwise - failure
376 
377   @ref Basic
378 **/
379 int CeedOperatorAssembleLinearQFunction(CeedOperator op, CeedVector *assembled,
380                                         CeedElemRestriction *rstr,
381                                         CeedRequest *request) {
382   int ierr;
383   Ceed ceed = op->ceed;
384   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
385 
386   // Backend version
387   if (op->AssembleLinearQFunction) {
388     ierr = op->AssembleLinearQFunction(op, assembled, rstr, request);
389     CeedChk(ierr);
390   } else {
391     // Fallback to reference Ceed
392     if (!op->opfallback) {
393       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
394     }
395     // Assemble
396     ierr = op->opfallback->AssembleLinearQFunction(op->opfallback, assembled,
397            rstr, request); CeedChk(ierr);
398   }
399 
400   return 0;
401 }
402 
403 /**
404   @brief Assemble the diagonal of a square linear Operator
405 
406   This returns a CeedVector containing the diagonal of a linear CeedOperator.
407 
408   @param op             CeedOperator to assemble CeedQFunction
409   @param[out] assembled CeedVector to store assembled CeedOperator diagonal
410   @param request        Address of CeedRequest for non-blocking completion, else
411                           CEED_REQUEST_IMMEDIATE
412 
413   @return An error code: 0 - success, otherwise - failure
414 
415   @ref Basic
416 **/
417 int CeedOperatorAssembleLinearDiagonal(CeedOperator op, CeedVector *assembled,
418                                        CeedRequest *request) {
419   int ierr;
420   Ceed ceed = op->ceed;
421   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
422 
423   // Use backend version, if available
424   if (op->AssembleLinearDiagonal) {
425     ierr = op->AssembleLinearDiagonal(op, assembled, request); CeedChk(ierr);
426   } else {
427     // Fallback to reference Ceed
428     if (!op->opfallback) {
429       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
430     }
431     // Assemble
432     ierr = op->opfallback->AssembleLinearDiagonal(op->opfallback, assembled,
433            request); CeedChk(ierr);
434   }
435 
436   return 0;
437 }
438 
439 /**
440   @brief Build a FDM based approximate inverse for each element for a
441            CeedOperator
442 
443   This returns a CeedOperator and CeedVector to apply a Fast Diagonalization
444     Method based approximate inverse. This function obtains the simultaneous
445     diagonalization for the 1D mass and Laplacian operators,
446       M = V^T V, K = V^T S V.
447     The assembled QFunction is used to modify the eigenvalues from simultaneous
448     diagonalization and obtain an approximate inverse of the form
449       V^T S^hat V. The CeedOperator must be linear and non-composite. The
450     associated CeedQFunction must therefore also be linear.
451 
452   @param op             CeedOperator to create element inverses
453   @param[out] fdminv    CeedOperator to apply the action of a FDM based inverse
454                           for each element
455   @param[out] qdata     CeedVector to hold qdata for fdminv
456   @param request        Address of CeedRequest for non-blocking completion, else
457                           CEED_REQUEST_IMMEDIATE
458 
459   @return An error code: 0 - success, otherwise - failure
460 
461   @ref Advanced
462 **/
463 int CeedOperatorCreateFDMElementInverse(CeedOperator op, CeedOperator *fdminv,
464                                         CeedRequest *request) {
465   int ierr;
466   Ceed ceed = op->ceed;
467   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
468 
469   // Use backend version, if available
470   if (op->CreateFDMElementInverse) {
471     ierr = op->CreateFDMElementInverse(op, fdminv, request); CeedChk(ierr);
472   } else {
473     // Fallback to reference Ceed
474     if (!op->opfallback) {
475       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
476     }
477     // Assemble
478     ierr = op->opfallback->CreateFDMElementInverse(op->opfallback, fdminv,
479            request); CeedChk(ierr);
480   }
481 
482   return 0;
483 }
484 
485 
486 /**
487   @brief Apply CeedOperator to a vector
488 
489   This computes the action of the operator on the specified (active) input,
490   yielding its (active) output.  All inputs and outputs must be specified using
491   CeedOperatorSetField().
492 
493   @param op        CeedOperator to apply
494   @param[in] in    CeedVector containing input state or CEED_VECTOR_NONE if
495                   there are no active inputs
496   @param[out] out  CeedVector to store result of applying operator (must be
497                      distinct from @a in) or CEED_VECTOR_NONE if there are no
498                      active outputs
499   @param request   Address of CeedRequest for non-blocking completion, else
500                      CEED_REQUEST_IMMEDIATE
501 
502   @return An error code: 0 - success, otherwise - failure
503 
504   @ref Basic
505 **/
506 int CeedOperatorApply(CeedOperator op, CeedVector in, CeedVector out,
507                       CeedRequest *request) {
508   int ierr;
509   Ceed ceed = op->ceed;
510   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
511 
512   if (op->numelements)  {
513     // Standard Operator
514     if (op->Apply) {
515       ierr = op->Apply(op, in, out, request); CeedChk(ierr);
516     } else {
517       // Zero all output vectors
518       CeedQFunction qf = op->qf;
519       for (CeedInt i=0; i<qf->numoutputfields; i++) {
520         CeedVector vec = op->outputfields[i]->vec;
521         if (vec == CEED_VECTOR_ACTIVE)
522           vec = out;
523         if (vec != CEED_VECTOR_NONE) {
524           ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr);
525         }
526       }
527       // Apply
528       ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr);
529     }
530   } else if (op->composite) {
531     // Composite Operator
532     if (op->ApplyComposite) {
533       ierr = op->ApplyComposite(op, in, out, request); CeedChk(ierr);
534     } else {
535       CeedInt numsub;
536       ierr = CeedOperatorGetNumSub(op, &numsub); CeedChk(ierr);
537       CeedOperator *suboperators;
538       ierr = CeedOperatorGetSubList(op, &suboperators); CeedChk(ierr);
539 
540       // Zero all output vectors
541       if (out != CEED_VECTOR_NONE) {
542         ierr = CeedVectorSetValue(out, 0.0); CeedChk(ierr);
543       }
544       for (CeedInt i=0; i<numsub; i++) {
545         for (CeedInt j=0; j<suboperators[i]->qf->numoutputfields; j++) {
546           CeedVector vec = suboperators[i]->outputfields[j]->vec;
547           if (vec != CEED_VECTOR_ACTIVE && vec != CEED_VECTOR_NONE) {
548             ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr);
549           }
550         }
551       }
552       // Apply
553       for (CeedInt i=0; i<op->numsub; i++) {
554         ierr = CeedOperatorApplyAdd(op->suboperators[i], in, out, request);
555         CeedChk(ierr);
556       }
557     }
558   }
559 
560   return 0;
561 }
562 
563 /**
564   @brief Apply CeedOperator to a vector and add result to output vector
565 
566   This computes the action of the operator on the specified (active) input,
567   yielding its (active) output.  All inputs and outputs must be specified using
568   CeedOperatorSetField().
569 
570   @param op        CeedOperator to apply
571   @param[in] in    CeedVector containing input state or NULL if there are no
572                      active inputs
573   @param[out] out  CeedVector to sum in result of applying operator (must be
574                      distinct from @a in) or NULL if there are no active outputs
575   @param request   Address of CeedRequest for non-blocking completion, else
576                      CEED_REQUEST_IMMEDIATE
577 
578   @return An error code: 0 - success, otherwise - failure
579 
580   @ref Basic
581 **/
582 int CeedOperatorApplyAdd(CeedOperator op, CeedVector in, CeedVector out,
583                          CeedRequest *request) {
584   int ierr;
585   Ceed ceed = op->ceed;
586   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
587 
588   if (op->numelements)  {
589     // Standard Operator
590     ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr);
591   } else if (op->composite) {
592     // Composite Operator
593     if (op->ApplyAddComposite) {
594       ierr = op->ApplyAddComposite(op, in, out, request); CeedChk(ierr);
595     } else {
596       CeedInt numsub;
597       ierr = CeedOperatorGetNumSub(op, &numsub); CeedChk(ierr);
598       CeedOperator *suboperators;
599       ierr = CeedOperatorGetSubList(op, &suboperators); CeedChk(ierr);
600 
601       for (CeedInt i=0; i<numsub; i++) {
602         ierr = CeedOperatorApplyAdd(suboperators[i], in, out, request);
603         CeedChk(ierr);
604       }
605     }
606   }
607 
608   return 0;
609 }
610 
611 /**
612   @brief Get the Ceed associated with a CeedOperator
613 
614   @param op              CeedOperator
615   @param[out] ceed       Variable to store Ceed
616 
617   @return An error code: 0 - success, otherwise - failure
618 
619   @ref Advanced
620 **/
621 
622 int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) {
623   *ceed = op->ceed;
624   return 0;
625 }
626 
627 /**
628   @brief Get the number of elements associated with a CeedOperator
629 
630   @param op              CeedOperator
631   @param[out] numelem    Variable to store number of elements
632 
633   @return An error code: 0 - success, otherwise - failure
634 
635   @ref Advanced
636 **/
637 
638 int CeedOperatorGetNumElements(CeedOperator op, CeedInt *numelem) {
639   if (op->composite)
640     // LCOV_EXCL_START
641     return CeedError(op->ceed, 1, "Not defined for composite operator");
642   // LCOV_EXCL_STOP
643 
644   *numelem = op->numelements;
645   return 0;
646 }
647 
648 /**
649   @brief Get the number of quadrature points associated with a CeedOperator
650 
651   @param op              CeedOperator
652   @param[out] numqpts    Variable to store vector number of quadrature points
653 
654   @return An error code: 0 - success, otherwise - failure
655 
656   @ref Advanced
657 **/
658 
659 int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *numqpts) {
660   if (op->composite)
661     // LCOV_EXCL_START
662     return CeedError(op->ceed, 1, "Not defined for composite operator");
663   // LCOV_EXCL_STOP
664 
665   *numqpts = op->numqpoints;
666   return 0;
667 }
668 
669 /**
670   @brief Get the number of arguments associated with a CeedOperator
671 
672   @param op              CeedOperator
673   @param[out] numargs    Variable to store vector number of arguments
674 
675   @return An error code: 0 - success, otherwise - failure
676 
677   @ref Advanced
678 **/
679 
680 int CeedOperatorGetNumArgs(CeedOperator op, CeedInt *numargs) {
681   if (op->composite)
682     // LCOV_EXCL_START
683     return CeedError(op->ceed, 1, "Not defined for composite operators");
684   // LCOV_EXCL_STOP
685 
686   *numargs = op->nfields;
687   return 0;
688 }
689 
690 /**
691   @brief Get the setup status of a CeedOperator
692 
693   @param op             CeedOperator
694   @param[out] setupdone Variable to store setup status
695 
696   @return An error code: 0 - success, otherwise - failure
697 
698   @ref Advanced
699 **/
700 
701 int CeedOperatorGetSetupStatus(CeedOperator op, bool *setupdone) {
702   *setupdone = op->setupdone;
703   return 0;
704 }
705 
706 /**
707   @brief Get the QFunction associated with a CeedOperator
708 
709   @param op              CeedOperator
710   @param[out] qf         Variable to store QFunction
711 
712   @return An error code: 0 - success, otherwise - failure
713 
714   @ref Advanced
715 **/
716 
717 int CeedOperatorGetQFunction(CeedOperator op, CeedQFunction *qf) {
718   if (op->composite)
719     // LCOV_EXCL_START
720     return CeedError(op->ceed, 1, "Not defined for composite operator");
721   // LCOV_EXCL_STOP
722 
723   *qf = op->qf;
724   return 0;
725 }
726 
727 /**
728   @brief Get the number of suboperators associated with a CeedOperator
729 
730   @param op              CeedOperator
731   @param[out] numsub     Variable to store number of suboperators
732 
733   @return An error code: 0 - success, otherwise - failure
734 
735   @ref Advanced
736 **/
737 
738 int CeedOperatorGetNumSub(CeedOperator op, CeedInt *numsub) {
739   if (!op->composite)
740     // LCOV_EXCL_START
741     return CeedError(op->ceed, 1, "Not a composite operator");
742   // LCOV_EXCL_STOP
743 
744   *numsub = op->numsub;
745   return 0;
746 }
747 
748 /**
749   @brief Get the list of suboperators associated with a CeedOperator
750 
751   @param op                CeedOperator
752   @param[out] suboperators Variable to store list of suboperators
753 
754   @return An error code: 0 - success, otherwise - failure
755 
756   @ref Advanced
757 **/
758 
759 int CeedOperatorGetSubList(CeedOperator op, CeedOperator **suboperators) {
760   if (!op->composite)
761     // LCOV_EXCL_START
762     return CeedError(op->ceed, 1, "Not a composite operator");
763   // LCOV_EXCL_STOP
764 
765   *suboperators = op->suboperators;
766   return 0;
767 }
768 
769 /**
770   @brief Set the backend data of a CeedOperator
771 
772   @param[out] op         CeedOperator
773   @param data            Data to set
774 
775   @return An error code: 0 - success, otherwise - failure
776 
777   @ref Advanced
778 **/
779 
780 int CeedOperatorSetData(CeedOperator op, void **data) {
781   op->data = *data;
782   return 0;
783 }
784 
785 /**
786   @brief Get the backend data of a CeedOperator
787 
788   @param op              CeedOperator
789   @param[out] data       Variable to store data
790 
791   @return An error code: 0 - success, otherwise - failure
792 
793   @ref Advanced
794 **/
795 
796 int CeedOperatorGetData(CeedOperator op, void **data) {
797   *data = op->data;
798   return 0;
799 }
800 
801 /**
802   @brief Set the setup flag of a CeedOperator to True
803 
804   @param op              CeedOperator
805 
806   @return An error code: 0 - success, otherwise - failure
807 
808   @ref Advanced
809 **/
810 
811 int CeedOperatorSetSetupDone(CeedOperator op) {
812   op->setupdone = 1;
813   return 0;
814 }
815 
816 /**
817   @brief View a field of a CeedOperator
818 
819   @param[in] field       Operator field to view
820   @param[in] fieldnumber Number of field being viewed
821   @param[in] stream      Stream to view to, e.g., stdout
822 
823   @return An error code: 0 - success, otherwise - failure
824 
825   @ref Utility
826 **/
827 static int CeedOperatorFieldView(CeedOperatorField field,
828                                  CeedQFunctionField qffield,
829                                  CeedInt fieldnumber, bool sub, bool in,
830                                  FILE *stream) {
831   const char *pre = sub ? "  " : "";
832   const char *inout = in ? "Input" : "Output";
833 
834   fprintf(stream, "%s    %s Field [%d]:\n"
835           "%s      Name: \"%s\"\n"
836           "%s      Lmode: \"%s\"\n",
837           pre, inout, fieldnumber, pre, qffield->fieldname,
838           pre, CeedTransposeModes[field->lmode]);
839 
840   if (field->basis == CEED_BASIS_COLLOCATED)
841     fprintf(stream, "%s      Collocated basis\n", pre);
842 
843   if (field->vec == CEED_VECTOR_ACTIVE)
844     fprintf(stream, "%s      Active vector\n", pre);
845   else if (field->vec == CEED_VECTOR_NONE)
846     fprintf(stream, "%s      No vector\n", pre);
847 
848   return 0;
849 }
850 
851 /**
852   @brief View a single CeedOperator
853 
854   @param[in] op     CeedOperator to view
855   @param[in] stream Stream to write; typically stdout/stderr or a file
856 
857   @return Error code: 0 - success, otherwise - failure
858 
859   @ref Utility
860 **/
861 int CeedOperatorSingleView(CeedOperator op, bool sub, FILE *stream) {
862   int ierr;
863   const char *pre = sub ? "  " : "";
864 
865   CeedInt totalfields;
866   ierr = CeedOperatorGetNumArgs(op, &totalfields); CeedChk(ierr);
867 
868   fprintf(stream, "%s  %d Field%s\n", pre, totalfields, totalfields>1 ? "s" : "");
869 
870   fprintf(stream, "%s  %d Input Field%s:\n", pre, op->qf->numinputfields,
871           op->qf->numinputfields>1 ? "s" : "");
872   for (CeedInt i=0; i<op->qf->numinputfields; i++) {
873     ierr = CeedOperatorFieldView(op->inputfields[i], op->qf->inputfields[i],
874                                  i, sub, 1, stream); CeedChk(ierr);
875   }
876 
877   fprintf(stream, "%s  %d Output Field%s:\n", pre, op->qf->numoutputfields,
878           op->qf->numoutputfields>1 ? "s" : "");
879   for (CeedInt i=0; i<op->qf->numoutputfields; i++) {
880     ierr = CeedOperatorFieldView(op->outputfields[i], op->qf->inputfields[i],
881                                  i, sub, 0, stream); CeedChk(ierr);
882   }
883 
884   return 0;
885 }
886 
887 /**
888   @brief View a CeedOperator
889 
890   @param[in] op     CeedOperator to view
891   @param[in] stream Stream to write; typically stdout/stderr or a file
892 
893   @return Error code: 0 - success, otherwise - failure
894 
895   @ref Utility
896 **/
897 int CeedOperatorView(CeedOperator op, FILE *stream) {
898   int ierr;
899 
900   if (op->composite) {
901     fprintf(stream, "Composite CeedOperator\n");
902 
903     for (CeedInt i=0; i<op->numsub; i++) {
904       fprintf(stream, "  SubOperator [%d]:\n", i);
905       ierr = CeedOperatorSingleView(op->suboperators[i], 1, stream);
906       CeedChk(ierr);
907     }
908   } else {
909     fprintf(stream, "CeedOperator\n");
910     ierr = CeedOperatorSingleView(op, 0, stream); CeedChk(ierr);
911   }
912 
913   return 0;
914 }
915 
916 /**
917   @brief Get the CeedOperatorFields of a CeedOperator
918 
919   @param op                 CeedOperator
920   @param[out] inputfields   Variable to store inputfields
921   @param[out] outputfields  Variable to store outputfields
922 
923   @return An error code: 0 - success, otherwise - failure
924 
925   @ref Advanced
926 **/
927 
928 int CeedOperatorGetFields(CeedOperator op, CeedOperatorField **inputfields,
929                           CeedOperatorField **outputfields) {
930   if (op->composite)
931     // LCOV_EXCL_START
932     return CeedError(op->ceed, 1, "Not defined for composite operator");
933   // LCOV_EXCL_STOP
934 
935   if (inputfields) *inputfields = op->inputfields;
936   if (outputfields) *outputfields = op->outputfields;
937   return 0;
938 }
939 
940 /**
941   @brief Get the L vector CeedTransposeMode of a CeedOperatorField
942 
943   @param opfield         CeedOperatorField
944   @param[out] lmode      Variable to store CeedTransposeMode
945 
946   @return An error code: 0 - success, otherwise - failure
947 
948   @ref Advanced
949 **/
950 
951 int CeedOperatorFieldGetLMode(CeedOperatorField opfield,
952                               CeedTransposeMode *lmode) {
953   *lmode = opfield->lmode;
954   return 0;
955 }
956 
957 /**
958   @brief Get the CeedElemRestriction of a CeedOperatorField
959 
960   @param opfield         CeedOperatorField
961   @param[out] rstr       Variable to store CeedElemRestriction
962 
963   @return An error code: 0 - success, otherwise - failure
964 
965   @ref Advanced
966 **/
967 
968 int CeedOperatorFieldGetElemRestriction(CeedOperatorField opfield,
969                                         CeedElemRestriction *rstr) {
970   *rstr = opfield->Erestrict;
971   return 0;
972 }
973 
974 /**
975   @brief Get the CeedBasis of a CeedOperatorField
976 
977   @param opfield         CeedOperatorField
978   @param[out] basis      Variable to store CeedBasis
979 
980   @return An error code: 0 - success, otherwise - failure
981 
982   @ref Advanced
983 **/
984 
985 int CeedOperatorFieldGetBasis(CeedOperatorField opfield, CeedBasis *basis) {
986   *basis = opfield->basis;
987   return 0;
988 }
989 
990 /**
991   @brief Get the CeedVector of a CeedOperatorField
992 
993   @param opfield         CeedOperatorField
994   @param[out] vec        Variable to store CeedVector
995 
996   @return An error code: 0 - success, otherwise - failure
997 
998   @ref Advanced
999 **/
1000 
1001 int CeedOperatorFieldGetVector(CeedOperatorField opfield, CeedVector *vec) {
1002   *vec = opfield->vec;
1003   return 0;
1004 }
1005 
1006 /**
1007   @brief Destroy a CeedOperator
1008 
1009   @param op CeedOperator to destroy
1010 
1011   @return An error code: 0 - success, otherwise - failure
1012 
1013   @ref Basic
1014 **/
1015 int CeedOperatorDestroy(CeedOperator *op) {
1016   int ierr;
1017 
1018   if (!*op || --(*op)->refcount > 0) return 0;
1019   if ((*op)->Destroy) {
1020     ierr = (*op)->Destroy(*op); CeedChk(ierr);
1021   }
1022   ierr = CeedDestroy(&(*op)->ceed); CeedChk(ierr);
1023   // Free fields
1024   for (int i=0; i<(*op)->nfields; i++)
1025     if ((*op)->inputfields[i]) {
1026       ierr = CeedElemRestrictionDestroy(&(*op)->inputfields[i]->Erestrict);
1027       CeedChk(ierr);
1028       if ((*op)->inputfields[i]->basis != CEED_BASIS_COLLOCATED) {
1029         ierr = CeedBasisDestroy(&(*op)->inputfields[i]->basis); CeedChk(ierr);
1030       }
1031       if ((*op)->inputfields[i]->vec != CEED_VECTOR_ACTIVE &&
1032           (*op)->inputfields[i]->vec != CEED_VECTOR_NONE ) {
1033         ierr = CeedVectorDestroy(&(*op)->inputfields[i]->vec); CeedChk(ierr);
1034       }
1035       ierr = CeedFree(&(*op)->inputfields[i]); CeedChk(ierr);
1036     }
1037   for (int i=0; i<(*op)->nfields; i++)
1038     if ((*op)->outputfields[i]) {
1039       ierr = CeedElemRestrictionDestroy(&(*op)->outputfields[i]->Erestrict);
1040       CeedChk(ierr);
1041       if ((*op)->outputfields[i]->basis != CEED_BASIS_COLLOCATED) {
1042         ierr = CeedBasisDestroy(&(*op)->outputfields[i]->basis); CeedChk(ierr);
1043       }
1044       if ((*op)->outputfields[i]->vec != CEED_VECTOR_ACTIVE &&
1045           (*op)->outputfields[i]->vec != CEED_VECTOR_NONE ) {
1046         ierr = CeedVectorDestroy(&(*op)->outputfields[i]->vec); CeedChk(ierr);
1047       }
1048       ierr = CeedFree(&(*op)->outputfields[i]); CeedChk(ierr);
1049     }
1050   // Destroy suboperators
1051   for (int i=0; i<(*op)->numsub; i++)
1052     if ((*op)->suboperators[i]) {
1053       ierr = CeedOperatorDestroy(&(*op)->suboperators[i]); CeedChk(ierr);
1054     }
1055   ierr = CeedQFunctionDestroy(&(*op)->qf); CeedChk(ierr);
1056   ierr = CeedQFunctionDestroy(&(*op)->dqf); CeedChk(ierr);
1057   ierr = CeedQFunctionDestroy(&(*op)->dqfT); CeedChk(ierr);
1058 
1059   // Destroy fallback
1060   if ((*op)->opfallback) {
1061     ierr = (*op)->qffallback->Destroy((*op)->qffallback); CeedChk(ierr);
1062     ierr = CeedFree(&(*op)->qffallback); CeedChk(ierr);
1063     ierr = (*op)->opfallback->Destroy((*op)->opfallback); CeedChk(ierr);
1064     ierr = CeedFree(&(*op)->opfallback); CeedChk(ierr);
1065   }
1066 
1067   ierr = CeedFree(&(*op)->inputfields); CeedChk(ierr);
1068   ierr = CeedFree(&(*op)->outputfields); CeedChk(ierr);
1069   ierr = CeedFree(&(*op)->suboperators); CeedChk(ierr);
1070   ierr = CeedFree(op); CeedChk(ierr);
1071   return 0;
1072 }
1073 
1074 /// @}
1075