xref: /libCEED/rust/libceed-sys/c-src/interface/ceed-operator.c (revision 3d8e882215d238700cdceb37404f76ca7fa24eaa)
1 // Copyright (c) 2017-2022, Lawrence Livermore National Security, LLC and other CEED contributors.
2 // All Rights Reserved. See the top-level LICENSE and NOTICE files for details.
3 //
4 // SPDX-License-Identifier: BSD-2-Clause
5 //
6 // This file is part of CEED:  http://github.com/ceed
7 
8 #include <ceed/ceed.h>
9 #include <ceed/backend.h>
10 #include <ceed-impl.h>
11 #include <stdbool.h>
12 #include <stdio.h>
13 #include <string.h>
14 
15 /// @file
16 /// Implementation of CeedOperator interfaces
17 
18 /// ----------------------------------------------------------------------------
19 /// CeedOperator Library Internal Functions
20 /// ----------------------------------------------------------------------------
21 /// @addtogroup CeedOperatorDeveloper
22 /// @{
23 
24 /**
25   @brief Check if a CeedOperator Field matches the QFunction Field
26 
27   @param[in] ceed      Ceed object for error handling
28   @param[in] qf_field  QFunction Field matching Operator Field
29   @param[in] r         Operator Field ElemRestriction
30   @param[in] b         Operator Field Basis
31 
32   @return An error code: 0 - success, otherwise - failure
33 
34   @ref Developer
35 **/
36 static int CeedOperatorCheckField(Ceed ceed, CeedQFunctionField qf_field,
37                                   CeedElemRestriction r, CeedBasis b) {
38   int ierr;
39   CeedEvalMode eval_mode = qf_field->eval_mode;
40   CeedInt dim = 1, num_comp = 1, restr_num_comp = 1, size = qf_field->size;
41   // Restriction
42   if (r != CEED_ELEMRESTRICTION_NONE) {
43     if (eval_mode == CEED_EVAL_WEIGHT) {
44       // LCOV_EXCL_START
45       return CeedError(ceed, CEED_ERROR_INCOMPATIBLE,
46                        "CEED_ELEMRESTRICTION_NONE should be used "
47                        "for a field with eval mode CEED_EVAL_WEIGHT");
48       // LCOV_EXCL_STOP
49     }
50     ierr = CeedElemRestrictionGetNumComponents(r, &restr_num_comp);
51     CeedChk(ierr);
52   }
53   if ((r == CEED_ELEMRESTRICTION_NONE) != (eval_mode == CEED_EVAL_WEIGHT)) {
54     // LCOV_EXCL_START
55     return CeedError(ceed, CEED_ERROR_INCOMPATIBLE,
56                      "CEED_ELEMRESTRICTION_NONE and CEED_EVAL_WEIGHT "
57                      "must be used together.");
58     // LCOV_EXCL_STOP
59   }
60   // Basis
61   if (b != CEED_BASIS_COLLOCATED) {
62     if (eval_mode == CEED_EVAL_NONE)
63       // LCOV_EXCL_START
64       return CeedError(ceed, CEED_ERROR_INCOMPATIBLE,
65                        "Field '%s' configured with CEED_EVAL_NONE must "
66                        "be used with CEED_BASIS_COLLOCATED",
67                        // LCOV_EXCL_STOP
68                        qf_field->field_name);
69     ierr = CeedBasisGetDimension(b, &dim); CeedChk(ierr);
70     ierr = CeedBasisGetNumComponents(b, &num_comp); CeedChk(ierr);
71     if (r != CEED_ELEMRESTRICTION_NONE && restr_num_comp != num_comp) {
72       // LCOV_EXCL_START
73       return CeedError(ceed, CEED_ERROR_DIMENSION,
74                        "Field '%s' of size %d and EvalMode %s: ElemRestriction "
75                        "has %d components, but Basis has %d components",
76                        qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode],
77                        restr_num_comp,
78                        num_comp);
79       // LCOV_EXCL_STOP
80     }
81   }
82   // Field size
83   switch(eval_mode) {
84   case CEED_EVAL_NONE:
85     if (size != restr_num_comp)
86       // LCOV_EXCL_START
87       return CeedError(ceed, CEED_ERROR_DIMENSION,
88                        "Field '%s' of size %d and EvalMode %s: ElemRestriction has %d components",
89                        qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode],
90                        restr_num_comp);
91     // LCOV_EXCL_STOP
92     break;
93   case CEED_EVAL_INTERP:
94     if (size != num_comp)
95       // LCOV_EXCL_START
96       return CeedError(ceed, CEED_ERROR_DIMENSION,
97                        "Field '%s' of size %d and EvalMode %s: ElemRestriction/Basis has %d components",
98                        qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode],
99                        num_comp);
100     // LCOV_EXCL_STOP
101     break;
102   case CEED_EVAL_GRAD:
103     if (size != num_comp * dim)
104       // LCOV_EXCL_START
105       return CeedError(ceed, CEED_ERROR_DIMENSION,
106                        "Field '%s' of size %d and EvalMode %s in %d dimensions: "
107                        "ElemRestriction/Basis has %d components",
108                        qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode], dim,
109                        num_comp);
110     // LCOV_EXCL_STOP
111     break;
112   case CEED_EVAL_WEIGHT:
113     // No additional checks required
114     break;
115   case CEED_EVAL_DIV:
116     // Not implemented
117     break;
118   case CEED_EVAL_CURL:
119     // Not implemented
120     break;
121   }
122   return CEED_ERROR_SUCCESS;
123 }
124 
125 /**
126   @brief View a field of a CeedOperator
127 
128   @param[in] field         Operator field to view
129   @param[in] qf_field      QFunction field (carries field name)
130   @param[in] field_number  Number of field being viewed
131   @param[in] sub           true indicates sub-operator, which increases indentation; false for top-level operator
132   @param[in] input         true for an input field; false for output field
133   @param[in] stream        Stream to view to, e.g., stdout
134 
135   @return An error code: 0 - success, otherwise - failure
136 
137   @ref Utility
138 **/
139 static int CeedOperatorFieldView(CeedOperatorField field,
140                                  CeedQFunctionField qf_field,
141                                  CeedInt field_number, bool sub, bool input,
142                                  FILE *stream) {
143   const char *pre = sub ? "  " : "";
144   const char *in_out = input ? "Input" : "Output";
145 
146   fprintf(stream, "%s    %s Field [%d]:\n"
147           "%s      Name: \"%s\"\n",
148           pre, in_out, field_number, pre, qf_field->field_name);
149 
150   if (field->basis == CEED_BASIS_COLLOCATED)
151     fprintf(stream, "%s      Collocated basis\n", pre);
152 
153   if (field->vec == CEED_VECTOR_ACTIVE)
154     fprintf(stream, "%s      Active vector\n", pre);
155   else if (field->vec == CEED_VECTOR_NONE)
156     fprintf(stream, "%s      No vector\n", pre);
157   return CEED_ERROR_SUCCESS;
158 }
159 
160 /**
161   @brief View a single CeedOperator
162 
163   @param[in] op      CeedOperator to view
164   @param[in] sub     Boolean flag for sub-operator
165   @param[in] stream  Stream to write; typically stdout/stderr or a file
166 
167   @return Error code: 0 - success, otherwise - failure
168 
169   @ref Utility
170 **/
171 int CeedOperatorSingleView(CeedOperator op, bool sub, FILE *stream) {
172   int ierr;
173   const char *pre = sub ? "  " : "";
174 
175   CeedInt total_fields = 0;
176   ierr = CeedOperatorGetNumArgs(op, &total_fields); CeedChk(ierr);
177 
178   fprintf(stream, "%s  %d Field%s\n", pre, total_fields,
179           total_fields>1 ? "s" : "");
180 
181   fprintf(stream, "%s  %d Input Field%s:\n", pre, op->qf->num_input_fields,
182           op->qf->num_input_fields>1 ? "s" : "");
183   for (CeedInt i=0; i<op->qf->num_input_fields; i++) {
184     ierr = CeedOperatorFieldView(op->input_fields[i], op->qf->input_fields[i],
185                                  i, sub, 1, stream); CeedChk(ierr);
186   }
187 
188   fprintf(stream, "%s  %d Output Field%s:\n", pre, op->qf->num_output_fields,
189           op->qf->num_output_fields>1 ? "s" : "");
190   for (CeedInt i=0; i<op->qf->num_output_fields; i++) {
191     ierr = CeedOperatorFieldView(op->output_fields[i], op->qf->output_fields[i],
192                                  i, sub, 0, stream); CeedChk(ierr);
193   }
194   return CEED_ERROR_SUCCESS;
195 }
196 
197 /**
198   @brief Find the active vector basis for a CeedOperator
199 
200   @param[in] op             CeedOperator to find active basis for
201   @param[out] active_basis  Basis for active input vector
202 
203   @return An error code: 0 - success, otherwise - failure
204 
205   @ ref Developer
206 **/
207 int CeedOperatorGetActiveBasis(CeedOperator op, CeedBasis *active_basis) {
208   *active_basis = NULL;
209   for (int i = 0; i < op->qf->num_input_fields; i++)
210     if (op->input_fields[i]->vec == CEED_VECTOR_ACTIVE) {
211       *active_basis = op->input_fields[i]->basis;
212       break;
213     }
214 
215   if (!*active_basis) {
216     // LCOV_EXCL_START
217     int ierr;
218     Ceed ceed;
219     ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr);
220     return CeedError(ceed, CEED_ERROR_MINOR,
221                      "No active CeedBasis found");
222     // LCOV_EXCL_STOP
223   }
224   return CEED_ERROR_SUCCESS;
225 }
226 
227 /**
228   @brief Find the active vector ElemRestriction for a CeedOperator
229 
230   @param[in] op            CeedOperator to find active basis for
231   @param[out] active_rstr  ElemRestriction for active input vector
232 
233   @return An error code: 0 - success, otherwise - failure
234 
235   @ref Utility
236 **/
237 int CeedOperatorGetActiveElemRestriction(CeedOperator op,
238     CeedElemRestriction *active_rstr) {
239   *active_rstr = NULL;
240   for (int i = 0; i < op->qf->num_input_fields; i++)
241     if (op->input_fields[i]->vec == CEED_VECTOR_ACTIVE) {
242       *active_rstr = op->input_fields[i]->elem_restr;
243       break;
244     }
245 
246   if (!*active_rstr) {
247     // LCOV_EXCL_START
248     int ierr;
249     Ceed ceed;
250     ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr);
251     return CeedError(ceed, CEED_ERROR_INCOMPLETE,
252                      "No active CeedElemRestriction found");
253     // LCOV_EXCL_STOP
254   }
255   return CEED_ERROR_SUCCESS;
256 }
257 
258 /**
259   @brief Set QFunctionContext field value of the specified type.
260            For composite operators, the value is set in all
261            sub-operator QFunctionContexts that have a matching `field_name`.
262            A non-zero error code is returned for single operators
263            that do not have a matching field of the same type or composite
264            operators that do not have any field of a matching type.
265 
266   @param op          CeedOperator
267   @param field_label Label of field to set
268   @param field_type  Type of field to set
269   @param value       Value to set
270 
271   @return An error code: 0 - success, otherwise - failure
272 
273   @ref User
274 **/
275 static int CeedOperatorContextSetGeneric(CeedOperator op,
276     CeedContextFieldLabel field_label, CeedContextFieldType field_type,
277     void *value) {
278   int ierr;
279 
280   if (!field_label)
281     // LCOV_EXCL_START
282     return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED,
283                      "Invalid field label");
284   // LCOV_EXCL_STOP
285 
286   bool is_composite = false;
287   ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr);
288   if (is_composite) {
289     CeedInt num_sub;
290     CeedOperator *sub_operators;
291 
292     ierr = CeedOperatorGetNumSub(op, &num_sub); CeedChk(ierr);
293     ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr);
294     if (num_sub != field_label->num_sub_labels)
295       // LCOV_EXCL_START
296       return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED,
297                        "ContextLabel does not correspond to composite operator.\n"
298                        "Use CeedOperatorGetContextFieldLabel().");
299     // LCOV_EXCL_STOP
300 
301     for (CeedInt i = 0; i < num_sub; i++) {
302       // Try every sub-operator, ok if some sub-operators do not have field
303       if (field_label->sub_labels[i] && sub_operators[i]->qf->ctx) {
304         ierr = CeedQFunctionContextSetGeneric(sub_operators[i]->qf->ctx,
305                                               field_label->sub_labels[i],
306                                               field_type, value); CeedChk(ierr);
307       }
308     }
309   } else {
310     if (!op->qf->ctx)
311       // LCOV_EXCL_START
312       return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED,
313                        "QFunction does not have context data");
314     // LCOV_EXCL_STOP
315 
316     ierr = CeedQFunctionContextSetGeneric(op->qf->ctx, field_label,
317                                           field_type, value); CeedChk(ierr);
318   }
319 
320   return CEED_ERROR_SUCCESS;
321 }
322 
323 /// @}
324 
325 /// ----------------------------------------------------------------------------
326 /// CeedOperator Backend API
327 /// ----------------------------------------------------------------------------
328 /// @addtogroup CeedOperatorBackend
329 /// @{
330 
331 /**
332   @brief Get the number of arguments associated with a CeedOperator
333 
334   @param op             CeedOperator
335   @param[out] num_args  Variable to store vector number of arguments
336 
337   @return An error code: 0 - success, otherwise - failure
338 
339   @ref Backend
340 **/
341 
342 int CeedOperatorGetNumArgs(CeedOperator op, CeedInt *num_args) {
343   if (op->is_composite)
344     // LCOV_EXCL_START
345     return CeedError(op->ceed, CEED_ERROR_MINOR,
346                      "Not defined for composite operators");
347   // LCOV_EXCL_STOP
348 
349   *num_args = op->num_fields;
350   return CEED_ERROR_SUCCESS;
351 }
352 
353 /**
354   @brief Get the setup status of a CeedOperator
355 
356   @param op                  CeedOperator
357   @param[out] is_setup_done  Variable to store setup status
358 
359   @return An error code: 0 - success, otherwise - failure
360 
361   @ref Backend
362 **/
363 
364 int CeedOperatorIsSetupDone(CeedOperator op, bool *is_setup_done) {
365   *is_setup_done = op->is_backend_setup;
366   return CEED_ERROR_SUCCESS;
367 }
368 
369 /**
370   @brief Get the QFunction associated with a CeedOperator
371 
372   @param op       CeedOperator
373   @param[out] qf  Variable to store QFunction
374 
375   @return An error code: 0 - success, otherwise - failure
376 
377   @ref Backend
378 **/
379 
380 int CeedOperatorGetQFunction(CeedOperator op, CeedQFunction *qf) {
381   if (op->is_composite)
382     // LCOV_EXCL_START
383     return CeedError(op->ceed, CEED_ERROR_MINOR,
384                      "Not defined for composite operator");
385   // LCOV_EXCL_STOP
386 
387   *qf = op->qf;
388   return CEED_ERROR_SUCCESS;
389 }
390 
391 /**
392   @brief Get a boolean value indicating if the CeedOperator is composite
393 
394   @param op                 CeedOperator
395   @param[out] is_composite  Variable to store composite status
396 
397   @return An error code: 0 - success, otherwise - failure
398 
399   @ref Backend
400 **/
401 
402 int CeedOperatorIsComposite(CeedOperator op, bool *is_composite) {
403   *is_composite = op->is_composite;
404   return CEED_ERROR_SUCCESS;
405 }
406 
407 /**
408   @brief Get the number of sub_operators associated with a CeedOperator
409 
410   @param op                     CeedOperator
411   @param[out] num_suboperators  Variable to store number of sub_operators
412 
413   @return An error code: 0 - success, otherwise - failure
414 
415   @ref Backend
416 **/
417 
418 int CeedOperatorGetNumSub(CeedOperator op, CeedInt *num_suboperators) {
419   if (!op->is_composite)
420     // LCOV_EXCL_START
421     return CeedError(op->ceed, CEED_ERROR_MINOR, "Not a composite operator");
422   // LCOV_EXCL_STOP
423 
424   *num_suboperators = op->num_suboperators;
425   return CEED_ERROR_SUCCESS;
426 }
427 
428 /**
429   @brief Get the list of sub_operators associated with a CeedOperator
430 
431   @param op                  CeedOperator
432   @param[out] sub_operators  Variable to store list of sub_operators
433 
434   @return An error code: 0 - success, otherwise - failure
435 
436   @ref Backend
437 **/
438 
439 int CeedOperatorGetSubList(CeedOperator op, CeedOperator **sub_operators) {
440   if (!op->is_composite)
441     // LCOV_EXCL_START
442     return CeedError(op->ceed, CEED_ERROR_MINOR, "Not a composite operator");
443   // LCOV_EXCL_STOP
444 
445   *sub_operators = op->sub_operators;
446   return CEED_ERROR_SUCCESS;
447 }
448 
449 /**
450   @brief Get the backend data of a CeedOperator
451 
452   @param op         CeedOperator
453   @param[out] data  Variable to store data
454 
455   @return An error code: 0 - success, otherwise - failure
456 
457   @ref Backend
458 **/
459 
460 int CeedOperatorGetData(CeedOperator op, void *data) {
461   *(void **)data = op->data;
462   return CEED_ERROR_SUCCESS;
463 }
464 
465 /**
466   @brief Set the backend data of a CeedOperator
467 
468   @param[out] op  CeedOperator
469   @param data     Data to set
470 
471   @return An error code: 0 - success, otherwise - failure
472 
473   @ref Backend
474 **/
475 
476 int CeedOperatorSetData(CeedOperator op, void *data) {
477   op->data = data;
478   return CEED_ERROR_SUCCESS;
479 }
480 
481 /**
482   @brief Increment the reference counter for a CeedOperator
483 
484   @param op  CeedOperator to increment the reference counter
485 
486   @return An error code: 0 - success, otherwise - failure
487 
488   @ref Backend
489 **/
490 int CeedOperatorReference(CeedOperator op) {
491   op->ref_count++;
492   return CEED_ERROR_SUCCESS;
493 }
494 
495 /**
496   @brief Set the setup flag of a CeedOperator to True
497 
498   @param op  CeedOperator
499 
500   @return An error code: 0 - success, otherwise - failure
501 
502   @ref Backend
503 **/
504 
505 int CeedOperatorSetSetupDone(CeedOperator op) {
506   op->is_backend_setup = true;
507   return CEED_ERROR_SUCCESS;
508 }
509 
510 /// @}
511 
512 /// ----------------------------------------------------------------------------
513 /// CeedOperator Public API
514 /// ----------------------------------------------------------------------------
515 /// @addtogroup CeedOperatorUser
516 /// @{
517 
518 /**
519   @brief Create a CeedOperator and associate a CeedQFunction. A CeedBasis and
520            CeedElemRestriction can be associated with CeedQFunction fields with
521            \ref CeedOperatorSetField.
522 
523   @param ceed     A Ceed object where the CeedOperator will be created
524   @param qf       QFunction defining the action of the operator at quadrature points
525   @param dqf      QFunction defining the action of the Jacobian of @a qf (or
526                     @ref CEED_QFUNCTION_NONE)
527   @param dqfT     QFunction defining the action of the transpose of the Jacobian
528                     of @a qf (or @ref CEED_QFUNCTION_NONE)
529   @param[out] op  Address of the variable where the newly created
530                     CeedOperator will be stored
531 
532   @return An error code: 0 - success, otherwise - failure
533 
534   @ref User
535  */
536 int CeedOperatorCreate(Ceed ceed, CeedQFunction qf, CeedQFunction dqf,
537                        CeedQFunction dqfT, CeedOperator *op) {
538   int ierr;
539 
540   if (!ceed->OperatorCreate) {
541     Ceed delegate;
542     ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr);
543 
544     if (!delegate)
545       // LCOV_EXCL_START
546       return CeedError(ceed, CEED_ERROR_UNSUPPORTED,
547                        "Backend does not support OperatorCreate");
548     // LCOV_EXCL_STOP
549 
550     ierr = CeedOperatorCreate(delegate, qf, dqf, dqfT, op); CeedChk(ierr);
551     return CEED_ERROR_SUCCESS;
552   }
553 
554   if (!qf || qf == CEED_QFUNCTION_NONE)
555     // LCOV_EXCL_START
556     return CeedError(ceed, CEED_ERROR_MINOR,
557                      "Operator must have a valid QFunction.");
558   // LCOV_EXCL_STOP
559   ierr = CeedCalloc(1, op); CeedChk(ierr);
560   (*op)->ceed = ceed;
561   ierr = CeedReference(ceed); CeedChk(ierr);
562   (*op)->ref_count = 1;
563   (*op)->qf = qf;
564   ierr = CeedQFunctionReference(qf); CeedChk(ierr);
565   if (dqf && dqf != CEED_QFUNCTION_NONE) {
566     (*op)->dqf = dqf;
567     ierr = CeedQFunctionReference(dqf); CeedChk(ierr);
568   }
569   if (dqfT && dqfT != CEED_QFUNCTION_NONE) {
570     (*op)->dqfT = dqfT;
571     ierr = CeedQFunctionReference(dqfT); CeedChk(ierr);
572   }
573   ierr = CeedQFunctionAssemblyDataCreate(ceed, &(*op)->qf_assembled);
574   CeedChk(ierr);
575   ierr = CeedCalloc(CEED_FIELD_MAX, &(*op)->input_fields); CeedChk(ierr);
576   ierr = CeedCalloc(CEED_FIELD_MAX, &(*op)->output_fields); CeedChk(ierr);
577   ierr = ceed->OperatorCreate(*op); CeedChk(ierr);
578   return CEED_ERROR_SUCCESS;
579 }
580 
581 /**
582   @brief Create an operator that composes the action of several operators
583 
584   @param ceed     A Ceed object where the CeedOperator will be created
585   @param[out] op  Address of the variable where the newly created
586                     Composite CeedOperator will be stored
587 
588   @return An error code: 0 - success, otherwise - failure
589 
590   @ref User
591  */
592 int CeedCompositeOperatorCreate(Ceed ceed, CeedOperator *op) {
593   int ierr;
594 
595   if (!ceed->CompositeOperatorCreate) {
596     Ceed delegate;
597     ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr);
598 
599     if (delegate) {
600       ierr = CeedCompositeOperatorCreate(delegate, op); CeedChk(ierr);
601       return CEED_ERROR_SUCCESS;
602     }
603   }
604 
605   ierr = CeedCalloc(1, op); CeedChk(ierr);
606   (*op)->ceed = ceed;
607   ierr = CeedReference(ceed); CeedChk(ierr);
608   (*op)->is_composite = true;
609   ierr = CeedCalloc(CEED_COMPOSITE_MAX, &(*op)->sub_operators); CeedChk(ierr);
610 
611   if (ceed->CompositeOperatorCreate) {
612     ierr = ceed->CompositeOperatorCreate(*op); CeedChk(ierr);
613   }
614   return CEED_ERROR_SUCCESS;
615 }
616 
617 /**
618   @brief Copy the pointer to a CeedOperator. Both pointers should
619            be destroyed with `CeedOperatorDestroy()`;
620            Note: If `*op_copy` is non-NULL, then it is assumed that
621            `*op_copy` is a pointer to a CeedOperator. This
622            CeedOperator will be destroyed if `*op_copy` is the only
623            reference to this CeedOperator.
624 
625   @param op            CeedOperator to copy reference to
626   @param[out] op_copy  Variable to store copied reference
627 
628   @return An error code: 0 - success, otherwise - failure
629 
630   @ref User
631 **/
632 int CeedOperatorReferenceCopy(CeedOperator op, CeedOperator *op_copy) {
633   int ierr;
634 
635   ierr = CeedOperatorReference(op); CeedChk(ierr);
636   ierr = CeedOperatorDestroy(op_copy); CeedChk(ierr);
637   *op_copy = op;
638   return CEED_ERROR_SUCCESS;
639 }
640 
641 /**
642   @brief Provide a field to a CeedOperator for use by its CeedQFunction
643 
644   This function is used to specify both active and passive fields to a
645   CeedOperator.  For passive fields, a vector @arg v must be provided.  Passive
646   fields can inputs or outputs (updated in-place when operator is applied).
647 
648   Active fields must be specified using this function, but their data (in a
649   CeedVector) is passed in CeedOperatorApply().  There can be at most one active
650   input and at most one active output.
651 
652   @param op          CeedOperator on which to provide the field
653   @param field_name  Name of the field (to be matched with the name used by
654                        CeedQFunction)
655   @param r           CeedElemRestriction
656   @param b           CeedBasis in which the field resides or @ref CEED_BASIS_COLLOCATED
657                        if collocated with quadrature points
658   @param v           CeedVector to be used by CeedOperator or @ref CEED_VECTOR_ACTIVE
659                        if field is active or @ref CEED_VECTOR_NONE if using
660                        @ref CEED_EVAL_WEIGHT in the QFunction
661 
662   @return An error code: 0 - success, otherwise - failure
663 
664   @ref User
665 **/
666 int CeedOperatorSetField(CeedOperator op, const char *field_name,
667                          CeedElemRestriction r, CeedBasis b, CeedVector v) {
668   int ierr;
669   if (op->is_composite)
670     // LCOV_EXCL_START
671     return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
672                      "Cannot add field to composite operator.");
673   // LCOV_EXCL_STOP
674   if (op->is_immutable)
675     // LCOV_EXCL_START
676     return CeedError(op->ceed, CEED_ERROR_MAJOR,
677                      "Operator cannot be changed after set as immutable");
678   // LCOV_EXCL_STOP
679   if (!r)
680     // LCOV_EXCL_START
681     return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
682                      "ElemRestriction r for field \"%s\" must be non-NULL.",
683                      field_name);
684   // LCOV_EXCL_STOP
685   if (!b)
686     // LCOV_EXCL_START
687     return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
688                      "Basis b for field \"%s\" must be non-NULL.",
689                      field_name);
690   // LCOV_EXCL_STOP
691   if (!v)
692     // LCOV_EXCL_START
693     return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
694                      "Vector v for field \"%s\" must be non-NULL.",
695                      field_name);
696   // LCOV_EXCL_STOP
697 
698   CeedInt num_elem;
699   ierr = CeedElemRestrictionGetNumElements(r, &num_elem); CeedChk(ierr);
700   if (r != CEED_ELEMRESTRICTION_NONE && op->has_restriction &&
701       op->num_elem != num_elem)
702     // LCOV_EXCL_START
703     return CeedError(op->ceed, CEED_ERROR_DIMENSION,
704                      "ElemRestriction with %d elements incompatible with prior "
705                      "%d elements", num_elem, op->num_elem);
706   // LCOV_EXCL_STOP
707 
708   CeedInt num_qpts = 0;
709   if (b != CEED_BASIS_COLLOCATED) {
710     ierr = CeedBasisGetNumQuadraturePoints(b, &num_qpts); CeedChk(ierr);
711     if (op->num_qpts && op->num_qpts != num_qpts)
712       // LCOV_EXCL_START
713       return CeedError(op->ceed, CEED_ERROR_DIMENSION,
714                        "Basis with %d quadrature points "
715                        "incompatible with prior %d points", num_qpts,
716                        op->num_qpts);
717     // LCOV_EXCL_STOP
718   }
719   CeedQFunctionField qf_field;
720   CeedOperatorField *op_field;
721   for (CeedInt i=0; i<op->qf->num_input_fields; i++) {
722     if (!strcmp(field_name, (*op->qf->input_fields[i]).field_name)) {
723       qf_field = op->qf->input_fields[i];
724       op_field = &op->input_fields[i];
725       goto found;
726     }
727   }
728   for (CeedInt i=0; i<op->qf->num_output_fields; i++) {
729     if (!strcmp(field_name, (*op->qf->output_fields[i]).field_name)) {
730       qf_field = op->qf->output_fields[i];
731       op_field = &op->output_fields[i];
732       goto found;
733     }
734   }
735   // LCOV_EXCL_START
736   return CeedError(op->ceed, CEED_ERROR_INCOMPLETE,
737                    "QFunction has no knowledge of field '%s'",
738                    field_name);
739   // LCOV_EXCL_STOP
740 found:
741   ierr = CeedOperatorCheckField(op->ceed, qf_field, r, b); CeedChk(ierr);
742   ierr = CeedCalloc(1, op_field); CeedChk(ierr);
743 
744   (*op_field)->vec = v;
745   if (v != CEED_VECTOR_ACTIVE && v != CEED_VECTOR_NONE) {
746     ierr = CeedVectorReference(v); CeedChk(ierr);
747   }
748 
749   (*op_field)->elem_restr = r;
750   ierr = CeedElemRestrictionReference(r); CeedChk(ierr);
751   if (r != CEED_ELEMRESTRICTION_NONE) {
752     op->num_elem = num_elem;
753     op->has_restriction = true; // Restriction set, but num_elem may be 0
754   }
755 
756   (*op_field)->basis = b;
757   if (b != CEED_BASIS_COLLOCATED) {
758     if (!op->num_qpts) {
759       ierr = CeedOperatorSetNumQuadraturePoints(op, num_qpts); CeedChk(ierr);
760     }
761     ierr = CeedBasisReference(b); CeedChk(ierr);
762   }
763 
764   op->num_fields += 1;
765   ierr = CeedStringAllocCopy(field_name, (char **)&(*op_field)->field_name);
766   CeedChk(ierr);
767   return CEED_ERROR_SUCCESS;
768 }
769 
770 /**
771   @brief Get the CeedOperatorFields of a CeedOperator
772 
773   Note: Calling this function asserts that setup is complete
774           and sets the CeedOperator as immutable.
775 
776   @param op                      CeedOperator
777   @param[out] num_input_fields   Variable to store number of input fields
778   @param[out] input_fields       Variable to store input_fields
779   @param[out] num_output_fields  Variable to store number of output fields
780   @param[out] output_fields      Variable to store output_fields
781 
782   @return An error code: 0 - success, otherwise - failure
783 
784   @ref Advanced
785 **/
786 int CeedOperatorGetFields(CeedOperator op, CeedInt *num_input_fields,
787                           CeedOperatorField **input_fields,
788                           CeedInt *num_output_fields,
789                           CeedOperatorField **output_fields) {
790   int ierr;
791 
792   if (op->is_composite)
793     // LCOV_EXCL_START
794     return CeedError(op->ceed, CEED_ERROR_MINOR,
795                      "Not defined for composite operator");
796   // LCOV_EXCL_STOP
797   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
798 
799   if (num_input_fields) *num_input_fields = op->qf->num_input_fields;
800   if (input_fields) *input_fields = op->input_fields;
801   if (num_output_fields) *num_output_fields = op->qf->num_output_fields;
802   if (output_fields) *output_fields = op->output_fields;
803   return CEED_ERROR_SUCCESS;
804 }
805 
806 /**
807   @brief Get the name of a CeedOperatorField
808 
809   @param op_field         CeedOperatorField
810   @param[out] field_name  Variable to store the field name
811 
812   @return An error code: 0 - success, otherwise - failure
813 
814   @ref Advanced
815 **/
816 int CeedOperatorFieldGetName(CeedOperatorField op_field, char **field_name) {
817   *field_name = (char *)op_field->field_name;
818   return CEED_ERROR_SUCCESS;
819 }
820 
821 /**
822   @brief Get the CeedElemRestriction of a CeedOperatorField
823 
824   @param op_field   CeedOperatorField
825   @param[out] rstr  Variable to store CeedElemRestriction
826 
827   @return An error code: 0 - success, otherwise - failure
828 
829   @ref Advanced
830 **/
831 int CeedOperatorFieldGetElemRestriction(CeedOperatorField op_field,
832                                         CeedElemRestriction *rstr) {
833   *rstr = op_field->elem_restr;
834   return CEED_ERROR_SUCCESS;
835 }
836 
837 /**
838   @brief Get the CeedBasis of a CeedOperatorField
839 
840   @param op_field    CeedOperatorField
841   @param[out] basis  Variable to store CeedBasis
842 
843   @return An error code: 0 - success, otherwise - failure
844 
845   @ref Advanced
846 **/
847 int CeedOperatorFieldGetBasis(CeedOperatorField op_field, CeedBasis *basis) {
848   *basis = op_field->basis;
849   return CEED_ERROR_SUCCESS;
850 }
851 
852 /**
853   @brief Get the CeedVector of a CeedOperatorField
854 
855   @param op_field  CeedOperatorField
856   @param[out] vec  Variable to store CeedVector
857 
858   @return An error code: 0 - success, otherwise - failure
859 
860   @ref Advanced
861 **/
862 int CeedOperatorFieldGetVector(CeedOperatorField op_field, CeedVector *vec) {
863   *vec = op_field->vec;
864   return CEED_ERROR_SUCCESS;
865 }
866 
867 /**
868   @brief Add a sub-operator to a composite CeedOperator
869 
870   @param[out] composite_op  Composite CeedOperator
871   @param      sub_op        Sub-operator CeedOperator
872 
873   @return An error code: 0 - success, otherwise - failure
874 
875   @ref User
876  */
877 int CeedCompositeOperatorAddSub(CeedOperator composite_op,
878                                 CeedOperator sub_op) {
879   int ierr;
880 
881   if (!composite_op->is_composite)
882     // LCOV_EXCL_START
883     return CeedError(composite_op->ceed, CEED_ERROR_MINOR,
884                      "CeedOperator is not a composite operator");
885   // LCOV_EXCL_STOP
886 
887   if (composite_op->num_suboperators == CEED_COMPOSITE_MAX)
888     // LCOV_EXCL_START
889     return CeedError(composite_op->ceed, CEED_ERROR_UNSUPPORTED,
890                      "Cannot add additional sub_operators");
891   // LCOV_EXCL_STOP
892   if (composite_op->is_immutable)
893     // LCOV_EXCL_START
894     return CeedError(composite_op->ceed, CEED_ERROR_MAJOR,
895                      "Operator cannot be changed after set as immutable");
896   // LCOV_EXCL_STOP
897 
898   composite_op->sub_operators[composite_op->num_suboperators] = sub_op;
899   ierr = CeedOperatorReference(sub_op); CeedChk(ierr);
900   composite_op->num_suboperators++;
901   return CEED_ERROR_SUCCESS;
902 }
903 
904 /**
905   @brief Check if a CeedOperator is ready to be used.
906 
907   @param[in] op  CeedOperator to check
908 
909   @return An error code: 0 - success, otherwise - failure
910 
911   @ref User
912 **/
913 int CeedOperatorCheckReady(CeedOperator op) {
914   int ierr;
915   Ceed ceed;
916   ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr);
917 
918   if (op->is_interface_setup)
919     return CEED_ERROR_SUCCESS;
920 
921   CeedQFunction qf = op->qf;
922   if (op->is_composite) {
923     if (!op->num_suboperators)
924       // LCOV_EXCL_START
925       return CeedError(ceed, CEED_ERROR_INCOMPLETE, "No sub_operators set");
926     // LCOV_EXCL_STOP
927     for (CeedInt i = 0; i < op->num_suboperators; i++) {
928       ierr = CeedOperatorCheckReady(op->sub_operators[i]); CeedChk(ierr);
929     }
930   } else {
931     if (op->num_fields == 0)
932       // LCOV_EXCL_START
933       return CeedError(ceed, CEED_ERROR_INCOMPLETE, "No operator fields set");
934     // LCOV_EXCL_STOP
935     if (op->num_fields < qf->num_input_fields + qf->num_output_fields)
936       // LCOV_EXCL_START
937       return CeedError(ceed, CEED_ERROR_INCOMPLETE, "Not all operator fields set");
938     // LCOV_EXCL_STOP
939     if (!op->has_restriction)
940       // LCOV_EXCL_START
941       return CeedError(ceed, CEED_ERROR_INCOMPLETE,
942                        "At least one restriction required");
943     // LCOV_EXCL_STOP
944     if (op->num_qpts == 0)
945       // LCOV_EXCL_START
946       return CeedError(ceed, CEED_ERROR_INCOMPLETE,
947                        "At least one non-collocated basis is required "
948                        "or the number of quadrature points must be set");
949     // LCOV_EXCL_STOP
950   }
951 
952   // Flag as immutable and ready
953   op->is_interface_setup = true;
954   if (op->qf && op->qf != CEED_QFUNCTION_NONE)
955     // LCOV_EXCL_START
956     op->qf->is_immutable = true;
957   // LCOV_EXCL_STOP
958   if (op->dqf && op->dqf != CEED_QFUNCTION_NONE)
959     // LCOV_EXCL_START
960     op->dqf->is_immutable = true;
961   // LCOV_EXCL_STOP
962   if (op->dqfT && op->dqfT != CEED_QFUNCTION_NONE)
963     // LCOV_EXCL_START
964     op->dqfT->is_immutable = true;
965   // LCOV_EXCL_STOP
966   return CEED_ERROR_SUCCESS;
967 }
968 
969 /**
970   @brief Set reuse of CeedQFunction data in CeedOperatorLinearAssemble* functions.
971            When `reuse_assembly_data = false` (default), the CeedQFunction associated
972            with this CeedOperator is re-assembled every time a `CeedOperatorLinearAssemble*`
973            function is called.
974            When `reuse_assembly_data = true`, the CeedQFunction associated with
975            this CeedOperator is reused between calls to
976            `CeedOperatorSetQFunctionAssemblyDataUpdated`.
977 
978   @param[in] op                  CeedOperator
979   @param[in] reuse_assembly_data Boolean flag setting assembly data reuse
980 
981   @return An error code: 0 - success, otherwise - failure
982 
983   @ref Advanced
984 **/
985 int CeedOperatorSetQFunctionAssemblyReuse(CeedOperator op,
986     bool reuse_assembly_data) {
987   int ierr;
988   bool is_composite;
989 
990   ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr);
991   if (is_composite) {
992     for (CeedInt i = 0; i < op->num_suboperators; i++) {
993       ierr = CeedOperatorSetQFunctionAssemblyReuse(op->sub_operators[i],
994              reuse_assembly_data); CeedChk(ierr);
995     }
996   } else {
997     ierr = CeedQFunctionAssemblyDataSetReuse(op->qf_assembled, reuse_assembly_data);
998     CeedChk(ierr);
999   }
1000 
1001   return CEED_ERROR_SUCCESS;
1002 }
1003 
1004 /**
1005   @brief Mark CeedQFunction data as updated and the CeedQFunction as requiring re-assembly.
1006 
1007   @param[in] op                  CeedOperator
1008   @param[in] reuse_assembly_data Boolean flag setting assembly data reuse
1009 
1010   @return An error code: 0 - success, otherwise - failure
1011 
1012   @ref Advanced
1013 **/
1014 int CeedOperatorSetQFunctionAssemblyDataUpdateNeeded(CeedOperator op,
1015     bool needs_data_update) {
1016   int ierr;
1017   bool is_composite;
1018 
1019   ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr);
1020   if (is_composite) {
1021     for (CeedInt i = 0; i < op->num_suboperators; i++) {
1022       ierr = CeedOperatorSetQFunctionAssemblyDataUpdateNeeded(op->sub_operators[i],
1023              needs_data_update); CeedChk(ierr);
1024     }
1025   } else {
1026     ierr = CeedQFunctionAssemblyDataSetUpdateNeeded(op->qf_assembled,
1027            needs_data_update);
1028     CeedChk(ierr);
1029   }
1030 
1031   return CEED_ERROR_SUCCESS;
1032 }
1033 
1034 /**
1035   @brief Set the number of quadrature points associated with a CeedOperator.
1036            This should be used when creating a CeedOperator where every
1037            field has a collocated basis. This function cannot be used for
1038            composite CeedOperators.
1039 
1040   @param op        CeedOperator
1041   @param num_qpts  Number of quadrature points to set
1042 
1043   @return An error code: 0 - success, otherwise - failure
1044 
1045   @ref Advanced
1046 **/
1047 int CeedOperatorSetNumQuadraturePoints(CeedOperator op, CeedInt num_qpts) {
1048   if (op->is_composite)
1049     // LCOV_EXCL_START
1050     return CeedError(op->ceed, CEED_ERROR_MINOR,
1051                      "Not defined for composite operator");
1052   // LCOV_EXCL_STOP
1053   if (op->num_qpts)
1054     // LCOV_EXCL_START
1055     return CeedError(op->ceed, CEED_ERROR_MINOR,
1056                      "Number of quadrature points already defined");
1057   // LCOV_EXCL_STOP
1058   if (op->is_immutable)
1059     // LCOV_EXCL_START
1060     return CeedError(op->ceed, CEED_ERROR_MAJOR,
1061                      "Operator cannot be changed after set as immutable");
1062   // LCOV_EXCL_STOP
1063 
1064   op->num_qpts = num_qpts;
1065   return CEED_ERROR_SUCCESS;
1066 }
1067 
1068 /**
1069   @brief View a CeedOperator
1070 
1071   @param[in] op      CeedOperator to view
1072   @param[in] stream  Stream to write; typically stdout/stderr or a file
1073 
1074   @return Error code: 0 - success, otherwise - failure
1075 
1076   @ref User
1077 **/
1078 int CeedOperatorView(CeedOperator op, FILE *stream) {
1079   int ierr;
1080 
1081   if (op->is_composite) {
1082     fprintf(stream, "Composite CeedOperator\n");
1083 
1084     for (CeedInt i=0; i<op->num_suboperators; i++) {
1085       fprintf(stream, "  SubOperator [%d]:\n", i);
1086       ierr = CeedOperatorSingleView(op->sub_operators[i], 1, stream);
1087       CeedChk(ierr);
1088     }
1089   } else {
1090     fprintf(stream, "CeedOperator\n");
1091     ierr = CeedOperatorSingleView(op, 0, stream); CeedChk(ierr);
1092   }
1093   return CEED_ERROR_SUCCESS;
1094 }
1095 
1096 /**
1097   @brief Get the Ceed associated with a CeedOperator
1098 
1099   @param op         CeedOperator
1100   @param[out] ceed  Variable to store Ceed
1101 
1102   @return An error code: 0 - success, otherwise - failure
1103 
1104   @ref Advanced
1105 **/
1106 int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) {
1107   *ceed = op->ceed;
1108   return CEED_ERROR_SUCCESS;
1109 }
1110 
1111 /**
1112   @brief Get the number of elements associated with a CeedOperator
1113 
1114   @param op             CeedOperator
1115   @param[out] num_elem  Variable to store number of elements
1116 
1117   @return An error code: 0 - success, otherwise - failure
1118 
1119   @ref Advanced
1120 **/
1121 int CeedOperatorGetNumElements(CeedOperator op, CeedInt *num_elem) {
1122   if (op->is_composite)
1123     // LCOV_EXCL_START
1124     return CeedError(op->ceed, CEED_ERROR_MINOR,
1125                      "Not defined for composite operator");
1126   // LCOV_EXCL_STOP
1127 
1128   *num_elem = op->num_elem;
1129   return CEED_ERROR_SUCCESS;
1130 }
1131 
1132 /**
1133   @brief Get the number of quadrature points associated with a CeedOperator
1134 
1135   @param op             CeedOperator
1136   @param[out] num_qpts  Variable to store vector number of quadrature points
1137 
1138   @return An error code: 0 - success, otherwise - failure
1139 
1140   @ref Advanced
1141 **/
1142 int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *num_qpts) {
1143   if (op->is_composite)
1144     // LCOV_EXCL_START
1145     return CeedError(op->ceed, CEED_ERROR_MINOR,
1146                      "Not defined for composite operator");
1147   // LCOV_EXCL_STOP
1148 
1149   *num_qpts = op->num_qpts;
1150   return CEED_ERROR_SUCCESS;
1151 }
1152 
1153 /**
1154   @brief Get label for a registered QFunctionContext field, or `NULL` if no
1155            field has been registered with this `field_name`.
1156 
1157   @param[in] op            CeedOperator
1158   @param[in] field_name    Name of field to retrieve label
1159   @param[out] field_label  Variable to field label
1160 
1161   @return An error code: 0 - success, otherwise - failure
1162 
1163   @ref User
1164 **/
1165 int CeedOperatorContextGetFieldLabel(CeedOperator op,
1166                                      const char *field_name,
1167                                      CeedContextFieldLabel *field_label) {
1168   int ierr;
1169 
1170   bool is_composite;
1171   ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr);
1172   if (is_composite) {
1173     // Check if composite label already created
1174     for (CeedInt i=0; i<op->num_context_labels; i++) {
1175       if (!strcmp(op->context_labels[i]->name, field_name)) {
1176         *field_label = op->context_labels[i];
1177         return CEED_ERROR_SUCCESS;
1178       }
1179     }
1180 
1181     // Create composite label if needed
1182     CeedInt num_sub;
1183     CeedOperator *sub_operators;
1184     CeedContextFieldLabel new_field_label;
1185 
1186     ierr = CeedCalloc(1, &new_field_label); CeedChk(ierr);
1187     ierr = CeedOperatorGetNumSub(op, &num_sub); CeedChk(ierr);
1188     ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr);
1189     ierr = CeedCalloc(num_sub, &new_field_label->sub_labels); CeedChk(ierr);
1190     new_field_label->num_sub_labels = num_sub;
1191 
1192     bool label_found = false;
1193     for (CeedInt i=0; i<num_sub; i++) {
1194       if (sub_operators[i]->qf->ctx) {
1195         CeedContextFieldLabel new_field_label_i;
1196         ierr = CeedQFunctionContextGetFieldLabel(sub_operators[i]->qf->ctx, field_name,
1197                &new_field_label_i); CeedChk(ierr);
1198         if (new_field_label_i) {
1199           label_found = true;
1200           new_field_label->sub_labels[i] = new_field_label_i;
1201           new_field_label->name = new_field_label_i->name;
1202           new_field_label->description = new_field_label_i->description;
1203           if (new_field_label->type &&
1204               new_field_label->type != new_field_label_i->type) {
1205             // LCOV_EXCL_START
1206             ierr = CeedFree(&new_field_label); CeedChk(ierr);
1207             return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
1208                              "Incompatible field types on sub-operator contexts. "
1209                              "%s != %s",
1210                              CeedContextFieldTypes[new_field_label->type],
1211                              CeedContextFieldTypes[new_field_label_i->type]);
1212             // LCOV_EXCL_STOP
1213           } else {
1214             new_field_label->type = new_field_label_i->type;
1215           }
1216           if (new_field_label->num_values != 0 &&
1217               new_field_label->num_values != new_field_label_i->num_values) {
1218             // LCOV_EXCL_START
1219             ierr = CeedFree(&new_field_label); CeedChk(ierr);
1220             return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
1221                              "Incompatible field number of values on sub-operator"
1222                              " contexts. %ld != %ld",
1223                              new_field_label->num_values, new_field_label_i->num_values);
1224             // LCOV_EXCL_STOP
1225           } else {
1226             new_field_label->num_values = new_field_label_i->num_values;
1227           }
1228         }
1229       }
1230     }
1231     if (!label_found) {
1232       // LCOV_EXCL_START
1233       ierr = CeedFree(&new_field_label->sub_labels); CeedChk(ierr);
1234       ierr = CeedFree(&new_field_label); CeedChk(ierr);
1235       *field_label = NULL;
1236       // LCOV_EXCL_STOP
1237     } else {
1238       // Move new composite label to operator
1239       if (op->num_context_labels == 0) {
1240         ierr = CeedCalloc(1, &op->context_labels); CeedChk(ierr);
1241         op->max_context_labels = 1;
1242       } else if (op->num_context_labels == op->max_context_labels) {
1243         ierr = CeedRealloc(2*op->num_context_labels, &op->context_labels);
1244         CeedChk(ierr);
1245         op->max_context_labels *= 2;
1246       }
1247       op->context_labels[op->num_context_labels] = new_field_label;
1248       *field_label = new_field_label;
1249       op->num_context_labels++;
1250     }
1251 
1252     return CEED_ERROR_SUCCESS;
1253   } else {
1254     return CeedQFunctionContextGetFieldLabel(op->qf->ctx, field_name, field_label);
1255   }
1256 }
1257 
1258 /**
1259   @brief Set QFunctionContext field holding a double precision value.
1260            For composite operators, the value is set in all
1261            sub-operator QFunctionContexts that have a matching `field_name`.
1262 
1263   @param op          CeedOperator
1264   @param field_label Label of field to register
1265   @param values      Values to set
1266 
1267   @return An error code: 0 - success, otherwise - failure
1268 
1269   @ref User
1270 **/
1271 int CeedOperatorContextSetDouble(CeedOperator op,
1272                                  CeedContextFieldLabel field_label,
1273                                  double *values) {
1274   return CeedOperatorContextSetGeneric(op, field_label, CEED_CONTEXT_FIELD_DOUBLE,
1275                                        values);
1276 }
1277 
1278 /**
1279   @brief Set QFunctionContext field holding an int32 value.
1280            For composite operators, the value is set in all
1281            sub-operator QFunctionContexts that have a matching `field_name`.
1282 
1283   @param op          CeedOperator
1284   @param field_label Label of field to set
1285   @param values      Values to set
1286 
1287   @return An error code: 0 - success, otherwise - failure
1288 
1289   @ref User
1290 **/
1291 int CeedOperatorContextSetInt32(CeedOperator op,
1292                                 CeedContextFieldLabel field_label,
1293                                 int *values) {
1294   return CeedOperatorContextSetGeneric(op, field_label, CEED_CONTEXT_FIELD_INT32,
1295                                        values);
1296 }
1297 
1298 /**
1299   @brief Apply CeedOperator to a vector
1300 
1301   This computes the action of the operator on the specified (active) input,
1302   yielding its (active) output.  All inputs and outputs must be specified using
1303   CeedOperatorSetField().
1304 
1305   Note: Calling this function asserts that setup is complete
1306           and sets the CeedOperator as immutable.
1307 
1308   @param op        CeedOperator to apply
1309   @param[in] in    CeedVector containing input state or @ref CEED_VECTOR_NONE if
1310                      there are no active inputs
1311   @param[out] out  CeedVector to store result of applying operator (must be
1312                      distinct from @a in) or @ref CEED_VECTOR_NONE if there are no
1313                      active outputs
1314   @param request   Address of CeedRequest for non-blocking completion, else
1315                      @ref CEED_REQUEST_IMMEDIATE
1316 
1317   @return An error code: 0 - success, otherwise - failure
1318 
1319   @ref User
1320 **/
1321 int CeedOperatorApply(CeedOperator op, CeedVector in, CeedVector out,
1322                       CeedRequest *request) {
1323   int ierr;
1324   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
1325 
1326   if (op->num_elem)  {
1327     // Standard Operator
1328     if (op->Apply) {
1329       ierr = op->Apply(op, in, out, request); CeedChk(ierr);
1330     } else {
1331       // Zero all output vectors
1332       CeedQFunction qf = op->qf;
1333       for (CeedInt i=0; i<qf->num_output_fields; i++) {
1334         CeedVector vec = op->output_fields[i]->vec;
1335         if (vec == CEED_VECTOR_ACTIVE)
1336           vec = out;
1337         if (vec != CEED_VECTOR_NONE) {
1338           ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr);
1339         }
1340       }
1341       // Apply
1342       ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr);
1343     }
1344   } else if (op->is_composite) {
1345     // Composite Operator
1346     if (op->ApplyComposite) {
1347       ierr = op->ApplyComposite(op, in, out, request); CeedChk(ierr);
1348     } else {
1349       CeedInt num_suboperators;
1350       ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr);
1351       CeedOperator *sub_operators;
1352       ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr);
1353 
1354       // Zero all output vectors
1355       if (out != CEED_VECTOR_NONE) {
1356         ierr = CeedVectorSetValue(out, 0.0); CeedChk(ierr);
1357       }
1358       for (CeedInt i=0; i<num_suboperators; i++) {
1359         for (CeedInt j=0; j<sub_operators[i]->qf->num_output_fields; j++) {
1360           CeedVector vec = sub_operators[i]->output_fields[j]->vec;
1361           if (vec != CEED_VECTOR_ACTIVE && vec != CEED_VECTOR_NONE) {
1362             ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr);
1363           }
1364         }
1365       }
1366       // Apply
1367       for (CeedInt i=0; i<op->num_suboperators; i++) {
1368         ierr = CeedOperatorApplyAdd(op->sub_operators[i], in, out, request);
1369         CeedChk(ierr);
1370       }
1371     }
1372   }
1373   return CEED_ERROR_SUCCESS;
1374 }
1375 
1376 /**
1377   @brief Apply CeedOperator to a vector and add result to output vector
1378 
1379   This computes the action of the operator on the specified (active) input,
1380   yielding its (active) output.  All inputs and outputs must be specified using
1381   CeedOperatorSetField().
1382 
1383   @param op        CeedOperator to apply
1384   @param[in] in    CeedVector containing input state or NULL if there are no
1385                      active inputs
1386   @param[out] out  CeedVector to sum in result of applying operator (must be
1387                      distinct from @a in) or NULL if there are no active outputs
1388   @param request   Address of CeedRequest for non-blocking completion, else
1389                      @ref CEED_REQUEST_IMMEDIATE
1390 
1391   @return An error code: 0 - success, otherwise - failure
1392 
1393   @ref User
1394 **/
1395 int CeedOperatorApplyAdd(CeedOperator op, CeedVector in, CeedVector out,
1396                          CeedRequest *request) {
1397   int ierr;
1398   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
1399 
1400   if (op->num_elem)  {
1401     // Standard Operator
1402     ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr);
1403   } else if (op->is_composite) {
1404     // Composite Operator
1405     if (op->ApplyAddComposite) {
1406       ierr = op->ApplyAddComposite(op, in, out, request); CeedChk(ierr);
1407     } else {
1408       CeedInt num_suboperators;
1409       ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr);
1410       CeedOperator *sub_operators;
1411       ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr);
1412 
1413       for (CeedInt i=0; i<num_suboperators; i++) {
1414         ierr = CeedOperatorApplyAdd(sub_operators[i], in, out, request);
1415         CeedChk(ierr);
1416       }
1417     }
1418   }
1419   return CEED_ERROR_SUCCESS;
1420 }
1421 
1422 /**
1423   @brief Destroy a CeedOperator
1424 
1425   @param op  CeedOperator to destroy
1426 
1427   @return An error code: 0 - success, otherwise - failure
1428 
1429   @ref User
1430 **/
1431 int CeedOperatorDestroy(CeedOperator *op) {
1432   int ierr;
1433 
1434   if (!*op || --(*op)->ref_count > 0) return CEED_ERROR_SUCCESS;
1435   if ((*op)->Destroy) {
1436     ierr = (*op)->Destroy(*op); CeedChk(ierr);
1437   }
1438   ierr = CeedDestroy(&(*op)->ceed); CeedChk(ierr);
1439   // Free fields
1440   for (CeedInt i=0; i<(*op)->num_fields; i++)
1441     if ((*op)->input_fields[i]) {
1442       if ((*op)->input_fields[i]->elem_restr != CEED_ELEMRESTRICTION_NONE) {
1443         ierr = CeedElemRestrictionDestroy(&(*op)->input_fields[i]->elem_restr);
1444         CeedChk(ierr);
1445       }
1446       if ((*op)->input_fields[i]->basis != CEED_BASIS_COLLOCATED) {
1447         ierr = CeedBasisDestroy(&(*op)->input_fields[i]->basis); CeedChk(ierr);
1448       }
1449       if ((*op)->input_fields[i]->vec != CEED_VECTOR_ACTIVE &&
1450           (*op)->input_fields[i]->vec != CEED_VECTOR_NONE ) {
1451         ierr = CeedVectorDestroy(&(*op)->input_fields[i]->vec); CeedChk(ierr);
1452       }
1453       ierr = CeedFree(&(*op)->input_fields[i]->field_name); CeedChk(ierr);
1454       ierr = CeedFree(&(*op)->input_fields[i]); CeedChk(ierr);
1455     }
1456   for (CeedInt i=0; i<(*op)->num_fields; i++)
1457     if ((*op)->output_fields[i]) {
1458       ierr = CeedElemRestrictionDestroy(&(*op)->output_fields[i]->elem_restr);
1459       CeedChk(ierr);
1460       if ((*op)->output_fields[i]->basis != CEED_BASIS_COLLOCATED) {
1461         ierr = CeedBasisDestroy(&(*op)->output_fields[i]->basis); CeedChk(ierr);
1462       }
1463       if ((*op)->output_fields[i]->vec != CEED_VECTOR_ACTIVE &&
1464           (*op)->output_fields[i]->vec != CEED_VECTOR_NONE ) {
1465         ierr = CeedVectorDestroy(&(*op)->output_fields[i]->vec); CeedChk(ierr);
1466       }
1467       ierr = CeedFree(&(*op)->output_fields[i]->field_name); CeedChk(ierr);
1468       ierr = CeedFree(&(*op)->output_fields[i]); CeedChk(ierr);
1469     }
1470   // Destroy sub_operators
1471   for (CeedInt i=0; i<(*op)->num_suboperators; i++)
1472     if ((*op)->sub_operators[i]) {
1473       ierr = CeedOperatorDestroy(&(*op)->sub_operators[i]); CeedChk(ierr);
1474     }
1475   ierr = CeedQFunctionDestroy(&(*op)->qf); CeedChk(ierr);
1476   ierr = CeedQFunctionDestroy(&(*op)->dqf); CeedChk(ierr);
1477   ierr = CeedQFunctionDestroy(&(*op)->dqfT); CeedChk(ierr);
1478   // Destroy any composite labels
1479   for (CeedInt i=0; i<(*op)->num_context_labels; i++) {
1480     ierr = CeedFree(&(*op)->context_labels[i]->sub_labels); CeedChk(ierr);
1481     ierr = CeedFree(&(*op)->context_labels[i]); CeedChk(ierr);
1482   }
1483   ierr = CeedFree(&(*op)->context_labels); CeedChk(ierr);
1484 
1485   // Destroy fallback
1486   if ((*op)->op_fallback) {
1487     ierr = (*op)->qf_fallback->Destroy((*op)->qf_fallback); CeedChk(ierr);
1488     ierr = CeedFree(&(*op)->qf_fallback); CeedChk(ierr);
1489     ierr = (*op)->op_fallback->Destroy((*op)->op_fallback); CeedChk(ierr);
1490     ierr = CeedFree(&(*op)->op_fallback); CeedChk(ierr);
1491   }
1492 
1493   // Destroy QF assembly cache
1494   ierr = CeedQFunctionAssemblyDataDestroy(&(*op)->qf_assembled); CeedChk(ierr);
1495 
1496   ierr = CeedFree(&(*op)->input_fields); CeedChk(ierr);
1497   ierr = CeedFree(&(*op)->output_fields); CeedChk(ierr);
1498   ierr = CeedFree(&(*op)->sub_operators); CeedChk(ierr);
1499   ierr = CeedFree(op); CeedChk(ierr);
1500   return CEED_ERROR_SUCCESS;
1501 }
1502 
1503 /// @}
1504