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