xref: /libCEED/rust/libceed-sys/c-src/interface/ceed-operator.c (revision 506b1a0c535297a01950817d4491440b9ddb5287)
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   return CEED_ERROR_SUCCESS;
313 }
314 
315 /**
316   @brief Get QFunctionContext field values of the specified type, read-only.
317 
318   For composite operators, the values retrieved are for the first sub-operator QFunctionContext that have a matching `field_name`.
319   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
320 any field of a matching type.
321 
322   @param[in,out] op          CeedOperator
323   @param[in]     field_label Label of field to set
324   @param[in]     field_type  Type of field to set
325   @param[out]    num_values  Number of values of type `field_type` in array `values`
326   @param[out]    values      Values in the label
327 
328   @return An error code: 0 - success, otherwise - failure
329 
330   @ref User
331 **/
332 static int CeedOperatorContextGetGenericRead(CeedOperator op, CeedContextFieldLabel field_label, CeedContextFieldType field_type, size_t *num_values,
333                                              void *values) {
334   bool is_composite = false;
335 
336   CeedCheck(field_label, op->ceed, CEED_ERROR_UNSUPPORTED, "Invalid field label");
337 
338   *(void **)values = NULL;
339   *num_values      = 0;
340 
341   // Check if field_label and op correspond
342   if (field_label->from_op) {
343     CeedInt index = -1;
344 
345     for (CeedInt i = 0; i < op->num_context_labels; i++) {
346       if (op->context_labels[i] == field_label) index = i;
347     }
348     CeedCheck(index != -1, op->ceed, CEED_ERROR_UNSUPPORTED, "ContextFieldLabel does not correspond to the operator");
349   }
350 
351   CeedCall(CeedOperatorIsComposite(op, &is_composite));
352   if (is_composite) {
353     CeedInt       num_sub;
354     CeedOperator *sub_operators;
355 
356     CeedCall(CeedCompositeOperatorGetNumSub(op, &num_sub));
357     CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators));
358     CeedCheck(num_sub == field_label->num_sub_labels, op->ceed, CEED_ERROR_UNSUPPORTED,
359               "Composite operator modified after ContextFieldLabel created");
360 
361     for (CeedInt i = 0; i < num_sub; i++) {
362       // Try every sub-operator, ok if some sub-operators do not have field
363       if (field_label->sub_labels[i] && sub_operators[i]->qf->ctx) {
364         CeedCall(CeedQFunctionContextGetGenericRead(sub_operators[i]->qf->ctx, field_label->sub_labels[i], field_type, num_values, values));
365         return CEED_ERROR_SUCCESS;
366       }
367     }
368   } else {
369     CeedCheck(op->qf->ctx, op->ceed, CEED_ERROR_UNSUPPORTED, "QFunction does not have context data");
370     CeedCall(CeedQFunctionContextGetGenericRead(op->qf->ctx, field_label, field_type, num_values, values));
371   }
372   return CEED_ERROR_SUCCESS;
373 }
374 
375 /**
376   @brief Restore QFunctionContext field values of the specified type, read-only.
377 
378   For composite operators, the values restored are for the first sub-operator QFunctionContext that have a matching `field_name`.
379   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
380 any field of a matching type.
381 
382   @param[in,out] op          CeedOperator
383   @param[in]     field_label Label of field to set
384   @param[in]     field_type  Type of field to set
385   @param[in]     values      Values array to restore
386 
387   @return An error code: 0 - success, otherwise - failure
388 
389   @ref User
390 **/
391 static int CeedOperatorContextRestoreGenericRead(CeedOperator op, CeedContextFieldLabel field_label, CeedContextFieldType field_type, void *values) {
392   bool is_composite = false;
393 
394   CeedCheck(field_label, op->ceed, CEED_ERROR_UNSUPPORTED, "Invalid field label");
395 
396   // Check if field_label and op correspond
397   if (field_label->from_op) {
398     CeedInt index = -1;
399 
400     for (CeedInt i = 0; i < op->num_context_labels; i++) {
401       if (op->context_labels[i] == field_label) index = i;
402     }
403     CeedCheck(index != -1, op->ceed, CEED_ERROR_UNSUPPORTED, "ContextFieldLabel does not correspond to the operator");
404   }
405 
406   CeedCall(CeedOperatorIsComposite(op, &is_composite));
407   if (is_composite) {
408     CeedInt       num_sub;
409     CeedOperator *sub_operators;
410 
411     CeedCall(CeedCompositeOperatorGetNumSub(op, &num_sub));
412     CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators));
413     CeedCheck(num_sub == field_label->num_sub_labels, op->ceed, CEED_ERROR_UNSUPPORTED,
414               "Composite operator modified after ContextFieldLabel created");
415 
416     for (CeedInt i = 0; i < num_sub; i++) {
417       // Try every sub-operator, ok if some sub-operators do not have field
418       if (field_label->sub_labels[i] && sub_operators[i]->qf->ctx) {
419         CeedCall(CeedQFunctionContextRestoreGenericRead(sub_operators[i]->qf->ctx, field_label->sub_labels[i], field_type, values));
420         return CEED_ERROR_SUCCESS;
421       }
422     }
423   } else {
424     CeedCheck(op->qf->ctx, op->ceed, CEED_ERROR_UNSUPPORTED, "QFunction does not have context data");
425     CeedCall(CeedQFunctionContextRestoreGenericRead(op->qf->ctx, field_label, field_type, values));
426   }
427   return CEED_ERROR_SUCCESS;
428 }
429 
430 /// @}
431 
432 /// ----------------------------------------------------------------------------
433 /// CeedOperator Backend API
434 /// ----------------------------------------------------------------------------
435 /// @addtogroup CeedOperatorBackend
436 /// @{
437 
438 /**
439   @brief Get the number of arguments associated with a CeedOperator
440 
441   @param[in]  op        CeedOperator
442   @param[out] num_args  Variable to store vector number of arguments
443 
444   @return An error code: 0 - success, otherwise - failure
445 
446   @ref Backend
447 **/
448 int CeedOperatorGetNumArgs(CeedOperator op, CeedInt *num_args) {
449   CeedCheck(!op->is_composite, op->ceed, CEED_ERROR_MINOR, "Not defined for composite operators");
450   *num_args = op->num_fields;
451   return CEED_ERROR_SUCCESS;
452 }
453 
454 /**
455   @brief Get the setup status of a CeedOperator
456 
457   @param[in]  op            CeedOperator
458   @param[out] is_setup_done Variable to store setup status
459 
460   @return An error code: 0 - success, otherwise - failure
461 
462   @ref Backend
463 **/
464 int CeedOperatorIsSetupDone(CeedOperator op, bool *is_setup_done) {
465   *is_setup_done = op->is_backend_setup;
466   return CEED_ERROR_SUCCESS;
467 }
468 
469 /**
470   @brief Get the QFunction associated with a CeedOperator
471 
472   @param[in]  op CeedOperator
473   @param[out] qf Variable to store QFunction
474 
475   @return An error code: 0 - success, otherwise - failure
476 
477   @ref Backend
478 **/
479 int CeedOperatorGetQFunction(CeedOperator op, CeedQFunction *qf) {
480   CeedCheck(!op->is_composite, op->ceed, CEED_ERROR_MINOR, "Not defined for composite operator");
481   *qf = op->qf;
482   return CEED_ERROR_SUCCESS;
483 }
484 
485 /**
486   @brief Get a boolean value indicating if the CeedOperator is composite
487 
488   @param[in]  op           CeedOperator
489   @param[out] is_composite Variable to store composite status
490 
491   @return An error code: 0 - success, otherwise - failure
492 
493   @ref Backend
494 **/
495 int CeedOperatorIsComposite(CeedOperator op, bool *is_composite) {
496   *is_composite = op->is_composite;
497   return CEED_ERROR_SUCCESS;
498 }
499 
500 /**
501   @brief Get the backend data of a CeedOperator
502 
503   @param[in]  op   CeedOperator
504   @param[out] data Variable to store data
505 
506   @return An error code: 0 - success, otherwise - failure
507 
508   @ref Backend
509 **/
510 int CeedOperatorGetData(CeedOperator op, void *data) {
511   *(void **)data = op->data;
512   return CEED_ERROR_SUCCESS;
513 }
514 
515 /**
516   @brief Set the backend data of a CeedOperator
517 
518   @param[in,out] op   CeedOperator
519   @param[in]     data Data to set
520 
521   @return An error code: 0 - success, otherwise - failure
522 
523   @ref Backend
524 **/
525 int CeedOperatorSetData(CeedOperator op, void *data) {
526   op->data = data;
527   return CEED_ERROR_SUCCESS;
528 }
529 
530 /**
531   @brief Increment the reference counter for a CeedOperator
532 
533   @param[in,out] op CeedOperator to increment the reference counter
534 
535   @return An error code: 0 - success, otherwise - failure
536 
537   @ref Backend
538 **/
539 int CeedOperatorReference(CeedOperator op) {
540   op->ref_count++;
541   return CEED_ERROR_SUCCESS;
542 }
543 
544 /**
545   @brief Set the setup flag of a CeedOperator to True
546 
547   @param[in,out] op CeedOperator
548 
549   @return An error code: 0 - success, otherwise - failure
550 
551   @ref Backend
552 **/
553 int CeedOperatorSetSetupDone(CeedOperator op) {
554   op->is_backend_setup = true;
555   return CEED_ERROR_SUCCESS;
556 }
557 
558 /// @}
559 
560 /// ----------------------------------------------------------------------------
561 /// CeedOperator Public API
562 /// ----------------------------------------------------------------------------
563 /// @addtogroup CeedOperatorUser
564 /// @{
565 
566 /**
567   @brief Create a CeedOperator and associate a CeedQFunction.
568 
569   A CeedBasis and CeedElemRestriction can be associated with CeedQFunction fields with \ref CeedOperatorSetField.
570 
571   @param[in]  ceed Ceed object where the CeedOperator will be created
572   @param[in]  qf   QFunction defining the action of the operator at quadrature points
573   @param[in]  dqf  QFunction defining the action of the Jacobian of @a qf (or @ref CEED_QFUNCTION_NONE)
574   @param[in]  dqfT QFunction defining the action of the transpose of the Jacobian of @a qf (or @ref CEED_QFUNCTION_NONE)
575   @param[out] op   Address of the variable where the newly created CeedOperator will be stored
576 
577   @return An error code: 0 - success, otherwise - failure
578 
579   @ref User
580  */
581 int CeedOperatorCreate(Ceed ceed, CeedQFunction qf, CeedQFunction dqf, CeedQFunction dqfT, CeedOperator *op) {
582   if (!ceed->OperatorCreate) {
583     Ceed delegate;
584 
585     CeedCall(CeedGetObjectDelegate(ceed, &delegate, "Operator"));
586     CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support OperatorCreate");
587     CeedCall(CeedOperatorCreate(delegate, qf, dqf, dqfT, op));
588     return CEED_ERROR_SUCCESS;
589   }
590 
591   CeedCheck(qf && qf != CEED_QFUNCTION_NONE, ceed, CEED_ERROR_MINOR, "Operator must have a valid QFunction.");
592 
593   CeedCall(CeedCalloc(1, op));
594   CeedCall(CeedReferenceCopy(ceed, &(*op)->ceed));
595   (*op)->ref_count   = 1;
596   (*op)->input_size  = -1;
597   (*op)->output_size = -1;
598   CeedCall(CeedQFunctionReferenceCopy(qf, &(*op)->qf));
599   if (dqf && dqf != CEED_QFUNCTION_NONE) CeedCall(CeedQFunctionReferenceCopy(dqf, &(*op)->dqf));
600   if (dqfT && dqfT != CEED_QFUNCTION_NONE) CeedCall(CeedQFunctionReferenceCopy(dqfT, &(*op)->dqfT));
601   CeedCall(CeedQFunctionAssemblyDataCreate(ceed, &(*op)->qf_assembled));
602   CeedCall(CeedCalloc(CEED_FIELD_MAX, &(*op)->input_fields));
603   CeedCall(CeedCalloc(CEED_FIELD_MAX, &(*op)->output_fields));
604   CeedCall(ceed->OperatorCreate(*op));
605   return CEED_ERROR_SUCCESS;
606 }
607 
608 /**
609   @brief Create an operator that composes the action of several operators
610 
611   @param[in]  ceed Ceed object where the CeedOperator will be created
612   @param[out] op   Address of the variable where the newly created Composite CeedOperator will be stored
613 
614   @return An error code: 0 - success, otherwise - failure
615 
616   @ref User
617  */
618 int CeedCompositeOperatorCreate(Ceed ceed, CeedOperator *op) {
619   if (!ceed->CompositeOperatorCreate) {
620     Ceed delegate;
621 
622     CeedCall(CeedGetObjectDelegate(ceed, &delegate, "Operator"));
623     if (delegate) {
624       CeedCall(CeedCompositeOperatorCreate(delegate, op));
625       return CEED_ERROR_SUCCESS;
626     }
627   }
628 
629   CeedCall(CeedCalloc(1, op));
630   CeedCall(CeedReferenceCopy(ceed, &(*op)->ceed));
631   (*op)->ref_count    = 1;
632   (*op)->is_composite = true;
633   CeedCall(CeedCalloc(CEED_COMPOSITE_MAX, &(*op)->sub_operators));
634   (*op)->input_size  = -1;
635   (*op)->output_size = -1;
636 
637   if (ceed->CompositeOperatorCreate) CeedCall(ceed->CompositeOperatorCreate(*op));
638   return CEED_ERROR_SUCCESS;
639 }
640 
641 /**
642   @brief Copy the pointer to a CeedOperator.
643 
644   Both pointers should be destroyed with `CeedOperatorDestroy()`.
645 
646   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.
647         This CeedOperator will be destroyed if `op_copy` is the only reference to this CeedOperator.
648 
649   @param[in]  op         CeedOperator to copy reference to
650   @param[in,out] op_copy Variable to store copied reference
651 
652   @return An error code: 0 - success, otherwise - failure
653 
654   @ref User
655 **/
656 int CeedOperatorReferenceCopy(CeedOperator op, CeedOperator *op_copy) {
657   CeedCall(CeedOperatorReference(op));
658   CeedCall(CeedOperatorDestroy(op_copy));
659   *op_copy = op;
660   return CEED_ERROR_SUCCESS;
661 }
662 
663 /**
664   @brief Provide a field to a CeedOperator for use by its CeedQFunction.
665 
666   This function is used to specify both active and passive fields to a CeedOperator.
667   For passive fields, a vector @arg v must be provided.
668   Passive fields can inputs or outputs (updated in-place when operator is applied).
669 
670   Active fields must be specified using this function, but their data (in a CeedVector) is passed in CeedOperatorApply().
671   There can be at most one active input CeedVector and at most one active output CeedVector passed to CeedOperatorApply().
672 
673   The number of quadrature points must agree across all points.
674   When using @ref CEED_BASIS_NONE, the number of quadrature points is determined by the element size of r.
675 
676   @param[in,out] op         CeedOperator on which to provide the field
677   @param[in]     field_name Name of the field (to be matched with the name used by CeedQFunction)
678   @param[in]     r          CeedElemRestriction
679   @param[in]     b          CeedBasis in which the field resides or @ref CEED_BASIS_NONE if collocated with quadrature points
680   @param[in]     v          CeedVector to be used by CeedOperator or @ref CEED_VECTOR_ACTIVE if field is active or @ref CEED_VECTOR_NONE
681                               if using @ref CEED_EVAL_WEIGHT in the QFunction
682 
683   @return An error code: 0 - success, otherwise - failure
684 
685   @ref User
686 **/
687 int CeedOperatorSetField(CeedOperator op, const char *field_name, CeedElemRestriction r, CeedBasis b, CeedVector v) {
688   bool               is_input = true;
689   CeedInt            num_elem = 0, num_qpts = 0;
690   CeedQFunctionField qf_field;
691   CeedOperatorField *op_field;
692 
693   CeedCheck(!op->is_composite, op->ceed, CEED_ERROR_INCOMPATIBLE, "Cannot add field to composite operator.");
694   CeedCheck(!op->is_immutable, op->ceed, CEED_ERROR_MAJOR, "Operator cannot be changed after set as immutable");
695   CeedCheck(r, op->ceed, CEED_ERROR_INCOMPATIBLE, "ElemRestriction r for field \"%s\" must be non-NULL.", field_name);
696   CeedCheck(b, op->ceed, CEED_ERROR_INCOMPATIBLE, "Basis b for field \"%s\" must be non-NULL.", field_name);
697   CeedCheck(v, op->ceed, CEED_ERROR_INCOMPATIBLE, "Vector v for field \"%s\" must be non-NULL.", field_name);
698 
699   CeedCall(CeedElemRestrictionGetNumElements(r, &num_elem));
700   CeedCheck(r == CEED_ELEMRESTRICTION_NONE || !op->has_restriction || op->num_elem == num_elem, op->ceed, CEED_ERROR_DIMENSION,
701             "ElemRestriction with %" CeedInt_FMT " elements incompatible with prior %" CeedInt_FMT " elements", num_elem, op->num_elem);
702   {
703     CeedRestrictionType rstr_type;
704 
705     CeedCall(CeedElemRestrictionGetType(r, &rstr_type));
706     CeedCheck(rstr_type != CEED_RESTRICTION_POINTS, op->ceed, CEED_ERROR_UNSUPPORTED,
707               "CeedElemRestrictionAtPoints not supported for standard operator fields");
708   }
709 
710   if (b == CEED_BASIS_NONE) CeedCall(CeedElemRestrictionGetElementSize(r, &num_qpts));
711   else CeedCall(CeedBasisGetNumQuadraturePoints(b, &num_qpts));
712   CeedCheck(op->num_qpts == 0 || op->num_qpts == num_qpts, op->ceed, CEED_ERROR_DIMENSION,
713             "%s must correspond to the same number of quadrature points as previously added Bases. Found %" CeedInt_FMT
714             " quadrature points but expected %" CeedInt_FMT " quadrature points.",
715             b == CEED_BASIS_NONE ? "ElemRestriction" : "Basis", num_qpts, op->num_qpts);
716   for (CeedInt i = 0; i < op->qf->num_input_fields; i++) {
717     if (!strcmp(field_name, (*op->qf->input_fields[i]).field_name)) {
718       qf_field = op->qf->input_fields[i];
719       op_field = &op->input_fields[i];
720       goto found;
721     }
722   }
723   is_input = false;
724   for (CeedInt i = 0; i < op->qf->num_output_fields; i++) {
725     if (!strcmp(field_name, (*op->qf->output_fields[i]).field_name)) {
726       qf_field = op->qf->output_fields[i];
727       op_field = &op->output_fields[i];
728       goto found;
729     }
730   }
731   // LCOV_EXCL_START
732   return CeedError(op->ceed, CEED_ERROR_INCOMPLETE, "QFunction has no knowledge of field '%s'", field_name);
733   // LCOV_EXCL_STOP
734 found:
735   CeedCall(CeedOperatorCheckField(op->ceed, qf_field, r, b));
736   CeedCall(CeedCalloc(1, op_field));
737 
738   if (v == CEED_VECTOR_ACTIVE) {
739     CeedSize l_size;
740 
741     CeedCall(CeedElemRestrictionGetLVectorSize(r, &l_size));
742     if (is_input) {
743       if (op->input_size == -1) op->input_size = l_size;
744       CeedCheck(l_size == op->input_size, op->ceed, CEED_ERROR_INCOMPATIBLE, "LVector size %td does not match previous size %td", l_size,
745                 op->input_size);
746     } else {
747       if (op->output_size == -1) op->output_size = l_size;
748       CeedCheck(l_size == op->output_size, op->ceed, CEED_ERROR_INCOMPATIBLE, "LVector size %td does not match previous size %td", l_size,
749                 op->output_size);
750     }
751   }
752 
753   CeedCall(CeedVectorReferenceCopy(v, &(*op_field)->vec));
754   CeedCall(CeedElemRestrictionReferenceCopy(r, &(*op_field)->elem_rstr));
755   if (r != CEED_ELEMRESTRICTION_NONE) {
756     op->num_elem        = num_elem;
757     op->has_restriction = true;  // Restriction set, but num_elem may be 0
758   }
759   CeedCall(CeedBasisReferenceCopy(b, &(*op_field)->basis));
760   if (op->num_qpts == 0) CeedCall(CeedOperatorSetNumQuadraturePoints(op, num_qpts));
761 
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 the number of quadrature points associated with a CeedOperator.
1102 
1103   This should be used when creating a CeedOperator where every field has a collocated basis.
1104   This function cannot be used for composite CeedOperators.
1105 
1106   @param[in,out] op       CeedOperator
1107   @param[in]     num_qpts Number of quadrature points to set
1108 
1109   @return An error code: 0 - success, otherwise - failure
1110 
1111   @ref Advanced
1112 **/
1113 int CeedOperatorSetNumQuadraturePoints(CeedOperator op, CeedInt num_qpts) {
1114   CeedCheck(!op->is_composite, op->ceed, CEED_ERROR_MINOR, "Not defined for composite CeedOperator");
1115   CeedCheck(!op->is_immutable, op->ceed, CEED_ERROR_MAJOR, "Operator cannot be changed after set as immutable");
1116   if (op->num_qpts > 0) {
1117     CeedWarn(
1118         "CeedOperatorSetNumQuadraturePoints will be removed from the libCEED interface in the next release.\n"
1119         "This function is redundant and you can safely remove any calls to this function without replacing them.");
1120     CeedCheck(num_qpts == op->num_qpts, op->ceed, CEED_ERROR_DIMENSION, "Different number of quadrature points already defined for the CeedOperator");
1121   }
1122   op->num_qpts = num_qpts;
1123   return CEED_ERROR_SUCCESS;
1124 }
1125 
1126 /**
1127   @brief Set name of CeedOperator for CeedOperatorView output
1128 
1129   @param[in,out] op   CeedOperator
1130   @param[in]     name Name to set, or NULL to remove previously set name
1131 
1132   @return An error code: 0 - success, otherwise - failure
1133 
1134   @ref User
1135 **/
1136 int CeedOperatorSetName(CeedOperator op, const char *name) {
1137   char  *name_copy;
1138   size_t name_len = name ? strlen(name) : 0;
1139 
1140   CeedCall(CeedFree(&op->name));
1141   if (name_len > 0) {
1142     CeedCall(CeedCalloc(name_len + 1, &name_copy));
1143     memcpy(name_copy, name, name_len);
1144     op->name = name_copy;
1145   }
1146   return CEED_ERROR_SUCCESS;
1147 }
1148 
1149 /**
1150   @brief View a CeedOperator
1151 
1152   @param[in] op     CeedOperator to view
1153   @param[in] stream Stream to write; typically stdout/stderr or a file
1154 
1155   @return Error code: 0 - success, otherwise - failure
1156 
1157   @ref User
1158 **/
1159 int CeedOperatorView(CeedOperator op, FILE *stream) {
1160   bool has_name = op->name;
1161 
1162   if (op->is_composite) {
1163     fprintf(stream, "Composite CeedOperator%s%s\n", has_name ? " - " : "", has_name ? op->name : "");
1164 
1165     for (CeedInt i = 0; i < op->num_suboperators; i++) {
1166       has_name = op->sub_operators[i]->name;
1167       fprintf(stream, "  SubOperator %" CeedInt_FMT "%s%s:\n", i, has_name ? " - " : "", has_name ? op->sub_operators[i]->name : "");
1168       CeedCall(CeedOperatorSingleView(op->sub_operators[i], 1, stream));
1169     }
1170   } else {
1171     fprintf(stream, "CeedOperator%s%s\n", has_name ? " - " : "", has_name ? op->name : "");
1172     CeedCall(CeedOperatorSingleView(op, 0, stream));
1173   }
1174   return CEED_ERROR_SUCCESS;
1175 }
1176 
1177 /**
1178   @brief Get the Ceed associated with a CeedOperator
1179 
1180   @param[in]  op   CeedOperator
1181   @param[out] ceed Variable to store Ceed
1182 
1183   @return An error code: 0 - success, otherwise - failure
1184 
1185   @ref Advanced
1186 **/
1187 int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) {
1188   *ceed = op->ceed;
1189   return CEED_ERROR_SUCCESS;
1190 }
1191 
1192 /**
1193   @brief Get the number of elements associated with a CeedOperator
1194 
1195   @param[in]  op       CeedOperator
1196   @param[out] num_elem Variable to store number of elements
1197 
1198   @return An error code: 0 - success, otherwise - failure
1199 
1200   @ref Advanced
1201 **/
1202 int CeedOperatorGetNumElements(CeedOperator op, CeedInt *num_elem) {
1203   CeedCheck(!op->is_composite, op->ceed, CEED_ERROR_MINOR, "Not defined for composite operator");
1204   *num_elem = op->num_elem;
1205   return CEED_ERROR_SUCCESS;
1206 }
1207 
1208 /**
1209   @brief Get the number of quadrature points associated with a CeedOperator
1210 
1211   @param[in]  op       CeedOperator
1212   @param[out] num_qpts Variable to store vector number of quadrature points
1213 
1214   @return An error code: 0 - success, otherwise - failure
1215 
1216   @ref Advanced
1217 **/
1218 int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *num_qpts) {
1219   CeedCheck(!op->is_composite, op->ceed, CEED_ERROR_MINOR, "Not defined for composite operator");
1220   *num_qpts = op->num_qpts;
1221   return CEED_ERROR_SUCCESS;
1222 }
1223 
1224 /**
1225   @brief Estimate number of FLOPs required to apply CeedOperator on the active vector
1226 
1227   @param[in]  op    CeedOperator to estimate FLOPs for
1228   @param[out] flops Address of variable to hold FLOPs estimate
1229 
1230   @ref Backend
1231 **/
1232 int CeedOperatorGetFlopsEstimate(CeedOperator op, CeedSize *flops) {
1233   bool is_composite;
1234 
1235   CeedCall(CeedOperatorCheckReady(op));
1236 
1237   *flops = 0;
1238   CeedCall(CeedOperatorIsComposite(op, &is_composite));
1239   if (is_composite) {
1240     CeedInt num_suboperators;
1241 
1242     CeedCall(CeedCompositeOperatorGetNumSub(op, &num_suboperators));
1243     CeedOperator *sub_operators;
1244     CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators));
1245 
1246     // FLOPs for each suboperator
1247     for (CeedInt i = 0; i < num_suboperators; i++) {
1248       CeedSize suboperator_flops;
1249 
1250       CeedCall(CeedOperatorGetFlopsEstimate(sub_operators[i], &suboperator_flops));
1251       *flops += suboperator_flops;
1252     }
1253   } else {
1254     CeedInt            num_input_fields, num_output_fields, num_elem = 0;
1255     CeedOperatorField *input_fields, *output_fields;
1256 
1257     CeedCall(CeedOperatorGetFields(op, &num_input_fields, &input_fields, &num_output_fields, &output_fields));
1258     CeedCall(CeedOperatorGetNumElements(op, &num_elem));
1259 
1260     // Input FLOPs
1261     for (CeedInt i = 0; i < num_input_fields; i++) {
1262       if (input_fields[i]->vec == CEED_VECTOR_ACTIVE) {
1263         CeedSize rstr_flops, basis_flops;
1264 
1265         CeedCall(CeedElemRestrictionGetFlopsEstimate(input_fields[i]->elem_rstr, CEED_NOTRANSPOSE, &rstr_flops));
1266         *flops += rstr_flops;
1267         CeedCall(CeedBasisGetFlopsEstimate(input_fields[i]->basis, CEED_NOTRANSPOSE, op->qf->input_fields[i]->eval_mode, &basis_flops));
1268         *flops += basis_flops * num_elem;
1269       }
1270     }
1271     // QF FLOPs
1272     {
1273       CeedInt  num_qpts;
1274       CeedSize qf_flops;
1275 
1276       CeedCall(CeedOperatorGetNumQuadraturePoints(op, &num_qpts));
1277       CeedCall(CeedQFunctionGetFlopsEstimate(op->qf, &qf_flops));
1278       *flops += num_elem * num_qpts * qf_flops;
1279     }
1280 
1281     // Output FLOPs
1282     for (CeedInt i = 0; i < num_output_fields; i++) {
1283       if (output_fields[i]->vec == CEED_VECTOR_ACTIVE) {
1284         CeedSize rstr_flops, basis_flops;
1285 
1286         CeedCall(CeedElemRestrictionGetFlopsEstimate(output_fields[i]->elem_rstr, CEED_TRANSPOSE, &rstr_flops));
1287         *flops += rstr_flops;
1288         CeedCall(CeedBasisGetFlopsEstimate(output_fields[i]->basis, CEED_TRANSPOSE, op->qf->output_fields[i]->eval_mode, &basis_flops));
1289         *flops += basis_flops * num_elem;
1290       }
1291     }
1292   }
1293   return CEED_ERROR_SUCCESS;
1294 }
1295 
1296 /**
1297   @brief Get CeedQFunction global context for a CeedOperator.
1298 
1299   The caller is responsible for destroying `ctx` returned from this function via `CeedQFunctionContextDestroy()`.
1300 
1301   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.
1302         This CeedQFunctionContext will be destroyed if `ctx` is the only reference to this CeedQFunctionContext.
1303 
1304   @param[in]  op  CeedOperator
1305   @param[out] ctx Variable to store CeedQFunctionContext
1306 
1307   @return An error code: 0 - success, otherwise - failure
1308 
1309   @ref Advanced
1310 **/
1311 int CeedOperatorGetContext(CeedOperator op, CeedQFunctionContext *ctx) {
1312   CeedCheck(!op->is_composite, op->ceed, CEED_ERROR_INCOMPATIBLE, "Cannot retrieve QFunctionContext for composite operator");
1313   if (op->qf->ctx) CeedCall(CeedQFunctionContextReferenceCopy(op->qf->ctx, ctx));
1314   else *ctx = NULL;
1315   return CEED_ERROR_SUCCESS;
1316 }
1317 
1318 /**
1319   @brief Get label for a registered QFunctionContext field, or `NULL` if no field has been registered with this `field_name`.
1320 
1321   Fields are registered via `CeedQFunctionContextRegister*()` functions (eg. `CeedQFunctionContextRegisterDouble()`).
1322 
1323   @param[in]  op          CeedOperator
1324   @param[in]  field_name  Name of field to retrieve label
1325   @param[out] field_label Variable to field label
1326 
1327   @return An error code: 0 - success, otherwise - failure
1328 
1329   @ref User
1330 **/
1331 int CeedOperatorGetContextFieldLabel(CeedOperator op, const char *field_name, CeedContextFieldLabel *field_label) {
1332   bool is_composite, field_found = false;
1333 
1334   CeedCall(CeedOperatorIsComposite(op, &is_composite));
1335 
1336   if (is_composite) {
1337     // Composite operator
1338     // -- Check if composite label already created
1339     for (CeedInt i = 0; i < op->num_context_labels; i++) {
1340       if (!strcmp(op->context_labels[i]->name, field_name)) {
1341         *field_label = op->context_labels[i];
1342         return CEED_ERROR_SUCCESS;
1343       }
1344     }
1345 
1346     // -- Create composite label if needed
1347     CeedInt               num_sub;
1348     CeedOperator         *sub_operators;
1349     CeedContextFieldLabel new_field_label;
1350 
1351     CeedCall(CeedCalloc(1, &new_field_label));
1352     CeedCall(CeedCompositeOperatorGetNumSub(op, &num_sub));
1353     CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators));
1354     CeedCall(CeedCalloc(num_sub, &new_field_label->sub_labels));
1355     new_field_label->num_sub_labels = num_sub;
1356 
1357     for (CeedInt i = 0; i < num_sub; i++) {
1358       if (sub_operators[i]->qf->ctx) {
1359         CeedContextFieldLabel new_field_label_i;
1360 
1361         CeedCall(CeedQFunctionContextGetFieldLabel(sub_operators[i]->qf->ctx, field_name, &new_field_label_i));
1362         if (new_field_label_i) {
1363           field_found                    = true;
1364           new_field_label->sub_labels[i] = new_field_label_i;
1365           new_field_label->name          = new_field_label_i->name;
1366           new_field_label->description   = new_field_label_i->description;
1367           if (new_field_label->type && new_field_label->type != new_field_label_i->type) {
1368             // LCOV_EXCL_START
1369             CeedCall(CeedFree(&new_field_label));
1370             return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, "Incompatible field types on sub-operator contexts. %s != %s",
1371                              CeedContextFieldTypes[new_field_label->type], CeedContextFieldTypes[new_field_label_i->type]);
1372             // LCOV_EXCL_STOP
1373           } else {
1374             new_field_label->type = new_field_label_i->type;
1375           }
1376           if (new_field_label->num_values != 0 && new_field_label->num_values != new_field_label_i->num_values) {
1377             // LCOV_EXCL_START
1378             CeedCall(CeedFree(&new_field_label));
1379             return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, "Incompatible field number of values on sub-operator contexts. %ld != %ld",
1380                              new_field_label->num_values, new_field_label_i->num_values);
1381             // LCOV_EXCL_STOP
1382           } else {
1383             new_field_label->num_values = new_field_label_i->num_values;
1384           }
1385         }
1386       }
1387     }
1388     // -- Cleanup if field was found
1389     if (field_found) {
1390       *field_label = new_field_label;
1391     } else {
1392       // LCOV_EXCL_START
1393       CeedCall(CeedFree(&new_field_label->sub_labels));
1394       CeedCall(CeedFree(&new_field_label));
1395       *field_label = NULL;
1396       // LCOV_EXCL_STOP
1397     }
1398   } else {
1399     // Single, non-composite operator
1400     if (op->qf->ctx) {
1401       CeedCall(CeedQFunctionContextGetFieldLabel(op->qf->ctx, field_name, field_label));
1402     } else {
1403       *field_label = NULL;
1404     }
1405   }
1406 
1407   // Set label in operator
1408   if (*field_label) {
1409     (*field_label)->from_op = true;
1410 
1411     // Move new composite label to operator
1412     if (op->num_context_labels == 0) {
1413       CeedCall(CeedCalloc(1, &op->context_labels));
1414       op->max_context_labels = 1;
1415     } else if (op->num_context_labels == op->max_context_labels) {
1416       CeedCall(CeedRealloc(2 * op->num_context_labels, &op->context_labels));
1417       op->max_context_labels *= 2;
1418     }
1419     op->context_labels[op->num_context_labels] = *field_label;
1420     op->num_context_labels++;
1421   }
1422   return CEED_ERROR_SUCCESS;
1423 }
1424 
1425 /**
1426   @brief Set QFunctionContext field holding double precision values.
1427 
1428   For composite operators, the values are set in all sub-operator QFunctionContexts that have a matching `field_name`.
1429 
1430   @param[in,out] op          CeedOperator
1431   @param[in]     field_label Label of field to set
1432   @param[in]     values      Values to set
1433 
1434   @return An error code: 0 - success, otherwise - failure
1435 
1436   @ref User
1437 **/
1438 int CeedOperatorSetContextDouble(CeedOperator op, CeedContextFieldLabel field_label, double *values) {
1439   return CeedOperatorContextSetGeneric(op, field_label, CEED_CONTEXT_FIELD_DOUBLE, values);
1440 }
1441 
1442 /**
1443   @brief Get QFunctionContext field holding double precision values, read-only.
1444 
1445   For composite operators, the values correspond to the first sub-operator QFunctionContexts that has a matching `field_name`.
1446 
1447   @param[in]  op          CeedOperator
1448   @param[in]  field_label Label of field to get
1449   @param[out] num_values  Number of values in the field label
1450   @param[out] values      Pointer to context values
1451 
1452   @return An error code: 0 - success, otherwise - failure
1453 
1454   @ref User
1455 **/
1456 int CeedOperatorGetContextDoubleRead(CeedOperator op, CeedContextFieldLabel field_label, size_t *num_values, const double **values) {
1457   return CeedOperatorContextGetGenericRead(op, field_label, CEED_CONTEXT_FIELD_DOUBLE, num_values, values);
1458 }
1459 
1460 /**
1461   @brief Restore QFunctionContext field holding double precision values, read-only.
1462 
1463   @param[in]  op          CeedOperator
1464   @param[in]  field_label Label of field to restore
1465   @param[out] values      Pointer to context values
1466 
1467   @return An error code: 0 - success, otherwise - failure
1468 
1469   @ref User
1470 **/
1471 int CeedOperatorRestoreContextDoubleRead(CeedOperator op, CeedContextFieldLabel field_label, const double **values) {
1472   return CeedOperatorContextRestoreGenericRead(op, field_label, CEED_CONTEXT_FIELD_DOUBLE, values);
1473 }
1474 
1475 /**
1476   @brief Set QFunctionContext field holding int32 values.
1477 
1478   For composite operators, the values are set in all sub-operator QFunctionContexts that have a matching `field_name`.
1479 
1480   @param[in,out] op          CeedOperator
1481   @param[in]     field_label Label of field to set
1482   @param[in]     values      Values to set
1483 
1484   @return An error code: 0 - success, otherwise - failure
1485 
1486   @ref User
1487 **/
1488 int CeedOperatorSetContextInt32(CeedOperator op, CeedContextFieldLabel field_label, int *values) {
1489   return CeedOperatorContextSetGeneric(op, field_label, CEED_CONTEXT_FIELD_INT32, values);
1490 }
1491 
1492 /**
1493   @brief Get QFunctionContext field holding int32 values, read-only.
1494 
1495   For composite operators, the values correspond to the first sub-operator QFunctionContexts that has a matching `field_name`.
1496 
1497   @param[in]  op          CeedOperator
1498   @param[in]  field_label Label of field to get
1499   @param[out] num_values  Number of int32 values in `values`
1500   @param[out] values      Pointer to context values
1501 
1502   @return An error code: 0 - success, otherwise - failure
1503 
1504   @ref User
1505 **/
1506 int CeedOperatorGetContextInt32Read(CeedOperator op, CeedContextFieldLabel field_label, size_t *num_values, const int **values) {
1507   return CeedOperatorContextGetGenericRead(op, field_label, CEED_CONTEXT_FIELD_INT32, num_values, values);
1508 }
1509 
1510 /**
1511   @brief Restore QFunctionContext field holding int32 values, read-only.
1512 
1513   @param[in]  op          CeedOperator
1514   @param[in]  field_label Label of field to get
1515   @param[out] values      Pointer to context values
1516 
1517   @return An error code: 0 - success, otherwise - failure
1518 
1519   @ref User
1520 **/
1521 int CeedOperatorRestoreContextInt32Read(CeedOperator op, CeedContextFieldLabel field_label, const int **values) {
1522   return CeedOperatorContextRestoreGenericRead(op, field_label, CEED_CONTEXT_FIELD_INT32, values);
1523 }
1524 
1525 /**
1526   @brief Apply CeedOperator to a vector
1527 
1528   This computes the action of the operator on the specified (active) input, yielding its (active) output.
1529   All inputs and outputs must be specified using CeedOperatorSetField().
1530 
1531   Note: Calling this function asserts that setup is complete and sets the CeedOperator as immutable.
1532 
1533   @param[in]  op      CeedOperator to apply
1534   @param[in]  in      CeedVector containing input state or @ref CEED_VECTOR_NONE if there are no active inputs
1535   @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
1536 active outputs
1537   @param[in]  request Address of CeedRequest for non-blocking completion, else @ref CEED_REQUEST_IMMEDIATE
1538 
1539   @return An error code: 0 - success, otherwise - failure
1540 
1541   @ref User
1542 **/
1543 int CeedOperatorApply(CeedOperator op, CeedVector in, CeedVector out, CeedRequest *request) {
1544   CeedCall(CeedOperatorCheckReady(op));
1545 
1546   if (op->is_composite) {
1547     // Composite Operator
1548     if (op->ApplyComposite) {
1549       CeedCall(op->ApplyComposite(op, in, out, request));
1550     } else {
1551       CeedInt       num_suboperators;
1552       CeedOperator *sub_operators;
1553 
1554       CeedCall(CeedCompositeOperatorGetNumSub(op, &num_suboperators));
1555       CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators));
1556 
1557       // Zero all output vectors
1558       if (out != CEED_VECTOR_NONE) CeedCall(CeedVectorSetValue(out, 0.0));
1559       for (CeedInt i = 0; i < num_suboperators; i++) {
1560         for (CeedInt j = 0; j < sub_operators[i]->qf->num_output_fields; j++) {
1561           CeedVector vec = sub_operators[i]->output_fields[j]->vec;
1562 
1563           if (vec != CEED_VECTOR_ACTIVE && vec != CEED_VECTOR_NONE) {
1564             CeedCall(CeedVectorSetValue(vec, 0.0));
1565           }
1566         }
1567       }
1568       // Apply
1569       for (CeedInt i = 0; i < num_suboperators; i++) {
1570         CeedCall(CeedOperatorApplyAdd(sub_operators[i], in, out, request));
1571       }
1572     }
1573   } else {
1574     // Standard Operator
1575     if (op->Apply) {
1576       CeedCall(op->Apply(op, in, out, request));
1577     } else {
1578       // Zero all output vectors
1579       CeedQFunction qf = op->qf;
1580 
1581       for (CeedInt i = 0; i < qf->num_output_fields; i++) {
1582         CeedVector vec = op->output_fields[i]->vec;
1583 
1584         if (vec == CEED_VECTOR_ACTIVE) vec = out;
1585         if (vec != CEED_VECTOR_NONE) CeedCall(CeedVectorSetValue(vec, 0.0));
1586       }
1587       // Apply
1588       if (op->num_elem) CeedCall(op->ApplyAdd(op, in, out, request));
1589     }
1590   }
1591   return CEED_ERROR_SUCCESS;
1592 }
1593 
1594 /**
1595   @brief Apply CeedOperator to a vector and add result to output vector
1596 
1597   This computes the action of the operator on the specified (active) input, yielding its (active) output.
1598   All inputs and outputs must be specified using CeedOperatorSetField().
1599 
1600   @param[in]  op      CeedOperator to apply
1601   @param[in]  in      CeedVector containing input state or NULL if there are no active inputs
1602   @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
1603   @param[in]  request Address of CeedRequest for non-blocking completion, else @ref CEED_REQUEST_IMMEDIATE
1604 
1605   @return An error code: 0 - success, otherwise - failure
1606 
1607   @ref User
1608 **/
1609 int CeedOperatorApplyAdd(CeedOperator op, CeedVector in, CeedVector out, CeedRequest *request) {
1610   CeedCall(CeedOperatorCheckReady(op));
1611 
1612   if (op->is_composite) {
1613     // Composite Operator
1614     if (op->ApplyAddComposite) {
1615       CeedCall(op->ApplyAddComposite(op, in, out, request));
1616     } else {
1617       CeedInt       num_suboperators;
1618       CeedOperator *sub_operators;
1619 
1620       CeedCall(CeedCompositeOperatorGetNumSub(op, &num_suboperators));
1621       CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators));
1622       for (CeedInt i = 0; i < num_suboperators; i++) {
1623         CeedCall(CeedOperatorApplyAdd(sub_operators[i], in, out, request));
1624       }
1625     }
1626   } else if (op->num_elem) {
1627     // Standard Operator
1628     CeedCall(op->ApplyAdd(op, in, out, request));
1629   }
1630   return CEED_ERROR_SUCCESS;
1631 }
1632 
1633 /**
1634   @brief Destroy a CeedOperator
1635 
1636   @param[in,out] op CeedOperator to destroy
1637 
1638   @return An error code: 0 - success, otherwise - failure
1639 
1640   @ref User
1641 **/
1642 int CeedOperatorDestroy(CeedOperator *op) {
1643   if (!*op || --(*op)->ref_count > 0) {
1644     *op = NULL;
1645     return CEED_ERROR_SUCCESS;
1646   }
1647   if ((*op)->Destroy) CeedCall((*op)->Destroy(*op));
1648   CeedCall(CeedDestroy(&(*op)->ceed));
1649   // Free fields
1650   for (CeedInt i = 0; i < (*op)->num_fields; i++) {
1651     if ((*op)->input_fields[i]) {
1652       if ((*op)->input_fields[i]->elem_rstr != CEED_ELEMRESTRICTION_NONE) {
1653         CeedCall(CeedElemRestrictionDestroy(&(*op)->input_fields[i]->elem_rstr));
1654       }
1655       if ((*op)->input_fields[i]->basis != CEED_BASIS_NONE) {
1656         CeedCall(CeedBasisDestroy(&(*op)->input_fields[i]->basis));
1657       }
1658       if ((*op)->input_fields[i]->vec != CEED_VECTOR_ACTIVE && (*op)->input_fields[i]->vec != CEED_VECTOR_NONE) {
1659         CeedCall(CeedVectorDestroy(&(*op)->input_fields[i]->vec));
1660       }
1661       CeedCall(CeedFree(&(*op)->input_fields[i]->field_name));
1662       CeedCall(CeedFree(&(*op)->input_fields[i]));
1663     }
1664   }
1665   for (CeedInt i = 0; i < (*op)->num_fields; i++) {
1666     if ((*op)->output_fields[i]) {
1667       CeedCall(CeedElemRestrictionDestroy(&(*op)->output_fields[i]->elem_rstr));
1668       if ((*op)->output_fields[i]->basis != CEED_BASIS_NONE) {
1669         CeedCall(CeedBasisDestroy(&(*op)->output_fields[i]->basis));
1670       }
1671       if ((*op)->output_fields[i]->vec != CEED_VECTOR_ACTIVE && (*op)->output_fields[i]->vec != CEED_VECTOR_NONE) {
1672         CeedCall(CeedVectorDestroy(&(*op)->output_fields[i]->vec));
1673       }
1674       CeedCall(CeedFree(&(*op)->output_fields[i]->field_name));
1675       CeedCall(CeedFree(&(*op)->output_fields[i]));
1676     }
1677   }
1678   // Destroy sub_operators
1679   for (CeedInt i = 0; i < (*op)->num_suboperators; i++) {
1680     if ((*op)->sub_operators[i]) {
1681       CeedCall(CeedOperatorDestroy(&(*op)->sub_operators[i]));
1682     }
1683   }
1684   CeedCall(CeedQFunctionDestroy(&(*op)->qf));
1685   CeedCall(CeedQFunctionDestroy(&(*op)->dqf));
1686   CeedCall(CeedQFunctionDestroy(&(*op)->dqfT));
1687   // Destroy any composite labels
1688   if ((*op)->is_composite) {
1689     for (CeedInt i = 0; i < (*op)->num_context_labels; i++) {
1690       CeedCall(CeedFree(&(*op)->context_labels[i]->sub_labels));
1691       CeedCall(CeedFree(&(*op)->context_labels[i]));
1692     }
1693   }
1694   CeedCall(CeedFree(&(*op)->context_labels));
1695 
1696   // Destroy fallback
1697   CeedCall(CeedOperatorDestroy(&(*op)->op_fallback));
1698 
1699   // Destroy assembly data
1700   CeedCall(CeedQFunctionAssemblyDataDestroy(&(*op)->qf_assembled));
1701   CeedCall(CeedOperatorAssemblyDataDestroy(&(*op)->op_assembled));
1702 
1703   CeedCall(CeedFree(&(*op)->input_fields));
1704   CeedCall(CeedFree(&(*op)->output_fields));
1705   CeedCall(CeedFree(&(*op)->sub_operators));
1706   CeedCall(CeedFree(&(*op)->name));
1707   CeedCall(CeedFree(op));
1708   return CEED_ERROR_SUCCESS;
1709 }
1710 
1711 /// @}
1712