xref: /libCEED/rust/libceed-sys/c-src/interface/ceed-operator.c (revision ed094490f53e580908aa80e9fe815a6fd76d7526)
1d275d636SJeremy L Thompson // Copyright (c) 2017-2025, 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>
949aac155SJeremy L Thompson #include <ceed.h>
102b730f8bSJeremy L Thompson #include <ceed/backend.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 /**
25ca94c3ddSJeremy L Thompson   @brief Check if a `CeedOperator` Field matches the `CeedQFunction` Field
26e15f9bd0SJeremy L Thompson 
27ca94c3ddSJeremy L Thompson   @param[in] ceed     `Ceed` object for error handling
28ca94c3ddSJeremy L Thompson   @param[in] qf_field `CeedQFunction` Field matching `CeedOperator` Field
29bafebce1SSebastian Grimberg   @param[in] rstr     `CeedOperator` Field `CeedElemRestriction`
30bafebce1SSebastian Grimberg   @param[in] basis    `CeedOperator` Field `CeedBasis`
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 **/
36bafebce1SSebastian Grimberg static int CeedOperatorCheckField(Ceed ceed, CeedQFunctionField qf_field, CeedElemRestriction rstr, CeedBasis basis) {
376f8994e9SJeremy L Thompson   const char  *field_name;
381203703bSJeremy L Thompson   CeedInt      dim = 1, num_comp = 1, q_comp = 1, rstr_num_comp = 1, size;
391203703bSJeremy L Thompson   CeedEvalMode eval_mode;
401203703bSJeremy L Thompson 
411203703bSJeremy L Thompson   // Field data
42ab747706SJeremy L Thompson   CeedCall(CeedQFunctionFieldGetData(qf_field, &field_name, &size, &eval_mode));
432b730f8bSJeremy L Thompson 
44e15f9bd0SJeremy L Thompson   // Restriction
45bafebce1SSebastian Grimberg   CeedCheck((rstr == CEED_ELEMRESTRICTION_NONE) == (eval_mode == CEED_EVAL_WEIGHT), ceed, CEED_ERROR_INCOMPATIBLE,
466574a04fSJeremy L Thompson             "CEED_ELEMRESTRICTION_NONE and CEED_EVAL_WEIGHT must be used together.");
47bafebce1SSebastian Grimberg   if (rstr != CEED_ELEMRESTRICTION_NONE) {
48bafebce1SSebastian Grimberg     CeedCall(CeedElemRestrictionGetNumComponents(rstr, &rstr_num_comp));
49e1e9e29dSJed Brown   }
50e15f9bd0SJeremy L Thompson   // Basis
51bafebce1SSebastian Grimberg   CeedCheck((basis == CEED_BASIS_NONE) == (eval_mode == CEED_EVAL_NONE), ceed, CEED_ERROR_INCOMPATIBLE,
52356036faSJeremy L Thompson             "CEED_BASIS_NONE and CEED_EVAL_NONE must be used together.");
53bafebce1SSebastian Grimberg   if (basis != CEED_BASIS_NONE) {
54bafebce1SSebastian Grimberg     CeedCall(CeedBasisGetDimension(basis, &dim));
55bafebce1SSebastian Grimberg     CeedCall(CeedBasisGetNumComponents(basis, &num_comp));
56bafebce1SSebastian Grimberg     CeedCall(CeedBasisGetNumQuadratureComponents(basis, eval_mode, &q_comp));
57bafebce1SSebastian Grimberg     CeedCheck(rstr == CEED_ELEMRESTRICTION_NONE || rstr_num_comp == num_comp, ceed, CEED_ERROR_DIMENSION,
58ca94c3ddSJeremy L Thompson               "Field '%s' of size %" CeedInt_FMT " and EvalMode %s: CeedElemRestriction has %" CeedInt_FMT
59ca94c3ddSJeremy L Thompson               " components, but CeedBasis has %" CeedInt_FMT " components",
601203703bSJeremy L Thompson               field_name, size, CeedEvalModes[eval_mode], rstr_num_comp, num_comp);
61e15f9bd0SJeremy L Thompson   }
62e15f9bd0SJeremy L Thompson   // Field size
63d1d35e2fSjeremylt   switch (eval_mode) {
64e15f9bd0SJeremy L Thompson     case CEED_EVAL_NONE:
65edb2538eSJeremy L Thompson       CeedCheck(size == rstr_num_comp, ceed, CEED_ERROR_DIMENSION,
661203703bSJeremy L Thompson                 "Field '%s' of size %" CeedInt_FMT " and EvalMode %s: CeedElemRestriction has %" CeedInt_FMT " components", field_name, size,
671203703bSJeremy L Thompson                 CeedEvalModes[eval_mode], rstr_num_comp);
68e15f9bd0SJeremy L Thompson       break;
69e15f9bd0SJeremy L Thompson     case CEED_EVAL_INTERP:
70c4e3f59bSSebastian Grimberg     case CEED_EVAL_GRAD:
71c4e3f59bSSebastian Grimberg     case CEED_EVAL_DIV:
72c4e3f59bSSebastian Grimberg     case CEED_EVAL_CURL:
736574a04fSJeremy L Thompson       CeedCheck(size == num_comp * q_comp, ceed, CEED_ERROR_DIMENSION,
741203703bSJeremy L Thompson                 "Field '%s' of size %" CeedInt_FMT " and EvalMode %s: CeedElemRestriction/Basis has %" CeedInt_FMT " components", field_name, size,
751203703bSJeremy L Thompson                 CeedEvalModes[eval_mode], num_comp * q_comp);
76e15f9bd0SJeremy L Thompson       break;
77e15f9bd0SJeremy L Thompson     case CEED_EVAL_WEIGHT:
78d1d35e2fSjeremylt       // No additional checks required
79e15f9bd0SJeremy L Thompson       break;
80e15f9bd0SJeremy L Thompson   }
81e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
827a982d89SJeremy L. Thompson }
837a982d89SJeremy L. Thompson 
847a982d89SJeremy L. Thompson /**
85ca94c3ddSJeremy L Thompson   @brief View a field of a `CeedOperator`
867a982d89SJeremy L. Thompson 
871203703bSJeremy L Thompson   @param[in] op_field     `CeedOperator` Field to view
88ca94c3ddSJeremy L Thompson   @param[in] qf_field     `CeedQFunction` Field (carries field name)
89d1d35e2fSjeremylt   @param[in] field_number Number of field being viewed
904c4400c7SValeria Barra   @param[in] sub          true indicates sub-operator, which increases indentation; false for top-level operator
91d1d35e2fSjeremylt   @param[in] input        true for an input field; false for output field
92ca94c3ddSJeremy L Thompson   @param[in] stream       Stream to view to, e.g., `stdout`
937a982d89SJeremy L. Thompson 
947a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
957a982d89SJeremy L. Thompson 
967a982d89SJeremy L. Thompson   @ref Utility
977a982d89SJeremy L. Thompson **/
981203703bSJeremy L Thompson static int CeedOperatorFieldView(CeedOperatorField op_field, CeedQFunctionField qf_field, CeedInt field_number, bool sub, bool input, FILE *stream) {
997a982d89SJeremy L. Thompson   const char  *pre    = sub ? "  " : "";
100d1d35e2fSjeremylt   const char  *in_out = input ? "Input" : "Output";
1016f8994e9SJeremy L Thompson   const char  *field_name;
1021203703bSJeremy L Thompson   CeedInt      size;
1031203703bSJeremy L Thompson   CeedEvalMode eval_mode;
1041203703bSJeremy L Thompson   CeedVector   vec;
1051203703bSJeremy L Thompson   CeedBasis    basis;
1061203703bSJeremy L Thompson 
1071203703bSJeremy L Thompson   // Field data
108ab747706SJeremy L Thompson   CeedCall(CeedQFunctionFieldGetData(qf_field, &field_name, &size, &eval_mode));
109ab747706SJeremy L Thompson   CeedCall(CeedOperatorFieldGetData(op_field, NULL, NULL, &basis, &vec));
1107a982d89SJeremy L. Thompson 
1112b730f8bSJeremy L Thompson   fprintf(stream,
1122b730f8bSJeremy L Thompson           "%s    %s field %" CeedInt_FMT
1132b730f8bSJeremy L Thompson           ":\n"
1147a982d89SJeremy L. Thompson           "%s      Name: \"%s\"\n",
1151203703bSJeremy L Thompson           pre, in_out, field_number, pre, field_name);
1161203703bSJeremy L Thompson   fprintf(stream, "%s      Size: %" CeedInt_FMT "\n", pre, size);
1171203703bSJeremy L Thompson   fprintf(stream, "%s      EvalMode: %s\n", pre, CeedEvalModes[eval_mode]);
1181203703bSJeremy L Thompson   if (basis == CEED_BASIS_NONE) fprintf(stream, "%s      No basis\n", pre);
1191203703bSJeremy L Thompson   if (vec == CEED_VECTOR_ACTIVE) fprintf(stream, "%s      Active vector\n", pre);
1201203703bSJeremy L Thompson   else if (vec == CEED_VECTOR_NONE) fprintf(stream, "%s      No vector\n", pre);
121681d0ea7SJeremy L Thompson 
122681d0ea7SJeremy L Thompson   CeedCall(CeedVectorDestroy(&vec));
123681d0ea7SJeremy L Thompson   CeedCall(CeedBasisDestroy(&basis));
124e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1257a982d89SJeremy L. Thompson }
1267a982d89SJeremy L. Thompson 
1277a982d89SJeremy L. Thompson /**
128ca94c3ddSJeremy L Thompson   @brief View a single `CeedOperator`
1297a982d89SJeremy L. Thompson 
130ca94c3ddSJeremy L Thompson   @param[in] op     `CeedOperator` to view
1317a982d89SJeremy L. Thompson   @param[in] sub    Boolean flag for sub-operator
132ca94c3ddSJeremy L Thompson   @param[in] stream Stream to write; typically `stdout` or a file
1337a982d89SJeremy L. Thompson 
1347a982d89SJeremy L. Thompson   @return Error code: 0 - success, otherwise - failure
1357a982d89SJeremy L. Thompson 
1367a982d89SJeremy L. Thompson   @ref Utility
1377a982d89SJeremy L. Thompson **/
1387a982d89SJeremy L. Thompson int CeedOperatorSingleView(CeedOperator op, bool sub, FILE *stream) {
13999f7f61fSJeremy L Thompson   bool                is_at_points;
1407a982d89SJeremy L. Thompson   const char         *pre = sub ? "  " : "";
1411203703bSJeremy L Thompson   CeedInt             num_elem, num_qpts, total_fields = 0, num_input_fields, num_output_fields;
1421203703bSJeremy L Thompson   CeedQFunction       qf;
1431203703bSJeremy L Thompson   CeedQFunctionField *qf_input_fields, *qf_output_fields;
1441203703bSJeremy L Thompson   CeedOperatorField  *op_input_fields, *op_output_fields;
1457a982d89SJeremy L. Thompson 
14699f7f61fSJeremy L Thompson   CeedCall(CeedOperatorIsAtPoints(op, &is_at_points));
1472b730f8bSJeremy L Thompson   CeedCall(CeedOperatorGetNumElements(op, &num_elem));
1482b730f8bSJeremy L Thompson   CeedCall(CeedOperatorGetNumQuadraturePoints(op, &num_qpts));
1492b730f8bSJeremy L Thompson   CeedCall(CeedOperatorGetNumArgs(op, &total_fields));
1501203703bSJeremy L Thompson   CeedCall(CeedOperatorGetFields(op, &num_input_fields, &op_input_fields, &num_output_fields, &op_output_fields));
1511203703bSJeremy L Thompson   CeedCall(CeedOperatorGetQFunction(op, &qf));
1521203703bSJeremy L Thompson   CeedCall(CeedQFunctionGetFields(qf, NULL, &qf_input_fields, NULL, &qf_output_fields));
153c11e12f4SJeremy L Thompson   CeedCall(CeedQFunctionDestroy(&qf));
1541c66c397SJeremy L Thompson 
15599f7f61fSJeremy L Thompson   if (is_at_points) {
15699f7f61fSJeremy L Thompson     CeedInt             max_points = 0;
15799f7f61fSJeremy L Thompson     CeedElemRestriction rstr_points;
15899f7f61fSJeremy L Thompson 
15999f7f61fSJeremy L Thompson     CeedCall(CeedOperatorAtPointsGetPoints(op, &rstr_points, NULL));
16099f7f61fSJeremy L Thompson     CeedCall(CeedElemRestrictionGetMaxPointsInElement(rstr_points, &max_points));
16199f7f61fSJeremy L Thompson     fprintf(stream, "%s  %" CeedInt_FMT " elements with %" CeedInt_FMT " max points each\n", pre, num_elem, max_points);
16299f7f61fSJeremy L Thompson     CeedCall(CeedElemRestrictionDestroy(&rstr_points));
16399f7f61fSJeremy L Thompson   } else {
1642b730f8bSJeremy L Thompson     fprintf(stream, "%s  %" CeedInt_FMT " elements with %" CeedInt_FMT " quadrature points each\n", pre, num_elem, num_qpts);
16599f7f61fSJeremy L Thompson   }
1662b730f8bSJeremy L Thompson   fprintf(stream, "%s  %" CeedInt_FMT " field%s\n", pre, total_fields, total_fields > 1 ? "s" : "");
1671203703bSJeremy L Thompson   fprintf(stream, "%s  %" CeedInt_FMT " input field%s:\n", pre, num_input_fields, num_input_fields > 1 ? "s" : "");
1681203703bSJeremy L Thompson   for (CeedInt i = 0; i < num_input_fields; i++) {
1691203703bSJeremy L Thompson     CeedCall(CeedOperatorFieldView(op_input_fields[i], qf_input_fields[i], i, sub, 1, stream));
1707a982d89SJeremy L. Thompson   }
1711203703bSJeremy L Thompson   fprintf(stream, "%s  %" CeedInt_FMT " output field%s:\n", pre, num_output_fields, num_output_fields > 1 ? "s" : "");
1721203703bSJeremy L Thompson   for (CeedInt i = 0; i < num_output_fields; i++) {
1731203703bSJeremy L Thompson     CeedCall(CeedOperatorFieldView(op_output_fields[i], qf_output_fields[i], i, sub, 0, stream));
1747a982d89SJeremy L. Thompson   }
175e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1767a982d89SJeremy L. Thompson }
1777a982d89SJeremy L. Thompson 
178d99fa3c5SJeremy L Thompson /**
179681d0ea7SJeremy L Thompson   @brief Find the active input vector `CeedBasis` for a non-composite `CeedOperator`.
180681d0ea7SJeremy L Thompson 
181681d0ea7SJeremy L Thompson   Note: Caller is responsible for destroying the `active_basis` with @ref CeedBasisDestroy().
182eaf62fffSJeremy L Thompson 
183ca94c3ddSJeremy L Thompson   @param[in]  op           `CeedOperator` to find active `CeedBasis` for
184ca94c3ddSJeremy L Thompson   @param[out] active_basis `CeedBasis` for active input vector or `NULL` for composite operator
185eaf62fffSJeremy L Thompson 
186eaf62fffSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
187eaf62fffSJeremy L Thompson 
188eaf62fffSJeremy L Thompson   @ref Developer
189eaf62fffSJeremy L Thompson **/
190eaf62fffSJeremy L Thompson int CeedOperatorGetActiveBasis(CeedOperator op, CeedBasis *active_basis) {
191506b1a0cSSebastian Grimberg   CeedCall(CeedOperatorGetActiveBases(op, active_basis, NULL));
192506b1a0cSSebastian Grimberg   return CEED_ERROR_SUCCESS;
193506b1a0cSSebastian Grimberg }
194506b1a0cSSebastian Grimberg 
195506b1a0cSSebastian Grimberg /**
196681d0ea7SJeremy L Thompson   @brief Find the active input and output vector `CeedBasis` for a non-composite `CeedOperator`.
197681d0ea7SJeremy L Thompson 
198681d0ea7SJeremy L Thompson   Note: Caller is responsible for destroying the bases with @ref CeedBasisDestroy().
199506b1a0cSSebastian Grimberg 
200ca94c3ddSJeremy L Thompson   @param[in]  op                  `CeedOperator` to find active `CeedBasis` for
201ca94c3ddSJeremy L Thompson   @param[out] active_input_basis  `CeedBasis` for active input vector or `NULL` for composite operator
202ca94c3ddSJeremy L Thompson   @param[out] active_output_basis `CeedBasis` for active output vector or `NULL` for composite operator
203506b1a0cSSebastian Grimberg 
204506b1a0cSSebastian Grimberg   @return An error code: 0 - success, otherwise - failure
205506b1a0cSSebastian Grimberg 
206506b1a0cSSebastian Grimberg   @ref Developer
207506b1a0cSSebastian Grimberg **/
208506b1a0cSSebastian Grimberg int CeedOperatorGetActiveBases(CeedOperator op, CeedBasis *active_input_basis, CeedBasis *active_output_basis) {
2091203703bSJeremy L Thompson   bool               is_composite;
2101203703bSJeremy L Thompson   CeedInt            num_input_fields, num_output_fields;
2111203703bSJeremy L Thompson   CeedOperatorField *op_input_fields, *op_output_fields;
2121c66c397SJeremy L Thompson 
2131203703bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
2141203703bSJeremy L Thompson   CeedCall(CeedOperatorGetFields(op, &num_input_fields, &op_input_fields, &num_output_fields, &op_output_fields));
2151203703bSJeremy L Thompson 
216506b1a0cSSebastian Grimberg   if (active_input_basis) {
217506b1a0cSSebastian Grimberg     *active_input_basis = NULL;
2181203703bSJeremy L Thompson     if (!is_composite) {
2191203703bSJeremy L Thompson       for (CeedInt i = 0; i < num_input_fields; i++) {
2201203703bSJeremy L Thompson         CeedVector vec;
2211203703bSJeremy L Thompson 
2221203703bSJeremy L Thompson         CeedCall(CeedOperatorFieldGetVector(op_input_fields[i], &vec));
2231203703bSJeremy L Thompson         if (vec == CEED_VECTOR_ACTIVE) {
2241203703bSJeremy L Thompson           CeedBasis basis;
2251203703bSJeremy L Thompson 
2261203703bSJeremy L Thompson           CeedCall(CeedOperatorFieldGetBasis(op_input_fields[i], &basis));
2279bc66399SJeremy L Thompson           CeedCheck(!*active_input_basis || *active_input_basis == basis, CeedOperatorReturnCeed(op), CEED_ERROR_MINOR,
2289bc66399SJeremy L Thompson                     "Multiple active input CeedBases found");
229681d0ea7SJeremy L Thompson           if (!*active_input_basis) CeedCall(CeedBasisReferenceCopy(basis, active_input_basis));
230681d0ea7SJeremy L Thompson           CeedCall(CeedBasisDestroy(&basis));
231eaf62fffSJeremy L Thompson         }
232681d0ea7SJeremy L Thompson         CeedCall(CeedVectorDestroy(&vec));
2332b730f8bSJeremy L Thompson       }
2349bc66399SJeremy L Thompson       CeedCheck(*active_input_basis, CeedOperatorReturnCeed(op), CEED_ERROR_INCOMPLETE, "No active input CeedBasis found");
235506b1a0cSSebastian Grimberg     }
236506b1a0cSSebastian Grimberg   }
237506b1a0cSSebastian Grimberg   if (active_output_basis) {
238506b1a0cSSebastian Grimberg     *active_output_basis = NULL;
2391203703bSJeremy L Thompson     if (!is_composite) {
2401203703bSJeremy L Thompson       for (CeedInt i = 0; i < num_output_fields; i++) {
2411203703bSJeremy L Thompson         CeedVector vec;
2421203703bSJeremy L Thompson 
2431203703bSJeremy L Thompson         CeedCall(CeedOperatorFieldGetVector(op_output_fields[i], &vec));
2441203703bSJeremy L Thompson         if (vec == CEED_VECTOR_ACTIVE) {
2451203703bSJeremy L Thompson           CeedBasis basis;
2461203703bSJeremy L Thompson 
2471203703bSJeremy L Thompson           CeedCall(CeedOperatorFieldGetBasis(op_output_fields[i], &basis));
2489bc66399SJeremy L Thompson           CeedCheck(!*active_output_basis || *active_output_basis == basis, CeedOperatorReturnCeed(op), CEED_ERROR_MINOR,
2499bc66399SJeremy L Thompson                     "Multiple active output CeedBases found");
250681d0ea7SJeremy L Thompson           if (!*active_output_basis) CeedCall(CeedBasisReferenceCopy(basis, active_output_basis));
251681d0ea7SJeremy L Thompson           CeedCall(CeedBasisDestroy(&basis));
252506b1a0cSSebastian Grimberg         }
253681d0ea7SJeremy L Thompson         CeedCall(CeedVectorDestroy(&vec));
254506b1a0cSSebastian Grimberg       }
2559bc66399SJeremy L Thompson       CeedCheck(*active_output_basis, CeedOperatorReturnCeed(op), CEED_ERROR_INCOMPLETE, "No active output CeedBasis found");
256506b1a0cSSebastian Grimberg     }
257506b1a0cSSebastian Grimberg   }
258eaf62fffSJeremy L Thompson   return CEED_ERROR_SUCCESS;
259eaf62fffSJeremy L Thompson }
260eaf62fffSJeremy L Thompson 
261eaf62fffSJeremy L Thompson /**
262681d0ea7SJeremy L Thompson   @brief Find the active vector `CeedElemRestriction` for a non-composite `CeedOperator`.
263681d0ea7SJeremy L Thompson 
264681d0ea7SJeremy L Thompson   Note: Caller is responsible for destroying the `active_rstr` with @ref CeedElemRestrictionDestroy().
265e2f04181SAndrew T. Barker 
266ca94c3ddSJeremy L Thompson   @param[in]  op          `CeedOperator` to find active `CeedElemRestriction` for
267ca94c3ddSJeremy L Thompson   @param[out] active_rstr `CeedElemRestriction` for active input vector or NULL for composite operator
268e2f04181SAndrew T. Barker 
269e2f04181SAndrew T. Barker   @return An error code: 0 - success, otherwise - failure
270e2f04181SAndrew T. Barker 
271e2f04181SAndrew T. Barker   @ref Utility
272e2f04181SAndrew T. Barker **/
2732b730f8bSJeremy L Thompson int CeedOperatorGetActiveElemRestriction(CeedOperator op, CeedElemRestriction *active_rstr) {
274506b1a0cSSebastian Grimberg   CeedCall(CeedOperatorGetActiveElemRestrictions(op, active_rstr, NULL));
275506b1a0cSSebastian Grimberg   return CEED_ERROR_SUCCESS;
276506b1a0cSSebastian Grimberg }
277506b1a0cSSebastian Grimberg 
278506b1a0cSSebastian Grimberg /**
279681d0ea7SJeremy L Thompson   @brief Find the active input and output vector `CeedElemRestriction` for a non-composite `CeedOperator`.
280681d0ea7SJeremy L Thompson 
281681d0ea7SJeremy L Thompson   Note: Caller is responsible for destroying the restrictions with @ref CeedElemRestrictionDestroy().
282506b1a0cSSebastian Grimberg 
283ca94c3ddSJeremy L Thompson   @param[in]  op                 `CeedOperator` to find active `CeedElemRestriction` for
284ca94c3ddSJeremy L Thompson   @param[out] active_input_rstr  `CeedElemRestriction` for active input vector or NULL for composite operator
285ca94c3ddSJeremy L Thompson   @param[out] active_output_rstr `CeedElemRestriction` for active output vector or NULL for composite operator
286506b1a0cSSebastian Grimberg 
287506b1a0cSSebastian Grimberg   @return An error code: 0 - success, otherwise - failure
288506b1a0cSSebastian Grimberg 
289506b1a0cSSebastian Grimberg   @ref Utility
290506b1a0cSSebastian Grimberg **/
291506b1a0cSSebastian Grimberg int CeedOperatorGetActiveElemRestrictions(CeedOperator op, CeedElemRestriction *active_input_rstr, CeedElemRestriction *active_output_rstr) {
2921203703bSJeremy L Thompson   bool               is_composite;
2931203703bSJeremy L Thompson   CeedInt            num_input_fields, num_output_fields;
2941203703bSJeremy L Thompson   CeedOperatorField *op_input_fields, *op_output_fields;
2951c66c397SJeremy L Thompson 
2961203703bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
2971203703bSJeremy L Thompson   CeedCall(CeedOperatorGetFields(op, &num_input_fields, &op_input_fields, &num_output_fields, &op_output_fields));
2981203703bSJeremy L Thompson 
299506b1a0cSSebastian Grimberg   if (active_input_rstr) {
300506b1a0cSSebastian Grimberg     *active_input_rstr = NULL;
3011203703bSJeremy L Thompson     if (!is_composite) {
3021203703bSJeremy L Thompson       for (CeedInt i = 0; i < num_input_fields; i++) {
3031203703bSJeremy L Thompson         CeedVector vec;
3041203703bSJeremy L Thompson 
3051203703bSJeremy L Thompson         CeedCall(CeedOperatorFieldGetVector(op_input_fields[i], &vec));
3061203703bSJeremy L Thompson         if (vec == CEED_VECTOR_ACTIVE) {
3071203703bSJeremy L Thompson           CeedElemRestriction rstr;
3081203703bSJeremy L Thompson 
3091203703bSJeremy L Thompson           CeedCall(CeedOperatorFieldGetElemRestriction(op_input_fields[i], &rstr));
3109bc66399SJeremy L Thompson           CeedCheck(!*active_input_rstr || *active_input_rstr == rstr, CeedOperatorReturnCeed(op), CEED_ERROR_MINOR,
3119bc66399SJeremy L Thompson                     "Multiple active input CeedElemRestrictions found");
312681d0ea7SJeremy L Thompson           if (!*active_input_rstr) CeedCall(CeedElemRestrictionReferenceCopy(rstr, active_input_rstr));
313681d0ea7SJeremy L Thompson           CeedCall(CeedElemRestrictionDestroy(&rstr));
314e2f04181SAndrew T. Barker         }
315681d0ea7SJeremy L Thompson         CeedCall(CeedVectorDestroy(&vec));
3162b730f8bSJeremy L Thompson       }
3179bc66399SJeremy L Thompson       CeedCheck(*active_input_rstr, CeedOperatorReturnCeed(op), CEED_ERROR_INCOMPLETE, "No active input CeedElemRestriction found");
318506b1a0cSSebastian Grimberg     }
319506b1a0cSSebastian Grimberg   }
320506b1a0cSSebastian Grimberg   if (active_output_rstr) {
321506b1a0cSSebastian Grimberg     *active_output_rstr = NULL;
3221203703bSJeremy L Thompson     if (!is_composite) {
3231203703bSJeremy L Thompson       for (CeedInt i = 0; i < num_output_fields; i++) {
3241203703bSJeremy L Thompson         CeedVector vec;
3251203703bSJeremy L Thompson 
3261203703bSJeremy L Thompson         CeedCall(CeedOperatorFieldGetVector(op_output_fields[i], &vec));
3271203703bSJeremy L Thompson         if (vec == CEED_VECTOR_ACTIVE) {
3281203703bSJeremy L Thompson           CeedElemRestriction rstr;
3291203703bSJeremy L Thompson 
3301203703bSJeremy L Thompson           CeedCall(CeedOperatorFieldGetElemRestriction(op_output_fields[i], &rstr));
3319bc66399SJeremy L Thompson           CeedCheck(!*active_output_rstr || *active_output_rstr == rstr, CeedOperatorReturnCeed(op), CEED_ERROR_MINOR,
3329bc66399SJeremy L Thompson                     "Multiple active output CeedElemRestrictions found");
333681d0ea7SJeremy L Thompson           if (!*active_output_rstr) CeedCall(CeedElemRestrictionReferenceCopy(rstr, active_output_rstr));
334681d0ea7SJeremy L Thompson           CeedCall(CeedElemRestrictionDestroy(&rstr));
335506b1a0cSSebastian Grimberg         }
336681d0ea7SJeremy L Thompson         CeedCall(CeedVectorDestroy(&vec));
337506b1a0cSSebastian Grimberg       }
3389bc66399SJeremy L Thompson       CeedCheck(*active_output_rstr, CeedOperatorReturnCeed(op), CEED_ERROR_INCOMPLETE, "No active output CeedElemRestriction found");
339506b1a0cSSebastian Grimberg     }
340506b1a0cSSebastian Grimberg   }
341e2f04181SAndrew T. Barker   return CEED_ERROR_SUCCESS;
342e2f04181SAndrew T. Barker }
343e2f04181SAndrew T. Barker 
344d8dd9a91SJeremy L Thompson /**
345ca94c3ddSJeremy L Thompson   @brief Set `CeedQFunctionContext` field values of the specified type.
3464385fb7fSSebastian Grimberg 
347ca94c3ddSJeremy L Thompson   For composite operators, the value is set in all sub-operator `CeedQFunctionContext` that have a matching `field_name`.
348ca94c3ddSJeremy L Thompson   A non-zero error code is returned for single operators that do not have a matching field of the same type or composite operators that do not have any field of a matching type.
349d8dd9a91SJeremy L Thompson 
350ca94c3ddSJeremy L Thompson   @param[in,out] op          `CeedOperator`
351ea61e9acSJeremy L Thompson   @param[in]     field_label Label of field to set
352ea61e9acSJeremy L Thompson   @param[in]     field_type  Type of field to set
3532788fa27SJeremy L Thompson   @param[in]     values      Values to set
354d8dd9a91SJeremy L Thompson 
355d8dd9a91SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
356d8dd9a91SJeremy L Thompson 
3576ab8e59fSJames Wright   @ref Developer
358d8dd9a91SJeremy L Thompson **/
3592788fa27SJeremy L Thompson static int CeedOperatorContextSetGeneric(CeedOperator op, CeedContextFieldLabel field_label, CeedContextFieldType field_type, void *values) {
3601c66c397SJeremy L Thompson   bool is_composite = false;
3611c66c397SJeremy L Thompson 
3629bc66399SJeremy L Thompson   CeedCheck(field_label, CeedOperatorReturnCeed(op), CEED_ERROR_UNSUPPORTED, "Invalid field label");
3633668ca4bSJeremy L Thompson 
3645ac9af79SJeremy L Thompson   // Check if field_label and op correspond
3655ac9af79SJeremy L Thompson   if (field_label->from_op) {
3665ac9af79SJeremy L Thompson     CeedInt index = -1;
3675ac9af79SJeremy L Thompson 
3685ac9af79SJeremy L Thompson     for (CeedInt i = 0; i < op->num_context_labels; i++) {
3695ac9af79SJeremy L Thompson       if (op->context_labels[i] == field_label) index = i;
3705ac9af79SJeremy L Thompson     }
3719bc66399SJeremy L Thompson     CeedCheck(index != -1, CeedOperatorReturnCeed(op), CEED_ERROR_UNSUPPORTED, "ContextFieldLabel does not correspond to the operator");
3725ac9af79SJeremy L Thompson   }
3735ac9af79SJeremy L Thompson 
3742b730f8bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
375d8dd9a91SJeremy L Thompson   if (is_composite) {
376d8dd9a91SJeremy L Thompson     CeedInt       num_sub;
377d8dd9a91SJeremy L Thompson     CeedOperator *sub_operators;
378d8dd9a91SJeremy L Thompson 
379*ed094490SJeremy L Thompson     CeedCall(CeedOperatorCompositeGetNumSub(op, &num_sub));
380*ed094490SJeremy L Thompson     CeedCall(CeedOperatorCompositeGetSubList(op, &sub_operators));
3819bc66399SJeremy L Thompson     CeedCheck(num_sub == field_label->num_sub_labels, CeedOperatorReturnCeed(op), CEED_ERROR_UNSUPPORTED,
3829bc66399SJeremy L Thompson               "Composite operator modified after ContextFieldLabel created");
383d8dd9a91SJeremy L Thompson 
384d8dd9a91SJeremy L Thompson     for (CeedInt i = 0; i < num_sub; i++) {
3851203703bSJeremy L Thompson       CeedQFunctionContext ctx;
3861203703bSJeremy L Thompson 
3871485364cSJeremy L Thompson       CeedCall(CeedOperatorGetContext(sub_operators[i], &ctx));
388d8dd9a91SJeremy L Thompson       // Try every sub-operator, ok if some sub-operators do not have field
3891485364cSJeremy L Thompson       if (ctx && field_label->sub_labels[i]) {
3901203703bSJeremy L Thompson         CeedCall(CeedQFunctionContextSetGeneric(ctx, field_label->sub_labels[i], field_type, values));
391d8dd9a91SJeremy L Thompson       }
3921485364cSJeremy L Thompson       CeedCall(CeedQFunctionContextDestroy(&ctx));
393d8dd9a91SJeremy L Thompson     }
394d8dd9a91SJeremy L Thompson   } else {
3951203703bSJeremy L Thompson     CeedQFunctionContext ctx;
3961203703bSJeremy L Thompson 
3971485364cSJeremy L Thompson     CeedCall(CeedOperatorGetContext(op, &ctx));
3989bc66399SJeremy L Thompson     CeedCheck(ctx, CeedOperatorReturnCeed(op), CEED_ERROR_UNSUPPORTED, "QFunction does not have context data");
3991203703bSJeremy L Thompson     CeedCall(CeedQFunctionContextSetGeneric(ctx, field_label, field_type, values));
4001485364cSJeremy L Thompson     CeedCall(CeedQFunctionContextDestroy(&ctx));
4012788fa27SJeremy L Thompson   }
4026d95ab46SJeremy L Thompson   CeedCall(CeedOperatorSetQFunctionAssemblyDataUpdateNeeded(op, true));
4032788fa27SJeremy L Thompson   return CEED_ERROR_SUCCESS;
4042788fa27SJeremy L Thompson }
4052788fa27SJeremy L Thompson 
4062788fa27SJeremy L Thompson /**
407ca94c3ddSJeremy L Thompson   @brief Get `CeedQFunctionContext` field values of the specified type, read-only.
4084385fb7fSSebastian Grimberg 
409ca94c3ddSJeremy L Thompson   For composite operators, the values retrieved are for the first sub-operator `CeedQFunctionContext` that have a matching `field_name`.
410ca94c3ddSJeremy L Thompson   A non-zero error code is returned for single operators that do not have a matching field of the same type or composite operators that do not have any field of a matching type.
4112788fa27SJeremy L Thompson 
412ca94c3ddSJeremy L Thompson   @param[in,out] op          `CeedOperator`
4132788fa27SJeremy L Thompson   @param[in]     field_label Label of field to set
4142788fa27SJeremy L Thompson   @param[in]     field_type  Type of field to set
415c5d0f995SJed Brown   @param[out]    num_values  Number of values of type `field_type` in array `values`
416c5d0f995SJed Brown   @param[out]    values      Values in the label
4172788fa27SJeremy L Thompson 
4182788fa27SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
4192788fa27SJeremy L Thompson 
4206ab8e59fSJames Wright   @ref Developer
4212788fa27SJeremy L Thompson **/
4222788fa27SJeremy L Thompson static int CeedOperatorContextGetGenericRead(CeedOperator op, CeedContextFieldLabel field_label, CeedContextFieldType field_type, size_t *num_values,
4232788fa27SJeremy L Thompson                                              void *values) {
4241c66c397SJeremy L Thompson   bool is_composite = false;
4251c66c397SJeremy L Thompson 
4269bc66399SJeremy L Thompson   CeedCheck(field_label, CeedOperatorReturnCeed(op), CEED_ERROR_UNSUPPORTED, "Invalid field label");
4272788fa27SJeremy L Thompson 
4282788fa27SJeremy L Thompson   *(void **)values = NULL;
4292788fa27SJeremy L Thompson   *num_values      = 0;
4302788fa27SJeremy L Thompson 
4315ac9af79SJeremy L Thompson   // Check if field_label and op correspond
4325ac9af79SJeremy L Thompson   if (field_label->from_op) {
4335ac9af79SJeremy L Thompson     CeedInt index = -1;
4345ac9af79SJeremy L Thompson 
4355ac9af79SJeremy L Thompson     for (CeedInt i = 0; i < op->num_context_labels; i++) {
4365ac9af79SJeremy L Thompson       if (op->context_labels[i] == field_label) index = i;
4375ac9af79SJeremy L Thompson     }
4389bc66399SJeremy L Thompson     CeedCheck(index != -1, CeedOperatorReturnCeed(op), CEED_ERROR_UNSUPPORTED, "ContextFieldLabel does not correspond to the operator");
4395ac9af79SJeremy L Thompson   }
4405ac9af79SJeremy L Thompson 
4412788fa27SJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
4422788fa27SJeremy L Thompson   if (is_composite) {
4432788fa27SJeremy L Thompson     CeedInt       num_sub;
4442788fa27SJeremy L Thompson     CeedOperator *sub_operators;
4452788fa27SJeremy L Thompson 
446*ed094490SJeremy L Thompson     CeedCall(CeedOperatorCompositeGetNumSub(op, &num_sub));
447*ed094490SJeremy L Thompson     CeedCall(CeedOperatorCompositeGetSubList(op, &sub_operators));
4489bc66399SJeremy L Thompson     CeedCheck(num_sub == field_label->num_sub_labels, CeedOperatorReturnCeed(op), CEED_ERROR_UNSUPPORTED,
4499bc66399SJeremy L Thompson               "Composite operator modified after ContextFieldLabel created");
4502788fa27SJeremy L Thompson 
4512788fa27SJeremy L Thompson     for (CeedInt i = 0; i < num_sub; i++) {
4521203703bSJeremy L Thompson       CeedQFunctionContext ctx;
4531203703bSJeremy L Thompson 
4541485364cSJeremy L Thompson       CeedCall(CeedOperatorGetContext(sub_operators[i], &ctx));
4552788fa27SJeremy L Thompson       // Try every sub-operator, ok if some sub-operators do not have field
4561485364cSJeremy L Thompson       if (ctx && field_label->sub_labels[i]) {
4571203703bSJeremy L Thompson         CeedCall(CeedQFunctionContextGetGenericRead(ctx, field_label->sub_labels[i], field_type, num_values, values));
4581485364cSJeremy L Thompson         CeedCall(CeedQFunctionContextDestroy(&ctx));
4592788fa27SJeremy L Thompson         return CEED_ERROR_SUCCESS;
4602788fa27SJeremy L Thompson       }
4611485364cSJeremy L Thompson       CeedCall(CeedQFunctionContextDestroy(&ctx));
4622788fa27SJeremy L Thompson     }
4632788fa27SJeremy L Thompson   } else {
4641203703bSJeremy L Thompson     CeedQFunctionContext ctx;
4651203703bSJeremy L Thompson 
4661485364cSJeremy L Thompson     CeedCall(CeedOperatorGetContext(op, &ctx));
4679bc66399SJeremy L Thompson     CeedCheck(ctx, CeedOperatorReturnCeed(op), CEED_ERROR_UNSUPPORTED, "QFunction does not have context data");
4681203703bSJeremy L Thompson     CeedCall(CeedQFunctionContextGetGenericRead(ctx, field_label, field_type, num_values, values));
4691485364cSJeremy L Thompson     CeedCall(CeedQFunctionContextDestroy(&ctx));
4702788fa27SJeremy L Thompson   }
4712788fa27SJeremy L Thompson   return CEED_ERROR_SUCCESS;
4722788fa27SJeremy L Thompson }
4732788fa27SJeremy L Thompson 
4742788fa27SJeremy L Thompson /**
475ca94c3ddSJeremy L Thompson   @brief Restore `CeedQFunctionContext` field values of the specified type, read-only.
4764385fb7fSSebastian Grimberg 
477ca94c3ddSJeremy L Thompson   For composite operators, the values restored are for the first sub-operator `CeedQFunctionContext` that have a matching `field_name`.
478ca94c3ddSJeremy L Thompson   A non-zero error code is returned for single operators that do not have a matching field of the same type or composite operators that do not have any field of a matching type.
4792788fa27SJeremy L Thompson 
480ca94c3ddSJeremy L Thompson   @param[in,out] op          `CeedOperator`
4812788fa27SJeremy L Thompson   @param[in]     field_label Label of field to set
4822788fa27SJeremy L Thompson   @param[in]     field_type  Type of field to set
483c5d0f995SJed Brown   @param[in]     values      Values array to restore
4842788fa27SJeremy L Thompson 
4852788fa27SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
4862788fa27SJeremy L Thompson 
4876ab8e59fSJames Wright   @ref Developer
4882788fa27SJeremy L Thompson **/
4892788fa27SJeremy L Thompson static int CeedOperatorContextRestoreGenericRead(CeedOperator op, CeedContextFieldLabel field_label, CeedContextFieldType field_type, void *values) {
4901c66c397SJeremy L Thompson   bool is_composite = false;
4911c66c397SJeremy L Thompson 
4929bc66399SJeremy L Thompson   CeedCheck(field_label, CeedOperatorReturnCeed(op), CEED_ERROR_UNSUPPORTED, "Invalid field label");
4932788fa27SJeremy L Thompson 
4945ac9af79SJeremy L Thompson   // Check if field_label and op correspond
4955ac9af79SJeremy L Thompson   if (field_label->from_op) {
4965ac9af79SJeremy L Thompson     CeedInt index = -1;
4975ac9af79SJeremy L Thompson 
4985ac9af79SJeremy L Thompson     for (CeedInt i = 0; i < op->num_context_labels; i++) {
4995ac9af79SJeremy L Thompson       if (op->context_labels[i] == field_label) index = i;
5005ac9af79SJeremy L Thompson     }
5019bc66399SJeremy L Thompson     CeedCheck(index != -1, CeedOperatorReturnCeed(op), CEED_ERROR_UNSUPPORTED, "ContextFieldLabel does not correspond to the operator");
5025ac9af79SJeremy L Thompson   }
5035ac9af79SJeremy L Thompson 
5042788fa27SJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
5052788fa27SJeremy L Thompson   if (is_composite) {
5062788fa27SJeremy L Thompson     CeedInt       num_sub;
5072788fa27SJeremy L Thompson     CeedOperator *sub_operators;
5082788fa27SJeremy L Thompson 
509*ed094490SJeremy L Thompson     CeedCall(CeedOperatorCompositeGetNumSub(op, &num_sub));
510*ed094490SJeremy L Thompson     CeedCall(CeedOperatorCompositeGetSubList(op, &sub_operators));
5119bc66399SJeremy L Thompson     CeedCheck(num_sub == field_label->num_sub_labels, CeedOperatorReturnCeed(op), CEED_ERROR_UNSUPPORTED,
5129bc66399SJeremy L Thompson               "Composite operator modified after ContextFieldLabel created");
5132788fa27SJeremy L Thompson 
5142788fa27SJeremy L Thompson     for (CeedInt i = 0; i < num_sub; i++) {
5151203703bSJeremy L Thompson       CeedQFunctionContext ctx;
5161203703bSJeremy L Thompson 
5171485364cSJeremy L Thompson       CeedCall(CeedOperatorGetContext(sub_operators[i], &ctx));
5182788fa27SJeremy L Thompson       // Try every sub-operator, ok if some sub-operators do not have field
5191485364cSJeremy L Thompson       if (ctx && field_label->sub_labels[i]) {
5201203703bSJeremy L Thompson         CeedCall(CeedQFunctionContextRestoreGenericRead(ctx, field_label->sub_labels[i], field_type, values));
5211485364cSJeremy L Thompson         CeedCall(CeedQFunctionContextDestroy(&ctx));
5222788fa27SJeremy L Thompson         return CEED_ERROR_SUCCESS;
5232788fa27SJeremy L Thompson       }
5241485364cSJeremy L Thompson       CeedCall(CeedQFunctionContextDestroy(&ctx));
5252788fa27SJeremy L Thompson     }
5262788fa27SJeremy L Thompson   } else {
5271203703bSJeremy L Thompson     CeedQFunctionContext ctx;
5281203703bSJeremy L Thompson 
5291485364cSJeremy L Thompson     CeedCall(CeedOperatorGetContext(op, &ctx));
5309bc66399SJeremy L Thompson     CeedCheck(ctx, CeedOperatorReturnCeed(op), CEED_ERROR_UNSUPPORTED, "QFunction does not have context data");
5311203703bSJeremy L Thompson     CeedCall(CeedQFunctionContextRestoreGenericRead(ctx, field_label, field_type, values));
5321485364cSJeremy L Thompson     CeedCall(CeedQFunctionContextDestroy(&ctx));
533d8dd9a91SJeremy L Thompson   }
534d8dd9a91SJeremy L Thompson   return CEED_ERROR_SUCCESS;
535d8dd9a91SJeremy L Thompson }
536d8dd9a91SJeremy L Thompson 
5377a982d89SJeremy L. Thompson /// @}
5387a982d89SJeremy L. Thompson 
5397a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
5407a982d89SJeremy L. Thompson /// CeedOperator Backend API
5417a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
5427a982d89SJeremy L. Thompson /// @addtogroup CeedOperatorBackend
5437a982d89SJeremy L. Thompson /// @{
5447a982d89SJeremy L. Thompson 
5457a982d89SJeremy L. Thompson /**
546ca94c3ddSJeremy L Thompson   @brief Get the number of arguments associated with a `CeedOperator`
5477a982d89SJeremy L. Thompson 
548ca94c3ddSJeremy L Thompson   @param[in]  op        `CeedOperator`
549d1d35e2fSjeremylt   @param[out] num_args  Variable to store vector number of arguments
5507a982d89SJeremy L. Thompson 
5517a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5527a982d89SJeremy L. Thompson 
5537a982d89SJeremy L. Thompson   @ref Backend
5547a982d89SJeremy L. Thompson **/
555d1d35e2fSjeremylt int CeedOperatorGetNumArgs(CeedOperator op, CeedInt *num_args) {
5561203703bSJeremy L Thompson   bool is_composite;
5571203703bSJeremy L Thompson 
5581203703bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
5596e536b99SJeremy L Thompson   CeedCheck(!is_composite, CeedOperatorReturnCeed(op), CEED_ERROR_MINOR, "Not defined for composite operators");
560d1d35e2fSjeremylt   *num_args = op->num_fields;
561e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5627a982d89SJeremy L. Thompson }
5637a982d89SJeremy L. Thompson 
5647a982d89SJeremy L. Thompson /**
5659463e855SJeremy L Thompson   @brief Get the tensor product status of all bases for a `CeedOperator`.
5669463e855SJeremy L Thompson 
5679463e855SJeremy L Thompson   `has_tensor_bases` is only set to `true` if every field uses a tensor-product basis.
5689463e855SJeremy L Thompson 
5699463e855SJeremy L Thompson   @param[in]  op               `CeedOperator`
5709463e855SJeremy L Thompson   @param[out] has_tensor_bases Variable to store tensor bases status
5719463e855SJeremy L Thompson 
5729463e855SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
5739463e855SJeremy L Thompson 
5749463e855SJeremy L Thompson   @ref Backend
5759463e855SJeremy L Thompson **/
5769463e855SJeremy L Thompson int CeedOperatorHasTensorBases(CeedOperator op, bool *has_tensor_bases) {
5779463e855SJeremy L Thompson   CeedInt            num_inputs, num_outputs;
5789463e855SJeremy L Thompson   CeedOperatorField *input_fields, *output_fields;
5799463e855SJeremy L Thompson 
5809463e855SJeremy L Thompson   CeedCall(CeedOperatorGetFields(op, &num_inputs, &input_fields, &num_outputs, &output_fields));
5819463e855SJeremy L Thompson   *has_tensor_bases = true;
5829463e855SJeremy L Thompson   for (CeedInt i = 0; i < num_inputs; i++) {
5839463e855SJeremy L Thompson     bool      is_tensor;
5849463e855SJeremy L Thompson     CeedBasis basis;
5859463e855SJeremy L Thompson 
5869463e855SJeremy L Thompson     CeedCall(CeedOperatorFieldGetBasis(input_fields[i], &basis));
5879463e855SJeremy L Thompson     if (basis != CEED_BASIS_NONE) {
5889463e855SJeremy L Thompson       CeedCall(CeedBasisIsTensor(basis, &is_tensor));
589025ec10cSJeremy L Thompson       *has_tensor_bases = *has_tensor_bases & is_tensor;
5909463e855SJeremy L Thompson     }
591681d0ea7SJeremy L Thompson     CeedCall(CeedBasisDestroy(&basis));
5929463e855SJeremy L Thompson   }
5939463e855SJeremy L Thompson   for (CeedInt i = 0; i < num_outputs; i++) {
5949463e855SJeremy L Thompson     bool      is_tensor;
5959463e855SJeremy L Thompson     CeedBasis basis;
5969463e855SJeremy L Thompson 
5979463e855SJeremy L Thompson     CeedCall(CeedOperatorFieldGetBasis(output_fields[i], &basis));
5989463e855SJeremy L Thompson     if (basis != CEED_BASIS_NONE) {
5999463e855SJeremy L Thompson       CeedCall(CeedBasisIsTensor(basis, &is_tensor));
600025ec10cSJeremy L Thompson       *has_tensor_bases = *has_tensor_bases & is_tensor;
6019463e855SJeremy L Thompson     }
602681d0ea7SJeremy L Thompson     CeedCall(CeedBasisDestroy(&basis));
6039463e855SJeremy L Thompson   }
6049463e855SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6059463e855SJeremy L Thompson }
6069463e855SJeremy L Thompson 
6079463e855SJeremy L Thompson /**
6081203703bSJeremy L Thompson   @brief Get a boolean value indicating if the `CeedOperator` is immutable
6091203703bSJeremy L Thompson 
6101203703bSJeremy L Thompson   @param[in]  op           `CeedOperator`
6111203703bSJeremy L Thompson   @param[out] is_immutable Variable to store immutability status
6121203703bSJeremy L Thompson 
6131203703bSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
6141203703bSJeremy L Thompson 
6151203703bSJeremy L Thompson   @ref Backend
6161203703bSJeremy L Thompson **/
6171203703bSJeremy L Thompson int CeedOperatorIsImmutable(CeedOperator op, bool *is_immutable) {
6181203703bSJeremy L Thompson   *is_immutable = op->is_immutable;
6191203703bSJeremy L Thompson   return CEED_ERROR_SUCCESS;
6201203703bSJeremy L Thompson }
6211203703bSJeremy L Thompson 
6221203703bSJeremy L Thompson /**
623ca94c3ddSJeremy L Thompson   @brief Get the setup status of a `CeedOperator`
6247a982d89SJeremy L. Thompson 
625ca94c3ddSJeremy L Thompson   @param[in]  op            `CeedOperator`
626d1d35e2fSjeremylt   @param[out] is_setup_done Variable to store setup status
6277a982d89SJeremy L. Thompson 
6287a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6297a982d89SJeremy L. Thompson 
6307a982d89SJeremy L. Thompson   @ref Backend
6317a982d89SJeremy L. Thompson **/
632d1d35e2fSjeremylt int CeedOperatorIsSetupDone(CeedOperator op, bool *is_setup_done) {
633f04ea552SJeremy L Thompson   *is_setup_done = op->is_backend_setup;
634e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6357a982d89SJeremy L. Thompson }
6367a982d89SJeremy L. Thompson 
6377a982d89SJeremy L. Thompson /**
638ca94c3ddSJeremy L Thompson   @brief Get the `CeedQFunction` associated with a `CeedOperator`
6397a982d89SJeremy L. Thompson 
640ca94c3ddSJeremy L Thompson   @param[in]  op `CeedOperator`
641ca94c3ddSJeremy L Thompson   @param[out] qf Variable to store `CeedQFunction`
6427a982d89SJeremy L. Thompson 
6437a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6447a982d89SJeremy L. Thompson 
6457a982d89SJeremy L. Thompson   @ref Backend
6467a982d89SJeremy L. Thompson **/
6477a982d89SJeremy L. Thompson int CeedOperatorGetQFunction(CeedOperator op, CeedQFunction *qf) {
6481203703bSJeremy L Thompson   bool is_composite;
6491203703bSJeremy L Thompson 
6501203703bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
6516e536b99SJeremy L Thompson   CeedCheck(!is_composite, CeedOperatorReturnCeed(op), CEED_ERROR_MINOR, "Not defined for composite operator");
652c11e12f4SJeremy L Thompson   *qf = NULL;
653c11e12f4SJeremy L Thompson   CeedCall(CeedQFunctionReferenceCopy(op->qf, qf));
654e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6557a982d89SJeremy L. Thompson }
6567a982d89SJeremy L. Thompson 
6577a982d89SJeremy L. Thompson /**
658ca94c3ddSJeremy L Thompson   @brief Get a boolean value indicating if the `CeedOperator` is composite
659c04a41a7SJeremy L Thompson 
660ca94c3ddSJeremy L Thompson   @param[in]  op           `CeedOperator`
661d1d35e2fSjeremylt   @param[out] is_composite Variable to store composite status
662c04a41a7SJeremy L Thompson 
663c04a41a7SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
664c04a41a7SJeremy L Thompson 
665c04a41a7SJeremy L Thompson   @ref Backend
666c04a41a7SJeremy L Thompson **/
667d1d35e2fSjeremylt int CeedOperatorIsComposite(CeedOperator op, bool *is_composite) {
668f04ea552SJeremy L Thompson   *is_composite = op->is_composite;
669e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
670c04a41a7SJeremy L Thompson }
671c04a41a7SJeremy L Thompson 
672c04a41a7SJeremy L Thompson /**
673ca94c3ddSJeremy L Thompson   @brief Get the backend data of a `CeedOperator`
6747a982d89SJeremy L. Thompson 
675ca94c3ddSJeremy L Thompson   @param[in]  op   `CeedOperator`
6767a982d89SJeremy L. Thompson   @param[out] data Variable to store data
6777a982d89SJeremy L. Thompson 
6787a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6797a982d89SJeremy L. Thompson 
6807a982d89SJeremy L. Thompson   @ref Backend
6817a982d89SJeremy L. Thompson **/
682777ff853SJeremy L Thompson int CeedOperatorGetData(CeedOperator op, void *data) {
683777ff853SJeremy L Thompson   *(void **)data = op->data;
684e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6857a982d89SJeremy L. Thompson }
6867a982d89SJeremy L. Thompson 
6877a982d89SJeremy L. Thompson /**
688ca94c3ddSJeremy L Thompson   @brief Set the backend data of a `CeedOperator`
6897a982d89SJeremy L. Thompson 
690ca94c3ddSJeremy L Thompson   @param[in,out] op   `CeedOperator`
691ea61e9acSJeremy L Thompson   @param[in]     data Data to set
6927a982d89SJeremy L. Thompson 
6937a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6947a982d89SJeremy L. Thompson 
6957a982d89SJeremy L. Thompson   @ref Backend
6967a982d89SJeremy L. Thompson **/
697777ff853SJeremy L Thompson int CeedOperatorSetData(CeedOperator op, void *data) {
698777ff853SJeremy L Thompson   op->data = data;
699e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
7007a982d89SJeremy L. Thompson }
7017a982d89SJeremy L. Thompson 
7027a982d89SJeremy L. Thompson /**
703ca94c3ddSJeremy L Thompson   @brief Increment the reference counter for a `CeedOperator`
70434359f16Sjeremylt 
705ca94c3ddSJeremy L Thompson   @param[in,out] op `CeedOperator` to increment the reference counter
70634359f16Sjeremylt 
70734359f16Sjeremylt   @return An error code: 0 - success, otherwise - failure
70834359f16Sjeremylt 
70934359f16Sjeremylt   @ref Backend
71034359f16Sjeremylt **/
7119560d06aSjeremylt int CeedOperatorReference(CeedOperator op) {
71234359f16Sjeremylt   op->ref_count++;
71334359f16Sjeremylt   return CEED_ERROR_SUCCESS;
71434359f16Sjeremylt }
71534359f16Sjeremylt 
71634359f16Sjeremylt /**
717ca94c3ddSJeremy L Thompson   @brief Set the setup flag of a `CeedOperator` to `true`
7187a982d89SJeremy L. Thompson 
719ca94c3ddSJeremy L Thompson   @param[in,out] op `CeedOperator`
7207a982d89SJeremy L. Thompson 
7217a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
7227a982d89SJeremy L. Thompson 
7237a982d89SJeremy L. Thompson   @ref Backend
7247a982d89SJeremy L. Thompson **/
7257a982d89SJeremy L. Thompson int CeedOperatorSetSetupDone(CeedOperator op) {
726f04ea552SJeremy L Thompson   op->is_backend_setup = true;
727e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
7287a982d89SJeremy L. Thompson }
7297a982d89SJeremy L. Thompson 
7307a982d89SJeremy L. Thompson /// @}
7317a982d89SJeremy L. Thompson 
7327a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
7337a982d89SJeremy L. Thompson /// CeedOperator Public API
7347a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
7357a982d89SJeremy L. Thompson /// @addtogroup CeedOperatorUser
736dfdf5a53Sjeremylt /// @{
737d7b241e6Sjeremylt 
738d7b241e6Sjeremylt /**
739ca94c3ddSJeremy L Thompson   @brief Create a `CeedOperator` and associate a `CeedQFunction`.
7404385fb7fSSebastian Grimberg 
741ca94c3ddSJeremy L Thompson   A `CeedBasis` and `CeedElemRestriction` can be associated with `CeedQFunction` fields with @ref CeedOperatorSetField().
742d7b241e6Sjeremylt 
743ca94c3ddSJeremy L Thompson   @param[in]  ceed `Ceed` object used to create the `CeedOperator`
744ca94c3ddSJeremy L Thompson   @param[in]  qf   `CeedQFunction` defining the action of the operator at quadrature points
745ca94c3ddSJeremy L Thompson   @param[in]  dqf  `CeedQFunction` defining the action of the Jacobian of `qf` (or @ref CEED_QFUNCTION_NONE)
746ca94c3ddSJeremy L Thompson   @param[in]  dqfT `CeedQFunction` defining the action of the transpose of the Jacobian of `qf` (or @ref CEED_QFUNCTION_NONE)
747ca94c3ddSJeremy L Thompson   @param[out] op   Address of the variable where the newly created `CeedOperator` will be stored
748b11c1e72Sjeremylt 
749b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
750dfdf5a53Sjeremylt 
7517a982d89SJeremy L. Thompson   @ref User
752d7b241e6Sjeremylt  */
7532b730f8bSJeremy L Thompson int CeedOperatorCreate(Ceed ceed, CeedQFunction qf, CeedQFunction dqf, CeedQFunction dqfT, CeedOperator *op) {
7545fe0d4faSjeremylt   if (!ceed->OperatorCreate) {
7555fe0d4faSjeremylt     Ceed delegate;
7566574a04fSJeremy L Thompson 
7572b730f8bSJeremy L Thompson     CeedCall(CeedGetObjectDelegate(ceed, &delegate, "Operator"));
7581ef3a2a9SJeremy L Thompson     CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement CeedOperatorCreate");
7592b730f8bSJeremy L Thompson     CeedCall(CeedOperatorCreate(delegate, qf, dqf, dqfT, op));
7609bc66399SJeremy L Thompson     CeedCall(CeedDestroy(&delegate));
761e15f9bd0SJeremy L Thompson     return CEED_ERROR_SUCCESS;
7625fe0d4faSjeremylt   }
7635fe0d4faSjeremylt 
764ca94c3ddSJeremy L Thompson   CeedCheck(qf && qf != CEED_QFUNCTION_NONE, ceed, CEED_ERROR_MINOR, "Operator must have a valid CeedQFunction.");
765db002c03SJeremy L Thompson 
7662b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(1, op));
767db002c03SJeremy L Thompson   CeedCall(CeedReferenceCopy(ceed, &(*op)->ceed));
768d1d35e2fSjeremylt   (*op)->ref_count   = 1;
7692b104005SJeremy L Thompson   (*op)->input_size  = -1;
7702b104005SJeremy L Thompson   (*op)->output_size = -1;
771db002c03SJeremy L Thompson   CeedCall(CeedQFunctionReferenceCopy(qf, &(*op)->qf));
772db002c03SJeremy L Thompson   if (dqf && dqf != CEED_QFUNCTION_NONE) CeedCall(CeedQFunctionReferenceCopy(dqf, &(*op)->dqf));
773db002c03SJeremy L Thompson   if (dqfT && dqfT != CEED_QFUNCTION_NONE) CeedCall(CeedQFunctionReferenceCopy(dqfT, &(*op)->dqfT));
7742b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(CEED_FIELD_MAX, &(*op)->input_fields));
7752b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(CEED_FIELD_MAX, &(*op)->output_fields));
7762b730f8bSJeremy L Thompson   CeedCall(ceed->OperatorCreate(*op));
777e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
778d7b241e6Sjeremylt }
779d7b241e6Sjeremylt 
780d7b241e6Sjeremylt /**
781ca94c3ddSJeremy L Thompson   @brief Create a `CeedOperator` for evaluation at evaluation at arbitrary points in each element.
78248acf710SJeremy L Thompson 
783ca94c3ddSJeremy L Thompson   A `CeedBasis` and `CeedElemRestriction` can be associated with `CeedQFunction` fields with `CeedOperator` SetField.
784ca94c3ddSJeremy L Thompson   The locations of each point are set with @ref CeedOperatorAtPointsSetPoints().
78548acf710SJeremy L Thompson 
786ca94c3ddSJeremy L Thompson   @param[in]  ceed `Ceed` object used to create the `CeedOperator`
787ca94c3ddSJeremy L Thompson   @param[in]  qf   `CeedQFunction` defining the action of the operator at quadrature points
788ca94c3ddSJeremy L Thompson   @param[in]  dqf  `CeedQFunction` defining the action of the Jacobian of @a qf (or @ref CEED_QFUNCTION_NONE)
789ca94c3ddSJeremy L Thompson   @param[in]  dqfT `CeedQFunction` defining the action of the transpose of the Jacobian of @a qf (or @ref CEED_QFUNCTION_NONE)
79048acf710SJeremy L Thompson   @param[out] op   Address of the variable where the newly created CeedOperator will be stored
79148acf710SJeremy L Thompson 
79248acf710SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
79348acf710SJeremy L Thompson 
79448acf710SJeremy L Thompson   @ref User
79548acf710SJeremy L Thompson  */
79648acf710SJeremy L Thompson int CeedOperatorCreateAtPoints(Ceed ceed, CeedQFunction qf, CeedQFunction dqf, CeedQFunction dqfT, CeedOperator *op) {
79748acf710SJeremy L Thompson   if (!ceed->OperatorCreateAtPoints) {
79848acf710SJeremy L Thompson     Ceed delegate;
79948acf710SJeremy L Thompson 
80048acf710SJeremy L Thompson     CeedCall(CeedGetObjectDelegate(ceed, &delegate, "Operator"));
8011ef3a2a9SJeremy L Thompson     CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement CeedOperatorCreateAtPoints");
80248acf710SJeremy L Thompson     CeedCall(CeedOperatorCreateAtPoints(delegate, qf, dqf, dqfT, op));
8039bc66399SJeremy L Thompson     CeedCall(CeedDestroy(&delegate));
80448acf710SJeremy L Thompson     return CEED_ERROR_SUCCESS;
80548acf710SJeremy L Thompson   }
80648acf710SJeremy L Thompson 
807ca94c3ddSJeremy L Thompson   CeedCheck(qf && qf != CEED_QFUNCTION_NONE, ceed, CEED_ERROR_MINOR, "Operator must have a valid CeedQFunction.");
80848acf710SJeremy L Thompson 
80948acf710SJeremy L Thompson   CeedCall(CeedCalloc(1, op));
81048acf710SJeremy L Thompson   CeedCall(CeedReferenceCopy(ceed, &(*op)->ceed));
81148acf710SJeremy L Thompson   (*op)->ref_count    = 1;
81248acf710SJeremy L Thompson   (*op)->is_at_points = true;
81348acf710SJeremy L Thompson   (*op)->input_size   = -1;
81448acf710SJeremy L Thompson   (*op)->output_size  = -1;
81548acf710SJeremy L Thompson   CeedCall(CeedQFunctionReferenceCopy(qf, &(*op)->qf));
81648acf710SJeremy L Thompson   if (dqf && dqf != CEED_QFUNCTION_NONE) CeedCall(CeedQFunctionReferenceCopy(dqf, &(*op)->dqf));
81748acf710SJeremy L Thompson   if (dqfT && dqfT != CEED_QFUNCTION_NONE) CeedCall(CeedQFunctionReferenceCopy(dqfT, &(*op)->dqfT));
81848acf710SJeremy L Thompson   CeedCall(CeedCalloc(CEED_FIELD_MAX, &(*op)->input_fields));
81948acf710SJeremy L Thompson   CeedCall(CeedCalloc(CEED_FIELD_MAX, &(*op)->output_fields));
82048acf710SJeremy L Thompson   CeedCall(ceed->OperatorCreateAtPoints(*op));
82148acf710SJeremy L Thompson   return CEED_ERROR_SUCCESS;
82248acf710SJeremy L Thompson }
82348acf710SJeremy L Thompson 
82448acf710SJeremy L Thompson /**
825ca94c3ddSJeremy L Thompson   @brief Create a composite `CeedOperator` that composes the action of several `CeedOperator`
82652d6035fSJeremy L Thompson 
827ca94c3ddSJeremy L Thompson   @param[in]  ceed `Ceed` object used to create the `CeedOperator`
828ca94c3ddSJeremy L Thompson   @param[out] op   Address of the variable where the newly created composite `CeedOperator` will be stored
82952d6035fSJeremy L Thompson 
83052d6035fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
83152d6035fSJeremy L Thompson 
8327a982d89SJeremy L. Thompson   @ref User
83352d6035fSJeremy L Thompson  */
834*ed094490SJeremy L Thompson int CeedOperatorCreateComposite(Ceed ceed, CeedOperator *op) {
83552d6035fSJeremy L Thompson   if (!ceed->CompositeOperatorCreate) {
83652d6035fSJeremy L Thompson     Ceed delegate;
83752d6035fSJeremy L Thompson 
8381c66c397SJeremy L Thompson     CeedCall(CeedGetObjectDelegate(ceed, &delegate, "Operator"));
839250756a7Sjeremylt     if (delegate) {
840*ed094490SJeremy L Thompson       CeedCall(CeedOperatorCreateComposite(delegate, op));
8419bc66399SJeremy L Thompson       CeedCall(CeedDestroy(&delegate));
842e15f9bd0SJeremy L Thompson       return CEED_ERROR_SUCCESS;
84352d6035fSJeremy L Thompson     }
844250756a7Sjeremylt   }
84552d6035fSJeremy L Thompson 
8462b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(1, op));
847db002c03SJeremy L Thompson   CeedCall(CeedReferenceCopy(ceed, &(*op)->ceed));
848996d9ab5SJed Brown   (*op)->ref_count    = 1;
849f04ea552SJeremy L Thompson   (*op)->is_composite = true;
8502b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(CEED_COMPOSITE_MAX, &(*op)->sub_operators));
8512b104005SJeremy L Thompson   (*op)->input_size  = -1;
8522b104005SJeremy L Thompson   (*op)->output_size = -1;
853250756a7Sjeremylt 
854db002c03SJeremy L Thompson   if (ceed->CompositeOperatorCreate) CeedCall(ceed->CompositeOperatorCreate(*op));
855e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
85652d6035fSJeremy L Thompson }
85752d6035fSJeremy L Thompson 
85852d6035fSJeremy L Thompson /**
859ca94c3ddSJeremy L Thompson   @brief Copy the pointer to a `CeedOperator`.
8604385fb7fSSebastian Grimberg 
861ca94c3ddSJeremy L Thompson   Both pointers should be destroyed with @ref CeedOperatorDestroy().
862512bb800SJeremy L Thompson 
863ca94c3ddSJeremy L Thompson   Note: If the value of `*op_copy` passed to this function is non-`NULL`, then it is assumed that `*op_copy` is a pointer to a `CeedOperator`.
864ca94c3ddSJeremy L Thompson         This `CeedOperator` will be destroyed if `*op_copy` is the only reference to this `CeedOperator`.
8659560d06aSjeremylt 
866ca94c3ddSJeremy L Thompson   @param[in]     op      `CeedOperator` to copy reference to
867ea61e9acSJeremy L Thompson   @param[in,out] op_copy Variable to store copied reference
8689560d06aSjeremylt 
8699560d06aSjeremylt   @return An error code: 0 - success, otherwise - failure
8709560d06aSjeremylt 
8719560d06aSjeremylt   @ref User
8729560d06aSjeremylt **/
8739560d06aSjeremylt int CeedOperatorReferenceCopy(CeedOperator op, CeedOperator *op_copy) {
8742b730f8bSJeremy L Thompson   CeedCall(CeedOperatorReference(op));
8752b730f8bSJeremy L Thompson   CeedCall(CeedOperatorDestroy(op_copy));
8769560d06aSjeremylt   *op_copy = op;
8779560d06aSjeremylt   return CEED_ERROR_SUCCESS;
8789560d06aSjeremylt }
8799560d06aSjeremylt 
8809560d06aSjeremylt /**
881ca94c3ddSJeremy L Thompson   @brief Provide a field to a `CeedOperator` for use by its `CeedQFunction`.
882d7b241e6Sjeremylt 
883ca94c3ddSJeremy L Thompson   This function is used to specify both active and passive fields to a `CeedOperator`.
884bafebce1SSebastian Grimberg   For passive fields, a `CeedVector` `vec` must be provided.
885ea61e9acSJeremy L Thompson   Passive fields can inputs or outputs (updated in-place when operator is applied).
886d7b241e6Sjeremylt 
887ca94c3ddSJeremy L Thompson   Active fields must be specified using this function, but their data (in a `CeedVector`) is passed in @ref CeedOperatorApply().
888ca94c3ddSJeremy L Thompson   There can be at most one active input `CeedVector` and at most one active output@ref  CeedVector passed to @ref CeedOperatorApply().
889d7b241e6Sjeremylt 
890528a22edSJeremy L Thompson   The number of quadrature points must agree across all points.
891bafebce1SSebastian Grimberg   When using @ref CEED_BASIS_NONE, the number of quadrature points is determined by the element size of `rstr`.
892528a22edSJeremy L Thompson 
893ca94c3ddSJeremy L Thompson   @param[in,out] op         `CeedOperator` on which to provide the field
894ca94c3ddSJeremy L Thompson   @param[in]     field_name Name of the field (to be matched with the name used by `CeedQFunction`)
895bafebce1SSebastian Grimberg   @param[in]     rstr       `CeedElemRestriction`
896bafebce1SSebastian Grimberg   @param[in]     basis      `CeedBasis` in which the field resides or @ref CEED_BASIS_NONE if collocated with quadrature points
897bafebce1SSebastian Grimberg   @param[in]     vec        `CeedVector` to be used by CeedOperator or @ref CEED_VECTOR_ACTIVE if field is active or @ref CEED_VECTOR_NONE if using @ref CEED_EVAL_WEIGHT in the `CeedQFunction`
898b11c1e72Sjeremylt 
899b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
900dfdf5a53Sjeremylt 
9017a982d89SJeremy L. Thompson   @ref User
902b11c1e72Sjeremylt **/
903bafebce1SSebastian Grimberg int CeedOperatorSetField(CeedOperator op, const char *field_name, CeedElemRestriction rstr, CeedBasis basis, CeedVector vec) {
9041203703bSJeremy L Thompson   bool               is_input = true, is_at_points, is_composite, is_immutable;
9051203703bSJeremy L Thompson   CeedInt            num_elem = 0, num_qpts = 0, num_input_fields, num_output_fields;
9061203703bSJeremy L Thompson   CeedQFunction      qf;
9071203703bSJeremy L Thompson   CeedQFunctionField qf_field, *qf_input_fields, *qf_output_fields;
9081c66c397SJeremy L Thompson   CeedOperatorField *op_field;
9091c66c397SJeremy L Thompson 
9101203703bSJeremy L Thompson   CeedCall(CeedOperatorIsAtPoints(op, &is_at_points));
9111203703bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
9121203703bSJeremy L Thompson   CeedCall(CeedOperatorIsImmutable(op, &is_immutable));
9139bc66399SJeremy L Thompson   CeedCheck(!is_composite, CeedOperatorReturnCeed(op), CEED_ERROR_INCOMPATIBLE, "Cannot add field to composite operator.");
9149bc66399SJeremy L Thompson   CeedCheck(!is_immutable, CeedOperatorReturnCeed(op), CEED_ERROR_MAJOR, "Operator cannot be changed after set as immutable");
9159bc66399SJeremy L Thompson   CeedCheck(rstr, CeedOperatorReturnCeed(op), CEED_ERROR_INCOMPATIBLE, "CeedElemRestriction rstr for field \"%s\" must be non-NULL.", field_name);
9169bc66399SJeremy L Thompson   CeedCheck(basis, CeedOperatorReturnCeed(op), CEED_ERROR_INCOMPATIBLE, "CeedBasis basis for field \"%s\" must be non-NULL.", field_name);
9179bc66399SJeremy L Thompson   CeedCheck(vec, CeedOperatorReturnCeed(op), CEED_ERROR_INCOMPATIBLE, "CeedVector vec for field \"%s\" must be non-NULL.", field_name);
91852d6035fSJeremy L Thompson 
919bafebce1SSebastian Grimberg   CeedCall(CeedElemRestrictionGetNumElements(rstr, &num_elem));
9209bc66399SJeremy L Thompson   CeedCheck(rstr == CEED_ELEMRESTRICTION_NONE || !op->has_restriction || num_elem == op->num_elem, CeedOperatorReturnCeed(op), CEED_ERROR_DIMENSION,
921ca94c3ddSJeremy L Thompson             "CeedElemRestriction with %" CeedInt_FMT " elements incompatible with prior %" CeedInt_FMT " elements", num_elem, op->num_elem);
9222c7e7413SJeremy L Thompson   {
9232c7e7413SJeremy L Thompson     CeedRestrictionType rstr_type;
9242c7e7413SJeremy L Thompson 
925bafebce1SSebastian Grimberg     CeedCall(CeedElemRestrictionGetType(rstr, &rstr_type));
92648acf710SJeremy L Thompson     if (rstr_type == CEED_RESTRICTION_POINTS) {
9279bc66399SJeremy L Thompson       CeedCheck(is_at_points, CeedOperatorReturnCeed(op), CEED_ERROR_UNSUPPORTED,
9289bc66399SJeremy L Thompson                 "CeedElemRestriction AtPoints not supported for standard operator fields");
9299bc66399SJeremy L Thompson       CeedCheck(basis == CEED_BASIS_NONE, CeedOperatorReturnCeed(op), CEED_ERROR_UNSUPPORTED,
9309bc66399SJeremy L Thompson                 "CeedElemRestriction AtPoints must be used with CEED_BASIS_NONE");
93148acf710SJeremy L Thompson       if (!op->first_points_rstr) {
932bafebce1SSebastian Grimberg         CeedCall(CeedElemRestrictionReferenceCopy(rstr, &op->first_points_rstr));
93348acf710SJeremy L Thompson       } else {
93448acf710SJeremy L Thompson         bool are_compatible;
93548acf710SJeremy L Thompson 
936bafebce1SSebastian Grimberg         CeedCall(CeedElemRestrictionAtPointsAreCompatible(op->first_points_rstr, rstr, &are_compatible));
9379bc66399SJeremy L Thompson         CeedCheck(are_compatible, CeedOperatorReturnCeed(op), CEED_ERROR_INCOMPATIBLE,
938ca94c3ddSJeremy L Thompson                   "CeedElemRestriction must have compatible offsets with previously set CeedElemRestriction");
93948acf710SJeremy L Thompson       }
94048acf710SJeremy L Thompson     }
9412c7e7413SJeremy L Thompson   }
942d7b241e6Sjeremylt 
943bafebce1SSebastian Grimberg   if (basis == CEED_BASIS_NONE) CeedCall(CeedElemRestrictionGetElementSize(rstr, &num_qpts));
944bafebce1SSebastian Grimberg   else CeedCall(CeedBasisGetNumQuadraturePoints(basis, &num_qpts));
9459bc66399SJeremy L Thompson   CeedCheck(op->num_qpts == 0 || num_qpts == op->num_qpts, CeedOperatorReturnCeed(op), CEED_ERROR_DIMENSION,
946ca94c3ddSJeremy L Thompson             "%s must correspond to the same number of quadrature points as previously added CeedBases. Found %" CeedInt_FMT
947528a22edSJeremy L Thompson             " quadrature points but expected %" CeedInt_FMT " quadrature points.",
948bafebce1SSebastian Grimberg             basis == CEED_BASIS_NONE ? "CeedElemRestriction" : "CeedBasis", num_qpts, op->num_qpts);
9491203703bSJeremy L Thompson 
9501203703bSJeremy L Thompson   CeedCall(CeedOperatorGetQFunction(op, &qf));
9511203703bSJeremy L Thompson   CeedCall(CeedQFunctionGetFields(qf, &num_input_fields, &qf_input_fields, &num_output_fields, &qf_output_fields));
952c11e12f4SJeremy L Thompson   CeedCall(CeedQFunctionDestroy(&qf));
9531203703bSJeremy L Thompson   for (CeedInt i = 0; i < num_input_fields; i++) {
9546f8994e9SJeremy L Thompson     const char *qf_field_name;
9551203703bSJeremy L Thompson 
9561203703bSJeremy L Thompson     CeedCall(CeedQFunctionFieldGetName(qf_input_fields[i], &qf_field_name));
9571203703bSJeremy L Thompson     if (!strcmp(field_name, qf_field_name)) {
9581203703bSJeremy L Thompson       qf_field = qf_input_fields[i];
959d1d35e2fSjeremylt       op_field = &op->input_fields[i];
960d7b241e6Sjeremylt       goto found;
961d7b241e6Sjeremylt     }
962d7b241e6Sjeremylt   }
9632b104005SJeremy L Thompson   is_input = false;
9641203703bSJeremy L Thompson   for (CeedInt i = 0; i < num_output_fields; i++) {
9656f8994e9SJeremy L Thompson     const char *qf_field_name;
9661203703bSJeremy L Thompson 
9671203703bSJeremy L Thompson     CeedCall(CeedQFunctionFieldGetName(qf_output_fields[i], &qf_field_name));
9681203703bSJeremy L Thompson     if (!strcmp(field_name, qf_field_name)) {
9691203703bSJeremy L Thompson       qf_field = qf_output_fields[i];
970d1d35e2fSjeremylt       op_field = &op->output_fields[i];
971d7b241e6Sjeremylt       goto found;
972d7b241e6Sjeremylt     }
973d7b241e6Sjeremylt   }
974c042f62fSJeremy L Thompson   // LCOV_EXCL_START
9759bc66399SJeremy L Thompson   return CeedError(CeedOperatorReturnCeed(op), CEED_ERROR_INCOMPLETE, "CeedQFunction has no knowledge of field '%s'", field_name);
976c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
977d7b241e6Sjeremylt found:
9789bc66399SJeremy L Thompson   CeedCall(CeedOperatorCheckField(CeedOperatorReturnCeed(op), qf_field, rstr, basis));
9792b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(1, op_field));
980e15f9bd0SJeremy L Thompson 
981bafebce1SSebastian Grimberg   if (vec == CEED_VECTOR_ACTIVE) {
9822b104005SJeremy L Thompson     CeedSize l_size;
9831c66c397SJeremy L Thompson 
984bafebce1SSebastian Grimberg     CeedCall(CeedElemRestrictionGetLVectorSize(rstr, &l_size));
9852b104005SJeremy L Thompson     if (is_input) {
9862b104005SJeremy L Thompson       if (op->input_size == -1) op->input_size = l_size;
9879bc66399SJeremy L Thompson       CeedCheck(l_size == op->input_size, CeedOperatorReturnCeed(op), CEED_ERROR_INCOMPATIBLE,
988249f8407SJeremy L Thompson                 "LVector size %" CeedSize_FMT " does not match previous size %" CeedSize_FMT "", l_size, op->input_size);
9892b104005SJeremy L Thompson     } else {
9902b104005SJeremy L Thompson       if (op->output_size == -1) op->output_size = l_size;
9919bc66399SJeremy L Thompson       CeedCheck(l_size == op->output_size, CeedOperatorReturnCeed(op), CEED_ERROR_INCOMPATIBLE,
992249f8407SJeremy L Thompson                 "LVector size %" CeedSize_FMT " does not match previous size %" CeedSize_FMT "", l_size, op->output_size);
9932b104005SJeremy L Thompson     }
9942b730f8bSJeremy L Thompson   }
9952b104005SJeremy L Thompson 
996bafebce1SSebastian Grimberg   CeedCall(CeedVectorReferenceCopy(vec, &(*op_field)->vec));
997bafebce1SSebastian Grimberg   CeedCall(CeedElemRestrictionReferenceCopy(rstr, &(*op_field)->elem_rstr));
998bafebce1SSebastian Grimberg   if (rstr != CEED_ELEMRESTRICTION_NONE && !op->has_restriction) {
999d1d35e2fSjeremylt     op->num_elem        = num_elem;
1000d1d35e2fSjeremylt     op->has_restriction = true;  // Restriction set, but num_elem may be 0
1001e15f9bd0SJeremy L Thompson   }
1002bafebce1SSebastian Grimberg   CeedCall(CeedBasisReferenceCopy(basis, &(*op_field)->basis));
10032a3ff1c9SZach Atkins   if (op->num_qpts == 0 && !is_at_points) op->num_qpts = num_qpts;  // no consistent number of qpts for OperatorAtPoints
1004d1d35e2fSjeremylt   op->num_fields += 1;
10052b730f8bSJeremy L Thompson   CeedCall(CeedStringAllocCopy(field_name, (char **)&(*op_field)->field_name));
1006e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1007d7b241e6Sjeremylt }
1008d7b241e6Sjeremylt 
1009d7b241e6Sjeremylt /**
1010ca94c3ddSJeremy L Thompson   @brief Get the `CeedOperator` Field of a `CeedOperator`.
101143bbe138SJeremy L Thompson 
1012ca94c3ddSJeremy L Thompson   Note: Calling this function asserts that setup is complete and sets the `CeedOperator` as immutable.
1013f04ea552SJeremy L Thompson 
1014ca94c3ddSJeremy L Thompson   @param[in]  op                `CeedOperator`
1015f74ec584SJeremy L Thompson   @param[out] num_input_fields  Variable to store number of input fields
1016ca94c3ddSJeremy L Thompson   @param[out] input_fields      Variable to store input fields
1017f74ec584SJeremy L Thompson   @param[out] num_output_fields Variable to store number of output fields
1018ca94c3ddSJeremy L Thompson   @param[out] output_fields     Variable to store output fields
101943bbe138SJeremy L Thompson 
102043bbe138SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
102143bbe138SJeremy L Thompson 
1022e9b533fbSJeremy L Thompson   @ref Advanced
102343bbe138SJeremy L Thompson **/
10242b730f8bSJeremy L Thompson int CeedOperatorGetFields(CeedOperator op, CeedInt *num_input_fields, CeedOperatorField **input_fields, CeedInt *num_output_fields,
102543bbe138SJeremy L Thompson                           CeedOperatorField **output_fields) {
10261203703bSJeremy L Thompson   bool          is_composite;
10271203703bSJeremy L Thompson   CeedQFunction qf;
10281203703bSJeremy L Thompson 
10291203703bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
10306e536b99SJeremy L Thompson   CeedCheck(!is_composite, CeedOperatorReturnCeed(op), CEED_ERROR_MINOR, "Not defined for composite operator");
10312b730f8bSJeremy L Thompson   CeedCall(CeedOperatorCheckReady(op));
103243bbe138SJeremy L Thompson 
10331203703bSJeremy L Thompson   CeedCall(CeedOperatorGetQFunction(op, &qf));
10341203703bSJeremy L Thompson   CeedCall(CeedQFunctionGetFields(qf, num_input_fields, NULL, num_output_fields, NULL));
1035c11e12f4SJeremy L Thompson   CeedCall(CeedQFunctionDestroy(&qf));
103643bbe138SJeremy L Thompson   if (input_fields) *input_fields = op->input_fields;
103743bbe138SJeremy L Thompson   if (output_fields) *output_fields = op->output_fields;
103843bbe138SJeremy L Thompson   return CEED_ERROR_SUCCESS;
103943bbe138SJeremy L Thompson }
104043bbe138SJeremy L Thompson 
104143bbe138SJeremy L Thompson /**
1042ca94c3ddSJeremy L Thompson   @brief Set the arbitrary points in each element for a `CeedOperator` at points.
104348acf710SJeremy L Thompson 
1044ca94c3ddSJeremy L Thompson   Note: Calling this function asserts that setup is complete and sets the `CeedOperator` as immutable.
104548acf710SJeremy L Thompson 
1046ca94c3ddSJeremy L Thompson   @param[in,out] op           `CeedOperator` at points
1047ca94c3ddSJeremy L Thompson   @param[in]     rstr_points  `CeedElemRestriction` for the coordinates of each point by element
1048ca94c3ddSJeremy L Thompson   @param[in]     point_coords `CeedVector` holding coordinates of each point
104948acf710SJeremy L Thompson 
105048acf710SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
105148acf710SJeremy L Thompson 
105248acf710SJeremy L Thompson   @ref Advanced
105348acf710SJeremy L Thompson **/
105448acf710SJeremy L Thompson int CeedOperatorAtPointsSetPoints(CeedOperator op, CeedElemRestriction rstr_points, CeedVector point_coords) {
10551203703bSJeremy L Thompson   bool is_at_points, is_immutable;
10562a3ff1c9SZach Atkins 
10572a3ff1c9SZach Atkins   CeedCall(CeedOperatorIsAtPoints(op, &is_at_points));
10581203703bSJeremy L Thompson   CeedCall(CeedOperatorIsImmutable(op, &is_immutable));
10599bc66399SJeremy L Thompson   CeedCheck(is_at_points, CeedOperatorReturnCeed(op), CEED_ERROR_MINOR, "Only defined for operator at points");
10609bc66399SJeremy L Thompson   CeedCheck(!is_immutable, CeedOperatorReturnCeed(op), CEED_ERROR_MAJOR, "Operator cannot be changed after set as immutable");
106148acf710SJeremy L Thompson 
106248acf710SJeremy L Thompson   if (!op->first_points_rstr) {
106348acf710SJeremy L Thompson     CeedCall(CeedElemRestrictionReferenceCopy(rstr_points, &op->first_points_rstr));
106448acf710SJeremy L Thompson   } else {
106548acf710SJeremy L Thompson     bool are_compatible;
106648acf710SJeremy L Thompson 
106748acf710SJeremy L Thompson     CeedCall(CeedElemRestrictionAtPointsAreCompatible(op->first_points_rstr, rstr_points, &are_compatible));
10689bc66399SJeremy L Thompson     CeedCheck(are_compatible, CeedOperatorReturnCeed(op), CEED_ERROR_INCOMPATIBLE,
1069ca94c3ddSJeremy L Thompson               "CeedElemRestriction must have compatible offsets with previously set field CeedElemRestriction");
107048acf710SJeremy L Thompson   }
107148acf710SJeremy L Thompson 
107248acf710SJeremy L Thompson   CeedCall(CeedElemRestrictionReferenceCopy(rstr_points, &op->rstr_points));
107348acf710SJeremy L Thompson   CeedCall(CeedVectorReferenceCopy(point_coords, &op->point_coords));
107448acf710SJeremy L Thompson   return CEED_ERROR_SUCCESS;
107548acf710SJeremy L Thompson }
107648acf710SJeremy L Thompson 
107748acf710SJeremy L Thompson /**
1078b594f9faSZach Atkins   @brief Get a boolean value indicating if the `CeedOperator` was created with `CeedOperatorCreateAtPoints`
1079b594f9faSZach Atkins 
1080b594f9faSZach Atkins   @param[in]  op           `CeedOperator`
1081b594f9faSZach Atkins   @param[out] is_at_points Variable to store at points status
1082b594f9faSZach Atkins 
1083b594f9faSZach Atkins   @return An error code: 0 - success, otherwise - failure
1084b594f9faSZach Atkins 
1085b594f9faSZach Atkins   @ref User
1086b594f9faSZach Atkins **/
1087b594f9faSZach Atkins int CeedOperatorIsAtPoints(CeedOperator op, bool *is_at_points) {
1088b594f9faSZach Atkins   *is_at_points = op->is_at_points;
1089b594f9faSZach Atkins   return CEED_ERROR_SUCCESS;
1090b594f9faSZach Atkins }
1091b594f9faSZach Atkins 
1092b594f9faSZach Atkins /**
1093ca94c3ddSJeremy L Thompson   @brief Get the arbitrary points in each element for a `CeedOperator` at points.
109448acf710SJeremy L Thompson 
1095ca94c3ddSJeremy L Thompson   Note: Calling this function asserts that setup is complete and sets the `CeedOperator` as immutable.
109648acf710SJeremy L Thompson 
1097ca94c3ddSJeremy L Thompson   @param[in]  op           `CeedOperator` at points
1098ca94c3ddSJeremy L Thompson   @param[out] rstr_points  Variable to hold `CeedElemRestriction` for the coordinates of each point by element
1099ca94c3ddSJeremy L Thompson   @param[out] point_coords Variable to hold `CeedVector` holding coordinates of each point
110048acf710SJeremy L Thompson 
110148acf710SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
110248acf710SJeremy L Thompson 
110348acf710SJeremy L Thompson   @ref Advanced
110448acf710SJeremy L Thompson **/
110548acf710SJeremy L Thompson int CeedOperatorAtPointsGetPoints(CeedOperator op, CeedElemRestriction *rstr_points, CeedVector *point_coords) {
11062a3ff1c9SZach Atkins   bool is_at_points;
11072a3ff1c9SZach Atkins 
11082a3ff1c9SZach Atkins   CeedCall(CeedOperatorIsAtPoints(op, &is_at_points));
11096e536b99SJeremy L Thompson   CeedCheck(is_at_points, CeedOperatorReturnCeed(op), CEED_ERROR_MINOR, "Only defined for operator at points");
111048acf710SJeremy L Thompson   CeedCall(CeedOperatorCheckReady(op));
111148acf710SJeremy L Thompson 
11123f919cbcSJeremy L Thompson   if (rstr_points) {
11133f919cbcSJeremy L Thompson     *rstr_points = NULL;
11143f919cbcSJeremy L Thompson     CeedCall(CeedElemRestrictionReferenceCopy(op->rstr_points, rstr_points));
11153f919cbcSJeremy L Thompson   }
11163f919cbcSJeremy L Thompson   if (point_coords) {
11173f919cbcSJeremy L Thompson     *point_coords = NULL;
11183f919cbcSJeremy L Thompson     CeedCall(CeedVectorReferenceCopy(op->point_coords, point_coords));
11193f919cbcSJeremy L Thompson   }
112048acf710SJeremy L Thompson   return CEED_ERROR_SUCCESS;
112148acf710SJeremy L Thompson }
112248acf710SJeremy L Thompson 
112348acf710SJeremy L Thompson /**
1124be9c6463SJeremy L Thompson   @brief Get a `CeedOperator` Field of a `CeedOperator` from its name.
1125be9c6463SJeremy L Thompson 
1126be9c6463SJeremy L Thompson   `op_field` is set to `NULL` if the field is not found.
1127de5900adSJames Wright 
1128ca94c3ddSJeremy L Thompson   Note: Calling this function asserts that setup is complete and sets the `CeedOperator` as immutable.
1129de5900adSJames Wright 
1130ca94c3ddSJeremy L Thompson   @param[in]  op         `CeedOperator`
1131ca94c3ddSJeremy L Thompson   @param[in]  field_name Name of desired `CeedOperator` Field
1132ca94c3ddSJeremy L Thompson   @param[out] op_field   `CeedOperator` Field corresponding to the name
1133de5900adSJames Wright 
1134de5900adSJames Wright   @return An error code: 0 - success, otherwise - failure
1135de5900adSJames Wright 
1136de5900adSJames Wright   @ref Advanced
1137de5900adSJames Wright **/
1138de5900adSJames Wright int CeedOperatorGetFieldByName(CeedOperator op, const char *field_name, CeedOperatorField *op_field) {
11396f8994e9SJeremy L Thompson   const char        *name;
1140de5900adSJames Wright   CeedInt            num_input_fields, num_output_fields;
1141de5900adSJames Wright   CeedOperatorField *input_fields, *output_fields;
1142de5900adSJames Wright 
1143be9c6463SJeremy L Thompson   *op_field = NULL;
11441c66c397SJeremy L Thompson   CeedCall(CeedOperatorGetFields(op, &num_input_fields, &input_fields, &num_output_fields, &output_fields));
1145de5900adSJames Wright   for (CeedInt i = 0; i < num_input_fields; i++) {
1146de5900adSJames Wright     CeedCall(CeedOperatorFieldGetName(input_fields[i], &name));
1147de5900adSJames Wright     if (!strcmp(name, field_name)) {
1148de5900adSJames Wright       *op_field = input_fields[i];
1149de5900adSJames Wright       return CEED_ERROR_SUCCESS;
1150de5900adSJames Wright     }
1151de5900adSJames Wright   }
1152de5900adSJames Wright   for (CeedInt i = 0; i < num_output_fields; i++) {
1153de5900adSJames Wright     CeedCall(CeedOperatorFieldGetName(output_fields[i], &name));
1154de5900adSJames Wright     if (!strcmp(name, field_name)) {
1155de5900adSJames Wright       *op_field = output_fields[i];
1156de5900adSJames Wright       return CEED_ERROR_SUCCESS;
1157de5900adSJames Wright     }
1158de5900adSJames Wright   }
1159be9c6463SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1160de5900adSJames Wright }
1161de5900adSJames Wright 
1162de5900adSJames Wright /**
1163ca94c3ddSJeremy L Thompson   @brief Get the name of a `CeedOperator` Field
116428567f8fSJeremy L Thompson 
1165ca94c3ddSJeremy L Thompson   @param[in]  op_field   `CeedOperator` Field
116628567f8fSJeremy L Thompson   @param[out] field_name Variable to store the field name
116728567f8fSJeremy L Thompson 
116828567f8fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
116928567f8fSJeremy L Thompson 
1170e9b533fbSJeremy L Thompson   @ref Advanced
117128567f8fSJeremy L Thompson **/
11726f8994e9SJeremy L Thompson int CeedOperatorFieldGetName(CeedOperatorField op_field, const char **field_name) {
11736f8994e9SJeremy L Thompson   *field_name = op_field->field_name;
117428567f8fSJeremy L Thompson   return CEED_ERROR_SUCCESS;
117528567f8fSJeremy L Thompson }
117628567f8fSJeremy L Thompson 
117728567f8fSJeremy L Thompson /**
1178681d0ea7SJeremy L Thompson   @brief Get the `CeedElemRestriction` of a `CeedOperator` Field.
1179681d0ea7SJeremy L Thompson 
1180681d0ea7SJeremy L Thompson   Note: Caller is responsible for destroying the `rstr` with @ref CeedElemRestrictionDestroy().
118143bbe138SJeremy L Thompson 
1182ca94c3ddSJeremy L Thompson   @param[in]  op_field `CeedOperator` Field
1183ca94c3ddSJeremy L Thompson   @param[out] rstr     Variable to store `CeedElemRestriction`
118443bbe138SJeremy L Thompson 
118543bbe138SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
118643bbe138SJeremy L Thompson 
1187e9b533fbSJeremy L Thompson   @ref Advanced
118843bbe138SJeremy L Thompson **/
11892b730f8bSJeremy L Thompson int CeedOperatorFieldGetElemRestriction(CeedOperatorField op_field, CeedElemRestriction *rstr) {
1190681d0ea7SJeremy L Thompson   *rstr = NULL;
1191681d0ea7SJeremy L Thompson   CeedCall(CeedElemRestrictionReferenceCopy(op_field->elem_rstr, rstr));
119243bbe138SJeremy L Thompson   return CEED_ERROR_SUCCESS;
119343bbe138SJeremy L Thompson }
119443bbe138SJeremy L Thompson 
119543bbe138SJeremy L Thompson /**
1196681d0ea7SJeremy L Thompson   @brief Get the `CeedBasis` of a `CeedOperator` Field.
1197681d0ea7SJeremy L Thompson 
1198681d0ea7SJeremy L Thompson   Note: Caller is responsible for destroying the `basis` with @ref CeedBasisDestroy().
119943bbe138SJeremy L Thompson 
1200ca94c3ddSJeremy L Thompson   @param[in]  op_field `CeedOperator` Field
1201ca94c3ddSJeremy L Thompson   @param[out] basis    Variable to store `CeedBasis`
120243bbe138SJeremy L Thompson 
120343bbe138SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
120443bbe138SJeremy L Thompson 
1205e9b533fbSJeremy L Thompson   @ref Advanced
120643bbe138SJeremy L Thompson **/
120743bbe138SJeremy L Thompson int CeedOperatorFieldGetBasis(CeedOperatorField op_field, CeedBasis *basis) {
1208681d0ea7SJeremy L Thompson   *basis = NULL;
1209681d0ea7SJeremy L Thompson   CeedCall(CeedBasisReferenceCopy(op_field->basis, basis));
121043bbe138SJeremy L Thompson   return CEED_ERROR_SUCCESS;
121143bbe138SJeremy L Thompson }
121243bbe138SJeremy L Thompson 
121343bbe138SJeremy L Thompson /**
1214681d0ea7SJeremy L Thompson   @brief Get the `CeedVector` of a `CeedOperator` Field.
1215681d0ea7SJeremy L Thompson 
1216681d0ea7SJeremy L Thompson   Note: Caller is responsible for destroying the `vec` with @ref CeedVectorDestroy().
121743bbe138SJeremy L Thompson 
1218ca94c3ddSJeremy L Thompson   @param[in]  op_field `CeedOperator` Field
1219ca94c3ddSJeremy L Thompson   @param[out] vec      Variable to store `CeedVector`
122043bbe138SJeremy L Thompson 
122143bbe138SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
122243bbe138SJeremy L Thompson 
1223e9b533fbSJeremy L Thompson   @ref Advanced
122443bbe138SJeremy L Thompson **/
122543bbe138SJeremy L Thompson int CeedOperatorFieldGetVector(CeedOperatorField op_field, CeedVector *vec) {
1226681d0ea7SJeremy L Thompson   *vec = NULL;
1227681d0ea7SJeremy L Thompson   CeedCall(CeedVectorReferenceCopy(op_field->vec, vec));
122843bbe138SJeremy L Thompson   return CEED_ERROR_SUCCESS;
122943bbe138SJeremy L Thompson }
123043bbe138SJeremy L Thompson 
123143bbe138SJeremy L Thompson /**
1232ab747706SJeremy L Thompson   @brief Get the data of a `CeedOperator` Field.
1233ab747706SJeremy L Thompson 
1234681d0ea7SJeremy L Thompson   Any arguments set as `NULL` are ignored..
1235681d0ea7SJeremy L Thompson 
1236681d0ea7SJeremy L Thompson   Note: Caller is responsible for destroying the `rstr`, `basis`, and `vec`.
1237ab747706SJeremy L Thompson 
1238ab747706SJeremy L Thompson   @param[in]  op_field   `CeedOperator` Field
1239ab747706SJeremy L Thompson   @param[out] field_name Variable to store the field name
1240ab747706SJeremy L Thompson   @param[out] rstr       Variable to store `CeedElemRestriction`
1241ab747706SJeremy L Thompson   @param[out] basis      Variable to store `CeedBasis`
1242ab747706SJeremy L Thompson   @param[out] vec        Variable to store `CeedVector`
1243ab747706SJeremy L Thompson 
1244ab747706SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1245ab747706SJeremy L Thompson 
1246ab747706SJeremy L Thompson   @ref Advanced
1247ab747706SJeremy L Thompson **/
12486f8994e9SJeremy L Thompson int CeedOperatorFieldGetData(CeedOperatorField op_field, const char **field_name, CeedElemRestriction *rstr, CeedBasis *basis, CeedVector *vec) {
1249ab747706SJeremy L Thompson   if (field_name) CeedCall(CeedOperatorFieldGetName(op_field, field_name));
1250ab747706SJeremy L Thompson   if (rstr) CeedCall(CeedOperatorFieldGetElemRestriction(op_field, rstr));
1251ab747706SJeremy L Thompson   if (basis) CeedCall(CeedOperatorFieldGetBasis(op_field, basis));
1252ab747706SJeremy L Thompson   if (vec) CeedCall(CeedOperatorFieldGetVector(op_field, vec));
1253ab747706SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1254ab747706SJeremy L Thompson }
1255ab747706SJeremy L Thompson 
1256ab747706SJeremy L Thompson /**
1257ca94c3ddSJeremy L Thompson   @brief Add a sub-operator to a composite `CeedOperator`
1258288c0443SJeremy L Thompson 
1259ca94c3ddSJeremy L Thompson   @param[in,out] composite_op Composite `CeedOperator`
1260ca94c3ddSJeremy L Thompson   @param[in]     sub_op       Sub-operator `CeedOperator`
126152d6035fSJeremy L Thompson 
126252d6035fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
126352d6035fSJeremy L Thompson 
12647a982d89SJeremy L. Thompson   @ref User
126552d6035fSJeremy L Thompson  */
1266*ed094490SJeremy L Thompson int CeedOperatorCompositeAddSub(CeedOperator composite_op, CeedOperator sub_op) {
12671203703bSJeremy L Thompson   bool is_immutable;
12681203703bSJeremy L Thompson 
12699bc66399SJeremy L Thompson   CeedCheck(composite_op->is_composite, CeedOperatorReturnCeed(composite_op), CEED_ERROR_MINOR, "CeedOperator is not a composite operator");
12709bc66399SJeremy L Thompson   CeedCheck(composite_op->num_suboperators < CEED_COMPOSITE_MAX, CeedOperatorReturnCeed(composite_op), CEED_ERROR_UNSUPPORTED,
12719bc66399SJeremy L Thompson             "Cannot add additional sub-operators");
12721203703bSJeremy L Thompson   CeedCall(CeedOperatorIsImmutable(composite_op, &is_immutable));
12739bc66399SJeremy L Thompson   CeedCheck(!is_immutable, CeedOperatorReturnCeed(composite_op), CEED_ERROR_MAJOR, "Operator cannot be changed after set as immutable");
12742b730f8bSJeremy L Thompson 
12752b730f8bSJeremy L Thompson   {
12762b730f8bSJeremy L Thompson     CeedSize input_size, output_size;
12771c66c397SJeremy L Thompson 
12782b730f8bSJeremy L Thompson     CeedCall(CeedOperatorGetActiveVectorLengths(sub_op, &input_size, &output_size));
12792b730f8bSJeremy L Thompson     if (composite_op->input_size == -1) composite_op->input_size = input_size;
12802b730f8bSJeremy L Thompson     if (composite_op->output_size == -1) composite_op->output_size = output_size;
12812b730f8bSJeremy L Thompson     // Note, a size of -1 means no active vector restriction set, so no incompatibility
12829bc66399SJeremy L Thompson     CeedCheck((input_size == -1 || input_size == composite_op->input_size) && (output_size == -1 || output_size == composite_op->output_size),
12839bc66399SJeremy L Thompson               CeedOperatorReturnCeed(composite_op), CEED_ERROR_MAJOR,
1284249f8407SJeremy L Thompson               "Sub-operators must have compatible dimensions; composite operator of shape (%" CeedSize_FMT ", %" CeedSize_FMT
1285249f8407SJeremy L Thompson               ") not compatible with sub-operator of "
1286249f8407SJeremy L Thompson               "shape (%" CeedSize_FMT ", %" CeedSize_FMT ")",
12872b730f8bSJeremy L Thompson               composite_op->input_size, composite_op->output_size, input_size, output_size);
12882b730f8bSJeremy L Thompson   }
12892b730f8bSJeremy L Thompson 
1290d1d35e2fSjeremylt   composite_op->sub_operators[composite_op->num_suboperators] = sub_op;
12912b730f8bSJeremy L Thompson   CeedCall(CeedOperatorReference(sub_op));
1292d1d35e2fSjeremylt   composite_op->num_suboperators++;
1293e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
129452d6035fSJeremy L Thompson }
129552d6035fSJeremy L Thompson 
129652d6035fSJeremy L Thompson /**
1297ca94c3ddSJeremy L Thompson   @brief Get the number of sub-operators associated with a `CeedOperator`
129875f0d5a4SJeremy L Thompson 
1299ca94c3ddSJeremy L Thompson   @param[in]  op               `CeedOperator`
1300ca94c3ddSJeremy L Thompson   @param[out] num_suboperators Variable to store number of sub-operators
130175f0d5a4SJeremy L Thompson 
130275f0d5a4SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
130375f0d5a4SJeremy L Thompson 
130475f0d5a4SJeremy L Thompson   @ref Backend
130575f0d5a4SJeremy L Thompson **/
1306*ed094490SJeremy L Thompson int CeedOperatorCompositeGetNumSub(CeedOperator op, CeedInt *num_suboperators) {
13071203703bSJeremy L Thompson   bool is_composite;
13081203703bSJeremy L Thompson 
13091203703bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
13106e536b99SJeremy L Thompson   CeedCheck(is_composite, CeedOperatorReturnCeed(op), CEED_ERROR_MINOR, "Only defined for a composite operator");
131175f0d5a4SJeremy L Thompson   *num_suboperators = op->num_suboperators;
131275f0d5a4SJeremy L Thompson   return CEED_ERROR_SUCCESS;
131375f0d5a4SJeremy L Thompson }
131475f0d5a4SJeremy L Thompson 
131575f0d5a4SJeremy L Thompson /**
1316ca94c3ddSJeremy L Thompson   @brief Get the list of sub-operators associated with a `CeedOperator`
131775f0d5a4SJeremy L Thompson 
1318ca94c3ddSJeremy L Thompson   @param[in]  op             `CeedOperator`
1319ca94c3ddSJeremy L Thompson   @param[out] sub_operators  Variable to store list of sub-operators
132075f0d5a4SJeremy L Thompson 
132175f0d5a4SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
132275f0d5a4SJeremy L Thompson 
132375f0d5a4SJeremy L Thompson   @ref Backend
132475f0d5a4SJeremy L Thompson **/
1325*ed094490SJeremy L Thompson int CeedOperatorCompositeGetSubList(CeedOperator op, CeedOperator **sub_operators) {
13261203703bSJeremy L Thompson   bool is_composite;
13271203703bSJeremy L Thompson 
13281203703bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
13296e536b99SJeremy L Thompson   CeedCheck(is_composite, CeedOperatorReturnCeed(op), CEED_ERROR_MINOR, "Only defined for a composite operator");
133075f0d5a4SJeremy L Thompson   *sub_operators = op->sub_operators;
133175f0d5a4SJeremy L Thompson   return CEED_ERROR_SUCCESS;
133275f0d5a4SJeremy L Thompson }
133375f0d5a4SJeremy L Thompson 
133475f0d5a4SJeremy L Thompson /**
13358a297abdSJames Wright   @brief Get a sub `CeedOperator` of a composite `CeedOperator` from its name.
13368a297abdSJames Wright 
13378a297abdSJames Wright   `sub_op` is set to `NULL` if the sub operator is not found.
13388a297abdSJames Wright 
13398a297abdSJames Wright   Note: Calling this function asserts that setup is complete and sets the `CeedOperator` as immutable.
13408a297abdSJames Wright 
13418a297abdSJames Wright   @param[in]  op      Composite `CeedOperator`
13428a297abdSJames Wright   @param[in]  op_name Name of desired sub `CeedOperator`
13438a297abdSJames Wright   @param[out] sub_op  Sub `CeedOperator` corresponding to the name
13448a297abdSJames Wright 
13458a297abdSJames Wright   @return An error code: 0 - success, otherwise - failure
13468a297abdSJames Wright 
13478a297abdSJames Wright   @ref Advanced
13488a297abdSJames Wright **/
1349*ed094490SJeremy L Thompson int CeedOperatorCompositeGetSubByName(CeedOperator op, const char *op_name, CeedOperator *sub_op) {
13508a297abdSJames Wright   bool          is_composite;
13518a297abdSJames Wright   CeedInt       num_sub_ops;
13528a297abdSJames Wright   CeedOperator *sub_ops;
13538a297abdSJames Wright 
13548a297abdSJames Wright   CeedCall(CeedOperatorIsComposite(op, &is_composite));
13558a297abdSJames Wright   CeedCheck(is_composite, CeedOperatorReturnCeed(op), CEED_ERROR_MINOR, "Only defined for a composite operator");
13568a297abdSJames Wright   *sub_op = NULL;
1357*ed094490SJeremy L Thompson   CeedCall(CeedOperatorCompositeGetNumSub(op, &num_sub_ops));
1358*ed094490SJeremy L Thompson   CeedCall(CeedOperatorCompositeGetSubList(op, &sub_ops));
13598a297abdSJames Wright   for (CeedInt i = 0; i < num_sub_ops; i++) {
13608a297abdSJames Wright     if (sub_ops[i]->name && !strcmp(op_name, sub_ops[i]->name)) {
13618a297abdSJames Wright       *sub_op = sub_ops[i];
13628a297abdSJames Wright       return CEED_ERROR_SUCCESS;
13638a297abdSJames Wright     }
13648a297abdSJames Wright   }
13658a297abdSJames Wright   return CEED_ERROR_SUCCESS;
13668a297abdSJames Wright }
13678a297abdSJames Wright 
13688a297abdSJames Wright /**
1369ca94c3ddSJeremy L Thompson   @brief Check if a `CeedOperator` is ready to be used.
13704db537f9SJeremy L Thompson 
1371ca94c3ddSJeremy L Thompson   @param[in] op `CeedOperator` to check
13724db537f9SJeremy L Thompson 
13734db537f9SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
13744db537f9SJeremy L Thompson 
13754db537f9SJeremy L Thompson   @ref User
13764db537f9SJeremy L Thompson **/
13774db537f9SJeremy L Thompson int CeedOperatorCheckReady(CeedOperator op) {
13781203703bSJeremy L Thompson   bool          is_at_points, is_composite;
13791203703bSJeremy L Thompson   CeedQFunction qf = NULL;
13804db537f9SJeremy L Thompson 
13812b730f8bSJeremy L Thompson   if (op->is_interface_setup) return CEED_ERROR_SUCCESS;
13824db537f9SJeremy L Thompson 
13831203703bSJeremy L Thompson   CeedCall(CeedOperatorIsAtPoints(op, &is_at_points));
13841203703bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
13851203703bSJeremy L Thompson   if (!is_composite) CeedCall(CeedOperatorGetQFunction(op, &qf));
13861203703bSJeremy L Thompson   if (is_composite) {
13871203703bSJeremy L Thompson     CeedInt num_suboperators;
13881203703bSJeremy L Thompson 
1389*ed094490SJeremy L Thompson     CeedCall(CeedOperatorCompositeGetNumSub(op, &num_suboperators));
13901203703bSJeremy L Thompson     if (!num_suboperators) {
139143622462SJeremy L Thompson       // Empty operator setup
139243622462SJeremy L Thompson       op->input_size  = 0;
139343622462SJeremy L Thompson       op->output_size = 0;
139443622462SJeremy L Thompson     } else {
13951203703bSJeremy L Thompson       CeedOperator *sub_operators;
13961203703bSJeremy L Thompson 
1397*ed094490SJeremy L Thompson       CeedCall(CeedOperatorCompositeGetSubList(op, &sub_operators));
13981203703bSJeremy L Thompson       for (CeedInt i = 0; i < num_suboperators; i++) {
13991203703bSJeremy L Thompson         CeedCall(CeedOperatorCheckReady(sub_operators[i]));
14004db537f9SJeremy L Thompson       }
14012b104005SJeremy L Thompson       // Sub-operators could be modified after adding to composite operator
14022b104005SJeremy L Thompson       // Need to verify no lvec incompatibility from any changes
14032b104005SJeremy L Thompson       CeedSize input_size, output_size;
14042b730f8bSJeremy L Thompson       CeedCall(CeedOperatorGetActiveVectorLengths(op, &input_size, &output_size));
140543622462SJeremy L Thompson     }
14064db537f9SJeremy L Thompson   } else {
14071203703bSJeremy L Thompson     CeedInt num_input_fields, num_output_fields;
14081203703bSJeremy L Thompson 
14099bc66399SJeremy L Thompson     CeedCheck(op->num_fields > 0, CeedOperatorReturnCeed(op), CEED_ERROR_INCOMPLETE, "No operator fields set");
14101203703bSJeremy L Thompson     CeedCall(CeedQFunctionGetFields(qf, &num_input_fields, NULL, &num_output_fields, NULL));
14119bc66399SJeremy L Thompson     CeedCheck(op->num_fields == num_input_fields + num_output_fields, CeedOperatorReturnCeed(op), CEED_ERROR_INCOMPLETE,
14129bc66399SJeremy L Thompson               "Not all operator fields set");
14139bc66399SJeremy L Thompson     CeedCheck(op->has_restriction, CeedOperatorReturnCeed(op), CEED_ERROR_INCOMPLETE, "At least one restriction required");
14149bc66399SJeremy L Thompson     CeedCheck(op->num_qpts > 0 || is_at_points, CeedOperatorReturnCeed(op), CEED_ERROR_INCOMPLETE,
1415ca94c3ddSJeremy L Thompson               "At least one non-collocated CeedBasis is required or the number of quadrature points must be set");
14162b730f8bSJeremy L Thompson   }
14174db537f9SJeremy L Thompson 
14184db537f9SJeremy L Thompson   // Flag as immutable and ready
14194db537f9SJeremy L Thompson   op->is_interface_setup = true;
14201203703bSJeremy L Thompson   if (qf && qf != CEED_QFUNCTION_NONE) CeedCall(CeedQFunctionSetImmutable(qf));
1421c11e12f4SJeremy L Thompson   CeedCall(CeedQFunctionDestroy(&qf));
14221203703bSJeremy L Thompson   if (op->dqf && op->dqf != CEED_QFUNCTION_NONE) CeedCall(CeedQFunctionSetImmutable(op->dqf));
14231203703bSJeremy L Thompson   if (op->dqfT && op->dqfT != CEED_QFUNCTION_NONE) CeedCall(CeedQFunctionSetImmutable(op->dqfT));
14244db537f9SJeremy L Thompson   return CEED_ERROR_SUCCESS;
14254db537f9SJeremy L Thompson }
14264db537f9SJeremy L Thompson 
14274db537f9SJeremy L Thompson /**
1428ca94c3ddSJeremy L Thompson   @brief Get vector lengths for the active input and/or output `CeedVector` of a `CeedOperator`.
14294385fb7fSSebastian Grimberg 
1430ca94c3ddSJeremy L Thompson   Note: Lengths of `-1` indicate that the CeedOperator does not have an active input and/or output.
1431c9366a6bSJeremy L Thompson 
1432ca94c3ddSJeremy L Thompson   @param[in]  op          `CeedOperator`
1433ca94c3ddSJeremy L Thompson   @param[out] input_size  Variable to store active input vector length, or `NULL`
1434ca94c3ddSJeremy L Thompson   @param[out] output_size Variable to store active output vector length, or `NULL`
1435c9366a6bSJeremy L Thompson 
1436c9366a6bSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1437c9366a6bSJeremy L Thompson 
1438c9366a6bSJeremy L Thompson   @ref User
1439c9366a6bSJeremy L Thompson **/
14402b730f8bSJeremy L Thompson int CeedOperatorGetActiveVectorLengths(CeedOperator op, CeedSize *input_size, CeedSize *output_size) {
1441c9366a6bSJeremy L Thompson   bool is_composite;
1442c9366a6bSJeremy L Thompson 
14432b104005SJeremy L Thompson   if (input_size) *input_size = op->input_size;
14442b104005SJeremy L Thompson   if (output_size) *output_size = op->output_size;
1445c9366a6bSJeremy L Thompson 
14462b730f8bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
14472b104005SJeremy L Thompson   if (is_composite && (op->input_size == -1 || op->output_size == -1)) {
14481203703bSJeremy L Thompson     CeedInt       num_suboperators;
14491203703bSJeremy L Thompson     CeedOperator *sub_operators;
14501203703bSJeremy L Thompson 
1451*ed094490SJeremy L Thompson     CeedCall(CeedOperatorCompositeGetNumSub(op, &num_suboperators));
1452*ed094490SJeremy L Thompson     CeedCall(CeedOperatorCompositeGetSubList(op, &sub_operators));
14531203703bSJeremy L Thompson     for (CeedInt i = 0; i < num_suboperators; i++) {
1454c9366a6bSJeremy L Thompson       CeedSize sub_input_size, sub_output_size;
14551c66c397SJeremy L Thompson 
14561203703bSJeremy L Thompson       CeedCall(CeedOperatorGetActiveVectorLengths(sub_operators[i], &sub_input_size, &sub_output_size));
14572b104005SJeremy L Thompson       if (op->input_size == -1) op->input_size = sub_input_size;
14582b104005SJeremy L Thompson       if (op->output_size == -1) op->output_size = sub_output_size;
14592b104005SJeremy L Thompson       // Note, a size of -1 means no active vector restriction set, so no incompatibility
14606e536b99SJeremy L Thompson       CeedCheck((sub_input_size == -1 || sub_input_size == op->input_size) && (sub_output_size == -1 || sub_output_size == op->output_size),
14616e536b99SJeremy L Thompson                 CeedOperatorReturnCeed(op), CEED_ERROR_MAJOR,
1462249f8407SJeremy L Thompson                 "Sub-operators must have compatible dimensions; composite operator of shape (%" CeedSize_FMT ", %" CeedSize_FMT
1463249f8407SJeremy L Thompson                 ") not compatible with sub-operator of "
1464249f8407SJeremy L Thompson                 "shape (%" CeedSize_FMT ", %" CeedSize_FMT ")",
14652b104005SJeremy L Thompson                 op->input_size, op->output_size, input_size, output_size);
1466c9366a6bSJeremy L Thompson     }
14672b730f8bSJeremy L Thompson   }
1468c9366a6bSJeremy L Thompson   return CEED_ERROR_SUCCESS;
1469c9366a6bSJeremy L Thompson }
1470c9366a6bSJeremy L Thompson 
1471c9366a6bSJeremy L Thompson /**
1472ca94c3ddSJeremy L Thompson   @brief Set reuse of `CeedQFunction` data in `CeedOperatorLinearAssemble*()` functions.
14734385fb7fSSebastian Grimberg 
1474ca94c3ddSJeremy L Thompson   When `reuse_assembly_data = false` (default), the `CeedQFunction` associated with this `CeedOperator` is re-assembled every time a `CeedOperatorLinearAssemble*()` function is called.
1475ca94c3ddSJeremy L Thompson   When `reuse_assembly_data = true`, the `CeedQFunction` associated with this `CeedOperator` is reused between calls to @ref CeedOperatorSetQFunctionAssemblyDataUpdateNeeded().
14768b919e6bSJeremy L Thompson 
1477ca94c3ddSJeremy L Thompson   @param[in] op                  `CeedOperator`
1478beecbf24SJeremy L Thompson   @param[in] reuse_assembly_data Boolean flag setting assembly data reuse
14798b919e6bSJeremy L Thompson 
14808b919e6bSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
14818b919e6bSJeremy L Thompson 
14828b919e6bSJeremy L Thompson   @ref Advanced
14838b919e6bSJeremy L Thompson **/
14842b730f8bSJeremy L Thompson int CeedOperatorSetQFunctionAssemblyReuse(CeedOperator op, bool reuse_assembly_data) {
14858b919e6bSJeremy L Thompson   bool is_composite;
14868b919e6bSJeremy L Thompson 
14872b730f8bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
14888b919e6bSJeremy L Thompson   if (is_composite) {
14898b919e6bSJeremy L Thompson     for (CeedInt i = 0; i < op->num_suboperators; i++) {
14902b730f8bSJeremy L Thompson       CeedCall(CeedOperatorSetQFunctionAssemblyReuse(op->sub_operators[i], reuse_assembly_data));
14918b919e6bSJeremy L Thompson     }
14928b919e6bSJeremy L Thompson   } else {
14937d5185d7SSebastian Grimberg     CeedQFunctionAssemblyData data;
14947d5185d7SSebastian Grimberg 
14957d5185d7SSebastian Grimberg     CeedCall(CeedOperatorGetQFunctionAssemblyData(op, &data));
14967d5185d7SSebastian Grimberg     CeedCall(CeedQFunctionAssemblyDataSetReuse(data, reuse_assembly_data));
1497beecbf24SJeremy L Thompson   }
1498beecbf24SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1499beecbf24SJeremy L Thompson }
1500beecbf24SJeremy L Thompson 
1501beecbf24SJeremy L Thompson /**
1502ca94c3ddSJeremy L Thompson   @brief Mark `CeedQFunction` data as updated and the `CeedQFunction` as requiring re-assembly.
1503beecbf24SJeremy L Thompson 
1504ca94c3ddSJeremy L Thompson   @param[in] op                `CeedOperator`
15056e15d496SJeremy L Thompson   @param[in] needs_data_update Boolean flag setting assembly data reuse
1506beecbf24SJeremy L Thompson 
1507beecbf24SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1508beecbf24SJeremy L Thompson 
1509beecbf24SJeremy L Thompson   @ref Advanced
1510beecbf24SJeremy L Thompson **/
15112b730f8bSJeremy L Thompson int CeedOperatorSetQFunctionAssemblyDataUpdateNeeded(CeedOperator op, bool needs_data_update) {
1512beecbf24SJeremy L Thompson   bool is_composite;
1513beecbf24SJeremy L Thompson 
15142b730f8bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
1515beecbf24SJeremy L Thompson   if (is_composite) {
15161203703bSJeremy L Thompson     CeedInt       num_suboperators;
15171203703bSJeremy L Thompson     CeedOperator *sub_operators;
15181203703bSJeremy L Thompson 
1519*ed094490SJeremy L Thompson     CeedCall(CeedOperatorCompositeGetNumSub(op, &num_suboperators));
1520*ed094490SJeremy L Thompson     CeedCall(CeedOperatorCompositeGetSubList(op, &sub_operators));
15211203703bSJeremy L Thompson     for (CeedInt i = 0; i < num_suboperators; i++) {
15221203703bSJeremy L Thompson       CeedCall(CeedOperatorSetQFunctionAssemblyDataUpdateNeeded(sub_operators[i], needs_data_update));
1523beecbf24SJeremy L Thompson     }
1524beecbf24SJeremy L Thompson   } else {
15257d5185d7SSebastian Grimberg     CeedQFunctionAssemblyData data;
15267d5185d7SSebastian Grimberg 
15277d5185d7SSebastian Grimberg     CeedCall(CeedOperatorGetQFunctionAssemblyData(op, &data));
15287d5185d7SSebastian Grimberg     CeedCall(CeedQFunctionAssemblyDataSetUpdateNeeded(data, needs_data_update));
15298b919e6bSJeremy L Thompson   }
15308b919e6bSJeremy L Thompson   return CEED_ERROR_SUCCESS;
15318b919e6bSJeremy L Thompson }
15328b919e6bSJeremy L Thompson 
15338b919e6bSJeremy L Thompson /**
1534ca94c3ddSJeremy L Thompson   @brief Set name of `CeedOperator` for @ref CeedOperatorView() output
1535ea6b5821SJeremy L Thompson 
1536ca94c3ddSJeremy L Thompson   @param[in,out] op   `CeedOperator`
1537ea61e9acSJeremy L Thompson   @param[in]     name Name to set, or NULL to remove previously set name
1538ea6b5821SJeremy L Thompson 
1539ea6b5821SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1540ea6b5821SJeremy L Thompson 
1541ea6b5821SJeremy L Thompson   @ref User
1542ea6b5821SJeremy L Thompson **/
1543ea6b5821SJeremy L Thompson int CeedOperatorSetName(CeedOperator op, const char *name) {
1544ea6b5821SJeremy L Thompson   char  *name_copy;
1545ea6b5821SJeremy L Thompson   size_t name_len = name ? strlen(name) : 0;
1546ea6b5821SJeremy L Thompson 
15472b730f8bSJeremy L Thompson   CeedCall(CeedFree(&op->name));
1548ea6b5821SJeremy L Thompson   if (name_len > 0) {
15492b730f8bSJeremy L Thompson     CeedCall(CeedCalloc(name_len + 1, &name_copy));
1550ea6b5821SJeremy L Thompson     memcpy(name_copy, name, name_len);
1551ea6b5821SJeremy L Thompson     op->name = name_copy;
1552ea6b5821SJeremy L Thompson   }
1553ea6b5821SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1554ea6b5821SJeremy L Thompson }
1555ea6b5821SJeremy L Thompson 
1556ea6b5821SJeremy L Thompson /**
1557d3d5610dSJeremy L Thompson   @brief Get name of `CeedOperator`
1558d3d5610dSJeremy L Thompson 
1559d3d5610dSJeremy L Thompson   @param[in]     op   `CeedOperator`
1560d3d5610dSJeremy L Thompson   @param[in,out] name Address of variable to hold currently set name
1561d3d5610dSJeremy L Thompson 
1562d3d5610dSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1563d3d5610dSJeremy L Thompson 
1564d3d5610dSJeremy L Thompson   @ref User
1565d3d5610dSJeremy L Thompson **/
1566d3d5610dSJeremy L Thompson int CeedOperatorGetName(CeedOperator op, const char **name) {
1567d3d5610dSJeremy L Thompson   if (op->name) {
1568d3d5610dSJeremy L Thompson     *name = op->name;
1569d3d5610dSJeremy L Thompson   } else if (!op->is_composite) {
1570d3d5610dSJeremy L Thompson     CeedQFunction qf;
1571d3d5610dSJeremy L Thompson 
1572d3d5610dSJeremy L Thompson     CeedCall(CeedOperatorGetQFunction(op, &qf));
1573d3d5610dSJeremy L Thompson     if (qf) CeedCall(CeedQFunctionGetName(qf, name));
1574d3d5610dSJeremy L Thompson     CeedCall(CeedQFunctionDestroy(&qf));
1575d3d5610dSJeremy L Thompson   }
1576d3d5610dSJeremy L Thompson   return CEED_ERROR_SUCCESS;
1577d3d5610dSJeremy L Thompson }
1578d3d5610dSJeremy L Thompson 
1579d3d5610dSJeremy L Thompson /**
1580935f026aSJeremy L Thompson   @brief Core logic for viewing a `CeedOperator`
15817a982d89SJeremy L. Thompson 
1582935f026aSJeremy L Thompson   @param[in] op     `CeedOperator` to view brief summary
1583ca94c3ddSJeremy L Thompson   @param[in] stream  Stream to write; typically `stdout` or a file
15848bf1b130SJames Wright   @param[in] is_full Whether to write full operator view or terse
15857a982d89SJeremy L. Thompson 
15867a982d89SJeremy L. Thompson   @return Error code: 0 - success, otherwise - failure
15876ab8e59fSJames Wright 
15886ab8e59fSJames Wright   @ref Developer
15897a982d89SJeremy L. Thompson **/
15908bf1b130SJames Wright static int CeedOperatorView_Core(CeedOperator op, FILE *stream, bool is_full) {
1591d3d5610dSJeremy L Thompson   bool        has_name, is_composite, is_at_points;
1592d3d5610dSJeremy L Thompson   const char *name = NULL;
15937a982d89SJeremy L. Thompson 
1594d3d5610dSJeremy L Thompson   CeedCall(CeedOperatorGetName(op, &name));
1595d3d5610dSJeremy L Thompson   has_name = name ? strlen(name) : false;
15961203703bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
159799f7f61fSJeremy L Thompson   CeedCall(CeedOperatorIsAtPoints(op, &is_at_points));
15981203703bSJeremy L Thompson   if (is_composite) {
15991203703bSJeremy L Thompson     CeedInt       num_suboperators;
16001203703bSJeremy L Thompson     CeedOperator *sub_operators;
16011203703bSJeremy L Thompson 
1602*ed094490SJeremy L Thompson     CeedCall(CeedOperatorCompositeGetNumSub(op, &num_suboperators));
1603*ed094490SJeremy L Thompson     CeedCall(CeedOperatorCompositeGetSubList(op, &sub_operators));
1604d3d5610dSJeremy L Thompson     fprintf(stream, "Composite CeedOperator%s%s\n", has_name ? " - " : "", has_name ? name : "");
16057a982d89SJeremy L. Thompson 
16061203703bSJeremy L Thompson     for (CeedInt i = 0; i < num_suboperators; i++) {
16071203703bSJeremy L Thompson       has_name = sub_operators[i]->name;
160899f7f61fSJeremy L Thompson       fprintf(stream, "  SubOperator%s %" CeedInt_FMT "%s%s%s\n", is_at_points ? " AtPoints" : "", i, has_name ? " - " : "",
160999f7f61fSJeremy L Thompson               has_name ? sub_operators[i]->name : "", is_full ? ":" : "");
1610935f026aSJeremy L Thompson       if (is_full) CeedCall(CeedOperatorSingleView(sub_operators[i], 1, stream));
16117a982d89SJeremy L. Thompson     }
16127a982d89SJeremy L. Thompson   } else {
1613d3d5610dSJeremy L Thompson     fprintf(stream, "CeedOperator%s%s%s\n", is_at_points ? " AtPoints" : "", has_name ? " - " : "", has_name ? name : "");
1614935f026aSJeremy L Thompson     if (is_full) CeedCall(CeedOperatorSingleView(op, 0, stream));
16157a982d89SJeremy L. Thompson   }
1616e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
16177a982d89SJeremy L. Thompson }
16183bd813ffSjeremylt 
16193bd813ffSjeremylt /**
1620935f026aSJeremy L Thompson   @brief View a `CeedOperator`
1621935f026aSJeremy L Thompson 
1622935f026aSJeremy L Thompson   @param[in] op     `CeedOperator` to view
1623935f026aSJeremy L Thompson   @param[in] stream Stream to write; typically `stdout` or a file
1624935f026aSJeremy L Thompson 
1625935f026aSJeremy L Thompson   @return Error code: 0 - success, otherwise - failure
1626935f026aSJeremy L Thompson 
1627935f026aSJeremy L Thompson   @ref User
1628935f026aSJeremy L Thompson **/
1629935f026aSJeremy L Thompson int CeedOperatorView(CeedOperator op, FILE *stream) {
1630935f026aSJeremy L Thompson   CeedCall(CeedOperatorView_Core(op, stream, true));
1631935f026aSJeremy L Thompson   return CEED_ERROR_SUCCESS;
1632935f026aSJeremy L Thompson }
1633935f026aSJeremy L Thompson 
1634935f026aSJeremy L Thompson /**
1635935f026aSJeremy L Thompson   @brief View a brief summary `CeedOperator`
1636935f026aSJeremy L Thompson 
1637935f026aSJeremy L Thompson   @param[in] op     `CeedOperator` to view brief summary
1638935f026aSJeremy L Thompson   @param[in] stream Stream to write; typically `stdout` or a file
1639935f026aSJeremy L Thompson 
1640935f026aSJeremy L Thompson   @return Error code: 0 - success, otherwise - failure
1641935f026aSJeremy L Thompson 
1642935f026aSJeremy L Thompson   @ref User
1643935f026aSJeremy L Thompson **/
1644935f026aSJeremy L Thompson int CeedOperatorViewTerse(CeedOperator op, FILE *stream) {
1645935f026aSJeremy L Thompson   CeedCall(CeedOperatorView_Core(op, stream, false));
1646935f026aSJeremy L Thompson   return CEED_ERROR_SUCCESS;
1647935f026aSJeremy L Thompson }
1648935f026aSJeremy L Thompson 
1649935f026aSJeremy L Thompson /**
1650ca94c3ddSJeremy L Thompson   @brief Get the `Ceed` associated with a `CeedOperator`
1651b7c9bbdaSJeremy L Thompson 
1652ca94c3ddSJeremy L Thompson   @param[in]  op   `CeedOperator`
1653ca94c3ddSJeremy L Thompson   @param[out] ceed Variable to store `Ceed`
1654b7c9bbdaSJeremy L Thompson 
1655b7c9bbdaSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1656b7c9bbdaSJeremy L Thompson 
1657b7c9bbdaSJeremy L Thompson   @ref Advanced
1658b7c9bbdaSJeremy L Thompson **/
1659b7c9bbdaSJeremy L Thompson int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) {
16609bc66399SJeremy L Thompson   *ceed = NULL;
16619bc66399SJeremy L Thompson   CeedCall(CeedReferenceCopy(CeedOperatorReturnCeed(op), ceed));
1662b7c9bbdaSJeremy L Thompson   return CEED_ERROR_SUCCESS;
1663b7c9bbdaSJeremy L Thompson }
1664b7c9bbdaSJeremy L Thompson 
1665b7c9bbdaSJeremy L Thompson /**
16666e536b99SJeremy L Thompson   @brief Return the `Ceed` associated with a `CeedOperator`
16676e536b99SJeremy L Thompson 
16686e536b99SJeremy L Thompson   @param[in]  op `CeedOperator`
16696e536b99SJeremy L Thompson 
16706e536b99SJeremy L Thompson   @return `Ceed` associated with the `op`
16716e536b99SJeremy L Thompson 
16726e536b99SJeremy L Thompson   @ref Advanced
16736e536b99SJeremy L Thompson **/
16746e536b99SJeremy L Thompson Ceed CeedOperatorReturnCeed(CeedOperator op) { return op->ceed; }
16756e536b99SJeremy L Thompson 
16766e536b99SJeremy L Thompson /**
1677ca94c3ddSJeremy L Thompson   @brief Get the number of elements associated with a `CeedOperator`
1678b7c9bbdaSJeremy L Thompson 
1679ca94c3ddSJeremy L Thompson   @param[in]  op       `CeedOperator`
1680b7c9bbdaSJeremy L Thompson   @param[out] num_elem Variable to store number of elements
1681b7c9bbdaSJeremy L Thompson 
1682b7c9bbdaSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1683b7c9bbdaSJeremy L Thompson 
1684b7c9bbdaSJeremy L Thompson   @ref Advanced
1685b7c9bbdaSJeremy L Thompson **/
1686b7c9bbdaSJeremy L Thompson int CeedOperatorGetNumElements(CeedOperator op, CeedInt *num_elem) {
16871203703bSJeremy L Thompson   bool is_composite;
16881203703bSJeremy L Thompson 
16891203703bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
16906e536b99SJeremy L Thompson   CeedCheck(!is_composite, CeedOperatorReturnCeed(op), CEED_ERROR_MINOR, "Not defined for composite operator");
1691b7c9bbdaSJeremy L Thompson   *num_elem = op->num_elem;
1692b7c9bbdaSJeremy L Thompson   return CEED_ERROR_SUCCESS;
1693b7c9bbdaSJeremy L Thompson }
1694b7c9bbdaSJeremy L Thompson 
1695b7c9bbdaSJeremy L Thompson /**
1696ca94c3ddSJeremy L Thompson   @brief Get the number of quadrature points associated with a `CeedOperator`
1697b7c9bbdaSJeremy L Thompson 
1698ca94c3ddSJeremy L Thompson   @param[in]  op       `CeedOperator`
1699b7c9bbdaSJeremy L Thompson   @param[out] num_qpts Variable to store vector number of quadrature points
1700b7c9bbdaSJeremy L Thompson 
1701b7c9bbdaSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1702b7c9bbdaSJeremy L Thompson 
1703b7c9bbdaSJeremy L Thompson   @ref Advanced
1704b7c9bbdaSJeremy L Thompson **/
1705b7c9bbdaSJeremy L Thompson int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *num_qpts) {
17061203703bSJeremy L Thompson   bool is_composite;
17071203703bSJeremy L Thompson 
17081203703bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
17096e536b99SJeremy L Thompson   CeedCheck(!is_composite, CeedOperatorReturnCeed(op), CEED_ERROR_MINOR, "Not defined for composite operator");
1710b7c9bbdaSJeremy L Thompson   *num_qpts = op->num_qpts;
1711b7c9bbdaSJeremy L Thompson   return CEED_ERROR_SUCCESS;
1712b7c9bbdaSJeremy L Thompson }
1713b7c9bbdaSJeremy L Thompson 
1714b7c9bbdaSJeremy L Thompson /**
1715ca94c3ddSJeremy L Thompson   @brief Estimate number of FLOPs required to apply `CeedOperator` on the active `CeedVector`
17166e15d496SJeremy L Thompson 
1717ca94c3ddSJeremy L Thompson   @param[in]  op    `CeedOperator` to estimate FLOPs for
1718ea61e9acSJeremy L Thompson   @param[out] flops Address of variable to hold FLOPs estimate
17196e15d496SJeremy L Thompson 
17206e15d496SJeremy L Thompson   @ref Backend
17216e15d496SJeremy L Thompson **/
17229d36ca50SJeremy L Thompson int CeedOperatorGetFlopsEstimate(CeedOperator op, CeedSize *flops) {
17236e15d496SJeremy L Thompson   bool is_composite;
17241c66c397SJeremy L Thompson 
17252b730f8bSJeremy L Thompson   CeedCall(CeedOperatorCheckReady(op));
17266e15d496SJeremy L Thompson 
17276e15d496SJeremy L Thompson   *flops = 0;
17282b730f8bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
17296e15d496SJeremy L Thompson   if (is_composite) {
17306e15d496SJeremy L Thompson     CeedInt num_suboperators;
17311c66c397SJeremy L Thompson 
1732*ed094490SJeremy L Thompson     CeedCall(CeedOperatorCompositeGetNumSub(op, &num_suboperators));
17336e15d496SJeremy L Thompson     CeedOperator *sub_operators;
1734*ed094490SJeremy L Thompson     CeedCall(CeedOperatorCompositeGetSubList(op, &sub_operators));
17356e15d496SJeremy L Thompson 
17366e15d496SJeremy L Thompson     // FLOPs for each suboperator
17376e15d496SJeremy L Thompson     for (CeedInt i = 0; i < num_suboperators; i++) {
17389d36ca50SJeremy L Thompson       CeedSize suboperator_flops;
17391c66c397SJeremy L Thompson 
17402b730f8bSJeremy L Thompson       CeedCall(CeedOperatorGetFlopsEstimate(sub_operators[i], &suboperator_flops));
17416e15d496SJeremy L Thompson       *flops += suboperator_flops;
17426e15d496SJeremy L Thompson     }
17436e15d496SJeremy L Thompson   } else {
17443f919cbcSJeremy L Thompson     bool                is_at_points;
17453f919cbcSJeremy L Thompson     CeedInt             num_input_fields, num_output_fields, num_elem = 0, num_points = 0;
17461203703bSJeremy L Thompson     CeedQFunction       qf;
17471203703bSJeremy L Thompson     CeedQFunctionField *qf_input_fields, *qf_output_fields;
17481203703bSJeremy L Thompson     CeedOperatorField  *op_input_fields, *op_output_fields;
17491c66c397SJeremy L Thompson 
17503f919cbcSJeremy L Thompson     CeedCall(CeedOperatorGetNumElements(op, &num_elem));
175119feff82SJeremy L Thompson     if (num_elem == 0) return CEED_ERROR_SUCCESS;
175219feff82SJeremy L Thompson     CeedCall(CeedOperatorIsAtPoints(op, &is_at_points));
17533f919cbcSJeremy L Thompson     if (is_at_points) {
17543f919cbcSJeremy L Thompson       CeedMemType         mem_type;
17553f919cbcSJeremy L Thompson       CeedElemRestriction rstr_points = NULL;
17563f919cbcSJeremy L Thompson 
17573f919cbcSJeremy L Thompson       CeedCall(CeedOperatorAtPointsGetPoints(op, &rstr_points, NULL));
17583f919cbcSJeremy L Thompson       CeedCall(CeedGetPreferredMemType(CeedOperatorReturnCeed(op), &mem_type));
17593f919cbcSJeremy L Thompson       if (mem_type == CEED_MEM_DEVICE) {
17603f919cbcSJeremy L Thompson         // Device backends pad out to the same number of points per element
17613f919cbcSJeremy L Thompson         CeedCall(CeedElemRestrictionGetMaxPointsInElement(rstr_points, &num_points));
17623f919cbcSJeremy L Thompson       } else {
17633f919cbcSJeremy L Thompson         num_points = 0;
17643f919cbcSJeremy L Thompson         for (CeedInt i = 0; i < num_elem; i++) {
17653f919cbcSJeremy L Thompson           CeedInt points_in_elem = 0;
17663f919cbcSJeremy L Thompson 
17673f919cbcSJeremy L Thompson           CeedCall(CeedElemRestrictionGetNumPointsInElement(rstr_points, i, &points_in_elem));
17683f919cbcSJeremy L Thompson           num_points += points_in_elem;
17693f919cbcSJeremy L Thompson         }
17703f919cbcSJeremy L Thompson         num_points = num_points / num_elem + (num_points % num_elem > 0);
17713f919cbcSJeremy L Thompson       }
17723f919cbcSJeremy L Thompson       CeedCall(CeedElemRestrictionDestroy(&rstr_points));
17733f919cbcSJeremy L Thompson     }
17741203703bSJeremy L Thompson     CeedCall(CeedOperatorGetQFunction(op, &qf));
17751203703bSJeremy L Thompson     CeedCall(CeedQFunctionGetFields(qf, &num_input_fields, &qf_input_fields, &num_output_fields, &qf_output_fields));
1776c11e12f4SJeremy L Thompson     CeedCall(CeedQFunctionDestroy(&qf));
17771203703bSJeremy L Thompson     CeedCall(CeedOperatorGetFields(op, NULL, &op_input_fields, NULL, &op_output_fields));
17784385fb7fSSebastian Grimberg 
17796e15d496SJeremy L Thompson     // Input FLOPs
17806e15d496SJeremy L Thompson     for (CeedInt i = 0; i < num_input_fields; i++) {
17811203703bSJeremy L Thompson       CeedVector vec;
17826e15d496SJeremy L Thompson 
17831203703bSJeremy L Thompson       CeedCall(CeedOperatorFieldGetVector(op_input_fields[i], &vec));
17841203703bSJeremy L Thompson       if (vec == CEED_VECTOR_ACTIVE) {
17851203703bSJeremy L Thompson         CeedEvalMode        eval_mode;
17861203703bSJeremy L Thompson         CeedSize            rstr_flops, basis_flops;
17871203703bSJeremy L Thompson         CeedElemRestriction rstr;
17881203703bSJeremy L Thompson         CeedBasis           basis;
17891203703bSJeremy L Thompson 
17901203703bSJeremy L Thompson         CeedCall(CeedOperatorFieldGetElemRestriction(op_input_fields[i], &rstr));
17911203703bSJeremy L Thompson         CeedCall(CeedElemRestrictionGetFlopsEstimate(rstr, CEED_NOTRANSPOSE, &rstr_flops));
1792681d0ea7SJeremy L Thompson         CeedCall(CeedElemRestrictionDestroy(&rstr));
1793edb2538eSJeremy L Thompson         *flops += rstr_flops;
17941203703bSJeremy L Thompson         CeedCall(CeedOperatorFieldGetBasis(op_input_fields[i], &basis));
17951203703bSJeremy L Thompson         CeedCall(CeedQFunctionFieldGetEvalMode(qf_input_fields[i], &eval_mode));
17963f919cbcSJeremy L Thompson         CeedCall(CeedBasisGetFlopsEstimate(basis, CEED_NOTRANSPOSE, eval_mode, is_at_points, num_points, &basis_flops));
1797681d0ea7SJeremy L Thompson         CeedCall(CeedBasisDestroy(&basis));
17986e15d496SJeremy L Thompson         *flops += basis_flops * num_elem;
17996e15d496SJeremy L Thompson       }
1800681d0ea7SJeremy L Thompson       CeedCall(CeedVectorDestroy(&vec));
18016e15d496SJeremy L Thompson     }
18026e15d496SJeremy L Thompson     // QF FLOPs
18031c66c397SJeremy L Thompson     {
18049d36ca50SJeremy L Thompson       CeedInt       num_qpts;
18059d36ca50SJeremy L Thompson       CeedSize      qf_flops;
18061203703bSJeremy L Thompson       CeedQFunction qf;
18071c66c397SJeremy L Thompson 
18083f919cbcSJeremy L Thompson       if (is_at_points) num_qpts = num_points;
18093f919cbcSJeremy L Thompson       else CeedCall(CeedOperatorGetNumQuadraturePoints(op, &num_qpts));
18101203703bSJeremy L Thompson       CeedCall(CeedOperatorGetQFunction(op, &qf));
18111203703bSJeremy L Thompson       CeedCall(CeedQFunctionGetFlopsEstimate(qf, &qf_flops));
1812c11e12f4SJeremy L Thompson       CeedCall(CeedQFunctionDestroy(&qf));
18136e536b99SJeremy L Thompson       CeedCheck(qf_flops > -1, CeedOperatorReturnCeed(op), CEED_ERROR_INCOMPLETE,
18146e536b99SJeremy L Thompson                 "Must set CeedQFunction FLOPs estimate with CeedQFunctionSetUserFlopsEstimate");
18156e15d496SJeremy L Thompson       *flops += num_elem * num_qpts * qf_flops;
18161c66c397SJeremy L Thompson     }
18171c66c397SJeremy L Thompson 
18186e15d496SJeremy L Thompson     // Output FLOPs
18196e15d496SJeremy L Thompson     for (CeedInt i = 0; i < num_output_fields; i++) {
18201203703bSJeremy L Thompson       CeedVector vec;
18216e15d496SJeremy L Thompson 
18221203703bSJeremy L Thompson       CeedCall(CeedOperatorFieldGetVector(op_output_fields[i], &vec));
18231203703bSJeremy L Thompson       if (vec == CEED_VECTOR_ACTIVE) {
18241203703bSJeremy L Thompson         CeedEvalMode        eval_mode;
18251203703bSJeremy L Thompson         CeedSize            rstr_flops, basis_flops;
18261203703bSJeremy L Thompson         CeedElemRestriction rstr;
18271203703bSJeremy L Thompson         CeedBasis           basis;
18281203703bSJeremy L Thompson 
18291203703bSJeremy L Thompson         CeedCall(CeedOperatorFieldGetElemRestriction(op_output_fields[i], &rstr));
18301203703bSJeremy L Thompson         CeedCall(CeedElemRestrictionGetFlopsEstimate(rstr, CEED_TRANSPOSE, &rstr_flops));
1831681d0ea7SJeremy L Thompson         CeedCall(CeedElemRestrictionDestroy(&rstr));
1832edb2538eSJeremy L Thompson         *flops += rstr_flops;
18331203703bSJeremy L Thompson         CeedCall(CeedOperatorFieldGetBasis(op_output_fields[i], &basis));
18341203703bSJeremy L Thompson         CeedCall(CeedQFunctionFieldGetEvalMode(qf_output_fields[i], &eval_mode));
18353f919cbcSJeremy L Thompson         CeedCall(CeedBasisGetFlopsEstimate(basis, CEED_TRANSPOSE, eval_mode, is_at_points, num_points, &basis_flops));
1836681d0ea7SJeremy L Thompson         CeedCall(CeedBasisDestroy(&basis));
18376e15d496SJeremy L Thompson         *flops += basis_flops * num_elem;
18386e15d496SJeremy L Thompson       }
1839681d0ea7SJeremy L Thompson       CeedCall(CeedVectorDestroy(&vec));
18406e15d496SJeremy L Thompson     }
18416e15d496SJeremy L Thompson   }
18426e15d496SJeremy L Thompson   return CEED_ERROR_SUCCESS;
18436e15d496SJeremy L Thompson }
18446e15d496SJeremy L Thompson 
18456e15d496SJeremy L Thompson /**
1846ca94c3ddSJeremy L Thompson   @brief Get `CeedQFunction` global context for a `CeedOperator`.
18479fd66db6SSebastian Grimberg 
1848ca94c3ddSJeremy L Thompson   The caller is responsible for destroying `ctx` returned from this function via @ref CeedQFunctionContextDestroy().
1849512bb800SJeremy L Thompson 
1850ca94c3ddSJeremy L Thompson   Note: If the value of `ctx` passed into this function is non-`NULL`, then it is assumed that `ctx` is a pointer to a `CeedQFunctionContext`.
1851ca94c3ddSJeremy L Thompson         This `CeedQFunctionContext` will be destroyed if `ctx` is the only reference to this `CeedQFunctionContext`.
18520126412dSJeremy L Thompson 
1853ca94c3ddSJeremy L Thompson   @param[in]  op  `CeedOperator`
1854ca94c3ddSJeremy L Thompson   @param[out] ctx Variable to store `CeedQFunctionContext`
18550126412dSJeremy L Thompson 
18560126412dSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
18570126412dSJeremy L Thompson 
1858859c15bbSJames Wright   @ref Advanced
18590126412dSJeremy L Thompson **/
18600126412dSJeremy L Thompson int CeedOperatorGetContext(CeedOperator op, CeedQFunctionContext *ctx) {
18611203703bSJeremy L Thompson   bool                 is_composite;
18621203703bSJeremy L Thompson   CeedQFunction        qf;
18631203703bSJeremy L Thompson   CeedQFunctionContext qf_ctx;
18641203703bSJeremy L Thompson 
18651203703bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
18666e536b99SJeremy L Thompson   CeedCheck(!is_composite, CeedOperatorReturnCeed(op), CEED_ERROR_INCOMPATIBLE, "Cannot retrieve CeedQFunctionContext for composite operator");
18671203703bSJeremy L Thompson   CeedCall(CeedOperatorGetQFunction(op, &qf));
18681203703bSJeremy L Thompson   CeedCall(CeedQFunctionGetInnerContext(qf, &qf_ctx));
1869c11e12f4SJeremy L Thompson   CeedCall(CeedQFunctionDestroy(&qf));
18701485364cSJeremy L Thompson   *ctx = NULL;
18711203703bSJeremy L Thompson   if (qf_ctx) CeedCall(CeedQFunctionContextReferenceCopy(qf_ctx, ctx));
18720126412dSJeremy L Thompson   return CEED_ERROR_SUCCESS;
18730126412dSJeremy L Thompson }
18740126412dSJeremy L Thompson 
18750126412dSJeremy L Thompson /**
1876ca94c3ddSJeremy L Thompson   @brief Get label for a registered `CeedQFunctionContext` field, or `NULL` if no field has been registered with this `field_name`.
18773668ca4bSJeremy L Thompson 
1878ca94c3ddSJeremy L Thompson   Fields are registered via `CeedQFunctionContextRegister*()` functions (eg. @ref CeedQFunctionContextRegisterDouble()).
1879859c15bbSJames Wright 
1880ca94c3ddSJeremy L Thompson   @param[in]  op          `CeedOperator`
18813668ca4bSJeremy L Thompson   @param[in]  field_name  Name of field to retrieve label
18823668ca4bSJeremy L Thompson   @param[out] field_label Variable to field label
18833668ca4bSJeremy L Thompson 
18843668ca4bSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
18853668ca4bSJeremy L Thompson 
18863668ca4bSJeremy L Thompson   @ref User
18873668ca4bSJeremy L Thompson **/
188817b0d5c6SJeremy L Thompson int CeedOperatorGetContextFieldLabel(CeedOperator op, const char *field_name, CeedContextFieldLabel *field_label) {
18891c66c397SJeremy L Thompson   bool is_composite, field_found = false;
18901c66c397SJeremy L Thompson 
18912b730f8bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
18922b730f8bSJeremy L Thompson 
18933668ca4bSJeremy L Thompson   if (is_composite) {
1894a98a090bSJeremy L Thompson     // Composite operator
1895a98a090bSJeremy L Thompson     // -- Check if composite label already created
18963668ca4bSJeremy L Thompson     for (CeedInt i = 0; i < op->num_context_labels; i++) {
18973668ca4bSJeremy L Thompson       if (!strcmp(op->context_labels[i]->name, field_name)) {
18983668ca4bSJeremy L Thompson         *field_label = op->context_labels[i];
18993668ca4bSJeremy L Thompson         return CEED_ERROR_SUCCESS;
19003668ca4bSJeremy L Thompson       }
19013668ca4bSJeremy L Thompson     }
19023668ca4bSJeremy L Thompson 
1903a98a090bSJeremy L Thompson     // -- Create composite label if needed
19043668ca4bSJeremy L Thompson     CeedInt               num_sub;
19053668ca4bSJeremy L Thompson     CeedOperator         *sub_operators;
19063668ca4bSJeremy L Thompson     CeedContextFieldLabel new_field_label;
19073668ca4bSJeremy L Thompson 
19082b730f8bSJeremy L Thompson     CeedCall(CeedCalloc(1, &new_field_label));
1909*ed094490SJeremy L Thompson     CeedCall(CeedOperatorCompositeGetNumSub(op, &num_sub));
1910*ed094490SJeremy L Thompson     CeedCall(CeedOperatorCompositeGetSubList(op, &sub_operators));
19112b730f8bSJeremy L Thompson     CeedCall(CeedCalloc(num_sub, &new_field_label->sub_labels));
19123668ca4bSJeremy L Thompson     new_field_label->num_sub_labels = num_sub;
19133668ca4bSJeremy L Thompson 
19143668ca4bSJeremy L Thompson     for (CeedInt i = 0; i < num_sub; i++) {
19153668ca4bSJeremy L Thompson       if (sub_operators[i]->qf->ctx) {
19163668ca4bSJeremy L Thompson         CeedContextFieldLabel new_field_label_i;
19171c66c397SJeremy L Thompson 
19182b730f8bSJeremy L Thompson         CeedCall(CeedQFunctionContextGetFieldLabel(sub_operators[i]->qf->ctx, field_name, &new_field_label_i));
19193668ca4bSJeremy L Thompson         if (new_field_label_i) {
1920a98a090bSJeremy L Thompson           field_found                    = true;
19213668ca4bSJeremy L Thompson           new_field_label->sub_labels[i] = new_field_label_i;
19223668ca4bSJeremy L Thompson           new_field_label->name          = new_field_label_i->name;
19233668ca4bSJeremy L Thompson           new_field_label->description   = new_field_label_i->description;
19242b730f8bSJeremy L Thompson           if (new_field_label->type && new_field_label->type != new_field_label_i->type) {
19257bfe0f0eSJeremy L Thompson             // LCOV_EXCL_START
19262b730f8bSJeremy L Thompson             CeedCall(CeedFree(&new_field_label));
19276e536b99SJeremy L Thompson             return CeedError(CeedOperatorReturnCeed(op), CEED_ERROR_INCOMPATIBLE, "Incompatible field types on sub-operator contexts. %s != %s",
19282b730f8bSJeremy L Thompson                              CeedContextFieldTypes[new_field_label->type], CeedContextFieldTypes[new_field_label_i->type]);
19297bfe0f0eSJeremy L Thompson             // LCOV_EXCL_STOP
19307bfe0f0eSJeremy L Thompson           } else {
19317bfe0f0eSJeremy L Thompson             new_field_label->type = new_field_label_i->type;
19327bfe0f0eSJeremy L Thompson           }
19332b730f8bSJeremy L Thompson           if (new_field_label->num_values != 0 && new_field_label->num_values != new_field_label_i->num_values) {
19347bfe0f0eSJeremy L Thompson             // LCOV_EXCL_START
19352b730f8bSJeremy L Thompson             CeedCall(CeedFree(&new_field_label));
19366e536b99SJeremy L Thompson             return CeedError(CeedOperatorReturnCeed(op), CEED_ERROR_INCOMPATIBLE,
19376e536b99SJeremy L Thompson                              "Incompatible field number of values on sub-operator contexts. %zu != %zu", new_field_label->num_values,
19386e536b99SJeremy L Thompson                              new_field_label_i->num_values);
19397bfe0f0eSJeremy L Thompson             // LCOV_EXCL_STOP
19407bfe0f0eSJeremy L Thompson           } else {
19417bfe0f0eSJeremy L Thompson             new_field_label->num_values = new_field_label_i->num_values;
19427bfe0f0eSJeremy L Thompson           }
19433668ca4bSJeremy L Thompson         }
19443668ca4bSJeremy L Thompson       }
19453668ca4bSJeremy L Thompson     }
1946a98a090bSJeremy L Thompson     // -- Cleanup if field was found
1947a98a090bSJeremy L Thompson     if (field_found) {
1948a98a090bSJeremy L Thompson       *field_label = new_field_label;
1949a98a090bSJeremy L Thompson     } else {
19503668ca4bSJeremy L Thompson       // LCOV_EXCL_START
19512b730f8bSJeremy L Thompson       CeedCall(CeedFree(&new_field_label->sub_labels));
19522b730f8bSJeremy L Thompson       CeedCall(CeedFree(&new_field_label));
19533668ca4bSJeremy L Thompson       *field_label = NULL;
19543668ca4bSJeremy L Thompson       // LCOV_EXCL_STOP
19555ac9af79SJeremy L Thompson     }
19565ac9af79SJeremy L Thompson   } else {
19571203703bSJeremy L Thompson     CeedQFunction        qf;
19581203703bSJeremy L Thompson     CeedQFunctionContext ctx;
19591203703bSJeremy L Thompson 
1960a98a090bSJeremy L Thompson     // Single, non-composite operator
19611203703bSJeremy L Thompson     CeedCall(CeedOperatorGetQFunction(op, &qf));
19621203703bSJeremy L Thompson     CeedCall(CeedQFunctionGetInnerContext(qf, &ctx));
1963c11e12f4SJeremy L Thompson     CeedCall(CeedQFunctionDestroy(&qf));
19641203703bSJeremy L Thompson     if (ctx) {
19651203703bSJeremy L Thompson       CeedCall(CeedQFunctionContextGetFieldLabel(ctx, field_name, field_label));
1966a98a090bSJeremy L Thompson     } else {
1967a98a090bSJeremy L Thompson       *field_label = NULL;
1968a98a090bSJeremy L Thompson     }
19695ac9af79SJeremy L Thompson   }
19705ac9af79SJeremy L Thompson 
19715ac9af79SJeremy L Thompson   // Set label in operator
19725ac9af79SJeremy L Thompson   if (*field_label) {
19735ac9af79SJeremy L Thompson     (*field_label)->from_op = true;
19745ac9af79SJeremy L Thompson 
19753668ca4bSJeremy L Thompson     // Move new composite label to operator
19763668ca4bSJeremy L Thompson     if (op->num_context_labels == 0) {
19772b730f8bSJeremy L Thompson       CeedCall(CeedCalloc(1, &op->context_labels));
19783668ca4bSJeremy L Thompson       op->max_context_labels = 1;
19793668ca4bSJeremy L Thompson     } else if (op->num_context_labels == op->max_context_labels) {
19802b730f8bSJeremy L Thompson       CeedCall(CeedRealloc(2 * op->num_context_labels, &op->context_labels));
19813668ca4bSJeremy L Thompson       op->max_context_labels *= 2;
19823668ca4bSJeremy L Thompson     }
19835ac9af79SJeremy L Thompson     op->context_labels[op->num_context_labels] = *field_label;
19843668ca4bSJeremy L Thompson     op->num_context_labels++;
19853668ca4bSJeremy L Thompson   }
19863668ca4bSJeremy L Thompson   return CEED_ERROR_SUCCESS;
19873668ca4bSJeremy L Thompson }
19883668ca4bSJeremy L Thompson 
19893668ca4bSJeremy L Thompson /**
1990ca94c3ddSJeremy L Thompson   @brief Set `CeedQFunctionContext` field holding double precision values.
19914385fb7fSSebastian Grimberg 
1992ca94c3ddSJeremy L Thompson   For composite operators, the values are set in all sub-operator `CeedQFunctionContext` that have a matching `field_name`.
1993d8dd9a91SJeremy L Thompson 
1994ca94c3ddSJeremy L Thompson   @param[in,out] op          `CeedOperator`
19952788fa27SJeremy L Thompson   @param[in]     field_label Label of field to set
1996ea61e9acSJeremy L Thompson   @param[in]     values      Values to set
1997d8dd9a91SJeremy L Thompson 
1998d8dd9a91SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1999d8dd9a91SJeremy L Thompson 
2000d8dd9a91SJeremy L Thompson   @ref User
2001d8dd9a91SJeremy L Thompson **/
200217b0d5c6SJeremy L Thompson int CeedOperatorSetContextDouble(CeedOperator op, CeedContextFieldLabel field_label, double *values) {
20032b730f8bSJeremy L Thompson   return CeedOperatorContextSetGeneric(op, field_label, CEED_CONTEXT_FIELD_DOUBLE, values);
2004d8dd9a91SJeremy L Thompson }
2005d8dd9a91SJeremy L Thompson 
2006d8dd9a91SJeremy L Thompson /**
2007ca94c3ddSJeremy L Thompson   @brief Get `CeedQFunctionContext` field holding double precision values, read-only.
20084385fb7fSSebastian Grimberg 
2009ca94c3ddSJeremy L Thompson   For composite operators, the values correspond to the first sub-operator `CeedQFunctionContext` that has a matching `field_name`.
20102788fa27SJeremy L Thompson 
2011ca94c3ddSJeremy L Thompson   @param[in]  op          `CeedOperator`
20122788fa27SJeremy L Thompson   @param[in]  field_label Label of field to get
20132788fa27SJeremy L Thompson   @param[out] num_values  Number of values in the field label
20142788fa27SJeremy L Thompson   @param[out] values      Pointer to context values
20152788fa27SJeremy L Thompson 
20162788fa27SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
20172788fa27SJeremy L Thompson 
20182788fa27SJeremy L Thompson   @ref User
20192788fa27SJeremy L Thompson **/
202017b0d5c6SJeremy L Thompson int CeedOperatorGetContextDoubleRead(CeedOperator op, CeedContextFieldLabel field_label, size_t *num_values, const double **values) {
20212788fa27SJeremy L Thompson   return CeedOperatorContextGetGenericRead(op, field_label, CEED_CONTEXT_FIELD_DOUBLE, num_values, values);
20222788fa27SJeremy L Thompson }
20232788fa27SJeremy L Thompson 
20242788fa27SJeremy L Thompson /**
2025ca94c3ddSJeremy L Thompson   @brief Restore `CeedQFunctionContext` field holding double precision values, read-only.
20262788fa27SJeremy L Thompson 
2027ca94c3ddSJeremy L Thompson   @param[in]  op          `CeedOperator`
20282788fa27SJeremy L Thompson   @param[in]  field_label Label of field to restore
20292788fa27SJeremy L Thompson   @param[out] values      Pointer to context values
20302788fa27SJeremy L Thompson 
20312788fa27SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
20322788fa27SJeremy L Thompson 
20332788fa27SJeremy L Thompson   @ref User
20342788fa27SJeremy L Thompson **/
203517b0d5c6SJeremy L Thompson int CeedOperatorRestoreContextDoubleRead(CeedOperator op, CeedContextFieldLabel field_label, const double **values) {
20362788fa27SJeremy L Thompson   return CeedOperatorContextRestoreGenericRead(op, field_label, CEED_CONTEXT_FIELD_DOUBLE, values);
20372788fa27SJeremy L Thompson }
20382788fa27SJeremy L Thompson 
20392788fa27SJeremy L Thompson /**
2040ca94c3ddSJeremy L Thompson   @brief Set `CeedQFunctionContext` field holding `int32` values.
20414385fb7fSSebastian Grimberg 
2042ca94c3ddSJeremy L Thompson   For composite operators, the values are set in all sub-operator `CeedQFunctionContext` that have a matching `field_name`.
2043d8dd9a91SJeremy L Thompson 
2044ca94c3ddSJeremy L Thompson   @param[in,out] op          `CeedOperator`
2045ea61e9acSJeremy L Thompson   @param[in]     field_label Label of field to set
2046ea61e9acSJeremy L Thompson   @param[in]     values      Values to set
2047d8dd9a91SJeremy L Thompson 
2048d8dd9a91SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
2049d8dd9a91SJeremy L Thompson 
2050d8dd9a91SJeremy L Thompson   @ref User
2051d8dd9a91SJeremy L Thompson **/
205223dbfd29SJeremy L Thompson int CeedOperatorSetContextInt32(CeedOperator op, CeedContextFieldLabel field_label, int32_t *values) {
20532b730f8bSJeremy L Thompson   return CeedOperatorContextSetGeneric(op, field_label, CEED_CONTEXT_FIELD_INT32, values);
2054d8dd9a91SJeremy L Thompson }
2055d8dd9a91SJeremy L Thompson 
2056d8dd9a91SJeremy L Thompson /**
2057ca94c3ddSJeremy L Thompson   @brief Get `CeedQFunctionContext` field holding `int32` values, read-only.
20584385fb7fSSebastian Grimberg 
2059ca94c3ddSJeremy L Thompson   For composite operators, the values correspond to the first sub-operator `CeedQFunctionContext` that has a matching `field_name`.
20602788fa27SJeremy L Thompson 
2061ca94c3ddSJeremy L Thompson   @param[in]  op          `CeedOperator`
20622788fa27SJeremy L Thompson   @param[in]  field_label Label of field to get
2063ca94c3ddSJeremy L Thompson   @param[out] num_values  Number of `int32` values in `values`
20642788fa27SJeremy L Thompson   @param[out] values      Pointer to context values
20652788fa27SJeremy L Thompson 
20662788fa27SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
20672788fa27SJeremy L Thompson 
20682788fa27SJeremy L Thompson   @ref User
20692788fa27SJeremy L Thompson **/
207023dbfd29SJeremy L Thompson int CeedOperatorGetContextInt32Read(CeedOperator op, CeedContextFieldLabel field_label, size_t *num_values, const int32_t **values) {
20712788fa27SJeremy L Thompson   return CeedOperatorContextGetGenericRead(op, field_label, CEED_CONTEXT_FIELD_INT32, num_values, values);
20722788fa27SJeremy L Thompson }
20732788fa27SJeremy L Thompson 
20742788fa27SJeremy L Thompson /**
2075ca94c3ddSJeremy L Thompson   @brief Restore `CeedQFunctionContext` field holding `int32` values, read-only.
20762788fa27SJeremy L Thompson 
2077ca94c3ddSJeremy L Thompson   @param[in]  op          `CeedOperator`
20782788fa27SJeremy L Thompson   @param[in]  field_label Label of field to get
20792788fa27SJeremy L Thompson   @param[out] values      Pointer to context values
20802788fa27SJeremy L Thompson 
20812788fa27SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
20822788fa27SJeremy L Thompson 
20832788fa27SJeremy L Thompson   @ref User
20842788fa27SJeremy L Thompson **/
208523dbfd29SJeremy L Thompson int CeedOperatorRestoreContextInt32Read(CeedOperator op, CeedContextFieldLabel field_label, const int32_t **values) {
20862788fa27SJeremy L Thompson   return CeedOperatorContextRestoreGenericRead(op, field_label, CEED_CONTEXT_FIELD_INT32, values);
20872788fa27SJeremy L Thompson }
20882788fa27SJeremy L Thompson 
20892788fa27SJeremy L Thompson /**
2090ca94c3ddSJeremy L Thompson   @brief Set `CeedQFunctionContext` field holding boolean values.
20915b6ec284SJeremy L Thompson 
2092ca94c3ddSJeremy L Thompson   For composite operators, the values are set in all sub-operator `CeedQFunctionContext` that have a matching `field_name`.
20935b6ec284SJeremy L Thompson 
2094ca94c3ddSJeremy L Thompson   @param[in,out] op          `CeedOperator`
20955b6ec284SJeremy L Thompson   @param[in]     field_label Label of field to set
20965b6ec284SJeremy L Thompson   @param[in]     values      Values to set
20975b6ec284SJeremy L Thompson 
20985b6ec284SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
20995b6ec284SJeremy L Thompson 
21005b6ec284SJeremy L Thompson   @ref User
21015b6ec284SJeremy L Thompson **/
21025b6ec284SJeremy L Thompson int CeedOperatorSetContextBoolean(CeedOperator op, CeedContextFieldLabel field_label, bool *values) {
21035b6ec284SJeremy L Thompson   return CeedOperatorContextSetGeneric(op, field_label, CEED_CONTEXT_FIELD_BOOL, values);
21045b6ec284SJeremy L Thompson }
21055b6ec284SJeremy L Thompson 
21065b6ec284SJeremy L Thompson /**
2107ca94c3ddSJeremy L Thompson   @brief Get `CeedQFunctionContext` field holding boolean values, read-only.
21085b6ec284SJeremy L Thompson 
2109ca94c3ddSJeremy L Thompson   For composite operators, the values correspond to the first sub-operator `CeedQFunctionContext` that has a matching `field_name`.
21105b6ec284SJeremy L Thompson 
2111ca94c3ddSJeremy L Thompson   @param[in]  op          `CeedOperator`
21125b6ec284SJeremy L Thompson   @param[in]  field_label Label of field to get
2113ca94c3ddSJeremy L Thompson   @param[out] num_values  Number of boolean values in `values`
21145b6ec284SJeremy L Thompson   @param[out] values      Pointer to context values
21155b6ec284SJeremy L Thompson 
21165b6ec284SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
21175b6ec284SJeremy L Thompson 
21185b6ec284SJeremy L Thompson   @ref User
21195b6ec284SJeremy L Thompson **/
21205b6ec284SJeremy L Thompson int CeedOperatorGetContextBooleanRead(CeedOperator op, CeedContextFieldLabel field_label, size_t *num_values, const bool **values) {
21215b6ec284SJeremy L Thompson   return CeedOperatorContextGetGenericRead(op, field_label, CEED_CONTEXT_FIELD_BOOL, num_values, values);
21225b6ec284SJeremy L Thompson }
21235b6ec284SJeremy L Thompson 
21245b6ec284SJeremy L Thompson /**
2125ca94c3ddSJeremy L Thompson   @brief Restore `CeedQFunctionContext` field holding boolean values, read-only.
21265b6ec284SJeremy L Thompson 
2127ca94c3ddSJeremy L Thompson   @param[in]  op          `CeedOperator`
21285b6ec284SJeremy L Thompson   @param[in]  field_label Label of field to get
21295b6ec284SJeremy L Thompson   @param[out] values      Pointer to context values
21305b6ec284SJeremy L Thompson 
21315b6ec284SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
21325b6ec284SJeremy L Thompson 
21335b6ec284SJeremy L Thompson   @ref User
21345b6ec284SJeremy L Thompson **/
21355b6ec284SJeremy L Thompson int CeedOperatorRestoreContextBooleanRead(CeedOperator op, CeedContextFieldLabel field_label, const bool **values) {
21365b6ec284SJeremy L Thompson   return CeedOperatorContextRestoreGenericRead(op, field_label, CEED_CONTEXT_FIELD_BOOL, values);
21375b6ec284SJeremy L Thompson }
21385b6ec284SJeremy L Thompson 
21395b6ec284SJeremy L Thompson /**
2140ca94c3ddSJeremy L Thompson   @brief Apply `CeedOperator` to a `CeedVector`.
2141d7b241e6Sjeremylt 
2142ea61e9acSJeremy L Thompson   This computes the action of the operator on the specified (active) input, yielding its (active) output.
2143ca94c3ddSJeremy L Thompson   All inputs and outputs must be specified using @ref CeedOperatorSetField().
2144d7b241e6Sjeremylt 
21455da5ab9fSZach Atkins   @note Calling this function asserts that setup is complete and sets the `CeedOperator` as immutable.
2146f04ea552SJeremy L Thompson 
2147ca94c3ddSJeremy L Thompson   @param[in]  op      `CeedOperator` to apply
2148ca94c3ddSJeremy L Thompson   @param[in]  in      `CeedVector` containing input state or @ref CEED_VECTOR_NONE if there are no active inputs
2149ca94c3ddSJeremy L Thompson   @param[out] out     `CeedVector` to store result of applying operator (must be distinct from `in`) or @ref CEED_VECTOR_NONE if there are no active outputs
2150ca94c3ddSJeremy L Thompson   @param[in]  request Address of @ref CeedRequest for non-blocking completion, else @ref CEED_REQUEST_IMMEDIATE
2151b11c1e72Sjeremylt 
2152b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
2153dfdf5a53Sjeremylt 
21547a982d89SJeremy L. Thompson   @ref User
2155b11c1e72Sjeremylt **/
21562b730f8bSJeremy L Thompson int CeedOperatorApply(CeedOperator op, CeedVector in, CeedVector out, CeedRequest *request) {
21571203703bSJeremy L Thompson   bool is_composite;
21581203703bSJeremy L Thompson 
21592b730f8bSJeremy L Thompson   CeedCall(CeedOperatorCheckReady(op));
2160d7b241e6Sjeremylt 
21611203703bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
21620db52efcSZach Atkins   if (is_composite && op->ApplyComposite) {
2163250756a7Sjeremylt     // Composite Operator
21642b730f8bSJeremy L Thompson     CeedCall(op->ApplyComposite(op, in, out, request));
21650db52efcSZach Atkins   } else if (!is_composite && op->Apply) {
21663ca2b39bSJeremy L Thompson     // Standard Operator
21673ca2b39bSJeremy L Thompson     CeedCall(op->Apply(op, in, out, request));
21683ca2b39bSJeremy L Thompson   } else {
21690db52efcSZach Atkins     // Standard or composite, default to zeroing out and calling ApplyAddActive
21700db52efcSZach Atkins     // Zero active output
21710db52efcSZach Atkins     if (out != CEED_VECTOR_NONE) CeedCall(CeedVectorSetValue(out, 0.0));
21721203703bSJeremy L Thompson 
21730db52efcSZach Atkins     // ApplyAddActive
21740db52efcSZach Atkins     CeedCall(CeedOperatorApplyAddActive(op, in, out, request));
2175250756a7Sjeremylt   }
2176e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2177cae8b89aSjeremylt }
2178cae8b89aSjeremylt 
2179cae8b89aSjeremylt /**
2180ca94c3ddSJeremy L Thompson   @brief Apply `CeedOperator` to a `CeedVector` and add result to output `CeedVector`.
2181cae8b89aSjeremylt 
2182ea61e9acSJeremy L Thompson   This computes the action of the operator on the specified (active) input, yielding its (active) output.
2183ca94c3ddSJeremy L Thompson   All inputs and outputs must be specified using @ref CeedOperatorSetField().
2184cae8b89aSjeremylt 
21855da5ab9fSZach Atkins   @note Calling this function asserts that setup is complete and sets the `CeedOperator` as immutable.
21865da5ab9fSZach Atkins   @warning This function adds into ALL outputs, including passive outputs. To only add into the active output, use `CeedOperatorApplyAddActive()`.
21875da5ab9fSZach Atkins   @see `CeedOperatorApplyAddActive()`
21885da5ab9fSZach Atkins 
2189ca94c3ddSJeremy L Thompson   @param[in]  op      `CeedOperator` to apply
2190ca94c3ddSJeremy L Thompson   @param[in]  in      `CeedVector` containing input state or @ref CEED_VECTOR_NONE if there are no active inputs
2191ca94c3ddSJeremy L Thompson   @param[out] out     `CeedVector` to sum in result of applying operator (must be distinct from `in`) or @ref CEED_VECTOR_NONE if there are no active outputs
2192ca94c3ddSJeremy L Thompson   @param[in]  request Address of @ref CeedRequest for non-blocking completion, else @ref CEED_REQUEST_IMMEDIATE
2193cae8b89aSjeremylt 
2194cae8b89aSjeremylt   @return An error code: 0 - success, otherwise - failure
2195cae8b89aSjeremylt 
21967a982d89SJeremy L. Thompson   @ref User
2197cae8b89aSjeremylt **/
21982b730f8bSJeremy L Thompson int CeedOperatorApplyAdd(CeedOperator op, CeedVector in, CeedVector out, CeedRequest *request) {
21991203703bSJeremy L Thompson   bool is_composite;
22001203703bSJeremy L Thompson 
22012b730f8bSJeremy L Thompson   CeedCall(CeedOperatorCheckReady(op));
2202cae8b89aSjeremylt 
22031203703bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
22041203703bSJeremy L Thompson   if (is_composite) {
2205250756a7Sjeremylt     // Composite Operator
2206250756a7Sjeremylt     if (op->ApplyAddComposite) {
22072b730f8bSJeremy L Thompson       CeedCall(op->ApplyAddComposite(op, in, out, request));
2208cae8b89aSjeremylt     } else {
2209d1d35e2fSjeremylt       CeedInt       num_suboperators;
2210d1d35e2fSjeremylt       CeedOperator *sub_operators;
2211250756a7Sjeremylt 
2212*ed094490SJeremy L Thompson       CeedCall(CeedOperatorCompositeGetNumSub(op, &num_suboperators));
2213*ed094490SJeremy L Thompson       CeedCall(CeedOperatorCompositeGetSubList(op, &sub_operators));
2214d1d35e2fSjeremylt       for (CeedInt i = 0; i < num_suboperators; i++) {
22152b730f8bSJeremy L Thompson         CeedCall(CeedOperatorApplyAdd(sub_operators[i], in, out, request));
22161d7d2407SJeremy L Thompson       }
2217250756a7Sjeremylt     }
22181203703bSJeremy L Thompson   } else if (op->num_elem > 0) {
22193ca2b39bSJeremy L Thompson     // Standard Operator
22203ca2b39bSJeremy L Thompson     CeedCall(op->ApplyAdd(op, in, out, request));
2221250756a7Sjeremylt   }
2222e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2223d7b241e6Sjeremylt }
2224d7b241e6Sjeremylt 
2225d7b241e6Sjeremylt /**
22265da5ab9fSZach Atkins   @brief Apply `CeedOperator` to a `CeedVector` and add result to output `CeedVector`. Only sums into active outputs, overwrites passive outputs.
22275da5ab9fSZach Atkins 
22285da5ab9fSZach Atkins   This computes the action of the operator on the specified (active) input, yielding its (active) output.
22295da5ab9fSZach Atkins   All inputs and outputs must be specified using @ref CeedOperatorSetField().
22305da5ab9fSZach Atkins 
22315da5ab9fSZach Atkins   @note Calling this function asserts that setup is complete and sets the `CeedOperator` as immutable.
22325da5ab9fSZach Atkins 
22335da5ab9fSZach Atkins   @param[in]  op      `CeedOperator` to apply
22345da5ab9fSZach Atkins   @param[in]  in      `CeedVector` containing input state or @ref CEED_VECTOR_NONE if there are no active inputs
22355da5ab9fSZach Atkins   @param[out] out     `CeedVector` to sum in result of applying operator (must be distinct from `in`) or @ref CEED_VECTOR_NONE if there are no active outputs
22365da5ab9fSZach Atkins   @param[in]  request Address of @ref CeedRequest for non-blocking completion, else @ref CEED_REQUEST_IMMEDIATE
22375da5ab9fSZach Atkins 
22385da5ab9fSZach Atkins   @return An error code: 0 - success, otherwise - failure
22395da5ab9fSZach Atkins 
22405da5ab9fSZach Atkins   @ref User
22415da5ab9fSZach Atkins **/
22425da5ab9fSZach Atkins int CeedOperatorApplyAddActive(CeedOperator op, CeedVector in, CeedVector out, CeedRequest *request) {
22435da5ab9fSZach Atkins   bool is_composite;
22445da5ab9fSZach Atkins 
22455da5ab9fSZach Atkins   CeedCall(CeedOperatorCheckReady(op));
22465da5ab9fSZach Atkins 
22475da5ab9fSZach Atkins   CeedCall(CeedOperatorIsComposite(op, &is_composite));
22485da5ab9fSZach Atkins   if (is_composite) {
22495da5ab9fSZach Atkins     // Composite Operator
22505da5ab9fSZach Atkins     CeedInt       num_suboperators;
22515da5ab9fSZach Atkins     CeedOperator *sub_operators;
22525da5ab9fSZach Atkins 
2253*ed094490SJeremy L Thompson     CeedCall(CeedOperatorCompositeGetNumSub(op, &num_suboperators));
2254*ed094490SJeremy L Thompson     CeedCall(CeedOperatorCompositeGetSubList(op, &sub_operators));
22555da5ab9fSZach Atkins 
22565da5ab9fSZach Atkins     // Zero all output vectors
22575da5ab9fSZach Atkins     for (CeedInt i = 0; i < num_suboperators; i++) {
22585da5ab9fSZach Atkins       CeedInt            num_output_fields;
22595da5ab9fSZach Atkins       CeedOperatorField *output_fields;
22605da5ab9fSZach Atkins 
22615da5ab9fSZach Atkins       CeedCall(CeedOperatorGetFields(sub_operators[i], NULL, NULL, &num_output_fields, &output_fields));
22625da5ab9fSZach Atkins       for (CeedInt j = 0; j < num_output_fields; j++) {
22635da5ab9fSZach Atkins         CeedVector vec;
22645da5ab9fSZach Atkins 
22655da5ab9fSZach Atkins         CeedCall(CeedOperatorFieldGetVector(output_fields[j], &vec));
22665da5ab9fSZach Atkins         if (vec != CEED_VECTOR_ACTIVE && vec != CEED_VECTOR_NONE) CeedCall(CeedVectorSetValue(vec, 0.0));
22675da5ab9fSZach Atkins         CeedCall(CeedVectorDestroy(&vec));
22685da5ab9fSZach Atkins       }
22695da5ab9fSZach Atkins     }
22705da5ab9fSZach Atkins     // ApplyAdd
22715da5ab9fSZach Atkins     CeedCall(CeedOperatorApplyAdd(op, in, out, request));
22725da5ab9fSZach Atkins   } else {
22735da5ab9fSZach Atkins     // Standard Operator
22745da5ab9fSZach Atkins     CeedInt            num_output_fields;
22755da5ab9fSZach Atkins     CeedOperatorField *output_fields;
22765da5ab9fSZach Atkins 
22775da5ab9fSZach Atkins     CeedCall(CeedOperatorGetFields(op, NULL, NULL, &num_output_fields, &output_fields));
22785da5ab9fSZach Atkins     // Zero all output vectors
22795da5ab9fSZach Atkins     for (CeedInt i = 0; i < num_output_fields; i++) {
22805da5ab9fSZach Atkins       CeedVector vec;
22815da5ab9fSZach Atkins 
22825da5ab9fSZach Atkins       CeedCall(CeedOperatorFieldGetVector(output_fields[i], &vec));
22835da5ab9fSZach Atkins       if (vec != CEED_VECTOR_ACTIVE && vec != CEED_VECTOR_NONE) CeedCall(CeedVectorSetValue(vec, 0.0));
22845da5ab9fSZach Atkins       CeedCall(CeedVectorDestroy(&vec));
22855da5ab9fSZach Atkins     }
22865da5ab9fSZach Atkins     // ApplyAdd
22875da5ab9fSZach Atkins     CeedCall(CeedOperatorApplyAdd(op, in, out, request));
22885da5ab9fSZach Atkins   }
22895da5ab9fSZach Atkins   return CEED_ERROR_SUCCESS;
22905da5ab9fSZach Atkins }
22915da5ab9fSZach Atkins 
22925da5ab9fSZach Atkins /**
2293536b928cSSebastian Grimberg   @brief Destroy temporary assembly data associated with a `CeedOperator`
2294536b928cSSebastian Grimberg 
2295536b928cSSebastian Grimberg   @param[in,out] op `CeedOperator` whose assembly data to destroy
2296536b928cSSebastian Grimberg 
2297536b928cSSebastian Grimberg   @return An error code: 0 - success, otherwise - failure
2298536b928cSSebastian Grimberg 
2299536b928cSSebastian Grimberg   @ref User
2300536b928cSSebastian Grimberg **/
2301536b928cSSebastian Grimberg int CeedOperatorAssemblyDataStrip(CeedOperator op) {
2302536b928cSSebastian Grimberg   bool is_composite;
2303536b928cSSebastian Grimberg 
2304536b928cSSebastian Grimberg   CeedCall(CeedQFunctionAssemblyDataDestroy(&op->qf_assembled));
2305536b928cSSebastian Grimberg   CeedCall(CeedOperatorAssemblyDataDestroy(&op->op_assembled));
2306536b928cSSebastian Grimberg   CeedCall(CeedOperatorIsComposite(op, &is_composite));
2307536b928cSSebastian Grimberg   if (is_composite) {
2308536b928cSSebastian Grimberg     CeedInt       num_suboperators;
2309536b928cSSebastian Grimberg     CeedOperator *sub_operators;
2310536b928cSSebastian Grimberg 
2311*ed094490SJeremy L Thompson     CeedCall(CeedOperatorCompositeGetNumSub(op, &num_suboperators));
2312*ed094490SJeremy L Thompson     CeedCall(CeedOperatorCompositeGetSubList(op, &sub_operators));
2313536b928cSSebastian Grimberg     for (CeedInt i = 0; i < num_suboperators; i++) {
2314536b928cSSebastian Grimberg       CeedCall(CeedQFunctionAssemblyDataDestroy(&sub_operators[i]->qf_assembled));
2315536b928cSSebastian Grimberg       CeedCall(CeedOperatorAssemblyDataDestroy(&sub_operators[i]->op_assembled));
2316536b928cSSebastian Grimberg     }
2317536b928cSSebastian Grimberg   }
2318536b928cSSebastian Grimberg   return CEED_ERROR_SUCCESS;
2319536b928cSSebastian Grimberg }
2320536b928cSSebastian Grimberg 
2321536b928cSSebastian Grimberg /**
2322ca94c3ddSJeremy L Thompson   @brief Destroy a `CeedOperator`
2323d7b241e6Sjeremylt 
2324ca94c3ddSJeremy L Thompson   @param[in,out] op `CeedOperator` to destroy
2325b11c1e72Sjeremylt 
2326b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
2327dfdf5a53Sjeremylt 
23287a982d89SJeremy L. Thompson   @ref User
2329b11c1e72Sjeremylt **/
2330d7b241e6Sjeremylt int CeedOperatorDestroy(CeedOperator *op) {
2331ad6481ceSJeremy L Thompson   if (!*op || --(*op)->ref_count > 0) {
2332ad6481ceSJeremy L Thompson     *op = NULL;
2333ad6481ceSJeremy L Thompson     return CEED_ERROR_SUCCESS;
2334ad6481ceSJeremy L Thompson   }
2335f883f0a5SSebastian Grimberg   // Backend destroy
2336f883f0a5SSebastian Grimberg   if ((*op)->Destroy) {
2337f883f0a5SSebastian Grimberg     CeedCall((*op)->Destroy(*op));
2338f883f0a5SSebastian Grimberg   }
2339fe2413ffSjeremylt   // Free fields
23402b730f8bSJeremy L Thompson   for (CeedInt i = 0; i < (*op)->num_fields; i++) {
2341d1d35e2fSjeremylt     if ((*op)->input_fields[i]) {
2342437c7c90SJeremy L Thompson       if ((*op)->input_fields[i]->elem_rstr != CEED_ELEMRESTRICTION_NONE) {
2343437c7c90SJeremy L Thompson         CeedCall(CeedElemRestrictionDestroy(&(*op)->input_fields[i]->elem_rstr));
234415910d16Sjeremylt       }
2345356036faSJeremy L Thompson       if ((*op)->input_fields[i]->basis != CEED_BASIS_NONE) {
23462b730f8bSJeremy L Thompson         CeedCall(CeedBasisDestroy(&(*op)->input_fields[i]->basis));
234771352a93Sjeremylt       }
23482b730f8bSJeremy L Thompson       if ((*op)->input_fields[i]->vec != CEED_VECTOR_ACTIVE && (*op)->input_fields[i]->vec != CEED_VECTOR_NONE) {
23492b730f8bSJeremy L Thompson         CeedCall(CeedVectorDestroy(&(*op)->input_fields[i]->vec));
235071352a93Sjeremylt       }
23512b730f8bSJeremy L Thompson       CeedCall(CeedFree(&(*op)->input_fields[i]->field_name));
23522b730f8bSJeremy L Thompson       CeedCall(CeedFree(&(*op)->input_fields[i]));
2353fe2413ffSjeremylt     }
23542b730f8bSJeremy L Thompson   }
23552b730f8bSJeremy L Thompson   for (CeedInt i = 0; i < (*op)->num_fields; i++) {
2356d1d35e2fSjeremylt     if ((*op)->output_fields[i]) {
2357437c7c90SJeremy L Thompson       CeedCall(CeedElemRestrictionDestroy(&(*op)->output_fields[i]->elem_rstr));
2358356036faSJeremy L Thompson       if ((*op)->output_fields[i]->basis != CEED_BASIS_NONE) {
23592b730f8bSJeremy L Thompson         CeedCall(CeedBasisDestroy(&(*op)->output_fields[i]->basis));
236071352a93Sjeremylt       }
23612b730f8bSJeremy L Thompson       if ((*op)->output_fields[i]->vec != CEED_VECTOR_ACTIVE && (*op)->output_fields[i]->vec != CEED_VECTOR_NONE) {
23622b730f8bSJeremy L Thompson         CeedCall(CeedVectorDestroy(&(*op)->output_fields[i]->vec));
236371352a93Sjeremylt       }
23642b730f8bSJeremy L Thompson       CeedCall(CeedFree(&(*op)->output_fields[i]->field_name));
23652b730f8bSJeremy L Thompson       CeedCall(CeedFree(&(*op)->output_fields[i]));
23662b730f8bSJeremy L Thompson     }
2367fe2413ffSjeremylt   }
2368f883f0a5SSebastian Grimberg   CeedCall(CeedFree(&(*op)->input_fields));
2369f883f0a5SSebastian Grimberg   CeedCall(CeedFree(&(*op)->output_fields));
2370f883f0a5SSebastian Grimberg   // Destroy AtPoints data
237148acf710SJeremy L Thompson   CeedCall(CeedVectorDestroy(&(*op)->point_coords));
237248acf710SJeremy L Thompson   CeedCall(CeedElemRestrictionDestroy(&(*op)->rstr_points));
237348acf710SJeremy L Thompson   CeedCall(CeedElemRestrictionDestroy(&(*op)->first_points_rstr));
2374c6b536a8SSebastian Grimberg   // Destroy assembly data (must happen before destroying sub_operators)
2375f883f0a5SSebastian Grimberg   CeedCall(CeedOperatorAssemblyDataStrip(*op));
2376d1d35e2fSjeremylt   // Destroy sub_operators
23772b730f8bSJeremy L Thompson   for (CeedInt i = 0; i < (*op)->num_suboperators; i++) {
2378d1d35e2fSjeremylt     if ((*op)->sub_operators[i]) {
23792b730f8bSJeremy L Thompson       CeedCall(CeedOperatorDestroy(&(*op)->sub_operators[i]));
238052d6035fSJeremy L Thompson     }
23812b730f8bSJeremy L Thompson   }
2382f883f0a5SSebastian Grimberg   CeedCall(CeedFree(&(*op)->sub_operators));
23832b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionDestroy(&(*op)->qf));
23842b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionDestroy(&(*op)->dqf));
23852b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionDestroy(&(*op)->dqfT));
23863668ca4bSJeremy L Thompson   // Destroy any composite labels
23875ac9af79SJeremy L Thompson   if ((*op)->is_composite) {
23883668ca4bSJeremy L Thompson     for (CeedInt i = 0; i < (*op)->num_context_labels; i++) {
23892b730f8bSJeremy L Thompson       CeedCall(CeedFree(&(*op)->context_labels[i]->sub_labels));
23902b730f8bSJeremy L Thompson       CeedCall(CeedFree(&(*op)->context_labels[i]));
23913668ca4bSJeremy L Thompson     }
23925ac9af79SJeremy L Thompson   }
23932b730f8bSJeremy L Thompson   CeedCall(CeedFree(&(*op)->context_labels));
2394fe2413ffSjeremylt 
23955107b09fSJeremy L Thompson   // Destroy fallback
23962b730f8bSJeremy L Thompson   CeedCall(CeedOperatorDestroy(&(*op)->op_fallback));
23975107b09fSJeremy L Thompson 
23982b730f8bSJeremy L Thompson   CeedCall(CeedFree(&(*op)->name));
2399f883f0a5SSebastian Grimberg   CeedCall(CeedDestroy(&(*op)->ceed));
24002b730f8bSJeremy L Thompson   CeedCall(CeedFree(op));
2401e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2402d7b241e6Sjeremylt }
2403d7b241e6Sjeremylt 
2404d7b241e6Sjeremylt /// @}
2405