xref: /libCEED/interface/ceed-operator.c (revision 4d2a38eef5ff52550a65501d135c766add2f50f7)
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
35                    CEED_QFUNCTION_NONE)
36   @param dqfT    QFunction defining the action of the transpose of the Jacobian
37                    of @a qf (or CEED_QFUNCTION_NONE)
38   @param[out] op Address of the variable where the newly created
39                      CeedOperator will be stored
40 
41   @return An error code: 0 - success, otherwise - failure
42 
43   @ref Basic
44  */
45 int CeedOperatorCreate(Ceed ceed, CeedQFunction qf, CeedQFunction dqf,
46                        CeedQFunction dqfT, CeedOperator *op) {
47   int ierr;
48 
49   if (!ceed->OperatorCreate) {
50     Ceed delegate;
51     ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr);
52 
53     if (!delegate)
54       // LCOV_EXCL_START
55       return CeedError(ceed, 1, "Backend does not support OperatorCreate");
56     // LCOV_EXCL_STOP
57 
58     ierr = CeedOperatorCreate(delegate, qf, dqf, dqfT, op); CeedChk(ierr);
59     return 0;
60   }
61 
62   ierr = CeedCalloc(1, op); CeedChk(ierr);
63   (*op)->ceed = ceed;
64   ceed->refcount++;
65   (*op)->refcount = 1;
66   if (qf == CEED_QFUNCTION_NONE)
67     // LCOV_EXCL_START
68     return CeedError(ceed, 1, "Operator must have a valid QFunction.");
69   // LCOV_EXCL_STOP
70   (*op)->qf = qf;
71   qf->refcount++;
72   if (dqf && dqf != CEED_QFUNCTION_NONE) {
73     (*op)->dqf = dqf;
74     dqf->refcount++;
75   }
76   if (dqfT && dqfT != CEED_QFUNCTION_NONE) {
77     (*op)->dqfT = dqfT;
78     dqfT->refcount++;
79   }
80   ierr = CeedCalloc(16, &(*op)->inputfields); CeedChk(ierr);
81   ierr = CeedCalloc(16, &(*op)->outputfields); CeedChk(ierr);
82   ierr = ceed->OperatorCreate(*op); CeedChk(ierr);
83   return 0;
84 }
85 
86 /**
87   @brief Create an operator that composes the action of several operators
88 
89   @param ceed    A Ceed object where the CeedOperator will be created
90   @param[out] op Address of the variable where the newly created
91                      Composite CeedOperator will be stored
92 
93   @return An error code: 0 - success, otherwise - failure
94 
95   @ref Basic
96  */
97 int CeedCompositeOperatorCreate(Ceed ceed, CeedOperator *op) {
98   int ierr;
99 
100   if (!ceed->CompositeOperatorCreate) {
101     Ceed delegate;
102     ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr);
103 
104     if (delegate) {
105       ierr = CeedCompositeOperatorCreate(delegate, op); CeedChk(ierr);
106       return 0;
107     }
108   }
109 
110   ierr = CeedCalloc(1, op); CeedChk(ierr);
111   (*op)->ceed = ceed;
112   ceed->refcount++;
113   (*op)->composite = true;
114   ierr = CeedCalloc(16, &(*op)->suboperators); CeedChk(ierr);
115 
116   if (ceed->CompositeOperatorCreate) {
117     ierr = ceed->CompositeOperatorCreate(*op); CeedChk(ierr);
118   }
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 Composite CeedOperator
235   @param      subop       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 Duplicate a CeedOperator with a reference Ceed to fallback for advanced
261            CeedOperator functionality
262 
263   @param op           CeedOperator to create fallback for
264 
265   @return An error code: 0 - success, otherwise - failure
266 
267   @ref Developer
268 **/
269 int CeedOperatorCreateFallback(CeedOperator op) {
270   int ierr;
271 
272   // Fallback Ceed
273   const char *resource, *fallbackresource;
274   ierr = CeedGetResource(op->ceed, &resource); CeedChk(ierr);
275   ierr = CeedGetOperatorFallbackResource(op->ceed, &fallbackresource);
276   CeedChk(ierr);
277   if (!strcmp(resource, fallbackresource))
278     // LCOV_EXCL_START
279     return CeedError(op->ceed, 1, "Backend %s cannot create an operator"
280                      "fallback to resource %s", resource, fallbackresource);
281   // LCOV_EXCL_STOP
282 
283   Ceed ceedref;
284   ierr = CeedInit(fallbackresource, &ceedref); CeedChk(ierr);
285   ceedref->opfallbackparent = op->ceed;
286   op->ceed->opfallbackceed = ceedref;
287 
288   // Clone Op
289   CeedOperator opref;
290   ierr = CeedCalloc(1, &opref); CeedChk(ierr);
291   memcpy(opref, op, sizeof(*opref)); CeedChk(ierr);
292   opref->data = NULL;
293   opref->setupdone = 0;
294   opref->ceed = ceedref;
295   ierr = ceedref->OperatorCreate(opref); CeedChk(ierr);
296   op->opfallback = opref;
297 
298   // Clone QF
299   CeedQFunction qfref;
300   ierr = CeedCalloc(1, &qfref); CeedChk(ierr);
301   memcpy(qfref, (op->qf), sizeof(*qfref)); CeedChk(ierr);
302   qfref->data = NULL;
303   qfref->ceed = ceedref;
304   ierr = ceedref->QFunctionCreate(qfref); CeedChk(ierr);
305   opref->qf = qfref;
306   op->qffallback = qfref;
307 
308   return 0;
309 }
310 
311 /**
312   @brief Check if a CeedOperator is ready to be used.
313 
314   @param[in] ceed Ceed object for error handling
315   @param[in] op   CeedOperator to check
316 
317   @return An error code: 0 - success, otherwise - failure
318 
319   @ref Basic
320 **/
321 static int CeedOperatorCheckReady(Ceed ceed, CeedOperator op) {
322   CeedQFunction qf = op->qf;
323 
324   if (op->composite) {
325     if (!op->numsub)
326       // LCOV_EXCL_START
327       return CeedError(ceed, 1, "No suboperators set");
328     // LCOV_EXCL_STOP
329   } else {
330     if (op->nfields == 0)
331       // LCOV_EXCL_START
332       return CeedError(ceed, 1, "No operator fields set");
333     // LCOV_EXCL_STOP
334     if (op->nfields < qf->numinputfields + qf->numoutputfields)
335       // LCOV_EXCL_START
336       return CeedError(ceed, 1, "Not all operator fields set");
337     // LCOV_EXCL_STOP
338     if (!op->hasrestriction)
339       // LCOV_EXCL_START
340       return CeedError(ceed, 1,"At least one restriction required");
341     // LCOV_EXCL_STOP
342     if (op->numqpoints == 0)
343       // LCOV_EXCL_START
344       return CeedError(ceed, 1,"At least one non-collocated basis required");
345     // LCOV_EXCL_STOP
346   }
347 
348   return 0;
349 }
350 
351 /**
352   @brief Assemble a linear CeedQFunction associated with a CeedOperator
353 
354   This returns a CeedVector containing a matrix at each quadrature point
355     providing the action of the CeedQFunction associated with the CeedOperator.
356     The vector 'assembled' is of shape
357       [num_elements, num_input_fields, num_output_fields, num_quad_points]
358     and contains column-major matrices representing the action of the
359     CeedQFunction for a corresponding quadrature point on an element. Inputs and
360     outputs are in the order provided by the user when adding CeedOperator fields.
361     For example, a QFunction with inputs 'u' and 'gradu' and outputs 'gradv' and
362     'v', provided in that order, would result in an assembled QFunction that
363     consists of (1 + dim) x (dim + 1) matrices at each quadrature point acting
364     on the input [u, du_0, du_1] and producing the output [dv_0, dv_1, v].
365 
366   @param op             CeedOperator to assemble CeedQFunction
367   @param[out] assembled CeedVector to store assembled CeedQFunction at
368                           quadrature points
369   @param[out] rstr      CeedElemRestriction for CeedVector containing assembled
370                           CeedQFunction
371   @param request        Address of CeedRequest for non-blocking completion, else
372                           CEED_REQUEST_IMMEDIATE
373 
374   @return An error code: 0 - success, otherwise - failure
375 
376   @ref Basic
377 **/
378 int CeedOperatorAssembleLinearQFunction(CeedOperator op, CeedVector *assembled,
379                                         CeedElemRestriction *rstr,
380                                         CeedRequest *request) {
381   int ierr;
382   Ceed ceed = op->ceed;
383   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
384 
385   if (op->AssembleLinearQFunction) {
386     ierr = op->AssembleLinearQFunction(op, assembled, rstr, request);
387     CeedChk(ierr);
388   } else {
389     // Fallback to reference Ceed
390     if (!op->opfallback) {
391       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
392     }
393     // Assemble
394     ierr = op->opfallback->AssembleLinearQFunction(op->opfallback, assembled,
395            rstr, request); CeedChk(ierr);
396   }
397 
398   return 0;
399 }
400 
401 /**
402   @brief Assemble the diagonal of a square linear Operator
403 
404   This returns a CeedVector containing the diagonal of a linear CeedOperator.
405 
406   @param op             CeedOperator to assemble CeedQFunction
407   @param[out] assembled CeedVector to store assembled CeedOperator diagonal
408   @param request        Address of CeedRequest for non-blocking completion, else
409                           CEED_REQUEST_IMMEDIATE
410 
411   @return An error code: 0 - success, otherwise - failure
412 
413   @ref Basic
414 **/
415 int CeedOperatorAssembleLinearDiagonal(CeedOperator op, CeedVector *assembled,
416                                        CeedRequest *request) {
417   int ierr;
418   Ceed ceed = op->ceed;
419   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
420 
421   // Use backend version, if available
422   if (op->AssembleLinearDiagonal) {
423     ierr = op->AssembleLinearDiagonal(op, assembled, request); CeedChk(ierr);
424     return 0;
425   }
426 
427   // Assemble QFunction
428   CeedQFunction qf = op->qf;
429   CeedVector assembledqf;
430   CeedElemRestriction rstr;
431   ierr = CeedOperatorAssembleLinearQFunction(op,  &assembledqf, &rstr, request);
432   CeedChk(ierr);
433   ierr = CeedElemRestrictionDestroy(&rstr); CeedChk(ierr);
434 
435   // Determine active input basis
436   CeedInt numemodein = 0, ncomp, dim = 1;
437   CeedEvalMode *emodein = NULL;
438   CeedBasis basisin = NULL;
439   CeedElemRestriction rstrin = NULL;
440   for (CeedInt i=0; i<qf->numinputfields; i++)
441     if (op->inputfields[i]->vec == CEED_VECTOR_ACTIVE) {
442       ierr = CeedOperatorFieldGetBasis(op->inputfields[i], &basisin);
443       CeedChk(ierr);
444       ierr = CeedBasisGetNumComponents(basisin, &ncomp); CeedChk(ierr);
445       ierr = CeedBasisGetDimension(basisin, &dim); CeedChk(ierr);
446       ierr = CeedOperatorFieldGetElemRestriction(op->inputfields[i], &rstrin);
447       CeedChk(ierr);
448       CeedEvalMode emode;
449       ierr = CeedQFunctionFieldGetEvalMode(qf->inputfields[i], &emode);
450       CeedChk(ierr);
451       switch (emode) {
452       case CEED_EVAL_NONE:
453       case CEED_EVAL_INTERP:
454         ierr = CeedRealloc(numemodein + 1, &emodein); CeedChk(ierr);
455         emodein[numemodein] = emode;
456         numemodein += 1;
457         break;
458       case CEED_EVAL_GRAD:
459         ierr = CeedRealloc(numemodein + dim, &emodein); CeedChk(ierr);
460         for (CeedInt d=0; d<dim; d++)
461           emodein[numemodein+d] = emode;
462         numemodein += dim;
463         break;
464       case CEED_EVAL_WEIGHT:
465       case CEED_EVAL_DIV:
466       case CEED_EVAL_CURL:
467         break; // Caught by QF Assembly
468       }
469     }
470 
471   // Determine active output basis
472   CeedInt numemodeout = 0;
473   CeedEvalMode *emodeout = NULL;
474   CeedBasis basisout = NULL;
475   CeedElemRestriction rstrout = NULL;
476   CeedTransposeMode lmodeout = CEED_NOTRANSPOSE;
477   for (CeedInt i=0; i<qf->numoutputfields; i++)
478     if (op->outputfields[i]->vec == CEED_VECTOR_ACTIVE) {
479       ierr = CeedOperatorFieldGetBasis(op->outputfields[i], &basisout);
480       CeedChk(ierr);
481       ierr = CeedOperatorFieldGetElemRestriction(op->outputfields[i], &rstrout);
482       CeedChk(ierr);
483       ierr = CeedOperatorFieldGetLMode(op->outputfields[i], &lmodeout);
484       CeedChk(ierr);
485       CeedEvalMode emode;
486       ierr = CeedQFunctionFieldGetEvalMode(qf->outputfields[i], &emode);
487       CeedChk(ierr);
488       switch (emode) {
489       case CEED_EVAL_NONE:
490       case CEED_EVAL_INTERP:
491         ierr = CeedRealloc(numemodeout + 1, &emodeout); CeedChk(ierr);
492         emodeout[numemodeout] = emode;
493         numemodeout += 1;
494         break;
495       case CEED_EVAL_GRAD:
496         ierr = CeedRealloc(numemodeout + dim, &emodeout); CeedChk(ierr);
497         for (CeedInt d=0; d<dim; d++)
498           emodeout[numemodeout+d] = emode;
499         numemodeout += dim;
500         break;
501       case CEED_EVAL_WEIGHT:
502       case CEED_EVAL_DIV:
503       case CEED_EVAL_CURL:
504         break; // Caught by QF Assembly
505       }
506     }
507 
508   // Create diagonal vector
509   CeedVector elemdiag;
510   ierr = CeedElemRestrictionCreateVector(rstrin, assembled, &elemdiag);
511   CeedChk(ierr);
512 
513   // Assemble element operator diagonals
514   CeedScalar *elemdiagarray, *assembledqfarray;
515   ierr = CeedVectorSetValue(elemdiag, 0.0); CeedChk(ierr);
516   ierr = CeedVectorGetArray(elemdiag, CEED_MEM_HOST, &elemdiagarray);
517   CeedChk(ierr);
518   ierr = CeedVectorGetArray(assembledqf, CEED_MEM_HOST, &assembledqfarray);
519   CeedChk(ierr);
520   CeedInt nelem, nnodes, nqpts;
521   ierr = CeedElemRestrictionGetNumElements(rstrin, &nelem); CeedChk(ierr);
522   ierr = CeedBasisGetNumNodes(basisin, &nnodes); CeedChk(ierr);
523   ierr = CeedBasisGetNumQuadraturePoints(basisin, &nqpts); CeedChk(ierr);
524   // Compute the diagonal of B^T D B
525   // Each node, qpt pair
526   for (CeedInt n=0; n<nnodes; n++)
527     for (CeedInt q=0; q<nqpts; q++) {
528       CeedInt dout = -1;
529       // Each basis eval mode pair
530       for (CeedInt eout=0; eout<numemodeout; eout++) {
531         CeedScalar bt = 1.0;
532         if (emodeout[eout] == CEED_EVAL_GRAD)
533           dout += 1;
534         ierr = CeedBasisGetValue(basisout, emodeout[eout], q, n, dout, &bt);
535         CeedChk(ierr);
536         CeedInt din = -1;
537         for (CeedInt ein=0; ein<numemodein; ein++) {
538           CeedScalar b = 0.0;
539           if (emodein[ein] == CEED_EVAL_GRAD)
540             din += 1;
541           ierr = CeedBasisGetValue(basisin, emodein[ein], q, n, din, &b);
542           CeedChk(ierr);
543           // Each element and component
544           for (CeedInt e=0; e<nelem; e++)
545             for (CeedInt cout=0; cout<ncomp; cout++) {
546               CeedScalar db = 0.0;
547               for (CeedInt cin=0; cin<ncomp; cin++)
548                 db += assembledqfarray[((((e*numemodein+ein)*ncomp+cin)*
549                                          numemodeout+eout)*ncomp+cout)*nqpts+q]*b;
550               elemdiagarray[(e*ncomp+cout)*nnodes+n] += bt * db;
551             }
552         }
553       }
554     }
555 
556   ierr = CeedVectorRestoreArray(elemdiag, &elemdiagarray); CeedChk(ierr);
557   ierr = CeedVectorRestoreArray(assembledqf, &assembledqfarray); CeedChk(ierr);
558 
559   // Assemble local operator diagonal
560   ierr = CeedVectorSetValue(*assembled, 0.0); CeedChk(ierr);
561   ierr = CeedElemRestrictionApply(rstrout, CEED_TRANSPOSE, lmodeout, elemdiag,
562                                   *assembled, request); CeedChk(ierr);
563 
564   // Cleanup
565   ierr = CeedVectorDestroy(&assembledqf); CeedChk(ierr);
566   ierr = CeedVectorDestroy(&elemdiag); CeedChk(ierr);
567   ierr = CeedFree(&emodein); CeedChk(ierr);
568   ierr = CeedFree(&emodeout); CeedChk(ierr);
569 
570   return 0;
571 }
572 
573 /**
574   @brief Apply CeedOperator to a vector and overwrite output vector
575 
576   This computes the action of the operator on the specified (active) input,
577   yielding its (active) output.  All inputs and outputs must be specified using
578   CeedOperatorSetField().
579 
580   @param op        CeedOperator to apply
581   @param[in] in    CeedVector containing input state or CEED_VECTOR_NONE if
582                   there are no active inputs
583   @param[out] out  CeedVector to store result of applying operator (must be
584                      distinct from @a in) or CEED_VECTOR_NONE if there are no
585                      active outputs
586   @param request   Address of CeedRequest for non-blocking completion, else
587                      CEED_REQUEST_IMMEDIATE
588 
589   @return An error code: 0 - success, otherwise - failure
590 
591   @ref Basic
592 **/
593 int CeedOperatorApply(CeedOperator op, CeedVector in, CeedVector out,
594                       CeedRequest *request) {
595   int ierr;
596   Ceed ceed = op->ceed;
597   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
598 
599   if (op->numelements)  {
600     // Standard Operator
601     if (op->Apply) {
602       ierr = op->Apply(op, in, out, request); CeedChk(ierr);
603     } else {
604       // Zero all output vectors
605       CeedQFunction qf = op->qf;
606       for (CeedInt i=0; i<qf->numoutputfields; i++) {
607         CeedVector vec = op->outputfields[i]->vec;
608         if (vec == CEED_VECTOR_ACTIVE)
609           vec = out;
610         if (vec != CEED_VECTOR_NONE) {
611           ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr);
612         }
613       }
614       // Apply
615       ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr);
616     }
617   } else if (op->composite) {
618     // Composite Operator
619     if (op->ApplyComposite) {
620       ierr = op->ApplyComposite(op, in, out, request); CeedChk(ierr);
621     } else {
622       CeedInt numsub;
623       ierr = CeedOperatorGetNumSub(op, &numsub); CeedChk(ierr);
624       CeedOperator *suboperators;
625       ierr = CeedOperatorGetSubList(op, &suboperators); CeedChk(ierr);
626 
627       // Zero all output vectors
628       if (out != CEED_VECTOR_NONE) {
629         ierr = CeedVectorSetValue(out, 0.0); CeedChk(ierr);
630       }
631       for (CeedInt i=0; i<numsub; i++) {
632         for (CeedInt j=0; j<suboperators[i]->qf->numoutputfields; j++) {
633           CeedVector vec = suboperators[i]->outputfields[j]->vec;
634           if (vec != CEED_VECTOR_ACTIVE && vec != CEED_VECTOR_NONE) {
635             ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr);
636           }
637         }
638       }
639       // Apply
640       for (CeedInt i=0; i<op->numsub; i++) {
641         ierr = CeedOperatorApplyAdd(op->suboperators[i], in, out, request);
642         CeedChk(ierr);
643       }
644     }
645   }
646 
647   return 0;
648 }
649 
650 /**
651   @brief Apply CeedOperator to a vector and add result to output vector
652 
653   This computes the action of the operator on the specified (active) input,
654   yielding its (active) output.  All inputs and outputs must be specified using
655   CeedOperatorSetField().
656 
657   @param op        CeedOperator to apply
658   @param[in] in    CeedVector containing input state or NULL if there are no
659                      active inputs
660   @param[out] out  CeedVector to sum in result of applying operator (must be
661                      distinct from @a in) or NULL if there are no active outputs
662   @param request   Address of CeedRequest for non-blocking completion, else
663                      CEED_REQUEST_IMMEDIATE
664 
665   @return An error code: 0 - success, otherwise - failure
666 
667   @ref Basic
668 **/
669 int CeedOperatorApplyAdd(CeedOperator op, CeedVector in, CeedVector out,
670                          CeedRequest *request) {
671   int ierr;
672   Ceed ceed = op->ceed;
673   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
674 
675   if (op->numelements)  {
676     // Standard Operator
677     ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr);
678   } else if (op->composite) {
679     // Composite Operator
680     if (op->ApplyAddComposite) {
681       ierr = op->ApplyAddComposite(op, in, out, request); CeedChk(ierr);
682     } else {
683       CeedInt numsub;
684       ierr = CeedOperatorGetNumSub(op, &numsub); CeedChk(ierr);
685       CeedOperator *suboperators;
686       ierr = CeedOperatorGetSubList(op, &suboperators); CeedChk(ierr);
687 
688       for (CeedInt i=0; i<numsub; i++) {
689         ierr = CeedOperatorApplyAdd(suboperators[i], in, out, request);
690         CeedChk(ierr);
691       }
692     }
693   }
694 
695   return 0;
696 }
697 
698 /**
699   @brief Get the Ceed associated with a CeedOperator
700 
701   @param op              CeedOperator
702   @param[out] ceed       Variable to store Ceed
703 
704   @return An error code: 0 - success, otherwise - failure
705 
706   @ref Advanced
707 **/
708 
709 int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) {
710   *ceed = op->ceed;
711   return 0;
712 }
713 
714 /**
715   @brief Get the number of elements associated with a CeedOperator
716 
717   @param op              CeedOperator
718   @param[out] numelem    Variable to store number of elements
719 
720   @return An error code: 0 - success, otherwise - failure
721 
722   @ref Advanced
723 **/
724 
725 int CeedOperatorGetNumElements(CeedOperator op, CeedInt *numelem) {
726   if (op->composite)
727     // LCOV_EXCL_START
728     return CeedError(op->ceed, 1, "Not defined for composite operator");
729   // LCOV_EXCL_STOP
730 
731   *numelem = op->numelements;
732   return 0;
733 }
734 
735 /**
736   @brief Get the number of quadrature points associated with a CeedOperator
737 
738   @param op              CeedOperator
739   @param[out] numqpts    Variable to store vector number of quadrature points
740 
741   @return An error code: 0 - success, otherwise - failure
742 
743   @ref Advanced
744 **/
745 
746 int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *numqpts) {
747   if (op->composite)
748     // LCOV_EXCL_START
749     return CeedError(op->ceed, 1, "Not defined for composite operator");
750   // LCOV_EXCL_STOP
751 
752   *numqpts = op->numqpoints;
753   return 0;
754 }
755 
756 /**
757   @brief Get the number of arguments associated with a CeedOperator
758 
759   @param op              CeedOperator
760   @param[out] numargs    Variable to store vector number of arguments
761 
762   @return An error code: 0 - success, otherwise - failure
763 
764   @ref Advanced
765 **/
766 
767 int CeedOperatorGetNumArgs(CeedOperator op, CeedInt *numargs) {
768   if (op->composite)
769     // LCOV_EXCL_START
770     return CeedError(op->ceed, 1, "Not defined for composite operators");
771   // LCOV_EXCL_STOP
772 
773   *numargs = op->nfields;
774   return 0;
775 }
776 
777 /**
778   @brief Get the setup status of a CeedOperator
779 
780   @param op             CeedOperator
781   @param[out] setupdone Variable to store setup status
782 
783   @return An error code: 0 - success, otherwise - failure
784 
785   @ref Advanced
786 **/
787 
788 int CeedOperatorGetSetupStatus(CeedOperator op, bool *setupdone) {
789   *setupdone = op->setupdone;
790   return 0;
791 }
792 
793 /**
794   @brief Get the QFunction associated with a CeedOperator
795 
796   @param op              CeedOperator
797   @param[out] qf         Variable to store QFunction
798 
799   @return An error code: 0 - success, otherwise - failure
800 
801   @ref Advanced
802 **/
803 
804 int CeedOperatorGetQFunction(CeedOperator op, CeedQFunction *qf) {
805   if (op->composite)
806     // LCOV_EXCL_START
807     return CeedError(op->ceed, 1, "Not defined for composite operator");
808   // LCOV_EXCL_STOP
809 
810   *qf = op->qf;
811   return 0;
812 }
813 
814 /**
815   @brief Get the number of suboperators associated with a CeedOperator
816 
817   @param op              CeedOperator
818   @param[out] numsub     Variable to store number of suboperators
819 
820   @return An error code: 0 - success, otherwise - failure
821 
822   @ref Advanced
823 **/
824 
825 int CeedOperatorGetNumSub(CeedOperator op, CeedInt *numsub) {
826   if (!op->composite)
827     // LCOV_EXCL_START
828     return CeedError(op->ceed, 1, "Not a composite operator");
829   // LCOV_EXCL_STOP
830 
831   *numsub = op->numsub;
832   return 0;
833 }
834 
835 /**
836   @brief Get the list of suboperators associated with a CeedOperator
837 
838   @param op                CeedOperator
839   @param[out] suboperators Variable to store list of suboperators
840 
841   @return An error code: 0 - success, otherwise - failure
842 
843   @ref Advanced
844 **/
845 
846 int CeedOperatorGetSubList(CeedOperator op, CeedOperator **suboperators) {
847   if (!op->composite)
848     // LCOV_EXCL_START
849     return CeedError(op->ceed, 1, "Not a composite operator");
850   // LCOV_EXCL_STOP
851 
852   *suboperators = op->suboperators;
853   return 0;
854 }
855 
856 /**
857   @brief Set the backend data of a CeedOperator
858 
859   @param[out] op         CeedOperator
860   @param data            Data to set
861 
862   @return An error code: 0 - success, otherwise - failure
863 
864   @ref Advanced
865 **/
866 
867 int CeedOperatorSetData(CeedOperator op, void **data) {
868   op->data = *data;
869   return 0;
870 }
871 
872 /**
873   @brief Get the backend data of a CeedOperator
874 
875   @param op              CeedOperator
876   @param[out] data       Variable to store data
877 
878   @return An error code: 0 - success, otherwise - failure
879 
880   @ref Advanced
881 **/
882 
883 int CeedOperatorGetData(CeedOperator op, void **data) {
884   *data = op->data;
885   return 0;
886 }
887 
888 /**
889   @brief Set the setup flag of a CeedOperator to True
890 
891   @param op              CeedOperator
892 
893   @return An error code: 0 - success, otherwise - failure
894 
895   @ref Advanced
896 **/
897 
898 int CeedOperatorSetSetupDone(CeedOperator op) {
899   op->setupdone = 1;
900   return 0;
901 }
902 
903 /**
904   @brief View a field of a CeedOperator
905 
906   @param[in] field       Operator field to view
907   @param[in] fieldnumber Number of field being viewed
908   @param[in] stream      Stream to view to, e.g., stdout
909 
910   @return An error code: 0 - success, otherwise - failure
911 
912   @ref Utility
913 **/
914 static int CeedOperatorFieldView(CeedOperatorField field,
915                                  CeedQFunctionField qffield,
916                                  CeedInt fieldnumber, bool sub, bool in,
917                                  FILE *stream) {
918   const char *pre = sub ? "  " : "";
919   const char *inout = in ? "Input" : "Output";
920 
921   fprintf(stream, "%s    %s Field [%d]:\n"
922           "%s      Name: \"%s\"\n"
923           "%s      Lmode: \"%s\"\n",
924           pre, inout, fieldnumber, pre, qffield->fieldname,
925           pre, CeedTransposeModes[field->lmode]);
926 
927   if (field->basis == CEED_BASIS_COLLOCATED)
928     fprintf(stream, "%s      Collocated basis\n", pre);
929 
930   if (field->vec == CEED_VECTOR_ACTIVE)
931     fprintf(stream, "%s      Active vector\n", pre);
932   else if (field->vec == CEED_VECTOR_NONE)
933     fprintf(stream, "%s      No vector\n", pre);
934 
935   return 0;
936 }
937 
938 /**
939   @brief View a single CeedOperator
940 
941   @param[in] op     CeedOperator to view
942   @param[in] stream Stream to write; typically stdout/stderr or a file
943 
944   @return Error code: 0 - success, otherwise - failure
945 
946   @ref Utility
947 **/
948 int CeedOperatorSingleView(CeedOperator op, bool sub, FILE *stream) {
949   int ierr;
950   const char *pre = sub ? "  " : "";
951 
952   CeedInt totalfields;
953   ierr = CeedOperatorGetNumArgs(op, &totalfields); CeedChk(ierr);
954 
955   fprintf(stream, "%s  %d Field%s\n", pre, totalfields, totalfields>1 ? "s" : "");
956 
957   fprintf(stream, "%s  %d Input Field%s:\n", pre, op->qf->numinputfields,
958           op->qf->numinputfields>1 ? "s" : "");
959   for (CeedInt i=0; i<op->qf->numinputfields; i++) {
960     ierr = CeedOperatorFieldView(op->inputfields[i], op->qf->inputfields[i],
961                                  i, sub, 1, stream); CeedChk(ierr);
962   }
963 
964   fprintf(stream, "%s  %d Output Field%s:\n", pre, op->qf->numoutputfields,
965           op->qf->numoutputfields>1 ? "s" : "");
966   for (CeedInt i=0; i<op->qf->numoutputfields; i++) {
967     ierr = CeedOperatorFieldView(op->outputfields[i], op->qf->inputfields[i],
968                                  i, sub, 0, stream); CeedChk(ierr);
969   }
970 
971   return 0;
972 }
973 
974 /**
975   @brief View a CeedOperator
976 
977   @param[in] op     CeedOperator to view
978   @param[in] stream Stream to write; typically stdout/stderr or a file
979 
980   @return Error code: 0 - success, otherwise - failure
981 
982   @ref Utility
983 **/
984 int CeedOperatorView(CeedOperator op, FILE *stream) {
985   int ierr;
986 
987   if (op->composite) {
988     fprintf(stream, "Composite CeedOperator\n");
989 
990     for (CeedInt i=0; i<op->numsub; i++) {
991       fprintf(stream, "  SubOperator [%d]:\n", i);
992       ierr = CeedOperatorSingleView(op->suboperators[i], 1, stream);
993       CeedChk(ierr);
994     }
995   } else {
996     fprintf(stream, "CeedOperator\n");
997     ierr = CeedOperatorSingleView(op, 0, stream); CeedChk(ierr);
998   }
999 
1000   return 0;
1001 }
1002 
1003 /**
1004   @brief Get the CeedOperatorFields of a CeedOperator
1005 
1006   @param op                 CeedOperator
1007   @param[out] inputfields   Variable to store inputfields
1008   @param[out] outputfields  Variable to store outputfields
1009 
1010   @return An error code: 0 - success, otherwise - failure
1011 
1012   @ref Advanced
1013 **/
1014 
1015 int CeedOperatorGetFields(CeedOperator op, CeedOperatorField **inputfields,
1016                           CeedOperatorField **outputfields) {
1017   if (op->composite)
1018     // LCOV_EXCL_START
1019     return CeedError(op->ceed, 1, "Not defined for composite operator");
1020   // LCOV_EXCL_STOP
1021 
1022   if (inputfields) *inputfields = op->inputfields;
1023   if (outputfields) *outputfields = op->outputfields;
1024   return 0;
1025 }
1026 
1027 /**
1028   @brief Get the L vector CeedTransposeMode of a CeedOperatorField
1029 
1030   @param opfield         CeedOperatorField
1031   @param[out] lmode      Variable to store CeedTransposeMode
1032 
1033   @return An error code: 0 - success, otherwise - failure
1034 
1035   @ref Advanced
1036 **/
1037 
1038 int CeedOperatorFieldGetLMode(CeedOperatorField opfield,
1039                               CeedTransposeMode *lmode) {
1040   *lmode = opfield->lmode;
1041   return 0;
1042 }
1043 
1044 /**
1045   @brief Get the CeedElemRestriction of a CeedOperatorField
1046 
1047   @param opfield         CeedOperatorField
1048   @param[out] rstr       Variable to store CeedElemRestriction
1049 
1050   @return An error code: 0 - success, otherwise - failure
1051 
1052   @ref Advanced
1053 **/
1054 
1055 int CeedOperatorFieldGetElemRestriction(CeedOperatorField opfield,
1056                                         CeedElemRestriction *rstr) {
1057   *rstr = opfield->Erestrict;
1058   return 0;
1059 }
1060 
1061 /**
1062   @brief Get the CeedBasis of a CeedOperatorField
1063 
1064   @param opfield         CeedOperatorField
1065   @param[out] basis      Variable to store CeedBasis
1066 
1067   @return An error code: 0 - success, otherwise - failure
1068 
1069   @ref Advanced
1070 **/
1071 
1072 int CeedOperatorFieldGetBasis(CeedOperatorField opfield, CeedBasis *basis) {
1073   *basis = opfield->basis;
1074   return 0;
1075 }
1076 
1077 /**
1078   @brief Get the CeedVector of a CeedOperatorField
1079 
1080   @param opfield         CeedOperatorField
1081   @param[out] vec        Variable to store CeedVector
1082 
1083   @return An error code: 0 - success, otherwise - failure
1084 
1085   @ref Advanced
1086 **/
1087 
1088 int CeedOperatorFieldGetVector(CeedOperatorField opfield, CeedVector *vec) {
1089   *vec = opfield->vec;
1090   return 0;
1091 }
1092 
1093 /**
1094   @brief Destroy a CeedOperator
1095 
1096   @param op CeedOperator to destroy
1097 
1098   @return An error code: 0 - success, otherwise - failure
1099 
1100   @ref Basic
1101 **/
1102 int CeedOperatorDestroy(CeedOperator *op) {
1103   int ierr;
1104 
1105   if (!*op || --(*op)->refcount > 0) return 0;
1106   if ((*op)->Destroy) {
1107     ierr = (*op)->Destroy(*op); CeedChk(ierr);
1108   }
1109   ierr = CeedDestroy(&(*op)->ceed); CeedChk(ierr);
1110   // Free fields
1111   for (int i=0; i<(*op)->nfields; i++)
1112     if ((*op)->inputfields[i]) {
1113       ierr = CeedElemRestrictionDestroy(&(*op)->inputfields[i]->Erestrict);
1114       CeedChk(ierr);
1115       if ((*op)->inputfields[i]->basis != CEED_BASIS_COLLOCATED) {
1116         ierr = CeedBasisDestroy(&(*op)->inputfields[i]->basis); CeedChk(ierr);
1117       }
1118       if ((*op)->inputfields[i]->vec != CEED_VECTOR_ACTIVE &&
1119           (*op)->inputfields[i]->vec != CEED_VECTOR_NONE ) {
1120         ierr = CeedVectorDestroy(&(*op)->inputfields[i]->vec); CeedChk(ierr);
1121       }
1122       ierr = CeedFree(&(*op)->inputfields[i]); CeedChk(ierr);
1123     }
1124   for (int i=0; i<(*op)->nfields; i++)
1125     if ((*op)->outputfields[i]) {
1126       ierr = CeedElemRestrictionDestroy(&(*op)->outputfields[i]->Erestrict);
1127       CeedChk(ierr);
1128       if ((*op)->outputfields[i]->basis != CEED_BASIS_COLLOCATED) {
1129         ierr = CeedBasisDestroy(&(*op)->outputfields[i]->basis); CeedChk(ierr);
1130       }
1131       if ((*op)->outputfields[i]->vec != CEED_VECTOR_ACTIVE &&
1132           (*op)->outputfields[i]->vec != CEED_VECTOR_NONE ) {
1133         ierr = CeedVectorDestroy(&(*op)->outputfields[i]->vec); CeedChk(ierr);
1134       }
1135       ierr = CeedFree(&(*op)->outputfields[i]); CeedChk(ierr);
1136     }
1137   // Destroy suboperators
1138   for (int i=0; i<(*op)->numsub; i++)
1139     if ((*op)->suboperators[i]) {
1140       ierr = CeedOperatorDestroy(&(*op)->suboperators[i]); CeedChk(ierr);
1141     }
1142   ierr = CeedQFunctionDestroy(&(*op)->qf); CeedChk(ierr);
1143   ierr = CeedQFunctionDestroy(&(*op)->dqf); CeedChk(ierr);
1144   ierr = CeedQFunctionDestroy(&(*op)->dqfT); CeedChk(ierr);
1145 
1146   // Destroy fallback
1147   if ((*op)->opfallback) {
1148     ierr = (*op)->qffallback->Destroy((*op)->qffallback); CeedChk(ierr);
1149     ierr = CeedFree(&(*op)->qffallback); CeedChk(ierr);
1150     ierr = (*op)->opfallback->Destroy((*op)->opfallback); CeedChk(ierr);
1151     ierr = CeedFree(&(*op)->opfallback); CeedChk(ierr);
1152   }
1153 
1154   ierr = CeedFree(&(*op)->inputfields); CeedChk(ierr);
1155   ierr = CeedFree(&(*op)->outputfields); CeedChk(ierr);
1156   ierr = CeedFree(&(*op)->suboperators); CeedChk(ierr);
1157   ierr = CeedFree(op); CeedChk(ierr);
1158   return 0;
1159 }
1160 
1161 /// @}
1162