xref: /libCEED/interface/ceed-operator.c (revision d9995aec8949465977409d138cd94b7dd885e51e)
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 request        Address of CeedRequest for non-blocking completion, else
456                           CEED_REQUEST_IMMEDIATE
457 
458   @return An error code: 0 - success, otherwise - failure
459 
460   @ref Advanced
461 **/
462 int CeedOperatorCreateFDMElementInverse(CeedOperator op, CeedOperator *fdminv,
463                                         CeedRequest *request) {
464   int ierr;
465   Ceed ceed = op->ceed;
466   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
467 
468   // Use backend version, if available
469   if (op->CreateFDMElementInverse) {
470     ierr = op->CreateFDMElementInverse(op, fdminv, request); CeedChk(ierr);
471   } else {
472     // Fallback to reference Ceed
473     if (!op->opfallback) {
474       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
475     }
476     // Assemble
477     ierr = op->opfallback->CreateFDMElementInverse(op->opfallback, fdminv,
478            request); CeedChk(ierr);
479   }
480 
481   return 0;
482 }
483 
484 
485 /**
486   @brief Apply CeedOperator to a vector
487 
488   This computes the action of the operator on the specified (active) input,
489   yielding its (active) output.  All inputs and outputs must be specified using
490   CeedOperatorSetField().
491 
492   @param op        CeedOperator to apply
493   @param[in] in    CeedVector containing input state or CEED_VECTOR_NONE if
494                   there are no active inputs
495   @param[out] out  CeedVector to store result of applying operator (must be
496                      distinct from @a in) or CEED_VECTOR_NONE if there are no
497                      active outputs
498   @param request   Address of CeedRequest for non-blocking completion, else
499                      CEED_REQUEST_IMMEDIATE
500 
501   @return An error code: 0 - success, otherwise - failure
502 
503   @ref Basic
504 **/
505 int CeedOperatorApply(CeedOperator op, CeedVector in, CeedVector out,
506                       CeedRequest *request) {
507   int ierr;
508   Ceed ceed = op->ceed;
509   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
510 
511   if (op->numelements)  {
512     // Standard Operator
513     if (op->Apply) {
514       ierr = op->Apply(op, in, out, request); CeedChk(ierr);
515     } else {
516       // Zero all output vectors
517       CeedQFunction qf = op->qf;
518       for (CeedInt i=0; i<qf->numoutputfields; i++) {
519         CeedVector vec = op->outputfields[i]->vec;
520         if (vec == CEED_VECTOR_ACTIVE)
521           vec = out;
522         if (vec != CEED_VECTOR_NONE) {
523           ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr);
524         }
525       }
526       // Apply
527       ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr);
528     }
529   } else if (op->composite) {
530     // Composite Operator
531     if (op->ApplyComposite) {
532       ierr = op->ApplyComposite(op, in, out, request); CeedChk(ierr);
533     } else {
534       CeedInt numsub;
535       ierr = CeedOperatorGetNumSub(op, &numsub); CeedChk(ierr);
536       CeedOperator *suboperators;
537       ierr = CeedOperatorGetSubList(op, &suboperators); CeedChk(ierr);
538 
539       // Zero all output vectors
540       if (out != CEED_VECTOR_NONE) {
541         ierr = CeedVectorSetValue(out, 0.0); CeedChk(ierr);
542       }
543       for (CeedInt i=0; i<numsub; i++) {
544         for (CeedInt j=0; j<suboperators[i]->qf->numoutputfields; j++) {
545           CeedVector vec = suboperators[i]->outputfields[j]->vec;
546           if (vec != CEED_VECTOR_ACTIVE && vec != CEED_VECTOR_NONE) {
547             ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr);
548           }
549         }
550       }
551       // Apply
552       for (CeedInt i=0; i<op->numsub; i++) {
553         ierr = CeedOperatorApplyAdd(op->suboperators[i], in, out, request);
554         CeedChk(ierr);
555       }
556     }
557   }
558 
559   return 0;
560 }
561 
562 /**
563   @brief Apply CeedOperator to a vector and add result to output vector
564 
565   This computes the action of the operator on the specified (active) input,
566   yielding its (active) output.  All inputs and outputs must be specified using
567   CeedOperatorSetField().
568 
569   @param op        CeedOperator to apply
570   @param[in] in    CeedVector containing input state or NULL if there are no
571                      active inputs
572   @param[out] out  CeedVector to sum in result of applying operator (must be
573                      distinct from @a in) or NULL if there are no active outputs
574   @param request   Address of CeedRequest for non-blocking completion, else
575                      CEED_REQUEST_IMMEDIATE
576 
577   @return An error code: 0 - success, otherwise - failure
578 
579   @ref Basic
580 **/
581 int CeedOperatorApplyAdd(CeedOperator op, CeedVector in, CeedVector out,
582                          CeedRequest *request) {
583   int ierr;
584   Ceed ceed = op->ceed;
585   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
586 
587   if (op->numelements)  {
588     // Standard Operator
589     ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr);
590   } else if (op->composite) {
591     // Composite Operator
592     if (op->ApplyAddComposite) {
593       ierr = op->ApplyAddComposite(op, in, out, request); CeedChk(ierr);
594     } else {
595       CeedInt numsub;
596       ierr = CeedOperatorGetNumSub(op, &numsub); CeedChk(ierr);
597       CeedOperator *suboperators;
598       ierr = CeedOperatorGetSubList(op, &suboperators); CeedChk(ierr);
599 
600       for (CeedInt i=0; i<numsub; i++) {
601         ierr = CeedOperatorApplyAdd(suboperators[i], in, out, request);
602         CeedChk(ierr);
603       }
604     }
605   }
606 
607   return 0;
608 }
609 
610 /**
611   @brief Get the Ceed associated with a CeedOperator
612 
613   @param op              CeedOperator
614   @param[out] ceed       Variable to store Ceed
615 
616   @return An error code: 0 - success, otherwise - failure
617 
618   @ref Advanced
619 **/
620 
621 int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) {
622   *ceed = op->ceed;
623   return 0;
624 }
625 
626 /**
627   @brief Get the number of elements associated with a CeedOperator
628 
629   @param op              CeedOperator
630   @param[out] numelem    Variable to store number of elements
631 
632   @return An error code: 0 - success, otherwise - failure
633 
634   @ref Advanced
635 **/
636 
637 int CeedOperatorGetNumElements(CeedOperator op, CeedInt *numelem) {
638   if (op->composite)
639     // LCOV_EXCL_START
640     return CeedError(op->ceed, 1, "Not defined for composite operator");
641   // LCOV_EXCL_STOP
642 
643   *numelem = op->numelements;
644   return 0;
645 }
646 
647 /**
648   @brief Get the number of quadrature points associated with a CeedOperator
649 
650   @param op              CeedOperator
651   @param[out] numqpts    Variable to store vector number of quadrature points
652 
653   @return An error code: 0 - success, otherwise - failure
654 
655   @ref Advanced
656 **/
657 
658 int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *numqpts) {
659   if (op->composite)
660     // LCOV_EXCL_START
661     return CeedError(op->ceed, 1, "Not defined for composite operator");
662   // LCOV_EXCL_STOP
663 
664   *numqpts = op->numqpoints;
665   return 0;
666 }
667 
668 /**
669   @brief Get the number of arguments associated with a CeedOperator
670 
671   @param op              CeedOperator
672   @param[out] numargs    Variable to store vector number of arguments
673 
674   @return An error code: 0 - success, otherwise - failure
675 
676   @ref Advanced
677 **/
678 
679 int CeedOperatorGetNumArgs(CeedOperator op, CeedInt *numargs) {
680   if (op->composite)
681     // LCOV_EXCL_START
682     return CeedError(op->ceed, 1, "Not defined for composite operators");
683   // LCOV_EXCL_STOP
684 
685   *numargs = op->nfields;
686   return 0;
687 }
688 
689 /**
690   @brief Get the setup status of a CeedOperator
691 
692   @param op             CeedOperator
693   @param[out] setupdone Variable to store setup status
694 
695   @return An error code: 0 - success, otherwise - failure
696 
697   @ref Advanced
698 **/
699 
700 int CeedOperatorGetSetupStatus(CeedOperator op, bool *setupdone) {
701   *setupdone = op->setupdone;
702   return 0;
703 }
704 
705 /**
706   @brief Get the QFunction associated with a CeedOperator
707 
708   @param op              CeedOperator
709   @param[out] qf         Variable to store QFunction
710 
711   @return An error code: 0 - success, otherwise - failure
712 
713   @ref Advanced
714 **/
715 
716 int CeedOperatorGetQFunction(CeedOperator op, CeedQFunction *qf) {
717   if (op->composite)
718     // LCOV_EXCL_START
719     return CeedError(op->ceed, 1, "Not defined for composite operator");
720   // LCOV_EXCL_STOP
721 
722   *qf = op->qf;
723   return 0;
724 }
725 
726 /**
727   @brief Get the number of suboperators associated with a CeedOperator
728 
729   @param op              CeedOperator
730   @param[out] numsub     Variable to store number of suboperators
731 
732   @return An error code: 0 - success, otherwise - failure
733 
734   @ref Advanced
735 **/
736 
737 int CeedOperatorGetNumSub(CeedOperator op, CeedInt *numsub) {
738   if (!op->composite)
739     // LCOV_EXCL_START
740     return CeedError(op->ceed, 1, "Not a composite operator");
741   // LCOV_EXCL_STOP
742 
743   *numsub = op->numsub;
744   return 0;
745 }
746 
747 /**
748   @brief Get the list of suboperators associated with a CeedOperator
749 
750   @param op                CeedOperator
751   @param[out] suboperators Variable to store list of suboperators
752 
753   @return An error code: 0 - success, otherwise - failure
754 
755   @ref Advanced
756 **/
757 
758 int CeedOperatorGetSubList(CeedOperator op, CeedOperator **suboperators) {
759   if (!op->composite)
760     // LCOV_EXCL_START
761     return CeedError(op->ceed, 1, "Not a composite operator");
762   // LCOV_EXCL_STOP
763 
764   *suboperators = op->suboperators;
765   return 0;
766 }
767 
768 /**
769   @brief Set the backend data of a CeedOperator
770 
771   @param[out] op         CeedOperator
772   @param data            Data to set
773 
774   @return An error code: 0 - success, otherwise - failure
775 
776   @ref Advanced
777 **/
778 
779 int CeedOperatorSetData(CeedOperator op, void **data) {
780   op->data = *data;
781   return 0;
782 }
783 
784 /**
785   @brief Get the backend data of a CeedOperator
786 
787   @param op              CeedOperator
788   @param[out] data       Variable to store data
789 
790   @return An error code: 0 - success, otherwise - failure
791 
792   @ref Advanced
793 **/
794 
795 int CeedOperatorGetData(CeedOperator op, void **data) {
796   *data = op->data;
797   return 0;
798 }
799 
800 /**
801   @brief Set the setup flag of a CeedOperator to True
802 
803   @param op              CeedOperator
804 
805   @return An error code: 0 - success, otherwise - failure
806 
807   @ref Advanced
808 **/
809 
810 int CeedOperatorSetSetupDone(CeedOperator op) {
811   op->setupdone = 1;
812   return 0;
813 }
814 
815 /**
816   @brief View a field of a CeedOperator
817 
818   @param[in] field       Operator field to view
819   @param[in] fieldnumber Number of field being viewed
820   @param[in] stream      Stream to view to, e.g., stdout
821 
822   @return An error code: 0 - success, otherwise - failure
823 
824   @ref Utility
825 **/
826 static int CeedOperatorFieldView(CeedOperatorField field,
827                                  CeedQFunctionField qffield,
828                                  CeedInt fieldnumber, bool sub, bool in,
829                                  FILE *stream) {
830   const char *pre = sub ? "  " : "";
831   const char *inout = in ? "Input" : "Output";
832 
833   fprintf(stream, "%s    %s Field [%d]:\n"
834           "%s      Name: \"%s\"\n"
835           "%s      Lmode: \"%s\"\n",
836           pre, inout, fieldnumber, pre, qffield->fieldname,
837           pre, CeedTransposeModes[field->lmode]);
838 
839   if (field->basis == CEED_BASIS_COLLOCATED)
840     fprintf(stream, "%s      Collocated basis\n", pre);
841 
842   if (field->vec == CEED_VECTOR_ACTIVE)
843     fprintf(stream, "%s      Active vector\n", pre);
844   else if (field->vec == CEED_VECTOR_NONE)
845     fprintf(stream, "%s      No vector\n", pre);
846 
847   return 0;
848 }
849 
850 /**
851   @brief View a single CeedOperator
852 
853   @param[in] op     CeedOperator to view
854   @param[in] sub    Boolean flag for sub-operator
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