xref: /libCEED/rust/libceed-sys/c-src/interface/ceed-operator.c (revision 2b730f8b5a9c809740a0b3b302db43a719c636b1)
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 
83d576824SJeremy L Thompson #include <ceed-impl.h>
9*2b730f8bSJeremy L Thompson #include <ceed/backend.h>
10*2b730f8bSJeremy L Thompson #include <ceed/ceed.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 **/
36*2b730f8bSJeremy L Thompson static int CeedOperatorCheckField(Ceed ceed, CeedQFunctionField qf_field, CeedElemRestriction r, CeedBasis b) {
37d1d35e2fSjeremylt   CeedEvalMode eval_mode = qf_field->eval_mode;
38*2b730f8bSJeremy L Thompson   CeedInt      dim = 1, num_comp = 1, Q_comp = 1, restr_num_comp = 1, size = qf_field->size;
39*2b730f8bSJeremy L Thompson 
40e15f9bd0SJeremy L Thompson   // Restriction
41e15f9bd0SJeremy L Thompson   if (r != CEED_ELEMRESTRICTION_NONE) {
42d1d35e2fSjeremylt     if (eval_mode == CEED_EVAL_WEIGHT) {
43e15f9bd0SJeremy L Thompson       // LCOV_EXCL_START
44*2b730f8bSJeremy L Thompson       return CeedError(ceed, CEED_ERROR_INCOMPATIBLE, "CEED_ELEMRESTRICTION_NONE should be used for a field with eval mode CEED_EVAL_WEIGHT");
45e15f9bd0SJeremy L Thompson       // LCOV_EXCL_STOP
46e15f9bd0SJeremy L Thompson     }
47*2b730f8bSJeremy L Thompson     CeedCall(CeedElemRestrictionGetNumComponents(r, &restr_num_comp));
48e1e9e29dSJed Brown   }
49d1d35e2fSjeremylt   if ((r == CEED_ELEMRESTRICTION_NONE) != (eval_mode == CEED_EVAL_WEIGHT)) {
50e1e9e29dSJed Brown     // LCOV_EXCL_START
51*2b730f8bSJeremy L Thompson     return CeedError(ceed, CEED_ERROR_INCOMPATIBLE, "CEED_ELEMRESTRICTION_NONE and CEED_EVAL_WEIGHT must be used together.");
52e1e9e29dSJed Brown     // LCOV_EXCL_STOP
53e1e9e29dSJed Brown   }
54e15f9bd0SJeremy L Thompson   // Basis
55e15f9bd0SJeremy L Thompson   if (b != CEED_BASIS_COLLOCATED) {
56*2b730f8bSJeremy L Thompson     if (eval_mode == CEED_EVAL_NONE) {
578229195eSjeremylt       // LCOV_EXCL_START
58*2b730f8bSJeremy L Thompson       return CeedError(ceed, CEED_ERROR_INCOMPATIBLE, "Field '%s' configured with CEED_EVAL_NONE must be used with CEED_BASIS_COLLOCATED",
59d1d35e2fSjeremylt                        qf_field->field_name);
6041bdf1c9SJeremy L Thompson       // LCOV_EXCL_STOP
61*2b730f8bSJeremy L Thompson     }
62*2b730f8bSJeremy L Thompson     CeedCall(CeedBasisGetDimension(b, &dim));
63*2b730f8bSJeremy L Thompson     CeedCall(CeedBasisGetNumComponents(b, &num_comp));
64*2b730f8bSJeremy L Thompson     CeedCall(CeedBasisGetNumQuadratureComponents(b, &Q_comp));
65d1d35e2fSjeremylt     if (r != CEED_ELEMRESTRICTION_NONE && restr_num_comp != num_comp) {
66e15f9bd0SJeremy L Thompson       // LCOV_EXCL_START
67e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_DIMENSION,
68*2b730f8bSJeremy L Thompson                        "Field '%s' of size %" CeedInt_FMT " and EvalMode %s: ElemRestriction has %" CeedInt_FMT
69*2b730f8bSJeremy L Thompson                        " components, but Basis has %" CeedInt_FMT " components",
70*2b730f8bSJeremy L Thompson                        qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode], restr_num_comp, num_comp);
71e15f9bd0SJeremy L Thompson       // LCOV_EXCL_STOP
72e15f9bd0SJeremy L Thompson     }
7341bdf1c9SJeremy L Thompson   } else if (eval_mode != CEED_EVAL_NONE) {
7441bdf1c9SJeremy L Thompson     // LCOV_EXCL_START
75*2b730f8bSJeremy L Thompson     return CeedError(ceed, CEED_ERROR_INCOMPATIBLE, "Field '%s' configured with %s cannot be used with CEED_BASIS_COLLOCATED", qf_field->field_name,
76*2b730f8bSJeremy L Thompson                      CeedEvalModes[eval_mode]);
7741bdf1c9SJeremy L Thompson     // LCOV_EXCL_STOP
78e15f9bd0SJeremy L Thompson   }
79e15f9bd0SJeremy L Thompson   // Field size
80d1d35e2fSjeremylt   switch (eval_mode) {
81e15f9bd0SJeremy L Thompson     case CEED_EVAL_NONE:
82*2b730f8bSJeremy L Thompson       if (size != restr_num_comp) {
83e15f9bd0SJeremy L Thompson         // LCOV_EXCL_START
84e15f9bd0SJeremy L Thompson         return CeedError(ceed, CEED_ERROR_DIMENSION,
85*2b730f8bSJeremy L Thompson                          "Field '%s' of size %" CeedInt_FMT " and EvalMode %s: ElemRestriction has " CeedInt_FMT " components", qf_field->field_name,
86*2b730f8bSJeremy L Thompson                          qf_field->size, CeedEvalModes[qf_field->eval_mode], restr_num_comp);
87e15f9bd0SJeremy L Thompson         // LCOV_EXCL_STOP
88*2b730f8bSJeremy L Thompson       }
89e15f9bd0SJeremy L Thompson       break;
90e15f9bd0SJeremy L Thompson     case CEED_EVAL_INTERP:
91*2b730f8bSJeremy L Thompson       if (size != num_comp * Q_comp) {
92e15f9bd0SJeremy L Thompson         // LCOV_EXCL_START
93e15f9bd0SJeremy L Thompson         return CeedError(ceed, CEED_ERROR_DIMENSION,
94*2b730f8bSJeremy L Thompson                          "Field '%s' of size %" CeedInt_FMT " and EvalMode %s: ElemRestriction/Basis has " CeedInt_FMT " components",
95*2b730f8bSJeremy L Thompson                          qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode], num_comp * Q_comp);
96e15f9bd0SJeremy L Thompson         // LCOV_EXCL_STOP
97*2b730f8bSJeremy L Thompson       }
98e15f9bd0SJeremy L Thompson       break;
99e15f9bd0SJeremy L Thompson     case CEED_EVAL_GRAD:
100*2b730f8bSJeremy L Thompson       if (size != num_comp * dim) {
101e15f9bd0SJeremy L Thompson         // LCOV_EXCL_START
102e15f9bd0SJeremy L Thompson         return CeedError(ceed, CEED_ERROR_DIMENSION,
103*2b730f8bSJeremy L Thompson                          "Field '%s' of size %" CeedInt_FMT " and EvalMode %s in %" CeedInt_FMT " dimensions: ElemRestriction/Basis has %" CeedInt_FMT
104*2b730f8bSJeremy L Thompson                          " components",
105*2b730f8bSJeremy L Thompson                          qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode], dim, num_comp);
106e15f9bd0SJeremy L Thompson         // LCOV_EXCL_STOP
107*2b730f8bSJeremy L Thompson       }
108e15f9bd0SJeremy L Thompson       break;
109e15f9bd0SJeremy L Thompson     case CEED_EVAL_WEIGHT:
110d1d35e2fSjeremylt       // No additional checks required
111e15f9bd0SJeremy L Thompson       break;
112e15f9bd0SJeremy L Thompson     case CEED_EVAL_DIV:
113*2b730f8bSJeremy L Thompson       if (size != num_comp) {
114a0c16c2cSrezgarshakeri         // LCOV_EXCL_START
115a0c16c2cSrezgarshakeri         return CeedError(ceed, CEED_ERROR_DIMENSION,
116*2b730f8bSJeremy L Thompson                          "Field '%s' of size %" CeedInt_FMT " and EvalMode %s: ElemRestriction/Basis has " CeedInt_FMT " components",
117*2b730f8bSJeremy L Thompson                          qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode], num_comp);
118a0c16c2cSrezgarshakeri         // LCOV_EXCL_STOP
119*2b730f8bSJeremy L Thompson       }
120e15f9bd0SJeremy L Thompson       break;
121e15f9bd0SJeremy L Thompson     case CEED_EVAL_CURL:
122e15f9bd0SJeremy L Thompson       // Not implemented
123e15f9bd0SJeremy L Thompson       break;
124e15f9bd0SJeremy L Thompson   }
125e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1267a982d89SJeremy L. Thompson }
1277a982d89SJeremy L. Thompson 
1287a982d89SJeremy L. Thompson /**
1297a982d89SJeremy L. Thompson   @brief View a field of a CeedOperator
1307a982d89SJeremy L. Thompson 
1317a982d89SJeremy L. Thompson   @param[in] field         Operator field to view
132d1d35e2fSjeremylt   @param[in] qf_field      QFunction field (carries field name)
133d1d35e2fSjeremylt   @param[in] field_number  Number of field being viewed
1344c4400c7SValeria Barra   @param[in] sub           true indicates sub-operator, which increases indentation; false for top-level operator
135d1d35e2fSjeremylt   @param[in] input         true for an input field; false for output field
1367a982d89SJeremy L. Thompson   @param[in] stream        Stream to view to, e.g., stdout
1377a982d89SJeremy L. Thompson 
1387a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
1397a982d89SJeremy L. Thompson 
1407a982d89SJeremy L. Thompson   @ref Utility
1417a982d89SJeremy L. Thompson **/
142*2b730f8bSJeremy L Thompson static int CeedOperatorFieldView(CeedOperatorField field, CeedQFunctionField qf_field, CeedInt field_number, bool sub, bool input, FILE *stream) {
1437a982d89SJeremy L. Thompson   const char *pre    = sub ? "  " : "";
144d1d35e2fSjeremylt   const char *in_out = input ? "Input" : "Output";
1457a982d89SJeremy L. Thompson 
146*2b730f8bSJeremy L Thompson   fprintf(stream,
147*2b730f8bSJeremy L Thompson           "%s    %s field %" CeedInt_FMT
148*2b730f8bSJeremy L Thompson           ":\n"
1497a982d89SJeremy L. Thompson           "%s      Name: \"%s\"\n",
150d1d35e2fSjeremylt           pre, in_out, field_number, pre, qf_field->field_name);
1517a982d89SJeremy L. Thompson 
152990fdeb6SJeremy L Thompson   fprintf(stream, "%s      Size: %" CeedInt_FMT "\n", pre, qf_field->size);
153f5ebfb90SJeremy L Thompson 
154*2b730f8bSJeremy L Thompson   fprintf(stream, "%s      EvalMode: %s\n", pre, CeedEvalModes[qf_field->eval_mode]);
155f5ebfb90SJeremy L Thompson 
156*2b730f8bSJeremy L Thompson   if (field->basis == CEED_BASIS_COLLOCATED) fprintf(stream, "%s      Collocated basis\n", pre);
1577a982d89SJeremy L. Thompson 
158*2b730f8bSJeremy L Thompson   if (field->vec == CEED_VECTOR_ACTIVE) fprintf(stream, "%s      Active vector\n", pre);
159*2b730f8bSJeremy L Thompson   else if (field->vec == CEED_VECTOR_NONE) fprintf(stream, "%s      No vector\n", pre);
160f5ebfb90SJeremy L Thompson 
161e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1627a982d89SJeremy L. Thompson }
1637a982d89SJeremy L. Thompson 
1647a982d89SJeremy L. Thompson /**
1657a982d89SJeremy L. Thompson   @brief View a single CeedOperator
1667a982d89SJeremy L. Thompson 
1677a982d89SJeremy L. Thompson   @param[in] op      CeedOperator to view
1687a982d89SJeremy L. Thompson   @param[in] sub     Boolean flag for sub-operator
1697a982d89SJeremy L. Thompson   @param[in] stream  Stream to write; typically stdout/stderr or a file
1707a982d89SJeremy L. Thompson 
1717a982d89SJeremy L. Thompson   @return Error code: 0 - success, otherwise - failure
1727a982d89SJeremy L. Thompson 
1737a982d89SJeremy L. Thompson   @ref Utility
1747a982d89SJeremy L. Thompson **/
1757a982d89SJeremy L. Thompson int CeedOperatorSingleView(CeedOperator op, bool sub, FILE *stream) {
1767a982d89SJeremy L. Thompson   const char *pre = sub ? "  " : "";
1777a982d89SJeremy L. Thompson 
178381e6593SJeremy L Thompson   CeedInt num_elem, num_qpts;
179*2b730f8bSJeremy L Thompson   CeedCall(CeedOperatorGetNumElements(op, &num_elem));
180*2b730f8bSJeremy L Thompson   CeedCall(CeedOperatorGetNumQuadraturePoints(op, &num_qpts));
181381e6593SJeremy L Thompson 
18278464608Sjeremylt   CeedInt total_fields = 0;
183*2b730f8bSJeremy L Thompson   CeedCall(CeedOperatorGetNumArgs(op, &total_fields));
184*2b730f8bSJeremy L Thompson   fprintf(stream, "%s  %" CeedInt_FMT " elements with %" CeedInt_FMT " quadrature points each\n", pre, num_elem, num_qpts);
1857a982d89SJeremy L. Thompson 
186*2b730f8bSJeremy L Thompson   fprintf(stream, "%s  %" CeedInt_FMT " field%s\n", pre, total_fields, total_fields > 1 ? "s" : "");
1877a982d89SJeremy L. Thompson 
188*2b730f8bSJeremy L Thompson   fprintf(stream, "%s  %" CeedInt_FMT " input field%s:\n", pre, op->qf->num_input_fields, op->qf->num_input_fields > 1 ? "s" : "");
189d1d35e2fSjeremylt   for (CeedInt i = 0; i < op->qf->num_input_fields; i++) {
190*2b730f8bSJeremy L Thompson     CeedCall(CeedOperatorFieldView(op->input_fields[i], op->qf->input_fields[i], i, sub, 1, stream));
1917a982d89SJeremy L. Thompson   }
1927a982d89SJeremy L. Thompson 
193*2b730f8bSJeremy L Thompson   fprintf(stream, "%s  %" CeedInt_FMT " output field%s:\n", pre, op->qf->num_output_fields, op->qf->num_output_fields > 1 ? "s" : "");
194d1d35e2fSjeremylt   for (CeedInt i = 0; i < op->qf->num_output_fields; i++) {
195*2b730f8bSJeremy L Thompson     CeedCall(CeedOperatorFieldView(op->output_fields[i], op->qf->output_fields[i], i, sub, 0, stream));
1967a982d89SJeremy L. Thompson   }
197e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1987a982d89SJeremy L. Thompson }
1997a982d89SJeremy L. Thompson 
200d99fa3c5SJeremy L Thompson /**
2010f60e0a8SJeremy L Thompson   @brief Find the active vector basis for a non-composite CeedOperator
202eaf62fffSJeremy L Thompson 
203eaf62fffSJeremy L Thompson   @param[in] op             CeedOperator to find active basis for
2040f60e0a8SJeremy L Thompson   @param[out] active_basis  Basis for active input vector or NULL for composite operator
205eaf62fffSJeremy L Thompson 
206eaf62fffSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
207eaf62fffSJeremy L Thompson 
208eaf62fffSJeremy L Thompson   @ ref Developer
209eaf62fffSJeremy L Thompson **/
210eaf62fffSJeremy L Thompson int CeedOperatorGetActiveBasis(CeedOperator op, CeedBasis *active_basis) {
211eaf62fffSJeremy L Thompson   *active_basis = NULL;
2120f60e0a8SJeremy L Thompson   if (op->is_composite) return CEED_ERROR_SUCCESS;
213*2b730f8bSJeremy L Thompson   for (CeedInt i = 0; i < op->qf->num_input_fields; i++) {
214eaf62fffSJeremy L Thompson     if (op->input_fields[i]->vec == CEED_VECTOR_ACTIVE) {
215eaf62fffSJeremy L Thompson       *active_basis = op->input_fields[i]->basis;
216eaf62fffSJeremy L Thompson       break;
217eaf62fffSJeremy L Thompson     }
218*2b730f8bSJeremy L Thompson   }
219eaf62fffSJeremy L Thompson 
220eaf62fffSJeremy L Thompson   if (!*active_basis) {
221eaf62fffSJeremy L Thompson     // LCOV_EXCL_START
222eaf62fffSJeremy L Thompson     Ceed ceed;
223*2b730f8bSJeremy L Thompson 
224*2b730f8bSJeremy L Thompson     CeedCall(CeedOperatorGetCeed(op, &ceed));
225*2b730f8bSJeremy L Thompson     return CeedError(ceed, CEED_ERROR_MINOR, "No active CeedBasis found");
226eaf62fffSJeremy L Thompson     // LCOV_EXCL_STOP
227eaf62fffSJeremy L Thompson   }
228eaf62fffSJeremy L Thompson   return CEED_ERROR_SUCCESS;
229eaf62fffSJeremy L Thompson }
230eaf62fffSJeremy L Thompson 
231eaf62fffSJeremy L Thompson /**
2320f60e0a8SJeremy L Thompson   @brief Find the active vector ElemRestriction for a non-composite CeedOperator
233e2f04181SAndrew T. Barker 
234e2f04181SAndrew T. Barker   @param[in] op            CeedOperator to find active basis for
2350f60e0a8SJeremy L Thompson   @param[out] active_rstr  ElemRestriction for active input vector or NULL for composite operator
236e2f04181SAndrew T. Barker 
237e2f04181SAndrew T. Barker   @return An error code: 0 - success, otherwise - failure
238e2f04181SAndrew T. Barker 
239e2f04181SAndrew T. Barker   @ref Utility
240e2f04181SAndrew T. Barker **/
241*2b730f8bSJeremy L Thompson int CeedOperatorGetActiveElemRestriction(CeedOperator op, CeedElemRestriction *active_rstr) {
242d1d35e2fSjeremylt   *active_rstr = NULL;
2430f60e0a8SJeremy L Thompson   if (op->is_composite) return CEED_ERROR_SUCCESS;
244*2b730f8bSJeremy L Thompson   for (CeedInt i = 0; i < op->qf->num_input_fields; i++) {
245d1d35e2fSjeremylt     if (op->input_fields[i]->vec == CEED_VECTOR_ACTIVE) {
246d1d35e2fSjeremylt       *active_rstr = op->input_fields[i]->elem_restr;
247e2f04181SAndrew T. Barker       break;
248e2f04181SAndrew T. Barker     }
249*2b730f8bSJeremy L Thompson   }
250e2f04181SAndrew T. Barker 
251d1d35e2fSjeremylt   if (!*active_rstr) {
252e2f04181SAndrew T. Barker     // LCOV_EXCL_START
253e2f04181SAndrew T. Barker     Ceed ceed;
254*2b730f8bSJeremy L Thompson 
255*2b730f8bSJeremy L Thompson     CeedCall(CeedOperatorGetCeed(op, &ceed));
256*2b730f8bSJeremy L Thompson     return CeedError(ceed, CEED_ERROR_INCOMPLETE, "No active CeedElemRestriction found");
257e2f04181SAndrew T. Barker     // LCOV_EXCL_STOP
258e2f04181SAndrew T. Barker   }
259e2f04181SAndrew T. Barker   return CEED_ERROR_SUCCESS;
260e2f04181SAndrew T. Barker }
261e2f04181SAndrew T. Barker 
262d8dd9a91SJeremy L Thompson /**
263d8dd9a91SJeremy L Thompson   @brief Set QFunctionContext field value of the specified type.
264d8dd9a91SJeremy L Thompson            For composite operators, the value is set in all
265d8dd9a91SJeremy L Thompson            sub-operator QFunctionContexts that have a matching `field_name`.
266d8dd9a91SJeremy L Thompson            A non-zero error code is returned for single operators
267d8dd9a91SJeremy L Thompson            that do not have a matching field of the same type or composite
268d8dd9a91SJeremy L Thompson            operators that do not have any field of a matching type.
269d8dd9a91SJeremy L Thompson 
270d8dd9a91SJeremy L Thompson   @param op          CeedOperator
2713668ca4bSJeremy L Thompson   @param field_label Label of field to set
272d8dd9a91SJeremy L Thompson   @param field_type  Type of field to set
273d8dd9a91SJeremy L Thompson   @param value       Value to set
274d8dd9a91SJeremy L Thompson 
275d8dd9a91SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
276d8dd9a91SJeremy L Thompson 
277d8dd9a91SJeremy L Thompson   @ref User
278d8dd9a91SJeremy L Thompson **/
279*2b730f8bSJeremy L Thompson static int CeedOperatorContextSetGeneric(CeedOperator op, CeedContextFieldLabel field_label, CeedContextFieldType field_type, void *value) {
280*2b730f8bSJeremy L Thompson   if (!field_label) {
2813668ca4bSJeremy L Thompson     // LCOV_EXCL_START
282*2b730f8bSJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED, "Invalid field label");
2833668ca4bSJeremy L Thompson     // LCOV_EXCL_STOP
284*2b730f8bSJeremy L Thompson   }
2853668ca4bSJeremy L Thompson 
2863668ca4bSJeremy L Thompson   bool is_composite = false;
287*2b730f8bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
288d8dd9a91SJeremy L Thompson   if (is_composite) {
289d8dd9a91SJeremy L Thompson     CeedInt       num_sub;
290d8dd9a91SJeremy L Thompson     CeedOperator *sub_operators;
291d8dd9a91SJeremy L Thompson 
292*2b730f8bSJeremy L Thompson     CeedCall(CeedOperatorGetNumSub(op, &num_sub));
293*2b730f8bSJeremy L Thompson     CeedCall(CeedOperatorGetSubList(op, &sub_operators));
294*2b730f8bSJeremy L Thompson     if (num_sub != field_label->num_sub_labels) {
2953668ca4bSJeremy L Thompson       // LCOV_EXCL_START
2963668ca4bSJeremy L Thompson       return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED,
297*2b730f8bSJeremy L Thompson                        "ContextLabel does not correspond to composite operator. Use CeedOperatorGetContextFieldLabel().");
2983668ca4bSJeremy L Thompson       // LCOV_EXCL_STOP
299*2b730f8bSJeremy L Thompson     }
300d8dd9a91SJeremy L Thompson 
301d8dd9a91SJeremy L Thompson     for (CeedInt i = 0; i < num_sub; i++) {
302d8dd9a91SJeremy L Thompson       // Try every sub-operator, ok if some sub-operators do not have field
3033668ca4bSJeremy L Thompson       if (field_label->sub_labels[i] && sub_operators[i]->qf->ctx) {
304*2b730f8bSJeremy L Thompson         CeedCall(CeedQFunctionContextSetGeneric(sub_operators[i]->qf->ctx, field_label->sub_labels[i], field_type, value));
305d8dd9a91SJeremy L Thompson       }
306d8dd9a91SJeremy L Thompson     }
307d8dd9a91SJeremy L Thompson   } else {
308*2b730f8bSJeremy L Thompson     if (!op->qf->ctx) {
309d8dd9a91SJeremy L Thompson       // LCOV_EXCL_START
310*2b730f8bSJeremy L Thompson       return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED, "QFunction does not have context data");
311d8dd9a91SJeremy L Thompson       // LCOV_EXCL_STOP
312*2b730f8bSJeremy L Thompson     }
313d8dd9a91SJeremy L Thompson 
314*2b730f8bSJeremy L Thompson     CeedCall(CeedQFunctionContextSetGeneric(op->qf->ctx, field_label, field_type, value));
315d8dd9a91SJeremy L Thompson   }
316d8dd9a91SJeremy L Thompson 
317d8dd9a91SJeremy L Thompson   return CEED_ERROR_SUCCESS;
318d8dd9a91SJeremy L Thompson }
319d8dd9a91SJeremy L Thompson 
3207a982d89SJeremy L. Thompson /// @}
3217a982d89SJeremy L. Thompson 
3227a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
3237a982d89SJeremy L. Thompson /// CeedOperator Backend API
3247a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
3257a982d89SJeremy L. Thompson /// @addtogroup CeedOperatorBackend
3267a982d89SJeremy L. Thompson /// @{
3277a982d89SJeremy L. Thompson 
3287a982d89SJeremy L. Thompson /**
3297a982d89SJeremy L. Thompson   @brief Get the number of arguments associated with a CeedOperator
3307a982d89SJeremy L. Thompson 
3317a982d89SJeremy L. Thompson   @param op             CeedOperator
332d1d35e2fSjeremylt   @param[out] num_args  Variable to store vector number of arguments
3337a982d89SJeremy L. Thompson 
3347a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
3357a982d89SJeremy L. Thompson 
3367a982d89SJeremy L. Thompson   @ref Backend
3377a982d89SJeremy L. Thompson **/
3387a982d89SJeremy L. Thompson 
339d1d35e2fSjeremylt int CeedOperatorGetNumArgs(CeedOperator op, CeedInt *num_args) {
340*2b730f8bSJeremy L Thompson   if (op->is_composite) {
3417a982d89SJeremy L. Thompson     // LCOV_EXCL_START
342*2b730f8bSJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR, "Not defined for composite operators");
3437a982d89SJeremy L. Thompson     // LCOV_EXCL_STOP
344*2b730f8bSJeremy L Thompson   }
345d1d35e2fSjeremylt   *num_args = op->num_fields;
346e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
3477a982d89SJeremy L. Thompson }
3487a982d89SJeremy L. Thompson 
3497a982d89SJeremy L. Thompson /**
3507a982d89SJeremy L. Thompson   @brief Get the setup status of a CeedOperator
3517a982d89SJeremy L. Thompson 
3527a982d89SJeremy L. Thompson   @param op                  CeedOperator
353d1d35e2fSjeremylt   @param[out] is_setup_done  Variable to store setup status
3547a982d89SJeremy L. Thompson 
3557a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
3567a982d89SJeremy L. Thompson 
3577a982d89SJeremy L. Thompson   @ref Backend
3587a982d89SJeremy L. Thompson **/
3597a982d89SJeremy L. Thompson 
360d1d35e2fSjeremylt int CeedOperatorIsSetupDone(CeedOperator op, bool *is_setup_done) {
361f04ea552SJeremy L Thompson   *is_setup_done = op->is_backend_setup;
362e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
3637a982d89SJeremy L. Thompson }
3647a982d89SJeremy L. Thompson 
3657a982d89SJeremy L. Thompson /**
3667a982d89SJeremy L. Thompson   @brief Get the QFunction associated with a CeedOperator
3677a982d89SJeremy L. Thompson 
3687a982d89SJeremy L. Thompson   @param op       CeedOperator
3697a982d89SJeremy L. Thompson   @param[out] qf  Variable to store QFunction
3707a982d89SJeremy L. Thompson 
3717a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
3727a982d89SJeremy L. Thompson 
3737a982d89SJeremy L. Thompson   @ref Backend
3747a982d89SJeremy L. Thompson **/
3757a982d89SJeremy L. Thompson 
3767a982d89SJeremy L. Thompson int CeedOperatorGetQFunction(CeedOperator op, CeedQFunction *qf) {
377*2b730f8bSJeremy L Thompson   if (op->is_composite) {
3787a982d89SJeremy L. Thompson     // LCOV_EXCL_START
379*2b730f8bSJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR, "Not defined for composite operator");
3807a982d89SJeremy L. Thompson     // LCOV_EXCL_STOP
381*2b730f8bSJeremy L Thompson   }
3827a982d89SJeremy L. Thompson   *qf = op->qf;
383e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
3847a982d89SJeremy L. Thompson }
3857a982d89SJeremy L. Thompson 
3867a982d89SJeremy L. Thompson /**
387c04a41a7SJeremy L Thompson   @brief Get a boolean value indicating if the CeedOperator is composite
388c04a41a7SJeremy L Thompson 
389c04a41a7SJeremy L Thompson   @param op                 CeedOperator
390d1d35e2fSjeremylt   @param[out] is_composite  Variable to store composite status
391c04a41a7SJeremy L Thompson 
392c04a41a7SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
393c04a41a7SJeremy L Thompson 
394c04a41a7SJeremy L Thompson   @ref Backend
395c04a41a7SJeremy L Thompson **/
396c04a41a7SJeremy L Thompson 
397d1d35e2fSjeremylt int CeedOperatorIsComposite(CeedOperator op, bool *is_composite) {
398f04ea552SJeremy L Thompson   *is_composite = op->is_composite;
399e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
400c04a41a7SJeremy L Thompson }
401c04a41a7SJeremy L Thompson 
402c04a41a7SJeremy L Thompson /**
403d1d35e2fSjeremylt   @brief Get the number of sub_operators associated with a CeedOperator
4047a982d89SJeremy L. Thompson 
4057a982d89SJeremy L. Thompson   @param op                     CeedOperator
406d1d35e2fSjeremylt   @param[out] num_suboperators  Variable to store number of sub_operators
4077a982d89SJeremy L. Thompson 
4087a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
4097a982d89SJeremy L. Thompson 
4107a982d89SJeremy L. Thompson   @ref Backend
4117a982d89SJeremy L. Thompson **/
4127a982d89SJeremy L. Thompson 
413d1d35e2fSjeremylt int CeedOperatorGetNumSub(CeedOperator op, CeedInt *num_suboperators) {
414*2b730f8bSJeremy L Thompson   if (!op->is_composite) {
4157a982d89SJeremy L. Thompson     // LCOV_EXCL_START
416e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR, "Not a composite operator");
4177a982d89SJeremy L. Thompson     // LCOV_EXCL_STOP
418*2b730f8bSJeremy L Thompson   }
419d1d35e2fSjeremylt   *num_suboperators = op->num_suboperators;
420e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
4217a982d89SJeremy L. Thompson }
4227a982d89SJeremy L. Thompson 
4237a982d89SJeremy L. Thompson /**
424d1d35e2fSjeremylt   @brief Get the list of sub_operators associated with a CeedOperator
4257a982d89SJeremy L. Thompson 
4267a982d89SJeremy L. Thompson   @param op                  CeedOperator
427d1d35e2fSjeremylt   @param[out] sub_operators  Variable to store list of sub_operators
4287a982d89SJeremy L. Thompson 
4297a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
4307a982d89SJeremy L. Thompson 
4317a982d89SJeremy L. Thompson   @ref Backend
4327a982d89SJeremy L. Thompson **/
4337a982d89SJeremy L. Thompson 
434d1d35e2fSjeremylt int CeedOperatorGetSubList(CeedOperator op, CeedOperator **sub_operators) {
435*2b730f8bSJeremy L Thompson   if (!op->is_composite) {
4367a982d89SJeremy L. Thompson     // LCOV_EXCL_START
437e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR, "Not a composite operator");
4387a982d89SJeremy L. Thompson     // LCOV_EXCL_STOP
439*2b730f8bSJeremy L Thompson   }
440d1d35e2fSjeremylt   *sub_operators = op->sub_operators;
441e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
4427a982d89SJeremy L. Thompson }
4437a982d89SJeremy L. Thompson 
4447a982d89SJeremy L. Thompson /**
4457a982d89SJeremy L. Thompson   @brief Get the backend data of a CeedOperator
4467a982d89SJeremy L. Thompson 
4477a982d89SJeremy L. Thompson   @param op         CeedOperator
4487a982d89SJeremy L. Thompson   @param[out] data  Variable to store data
4497a982d89SJeremy L. Thompson 
4507a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
4517a982d89SJeremy L. Thompson 
4527a982d89SJeremy L. Thompson   @ref Backend
4537a982d89SJeremy L. Thompson **/
4547a982d89SJeremy L. Thompson 
455777ff853SJeremy L Thompson int CeedOperatorGetData(CeedOperator op, void *data) {
456777ff853SJeremy L Thompson   *(void **)data = op->data;
457e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
4587a982d89SJeremy L. Thompson }
4597a982d89SJeremy L. Thompson 
4607a982d89SJeremy L. Thompson /**
4617a982d89SJeremy L. Thompson   @brief Set the backend data of a CeedOperator
4627a982d89SJeremy L. Thompson 
4637a982d89SJeremy L. Thompson   @param[out] op  CeedOperator
4647a982d89SJeremy L. Thompson   @param data     Data to set
4657a982d89SJeremy L. Thompson 
4667a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
4677a982d89SJeremy L. Thompson 
4687a982d89SJeremy L. Thompson   @ref Backend
4697a982d89SJeremy L. Thompson **/
4707a982d89SJeremy L. Thompson 
471777ff853SJeremy L Thompson int CeedOperatorSetData(CeedOperator op, void *data) {
472777ff853SJeremy L Thompson   op->data = data;
473e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
4747a982d89SJeremy L. Thompson }
4757a982d89SJeremy L. Thompson 
4767a982d89SJeremy L. Thompson /**
47734359f16Sjeremylt   @brief Increment the reference counter for a CeedOperator
47834359f16Sjeremylt 
47934359f16Sjeremylt   @param op  CeedOperator to increment the reference counter
48034359f16Sjeremylt 
48134359f16Sjeremylt   @return An error code: 0 - success, otherwise - failure
48234359f16Sjeremylt 
48334359f16Sjeremylt   @ref Backend
48434359f16Sjeremylt **/
4859560d06aSjeremylt int CeedOperatorReference(CeedOperator op) {
48634359f16Sjeremylt   op->ref_count++;
48734359f16Sjeremylt   return CEED_ERROR_SUCCESS;
48834359f16Sjeremylt }
48934359f16Sjeremylt 
49034359f16Sjeremylt /**
4917a982d89SJeremy L. Thompson   @brief Set the setup flag of a CeedOperator to True
4927a982d89SJeremy L. Thompson 
4937a982d89SJeremy L. Thompson   @param op  CeedOperator
4947a982d89SJeremy L. Thompson 
4957a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
4967a982d89SJeremy L. Thompson 
4977a982d89SJeremy L. Thompson   @ref Backend
4987a982d89SJeremy L. Thompson **/
4997a982d89SJeremy L. Thompson 
5007a982d89SJeremy L. Thompson int CeedOperatorSetSetupDone(CeedOperator op) {
501f04ea552SJeremy L Thompson   op->is_backend_setup = true;
502e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5037a982d89SJeremy L. Thompson }
5047a982d89SJeremy L. Thompson 
5057a982d89SJeremy L. Thompson /// @}
5067a982d89SJeremy L. Thompson 
5077a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
5087a982d89SJeremy L. Thompson /// CeedOperator Public API
5097a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
5107a982d89SJeremy L. Thompson /// @addtogroup CeedOperatorUser
511dfdf5a53Sjeremylt /// @{
512d7b241e6Sjeremylt 
513d7b241e6Sjeremylt /**
5140219ea01SJeremy L Thompson   @brief Create a CeedOperator and associate a CeedQFunction. A CeedBasis and
5150219ea01SJeremy L Thompson            CeedElemRestriction can be associated with CeedQFunction fields with
5160219ea01SJeremy L Thompson            \ref CeedOperatorSetField.
517d7b241e6Sjeremylt 
518b11c1e72Sjeremylt   @param ceed     A Ceed object where the CeedOperator will be created
519d7b241e6Sjeremylt   @param qf       QFunction defining the action of the operator at quadrature points
52034138859Sjeremylt   @param dqf      QFunction defining the action of the Jacobian of @a qf (or
5214cc79fe7SJed Brown                     @ref CEED_QFUNCTION_NONE)
522d7b241e6Sjeremylt   @param dqfT     QFunction defining the action of the transpose of the Jacobian
5234cc79fe7SJed Brown                     of @a qf (or @ref CEED_QFUNCTION_NONE)
524b11c1e72Sjeremylt   @param[out] op  Address of the variable where the newly created
525b11c1e72Sjeremylt                     CeedOperator will be stored
526b11c1e72Sjeremylt 
527b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
528dfdf5a53Sjeremylt 
5297a982d89SJeremy L. Thompson   @ref User
530d7b241e6Sjeremylt  */
531*2b730f8bSJeremy L Thompson int CeedOperatorCreate(Ceed ceed, CeedQFunction qf, CeedQFunction dqf, CeedQFunction dqfT, CeedOperator *op) {
5325fe0d4faSjeremylt   if (!ceed->OperatorCreate) {
5335fe0d4faSjeremylt     Ceed delegate;
534*2b730f8bSJeremy L Thompson     CeedCall(CeedGetObjectDelegate(ceed, &delegate, "Operator"));
5355fe0d4faSjeremylt 
536*2b730f8bSJeremy L Thompson     if (!delegate) {
537c042f62fSJeremy L Thompson       // LCOV_EXCL_START
538*2b730f8bSJeremy L Thompson       return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support OperatorCreate");
539c042f62fSJeremy L Thompson       // LCOV_EXCL_STOP
540*2b730f8bSJeremy L Thompson     }
5415fe0d4faSjeremylt 
542*2b730f8bSJeremy L Thompson     CeedCall(CeedOperatorCreate(delegate, qf, dqf, dqfT, op));
543e15f9bd0SJeremy L Thompson     return CEED_ERROR_SUCCESS;
5445fe0d4faSjeremylt   }
5455fe0d4faSjeremylt 
546*2b730f8bSJeremy L Thompson   if (!qf || qf == CEED_QFUNCTION_NONE) {
547b3b7035fSJeremy L Thompson     // LCOV_EXCL_START
548*2b730f8bSJeremy L Thompson     return CeedError(ceed, CEED_ERROR_MINOR, "Operator must have a valid QFunction.");
549b3b7035fSJeremy L Thompson     // LCOV_EXCL_STOP
550*2b730f8bSJeremy L Thompson   }
551*2b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(1, op));
552d7b241e6Sjeremylt   (*op)->ceed = ceed;
553*2b730f8bSJeremy L Thompson   CeedCall(CeedReference(ceed));
554d1d35e2fSjeremylt   (*op)->ref_count   = 1;
555d7b241e6Sjeremylt   (*op)->qf          = qf;
5562b104005SJeremy L Thompson   (*op)->input_size  = -1;
5572b104005SJeremy L Thompson   (*op)->output_size = -1;
558*2b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionReference(qf));
559442e7f0bSjeremylt   if (dqf && dqf != CEED_QFUNCTION_NONE) {
560d7b241e6Sjeremylt     (*op)->dqf = dqf;
561*2b730f8bSJeremy L Thompson     CeedCall(CeedQFunctionReference(dqf));
562442e7f0bSjeremylt   }
563442e7f0bSjeremylt   if (dqfT && dqfT != CEED_QFUNCTION_NONE) {
564d7b241e6Sjeremylt     (*op)->dqfT = dqfT;
565*2b730f8bSJeremy L Thompson     CeedCall(CeedQFunctionReference(dqfT));
566442e7f0bSjeremylt   }
567*2b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionAssemblyDataCreate(ceed, &(*op)->qf_assembled));
568*2b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(CEED_FIELD_MAX, &(*op)->input_fields));
569*2b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(CEED_FIELD_MAX, &(*op)->output_fields));
570*2b730f8bSJeremy L Thompson   CeedCall(ceed->OperatorCreate(*op));
571e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
572d7b241e6Sjeremylt }
573d7b241e6Sjeremylt 
574d7b241e6Sjeremylt /**
57552d6035fSJeremy L Thompson   @brief Create an operator that composes the action of several operators
57652d6035fSJeremy L Thompson 
57752d6035fSJeremy L Thompson   @param ceed     A Ceed object where the CeedOperator will be created
57852d6035fSJeremy L Thompson   @param[out] op  Address of the variable where the newly created
57952d6035fSJeremy L Thompson                     Composite CeedOperator will be stored
58052d6035fSJeremy L Thompson 
58152d6035fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
58252d6035fSJeremy L Thompson 
5837a982d89SJeremy L. Thompson   @ref User
58452d6035fSJeremy L Thompson  */
58552d6035fSJeremy L Thompson int CeedCompositeOperatorCreate(Ceed ceed, CeedOperator *op) {
58652d6035fSJeremy L Thompson   if (!ceed->CompositeOperatorCreate) {
58752d6035fSJeremy L Thompson     Ceed delegate;
588*2b730f8bSJeremy L Thompson     CeedCall(CeedGetObjectDelegate(ceed, &delegate, "Operator"));
58952d6035fSJeremy L Thompson 
590250756a7Sjeremylt     if (delegate) {
591*2b730f8bSJeremy L Thompson       CeedCall(CeedCompositeOperatorCreate(delegate, op));
592e15f9bd0SJeremy L Thompson       return CEED_ERROR_SUCCESS;
59352d6035fSJeremy L Thompson     }
594250756a7Sjeremylt   }
59552d6035fSJeremy L Thompson 
596*2b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(1, op));
59752d6035fSJeremy L Thompson   (*op)->ceed = ceed;
598*2b730f8bSJeremy L Thompson   CeedCall(CeedReference(ceed));
599996d9ab5SJed Brown   (*op)->ref_count    = 1;
600f04ea552SJeremy L Thompson   (*op)->is_composite = true;
601*2b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(CEED_COMPOSITE_MAX, &(*op)->sub_operators));
6022b104005SJeremy L Thompson   (*op)->input_size  = -1;
6032b104005SJeremy L Thompson   (*op)->output_size = -1;
604250756a7Sjeremylt 
605250756a7Sjeremylt   if (ceed->CompositeOperatorCreate) {
606*2b730f8bSJeremy L Thompson     CeedCall(ceed->CompositeOperatorCreate(*op));
607250756a7Sjeremylt   }
608e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
60952d6035fSJeremy L Thompson }
61052d6035fSJeremy L Thompson 
61152d6035fSJeremy L Thompson /**
6129560d06aSjeremylt   @brief Copy the pointer to a CeedOperator. Both pointers should
6139560d06aSjeremylt            be destroyed with `CeedOperatorDestroy()`;
6149560d06aSjeremylt            Note: If `*op_copy` is non-NULL, then it is assumed that
6159560d06aSjeremylt            `*op_copy` is a pointer to a CeedOperator. This
6169560d06aSjeremylt            CeedOperator will be destroyed if `*op_copy` is the only
6179560d06aSjeremylt            reference to this CeedOperator.
6189560d06aSjeremylt 
6199560d06aSjeremylt   @param op            CeedOperator to copy reference to
6209560d06aSjeremylt   @param[out] op_copy  Variable to store copied reference
6219560d06aSjeremylt 
6229560d06aSjeremylt   @return An error code: 0 - success, otherwise - failure
6239560d06aSjeremylt 
6249560d06aSjeremylt   @ref User
6259560d06aSjeremylt **/
6269560d06aSjeremylt int CeedOperatorReferenceCopy(CeedOperator op, CeedOperator *op_copy) {
627*2b730f8bSJeremy L Thompson   CeedCall(CeedOperatorReference(op));
628*2b730f8bSJeremy L Thompson   CeedCall(CeedOperatorDestroy(op_copy));
6299560d06aSjeremylt   *op_copy = op;
6309560d06aSjeremylt   return CEED_ERROR_SUCCESS;
6319560d06aSjeremylt }
6329560d06aSjeremylt 
6339560d06aSjeremylt /**
634b11c1e72Sjeremylt   @brief Provide a field to a CeedOperator for use by its CeedQFunction
635d7b241e6Sjeremylt 
636d7b241e6Sjeremylt   This function is used to specify both active and passive fields to a
637d7b241e6Sjeremylt   CeedOperator.  For passive fields, a vector @arg v must be provided.  Passive
638d7b241e6Sjeremylt   fields can inputs or outputs (updated in-place when operator is applied).
639d7b241e6Sjeremylt 
640d7b241e6Sjeremylt   Active fields must be specified using this function, but their data (in a
641d7b241e6Sjeremylt   CeedVector) is passed in CeedOperatorApply().  There can be at most one active
642979e564eSJames Wright   input CeedVector and at most one active output CeedVector passed to
643979e564eSJames Wright   CeedOperatorApply().
644d7b241e6Sjeremylt 
6458c91a0c9SJeremy L Thompson   @param op          CeedOperator on which to provide the field
646d1d35e2fSjeremylt   @param field_name  Name of the field (to be matched with the name used by
6478795c945Sjeremylt                        CeedQFunction)
648b11c1e72Sjeremylt   @param r           CeedElemRestriction
6494cc79fe7SJed Brown   @param b           CeedBasis in which the field resides or @ref CEED_BASIS_COLLOCATED
650b11c1e72Sjeremylt                        if collocated with quadrature points
6514cc79fe7SJed Brown   @param v           CeedVector to be used by CeedOperator or @ref CEED_VECTOR_ACTIVE
6524cc79fe7SJed Brown                        if field is active or @ref CEED_VECTOR_NONE if using
6534cc79fe7SJed Brown                        @ref CEED_EVAL_WEIGHT in the QFunction
654b11c1e72Sjeremylt 
655b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
656dfdf5a53Sjeremylt 
6577a982d89SJeremy L. Thompson   @ref User
658b11c1e72Sjeremylt **/
659*2b730f8bSJeremy L Thompson int CeedOperatorSetField(CeedOperator op, const char *field_name, CeedElemRestriction r, CeedBasis b, CeedVector v) {
660*2b730f8bSJeremy L Thompson   if (op->is_composite) {
661c042f62fSJeremy L Thompson     // LCOV_EXCL_START
662*2b730f8bSJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, "Cannot add field to composite operator.");
663c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
664*2b730f8bSJeremy L Thompson   }
665*2b730f8bSJeremy L Thompson   if (op->is_immutable) {
666f04ea552SJeremy L Thompson     // LCOV_EXCL_START
667*2b730f8bSJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MAJOR, "Operator cannot be changed after set as immutable");
668f04ea552SJeremy L Thompson     // LCOV_EXCL_STOP
669*2b730f8bSJeremy L Thompson   }
670*2b730f8bSJeremy L Thompson   if (!r) {
671c042f62fSJeremy L Thompson     // LCOV_EXCL_START
672*2b730f8bSJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, "ElemRestriction r for field \"%s\" must be non-NULL.", field_name);
673c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
674*2b730f8bSJeremy L Thompson   }
675*2b730f8bSJeremy L Thompson   if (!b) {
676c042f62fSJeremy L Thompson     // LCOV_EXCL_START
677*2b730f8bSJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, "Basis b for field \"%s\" must be non-NULL.", field_name);
678c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
679*2b730f8bSJeremy L Thompson   }
680*2b730f8bSJeremy L Thompson   if (!v) {
681c042f62fSJeremy L Thompson     // LCOV_EXCL_START
682*2b730f8bSJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, "Vector v for field \"%s\" must be non-NULL.", field_name);
683c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
684*2b730f8bSJeremy L Thompson   }
68552d6035fSJeremy L Thompson 
686d1d35e2fSjeremylt   CeedInt num_elem;
687*2b730f8bSJeremy L Thompson   CeedCall(CeedElemRestrictionGetNumElements(r, &num_elem));
688*2b730f8bSJeremy L Thompson   if (r != CEED_ELEMRESTRICTION_NONE && op->has_restriction && op->num_elem != num_elem) {
689c042f62fSJeremy L Thompson     // LCOV_EXCL_START
690e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_DIMENSION,
691*2b730f8bSJeremy L Thompson                      "ElemRestriction with %" CeedInt_FMT " elements incompatible with prior %" CeedInt_FMT " elements", num_elem, op->num_elem);
692c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
693*2b730f8bSJeremy L Thompson   }
694d7b241e6Sjeremylt 
69578464608Sjeremylt   CeedInt num_qpts = 0;
696e15f9bd0SJeremy L Thompson   if (b != CEED_BASIS_COLLOCATED) {
697*2b730f8bSJeremy L Thompson     CeedCall(CeedBasisGetNumQuadraturePoints(b, &num_qpts));
698*2b730f8bSJeremy L Thompson     if (op->num_qpts && op->num_qpts != num_qpts) {
699c042f62fSJeremy L Thompson       // LCOV_EXCL_START
700e15f9bd0SJeremy L Thompson       return CeedError(op->ceed, CEED_ERROR_DIMENSION,
701*2b730f8bSJeremy L Thompson                        "Basis with %" CeedInt_FMT " quadrature points incompatible with prior %" CeedInt_FMT " points", num_qpts, op->num_qpts);
702c042f62fSJeremy L Thompson       // LCOV_EXCL_STOP
703d7b241e6Sjeremylt     }
704*2b730f8bSJeremy L Thompson   }
705d1d35e2fSjeremylt   CeedQFunctionField qf_field;
706d1d35e2fSjeremylt   CeedOperatorField *op_field;
7072b104005SJeremy L Thompson   bool               is_input = true;
708d1d35e2fSjeremylt   for (CeedInt i = 0; i < op->qf->num_input_fields; i++) {
709d1d35e2fSjeremylt     if (!strcmp(field_name, (*op->qf->input_fields[i]).field_name)) {
710d1d35e2fSjeremylt       qf_field = op->qf->input_fields[i];
711d1d35e2fSjeremylt       op_field = &op->input_fields[i];
712d7b241e6Sjeremylt       goto found;
713d7b241e6Sjeremylt     }
714d7b241e6Sjeremylt   }
7152b104005SJeremy L Thompson   is_input = false;
716d1d35e2fSjeremylt   for (CeedInt i = 0; i < op->qf->num_output_fields; i++) {
717d1d35e2fSjeremylt     if (!strcmp(field_name, (*op->qf->output_fields[i]).field_name)) {
718d1d35e2fSjeremylt       qf_field = op->qf->output_fields[i];
719d1d35e2fSjeremylt       op_field = &op->output_fields[i];
720d7b241e6Sjeremylt       goto found;
721d7b241e6Sjeremylt     }
722d7b241e6Sjeremylt   }
723c042f62fSJeremy L Thompson   // LCOV_EXCL_START
724*2b730f8bSJeremy L Thompson   return CeedError(op->ceed, CEED_ERROR_INCOMPLETE, "QFunction has no knowledge of field '%s'", field_name);
725c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
726d7b241e6Sjeremylt found:
727*2b730f8bSJeremy L Thompson   CeedCall(CeedOperatorCheckField(op->ceed, qf_field, r, b));
728*2b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(1, op_field));
729e15f9bd0SJeremy L Thompson 
7302b104005SJeremy L Thompson   if (v == CEED_VECTOR_ACTIVE) {
7312b104005SJeremy L Thompson     CeedSize l_size;
732*2b730f8bSJeremy L Thompson     CeedCall(CeedElemRestrictionGetLVectorSize(r, &l_size));
7332b104005SJeremy L Thompson     if (is_input) {
7342b104005SJeremy L Thompson       if (op->input_size == -1) op->input_size = l_size;
735*2b730f8bSJeremy L Thompson       if (l_size != op->input_size) {
7362b104005SJeremy L Thompson         // LCOV_EXCL_START
737*2b730f8bSJeremy L Thompson         return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, "LVector size %td does not match previous size %td", l_size, op->input_size);
7382b104005SJeremy L Thompson         // LCOV_EXCL_STOP
739*2b730f8bSJeremy L Thompson       }
7402b104005SJeremy L Thompson     } else {
7412b104005SJeremy L Thompson       if (op->output_size == -1) op->output_size = l_size;
742*2b730f8bSJeremy L Thompson       if (l_size != op->output_size) {
7432b104005SJeremy L Thompson         // LCOV_EXCL_START
744*2b730f8bSJeremy L Thompson         return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, "LVector size %td does not match previous size %td", l_size, op->output_size);
7452b104005SJeremy L Thompson         // LCOV_EXCL_STOP
7462b104005SJeremy L Thompson       }
7472b104005SJeremy L Thompson     }
748*2b730f8bSJeremy L Thompson   }
7492b104005SJeremy L Thompson 
750d1d35e2fSjeremylt   (*op_field)->vec = v;
751e15f9bd0SJeremy L Thompson   if (v != CEED_VECTOR_ACTIVE && v != CEED_VECTOR_NONE) {
752*2b730f8bSJeremy L Thompson     CeedCall(CeedVectorReference(v));
753e15f9bd0SJeremy L Thompson   }
754e15f9bd0SJeremy L Thompson 
755d1d35e2fSjeremylt   (*op_field)->elem_restr = r;
756*2b730f8bSJeremy L Thompson   CeedCall(CeedElemRestrictionReference(r));
757e15f9bd0SJeremy L Thompson   if (r != CEED_ELEMRESTRICTION_NONE) {
758d1d35e2fSjeremylt     op->num_elem        = num_elem;
759d1d35e2fSjeremylt     op->has_restriction = true;  // Restriction set, but num_elem may be 0
760e15f9bd0SJeremy L Thompson   }
761d99fa3c5SJeremy L Thompson 
762d1d35e2fSjeremylt   (*op_field)->basis = b;
763e15f9bd0SJeremy L Thompson   if (b != CEED_BASIS_COLLOCATED) {
764cd4dfc48Sjeremylt     if (!op->num_qpts) {
765*2b730f8bSJeremy L Thompson       CeedCall(CeedOperatorSetNumQuadraturePoints(op, num_qpts));
766cd4dfc48Sjeremylt     }
767*2b730f8bSJeremy L Thompson     CeedCall(CeedBasisReference(b));
768e15f9bd0SJeremy L Thompson   }
769e15f9bd0SJeremy L Thompson 
770d1d35e2fSjeremylt   op->num_fields += 1;
771*2b730f8bSJeremy L Thompson   CeedCall(CeedStringAllocCopy(field_name, (char **)&(*op_field)->field_name));
772e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
773d7b241e6Sjeremylt }
774d7b241e6Sjeremylt 
775d7b241e6Sjeremylt /**
77643bbe138SJeremy L Thompson   @brief Get the CeedOperatorFields of a CeedOperator
77743bbe138SJeremy L Thompson 
778f04ea552SJeremy L Thompson   Note: Calling this function asserts that setup is complete
779f04ea552SJeremy L Thompson           and sets the CeedOperator as immutable.
780f04ea552SJeremy L Thompson 
78143bbe138SJeremy L Thompson   @param op                      CeedOperator
782f74ec584SJeremy L Thompson   @param[out] num_input_fields   Variable to store number of input fields
78343bbe138SJeremy L Thompson   @param[out] input_fields       Variable to store input_fields
784f74ec584SJeremy L Thompson   @param[out] num_output_fields  Variable to store number of output fields
78543bbe138SJeremy L Thompson   @param[out] output_fields      Variable to store output_fields
78643bbe138SJeremy L Thompson 
78743bbe138SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
78843bbe138SJeremy L Thompson 
789e9b533fbSJeremy L Thompson   @ref Advanced
79043bbe138SJeremy L Thompson **/
791*2b730f8bSJeremy L Thompson int CeedOperatorGetFields(CeedOperator op, CeedInt *num_input_fields, CeedOperatorField **input_fields, CeedInt *num_output_fields,
79243bbe138SJeremy L Thompson                           CeedOperatorField **output_fields) {
793*2b730f8bSJeremy L Thompson   if (op->is_composite) {
79443bbe138SJeremy L Thompson     // LCOV_EXCL_START
795*2b730f8bSJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR, "Not defined for composite operator");
79643bbe138SJeremy L Thompson     // LCOV_EXCL_STOP
797*2b730f8bSJeremy L Thompson   }
798*2b730f8bSJeremy L Thompson   CeedCall(CeedOperatorCheckReady(op));
79943bbe138SJeremy L Thompson 
80043bbe138SJeremy L Thompson   if (num_input_fields) *num_input_fields = op->qf->num_input_fields;
80143bbe138SJeremy L Thompson   if (input_fields) *input_fields = op->input_fields;
80243bbe138SJeremy L Thompson   if (num_output_fields) *num_output_fields = op->qf->num_output_fields;
80343bbe138SJeremy L Thompson   if (output_fields) *output_fields = op->output_fields;
80443bbe138SJeremy L Thompson   return CEED_ERROR_SUCCESS;
80543bbe138SJeremy L Thompson }
80643bbe138SJeremy L Thompson 
80743bbe138SJeremy L Thompson /**
80828567f8fSJeremy L Thompson   @brief Get the name of a CeedOperatorField
80928567f8fSJeremy L Thompson 
81028567f8fSJeremy L Thompson   @param op_field         CeedOperatorField
81128567f8fSJeremy L Thompson   @param[out] field_name  Variable to store the field name
81228567f8fSJeremy L Thompson 
81328567f8fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
81428567f8fSJeremy L Thompson 
815e9b533fbSJeremy L Thompson   @ref Advanced
81628567f8fSJeremy L Thompson **/
81728567f8fSJeremy L Thompson int CeedOperatorFieldGetName(CeedOperatorField op_field, char **field_name) {
81828567f8fSJeremy L Thompson   *field_name = (char *)op_field->field_name;
81928567f8fSJeremy L Thompson   return CEED_ERROR_SUCCESS;
82028567f8fSJeremy L Thompson }
82128567f8fSJeremy L Thompson 
82228567f8fSJeremy L Thompson /**
82343bbe138SJeremy L Thompson   @brief Get the CeedElemRestriction of a CeedOperatorField
82443bbe138SJeremy L Thompson 
82543bbe138SJeremy L Thompson   @param op_field   CeedOperatorField
82643bbe138SJeremy L Thompson   @param[out] rstr  Variable to store CeedElemRestriction
82743bbe138SJeremy L Thompson 
82843bbe138SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
82943bbe138SJeremy L Thompson 
830e9b533fbSJeremy L Thompson   @ref Advanced
83143bbe138SJeremy L Thompson **/
832*2b730f8bSJeremy L Thompson int CeedOperatorFieldGetElemRestriction(CeedOperatorField op_field, CeedElemRestriction *rstr) {
83343bbe138SJeremy L Thompson   *rstr = op_field->elem_restr;
83443bbe138SJeremy L Thompson   return CEED_ERROR_SUCCESS;
83543bbe138SJeremy L Thompson }
83643bbe138SJeremy L Thompson 
83743bbe138SJeremy L Thompson /**
83843bbe138SJeremy L Thompson   @brief Get the CeedBasis of a CeedOperatorField
83943bbe138SJeremy L Thompson 
84043bbe138SJeremy L Thompson   @param op_field    CeedOperatorField
84143bbe138SJeremy L Thompson   @param[out] basis  Variable to store CeedBasis
84243bbe138SJeremy L Thompson 
84343bbe138SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
84443bbe138SJeremy L Thompson 
845e9b533fbSJeremy L Thompson   @ref Advanced
84643bbe138SJeremy L Thompson **/
84743bbe138SJeremy L Thompson int CeedOperatorFieldGetBasis(CeedOperatorField op_field, CeedBasis *basis) {
84843bbe138SJeremy L Thompson   *basis = op_field->basis;
84943bbe138SJeremy L Thompson   return CEED_ERROR_SUCCESS;
85043bbe138SJeremy L Thompson }
85143bbe138SJeremy L Thompson 
85243bbe138SJeremy L Thompson /**
85343bbe138SJeremy L Thompson   @brief Get the CeedVector of a CeedOperatorField
85443bbe138SJeremy L Thompson 
85543bbe138SJeremy L Thompson   @param op_field  CeedOperatorField
85643bbe138SJeremy L Thompson   @param[out] vec  Variable to store CeedVector
85743bbe138SJeremy L Thompson 
85843bbe138SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
85943bbe138SJeremy L Thompson 
860e9b533fbSJeremy L Thompson   @ref Advanced
86143bbe138SJeremy L Thompson **/
86243bbe138SJeremy L Thompson int CeedOperatorFieldGetVector(CeedOperatorField op_field, CeedVector *vec) {
86343bbe138SJeremy L Thompson   *vec = op_field->vec;
86443bbe138SJeremy L Thompson   return CEED_ERROR_SUCCESS;
86543bbe138SJeremy L Thompson }
86643bbe138SJeremy L Thompson 
86743bbe138SJeremy L Thompson /**
86852d6035fSJeremy L Thompson   @brief Add a sub-operator to a composite CeedOperator
869288c0443SJeremy L Thompson 
870d1d35e2fSjeremylt   @param[out] composite_op  Composite CeedOperator
871d1d35e2fSjeremylt   @param      sub_op        Sub-operator CeedOperator
87252d6035fSJeremy L Thompson 
87352d6035fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
87452d6035fSJeremy L Thompson 
8757a982d89SJeremy L. Thompson   @ref User
87652d6035fSJeremy L Thompson  */
877*2b730f8bSJeremy L Thompson int CeedCompositeOperatorAddSub(CeedOperator composite_op, CeedOperator sub_op) {
878*2b730f8bSJeremy L Thompson   if (!composite_op->is_composite) {
879c042f62fSJeremy L Thompson     // LCOV_EXCL_START
880*2b730f8bSJeremy L Thompson     return CeedError(composite_op->ceed, CEED_ERROR_MINOR, "CeedOperator is not a composite operator");
8812b104005SJeremy L Thompson     // LCOV_EXCL_STOP
8822b104005SJeremy L Thompson   }
8832b104005SJeremy L Thompson 
884*2b730f8bSJeremy L Thompson   if (composite_op->num_suboperators == CEED_COMPOSITE_MAX) {
885*2b730f8bSJeremy L Thompson     // LCOV_EXCL_START
886*2b730f8bSJeremy L Thompson     return CeedError(composite_op->ceed, CEED_ERROR_UNSUPPORTED, "Cannot add additional sub-operators");
887*2b730f8bSJeremy L Thompson     // LCOV_EXCL_STOP
888*2b730f8bSJeremy L Thompson   }
889*2b730f8bSJeremy L Thompson   if (composite_op->is_immutable) {
890*2b730f8bSJeremy L Thompson     // LCOV_EXCL_START
891*2b730f8bSJeremy L Thompson     return CeedError(composite_op->ceed, CEED_ERROR_MAJOR, "Operator cannot be changed after set as immutable");
892*2b730f8bSJeremy L Thompson     // LCOV_EXCL_STOP
893*2b730f8bSJeremy L Thompson   }
894*2b730f8bSJeremy L Thompson 
895*2b730f8bSJeremy L Thompson   {
896*2b730f8bSJeremy L Thompson     CeedSize input_size, output_size;
897*2b730f8bSJeremy L Thompson     CeedCall(CeedOperatorGetActiveVectorLengths(sub_op, &input_size, &output_size));
898*2b730f8bSJeremy L Thompson     if (composite_op->input_size == -1) composite_op->input_size = input_size;
899*2b730f8bSJeremy L Thompson     if (composite_op->output_size == -1) composite_op->output_size = output_size;
900*2b730f8bSJeremy L Thompson     // Note, a size of -1 means no active vector restriction set, so no incompatibility
901*2b730f8bSJeremy L Thompson     if ((input_size != -1 && input_size != composite_op->input_size) || (output_size != -1 && output_size != composite_op->output_size)) {
902*2b730f8bSJeremy L Thompson       // LCOV_EXCL_START
903*2b730f8bSJeremy L Thompson       return CeedError(composite_op->ceed, CEED_ERROR_MAJOR,
904*2b730f8bSJeremy L Thompson                        "Sub-operators must have compatible dimensions; composite operator of shape (%td, %td) not compatible with sub-operator of "
905*2b730f8bSJeremy L Thompson                        "shape (%td, %td)",
906*2b730f8bSJeremy L Thompson                        composite_op->input_size, composite_op->output_size, input_size, output_size);
907*2b730f8bSJeremy L Thompson       // LCOV_EXCL_STOP
908*2b730f8bSJeremy L Thompson     }
909*2b730f8bSJeremy L Thompson   }
910*2b730f8bSJeremy L Thompson 
911d1d35e2fSjeremylt   composite_op->sub_operators[composite_op->num_suboperators] = sub_op;
912*2b730f8bSJeremy L Thompson   CeedCall(CeedOperatorReference(sub_op));
913d1d35e2fSjeremylt   composite_op->num_suboperators++;
914e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
91552d6035fSJeremy L Thompson }
91652d6035fSJeremy L Thompson 
91752d6035fSJeremy L Thompson /**
9184db537f9SJeremy L Thompson   @brief Check if a CeedOperator is ready to be used.
9194db537f9SJeremy L Thompson 
9204db537f9SJeremy L Thompson   @param[in] op  CeedOperator to check
9214db537f9SJeremy L Thompson 
9224db537f9SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
9234db537f9SJeremy L Thompson 
9244db537f9SJeremy L Thompson   @ref User
9254db537f9SJeremy L Thompson **/
9264db537f9SJeremy L Thompson int CeedOperatorCheckReady(CeedOperator op) {
9274db537f9SJeremy L Thompson   Ceed ceed;
928*2b730f8bSJeremy L Thompson   CeedCall(CeedOperatorGetCeed(op, &ceed));
9294db537f9SJeremy L Thompson 
930*2b730f8bSJeremy L Thompson   if (op->is_interface_setup) return CEED_ERROR_SUCCESS;
9314db537f9SJeremy L Thompson 
9324db537f9SJeremy L Thompson   CeedQFunction qf = op->qf;
9334db537f9SJeremy L Thompson   if (op->is_composite) {
93443622462SJeremy L Thompson     if (!op->num_suboperators) {
93543622462SJeremy L Thompson       // Empty operator setup
93643622462SJeremy L Thompson       op->input_size  = 0;
93743622462SJeremy L Thompson       op->output_size = 0;
93843622462SJeremy L Thompson     } else {
9394db537f9SJeremy L Thompson       for (CeedInt i = 0; i < op->num_suboperators; i++) {
940*2b730f8bSJeremy L Thompson         CeedCall(CeedOperatorCheckReady(op->sub_operators[i]));
9414db537f9SJeremy L Thompson       }
9422b104005SJeremy L Thompson       // Sub-operators could be modified after adding to composite operator
9432b104005SJeremy L Thompson       // Need to verify no lvec incompatibility from any changes
9442b104005SJeremy L Thompson       CeedSize input_size, output_size;
945*2b730f8bSJeremy L Thompson       CeedCall(CeedOperatorGetActiveVectorLengths(op, &input_size, &output_size));
94643622462SJeremy L Thompson     }
9474db537f9SJeremy L Thompson   } else {
948*2b730f8bSJeremy L Thompson     if (op->num_fields == 0) {
9494db537f9SJeremy L Thompson       // LCOV_EXCL_START
9504db537f9SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_INCOMPLETE, "No operator fields set");
9514db537f9SJeremy L Thompson       // LCOV_EXCL_STOP
952*2b730f8bSJeremy L Thompson     }
953*2b730f8bSJeremy L Thompson     if (op->num_fields < qf->num_input_fields + qf->num_output_fields) {
9544db537f9SJeremy L Thompson       // LCOV_EXCL_START
9554db537f9SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_INCOMPLETE, "Not all operator fields set");
9564db537f9SJeremy L Thompson       // LCOV_EXCL_STOP
957*2b730f8bSJeremy L Thompson     }
958*2b730f8bSJeremy L Thompson     if (!op->has_restriction) {
9594db537f9SJeremy L Thompson       // LCOV_EXCL_START
960*2b730f8bSJeremy L Thompson       return CeedError(ceed, CEED_ERROR_INCOMPLETE, "At least one restriction required");
9614db537f9SJeremy L Thompson       // LCOV_EXCL_STOP
962*2b730f8bSJeremy L Thompson     }
963*2b730f8bSJeremy L Thompson     if (op->num_qpts == 0) {
9644db537f9SJeremy L Thompson       // LCOV_EXCL_START
965*2b730f8bSJeremy L Thompson       return CeedError(ceed, CEED_ERROR_INCOMPLETE, "At least one non-collocated basis is required or the number of quadrature points must be set");
9664db537f9SJeremy L Thompson       // LCOV_EXCL_STOP
9674db537f9SJeremy L Thompson     }
968*2b730f8bSJeremy L Thompson   }
9694db537f9SJeremy L Thompson 
9704db537f9SJeremy L Thompson   // Flag as immutable and ready
9714db537f9SJeremy L Thompson   op->is_interface_setup = true;
972*2b730f8bSJeremy L Thompson   if (op->qf && op->qf != CEED_QFUNCTION_NONE) op->qf->is_immutable = true;
973*2b730f8bSJeremy L Thompson   if (op->dqf && op->dqf != CEED_QFUNCTION_NONE) op->dqf->is_immutable = true;
974*2b730f8bSJeremy L Thompson   if (op->dqfT && op->dqfT != CEED_QFUNCTION_NONE) op->dqfT->is_immutable = true;
9754db537f9SJeremy L Thompson   return CEED_ERROR_SUCCESS;
9764db537f9SJeremy L Thompson }
9774db537f9SJeremy L Thompson 
9784db537f9SJeremy L Thompson /**
979c9366a6bSJeremy L Thompson   @brief Get vector lengths for the active input and/or output vectors of a CeedOperator.
980c9366a6bSJeremy L Thompson            Note: Lengths of -1 indicate that the CeedOperator does not have an
981c9366a6bSJeremy L Thompson            active input and/or output.
982c9366a6bSJeremy L Thompson 
983c9366a6bSJeremy L Thompson   @param[in] op           CeedOperator
984c9366a6bSJeremy L Thompson   @param[out] input_size  Variable to store active input vector length, or NULL
985c9366a6bSJeremy L Thompson   @param[out] output_size Variable to store active output vector length, or NULL
986c9366a6bSJeremy L Thompson 
987c9366a6bSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
988c9366a6bSJeremy L Thompson 
989c9366a6bSJeremy L Thompson   @ref User
990c9366a6bSJeremy L Thompson **/
991*2b730f8bSJeremy L Thompson int CeedOperatorGetActiveVectorLengths(CeedOperator op, CeedSize *input_size, CeedSize *output_size) {
992c9366a6bSJeremy L Thompson   bool is_composite;
993c9366a6bSJeremy L Thompson 
9942b104005SJeremy L Thompson   if (input_size) *input_size = op->input_size;
9952b104005SJeremy L Thompson   if (output_size) *output_size = op->output_size;
996c9366a6bSJeremy L Thompson 
997*2b730f8bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
9982b104005SJeremy L Thompson   if (is_composite && (op->input_size == -1 || op->output_size == -1)) {
999c9366a6bSJeremy L Thompson     for (CeedInt i = 0; i < op->num_suboperators; i++) {
1000c9366a6bSJeremy L Thompson       CeedSize sub_input_size, sub_output_size;
1001*2b730f8bSJeremy L Thompson       CeedCall(CeedOperatorGetActiveVectorLengths(op->sub_operators[i], &sub_input_size, &sub_output_size));
10022b104005SJeremy L Thompson       if (op->input_size == -1) op->input_size = sub_input_size;
10032b104005SJeremy L Thompson       if (op->output_size == -1) op->output_size = sub_output_size;
10042b104005SJeremy L Thompson       // Note, a size of -1 means no active vector restriction set, so no incompatibility
1005*2b730f8bSJeremy L Thompson       if ((sub_input_size != -1 && sub_input_size != op->input_size) || (sub_output_size != -1 && sub_output_size != op->output_size)) {
10062b104005SJeremy L Thompson         // LCOV_EXCL_START
10072b104005SJeremy L Thompson         return CeedError(op->ceed, CEED_ERROR_MAJOR,
1008*2b730f8bSJeremy L Thompson                          "Sub-operators must have compatible dimensions; composite operator of shape (%td, %td) not compatible with sub-operator of "
1009*2b730f8bSJeremy L Thompson                          "shape (%td, %td)",
10102b104005SJeremy L Thompson                          op->input_size, op->output_size, input_size, output_size);
10112b104005SJeremy L Thompson         // LCOV_EXCL_STOP
1012c9366a6bSJeremy L Thompson       }
1013c9366a6bSJeremy L Thompson     }
1014*2b730f8bSJeremy L Thompson   }
1015c9366a6bSJeremy L Thompson 
1016c9366a6bSJeremy L Thompson   return CEED_ERROR_SUCCESS;
1017c9366a6bSJeremy L Thompson }
1018c9366a6bSJeremy L Thompson 
1019c9366a6bSJeremy L Thompson /**
1020beecbf24SJeremy L Thompson   @brief Set reuse of CeedQFunction data in CeedOperatorLinearAssemble* functions.
1021beecbf24SJeremy L Thompson            When `reuse_assembly_data = false` (default), the CeedQFunction associated
1022beecbf24SJeremy L Thompson            with this CeedOperator is re-assembled every time a `CeedOperatorLinearAssemble*`
1023beecbf24SJeremy L Thompson            function is called.
1024beecbf24SJeremy L Thompson            When `reuse_assembly_data = true`, the CeedQFunction associated with
1025beecbf24SJeremy L Thompson            this CeedOperator is reused between calls to
1026beecbf24SJeremy L Thompson            `CeedOperatorSetQFunctionAssemblyDataUpdated`.
10278b919e6bSJeremy L Thompson 
1028beecbf24SJeremy L Thompson   @param[in] op                  CeedOperator
1029beecbf24SJeremy L Thompson   @param[in] reuse_assembly_data Boolean flag setting assembly data reuse
10308b919e6bSJeremy L Thompson 
10318b919e6bSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
10328b919e6bSJeremy L Thompson 
10338b919e6bSJeremy L Thompson   @ref Advanced
10348b919e6bSJeremy L Thompson **/
1035*2b730f8bSJeremy L Thompson int CeedOperatorSetQFunctionAssemblyReuse(CeedOperator op, bool reuse_assembly_data) {
10368b919e6bSJeremy L Thompson   bool is_composite;
10378b919e6bSJeremy L Thompson 
1038*2b730f8bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
10398b919e6bSJeremy L Thompson   if (is_composite) {
10408b919e6bSJeremy L Thompson     for (CeedInt i = 0; i < op->num_suboperators; i++) {
1041*2b730f8bSJeremy L Thompson       CeedCall(CeedOperatorSetQFunctionAssemblyReuse(op->sub_operators[i], reuse_assembly_data));
10428b919e6bSJeremy L Thompson     }
10438b919e6bSJeremy L Thompson   } else {
1044*2b730f8bSJeremy L Thompson     CeedCall(CeedQFunctionAssemblyDataSetReuse(op->qf_assembled, reuse_assembly_data));
1045beecbf24SJeremy L Thompson   }
1046beecbf24SJeremy L Thompson 
1047beecbf24SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1048beecbf24SJeremy L Thompson }
1049beecbf24SJeremy L Thompson 
1050beecbf24SJeremy L Thompson /**
1051beecbf24SJeremy L Thompson   @brief Mark CeedQFunction data as updated and the CeedQFunction as requiring re-assembly.
1052beecbf24SJeremy L Thompson 
1053beecbf24SJeremy L Thompson   @param[in] op                CeedOperator
10546e15d496SJeremy L Thompson   @param[in] needs_data_update Boolean flag setting assembly data reuse
1055beecbf24SJeremy L Thompson 
1056beecbf24SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1057beecbf24SJeremy L Thompson 
1058beecbf24SJeremy L Thompson   @ref Advanced
1059beecbf24SJeremy L Thompson **/
1060*2b730f8bSJeremy L Thompson int CeedOperatorSetQFunctionAssemblyDataUpdateNeeded(CeedOperator op, bool needs_data_update) {
1061beecbf24SJeremy L Thompson   bool is_composite;
1062beecbf24SJeremy L Thompson 
1063*2b730f8bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
1064beecbf24SJeremy L Thompson   if (is_composite) {
1065beecbf24SJeremy L Thompson     for (CeedInt i = 0; i < op->num_suboperators; i++) {
1066*2b730f8bSJeremy L Thompson       CeedCall(CeedOperatorSetQFunctionAssemblyDataUpdateNeeded(op->sub_operators[i], needs_data_update));
1067beecbf24SJeremy L Thompson     }
1068beecbf24SJeremy L Thompson   } else {
1069*2b730f8bSJeremy L Thompson     CeedCall(CeedQFunctionAssemblyDataSetUpdateNeeded(op->qf_assembled, needs_data_update));
10708b919e6bSJeremy L Thompson   }
10718b919e6bSJeremy L Thompson 
10728b919e6bSJeremy L Thompson   return CEED_ERROR_SUCCESS;
10738b919e6bSJeremy L Thompson }
10748b919e6bSJeremy L Thompson 
10758b919e6bSJeremy L Thompson /**
1076cd4dfc48Sjeremylt   @brief Set the number of quadrature points associated with a CeedOperator.
1077cd4dfc48Sjeremylt            This should be used when creating a CeedOperator where every
1078cd4dfc48Sjeremylt            field has a collocated basis. This function cannot be used for
1079cd4dfc48Sjeremylt            composite CeedOperators.
1080cd4dfc48Sjeremylt 
1081cd4dfc48Sjeremylt   @param op        CeedOperator
1082cd4dfc48Sjeremylt   @param num_qpts  Number of quadrature points to set
1083cd4dfc48Sjeremylt 
1084cd4dfc48Sjeremylt   @return An error code: 0 - success, otherwise - failure
1085cd4dfc48Sjeremylt 
1086e9b533fbSJeremy L Thompson   @ref Advanced
1087cd4dfc48Sjeremylt **/
1088cd4dfc48Sjeremylt int CeedOperatorSetNumQuadraturePoints(CeedOperator op, CeedInt num_qpts) {
1089*2b730f8bSJeremy L Thompson   if (op->is_composite) {
1090cd4dfc48Sjeremylt     // LCOV_EXCL_START
1091*2b730f8bSJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR, "Not defined for composite operator");
1092cd4dfc48Sjeremylt     // LCOV_EXCL_STOP
1093*2b730f8bSJeremy L Thompson   }
1094*2b730f8bSJeremy L Thompson   if (op->num_qpts) {
1095cd4dfc48Sjeremylt     // LCOV_EXCL_START
1096*2b730f8bSJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR, "Number of quadrature points already defined");
1097cd4dfc48Sjeremylt     // LCOV_EXCL_STOP
1098*2b730f8bSJeremy L Thompson   }
1099*2b730f8bSJeremy L Thompson   if (op->is_immutable) {
1100f04ea552SJeremy L Thompson     // LCOV_EXCL_START
1101*2b730f8bSJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MAJOR, "Operator cannot be changed after set as immutable");
1102f04ea552SJeremy L Thompson     // LCOV_EXCL_STOP
1103*2b730f8bSJeremy L Thompson   }
1104cd4dfc48Sjeremylt   op->num_qpts = num_qpts;
1105cd4dfc48Sjeremylt   return CEED_ERROR_SUCCESS;
1106cd4dfc48Sjeremylt }
1107cd4dfc48Sjeremylt 
1108cd4dfc48Sjeremylt /**
1109ea6b5821SJeremy L Thompson   @brief Set name of CeedOperator for CeedOperatorView output
1110ea6b5821SJeremy L Thompson 
1111ea6b5821SJeremy L Thompson   @param op    CeedOperator
1112ea6b5821SJeremy L Thompson   @param name  Name to set, or NULL to remove previously set name
1113ea6b5821SJeremy L Thompson 
1114ea6b5821SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1115ea6b5821SJeremy L Thompson 
1116ea6b5821SJeremy L Thompson   @ref User
1117ea6b5821SJeremy L Thompson **/
1118ea6b5821SJeremy L Thompson int CeedOperatorSetName(CeedOperator op, const char *name) {
1119ea6b5821SJeremy L Thompson   char  *name_copy;
1120ea6b5821SJeremy L Thompson   size_t name_len = name ? strlen(name) : 0;
1121ea6b5821SJeremy L Thompson 
1122*2b730f8bSJeremy L Thompson   CeedCall(CeedFree(&op->name));
1123ea6b5821SJeremy L Thompson   if (name_len > 0) {
1124*2b730f8bSJeremy L Thompson     CeedCall(CeedCalloc(name_len + 1, &name_copy));
1125ea6b5821SJeremy L Thompson     memcpy(name_copy, name, name_len);
1126ea6b5821SJeremy L Thompson     op->name = name_copy;
1127ea6b5821SJeremy L Thompson   }
1128ea6b5821SJeremy L Thompson 
1129ea6b5821SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1130ea6b5821SJeremy L Thompson }
1131ea6b5821SJeremy L Thompson 
1132ea6b5821SJeremy L Thompson /**
11337a982d89SJeremy L. Thompson   @brief View a CeedOperator
11347a982d89SJeremy L. Thompson 
11357a982d89SJeremy L. Thompson   @param[in] op      CeedOperator to view
11367a982d89SJeremy L. Thompson   @param[in] stream  Stream to write; typically stdout/stderr or a file
11377a982d89SJeremy L. Thompson 
11387a982d89SJeremy L. Thompson   @return Error code: 0 - success, otherwise - failure
11397a982d89SJeremy L. Thompson 
11407a982d89SJeremy L. Thompson   @ref User
11417a982d89SJeremy L. Thompson **/
11427a982d89SJeremy L. Thompson int CeedOperatorView(CeedOperator op, FILE *stream) {
1143ea6b5821SJeremy L Thompson   bool has_name = op->name;
11447a982d89SJeremy L. Thompson 
1145f04ea552SJeremy L Thompson   if (op->is_composite) {
1146*2b730f8bSJeremy L Thompson     fprintf(stream, "Composite CeedOperator%s%s\n", has_name ? " - " : "", has_name ? op->name : "");
11477a982d89SJeremy L. Thompson 
1148d1d35e2fSjeremylt     for (CeedInt i = 0; i < op->num_suboperators; i++) {
1149ea6b5821SJeremy L Thompson       has_name = op->sub_operators[i]->name;
1150*2b730f8bSJeremy L Thompson       fprintf(stream, "  SubOperator %" CeedInt_FMT "%s%s:\n", i, has_name ? " - " : "", has_name ? op->sub_operators[i]->name : "");
1151*2b730f8bSJeremy L Thompson       CeedCall(CeedOperatorSingleView(op->sub_operators[i], 1, stream));
11527a982d89SJeremy L. Thompson     }
11537a982d89SJeremy L. Thompson   } else {
1154*2b730f8bSJeremy L Thompson     fprintf(stream, "CeedOperator%s%s\n", has_name ? " - " : "", has_name ? op->name : "");
1155*2b730f8bSJeremy L Thompson     CeedCall(CeedOperatorSingleView(op, 0, stream));
11567a982d89SJeremy L. Thompson   }
1157e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
11587a982d89SJeremy L. Thompson }
11593bd813ffSjeremylt 
11603bd813ffSjeremylt /**
1161b7c9bbdaSJeremy L Thompson   @brief Get the Ceed associated with a CeedOperator
1162b7c9bbdaSJeremy L Thompson 
1163b7c9bbdaSJeremy L Thompson   @param op         CeedOperator
1164b7c9bbdaSJeremy L Thompson   @param[out] ceed  Variable to store Ceed
1165b7c9bbdaSJeremy L Thompson 
1166b7c9bbdaSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1167b7c9bbdaSJeremy L Thompson 
1168b7c9bbdaSJeremy L Thompson   @ref Advanced
1169b7c9bbdaSJeremy L Thompson **/
1170b7c9bbdaSJeremy L Thompson int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) {
1171b7c9bbdaSJeremy L Thompson   *ceed = op->ceed;
1172b7c9bbdaSJeremy L Thompson   return CEED_ERROR_SUCCESS;
1173b7c9bbdaSJeremy L Thompson }
1174b7c9bbdaSJeremy L Thompson 
1175b7c9bbdaSJeremy L Thompson /**
1176b7c9bbdaSJeremy L Thompson   @brief Get the number of elements associated with a CeedOperator
1177b7c9bbdaSJeremy L Thompson 
1178b7c9bbdaSJeremy L Thompson   @param op             CeedOperator
1179b7c9bbdaSJeremy L Thompson   @param[out] num_elem  Variable to store number of elements
1180b7c9bbdaSJeremy L Thompson 
1181b7c9bbdaSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1182b7c9bbdaSJeremy L Thompson 
1183b7c9bbdaSJeremy L Thompson   @ref Advanced
1184b7c9bbdaSJeremy L Thompson **/
1185b7c9bbdaSJeremy L Thompson int CeedOperatorGetNumElements(CeedOperator op, CeedInt *num_elem) {
1186*2b730f8bSJeremy L Thompson   if (op->is_composite) {
1187b7c9bbdaSJeremy L Thompson     // LCOV_EXCL_START
1188*2b730f8bSJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR, "Not defined for composite operator");
1189b7c9bbdaSJeremy L Thompson     // LCOV_EXCL_STOP
1190*2b730f8bSJeremy L Thompson   }
1191b7c9bbdaSJeremy L Thompson   *num_elem = op->num_elem;
1192b7c9bbdaSJeremy L Thompson   return CEED_ERROR_SUCCESS;
1193b7c9bbdaSJeremy L Thompson }
1194b7c9bbdaSJeremy L Thompson 
1195b7c9bbdaSJeremy L Thompson /**
1196b7c9bbdaSJeremy L Thompson   @brief Get the number of quadrature points associated with a CeedOperator
1197b7c9bbdaSJeremy L Thompson 
1198b7c9bbdaSJeremy L Thompson   @param op             CeedOperator
1199b7c9bbdaSJeremy L Thompson   @param[out] num_qpts  Variable to store vector number of quadrature points
1200b7c9bbdaSJeremy L Thompson 
1201b7c9bbdaSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1202b7c9bbdaSJeremy L Thompson 
1203b7c9bbdaSJeremy L Thompson   @ref Advanced
1204b7c9bbdaSJeremy L Thompson **/
1205b7c9bbdaSJeremy L Thompson int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *num_qpts) {
1206*2b730f8bSJeremy L Thompson   if (op->is_composite) {
1207b7c9bbdaSJeremy L Thompson     // LCOV_EXCL_START
1208*2b730f8bSJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR, "Not defined for composite operator");
1209b7c9bbdaSJeremy L Thompson     // LCOV_EXCL_STOP
1210*2b730f8bSJeremy L Thompson   }
1211b7c9bbdaSJeremy L Thompson   *num_qpts = op->num_qpts;
1212b7c9bbdaSJeremy L Thompson   return CEED_ERROR_SUCCESS;
1213b7c9bbdaSJeremy L Thompson }
1214b7c9bbdaSJeremy L Thompson 
1215b7c9bbdaSJeremy L Thompson /**
12166e15d496SJeremy L Thompson   @brief Estimate number of FLOPs required to apply CeedOperator on the active vector
12176e15d496SJeremy L Thompson 
12186e15d496SJeremy L Thompson   @param op    Operator to estimate FLOPs for
12196e15d496SJeremy L Thompson   @param flops Address of variable to hold FLOPs estimate
12206e15d496SJeremy L Thompson 
12216e15d496SJeremy L Thompson   @ref Backend
12226e15d496SJeremy L Thompson **/
12239d36ca50SJeremy L Thompson int CeedOperatorGetFlopsEstimate(CeedOperator op, CeedSize *flops) {
12246e15d496SJeremy L Thompson   bool is_composite;
1225*2b730f8bSJeremy L Thompson   CeedCall(CeedOperatorCheckReady(op));
12266e15d496SJeremy L Thompson 
12276e15d496SJeremy L Thompson   *flops = 0;
1228*2b730f8bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
12296e15d496SJeremy L Thompson   if (is_composite) {
12306e15d496SJeremy L Thompson     CeedInt num_suboperators;
1231*2b730f8bSJeremy L Thompson     CeedCall(CeedOperatorGetNumSub(op, &num_suboperators));
12326e15d496SJeremy L Thompson     CeedOperator *sub_operators;
1233*2b730f8bSJeremy L Thompson     CeedCall(CeedOperatorGetSubList(op, &sub_operators));
12346e15d496SJeremy L Thompson 
12356e15d496SJeremy L Thompson     // FLOPs for each suboperator
12366e15d496SJeremy L Thompson     for (CeedInt i = 0; i < num_suboperators; i++) {
12379d36ca50SJeremy L Thompson       CeedSize suboperator_flops;
1238*2b730f8bSJeremy L Thompson       CeedCall(CeedOperatorGetFlopsEstimate(sub_operators[i], &suboperator_flops));
12396e15d496SJeremy L Thompson       *flops += suboperator_flops;
12406e15d496SJeremy L Thompson     }
12416e15d496SJeremy L Thompson   } else {
12426e15d496SJeremy L Thompson     CeedInt            num_input_fields, num_output_fields;
12436e15d496SJeremy L Thompson     CeedOperatorField *input_fields, *output_fields;
12446e15d496SJeremy L Thompson 
1245*2b730f8bSJeremy L Thompson     CeedCall(CeedOperatorGetFields(op, &num_input_fields, &input_fields, &num_output_fields, &output_fields));
12466e15d496SJeremy L Thompson 
12476e15d496SJeremy L Thompson     CeedInt num_elem = 0;
1248*2b730f8bSJeremy L Thompson     CeedCall(CeedOperatorGetNumElements(op, &num_elem));
12496e15d496SJeremy L Thompson     // Input FLOPs
12506e15d496SJeremy L Thompson     for (CeedInt i = 0; i < num_input_fields; i++) {
12516e15d496SJeremy L Thompson       if (input_fields[i]->vec == CEED_VECTOR_ACTIVE) {
12529d36ca50SJeremy L Thompson         CeedSize restr_flops, basis_flops;
12536e15d496SJeremy L Thompson 
1254*2b730f8bSJeremy L Thompson         CeedCall(CeedElemRestrictionGetFlopsEstimate(input_fields[i]->elem_restr, CEED_NOTRANSPOSE, &restr_flops));
12556e15d496SJeremy L Thompson         *flops += restr_flops;
1256*2b730f8bSJeremy L Thompson         CeedCall(CeedBasisGetFlopsEstimate(input_fields[i]->basis, CEED_NOTRANSPOSE, op->qf->input_fields[i]->eval_mode, &basis_flops));
12576e15d496SJeremy L Thompson         *flops += basis_flops * num_elem;
12586e15d496SJeremy L Thompson       }
12596e15d496SJeremy L Thompson     }
12606e15d496SJeremy L Thompson     // QF FLOPs
12619d36ca50SJeremy L Thompson     CeedInt  num_qpts;
12629d36ca50SJeremy L Thompson     CeedSize qf_flops;
1263*2b730f8bSJeremy L Thompson     CeedCall(CeedOperatorGetNumQuadraturePoints(op, &num_qpts));
1264*2b730f8bSJeremy L Thompson     CeedCall(CeedQFunctionGetFlopsEstimate(op->qf, &qf_flops));
12656e15d496SJeremy L Thompson     *flops += num_elem * num_qpts * qf_flops;
12666e15d496SJeremy L Thompson     // Output FLOPs
12676e15d496SJeremy L Thompson     for (CeedInt i = 0; i < num_output_fields; i++) {
12686e15d496SJeremy L Thompson       if (output_fields[i]->vec == CEED_VECTOR_ACTIVE) {
12699d36ca50SJeremy L Thompson         CeedSize restr_flops, basis_flops;
12706e15d496SJeremy L Thompson 
1271*2b730f8bSJeremy L Thompson         CeedCall(CeedElemRestrictionGetFlopsEstimate(output_fields[i]->elem_restr, CEED_TRANSPOSE, &restr_flops));
12726e15d496SJeremy L Thompson         *flops += restr_flops;
1273*2b730f8bSJeremy L Thompson         CeedCall(CeedBasisGetFlopsEstimate(output_fields[i]->basis, CEED_TRANSPOSE, op->qf->output_fields[i]->eval_mode, &basis_flops));
12746e15d496SJeremy L Thompson         *flops += basis_flops * num_elem;
12756e15d496SJeremy L Thompson       }
12766e15d496SJeremy L Thompson     }
12776e15d496SJeremy L Thompson   }
12786e15d496SJeremy L Thompson 
12796e15d496SJeremy L Thompson   return CEED_ERROR_SUCCESS;
12806e15d496SJeremy L Thompson }
12816e15d496SJeremy L Thompson 
12826e15d496SJeremy L Thompson /**
12833668ca4bSJeremy L Thompson   @brief Get label for a registered QFunctionContext field, or `NULL` if no
12843668ca4bSJeremy L Thompson            field has been registered with this `field_name`.
12853668ca4bSJeremy L Thompson 
12863668ca4bSJeremy L Thompson   @param[in] op            CeedOperator
12873668ca4bSJeremy L Thompson   @param[in] field_name    Name of field to retrieve label
12883668ca4bSJeremy L Thompson   @param[out] field_label  Variable to field label
12893668ca4bSJeremy L Thompson 
12903668ca4bSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
12913668ca4bSJeremy L Thompson 
12923668ca4bSJeremy L Thompson   @ref User
12933668ca4bSJeremy L Thompson **/
1294*2b730f8bSJeremy L Thompson int CeedOperatorContextGetFieldLabel(CeedOperator op, const char *field_name, CeedContextFieldLabel *field_label) {
12953668ca4bSJeremy L Thompson   bool is_composite;
1296*2b730f8bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
1297*2b730f8bSJeremy L Thompson 
12983668ca4bSJeremy L Thompson   if (is_composite) {
12993668ca4bSJeremy L Thompson     // Check if composite label already created
13003668ca4bSJeremy L Thompson     for (CeedInt i = 0; i < op->num_context_labels; i++) {
13013668ca4bSJeremy L Thompson       if (!strcmp(op->context_labels[i]->name, field_name)) {
13023668ca4bSJeremy L Thompson         *field_label = op->context_labels[i];
13033668ca4bSJeremy L Thompson         return CEED_ERROR_SUCCESS;
13043668ca4bSJeremy L Thompson       }
13053668ca4bSJeremy L Thompson     }
13063668ca4bSJeremy L Thompson 
13073668ca4bSJeremy L Thompson     // Create composite label if needed
13083668ca4bSJeremy L Thompson     CeedInt               num_sub;
13093668ca4bSJeremy L Thompson     CeedOperator         *sub_operators;
13103668ca4bSJeremy L Thompson     CeedContextFieldLabel new_field_label;
13113668ca4bSJeremy L Thompson 
1312*2b730f8bSJeremy L Thompson     CeedCall(CeedCalloc(1, &new_field_label));
1313*2b730f8bSJeremy L Thompson     CeedCall(CeedOperatorGetNumSub(op, &num_sub));
1314*2b730f8bSJeremy L Thompson     CeedCall(CeedOperatorGetSubList(op, &sub_operators));
1315*2b730f8bSJeremy L Thompson     CeedCall(CeedCalloc(num_sub, &new_field_label->sub_labels));
13163668ca4bSJeremy L Thompson     new_field_label->num_sub_labels = num_sub;
13173668ca4bSJeremy L Thompson 
13183668ca4bSJeremy L Thompson     bool label_found = false;
13193668ca4bSJeremy L Thompson     for (CeedInt i = 0; i < num_sub; i++) {
13203668ca4bSJeremy L Thompson       if (sub_operators[i]->qf->ctx) {
13213668ca4bSJeremy L Thompson         CeedContextFieldLabel new_field_label_i;
1322*2b730f8bSJeremy L Thompson         CeedCall(CeedQFunctionContextGetFieldLabel(sub_operators[i]->qf->ctx, field_name, &new_field_label_i));
13233668ca4bSJeremy L Thompson         if (new_field_label_i) {
13243668ca4bSJeremy L Thompson           label_found                    = true;
13253668ca4bSJeremy L Thompson           new_field_label->sub_labels[i] = new_field_label_i;
13263668ca4bSJeremy L Thompson           new_field_label->name          = new_field_label_i->name;
13273668ca4bSJeremy L Thompson           new_field_label->description   = new_field_label_i->description;
1328*2b730f8bSJeremy L Thompson           if (new_field_label->type && new_field_label->type != new_field_label_i->type) {
13297bfe0f0eSJeremy L Thompson             // LCOV_EXCL_START
1330*2b730f8bSJeremy L Thompson             CeedCall(CeedFree(&new_field_label));
1331*2b730f8bSJeremy L Thompson             return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, "Incompatible field types on sub-operator contexts. %s != %s",
1332*2b730f8bSJeremy L Thompson                              CeedContextFieldTypes[new_field_label->type], CeedContextFieldTypes[new_field_label_i->type]);
13337bfe0f0eSJeremy L Thompson             // LCOV_EXCL_STOP
13347bfe0f0eSJeremy L Thompson           } else {
13357bfe0f0eSJeremy L Thompson             new_field_label->type = new_field_label_i->type;
13367bfe0f0eSJeremy L Thompson           }
1337*2b730f8bSJeremy L Thompson           if (new_field_label->num_values != 0 && new_field_label->num_values != new_field_label_i->num_values) {
13387bfe0f0eSJeremy L Thompson             // LCOV_EXCL_START
1339*2b730f8bSJeremy L Thompson             CeedCall(CeedFree(&new_field_label));
1340*2b730f8bSJeremy L Thompson             return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, "Incompatible field number of values on sub-operator contexts. %ld != %ld",
13417bfe0f0eSJeremy L Thompson                              new_field_label->num_values, new_field_label_i->num_values);
13427bfe0f0eSJeremy L Thompson             // LCOV_EXCL_STOP
13437bfe0f0eSJeremy L Thompson           } else {
13447bfe0f0eSJeremy L Thompson             new_field_label->num_values = new_field_label_i->num_values;
13457bfe0f0eSJeremy L Thompson           }
13463668ca4bSJeremy L Thompson         }
13473668ca4bSJeremy L Thompson       }
13483668ca4bSJeremy L Thompson     }
13493668ca4bSJeremy L Thompson     if (!label_found) {
13503668ca4bSJeremy L Thompson       // LCOV_EXCL_START
1351*2b730f8bSJeremy L Thompson       CeedCall(CeedFree(&new_field_label->sub_labels));
1352*2b730f8bSJeremy L Thompson       CeedCall(CeedFree(&new_field_label));
13533668ca4bSJeremy L Thompson       *field_label = NULL;
13543668ca4bSJeremy L Thompson       // LCOV_EXCL_STOP
13553668ca4bSJeremy L Thompson     } else {
13563668ca4bSJeremy L Thompson       // Move new composite label to operator
13573668ca4bSJeremy L Thompson       if (op->num_context_labels == 0) {
1358*2b730f8bSJeremy L Thompson         CeedCall(CeedCalloc(1, &op->context_labels));
13593668ca4bSJeremy L Thompson         op->max_context_labels = 1;
13603668ca4bSJeremy L Thompson       } else if (op->num_context_labels == op->max_context_labels) {
1361*2b730f8bSJeremy L Thompson         CeedCall(CeedRealloc(2 * op->num_context_labels, &op->context_labels));
13623668ca4bSJeremy L Thompson         op->max_context_labels *= 2;
13633668ca4bSJeremy L Thompson       }
13643668ca4bSJeremy L Thompson       op->context_labels[op->num_context_labels] = new_field_label;
13653668ca4bSJeremy L Thompson       *field_label                               = new_field_label;
13663668ca4bSJeremy L Thompson       op->num_context_labels++;
13673668ca4bSJeremy L Thompson     }
13683668ca4bSJeremy L Thompson 
13693668ca4bSJeremy L Thompson     return CEED_ERROR_SUCCESS;
13703668ca4bSJeremy L Thompson   } else {
13713668ca4bSJeremy L Thompson     return CeedQFunctionContextGetFieldLabel(op->qf->ctx, field_name, field_label);
13723668ca4bSJeremy L Thompson   }
13733668ca4bSJeremy L Thompson }
13743668ca4bSJeremy L Thompson 
13753668ca4bSJeremy L Thompson /**
1376d8dd9a91SJeremy L Thompson   @brief Set QFunctionContext field holding a double precision value.
1377d8dd9a91SJeremy L Thompson            For composite operators, the value is set in all
1378d8dd9a91SJeremy L Thompson            sub-operator QFunctionContexts that have a matching `field_name`.
1379d8dd9a91SJeremy L Thompson 
1380d8dd9a91SJeremy L Thompson   @param op          CeedOperator
13813668ca4bSJeremy L Thompson   @param field_label Label of field to register
13827bfe0f0eSJeremy L Thompson   @param values      Values to set
1383d8dd9a91SJeremy L Thompson 
1384d8dd9a91SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1385d8dd9a91SJeremy L Thompson 
1386d8dd9a91SJeremy L Thompson   @ref User
1387d8dd9a91SJeremy L Thompson **/
1388*2b730f8bSJeremy L Thompson int CeedOperatorContextSetDouble(CeedOperator op, CeedContextFieldLabel field_label, double *values) {
1389*2b730f8bSJeremy L Thompson   return CeedOperatorContextSetGeneric(op, field_label, CEED_CONTEXT_FIELD_DOUBLE, values);
1390d8dd9a91SJeremy L Thompson }
1391d8dd9a91SJeremy L Thompson 
1392d8dd9a91SJeremy L Thompson /**
1393d8dd9a91SJeremy L Thompson   @brief Set QFunctionContext field holding an int32 value.
1394d8dd9a91SJeremy L Thompson            For composite operators, the value is set in all
1395d8dd9a91SJeremy L Thompson            sub-operator QFunctionContexts that have a matching `field_name`.
1396d8dd9a91SJeremy L Thompson 
1397d8dd9a91SJeremy L Thompson   @param op          CeedOperator
13983668ca4bSJeremy L Thompson   @param field_label Label of field to set
13997bfe0f0eSJeremy L Thompson   @param values      Values to set
1400d8dd9a91SJeremy L Thompson 
1401d8dd9a91SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1402d8dd9a91SJeremy L Thompson 
1403d8dd9a91SJeremy L Thompson   @ref User
1404d8dd9a91SJeremy L Thompson **/
1405*2b730f8bSJeremy L Thompson int CeedOperatorContextSetInt32(CeedOperator op, CeedContextFieldLabel field_label, int *values) {
1406*2b730f8bSJeremy L Thompson   return CeedOperatorContextSetGeneric(op, field_label, CEED_CONTEXT_FIELD_INT32, values);
1407d8dd9a91SJeremy L Thompson }
1408d8dd9a91SJeremy L Thompson 
1409d8dd9a91SJeremy L Thompson /**
14103bd813ffSjeremylt   @brief Apply CeedOperator to a vector
1411d7b241e6Sjeremylt 
1412d7b241e6Sjeremylt   This computes the action of the operator on the specified (active) input,
1413d7b241e6Sjeremylt   yielding its (active) output.  All inputs and outputs must be specified using
1414d7b241e6Sjeremylt   CeedOperatorSetField().
1415d7b241e6Sjeremylt 
1416f04ea552SJeremy L Thompson   Note: Calling this function asserts that setup is complete
1417f04ea552SJeremy L Thompson           and sets the CeedOperator as immutable.
1418f04ea552SJeremy L Thompson 
1419d7b241e6Sjeremylt   @param op        CeedOperator to apply
14204cc79fe7SJed Brown   @param[in] in    CeedVector containing input state or @ref CEED_VECTOR_NONE if
142134138859Sjeremylt                      there are no active inputs
1422b11c1e72Sjeremylt   @param[out] out  CeedVector to store result of applying operator (must be
14234cc79fe7SJed Brown                      distinct from @a in) or @ref CEED_VECTOR_NONE if there are no
142434138859Sjeremylt                      active outputs
1425d7b241e6Sjeremylt   @param request   Address of CeedRequest for non-blocking completion, else
14264cc79fe7SJed Brown                      @ref CEED_REQUEST_IMMEDIATE
1427b11c1e72Sjeremylt 
1428b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
1429dfdf5a53Sjeremylt 
14307a982d89SJeremy L. Thompson   @ref User
1431b11c1e72Sjeremylt **/
1432*2b730f8bSJeremy L Thompson int CeedOperatorApply(CeedOperator op, CeedVector in, CeedVector out, CeedRequest *request) {
1433*2b730f8bSJeremy L Thompson   CeedCall(CeedOperatorCheckReady(op));
1434d7b241e6Sjeremylt 
1435d1d35e2fSjeremylt   if (op->num_elem) {
1436250756a7Sjeremylt     // Standard Operator
1437cae8b89aSjeremylt     if (op->Apply) {
1438*2b730f8bSJeremy L Thompson       CeedCall(op->Apply(op, in, out, request));
1439cae8b89aSjeremylt     } else {
1440cae8b89aSjeremylt       // Zero all output vectors
1441250756a7Sjeremylt       CeedQFunction qf = op->qf;
1442d1d35e2fSjeremylt       for (CeedInt i = 0; i < qf->num_output_fields; i++) {
1443d1d35e2fSjeremylt         CeedVector vec = op->output_fields[i]->vec;
1444*2b730f8bSJeremy L Thompson         if (vec == CEED_VECTOR_ACTIVE) vec = out;
1445cae8b89aSjeremylt         if (vec != CEED_VECTOR_NONE) {
1446*2b730f8bSJeremy L Thompson           CeedCall(CeedVectorSetValue(vec, 0.0));
1447cae8b89aSjeremylt         }
1448cae8b89aSjeremylt       }
1449250756a7Sjeremylt       // Apply
1450*2b730f8bSJeremy L Thompson       CeedCall(op->ApplyAdd(op, in, out, request));
1451250756a7Sjeremylt     }
1452f04ea552SJeremy L Thompson   } else if (op->is_composite) {
1453250756a7Sjeremylt     // Composite Operator
1454250756a7Sjeremylt     if (op->ApplyComposite) {
1455*2b730f8bSJeremy L Thompson       CeedCall(op->ApplyComposite(op, in, out, request));
1456250756a7Sjeremylt     } else {
1457d1d35e2fSjeremylt       CeedInt num_suboperators;
1458*2b730f8bSJeremy L Thompson       CeedCall(CeedOperatorGetNumSub(op, &num_suboperators));
1459d1d35e2fSjeremylt       CeedOperator *sub_operators;
1460*2b730f8bSJeremy L Thompson       CeedCall(CeedOperatorGetSubList(op, &sub_operators));
1461250756a7Sjeremylt 
1462250756a7Sjeremylt       // Zero all output vectors
1463250756a7Sjeremylt       if (out != CEED_VECTOR_NONE) {
1464*2b730f8bSJeremy L Thompson         CeedCall(CeedVectorSetValue(out, 0.0));
1465cae8b89aSjeremylt       }
1466d1d35e2fSjeremylt       for (CeedInt i = 0; i < num_suboperators; i++) {
1467d1d35e2fSjeremylt         for (CeedInt j = 0; j < sub_operators[i]->qf->num_output_fields; j++) {
1468d1d35e2fSjeremylt           CeedVector vec = sub_operators[i]->output_fields[j]->vec;
1469250756a7Sjeremylt           if (vec != CEED_VECTOR_ACTIVE && vec != CEED_VECTOR_NONE) {
1470*2b730f8bSJeremy L Thompson             CeedCall(CeedVectorSetValue(vec, 0.0));
1471250756a7Sjeremylt           }
1472250756a7Sjeremylt         }
1473250756a7Sjeremylt       }
1474250756a7Sjeremylt       // Apply
1475d1d35e2fSjeremylt       for (CeedInt i = 0; i < op->num_suboperators; i++) {
1476*2b730f8bSJeremy L Thompson         CeedCall(CeedOperatorApplyAdd(op->sub_operators[i], in, out, request));
1477cae8b89aSjeremylt       }
1478cae8b89aSjeremylt     }
1479250756a7Sjeremylt   }
1480e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1481cae8b89aSjeremylt }
1482cae8b89aSjeremylt 
1483cae8b89aSjeremylt /**
1484cae8b89aSjeremylt   @brief Apply CeedOperator to a vector and add result to output vector
1485cae8b89aSjeremylt 
1486cae8b89aSjeremylt   This computes the action of the operator on the specified (active) input,
1487cae8b89aSjeremylt   yielding its (active) output.  All inputs and outputs must be specified using
1488cae8b89aSjeremylt   CeedOperatorSetField().
1489cae8b89aSjeremylt 
1490cae8b89aSjeremylt   @param op        CeedOperator to apply
1491cae8b89aSjeremylt   @param[in] in    CeedVector containing input state or NULL if there are no
1492cae8b89aSjeremylt                      active inputs
1493cae8b89aSjeremylt   @param[out] out  CeedVector to sum in result of applying operator (must be
1494cae8b89aSjeremylt                      distinct from @a in) or NULL if there are no active outputs
1495cae8b89aSjeremylt   @param request   Address of CeedRequest for non-blocking completion, else
14964cc79fe7SJed Brown                      @ref CEED_REQUEST_IMMEDIATE
1497cae8b89aSjeremylt 
1498cae8b89aSjeremylt   @return An error code: 0 - success, otherwise - failure
1499cae8b89aSjeremylt 
15007a982d89SJeremy L. Thompson   @ref User
1501cae8b89aSjeremylt **/
1502*2b730f8bSJeremy L Thompson int CeedOperatorApplyAdd(CeedOperator op, CeedVector in, CeedVector out, CeedRequest *request) {
1503*2b730f8bSJeremy L Thompson   CeedCall(CeedOperatorCheckReady(op));
1504cae8b89aSjeremylt 
1505d1d35e2fSjeremylt   if (op->num_elem) {
1506250756a7Sjeremylt     // Standard Operator
1507*2b730f8bSJeremy L Thompson     CeedCall(op->ApplyAdd(op, in, out, request));
1508f04ea552SJeremy L Thompson   } else if (op->is_composite) {
1509250756a7Sjeremylt     // Composite Operator
1510250756a7Sjeremylt     if (op->ApplyAddComposite) {
1511*2b730f8bSJeremy L Thompson       CeedCall(op->ApplyAddComposite(op, in, out, request));
1512cae8b89aSjeremylt     } else {
1513d1d35e2fSjeremylt       CeedInt num_suboperators;
1514*2b730f8bSJeremy L Thompson       CeedCall(CeedOperatorGetNumSub(op, &num_suboperators));
1515d1d35e2fSjeremylt       CeedOperator *sub_operators;
1516*2b730f8bSJeremy L Thompson       CeedCall(CeedOperatorGetSubList(op, &sub_operators));
1517250756a7Sjeremylt 
1518d1d35e2fSjeremylt       for (CeedInt i = 0; i < num_suboperators; i++) {
1519*2b730f8bSJeremy L Thompson         CeedCall(CeedOperatorApplyAdd(sub_operators[i], in, out, request));
15201d7d2407SJeremy L Thompson       }
1521250756a7Sjeremylt     }
1522250756a7Sjeremylt   }
1523e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1524d7b241e6Sjeremylt }
1525d7b241e6Sjeremylt 
1526d7b241e6Sjeremylt /**
1527b11c1e72Sjeremylt   @brief Destroy a CeedOperator
1528d7b241e6Sjeremylt 
1529d7b241e6Sjeremylt   @param op  CeedOperator to destroy
1530b11c1e72Sjeremylt 
1531b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
1532dfdf5a53Sjeremylt 
15337a982d89SJeremy L. Thompson   @ref User
1534b11c1e72Sjeremylt **/
1535d7b241e6Sjeremylt int CeedOperatorDestroy(CeedOperator *op) {
1536d1d35e2fSjeremylt   if (!*op || --(*op)->ref_count > 0) return CEED_ERROR_SUCCESS;
1537*2b730f8bSJeremy L Thompson   if ((*op)->Destroy) CeedCall((*op)->Destroy(*op));
1538*2b730f8bSJeremy L Thompson   CeedCall(CeedDestroy(&(*op)->ceed));
1539fe2413ffSjeremylt   // Free fields
1540*2b730f8bSJeremy L Thompson   for (CeedInt i = 0; i < (*op)->num_fields; i++) {
1541d1d35e2fSjeremylt     if ((*op)->input_fields[i]) {
1542d1d35e2fSjeremylt       if ((*op)->input_fields[i]->elem_restr != CEED_ELEMRESTRICTION_NONE) {
1543*2b730f8bSJeremy L Thompson         CeedCall(CeedElemRestrictionDestroy(&(*op)->input_fields[i]->elem_restr));
154415910d16Sjeremylt       }
1545d1d35e2fSjeremylt       if ((*op)->input_fields[i]->basis != CEED_BASIS_COLLOCATED) {
1546*2b730f8bSJeremy L Thompson         CeedCall(CeedBasisDestroy(&(*op)->input_fields[i]->basis));
154771352a93Sjeremylt       }
1548*2b730f8bSJeremy L Thompson       if ((*op)->input_fields[i]->vec != CEED_VECTOR_ACTIVE && (*op)->input_fields[i]->vec != CEED_VECTOR_NONE) {
1549*2b730f8bSJeremy L Thompson         CeedCall(CeedVectorDestroy(&(*op)->input_fields[i]->vec));
155071352a93Sjeremylt       }
1551*2b730f8bSJeremy L Thompson       CeedCall(CeedFree(&(*op)->input_fields[i]->field_name));
1552*2b730f8bSJeremy L Thompson       CeedCall(CeedFree(&(*op)->input_fields[i]));
1553fe2413ffSjeremylt     }
1554*2b730f8bSJeremy L Thompson   }
1555*2b730f8bSJeremy L Thompson   for (CeedInt i = 0; i < (*op)->num_fields; i++) {
1556d1d35e2fSjeremylt     if ((*op)->output_fields[i]) {
1557*2b730f8bSJeremy L Thompson       CeedCall(CeedElemRestrictionDestroy(&(*op)->output_fields[i]->elem_restr));
1558d1d35e2fSjeremylt       if ((*op)->output_fields[i]->basis != CEED_BASIS_COLLOCATED) {
1559*2b730f8bSJeremy L Thompson         CeedCall(CeedBasisDestroy(&(*op)->output_fields[i]->basis));
156071352a93Sjeremylt       }
1561*2b730f8bSJeremy L Thompson       if ((*op)->output_fields[i]->vec != CEED_VECTOR_ACTIVE && (*op)->output_fields[i]->vec != CEED_VECTOR_NONE) {
1562*2b730f8bSJeremy L Thompson         CeedCall(CeedVectorDestroy(&(*op)->output_fields[i]->vec));
156371352a93Sjeremylt       }
1564*2b730f8bSJeremy L Thompson       CeedCall(CeedFree(&(*op)->output_fields[i]->field_name));
1565*2b730f8bSJeremy L Thompson       CeedCall(CeedFree(&(*op)->output_fields[i]));
1566*2b730f8bSJeremy L Thompson     }
1567fe2413ffSjeremylt   }
1568d1d35e2fSjeremylt   // Destroy sub_operators
1569*2b730f8bSJeremy L Thompson   for (CeedInt i = 0; i < (*op)->num_suboperators; i++) {
1570d1d35e2fSjeremylt     if ((*op)->sub_operators[i]) {
1571*2b730f8bSJeremy L Thompson       CeedCall(CeedOperatorDestroy(&(*op)->sub_operators[i]));
157252d6035fSJeremy L Thompson     }
1573*2b730f8bSJeremy L Thompson   }
1574*2b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionDestroy(&(*op)->qf));
1575*2b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionDestroy(&(*op)->dqf));
1576*2b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionDestroy(&(*op)->dqfT));
15773668ca4bSJeremy L Thompson   // Destroy any composite labels
15783668ca4bSJeremy L Thompson   for (CeedInt i = 0; i < (*op)->num_context_labels; i++) {
1579*2b730f8bSJeremy L Thompson     CeedCall(CeedFree(&(*op)->context_labels[i]->sub_labels));
1580*2b730f8bSJeremy L Thompson     CeedCall(CeedFree(&(*op)->context_labels[i]));
15813668ca4bSJeremy L Thompson   }
1582*2b730f8bSJeremy L Thompson   CeedCall(CeedFree(&(*op)->context_labels));
1583fe2413ffSjeremylt 
15845107b09fSJeremy L Thompson   // Destroy fallback
1585*2b730f8bSJeremy L Thompson   CeedCall(CeedOperatorDestroy(&(*op)->op_fallback));
15865107b09fSJeremy L Thompson 
1587ed9e99e6SJeremy L Thompson   // Destroy assembly data
1588*2b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionAssemblyDataDestroy(&(*op)->qf_assembled));
1589*2b730f8bSJeremy L Thompson   CeedCall(CeedOperatorAssemblyDataDestroy(&(*op)->op_assembled));
159070a7ffb3SJeremy L Thompson 
1591*2b730f8bSJeremy L Thompson   CeedCall(CeedFree(&(*op)->input_fields));
1592*2b730f8bSJeremy L Thompson   CeedCall(CeedFree(&(*op)->output_fields));
1593*2b730f8bSJeremy L Thompson   CeedCall(CeedFree(&(*op)->sub_operators));
1594*2b730f8bSJeremy L Thompson   CeedCall(CeedFree(&(*op)->name));
1595*2b730f8bSJeremy L Thompson   CeedCall(CeedFree(op));
1596e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1597d7b241e6Sjeremylt }
1598d7b241e6Sjeremylt 
1599d7b241e6Sjeremylt /// @}
1600