xref: /libCEED/interface/ceed-operator.c (revision 92ae7e4738abdc83aced3d16a73cf4ec08460821)
13d8e8822SJeremy L Thompson // Copyright (c) 2017-2022, Lawrence Livermore National Security, LLC and other CEED contributors.
23d8e8822SJeremy L Thompson // All Rights Reserved. See the top-level LICENSE and NOTICE files for details.
3d7b241e6Sjeremylt //
43d8e8822SJeremy L Thompson // SPDX-License-Identifier: BSD-2-Clause
5d7b241e6Sjeremylt //
63d8e8822SJeremy L Thompson // This file is part of CEED:  http://github.com/ceed
7d7b241e6Sjeremylt 
8ec3da8bcSJed Brown #include <ceed/ceed.h>
9ec3da8bcSJed Brown #include <ceed/backend.h>
103d576824SJeremy L Thompson #include <ceed-impl.h>
113d576824SJeremy L Thompson #include <stdbool.h>
123d576824SJeremy L Thompson #include <stdio.h>
133d576824SJeremy L Thompson #include <string.h>
14d7b241e6Sjeremylt 
15dfdf5a53Sjeremylt /// @file
167a982d89SJeremy L. Thompson /// Implementation of CeedOperator interfaces
177a982d89SJeremy L. Thompson 
187a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
197a982d89SJeremy L. Thompson /// CeedOperator Library Internal Functions
207a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
217a982d89SJeremy L. Thompson /// @addtogroup CeedOperatorDeveloper
227a982d89SJeremy L. Thompson /// @{
237a982d89SJeremy L. Thompson 
247a982d89SJeremy L. Thompson /**
25e15f9bd0SJeremy L Thompson   @brief Check if a CeedOperator Field matches the QFunction Field
26e15f9bd0SJeremy L Thompson 
27e15f9bd0SJeremy L Thompson   @param[in] ceed      Ceed object for error handling
28d1d35e2fSjeremylt   @param[in] qf_field  QFunction Field matching Operator Field
29e15f9bd0SJeremy L Thompson   @param[in] r         Operator Field ElemRestriction
30e15f9bd0SJeremy L Thompson   @param[in] b         Operator Field Basis
31e15f9bd0SJeremy L Thompson 
32e15f9bd0SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
33e15f9bd0SJeremy L Thompson 
34e15f9bd0SJeremy L Thompson   @ref Developer
35e15f9bd0SJeremy L Thompson **/
36d1d35e2fSjeremylt static int CeedOperatorCheckField(Ceed ceed, CeedQFunctionField qf_field,
37e15f9bd0SJeremy L Thompson                                   CeedElemRestriction r, CeedBasis b) {
38e15f9bd0SJeremy L Thompson   int ierr;
39d1d35e2fSjeremylt   CeedEvalMode eval_mode = qf_field->eval_mode;
40d1d35e2fSjeremylt   CeedInt dim = 1, num_comp = 1, restr_num_comp = 1, size = qf_field->size;
41e15f9bd0SJeremy L Thompson   // Restriction
42e15f9bd0SJeremy L Thompson   if (r != CEED_ELEMRESTRICTION_NONE) {
43d1d35e2fSjeremylt     if (eval_mode == CEED_EVAL_WEIGHT) {
44e15f9bd0SJeremy L Thompson       // LCOV_EXCL_START
45e1e9e29dSJed Brown       return CeedError(ceed, CEED_ERROR_INCOMPATIBLE,
46e1e9e29dSJed Brown                        "CEED_ELEMRESTRICTION_NONE should be used "
47e15f9bd0SJeremy L Thompson                        "for a field with eval mode CEED_EVAL_WEIGHT");
48e15f9bd0SJeremy L Thompson       // LCOV_EXCL_STOP
49e15f9bd0SJeremy L Thompson     }
50d1d35e2fSjeremylt     ierr = CeedElemRestrictionGetNumComponents(r, &restr_num_comp);
5178464608Sjeremylt     CeedChk(ierr);
52e1e9e29dSJed Brown   }
53d1d35e2fSjeremylt   if ((r == CEED_ELEMRESTRICTION_NONE) != (eval_mode == CEED_EVAL_WEIGHT)) {
54e1e9e29dSJed Brown     // LCOV_EXCL_START
55e1e9e29dSJed Brown     return CeedError(ceed, CEED_ERROR_INCOMPATIBLE,
56e1e9e29dSJed Brown                      "CEED_ELEMRESTRICTION_NONE and CEED_EVAL_WEIGHT "
57e1e9e29dSJed Brown                      "must be used together.");
58e1e9e29dSJed Brown     // LCOV_EXCL_STOP
59e1e9e29dSJed Brown   }
60e15f9bd0SJeremy L Thompson   // Basis
61e15f9bd0SJeremy L Thompson   if (b != CEED_BASIS_COLLOCATED) {
62d1d35e2fSjeremylt     if (eval_mode == CEED_EVAL_NONE)
638229195eSjeremylt       // LCOV_EXCL_START
64e1e9e29dSJed Brown       return CeedError(ceed, CEED_ERROR_INCOMPATIBLE,
65d1d35e2fSjeremylt                        "Field '%s' configured with CEED_EVAL_NONE must "
66d1d35e2fSjeremylt                        "be used with CEED_BASIS_COLLOCATED",
678229195eSjeremylt                        // LCOV_EXCL_STOP
68d1d35e2fSjeremylt                        qf_field->field_name);
69e15f9bd0SJeremy L Thompson     ierr = CeedBasisGetDimension(b, &dim); CeedChk(ierr);
70d1d35e2fSjeremylt     ierr = CeedBasisGetNumComponents(b, &num_comp); CeedChk(ierr);
71d1d35e2fSjeremylt     if (r != CEED_ELEMRESTRICTION_NONE && restr_num_comp != num_comp) {
72e15f9bd0SJeremy L Thompson       // LCOV_EXCL_START
73e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_DIMENSION,
74d1d35e2fSjeremylt                        "Field '%s' of size %d and EvalMode %s: ElemRestriction "
75d1d35e2fSjeremylt                        "has %d components, but Basis has %d components",
76d1d35e2fSjeremylt                        qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode],
77d1d35e2fSjeremylt                        restr_num_comp,
78d1d35e2fSjeremylt                        num_comp);
79e15f9bd0SJeremy L Thompson       // LCOV_EXCL_STOP
80e15f9bd0SJeremy L Thompson     }
81e15f9bd0SJeremy L Thompson   }
82e15f9bd0SJeremy L Thompson   // Field size
83d1d35e2fSjeremylt   switch(eval_mode) {
84e15f9bd0SJeremy L Thompson   case CEED_EVAL_NONE:
85d1d35e2fSjeremylt     if (size != restr_num_comp)
86e15f9bd0SJeremy L Thompson       // LCOV_EXCL_START
87e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_DIMENSION,
88e1e9e29dSJed Brown                        "Field '%s' of size %d and EvalMode %s: ElemRestriction has %d components",
89d1d35e2fSjeremylt                        qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode],
90d1d35e2fSjeremylt                        restr_num_comp);
91e15f9bd0SJeremy L Thompson     // LCOV_EXCL_STOP
92e15f9bd0SJeremy L Thompson     break;
93e15f9bd0SJeremy L Thompson   case CEED_EVAL_INTERP:
94d1d35e2fSjeremylt     if (size != num_comp)
95e15f9bd0SJeremy L Thompson       // LCOV_EXCL_START
96e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_DIMENSION,
97e1e9e29dSJed Brown                        "Field '%s' of size %d and EvalMode %s: ElemRestriction/Basis has %d components",
98d1d35e2fSjeremylt                        qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode],
99d1d35e2fSjeremylt                        num_comp);
100e15f9bd0SJeremy L Thompson     // LCOV_EXCL_STOP
101e15f9bd0SJeremy L Thompson     break;
102e15f9bd0SJeremy L Thompson   case CEED_EVAL_GRAD:
103d1d35e2fSjeremylt     if (size != num_comp * dim)
104e15f9bd0SJeremy L Thompson       // LCOV_EXCL_START
105e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_DIMENSION,
106d1d35e2fSjeremylt                        "Field '%s' of size %d and EvalMode %s in %d dimensions: "
107d1d35e2fSjeremylt                        "ElemRestriction/Basis has %d components",
108d1d35e2fSjeremylt                        qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode], dim,
109d1d35e2fSjeremylt                        num_comp);
110e15f9bd0SJeremy L Thompson     // LCOV_EXCL_STOP
111e15f9bd0SJeremy L Thompson     break;
112e15f9bd0SJeremy L Thompson   case CEED_EVAL_WEIGHT:
113d1d35e2fSjeremylt     // No additional checks required
114e15f9bd0SJeremy L Thompson     break;
115e15f9bd0SJeremy L Thompson   case CEED_EVAL_DIV:
116e15f9bd0SJeremy L Thompson     // Not implemented
117e15f9bd0SJeremy L Thompson     break;
118e15f9bd0SJeremy L Thompson   case CEED_EVAL_CURL:
119e15f9bd0SJeremy L Thompson     // Not implemented
120e15f9bd0SJeremy L Thompson     break;
121e15f9bd0SJeremy L Thompson   }
122e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1237a982d89SJeremy L. Thompson }
1247a982d89SJeremy L. Thompson 
1257a982d89SJeremy L. Thompson /**
1267a982d89SJeremy L. Thompson   @brief View a field of a CeedOperator
1277a982d89SJeremy L. Thompson 
1287a982d89SJeremy L. Thompson   @param[in] field         Operator field to view
129d1d35e2fSjeremylt   @param[in] qf_field      QFunction field (carries field name)
130d1d35e2fSjeremylt   @param[in] field_number  Number of field being viewed
1314c4400c7SValeria Barra   @param[in] sub           true indicates sub-operator, which increases indentation; false for top-level operator
132d1d35e2fSjeremylt   @param[in] input         true for an input field; false for output field
1337a982d89SJeremy L. Thompson   @param[in] stream        Stream to view to, e.g., stdout
1347a982d89SJeremy L. Thompson 
1357a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
1367a982d89SJeremy L. Thompson 
1377a982d89SJeremy L. Thompson   @ref Utility
1387a982d89SJeremy L. Thompson **/
1397a982d89SJeremy L. Thompson static int CeedOperatorFieldView(CeedOperatorField field,
140d1d35e2fSjeremylt                                  CeedQFunctionField qf_field,
141d1d35e2fSjeremylt                                  CeedInt field_number, bool sub, bool input,
1427a982d89SJeremy L. Thompson                                  FILE *stream) {
1437a982d89SJeremy L. Thompson   const char *pre = sub ? "  " : "";
144d1d35e2fSjeremylt   const char *in_out = input ? "Input" : "Output";
1457a982d89SJeremy L. Thompson 
146b8bf0bcaSJeremy L Thompson   fprintf(stream, "%s    %s field %d:\n"
1477a982d89SJeremy L. Thompson           "%s      Name: \"%s\"\n",
148d1d35e2fSjeremylt           pre, in_out, field_number, pre, qf_field->field_name);
1497a982d89SJeremy L. Thompson 
1507a982d89SJeremy L. Thompson   if (field->basis == CEED_BASIS_COLLOCATED)
1517a982d89SJeremy L. Thompson     fprintf(stream, "%s      Collocated basis\n", pre);
1527a982d89SJeremy L. Thompson 
1537a982d89SJeremy L. Thompson   if (field->vec == CEED_VECTOR_ACTIVE)
1547a982d89SJeremy L. Thompson     fprintf(stream, "%s      Active vector\n", pre);
1557a982d89SJeremy L. Thompson   else if (field->vec == CEED_VECTOR_NONE)
1567a982d89SJeremy L. Thompson     fprintf(stream, "%s      No vector\n", pre);
157e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1587a982d89SJeremy L. Thompson }
1597a982d89SJeremy L. Thompson 
1607a982d89SJeremy L. Thompson /**
1617a982d89SJeremy L. Thompson   @brief View a single CeedOperator
1627a982d89SJeremy L. Thompson 
1637a982d89SJeremy L. Thompson   @param[in] op      CeedOperator to view
1647a982d89SJeremy L. Thompson   @param[in] sub     Boolean flag for sub-operator
1657a982d89SJeremy L. Thompson   @param[in] stream  Stream to write; typically stdout/stderr or a file
1667a982d89SJeremy L. Thompson 
1677a982d89SJeremy L. Thompson   @return Error code: 0 - success, otherwise - failure
1687a982d89SJeremy L. Thompson 
1697a982d89SJeremy L. Thompson   @ref Utility
1707a982d89SJeremy L. Thompson **/
1717a982d89SJeremy L. Thompson int CeedOperatorSingleView(CeedOperator op, bool sub, FILE *stream) {
1727a982d89SJeremy L. Thompson   int ierr;
1737a982d89SJeremy L. Thompson   const char *pre = sub ? "  " : "";
1747a982d89SJeremy L. Thompson 
175381e6593SJeremy L Thompson   CeedInt num_elem, num_qpts;
176381e6593SJeremy L Thompson   ierr = CeedOperatorGetNumElements(op, &num_elem); CeedChk(ierr);
177381e6593SJeremy L Thompson   ierr = CeedOperatorGetNumQuadraturePoints(op, &num_qpts); CeedChk(ierr);
178381e6593SJeremy L Thompson 
17978464608Sjeremylt   CeedInt total_fields = 0;
18078464608Sjeremylt   ierr = CeedOperatorGetNumArgs(op, &total_fields); CeedChk(ierr);
181381e6593SJeremy L Thompson   fprintf(stream, "%s  %d elements with %d quadrature points each\n",
182381e6593SJeremy L Thompson           pre, num_elem, num_qpts);
1837a982d89SJeremy L. Thompson 
184b8bf0bcaSJeremy L Thompson   fprintf(stream, "%s  %d field%s\n", pre, total_fields,
18578464608Sjeremylt           total_fields>1 ? "s" : "");
1867a982d89SJeremy L. Thompson 
187b8bf0bcaSJeremy L Thompson   fprintf(stream, "%s  %d input field%s:\n", pre, op->qf->num_input_fields,
188d1d35e2fSjeremylt           op->qf->num_input_fields>1 ? "s" : "");
189d1d35e2fSjeremylt   for (CeedInt i=0; i<op->qf->num_input_fields; i++) {
190d1d35e2fSjeremylt     ierr = CeedOperatorFieldView(op->input_fields[i], op->qf->input_fields[i],
1917a982d89SJeremy L. Thompson                                  i, sub, 1, stream); CeedChk(ierr);
1927a982d89SJeremy L. Thompson   }
1937a982d89SJeremy L. Thompson 
194b8bf0bcaSJeremy L Thompson   fprintf(stream, "%s  %d output field%s:\n", pre, op->qf->num_output_fields,
195d1d35e2fSjeremylt           op->qf->num_output_fields>1 ? "s" : "");
196d1d35e2fSjeremylt   for (CeedInt i=0; i<op->qf->num_output_fields; i++) {
197d1d35e2fSjeremylt     ierr = CeedOperatorFieldView(op->output_fields[i], op->qf->output_fields[i],
1987a982d89SJeremy L. Thompson                                  i, sub, 0, stream); CeedChk(ierr);
1997a982d89SJeremy L. Thompson   }
200e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2017a982d89SJeremy L. Thompson }
2027a982d89SJeremy L. Thompson 
203d99fa3c5SJeremy L Thompson /**
2040f60e0a8SJeremy L Thompson   @brief Find the active vector basis for a non-composite CeedOperator
205eaf62fffSJeremy L Thompson 
206eaf62fffSJeremy L Thompson   @param[in] op             CeedOperator to find active basis for
2070f60e0a8SJeremy L Thompson   @param[out] active_basis  Basis for active input vector or NULL for composite operator
208eaf62fffSJeremy L Thompson 
209eaf62fffSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
210eaf62fffSJeremy L Thompson 
211eaf62fffSJeremy L Thompson   @ ref Developer
212eaf62fffSJeremy L Thompson **/
213eaf62fffSJeremy L Thompson int CeedOperatorGetActiveBasis(CeedOperator op, CeedBasis *active_basis) {
214eaf62fffSJeremy L Thompson   *active_basis = NULL;
2150f60e0a8SJeremy L Thompson   if (op->is_composite) return CEED_ERROR_SUCCESS;
216*92ae7e47SJeremy L Thompson   for (CeedInt i = 0; i < op->qf->num_input_fields; i++)
217eaf62fffSJeremy L Thompson     if (op->input_fields[i]->vec == CEED_VECTOR_ACTIVE) {
218eaf62fffSJeremy L Thompson       *active_basis = op->input_fields[i]->basis;
219eaf62fffSJeremy L Thompson       break;
220eaf62fffSJeremy L Thompson     }
221eaf62fffSJeremy L Thompson 
222eaf62fffSJeremy L Thompson   if (!*active_basis) {
223eaf62fffSJeremy L Thompson     // LCOV_EXCL_START
224eaf62fffSJeremy L Thompson     int ierr;
225eaf62fffSJeremy L Thompson     Ceed ceed;
226eaf62fffSJeremy L Thompson     ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr);
227eaf62fffSJeremy L Thompson     return CeedError(ceed, CEED_ERROR_MINOR,
228eaf62fffSJeremy L Thompson                      "No active CeedBasis found");
229eaf62fffSJeremy L Thompson     // LCOV_EXCL_STOP
230eaf62fffSJeremy L Thompson   }
231eaf62fffSJeremy L Thompson   return CEED_ERROR_SUCCESS;
232eaf62fffSJeremy L Thompson }
233eaf62fffSJeremy L Thompson 
234eaf62fffSJeremy L Thompson /**
2350f60e0a8SJeremy L Thompson   @brief Find the active vector ElemRestriction for a non-composite CeedOperator
236e2f04181SAndrew T. Barker 
237e2f04181SAndrew T. Barker   @param[in] op            CeedOperator to find active basis for
2380f60e0a8SJeremy L Thompson   @param[out] active_rstr  ElemRestriction for active input vector or NULL for composite operator
239e2f04181SAndrew T. Barker 
240e2f04181SAndrew T. Barker   @return An error code: 0 - success, otherwise - failure
241e2f04181SAndrew T. Barker 
242e2f04181SAndrew T. Barker   @ref Utility
243e2f04181SAndrew T. Barker **/
244eaf62fffSJeremy L Thompson int CeedOperatorGetActiveElemRestriction(CeedOperator op,
245d1d35e2fSjeremylt     CeedElemRestriction *active_rstr) {
246d1d35e2fSjeremylt   *active_rstr = NULL;
2470f60e0a8SJeremy L Thompson   if (op->is_composite) return CEED_ERROR_SUCCESS;
248*92ae7e47SJeremy L Thompson   for (CeedInt i = 0; i < op->qf->num_input_fields; i++)
249d1d35e2fSjeremylt     if (op->input_fields[i]->vec == CEED_VECTOR_ACTIVE) {
250d1d35e2fSjeremylt       *active_rstr = op->input_fields[i]->elem_restr;
251e2f04181SAndrew T. Barker       break;
252e2f04181SAndrew T. Barker     }
253e2f04181SAndrew T. Barker 
254d1d35e2fSjeremylt   if (!*active_rstr) {
255e2f04181SAndrew T. Barker     // LCOV_EXCL_START
256e2f04181SAndrew T. Barker     int ierr;
257e2f04181SAndrew T. Barker     Ceed ceed;
258e2f04181SAndrew T. Barker     ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr);
259e2f04181SAndrew T. Barker     return CeedError(ceed, CEED_ERROR_INCOMPLETE,
260eaf62fffSJeremy L Thompson                      "No active CeedElemRestriction found");
261e2f04181SAndrew T. Barker     // LCOV_EXCL_STOP
262e2f04181SAndrew T. Barker   }
263e2f04181SAndrew T. Barker   return CEED_ERROR_SUCCESS;
264e2f04181SAndrew T. Barker }
265e2f04181SAndrew T. Barker 
266d8dd9a91SJeremy L Thompson /**
267d8dd9a91SJeremy L Thompson   @brief Set QFunctionContext field value of the specified type.
268d8dd9a91SJeremy L Thompson            For composite operators, the value is set in all
269d8dd9a91SJeremy L Thompson            sub-operator QFunctionContexts that have a matching `field_name`.
270d8dd9a91SJeremy L Thompson            A non-zero error code is returned for single operators
271d8dd9a91SJeremy L Thompson            that do not have a matching field of the same type or composite
272d8dd9a91SJeremy L Thompson            operators that do not have any field of a matching type.
273d8dd9a91SJeremy L Thompson 
274d8dd9a91SJeremy L Thompson   @param op          CeedOperator
2753668ca4bSJeremy L Thompson   @param field_label Label of field to set
276d8dd9a91SJeremy L Thompson   @param field_type  Type of field to set
277d8dd9a91SJeremy L Thompson   @param value       Value to set
278d8dd9a91SJeremy L Thompson 
279d8dd9a91SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
280d8dd9a91SJeremy L Thompson 
281d8dd9a91SJeremy L Thompson   @ref User
282d8dd9a91SJeremy L Thompson **/
283d8dd9a91SJeremy L Thompson static int CeedOperatorContextSetGeneric(CeedOperator op,
2843668ca4bSJeremy L Thompson     CeedContextFieldLabel field_label, CeedContextFieldType field_type,
2853668ca4bSJeremy L Thompson     void *value) {
286d8dd9a91SJeremy L Thompson   int ierr;
287d8dd9a91SJeremy L Thompson 
2883668ca4bSJeremy L Thompson   if (!field_label)
2893668ca4bSJeremy L Thompson     // LCOV_EXCL_START
2903668ca4bSJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED,
2913668ca4bSJeremy L Thompson                      "Invalid field label");
2923668ca4bSJeremy L Thompson   // LCOV_EXCL_STOP
2933668ca4bSJeremy L Thompson 
2943668ca4bSJeremy L Thompson   bool is_composite = false;
295d8dd9a91SJeremy L Thompson   ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr);
296d8dd9a91SJeremy L Thompson   if (is_composite) {
297d8dd9a91SJeremy L Thompson     CeedInt num_sub;
298d8dd9a91SJeremy L Thompson     CeedOperator *sub_operators;
299d8dd9a91SJeremy L Thompson 
300d8dd9a91SJeremy L Thompson     ierr = CeedOperatorGetNumSub(op, &num_sub); CeedChk(ierr);
301d8dd9a91SJeremy L Thompson     ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr);
3023668ca4bSJeremy L Thompson     if (num_sub != field_label->num_sub_labels)
3033668ca4bSJeremy L Thompson       // LCOV_EXCL_START
3043668ca4bSJeremy L Thompson       return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED,
3053668ca4bSJeremy L Thompson                        "ContextLabel does not correspond to composite operator.\n"
3063668ca4bSJeremy L Thompson                        "Use CeedOperatorGetContextFieldLabel().");
3073668ca4bSJeremy L Thompson     // LCOV_EXCL_STOP
308d8dd9a91SJeremy L Thompson 
309d8dd9a91SJeremy L Thompson     for (CeedInt i = 0; i < num_sub; i++) {
310d8dd9a91SJeremy L Thompson       // Try every sub-operator, ok if some sub-operators do not have field
3113668ca4bSJeremy L Thompson       if (field_label->sub_labels[i] && sub_operators[i]->qf->ctx) {
3123668ca4bSJeremy L Thompson         ierr = CeedQFunctionContextSetGeneric(sub_operators[i]->qf->ctx,
3133668ca4bSJeremy L Thompson                                               field_label->sub_labels[i],
3143668ca4bSJeremy L Thompson                                               field_type, value); CeedChk(ierr);
315d8dd9a91SJeremy L Thompson       }
316d8dd9a91SJeremy L Thompson     }
317d8dd9a91SJeremy L Thompson   } else {
318d8dd9a91SJeremy L Thompson     if (!op->qf->ctx)
319d8dd9a91SJeremy L Thompson       // LCOV_EXCL_START
320d8dd9a91SJeremy L Thompson       return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED,
321d8dd9a91SJeremy L Thompson                        "QFunction does not have context data");
322d8dd9a91SJeremy L Thompson     // LCOV_EXCL_STOP
323d8dd9a91SJeremy L Thompson 
3243668ca4bSJeremy L Thompson     ierr = CeedQFunctionContextSetGeneric(op->qf->ctx, field_label,
3253668ca4bSJeremy L Thompson                                           field_type, value); CeedChk(ierr);
326d8dd9a91SJeremy L Thompson   }
327d8dd9a91SJeremy L Thompson 
328d8dd9a91SJeremy L Thompson   return CEED_ERROR_SUCCESS;
329d8dd9a91SJeremy L Thompson }
330d8dd9a91SJeremy L Thompson 
3317a982d89SJeremy L. Thompson /// @}
3327a982d89SJeremy L. Thompson 
3337a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
3347a982d89SJeremy L. Thompson /// CeedOperator Backend API
3357a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
3367a982d89SJeremy L. Thompson /// @addtogroup CeedOperatorBackend
3377a982d89SJeremy L. Thompson /// @{
3387a982d89SJeremy L. Thompson 
3397a982d89SJeremy L. Thompson /**
3407a982d89SJeremy L. Thompson   @brief Get the number of arguments associated with a CeedOperator
3417a982d89SJeremy L. Thompson 
3427a982d89SJeremy L. Thompson   @param op             CeedOperator
343d1d35e2fSjeremylt   @param[out] num_args  Variable to store vector number of arguments
3447a982d89SJeremy L. Thompson 
3457a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
3467a982d89SJeremy L. Thompson 
3477a982d89SJeremy L. Thompson   @ref Backend
3487a982d89SJeremy L. Thompson **/
3497a982d89SJeremy L. Thompson 
350d1d35e2fSjeremylt int CeedOperatorGetNumArgs(CeedOperator op, CeedInt *num_args) {
351f04ea552SJeremy L Thompson   if (op->is_composite)
3527a982d89SJeremy L. Thompson     // LCOV_EXCL_START
353e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
354e15f9bd0SJeremy L Thompson                      "Not defined for composite operators");
3557a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
3567a982d89SJeremy L. Thompson 
357d1d35e2fSjeremylt   *num_args = op->num_fields;
358e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
3597a982d89SJeremy L. Thompson }
3607a982d89SJeremy L. Thompson 
3617a982d89SJeremy L. Thompson /**
3627a982d89SJeremy L. Thompson   @brief Get the setup status of a CeedOperator
3637a982d89SJeremy L. Thompson 
3647a982d89SJeremy L. Thompson   @param op                  CeedOperator
365d1d35e2fSjeremylt   @param[out] is_setup_done  Variable to store setup status
3667a982d89SJeremy L. Thompson 
3677a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
3687a982d89SJeremy L. Thompson 
3697a982d89SJeremy L. Thompson   @ref Backend
3707a982d89SJeremy L. Thompson **/
3717a982d89SJeremy L. Thompson 
372d1d35e2fSjeremylt int CeedOperatorIsSetupDone(CeedOperator op, bool *is_setup_done) {
373f04ea552SJeremy L Thompson   *is_setup_done = op->is_backend_setup;
374e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
3757a982d89SJeremy L. Thompson }
3767a982d89SJeremy L. Thompson 
3777a982d89SJeremy L. Thompson /**
3787a982d89SJeremy L. Thompson   @brief Get the QFunction associated with a CeedOperator
3797a982d89SJeremy L. Thompson 
3807a982d89SJeremy L. Thompson   @param op       CeedOperator
3817a982d89SJeremy L. Thompson   @param[out] qf  Variable to store QFunction
3827a982d89SJeremy L. Thompson 
3837a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
3847a982d89SJeremy L. Thompson 
3857a982d89SJeremy L. Thompson   @ref Backend
3867a982d89SJeremy L. Thompson **/
3877a982d89SJeremy L. Thompson 
3887a982d89SJeremy L. Thompson int CeedOperatorGetQFunction(CeedOperator op, CeedQFunction *qf) {
389f04ea552SJeremy L Thompson   if (op->is_composite)
3907a982d89SJeremy L. Thompson     // LCOV_EXCL_START
391e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
392e15f9bd0SJeremy L Thompson                      "Not defined for composite operator");
3937a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
3947a982d89SJeremy L. Thompson 
3957a982d89SJeremy L. Thompson   *qf = op->qf;
396e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
3977a982d89SJeremy L. Thompson }
3987a982d89SJeremy L. Thompson 
3997a982d89SJeremy L. Thompson /**
400c04a41a7SJeremy L Thompson   @brief Get a boolean value indicating if the CeedOperator is composite
401c04a41a7SJeremy L Thompson 
402c04a41a7SJeremy L Thompson   @param op                 CeedOperator
403d1d35e2fSjeremylt   @param[out] is_composite  Variable to store composite status
404c04a41a7SJeremy L Thompson 
405c04a41a7SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
406c04a41a7SJeremy L Thompson 
407c04a41a7SJeremy L Thompson   @ref Backend
408c04a41a7SJeremy L Thompson **/
409c04a41a7SJeremy L Thompson 
410d1d35e2fSjeremylt int CeedOperatorIsComposite(CeedOperator op, bool *is_composite) {
411f04ea552SJeremy L Thompson   *is_composite = op->is_composite;
412e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
413c04a41a7SJeremy L Thompson }
414c04a41a7SJeremy L Thompson 
415c04a41a7SJeremy L Thompson /**
416d1d35e2fSjeremylt   @brief Get the number of sub_operators associated with a CeedOperator
4177a982d89SJeremy L. Thompson 
4187a982d89SJeremy L. Thompson   @param op                     CeedOperator
419d1d35e2fSjeremylt   @param[out] num_suboperators  Variable to store number of sub_operators
4207a982d89SJeremy L. Thompson 
4217a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
4227a982d89SJeremy L. Thompson 
4237a982d89SJeremy L. Thompson   @ref Backend
4247a982d89SJeremy L. Thompson **/
4257a982d89SJeremy L. Thompson 
426d1d35e2fSjeremylt int CeedOperatorGetNumSub(CeedOperator op, CeedInt *num_suboperators) {
427f04ea552SJeremy L Thompson   if (!op->is_composite)
4287a982d89SJeremy L. Thompson     // LCOV_EXCL_START
429e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR, "Not a composite operator");
4307a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
4317a982d89SJeremy L. Thompson 
432d1d35e2fSjeremylt   *num_suboperators = op->num_suboperators;
433e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
4347a982d89SJeremy L. Thompson }
4357a982d89SJeremy L. Thompson 
4367a982d89SJeremy L. Thompson /**
437d1d35e2fSjeremylt   @brief Get the list of sub_operators associated with a CeedOperator
4387a982d89SJeremy L. Thompson 
4397a982d89SJeremy L. Thompson   @param op                  CeedOperator
440d1d35e2fSjeremylt   @param[out] sub_operators  Variable to store list of sub_operators
4417a982d89SJeremy L. Thompson 
4427a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
4437a982d89SJeremy L. Thompson 
4447a982d89SJeremy L. Thompson   @ref Backend
4457a982d89SJeremy L. Thompson **/
4467a982d89SJeremy L. Thompson 
447d1d35e2fSjeremylt int CeedOperatorGetSubList(CeedOperator op, CeedOperator **sub_operators) {
448f04ea552SJeremy L Thompson   if (!op->is_composite)
4497a982d89SJeremy L. Thompson     // LCOV_EXCL_START
450e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR, "Not a composite operator");
4517a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
4527a982d89SJeremy L. Thompson 
453d1d35e2fSjeremylt   *sub_operators = op->sub_operators;
454e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
4557a982d89SJeremy L. Thompson }
4567a982d89SJeremy L. Thompson 
4577a982d89SJeremy L. Thompson /**
4587a982d89SJeremy L. Thompson   @brief Get the backend data of a CeedOperator
4597a982d89SJeremy L. Thompson 
4607a982d89SJeremy L. Thompson   @param op         CeedOperator
4617a982d89SJeremy L. Thompson   @param[out] data  Variable to store data
4627a982d89SJeremy L. Thompson 
4637a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
4647a982d89SJeremy L. Thompson 
4657a982d89SJeremy L. Thompson   @ref Backend
4667a982d89SJeremy L. Thompson **/
4677a982d89SJeremy L. Thompson 
468777ff853SJeremy L Thompson int CeedOperatorGetData(CeedOperator op, void *data) {
469777ff853SJeremy L Thompson   *(void **)data = op->data;
470e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
4717a982d89SJeremy L. Thompson }
4727a982d89SJeremy L. Thompson 
4737a982d89SJeremy L. Thompson /**
4747a982d89SJeremy L. Thompson   @brief Set the backend data of a CeedOperator
4757a982d89SJeremy L. Thompson 
4767a982d89SJeremy L. Thompson   @param[out] op  CeedOperator
4777a982d89SJeremy L. Thompson   @param data     Data to set
4787a982d89SJeremy L. Thompson 
4797a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
4807a982d89SJeremy L. Thompson 
4817a982d89SJeremy L. Thompson   @ref Backend
4827a982d89SJeremy L. Thompson **/
4837a982d89SJeremy L. Thompson 
484777ff853SJeremy L Thompson int CeedOperatorSetData(CeedOperator op, void *data) {
485777ff853SJeremy L Thompson   op->data = data;
486e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
4877a982d89SJeremy L. Thompson }
4887a982d89SJeremy L. Thompson 
4897a982d89SJeremy L. Thompson /**
49034359f16Sjeremylt   @brief Increment the reference counter for a CeedOperator
49134359f16Sjeremylt 
49234359f16Sjeremylt   @param op  CeedOperator to increment the reference counter
49334359f16Sjeremylt 
49434359f16Sjeremylt   @return An error code: 0 - success, otherwise - failure
49534359f16Sjeremylt 
49634359f16Sjeremylt   @ref Backend
49734359f16Sjeremylt **/
4989560d06aSjeremylt int CeedOperatorReference(CeedOperator op) {
49934359f16Sjeremylt   op->ref_count++;
50034359f16Sjeremylt   return CEED_ERROR_SUCCESS;
50134359f16Sjeremylt }
50234359f16Sjeremylt 
50334359f16Sjeremylt /**
5047a982d89SJeremy L. Thompson   @brief Set the setup flag of a CeedOperator to True
5057a982d89SJeremy L. Thompson 
5067a982d89SJeremy L. Thompson   @param op  CeedOperator
5077a982d89SJeremy L. Thompson 
5087a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5097a982d89SJeremy L. Thompson 
5107a982d89SJeremy L. Thompson   @ref Backend
5117a982d89SJeremy L. Thompson **/
5127a982d89SJeremy L. Thompson 
5137a982d89SJeremy L. Thompson int CeedOperatorSetSetupDone(CeedOperator op) {
514f04ea552SJeremy L Thompson   op->is_backend_setup = true;
515e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5167a982d89SJeremy L. Thompson }
5177a982d89SJeremy L. Thompson 
5187a982d89SJeremy L. Thompson /// @}
5197a982d89SJeremy L. Thompson 
5207a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
5217a982d89SJeremy L. Thompson /// CeedOperator Public API
5227a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
5237a982d89SJeremy L. Thompson /// @addtogroup CeedOperatorUser
524dfdf5a53Sjeremylt /// @{
525d7b241e6Sjeremylt 
526d7b241e6Sjeremylt /**
5270219ea01SJeremy L Thompson   @brief Create a CeedOperator and associate a CeedQFunction. A CeedBasis and
5280219ea01SJeremy L Thompson            CeedElemRestriction can be associated with CeedQFunction fields with
5290219ea01SJeremy L Thompson            \ref CeedOperatorSetField.
530d7b241e6Sjeremylt 
531b11c1e72Sjeremylt   @param ceed     A Ceed object where the CeedOperator will be created
532d7b241e6Sjeremylt   @param qf       QFunction defining the action of the operator at quadrature points
53334138859Sjeremylt   @param dqf      QFunction defining the action of the Jacobian of @a qf (or
5344cc79fe7SJed Brown                     @ref CEED_QFUNCTION_NONE)
535d7b241e6Sjeremylt   @param dqfT     QFunction defining the action of the transpose of the Jacobian
5364cc79fe7SJed Brown                     of @a qf (or @ref CEED_QFUNCTION_NONE)
537b11c1e72Sjeremylt   @param[out] op  Address of the variable where the newly created
538b11c1e72Sjeremylt                     CeedOperator will be stored
539b11c1e72Sjeremylt 
540b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
541dfdf5a53Sjeremylt 
5427a982d89SJeremy L. Thompson   @ref User
543d7b241e6Sjeremylt  */
544d7b241e6Sjeremylt int CeedOperatorCreate(Ceed ceed, CeedQFunction qf, CeedQFunction dqf,
545d7b241e6Sjeremylt                        CeedQFunction dqfT, CeedOperator *op) {
546d7b241e6Sjeremylt   int ierr;
547d7b241e6Sjeremylt 
5485fe0d4faSjeremylt   if (!ceed->OperatorCreate) {
5495fe0d4faSjeremylt     Ceed delegate;
550aefd8378Sjeremylt     ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr);
5515fe0d4faSjeremylt 
5525fe0d4faSjeremylt     if (!delegate)
553c042f62fSJeremy L Thompson       // LCOV_EXCL_START
554e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_UNSUPPORTED,
555e15f9bd0SJeremy L Thompson                        "Backend does not support OperatorCreate");
556c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
5575fe0d4faSjeremylt 
5585fe0d4faSjeremylt     ierr = CeedOperatorCreate(delegate, qf, dqf, dqfT, op); CeedChk(ierr);
559e15f9bd0SJeremy L Thompson     return CEED_ERROR_SUCCESS;
5605fe0d4faSjeremylt   }
5615fe0d4faSjeremylt 
562b3b7035fSJeremy L Thompson   if (!qf || qf == CEED_QFUNCTION_NONE)
563b3b7035fSJeremy L Thompson     // LCOV_EXCL_START
564e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_MINOR,
565e15f9bd0SJeremy L Thompson                      "Operator must have a valid QFunction.");
566b3b7035fSJeremy L Thompson   // LCOV_EXCL_STOP
567d7b241e6Sjeremylt   ierr = CeedCalloc(1, op); CeedChk(ierr);
568d7b241e6Sjeremylt   (*op)->ceed = ceed;
5699560d06aSjeremylt   ierr = CeedReference(ceed); CeedChk(ierr);
570d1d35e2fSjeremylt   (*op)->ref_count = 1;
571d7b241e6Sjeremylt   (*op)->qf = qf;
5722b104005SJeremy L Thompson   (*op)->input_size = -1;
5732b104005SJeremy L Thompson   (*op)->output_size = -1;
5749560d06aSjeremylt   ierr = CeedQFunctionReference(qf); CeedChk(ierr);
575442e7f0bSjeremylt   if (dqf && dqf != CEED_QFUNCTION_NONE) {
576d7b241e6Sjeremylt     (*op)->dqf = dqf;
5779560d06aSjeremylt     ierr = CeedQFunctionReference(dqf); CeedChk(ierr);
578442e7f0bSjeremylt   }
579442e7f0bSjeremylt   if (dqfT && dqfT != CEED_QFUNCTION_NONE) {
580d7b241e6Sjeremylt     (*op)->dqfT = dqfT;
5819560d06aSjeremylt     ierr = CeedQFunctionReference(dqfT); CeedChk(ierr);
582442e7f0bSjeremylt   }
583480fae85SJeremy L Thompson   ierr = CeedQFunctionAssemblyDataCreate(ceed, &(*op)->qf_assembled);
584480fae85SJeremy L Thompson   CeedChk(ierr);
585bf4cb664SJeremy L Thompson   ierr = CeedCalloc(CEED_FIELD_MAX, &(*op)->input_fields); CeedChk(ierr);
586bf4cb664SJeremy L Thompson   ierr = CeedCalloc(CEED_FIELD_MAX, &(*op)->output_fields); CeedChk(ierr);
587d7b241e6Sjeremylt   ierr = ceed->OperatorCreate(*op); CeedChk(ierr);
588e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
589d7b241e6Sjeremylt }
590d7b241e6Sjeremylt 
591d7b241e6Sjeremylt /**
59252d6035fSJeremy L Thompson   @brief Create an operator that composes the action of several operators
59352d6035fSJeremy L Thompson 
59452d6035fSJeremy L Thompson   @param ceed     A Ceed object where the CeedOperator will be created
59552d6035fSJeremy L Thompson   @param[out] op  Address of the variable where the newly created
59652d6035fSJeremy L Thompson                     Composite CeedOperator will be stored
59752d6035fSJeremy L Thompson 
59852d6035fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
59952d6035fSJeremy L Thompson 
6007a982d89SJeremy L. Thompson   @ref User
60152d6035fSJeremy L Thompson  */
60252d6035fSJeremy L Thompson int CeedCompositeOperatorCreate(Ceed ceed, CeedOperator *op) {
60352d6035fSJeremy L Thompson   int ierr;
60452d6035fSJeremy L Thompson 
60552d6035fSJeremy L Thompson   if (!ceed->CompositeOperatorCreate) {
60652d6035fSJeremy L Thompson     Ceed delegate;
607aefd8378Sjeremylt     ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr);
60852d6035fSJeremy L Thompson 
609250756a7Sjeremylt     if (delegate) {
61052d6035fSJeremy L Thompson       ierr = CeedCompositeOperatorCreate(delegate, op); CeedChk(ierr);
611e15f9bd0SJeremy L Thompson       return CEED_ERROR_SUCCESS;
61252d6035fSJeremy L Thompson     }
613250756a7Sjeremylt   }
61452d6035fSJeremy L Thompson 
61552d6035fSJeremy L Thompson   ierr = CeedCalloc(1, op); CeedChk(ierr);
61652d6035fSJeremy L Thompson   (*op)->ceed = ceed;
6179560d06aSjeremylt   ierr = CeedReference(ceed); CeedChk(ierr);
618f04ea552SJeremy L Thompson   (*op)->is_composite = true;
619bf4cb664SJeremy L Thompson   ierr = CeedCalloc(CEED_COMPOSITE_MAX, &(*op)->sub_operators); CeedChk(ierr);
6202b104005SJeremy L Thompson   (*op)->input_size = -1;
6212b104005SJeremy L Thompson   (*op)->output_size = -1;
622250756a7Sjeremylt 
623250756a7Sjeremylt   if (ceed->CompositeOperatorCreate) {
62452d6035fSJeremy L Thompson     ierr = ceed->CompositeOperatorCreate(*op); CeedChk(ierr);
625250756a7Sjeremylt   }
626e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
62752d6035fSJeremy L Thompson }
62852d6035fSJeremy L Thompson 
62952d6035fSJeremy L Thompson /**
6309560d06aSjeremylt   @brief Copy the pointer to a CeedOperator. Both pointers should
6319560d06aSjeremylt            be destroyed with `CeedOperatorDestroy()`;
6329560d06aSjeremylt            Note: If `*op_copy` is non-NULL, then it is assumed that
6339560d06aSjeremylt            `*op_copy` is a pointer to a CeedOperator. This
6349560d06aSjeremylt            CeedOperator will be destroyed if `*op_copy` is the only
6359560d06aSjeremylt            reference to this CeedOperator.
6369560d06aSjeremylt 
6379560d06aSjeremylt   @param op            CeedOperator to copy reference to
6389560d06aSjeremylt   @param[out] op_copy  Variable to store copied reference
6399560d06aSjeremylt 
6409560d06aSjeremylt   @return An error code: 0 - success, otherwise - failure
6419560d06aSjeremylt 
6429560d06aSjeremylt   @ref User
6439560d06aSjeremylt **/
6449560d06aSjeremylt int CeedOperatorReferenceCopy(CeedOperator op, CeedOperator *op_copy) {
6459560d06aSjeremylt   int ierr;
6469560d06aSjeremylt 
6479560d06aSjeremylt   ierr = CeedOperatorReference(op); CeedChk(ierr);
6489560d06aSjeremylt   ierr = CeedOperatorDestroy(op_copy); CeedChk(ierr);
6499560d06aSjeremylt   *op_copy = op;
6509560d06aSjeremylt   return CEED_ERROR_SUCCESS;
6519560d06aSjeremylt }
6529560d06aSjeremylt 
6539560d06aSjeremylt /**
654b11c1e72Sjeremylt   @brief Provide a field to a CeedOperator for use by its CeedQFunction
655d7b241e6Sjeremylt 
656d7b241e6Sjeremylt   This function is used to specify both active and passive fields to a
657d7b241e6Sjeremylt   CeedOperator.  For passive fields, a vector @arg v must be provided.  Passive
658d7b241e6Sjeremylt   fields can inputs or outputs (updated in-place when operator is applied).
659d7b241e6Sjeremylt 
660d7b241e6Sjeremylt   Active fields must be specified using this function, but their data (in a
661d7b241e6Sjeremylt   CeedVector) is passed in CeedOperatorApply().  There can be at most one active
662979e564eSJames Wright   input CeedVector and at most one active output CeedVector passed to
663979e564eSJames Wright   CeedOperatorApply().
664d7b241e6Sjeremylt 
6658c91a0c9SJeremy L Thompson   @param op          CeedOperator on which to provide the field
666d1d35e2fSjeremylt   @param field_name  Name of the field (to be matched with the name used by
6678795c945Sjeremylt                        CeedQFunction)
668b11c1e72Sjeremylt   @param r           CeedElemRestriction
6694cc79fe7SJed Brown   @param b           CeedBasis in which the field resides or @ref CEED_BASIS_COLLOCATED
670b11c1e72Sjeremylt                        if collocated with quadrature points
6714cc79fe7SJed Brown   @param v           CeedVector to be used by CeedOperator or @ref CEED_VECTOR_ACTIVE
6724cc79fe7SJed Brown                        if field is active or @ref CEED_VECTOR_NONE if using
6734cc79fe7SJed Brown                        @ref CEED_EVAL_WEIGHT in the QFunction
674b11c1e72Sjeremylt 
675b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
676dfdf5a53Sjeremylt 
6777a982d89SJeremy L. Thompson   @ref User
678b11c1e72Sjeremylt **/
679d1d35e2fSjeremylt int CeedOperatorSetField(CeedOperator op, const char *field_name,
680a8d32208Sjeremylt                          CeedElemRestriction r, CeedBasis b, CeedVector v) {
681d7b241e6Sjeremylt   int ierr;
682f04ea552SJeremy L Thompson   if (op->is_composite)
683c042f62fSJeremy L Thompson     // LCOV_EXCL_START
684e1e9e29dSJed Brown     return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
685e15f9bd0SJeremy L Thompson                      "Cannot add field to composite operator.");
686c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
687f04ea552SJeremy L Thompson   if (op->is_immutable)
688f04ea552SJeremy L Thompson     // LCOV_EXCL_START
689f04ea552SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MAJOR,
690f04ea552SJeremy L Thompson                      "Operator cannot be changed after set as immutable");
691f04ea552SJeremy L Thompson   // LCOV_EXCL_STOP
6928b067b84SJed Brown   if (!r)
693c042f62fSJeremy L Thompson     // LCOV_EXCL_START
694e1e9e29dSJed Brown     return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
695c042f62fSJeremy L Thompson                      "ElemRestriction r for field \"%s\" must be non-NULL.",
696d1d35e2fSjeremylt                      field_name);
697c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
6988b067b84SJed Brown   if (!b)
699c042f62fSJeremy L Thompson     // LCOV_EXCL_START
700e1e9e29dSJed Brown     return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
701e15f9bd0SJeremy L Thompson                      "Basis b for field \"%s\" must be non-NULL.",
702d1d35e2fSjeremylt                      field_name);
703c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
7048b067b84SJed Brown   if (!v)
705c042f62fSJeremy L Thompson     // LCOV_EXCL_START
706e1e9e29dSJed Brown     return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
707e15f9bd0SJeremy L Thompson                      "Vector v for field \"%s\" must be non-NULL.",
708d1d35e2fSjeremylt                      field_name);
709c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
71052d6035fSJeremy L Thompson 
711d1d35e2fSjeremylt   CeedInt num_elem;
712d1d35e2fSjeremylt   ierr = CeedElemRestrictionGetNumElements(r, &num_elem); CeedChk(ierr);
713d1d35e2fSjeremylt   if (r != CEED_ELEMRESTRICTION_NONE && op->has_restriction &&
714d1d35e2fSjeremylt       op->num_elem != num_elem)
715c042f62fSJeremy L Thompson     // LCOV_EXCL_START
716e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_DIMENSION,
7171d102b48SJeremy L Thompson                      "ElemRestriction with %d elements incompatible with prior "
718d1d35e2fSjeremylt                      "%d elements", num_elem, op->num_elem);
719c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
720d7b241e6Sjeremylt 
72178464608Sjeremylt   CeedInt num_qpts = 0;
722e15f9bd0SJeremy L Thompson   if (b != CEED_BASIS_COLLOCATED) {
723d1d35e2fSjeremylt     ierr = CeedBasisGetNumQuadraturePoints(b, &num_qpts); CeedChk(ierr);
724d1d35e2fSjeremylt     if (op->num_qpts && op->num_qpts != num_qpts)
725c042f62fSJeremy L Thompson       // LCOV_EXCL_START
726e15f9bd0SJeremy L Thompson       return CeedError(op->ceed, CEED_ERROR_DIMENSION,
727e15f9bd0SJeremy L Thompson                        "Basis with %d quadrature points "
728d1d35e2fSjeremylt                        "incompatible with prior %d points", num_qpts,
729d1d35e2fSjeremylt                        op->num_qpts);
730c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
731d7b241e6Sjeremylt   }
732d1d35e2fSjeremylt   CeedQFunctionField qf_field;
733d1d35e2fSjeremylt   CeedOperatorField *op_field;
7342b104005SJeremy L Thompson   bool is_input = true;
735d1d35e2fSjeremylt   for (CeedInt i=0; i<op->qf->num_input_fields; i++) {
736d1d35e2fSjeremylt     if (!strcmp(field_name, (*op->qf->input_fields[i]).field_name)) {
737d1d35e2fSjeremylt       qf_field = op->qf->input_fields[i];
738d1d35e2fSjeremylt       op_field = &op->input_fields[i];
739d7b241e6Sjeremylt       goto found;
740d7b241e6Sjeremylt     }
741d7b241e6Sjeremylt   }
7422b104005SJeremy L Thompson   is_input = false;
743d1d35e2fSjeremylt   for (CeedInt i=0; i<op->qf->num_output_fields; i++) {
744d1d35e2fSjeremylt     if (!strcmp(field_name, (*op->qf->output_fields[i]).field_name)) {
745d1d35e2fSjeremylt       qf_field = op->qf->output_fields[i];
746d1d35e2fSjeremylt       op_field = &op->output_fields[i];
747d7b241e6Sjeremylt       goto found;
748d7b241e6Sjeremylt     }
749d7b241e6Sjeremylt   }
750c042f62fSJeremy L Thompson   // LCOV_EXCL_START
751e15f9bd0SJeremy L Thompson   return CeedError(op->ceed, CEED_ERROR_INCOMPLETE,
752e15f9bd0SJeremy L Thompson                    "QFunction has no knowledge of field '%s'",
753d1d35e2fSjeremylt                    field_name);
754c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
755d7b241e6Sjeremylt found:
756d1d35e2fSjeremylt   ierr = CeedOperatorCheckField(op->ceed, qf_field, r, b); CeedChk(ierr);
757d1d35e2fSjeremylt   ierr = CeedCalloc(1, op_field); CeedChk(ierr);
758e15f9bd0SJeremy L Thompson 
7592b104005SJeremy L Thompson   if (v == CEED_VECTOR_ACTIVE) {
7602b104005SJeremy L Thompson     CeedSize l_size;
7612b104005SJeremy L Thompson     ierr = CeedElemRestrictionGetLVectorSize(r, &l_size); CeedChk(ierr);
7622b104005SJeremy L Thompson     if (is_input) {
7632b104005SJeremy L Thompson       if (op->input_size == -1) op->input_size = l_size;
7642b104005SJeremy L Thompson       if (l_size != op->input_size)
7652b104005SJeremy L Thompson         // LCOV_EXCL_START
7662b104005SJeremy L Thompson         return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
7672b104005SJeremy L Thompson                          "LVector size %td does not match previous size %td",
7682b104005SJeremy L Thompson                          l_size, op->input_size);
7692b104005SJeremy L Thompson       // LCOV_EXCL_STOP
7702b104005SJeremy L Thompson     } else {
7712b104005SJeremy L Thompson       if (op->output_size == -1) op->output_size = l_size;
7722b104005SJeremy L Thompson       if (l_size != op->output_size)
7732b104005SJeremy L Thompson         // LCOV_EXCL_START
7742b104005SJeremy L Thompson         return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
7752b104005SJeremy L Thompson                          "LVector size %td does not match previous size %td",
7762b104005SJeremy L Thompson                          l_size, op->output_size);
7772b104005SJeremy L Thompson       // LCOV_EXCL_STOP
7782b104005SJeremy L Thompson     }
7792b104005SJeremy L Thompson   }
7802b104005SJeremy L Thompson 
781d1d35e2fSjeremylt   (*op_field)->vec = v;
782e15f9bd0SJeremy L Thompson   if (v != CEED_VECTOR_ACTIVE && v != CEED_VECTOR_NONE) {
7839560d06aSjeremylt     ierr = CeedVectorReference(v); CeedChk(ierr);
784e15f9bd0SJeremy L Thompson   }
785e15f9bd0SJeremy L Thompson 
786d1d35e2fSjeremylt   (*op_field)->elem_restr = r;
7879560d06aSjeremylt   ierr = CeedElemRestrictionReference(r); CeedChk(ierr);
788e15f9bd0SJeremy L Thompson   if (r != CEED_ELEMRESTRICTION_NONE) {
789d1d35e2fSjeremylt     op->num_elem = num_elem;
790d1d35e2fSjeremylt     op->has_restriction = true; // Restriction set, but num_elem may be 0
791e15f9bd0SJeremy L Thompson   }
792d99fa3c5SJeremy L Thompson 
793d1d35e2fSjeremylt   (*op_field)->basis = b;
794e15f9bd0SJeremy L Thompson   if (b != CEED_BASIS_COLLOCATED) {
795cd4dfc48Sjeremylt     if (!op->num_qpts) {
796cd4dfc48Sjeremylt       ierr = CeedOperatorSetNumQuadraturePoints(op, num_qpts); CeedChk(ierr);
797cd4dfc48Sjeremylt     }
7989560d06aSjeremylt     ierr = CeedBasisReference(b); CeedChk(ierr);
799e15f9bd0SJeremy L Thompson   }
800e15f9bd0SJeremy L Thompson 
801d1d35e2fSjeremylt   op->num_fields += 1;
802f7e22acaSJeremy L Thompson   ierr = CeedStringAllocCopy(field_name, (char **)&(*op_field)->field_name);
803f7e22acaSJeremy L Thompson   CeedChk(ierr);
804e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
805d7b241e6Sjeremylt }
806d7b241e6Sjeremylt 
807d7b241e6Sjeremylt /**
80843bbe138SJeremy L Thompson   @brief Get the CeedOperatorFields of a CeedOperator
80943bbe138SJeremy L Thompson 
810f04ea552SJeremy L Thompson   Note: Calling this function asserts that setup is complete
811f04ea552SJeremy L Thompson           and sets the CeedOperator as immutable.
812f04ea552SJeremy L Thompson 
81343bbe138SJeremy L Thompson   @param op                      CeedOperator
814f74ec584SJeremy L Thompson   @param[out] num_input_fields   Variable to store number of input fields
81543bbe138SJeremy L Thompson   @param[out] input_fields       Variable to store input_fields
816f74ec584SJeremy L Thompson   @param[out] num_output_fields  Variable to store number of output fields
81743bbe138SJeremy L Thompson   @param[out] output_fields      Variable to store output_fields
81843bbe138SJeremy L Thompson 
81943bbe138SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
82043bbe138SJeremy L Thompson 
821e9b533fbSJeremy L Thompson   @ref Advanced
82243bbe138SJeremy L Thompson **/
82343bbe138SJeremy L Thompson int CeedOperatorGetFields(CeedOperator op, CeedInt *num_input_fields,
82443bbe138SJeremy L Thompson                           CeedOperatorField **input_fields,
82543bbe138SJeremy L Thompson                           CeedInt *num_output_fields,
82643bbe138SJeremy L Thompson                           CeedOperatorField **output_fields) {
827f04ea552SJeremy L Thompson   int ierr;
828f04ea552SJeremy L Thompson 
829f04ea552SJeremy L Thompson   if (op->is_composite)
83043bbe138SJeremy L Thompson     // LCOV_EXCL_START
83143bbe138SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
83243bbe138SJeremy L Thompson                      "Not defined for composite operator");
83343bbe138SJeremy L Thompson   // LCOV_EXCL_STOP
834f04ea552SJeremy L Thompson   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
83543bbe138SJeremy L Thompson 
83643bbe138SJeremy L Thompson   if (num_input_fields) *num_input_fields = op->qf->num_input_fields;
83743bbe138SJeremy L Thompson   if (input_fields) *input_fields = op->input_fields;
83843bbe138SJeremy L Thompson   if (num_output_fields) *num_output_fields = op->qf->num_output_fields;
83943bbe138SJeremy L Thompson   if (output_fields) *output_fields = op->output_fields;
84043bbe138SJeremy L Thompson   return CEED_ERROR_SUCCESS;
84143bbe138SJeremy L Thompson }
84243bbe138SJeremy L Thompson 
84343bbe138SJeremy L Thompson /**
84428567f8fSJeremy L Thompson   @brief Get the name of a CeedOperatorField
84528567f8fSJeremy L Thompson 
84628567f8fSJeremy L Thompson   @param op_field         CeedOperatorField
84728567f8fSJeremy L Thompson   @param[out] field_name  Variable to store the field name
84828567f8fSJeremy L Thompson 
84928567f8fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
85028567f8fSJeremy L Thompson 
851e9b533fbSJeremy L Thompson   @ref Advanced
85228567f8fSJeremy L Thompson **/
85328567f8fSJeremy L Thompson int CeedOperatorFieldGetName(CeedOperatorField op_field, char **field_name) {
85428567f8fSJeremy L Thompson   *field_name = (char *)op_field->field_name;
85528567f8fSJeremy L Thompson   return CEED_ERROR_SUCCESS;
85628567f8fSJeremy L Thompson }
85728567f8fSJeremy L Thompson 
85828567f8fSJeremy L Thompson /**
85943bbe138SJeremy L Thompson   @brief Get the CeedElemRestriction of a CeedOperatorField
86043bbe138SJeremy L Thompson 
86143bbe138SJeremy L Thompson   @param op_field   CeedOperatorField
86243bbe138SJeremy L Thompson   @param[out] rstr  Variable to store CeedElemRestriction
86343bbe138SJeremy L Thompson 
86443bbe138SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
86543bbe138SJeremy L Thompson 
866e9b533fbSJeremy L Thompson   @ref Advanced
86743bbe138SJeremy L Thompson **/
86843bbe138SJeremy L Thompson int CeedOperatorFieldGetElemRestriction(CeedOperatorField op_field,
86943bbe138SJeremy L Thompson                                         CeedElemRestriction *rstr) {
87043bbe138SJeremy L Thompson   *rstr = op_field->elem_restr;
87143bbe138SJeremy L Thompson   return CEED_ERROR_SUCCESS;
87243bbe138SJeremy L Thompson }
87343bbe138SJeremy L Thompson 
87443bbe138SJeremy L Thompson /**
87543bbe138SJeremy L Thompson   @brief Get the CeedBasis of a CeedOperatorField
87643bbe138SJeremy L Thompson 
87743bbe138SJeremy L Thompson   @param op_field    CeedOperatorField
87843bbe138SJeremy L Thompson   @param[out] basis  Variable to store CeedBasis
87943bbe138SJeremy L Thompson 
88043bbe138SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
88143bbe138SJeremy L Thompson 
882e9b533fbSJeremy L Thompson   @ref Advanced
88343bbe138SJeremy L Thompson **/
88443bbe138SJeremy L Thompson int CeedOperatorFieldGetBasis(CeedOperatorField op_field, CeedBasis *basis) {
88543bbe138SJeremy L Thompson   *basis = op_field->basis;
88643bbe138SJeremy L Thompson   return CEED_ERROR_SUCCESS;
88743bbe138SJeremy L Thompson }
88843bbe138SJeremy L Thompson 
88943bbe138SJeremy L Thompson /**
89043bbe138SJeremy L Thompson   @brief Get the CeedVector of a CeedOperatorField
89143bbe138SJeremy L Thompson 
89243bbe138SJeremy L Thompson   @param op_field  CeedOperatorField
89343bbe138SJeremy L Thompson   @param[out] vec  Variable to store CeedVector
89443bbe138SJeremy L Thompson 
89543bbe138SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
89643bbe138SJeremy L Thompson 
897e9b533fbSJeremy L Thompson   @ref Advanced
89843bbe138SJeremy L Thompson **/
89943bbe138SJeremy L Thompson int CeedOperatorFieldGetVector(CeedOperatorField op_field, CeedVector *vec) {
90043bbe138SJeremy L Thompson   *vec = op_field->vec;
90143bbe138SJeremy L Thompson   return CEED_ERROR_SUCCESS;
90243bbe138SJeremy L Thompson }
90343bbe138SJeremy L Thompson 
90443bbe138SJeremy L Thompson /**
90552d6035fSJeremy L Thompson   @brief Add a sub-operator to a composite CeedOperator
906288c0443SJeremy L Thompson 
907d1d35e2fSjeremylt   @param[out] composite_op  Composite CeedOperator
908d1d35e2fSjeremylt   @param      sub_op        Sub-operator CeedOperator
90952d6035fSJeremy L Thompson 
91052d6035fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
91152d6035fSJeremy L Thompson 
9127a982d89SJeremy L. Thompson   @ref User
91352d6035fSJeremy L Thompson  */
914d1d35e2fSjeremylt int CeedCompositeOperatorAddSub(CeedOperator composite_op,
915d1d35e2fSjeremylt                                 CeedOperator sub_op) {
91634359f16Sjeremylt   int ierr;
91734359f16Sjeremylt 
918f04ea552SJeremy L Thompson   if (!composite_op->is_composite)
919c042f62fSJeremy L Thompson     // LCOV_EXCL_START
920d1d35e2fSjeremylt     return CeedError(composite_op->ceed, CEED_ERROR_MINOR,
921e2f04181SAndrew T. Barker                      "CeedOperator is not a composite operator");
922c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
92352d6035fSJeremy L Thompson 
924d1d35e2fSjeremylt   if (composite_op->num_suboperators == CEED_COMPOSITE_MAX)
925c042f62fSJeremy L Thompson     // LCOV_EXCL_START
926d1d35e2fSjeremylt     return CeedError(composite_op->ceed, CEED_ERROR_UNSUPPORTED,
9272b104005SJeremy L Thompson                      "Cannot add additional sub-operators");
928c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
929f04ea552SJeremy L Thompson   if (composite_op->is_immutable)
930f04ea552SJeremy L Thompson     // LCOV_EXCL_START
931f04ea552SJeremy L Thompson     return CeedError(composite_op->ceed, CEED_ERROR_MAJOR,
932f04ea552SJeremy L Thompson                      "Operator cannot be changed after set as immutable");
933f04ea552SJeremy L Thompson   // LCOV_EXCL_STOP
93452d6035fSJeremy L Thompson 
9352b104005SJeremy L Thompson   {
9362b104005SJeremy L Thompson     CeedSize input_size, output_size;
9372b104005SJeremy L Thompson     ierr = CeedOperatorGetActiveVectorLengths(sub_op, &input_size, &output_size);
9382b104005SJeremy L Thompson     CeedChk(ierr);
9392b104005SJeremy L Thompson     if (composite_op->input_size == -1) composite_op->input_size = input_size;
9402b104005SJeremy L Thompson     if (composite_op->output_size == -1) composite_op->output_size = output_size;
9412b104005SJeremy L Thompson     // Note, a size of -1 means no active vector restriction set, so no incompatibility
9422b104005SJeremy L Thompson     if ((input_size != -1 && input_size != composite_op->input_size) ||
9432b104005SJeremy L Thompson         (output_size != -1 && output_size != composite_op->output_size))
9442b104005SJeremy L Thompson       // LCOV_EXCL_START
9452b104005SJeremy L Thompson       return CeedError(composite_op->ceed, CEED_ERROR_MAJOR,
9462b104005SJeremy L Thompson                        "Sub-operators must have compatible dimensions; "
9472b104005SJeremy L Thompson                        "composite operator of shape (%td, %td) not compatible with "
9482b104005SJeremy L Thompson                        "sub-operator of shape (%td, %td)",
9492b104005SJeremy L Thompson                        composite_op->input_size, composite_op->output_size, input_size, output_size);
9502b104005SJeremy L Thompson     // LCOV_EXCL_STOP
9512b104005SJeremy L Thompson   }
9522b104005SJeremy L Thompson 
953d1d35e2fSjeremylt   composite_op->sub_operators[composite_op->num_suboperators] = sub_op;
9549560d06aSjeremylt   ierr = CeedOperatorReference(sub_op); CeedChk(ierr);
955d1d35e2fSjeremylt   composite_op->num_suboperators++;
956e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
95752d6035fSJeremy L Thompson }
95852d6035fSJeremy L Thompson 
95952d6035fSJeremy L Thompson /**
9604db537f9SJeremy L Thompson   @brief Check if a CeedOperator is ready to be used.
9614db537f9SJeremy L Thompson 
9624db537f9SJeremy L Thompson   @param[in] op  CeedOperator to check
9634db537f9SJeremy L Thompson 
9644db537f9SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
9654db537f9SJeremy L Thompson 
9664db537f9SJeremy L Thompson   @ref User
9674db537f9SJeremy L Thompson **/
9684db537f9SJeremy L Thompson int CeedOperatorCheckReady(CeedOperator op) {
9694db537f9SJeremy L Thompson   int ierr;
9704db537f9SJeremy L Thompson   Ceed ceed;
9714db537f9SJeremy L Thompson   ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr);
9724db537f9SJeremy L Thompson 
9734db537f9SJeremy L Thompson   if (op->is_interface_setup)
9744db537f9SJeremy L Thompson     return CEED_ERROR_SUCCESS;
9754db537f9SJeremy L Thompson 
9764db537f9SJeremy L Thompson   CeedQFunction qf = op->qf;
9774db537f9SJeremy L Thompson   if (op->is_composite) {
9784db537f9SJeremy L Thompson     if (!op->num_suboperators)
9794db537f9SJeremy L Thompson       // LCOV_EXCL_START
9804db537f9SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_INCOMPLETE, "No sub_operators set");
9814db537f9SJeremy L Thompson     // LCOV_EXCL_STOP
9824db537f9SJeremy L Thompson     for (CeedInt i = 0; i < op->num_suboperators; i++) {
9834db537f9SJeremy L Thompson       ierr = CeedOperatorCheckReady(op->sub_operators[i]); CeedChk(ierr);
9844db537f9SJeremy L Thompson     }
9852b104005SJeremy L Thompson     // Sub-operators could be modified after adding to composite operator
9862b104005SJeremy L Thompson     // Need to verify no lvec incompatibility from any changes
9872b104005SJeremy L Thompson     CeedSize input_size, output_size;
9882b104005SJeremy L Thompson     ierr = CeedOperatorGetActiveVectorLengths(op, &input_size, &output_size);
9892b104005SJeremy L Thompson     CeedChk(ierr);
9904db537f9SJeremy L Thompson   } else {
9914db537f9SJeremy L Thompson     if (op->num_fields == 0)
9924db537f9SJeremy L Thompson       // LCOV_EXCL_START
9934db537f9SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_INCOMPLETE, "No operator fields set");
9944db537f9SJeremy L Thompson     // LCOV_EXCL_STOP
9954db537f9SJeremy L Thompson     if (op->num_fields < qf->num_input_fields + qf->num_output_fields)
9964db537f9SJeremy L Thompson       // LCOV_EXCL_START
9974db537f9SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_INCOMPLETE, "Not all operator fields set");
9984db537f9SJeremy L Thompson     // LCOV_EXCL_STOP
9994db537f9SJeremy L Thompson     if (!op->has_restriction)
10004db537f9SJeremy L Thompson       // LCOV_EXCL_START
10014db537f9SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_INCOMPLETE,
10024db537f9SJeremy L Thompson                        "At least one restriction required");
10034db537f9SJeremy L Thompson     // LCOV_EXCL_STOP
10044db537f9SJeremy L Thompson     if (op->num_qpts == 0)
10054db537f9SJeremy L Thompson       // LCOV_EXCL_START
10064db537f9SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_INCOMPLETE,
10074db537f9SJeremy L Thompson                        "At least one non-collocated basis is required "
10084db537f9SJeremy L Thompson                        "or the number of quadrature points must be set");
10094db537f9SJeremy L Thompson     // LCOV_EXCL_STOP
10104db537f9SJeremy L Thompson   }
10114db537f9SJeremy L Thompson 
10124db537f9SJeremy L Thompson   // Flag as immutable and ready
10134db537f9SJeremy L Thompson   op->is_interface_setup = true;
10144db537f9SJeremy L Thompson   if (op->qf && op->qf != CEED_QFUNCTION_NONE)
10154db537f9SJeremy L Thompson     // LCOV_EXCL_START
10164db537f9SJeremy L Thompson     op->qf->is_immutable = true;
10174db537f9SJeremy L Thompson   // LCOV_EXCL_STOP
10184db537f9SJeremy L Thompson   if (op->dqf && op->dqf != CEED_QFUNCTION_NONE)
10194db537f9SJeremy L Thompson     // LCOV_EXCL_START
10204db537f9SJeremy L Thompson     op->dqf->is_immutable = true;
10214db537f9SJeremy L Thompson   // LCOV_EXCL_STOP
10224db537f9SJeremy L Thompson   if (op->dqfT && op->dqfT != CEED_QFUNCTION_NONE)
10234db537f9SJeremy L Thompson     // LCOV_EXCL_START
10244db537f9SJeremy L Thompson     op->dqfT->is_immutable = true;
10254db537f9SJeremy L Thompson   // LCOV_EXCL_STOP
10264db537f9SJeremy L Thompson   return CEED_ERROR_SUCCESS;
10274db537f9SJeremy L Thompson }
10284db537f9SJeremy L Thompson 
10294db537f9SJeremy L Thompson /**
1030c9366a6bSJeremy L Thompson   @brief Get vector lengths for the active input and/or output vectors of a CeedOperator.
1031c9366a6bSJeremy L Thompson            Note: Lengths of -1 indicate that the CeedOperator does not have an
1032c9366a6bSJeremy L Thompson            active input and/or output.
1033c9366a6bSJeremy L Thompson 
1034c9366a6bSJeremy L Thompson   @param[in] op           CeedOperator
1035c9366a6bSJeremy L Thompson   @param[out] input_size  Variable to store active input vector length, or NULL
1036c9366a6bSJeremy L Thompson   @param[out] output_size Variable to store active output vector length, or NULL
1037c9366a6bSJeremy L Thompson 
1038c9366a6bSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1039c9366a6bSJeremy L Thompson 
1040c9366a6bSJeremy L Thompson   @ref User
1041c9366a6bSJeremy L Thompson **/
1042c9366a6bSJeremy L Thompson int CeedOperatorGetActiveVectorLengths(CeedOperator op, CeedSize *input_size,
1043c9366a6bSJeremy L Thompson                                        CeedSize *output_size) {
1044c9366a6bSJeremy L Thompson   int ierr;
1045c9366a6bSJeremy L Thompson   bool is_composite;
1046c9366a6bSJeremy L Thompson 
10472b104005SJeremy L Thompson   if (input_size) *input_size = op->input_size;
10482b104005SJeremy L Thompson   if (output_size) *output_size = op->output_size;
1049c9366a6bSJeremy L Thompson 
1050c9366a6bSJeremy L Thompson   ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr);
10512b104005SJeremy L Thompson   if (is_composite && (op->input_size == -1 || op->output_size == -1)) {
1052c9366a6bSJeremy L Thompson     for (CeedInt i = 0; i < op->num_suboperators; i++) {
1053c9366a6bSJeremy L Thompson       CeedSize sub_input_size, sub_output_size;
1054c9366a6bSJeremy L Thompson       ierr = CeedOperatorGetActiveVectorLengths(op->sub_operators[i],
10552b104005SJeremy L Thompson              &sub_input_size, &sub_output_size); CeedChk(ierr);
10562b104005SJeremy L Thompson       if (op->input_size == -1) op->input_size = sub_input_size;
10572b104005SJeremy L Thompson       if (op->output_size == -1) op->output_size = sub_output_size;
10582b104005SJeremy L Thompson       // Note, a size of -1 means no active vector restriction set, so no incompatibility
10592b104005SJeremy L Thompson       if ((sub_input_size != -1 && sub_input_size != op->input_size) ||
10602b104005SJeremy L Thompson           (sub_output_size != -1 && sub_output_size != op->output_size))
10612b104005SJeremy L Thompson         // LCOV_EXCL_START
10622b104005SJeremy L Thompson         return CeedError(op->ceed, CEED_ERROR_MAJOR,
10632b104005SJeremy L Thompson                          "Sub-operators must have compatible dimensions; "
10642b104005SJeremy L Thompson                          "composite operator of shape (%td, %td) not compatible with "
10652b104005SJeremy L Thompson                          "sub-operator of shape (%td, %td)",
10662b104005SJeremy L Thompson                          op->input_size, op->output_size, input_size, output_size);
10672b104005SJeremy L Thompson       // LCOV_EXCL_STOP
1068c9366a6bSJeremy L Thompson     }
1069c9366a6bSJeremy L Thompson   }
1070c9366a6bSJeremy L Thompson 
1071c9366a6bSJeremy L Thompson   return CEED_ERROR_SUCCESS;
1072c9366a6bSJeremy L Thompson }
1073c9366a6bSJeremy L Thompson 
1074c9366a6bSJeremy L Thompson /**
1075beecbf24SJeremy L Thompson   @brief Set reuse of CeedQFunction data in CeedOperatorLinearAssemble* functions.
1076beecbf24SJeremy L Thompson            When `reuse_assembly_data = false` (default), the CeedQFunction associated
1077beecbf24SJeremy L Thompson            with this CeedOperator is re-assembled every time a `CeedOperatorLinearAssemble*`
1078beecbf24SJeremy L Thompson            function is called.
1079beecbf24SJeremy L Thompson            When `reuse_assembly_data = true`, the CeedQFunction associated with
1080beecbf24SJeremy L Thompson            this CeedOperator is reused between calls to
1081beecbf24SJeremy L Thompson            `CeedOperatorSetQFunctionAssemblyDataUpdated`.
10828b919e6bSJeremy L Thompson 
1083beecbf24SJeremy L Thompson   @param[in] op                  CeedOperator
1084beecbf24SJeremy L Thompson   @param[in] reuse_assembly_data Boolean flag setting assembly data reuse
10858b919e6bSJeremy L Thompson 
10868b919e6bSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
10878b919e6bSJeremy L Thompson 
10888b919e6bSJeremy L Thompson   @ref Advanced
10898b919e6bSJeremy L Thompson **/
1090beecbf24SJeremy L Thompson int CeedOperatorSetQFunctionAssemblyReuse(CeedOperator op,
1091beecbf24SJeremy L Thompson     bool reuse_assembly_data) {
10928b919e6bSJeremy L Thompson   int ierr;
10938b919e6bSJeremy L Thompson   bool is_composite;
10948b919e6bSJeremy L Thompson 
10958b919e6bSJeremy L Thompson   ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr);
10968b919e6bSJeremy L Thompson   if (is_composite) {
10978b919e6bSJeremy L Thompson     for (CeedInt i = 0; i < op->num_suboperators; i++) {
1098beecbf24SJeremy L Thompson       ierr = CeedOperatorSetQFunctionAssemblyReuse(op->sub_operators[i],
1099beecbf24SJeremy L Thompson              reuse_assembly_data); CeedChk(ierr);
11008b919e6bSJeremy L Thompson     }
11018b919e6bSJeremy L Thompson   } else {
1102beecbf24SJeremy L Thompson     ierr = CeedQFunctionAssemblyDataSetReuse(op->qf_assembled, reuse_assembly_data);
1103beecbf24SJeremy L Thompson     CeedChk(ierr);
1104beecbf24SJeremy L Thompson   }
1105beecbf24SJeremy L Thompson 
1106beecbf24SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1107beecbf24SJeremy L Thompson }
1108beecbf24SJeremy L Thompson 
1109beecbf24SJeremy L Thompson /**
1110beecbf24SJeremy L Thompson   @brief Mark CeedQFunction data as updated and the CeedQFunction as requiring re-assembly.
1111beecbf24SJeremy L Thompson 
1112beecbf24SJeremy L Thompson   @param[in] op                CeedOperator
11136e15d496SJeremy L Thompson   @param[in] needs_data_update Boolean flag setting assembly data reuse
1114beecbf24SJeremy L Thompson 
1115beecbf24SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1116beecbf24SJeremy L Thompson 
1117beecbf24SJeremy L Thompson   @ref Advanced
1118beecbf24SJeremy L Thompson **/
1119beecbf24SJeremy L Thompson int CeedOperatorSetQFunctionAssemblyDataUpdateNeeded(CeedOperator op,
1120beecbf24SJeremy L Thompson     bool needs_data_update) {
1121beecbf24SJeremy L Thompson   int ierr;
1122beecbf24SJeremy L Thompson   bool is_composite;
1123beecbf24SJeremy L Thompson 
1124beecbf24SJeremy L Thompson   ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr);
1125beecbf24SJeremy L Thompson   if (is_composite) {
1126beecbf24SJeremy L Thompson     for (CeedInt i = 0; i < op->num_suboperators; i++) {
1127beecbf24SJeremy L Thompson       ierr = CeedOperatorSetQFunctionAssemblyDataUpdateNeeded(op->sub_operators[i],
1128beecbf24SJeremy L Thompson              needs_data_update); CeedChk(ierr);
1129beecbf24SJeremy L Thompson     }
1130beecbf24SJeremy L Thompson   } else {
1131beecbf24SJeremy L Thompson     ierr = CeedQFunctionAssemblyDataSetUpdateNeeded(op->qf_assembled,
1132beecbf24SJeremy L Thompson            needs_data_update);
11338b919e6bSJeremy L Thompson     CeedChk(ierr);
11348b919e6bSJeremy L Thompson   }
11358b919e6bSJeremy L Thompson 
11368b919e6bSJeremy L Thompson   return CEED_ERROR_SUCCESS;
11378b919e6bSJeremy L Thompson }
11388b919e6bSJeremy L Thompson 
11398b919e6bSJeremy L Thompson /**
1140cd4dfc48Sjeremylt   @brief Set the number of quadrature points associated with a CeedOperator.
1141cd4dfc48Sjeremylt            This should be used when creating a CeedOperator where every
1142cd4dfc48Sjeremylt            field has a collocated basis. This function cannot be used for
1143cd4dfc48Sjeremylt            composite CeedOperators.
1144cd4dfc48Sjeremylt 
1145cd4dfc48Sjeremylt   @param op        CeedOperator
1146cd4dfc48Sjeremylt   @param num_qpts  Number of quadrature points to set
1147cd4dfc48Sjeremylt 
1148cd4dfc48Sjeremylt   @return An error code: 0 - success, otherwise - failure
1149cd4dfc48Sjeremylt 
1150e9b533fbSJeremy L Thompson   @ref Advanced
1151cd4dfc48Sjeremylt **/
1152cd4dfc48Sjeremylt int CeedOperatorSetNumQuadraturePoints(CeedOperator op, CeedInt num_qpts) {
1153f04ea552SJeremy L Thompson   if (op->is_composite)
1154cd4dfc48Sjeremylt     // LCOV_EXCL_START
1155cd4dfc48Sjeremylt     return CeedError(op->ceed, CEED_ERROR_MINOR,
1156cd4dfc48Sjeremylt                      "Not defined for composite operator");
1157cd4dfc48Sjeremylt   // LCOV_EXCL_STOP
1158cd4dfc48Sjeremylt   if (op->num_qpts)
1159cd4dfc48Sjeremylt     // LCOV_EXCL_START
1160cd4dfc48Sjeremylt     return CeedError(op->ceed, CEED_ERROR_MINOR,
1161cd4dfc48Sjeremylt                      "Number of quadrature points already defined");
1162cd4dfc48Sjeremylt   // LCOV_EXCL_STOP
1163f04ea552SJeremy L Thompson   if (op->is_immutable)
1164f04ea552SJeremy L Thompson     // LCOV_EXCL_START
1165f04ea552SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MAJOR,
1166f04ea552SJeremy L Thompson                      "Operator cannot be changed after set as immutable");
1167f04ea552SJeremy L Thompson   // LCOV_EXCL_STOP
1168cd4dfc48Sjeremylt 
1169cd4dfc48Sjeremylt   op->num_qpts = num_qpts;
1170cd4dfc48Sjeremylt   return CEED_ERROR_SUCCESS;
1171cd4dfc48Sjeremylt }
1172cd4dfc48Sjeremylt 
1173cd4dfc48Sjeremylt /**
1174ea6b5821SJeremy L Thompson   @brief Set name of CeedOperator for CeedOperatorView output
1175ea6b5821SJeremy L Thompson 
1176ea6b5821SJeremy L Thompson   @param op    CeedOperator
1177ea6b5821SJeremy L Thompson   @param name  Name to set, or NULL to remove previously set name
1178ea6b5821SJeremy L Thompson 
1179ea6b5821SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1180ea6b5821SJeremy L Thompson 
1181ea6b5821SJeremy L Thompson   @ref User
1182ea6b5821SJeremy L Thompson **/
1183ea6b5821SJeremy L Thompson int CeedOperatorSetName(CeedOperator op, const char *name) {
1184ea6b5821SJeremy L Thompson   int ierr;
1185ea6b5821SJeremy L Thompson   char *name_copy;
1186ea6b5821SJeremy L Thompson   size_t name_len = name ? strlen(name) : 0;
1187ea6b5821SJeremy L Thompson 
1188ea6b5821SJeremy L Thompson   ierr = CeedFree(&op->name); CeedChk(ierr);
1189ea6b5821SJeremy L Thompson   if (name_len > 0) {
1190ea6b5821SJeremy L Thompson     ierr = CeedCalloc(name_len + 1, &name_copy); CeedChk(ierr);
1191ea6b5821SJeremy L Thompson     memcpy(name_copy, name, name_len);
1192ea6b5821SJeremy L Thompson     op->name = name_copy;
1193ea6b5821SJeremy L Thompson   }
1194ea6b5821SJeremy L Thompson 
1195ea6b5821SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1196ea6b5821SJeremy L Thompson }
1197ea6b5821SJeremy L Thompson 
1198ea6b5821SJeremy L Thompson /**
11997a982d89SJeremy L. Thompson   @brief View a CeedOperator
12007a982d89SJeremy L. Thompson 
12017a982d89SJeremy L. Thompson   @param[in] op      CeedOperator to view
12027a982d89SJeremy L. Thompson   @param[in] stream  Stream to write; typically stdout/stderr or a file
12037a982d89SJeremy L. Thompson 
12047a982d89SJeremy L. Thompson   @return Error code: 0 - success, otherwise - failure
12057a982d89SJeremy L. Thompson 
12067a982d89SJeremy L. Thompson   @ref User
12077a982d89SJeremy L. Thompson **/
12087a982d89SJeremy L. Thompson int CeedOperatorView(CeedOperator op, FILE *stream) {
12097a982d89SJeremy L. Thompson   int ierr;
1210ea6b5821SJeremy L Thompson   bool has_name = op->name;
12117a982d89SJeremy L. Thompson 
1212f04ea552SJeremy L Thompson   if (op->is_composite) {
1213ea6b5821SJeremy L Thompson     fprintf(stream, "Composite CeedOperator%s%s\n",
1214ea6b5821SJeremy L Thompson             has_name ? " - " : "", has_name ? op->name : "");
12157a982d89SJeremy L. Thompson 
1216d1d35e2fSjeremylt     for (CeedInt i=0; i<op->num_suboperators; i++) {
1217ea6b5821SJeremy L Thompson       has_name = op->sub_operators[i]->name;
1218ea6b5821SJeremy L Thompson       fprintf(stream, "  SubOperator %d%s%s:\n", i,
1219ea6b5821SJeremy L Thompson               has_name ? " - " : "",
1220ea6b5821SJeremy L Thompson               has_name ? op->sub_operators[i]->name : "");
1221d1d35e2fSjeremylt       ierr = CeedOperatorSingleView(op->sub_operators[i], 1, stream);
12227a982d89SJeremy L. Thompson       CeedChk(ierr);
12237a982d89SJeremy L. Thompson     }
12247a982d89SJeremy L. Thompson   } else {
1225ea6b5821SJeremy L Thompson     fprintf(stream, "CeedOperator%s%s\n",
1226ea6b5821SJeremy L Thompson             has_name ? " - " : "", has_name ? op->name : "");
12277a982d89SJeremy L. Thompson     ierr = CeedOperatorSingleView(op, 0, stream); CeedChk(ierr);
12287a982d89SJeremy L. Thompson   }
1229e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
12307a982d89SJeremy L. Thompson }
12313bd813ffSjeremylt 
12323bd813ffSjeremylt /**
1233b7c9bbdaSJeremy L Thompson   @brief Get the Ceed associated with a CeedOperator
1234b7c9bbdaSJeremy L Thompson 
1235b7c9bbdaSJeremy L Thompson   @param op         CeedOperator
1236b7c9bbdaSJeremy L Thompson   @param[out] ceed  Variable to store Ceed
1237b7c9bbdaSJeremy L Thompson 
1238b7c9bbdaSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1239b7c9bbdaSJeremy L Thompson 
1240b7c9bbdaSJeremy L Thompson   @ref Advanced
1241b7c9bbdaSJeremy L Thompson **/
1242b7c9bbdaSJeremy L Thompson int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) {
1243b7c9bbdaSJeremy L Thompson   *ceed = op->ceed;
1244b7c9bbdaSJeremy L Thompson   return CEED_ERROR_SUCCESS;
1245b7c9bbdaSJeremy L Thompson }
1246b7c9bbdaSJeremy L Thompson 
1247b7c9bbdaSJeremy L Thompson /**
1248b7c9bbdaSJeremy L Thompson   @brief Get the number of elements associated with a CeedOperator
1249b7c9bbdaSJeremy L Thompson 
1250b7c9bbdaSJeremy L Thompson   @param op             CeedOperator
1251b7c9bbdaSJeremy L Thompson   @param[out] num_elem  Variable to store number of elements
1252b7c9bbdaSJeremy L Thompson 
1253b7c9bbdaSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1254b7c9bbdaSJeremy L Thompson 
1255b7c9bbdaSJeremy L Thompson   @ref Advanced
1256b7c9bbdaSJeremy L Thompson **/
1257b7c9bbdaSJeremy L Thompson int CeedOperatorGetNumElements(CeedOperator op, CeedInt *num_elem) {
1258b7c9bbdaSJeremy L Thompson   if (op->is_composite)
1259b7c9bbdaSJeremy L Thompson     // LCOV_EXCL_START
1260b7c9bbdaSJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
1261b7c9bbdaSJeremy L Thompson                      "Not defined for composite operator");
1262b7c9bbdaSJeremy L Thompson   // LCOV_EXCL_STOP
1263b7c9bbdaSJeremy L Thompson 
1264b7c9bbdaSJeremy L Thompson   *num_elem = op->num_elem;
1265b7c9bbdaSJeremy L Thompson   return CEED_ERROR_SUCCESS;
1266b7c9bbdaSJeremy L Thompson }
1267b7c9bbdaSJeremy L Thompson 
1268b7c9bbdaSJeremy L Thompson /**
1269b7c9bbdaSJeremy L Thompson   @brief Get the number of quadrature points associated with a CeedOperator
1270b7c9bbdaSJeremy L Thompson 
1271b7c9bbdaSJeremy L Thompson   @param op             CeedOperator
1272b7c9bbdaSJeremy L Thompson   @param[out] num_qpts  Variable to store vector number of quadrature points
1273b7c9bbdaSJeremy L Thompson 
1274b7c9bbdaSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1275b7c9bbdaSJeremy L Thompson 
1276b7c9bbdaSJeremy L Thompson   @ref Advanced
1277b7c9bbdaSJeremy L Thompson **/
1278b7c9bbdaSJeremy L Thompson int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *num_qpts) {
1279b7c9bbdaSJeremy L Thompson   if (op->is_composite)
1280b7c9bbdaSJeremy L Thompson     // LCOV_EXCL_START
1281b7c9bbdaSJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
1282b7c9bbdaSJeremy L Thompson                      "Not defined for composite operator");
1283b7c9bbdaSJeremy L Thompson   // LCOV_EXCL_STOP
1284b7c9bbdaSJeremy L Thompson 
1285b7c9bbdaSJeremy L Thompson   *num_qpts = op->num_qpts;
1286b7c9bbdaSJeremy L Thompson   return CEED_ERROR_SUCCESS;
1287b7c9bbdaSJeremy L Thompson }
1288b7c9bbdaSJeremy L Thompson 
1289b7c9bbdaSJeremy L Thompson /**
12906e15d496SJeremy L Thompson   @brief Estimate number of FLOPs required to apply CeedOperator on the active vector
12916e15d496SJeremy L Thompson 
12926e15d496SJeremy L Thompson   @param op    Operator to estimate FLOPs for
12936e15d496SJeremy L Thompson   @param flops Address of variable to hold FLOPs estimate
12946e15d496SJeremy L Thompson 
12956e15d496SJeremy L Thompson   @ref Backend
12966e15d496SJeremy L Thompson **/
12979d36ca50SJeremy L Thompson int CeedOperatorGetFlopsEstimate(CeedOperator op, CeedSize *flops) {
12986e15d496SJeremy L Thompson   int ierr;
12996e15d496SJeremy L Thompson   bool is_composite;
13006e15d496SJeremy L Thompson   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
13016e15d496SJeremy L Thompson 
13026e15d496SJeremy L Thompson   *flops = 0;
13036e15d496SJeremy L Thompson   ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr);
13046e15d496SJeremy L Thompson   if (is_composite) {
13056e15d496SJeremy L Thompson     CeedInt num_suboperators;
13066e15d496SJeremy L Thompson     ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr);
13076e15d496SJeremy L Thompson     CeedOperator *sub_operators;
13086e15d496SJeremy L Thompson     ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr);
13096e15d496SJeremy L Thompson 
13106e15d496SJeremy L Thompson     // FLOPs for each suboperator
13116e15d496SJeremy L Thompson     for (CeedInt i = 0; i < num_suboperators; i++) {
13129d36ca50SJeremy L Thompson       CeedSize suboperator_flops;
13136e15d496SJeremy L Thompson       ierr = CeedOperatorGetFlopsEstimate(sub_operators[i], &suboperator_flops);
13146e15d496SJeremy L Thompson       CeedChk(ierr);
13156e15d496SJeremy L Thompson       *flops += suboperator_flops;
13166e15d496SJeremy L Thompson     }
13176e15d496SJeremy L Thompson   } else {
13186e15d496SJeremy L Thompson     CeedInt num_input_fields, num_output_fields;
13196e15d496SJeremy L Thompson     CeedOperatorField *input_fields, *output_fields;
13206e15d496SJeremy L Thompson 
13216e15d496SJeremy L Thompson     ierr = CeedOperatorGetFields(op, &num_input_fields, &input_fields,
13226e15d496SJeremy L Thompson                                  &num_output_fields, &output_fields); CeedChk(ierr);
13236e15d496SJeremy L Thompson 
13246e15d496SJeremy L Thompson     CeedInt num_elem = 0;
13256e15d496SJeremy L Thompson     ierr = CeedOperatorGetNumElements(op, &num_elem); CeedChk(ierr);
13266e15d496SJeremy L Thompson     // Input FLOPs
13276e15d496SJeremy L Thompson     for (CeedInt i = 0; i < num_input_fields; i++) {
13286e15d496SJeremy L Thompson       if (input_fields[i]->vec == CEED_VECTOR_ACTIVE) {
13299d36ca50SJeremy L Thompson         CeedSize restr_flops, basis_flops;
13306e15d496SJeremy L Thompson 
13316e15d496SJeremy L Thompson         ierr = CeedElemRestrictionGetFlopsEstimate(input_fields[i]->elem_restr,
13326e15d496SJeremy L Thompson                CEED_NOTRANSPOSE, &restr_flops); CeedChk(ierr);
13336e15d496SJeremy L Thompson         *flops += restr_flops;
13346e15d496SJeremy L Thompson         ierr = CeedBasisGetFlopsEstimate(input_fields[i]->basis, CEED_NOTRANSPOSE,
13356e15d496SJeremy L Thompson                                          op->qf->input_fields[i]->eval_mode, &basis_flops); CeedChk(ierr);
13366e15d496SJeremy L Thompson         *flops += basis_flops * num_elem;
13376e15d496SJeremy L Thompson       }
13386e15d496SJeremy L Thompson     }
13396e15d496SJeremy L Thompson     // QF FLOPs
13409d36ca50SJeremy L Thompson     CeedInt num_qpts;
13419d36ca50SJeremy L Thompson     CeedSize qf_flops;
13426e15d496SJeremy L Thompson     ierr = CeedOperatorGetNumQuadraturePoints(op, &num_qpts); CeedChk(ierr);
13436e15d496SJeremy L Thompson     ierr = CeedQFunctionGetFlopsEstimate(op->qf, &qf_flops); CeedChk(ierr);
13446e15d496SJeremy L Thompson     *flops += num_elem * num_qpts * qf_flops;
13456e15d496SJeremy L Thompson     // Output FLOPs
13466e15d496SJeremy L Thompson     for (CeedInt i = 0; i < num_output_fields; i++) {
13476e15d496SJeremy L Thompson       if (output_fields[i]->vec == CEED_VECTOR_ACTIVE) {
13489d36ca50SJeremy L Thompson         CeedSize restr_flops, basis_flops;
13496e15d496SJeremy L Thompson 
13506e15d496SJeremy L Thompson         ierr = CeedElemRestrictionGetFlopsEstimate(output_fields[i]->elem_restr,
13516e15d496SJeremy L Thompson                CEED_TRANSPOSE, &restr_flops); CeedChk(ierr);
13526e15d496SJeremy L Thompson         *flops += restr_flops;
13536e15d496SJeremy L Thompson         ierr = CeedBasisGetFlopsEstimate(output_fields[i]->basis, CEED_TRANSPOSE,
13546e15d496SJeremy L Thompson                                          op->qf->output_fields[i]->eval_mode, &basis_flops); CeedChk(ierr);
13556e15d496SJeremy L Thompson         *flops += basis_flops * num_elem;
13566e15d496SJeremy L Thompson       }
13576e15d496SJeremy L Thompson     }
13586e15d496SJeremy L Thompson   }
13596e15d496SJeremy L Thompson 
13606e15d496SJeremy L Thompson   return CEED_ERROR_SUCCESS;
13616e15d496SJeremy L Thompson }
13626e15d496SJeremy L Thompson 
13636e15d496SJeremy L Thompson /**
13643668ca4bSJeremy L Thompson   @brief Get label for a registered QFunctionContext field, or `NULL` if no
13653668ca4bSJeremy L Thompson            field has been registered with this `field_name`.
13663668ca4bSJeremy L Thompson 
13673668ca4bSJeremy L Thompson   @param[in] op            CeedOperator
13683668ca4bSJeremy L Thompson   @param[in] field_name    Name of field to retrieve label
13693668ca4bSJeremy L Thompson   @param[out] field_label  Variable to field label
13703668ca4bSJeremy L Thompson 
13713668ca4bSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
13723668ca4bSJeremy L Thompson 
13733668ca4bSJeremy L Thompson   @ref User
13743668ca4bSJeremy L Thompson **/
13753668ca4bSJeremy L Thompson int CeedOperatorContextGetFieldLabel(CeedOperator op,
13763668ca4bSJeremy L Thompson                                      const char *field_name,
13773668ca4bSJeremy L Thompson                                      CeedContextFieldLabel *field_label) {
13783668ca4bSJeremy L Thompson   int ierr;
13793668ca4bSJeremy L Thompson 
13803668ca4bSJeremy L Thompson   bool is_composite;
13813668ca4bSJeremy L Thompson   ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr);
13823668ca4bSJeremy L Thompson   if (is_composite) {
13833668ca4bSJeremy L Thompson     // Check if composite label already created
13843668ca4bSJeremy L Thompson     for (CeedInt i=0; i<op->num_context_labels; i++) {
13853668ca4bSJeremy L Thompson       if (!strcmp(op->context_labels[i]->name, field_name)) {
13863668ca4bSJeremy L Thompson         *field_label = op->context_labels[i];
13873668ca4bSJeremy L Thompson         return CEED_ERROR_SUCCESS;
13883668ca4bSJeremy L Thompson       }
13893668ca4bSJeremy L Thompson     }
13903668ca4bSJeremy L Thompson 
13913668ca4bSJeremy L Thompson     // Create composite label if needed
13923668ca4bSJeremy L Thompson     CeedInt num_sub;
13933668ca4bSJeremy L Thompson     CeedOperator *sub_operators;
13943668ca4bSJeremy L Thompson     CeedContextFieldLabel new_field_label;
13953668ca4bSJeremy L Thompson 
13963668ca4bSJeremy L Thompson     ierr = CeedCalloc(1, &new_field_label); CeedChk(ierr);
13973668ca4bSJeremy L Thompson     ierr = CeedOperatorGetNumSub(op, &num_sub); CeedChk(ierr);
13983668ca4bSJeremy L Thompson     ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr);
13993668ca4bSJeremy L Thompson     ierr = CeedCalloc(num_sub, &new_field_label->sub_labels); CeedChk(ierr);
14003668ca4bSJeremy L Thompson     new_field_label->num_sub_labels = num_sub;
14013668ca4bSJeremy L Thompson 
14023668ca4bSJeremy L Thompson     bool label_found = false;
14033668ca4bSJeremy L Thompson     for (CeedInt i=0; i<num_sub; i++) {
14043668ca4bSJeremy L Thompson       if (sub_operators[i]->qf->ctx) {
14053668ca4bSJeremy L Thompson         CeedContextFieldLabel new_field_label_i;
14063668ca4bSJeremy L Thompson         ierr = CeedQFunctionContextGetFieldLabel(sub_operators[i]->qf->ctx, field_name,
14073668ca4bSJeremy L Thompson                &new_field_label_i); CeedChk(ierr);
14083668ca4bSJeremy L Thompson         if (new_field_label_i) {
14093668ca4bSJeremy L Thompson           label_found = true;
14103668ca4bSJeremy L Thompson           new_field_label->sub_labels[i] = new_field_label_i;
14113668ca4bSJeremy L Thompson           new_field_label->name = new_field_label_i->name;
14123668ca4bSJeremy L Thompson           new_field_label->description = new_field_label_i->description;
14137bfe0f0eSJeremy L Thompson           if (new_field_label->type &&
14147bfe0f0eSJeremy L Thompson               new_field_label->type != new_field_label_i->type) {
14157bfe0f0eSJeremy L Thompson             // LCOV_EXCL_START
14167bfe0f0eSJeremy L Thompson             ierr = CeedFree(&new_field_label); CeedChk(ierr);
14177bfe0f0eSJeremy L Thompson             return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
14187bfe0f0eSJeremy L Thompson                              "Incompatible field types on sub-operator contexts. "
14197bfe0f0eSJeremy L Thompson                              "%s != %s",
14207bfe0f0eSJeremy L Thompson                              CeedContextFieldTypes[new_field_label->type],
14217bfe0f0eSJeremy L Thompson                              CeedContextFieldTypes[new_field_label_i->type]);
14227bfe0f0eSJeremy L Thompson             // LCOV_EXCL_STOP
14237bfe0f0eSJeremy L Thompson           } else {
14247bfe0f0eSJeremy L Thompson             new_field_label->type = new_field_label_i->type;
14257bfe0f0eSJeremy L Thompson           }
14267bfe0f0eSJeremy L Thompson           if (new_field_label->num_values != 0 &&
14277bfe0f0eSJeremy L Thompson               new_field_label->num_values != new_field_label_i->num_values) {
14287bfe0f0eSJeremy L Thompson             // LCOV_EXCL_START
14297bfe0f0eSJeremy L Thompson             ierr = CeedFree(&new_field_label); CeedChk(ierr);
14307bfe0f0eSJeremy L Thompson             return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
14317bfe0f0eSJeremy L Thompson                              "Incompatible field number of values on sub-operator"
14327bfe0f0eSJeremy L Thompson                              " contexts. %ld != %ld",
14337bfe0f0eSJeremy L Thompson                              new_field_label->num_values, new_field_label_i->num_values);
14347bfe0f0eSJeremy L Thompson             // LCOV_EXCL_STOP
14357bfe0f0eSJeremy L Thompson           } else {
14367bfe0f0eSJeremy L Thompson             new_field_label->num_values = new_field_label_i->num_values;
14377bfe0f0eSJeremy L Thompson           }
14383668ca4bSJeremy L Thompson         }
14393668ca4bSJeremy L Thompson       }
14403668ca4bSJeremy L Thompson     }
14413668ca4bSJeremy L Thompson     if (!label_found) {
14423668ca4bSJeremy L Thompson       // LCOV_EXCL_START
1443a48e5f43SJeremy L Thompson       ierr = CeedFree(&new_field_label->sub_labels); CeedChk(ierr);
14443668ca4bSJeremy L Thompson       ierr = CeedFree(&new_field_label); CeedChk(ierr);
14453668ca4bSJeremy L Thompson       *field_label = NULL;
14463668ca4bSJeremy L Thompson       // LCOV_EXCL_STOP
14473668ca4bSJeremy L Thompson     } else {
14483668ca4bSJeremy L Thompson       // Move new composite label to operator
14493668ca4bSJeremy L Thompson       if (op->num_context_labels == 0) {
14503668ca4bSJeremy L Thompson         ierr = CeedCalloc(1, &op->context_labels); CeedChk(ierr);
14513668ca4bSJeremy L Thompson         op->max_context_labels = 1;
14523668ca4bSJeremy L Thompson       } else if (op->num_context_labels == op->max_context_labels) {
14533668ca4bSJeremy L Thompson         ierr = CeedRealloc(2*op->num_context_labels, &op->context_labels);
14543668ca4bSJeremy L Thompson         CeedChk(ierr);
14553668ca4bSJeremy L Thompson         op->max_context_labels *= 2;
14563668ca4bSJeremy L Thompson       }
14573668ca4bSJeremy L Thompson       op->context_labels[op->num_context_labels] = new_field_label;
14583668ca4bSJeremy L Thompson       *field_label = new_field_label;
14593668ca4bSJeremy L Thompson       op->num_context_labels++;
14603668ca4bSJeremy L Thompson     }
14613668ca4bSJeremy L Thompson 
14623668ca4bSJeremy L Thompson     return CEED_ERROR_SUCCESS;
14633668ca4bSJeremy L Thompson   } else {
14643668ca4bSJeremy L Thompson     return CeedQFunctionContextGetFieldLabel(op->qf->ctx, field_name, field_label);
14653668ca4bSJeremy L Thompson   }
14663668ca4bSJeremy L Thompson }
14673668ca4bSJeremy L Thompson 
14683668ca4bSJeremy L Thompson /**
1469d8dd9a91SJeremy L Thompson   @brief Set QFunctionContext field holding a double precision value.
1470d8dd9a91SJeremy L Thompson            For composite operators, the value is set in all
1471d8dd9a91SJeremy L Thompson            sub-operator QFunctionContexts that have a matching `field_name`.
1472d8dd9a91SJeremy L Thompson 
1473d8dd9a91SJeremy L Thompson   @param op          CeedOperator
14743668ca4bSJeremy L Thompson   @param field_label Label of field to register
14757bfe0f0eSJeremy L Thompson   @param values      Values to set
1476d8dd9a91SJeremy L Thompson 
1477d8dd9a91SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1478d8dd9a91SJeremy L Thompson 
1479d8dd9a91SJeremy L Thompson   @ref User
1480d8dd9a91SJeremy L Thompson **/
14813668ca4bSJeremy L Thompson int CeedOperatorContextSetDouble(CeedOperator op,
14823668ca4bSJeremy L Thompson                                  CeedContextFieldLabel field_label,
14837bfe0f0eSJeremy L Thompson                                  double *values) {
14843668ca4bSJeremy L Thompson   return CeedOperatorContextSetGeneric(op, field_label, CEED_CONTEXT_FIELD_DOUBLE,
14857bfe0f0eSJeremy L Thompson                                        values);
1486d8dd9a91SJeremy L Thompson }
1487d8dd9a91SJeremy L Thompson 
1488d8dd9a91SJeremy L Thompson /**
1489d8dd9a91SJeremy L Thompson   @brief Set QFunctionContext field holding an int32 value.
1490d8dd9a91SJeremy L Thompson            For composite operators, the value is set in all
1491d8dd9a91SJeremy L Thompson            sub-operator QFunctionContexts that have a matching `field_name`.
1492d8dd9a91SJeremy L Thompson 
1493d8dd9a91SJeremy L Thompson   @param op          CeedOperator
14943668ca4bSJeremy L Thompson   @param field_label Label of field to set
14957bfe0f0eSJeremy L Thompson   @param values      Values to set
1496d8dd9a91SJeremy L Thompson 
1497d8dd9a91SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1498d8dd9a91SJeremy L Thompson 
1499d8dd9a91SJeremy L Thompson   @ref User
1500d8dd9a91SJeremy L Thompson **/
15013668ca4bSJeremy L Thompson int CeedOperatorContextSetInt32(CeedOperator op,
15023668ca4bSJeremy L Thompson                                 CeedContextFieldLabel field_label,
15037bfe0f0eSJeremy L Thompson                                 int *values) {
15043668ca4bSJeremy L Thompson   return CeedOperatorContextSetGeneric(op, field_label, CEED_CONTEXT_FIELD_INT32,
15057bfe0f0eSJeremy L Thompson                                        values);
1506d8dd9a91SJeremy L Thompson }
1507d8dd9a91SJeremy L Thompson 
1508d8dd9a91SJeremy L Thompson /**
15093bd813ffSjeremylt   @brief Apply CeedOperator to a vector
1510d7b241e6Sjeremylt 
1511d7b241e6Sjeremylt   This computes the action of the operator on the specified (active) input,
1512d7b241e6Sjeremylt   yielding its (active) output.  All inputs and outputs must be specified using
1513d7b241e6Sjeremylt   CeedOperatorSetField().
1514d7b241e6Sjeremylt 
1515f04ea552SJeremy L Thompson   Note: Calling this function asserts that setup is complete
1516f04ea552SJeremy L Thompson           and sets the CeedOperator as immutable.
1517f04ea552SJeremy L Thompson 
1518d7b241e6Sjeremylt   @param op        CeedOperator to apply
15194cc79fe7SJed Brown   @param[in] in    CeedVector containing input state or @ref CEED_VECTOR_NONE if
152034138859Sjeremylt                      there are no active inputs
1521b11c1e72Sjeremylt   @param[out] out  CeedVector to store result of applying operator (must be
15224cc79fe7SJed Brown                      distinct from @a in) or @ref CEED_VECTOR_NONE if there are no
152334138859Sjeremylt                      active outputs
1524d7b241e6Sjeremylt   @param request   Address of CeedRequest for non-blocking completion, else
15254cc79fe7SJed Brown                      @ref CEED_REQUEST_IMMEDIATE
1526b11c1e72Sjeremylt 
1527b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
1528dfdf5a53Sjeremylt 
15297a982d89SJeremy L. Thompson   @ref User
1530b11c1e72Sjeremylt **/
1531692c2638Sjeremylt int CeedOperatorApply(CeedOperator op, CeedVector in, CeedVector out,
1532692c2638Sjeremylt                       CeedRequest *request) {
1533d7b241e6Sjeremylt   int ierr;
1534e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
1535d7b241e6Sjeremylt 
1536d1d35e2fSjeremylt   if (op->num_elem)  {
1537250756a7Sjeremylt     // Standard Operator
1538cae8b89aSjeremylt     if (op->Apply) {
1539250756a7Sjeremylt       ierr = op->Apply(op, in, out, request); CeedChk(ierr);
1540cae8b89aSjeremylt     } else {
1541cae8b89aSjeremylt       // Zero all output vectors
1542250756a7Sjeremylt       CeedQFunction qf = op->qf;
1543d1d35e2fSjeremylt       for (CeedInt i=0; i<qf->num_output_fields; i++) {
1544d1d35e2fSjeremylt         CeedVector vec = op->output_fields[i]->vec;
1545cae8b89aSjeremylt         if (vec == CEED_VECTOR_ACTIVE)
1546cae8b89aSjeremylt           vec = out;
1547cae8b89aSjeremylt         if (vec != CEED_VECTOR_NONE) {
1548cae8b89aSjeremylt           ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr);
1549cae8b89aSjeremylt         }
1550cae8b89aSjeremylt       }
1551250756a7Sjeremylt       // Apply
1552250756a7Sjeremylt       ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr);
1553250756a7Sjeremylt     }
1554f04ea552SJeremy L Thompson   } else if (op->is_composite) {
1555250756a7Sjeremylt     // Composite Operator
1556250756a7Sjeremylt     if (op->ApplyComposite) {
1557250756a7Sjeremylt       ierr = op->ApplyComposite(op, in, out, request); CeedChk(ierr);
1558250756a7Sjeremylt     } else {
1559d1d35e2fSjeremylt       CeedInt num_suboperators;
1560d1d35e2fSjeremylt       ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr);
1561d1d35e2fSjeremylt       CeedOperator *sub_operators;
1562d1d35e2fSjeremylt       ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr);
1563250756a7Sjeremylt 
1564250756a7Sjeremylt       // Zero all output vectors
1565250756a7Sjeremylt       if (out != CEED_VECTOR_NONE) {
1566cae8b89aSjeremylt         ierr = CeedVectorSetValue(out, 0.0); CeedChk(ierr);
1567cae8b89aSjeremylt       }
1568d1d35e2fSjeremylt       for (CeedInt i=0; i<num_suboperators; i++) {
1569d1d35e2fSjeremylt         for (CeedInt j=0; j<sub_operators[i]->qf->num_output_fields; j++) {
1570d1d35e2fSjeremylt           CeedVector vec = sub_operators[i]->output_fields[j]->vec;
1571250756a7Sjeremylt           if (vec != CEED_VECTOR_ACTIVE && vec != CEED_VECTOR_NONE) {
1572250756a7Sjeremylt             ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr);
1573250756a7Sjeremylt           }
1574250756a7Sjeremylt         }
1575250756a7Sjeremylt       }
1576250756a7Sjeremylt       // Apply
1577d1d35e2fSjeremylt       for (CeedInt i=0; i<op->num_suboperators; i++) {
1578d1d35e2fSjeremylt         ierr = CeedOperatorApplyAdd(op->sub_operators[i], in, out, request);
1579cae8b89aSjeremylt         CeedChk(ierr);
1580cae8b89aSjeremylt       }
1581cae8b89aSjeremylt     }
1582250756a7Sjeremylt   }
1583e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1584cae8b89aSjeremylt }
1585cae8b89aSjeremylt 
1586cae8b89aSjeremylt /**
1587cae8b89aSjeremylt   @brief Apply CeedOperator to a vector and add result to output vector
1588cae8b89aSjeremylt 
1589cae8b89aSjeremylt   This computes the action of the operator on the specified (active) input,
1590cae8b89aSjeremylt   yielding its (active) output.  All inputs and outputs must be specified using
1591cae8b89aSjeremylt   CeedOperatorSetField().
1592cae8b89aSjeremylt 
1593cae8b89aSjeremylt   @param op        CeedOperator to apply
1594cae8b89aSjeremylt   @param[in] in    CeedVector containing input state or NULL if there are no
1595cae8b89aSjeremylt                      active inputs
1596cae8b89aSjeremylt   @param[out] out  CeedVector to sum in result of applying operator (must be
1597cae8b89aSjeremylt                      distinct from @a in) or NULL if there are no active outputs
1598cae8b89aSjeremylt   @param request   Address of CeedRequest for non-blocking completion, else
15994cc79fe7SJed Brown                      @ref CEED_REQUEST_IMMEDIATE
1600cae8b89aSjeremylt 
1601cae8b89aSjeremylt   @return An error code: 0 - success, otherwise - failure
1602cae8b89aSjeremylt 
16037a982d89SJeremy L. Thompson   @ref User
1604cae8b89aSjeremylt **/
1605cae8b89aSjeremylt int CeedOperatorApplyAdd(CeedOperator op, CeedVector in, CeedVector out,
1606cae8b89aSjeremylt                          CeedRequest *request) {
1607cae8b89aSjeremylt   int ierr;
1608e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
1609cae8b89aSjeremylt 
1610d1d35e2fSjeremylt   if (op->num_elem)  {
1611250756a7Sjeremylt     // Standard Operator
1612250756a7Sjeremylt     ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr);
1613f04ea552SJeremy L Thompson   } else if (op->is_composite) {
1614250756a7Sjeremylt     // Composite Operator
1615250756a7Sjeremylt     if (op->ApplyAddComposite) {
1616250756a7Sjeremylt       ierr = op->ApplyAddComposite(op, in, out, request); CeedChk(ierr);
1617cae8b89aSjeremylt     } else {
1618d1d35e2fSjeremylt       CeedInt num_suboperators;
1619d1d35e2fSjeremylt       ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr);
1620d1d35e2fSjeremylt       CeedOperator *sub_operators;
1621d1d35e2fSjeremylt       ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr);
1622250756a7Sjeremylt 
1623d1d35e2fSjeremylt       for (CeedInt i=0; i<num_suboperators; i++) {
1624d1d35e2fSjeremylt         ierr = CeedOperatorApplyAdd(sub_operators[i], in, out, request);
1625cae8b89aSjeremylt         CeedChk(ierr);
16261d7d2407SJeremy L Thompson       }
1627250756a7Sjeremylt     }
1628250756a7Sjeremylt   }
1629e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1630d7b241e6Sjeremylt }
1631d7b241e6Sjeremylt 
1632d7b241e6Sjeremylt /**
1633b11c1e72Sjeremylt   @brief Destroy a CeedOperator
1634d7b241e6Sjeremylt 
1635d7b241e6Sjeremylt   @param op  CeedOperator to destroy
1636b11c1e72Sjeremylt 
1637b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
1638dfdf5a53Sjeremylt 
16397a982d89SJeremy L. Thompson   @ref User
1640b11c1e72Sjeremylt **/
1641d7b241e6Sjeremylt int CeedOperatorDestroy(CeedOperator *op) {
1642d7b241e6Sjeremylt   int ierr;
1643d7b241e6Sjeremylt 
1644d1d35e2fSjeremylt   if (!*op || --(*op)->ref_count > 0) return CEED_ERROR_SUCCESS;
1645d7b241e6Sjeremylt   if ((*op)->Destroy) {
1646d7b241e6Sjeremylt     ierr = (*op)->Destroy(*op); CeedChk(ierr);
1647d7b241e6Sjeremylt   }
1648fe2413ffSjeremylt   ierr = CeedDestroy(&(*op)->ceed); CeedChk(ierr);
1649fe2413ffSjeremylt   // Free fields
16503668ca4bSJeremy L Thompson   for (CeedInt i=0; i<(*op)->num_fields; i++)
1651d1d35e2fSjeremylt     if ((*op)->input_fields[i]) {
1652d1d35e2fSjeremylt       if ((*op)->input_fields[i]->elem_restr != CEED_ELEMRESTRICTION_NONE) {
1653d1d35e2fSjeremylt         ierr = CeedElemRestrictionDestroy(&(*op)->input_fields[i]->elem_restr);
165471352a93Sjeremylt         CeedChk(ierr);
165515910d16Sjeremylt       }
1656d1d35e2fSjeremylt       if ((*op)->input_fields[i]->basis != CEED_BASIS_COLLOCATED) {
1657d1d35e2fSjeremylt         ierr = CeedBasisDestroy(&(*op)->input_fields[i]->basis); CeedChk(ierr);
165871352a93Sjeremylt       }
1659d1d35e2fSjeremylt       if ((*op)->input_fields[i]->vec != CEED_VECTOR_ACTIVE &&
1660d1d35e2fSjeremylt           (*op)->input_fields[i]->vec != CEED_VECTOR_NONE ) {
1661d1d35e2fSjeremylt         ierr = CeedVectorDestroy(&(*op)->input_fields[i]->vec); CeedChk(ierr);
166271352a93Sjeremylt       }
1663d1d35e2fSjeremylt       ierr = CeedFree(&(*op)->input_fields[i]->field_name); CeedChk(ierr);
1664d1d35e2fSjeremylt       ierr = CeedFree(&(*op)->input_fields[i]); CeedChk(ierr);
1665fe2413ffSjeremylt     }
16663668ca4bSJeremy L Thompson   for (CeedInt i=0; i<(*op)->num_fields; i++)
1667d1d35e2fSjeremylt     if ((*op)->output_fields[i]) {
1668d1d35e2fSjeremylt       ierr = CeedElemRestrictionDestroy(&(*op)->output_fields[i]->elem_restr);
166971352a93Sjeremylt       CeedChk(ierr);
1670d1d35e2fSjeremylt       if ((*op)->output_fields[i]->basis != CEED_BASIS_COLLOCATED) {
1671d1d35e2fSjeremylt         ierr = CeedBasisDestroy(&(*op)->output_fields[i]->basis); CeedChk(ierr);
167271352a93Sjeremylt       }
1673d1d35e2fSjeremylt       if ((*op)->output_fields[i]->vec != CEED_VECTOR_ACTIVE &&
1674d1d35e2fSjeremylt           (*op)->output_fields[i]->vec != CEED_VECTOR_NONE ) {
1675d1d35e2fSjeremylt         ierr = CeedVectorDestroy(&(*op)->output_fields[i]->vec); CeedChk(ierr);
167671352a93Sjeremylt       }
1677d1d35e2fSjeremylt       ierr = CeedFree(&(*op)->output_fields[i]->field_name); CeedChk(ierr);
1678d1d35e2fSjeremylt       ierr = CeedFree(&(*op)->output_fields[i]); CeedChk(ierr);
1679fe2413ffSjeremylt     }
1680d1d35e2fSjeremylt   // Destroy sub_operators
16813668ca4bSJeremy L Thompson   for (CeedInt i=0; i<(*op)->num_suboperators; i++)
1682d1d35e2fSjeremylt     if ((*op)->sub_operators[i]) {
1683d1d35e2fSjeremylt       ierr = CeedOperatorDestroy(&(*op)->sub_operators[i]); CeedChk(ierr);
168452d6035fSJeremy L Thompson     }
1685d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->qf); CeedChk(ierr);
1686d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->dqf); CeedChk(ierr);
1687d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->dqfT); CeedChk(ierr);
16883668ca4bSJeremy L Thompson   // Destroy any composite labels
16893668ca4bSJeremy L Thompson   for (CeedInt i=0; i<(*op)->num_context_labels; i++) {
16903668ca4bSJeremy L Thompson     ierr = CeedFree(&(*op)->context_labels[i]->sub_labels); CeedChk(ierr);
16913668ca4bSJeremy L Thompson     ierr = CeedFree(&(*op)->context_labels[i]); CeedChk(ierr);
16923668ca4bSJeremy L Thompson   }
16933668ca4bSJeremy L Thompson   ierr = CeedFree(&(*op)->context_labels); CeedChk(ierr);
1694fe2413ffSjeremylt 
16955107b09fSJeremy L Thompson   // Destroy fallback
1696805fe78eSJeremy L Thompson   ierr = CeedOperatorDestroy(&(*op)->op_fallback); CeedChk(ierr);
16975107b09fSJeremy L Thompson 
169870a7ffb3SJeremy L Thompson   // Destroy QF assembly cache
1699480fae85SJeremy L Thompson   ierr = CeedQFunctionAssemblyDataDestroy(&(*op)->qf_assembled); CeedChk(ierr);
170070a7ffb3SJeremy L Thompson 
1701d1d35e2fSjeremylt   ierr = CeedFree(&(*op)->input_fields); CeedChk(ierr);
1702d1d35e2fSjeremylt   ierr = CeedFree(&(*op)->output_fields); CeedChk(ierr);
1703d1d35e2fSjeremylt   ierr = CeedFree(&(*op)->sub_operators); CeedChk(ierr);
1704ea6b5821SJeremy L Thompson   ierr = CeedFree(&(*op)->name); CeedChk(ierr);
1705d7b241e6Sjeremylt   ierr = CeedFree(op); CeedChk(ierr);
1706e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1707d7b241e6Sjeremylt }
1708d7b241e6Sjeremylt 
1709d7b241e6Sjeremylt /// @}
1710