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