xref: /libCEED/interface/ceed-operator.c (revision 6f8994e97a0b625c3ee237f2816b2aa73d18ec27)
13d8e8822SJeremy L Thompson // Copyright (c) 2017-2022, Lawrence Livermore National Security, LLC and other CEED contributors.
23d8e8822SJeremy L Thompson // All Rights Reserved. See the top-level LICENSE and NOTICE files for details.
3d7b241e6Sjeremylt //
43d8e8822SJeremy L Thompson // SPDX-License-Identifier: BSD-2-Clause
5d7b241e6Sjeremylt //
63d8e8822SJeremy L Thompson // This file is part of CEED:  http://github.com/ceed
7d7b241e6Sjeremylt 
83d576824SJeremy L Thompson #include <ceed-impl.h>
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) {
37*6f8994e9SJeremy 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";
101*6f8994e9SJeremy 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);
121e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1227a982d89SJeremy L. Thompson }
1237a982d89SJeremy L. Thompson 
1247a982d89SJeremy L. Thompson /**
125ca94c3ddSJeremy L Thompson   @brief View a single `CeedOperator`
1267a982d89SJeremy L. Thompson 
127ca94c3ddSJeremy L Thompson   @param[in] op     `CeedOperator` to view
1287a982d89SJeremy L. Thompson   @param[in] sub    Boolean flag for sub-operator
129ca94c3ddSJeremy L Thompson   @param[in] stream Stream to write; typically `stdout` or a file
1307a982d89SJeremy L. Thompson 
1317a982d89SJeremy L. Thompson   @return Error code: 0 - success, otherwise - failure
1327a982d89SJeremy L. Thompson 
1337a982d89SJeremy L. Thompson   @ref Utility
1347a982d89SJeremy L. Thompson **/
1357a982d89SJeremy L. Thompson int CeedOperatorSingleView(CeedOperator op, bool sub, FILE *stream) {
1367a982d89SJeremy L. Thompson   const char         *pre = sub ? "  " : "";
1371203703bSJeremy L Thompson   CeedInt             num_elem, num_qpts, total_fields = 0, num_input_fields, num_output_fields;
1381203703bSJeremy L Thompson   CeedQFunction       qf;
1391203703bSJeremy L Thompson   CeedQFunctionField *qf_input_fields, *qf_output_fields;
1401203703bSJeremy L Thompson   CeedOperatorField  *op_input_fields, *op_output_fields;
1417a982d89SJeremy L. Thompson 
1422b730f8bSJeremy L Thompson   CeedCall(CeedOperatorGetNumElements(op, &num_elem));
1432b730f8bSJeremy L Thompson   CeedCall(CeedOperatorGetNumQuadraturePoints(op, &num_qpts));
1442b730f8bSJeremy L Thompson   CeedCall(CeedOperatorGetNumArgs(op, &total_fields));
1451203703bSJeremy L Thompson   CeedCall(CeedOperatorGetFields(op, &num_input_fields, &op_input_fields, &num_output_fields, &op_output_fields));
1461203703bSJeremy L Thompson   CeedCall(CeedOperatorGetQFunction(op, &qf));
1471203703bSJeremy L Thompson   CeedCall(CeedQFunctionGetFields(qf, NULL, &qf_input_fields, NULL, &qf_output_fields));
1481c66c397SJeremy L Thompson 
1492b730f8bSJeremy L Thompson   fprintf(stream, "%s  %" CeedInt_FMT " elements with %" CeedInt_FMT " quadrature points each\n", pre, num_elem, num_qpts);
1502b730f8bSJeremy L Thompson   fprintf(stream, "%s  %" CeedInt_FMT " field%s\n", pre, total_fields, total_fields > 1 ? "s" : "");
1511203703bSJeremy L Thompson   fprintf(stream, "%s  %" CeedInt_FMT " input field%s:\n", pre, num_input_fields, num_input_fields > 1 ? "s" : "");
1521203703bSJeremy L Thompson   for (CeedInt i = 0; i < num_input_fields; i++) {
1531203703bSJeremy L Thompson     CeedCall(CeedOperatorFieldView(op_input_fields[i], qf_input_fields[i], i, sub, 1, stream));
1547a982d89SJeremy L. Thompson   }
1551203703bSJeremy L Thompson   fprintf(stream, "%s  %" CeedInt_FMT " output field%s:\n", pre, num_output_fields, num_output_fields > 1 ? "s" : "");
1561203703bSJeremy L Thompson   for (CeedInt i = 0; i < num_output_fields; i++) {
1571203703bSJeremy L Thompson     CeedCall(CeedOperatorFieldView(op_output_fields[i], qf_output_fields[i], i, sub, 0, stream));
1587a982d89SJeremy L. Thompson   }
159e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1607a982d89SJeremy L. Thompson }
1617a982d89SJeremy L. Thompson 
162d99fa3c5SJeremy L Thompson /**
163ca94c3ddSJeremy L Thompson   @brief Find the active input vector `CeedBasis` for a non-composite `CeedOperator`
164eaf62fffSJeremy L Thompson 
165ca94c3ddSJeremy L Thompson   @param[in]  op           `CeedOperator` to find active `CeedBasis` for
166ca94c3ddSJeremy L Thompson   @param[out] active_basis `CeedBasis` for active input vector or `NULL` for composite operator
167eaf62fffSJeremy L Thompson 
168eaf62fffSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
169eaf62fffSJeremy L Thompson 
170eaf62fffSJeremy L Thompson   @ref Developer
171eaf62fffSJeremy L Thompson **/
172eaf62fffSJeremy L Thompson int CeedOperatorGetActiveBasis(CeedOperator op, CeedBasis *active_basis) {
173506b1a0cSSebastian Grimberg   CeedCall(CeedOperatorGetActiveBases(op, active_basis, NULL));
174506b1a0cSSebastian Grimberg   return CEED_ERROR_SUCCESS;
175506b1a0cSSebastian Grimberg }
176506b1a0cSSebastian Grimberg 
177506b1a0cSSebastian Grimberg /**
178ca94c3ddSJeremy L Thompson   @brief Find the active input and output vector `CeedBasis` for a non-composite `CeedOperator`
179506b1a0cSSebastian Grimberg 
180ca94c3ddSJeremy L Thompson   @param[in]  op                  `CeedOperator` to find active `CeedBasis` for
181ca94c3ddSJeremy L Thompson   @param[out] active_input_basis  `CeedBasis` for active input vector or `NULL` for composite operator
182ca94c3ddSJeremy L Thompson   @param[out] active_output_basis `CeedBasis` for active output vector or `NULL` for composite operator
183506b1a0cSSebastian Grimberg 
184506b1a0cSSebastian Grimberg   @return An error code: 0 - success, otherwise - failure
185506b1a0cSSebastian Grimberg 
186506b1a0cSSebastian Grimberg   @ref Developer
187506b1a0cSSebastian Grimberg **/
188506b1a0cSSebastian Grimberg int CeedOperatorGetActiveBases(CeedOperator op, CeedBasis *active_input_basis, CeedBasis *active_output_basis) {
1891203703bSJeremy L Thompson   bool               is_composite;
1901203703bSJeremy L Thompson   CeedInt            num_input_fields, num_output_fields;
1916aaed0edSJeremy L Thompson   Ceed               ceed;
1921203703bSJeremy L Thompson   CeedOperatorField *op_input_fields, *op_output_fields;
1931c66c397SJeremy L Thompson 
1946aaed0edSJeremy L Thompson   CeedCall(CeedOperatorGetCeed(op, &ceed));
1951203703bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
1961203703bSJeremy L Thompson   CeedCall(CeedOperatorGetFields(op, &num_input_fields, &op_input_fields, &num_output_fields, &op_output_fields));
1971203703bSJeremy L Thompson 
198506b1a0cSSebastian Grimberg   if (active_input_basis) {
199506b1a0cSSebastian Grimberg     *active_input_basis = NULL;
2001203703bSJeremy L Thompson     if (!is_composite) {
2011203703bSJeremy L Thompson       for (CeedInt i = 0; i < num_input_fields; i++) {
2021203703bSJeremy L Thompson         CeedVector vec;
2031203703bSJeremy L Thompson 
2041203703bSJeremy L Thompson         CeedCall(CeedOperatorFieldGetVector(op_input_fields[i], &vec));
2051203703bSJeremy L Thompson         if (vec == CEED_VECTOR_ACTIVE) {
2061203703bSJeremy L Thompson           CeedBasis basis;
2071203703bSJeremy L Thompson 
2081203703bSJeremy L Thompson           CeedCall(CeedOperatorFieldGetBasis(op_input_fields[i], &basis));
2091203703bSJeremy L Thompson           CeedCheck(!*active_input_basis || *active_input_basis == basis, ceed, CEED_ERROR_MINOR, "Multiple active input CeedBases found");
2101203703bSJeremy L Thompson           *active_input_basis = basis;
211eaf62fffSJeremy L Thompson         }
2122b730f8bSJeremy L Thompson       }
213506b1a0cSSebastian Grimberg       CeedCheck(*active_input_basis, ceed, CEED_ERROR_INCOMPLETE, "No active input CeedBasis found");
214506b1a0cSSebastian Grimberg     }
215506b1a0cSSebastian Grimberg   }
216506b1a0cSSebastian Grimberg   if (active_output_basis) {
217506b1a0cSSebastian Grimberg     *active_output_basis = NULL;
2181203703bSJeremy L Thompson     if (!is_composite) {
2191203703bSJeremy L Thompson       for (CeedInt i = 0; i < num_output_fields; i++) {
2201203703bSJeremy L Thompson         CeedVector vec;
2211203703bSJeremy L Thompson 
2221203703bSJeremy L Thompson         CeedCall(CeedOperatorFieldGetVector(op_output_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_output_fields[i], &basis));
2271203703bSJeremy L Thompson           CeedCheck(!*active_output_basis || *active_output_basis == basis, ceed, CEED_ERROR_MINOR, "Multiple active output CeedBases found");
2281203703bSJeremy L Thompson           *active_output_basis = basis;
229506b1a0cSSebastian Grimberg         }
230506b1a0cSSebastian Grimberg       }
231506b1a0cSSebastian Grimberg       CeedCheck(*active_output_basis, ceed, CEED_ERROR_INCOMPLETE, "No active output CeedBasis found");
232506b1a0cSSebastian Grimberg     }
233506b1a0cSSebastian Grimberg   }
234eaf62fffSJeremy L Thompson   return CEED_ERROR_SUCCESS;
235eaf62fffSJeremy L Thompson }
236eaf62fffSJeremy L Thompson 
237eaf62fffSJeremy L Thompson /**
238ca94c3ddSJeremy L Thompson   @brief Find the active vector `CeedElemRestriction` for a non-composite `CeedOperator`
239e2f04181SAndrew T. Barker 
240ca94c3ddSJeremy L Thompson   @param[in]  op          `CeedOperator` to find active `CeedElemRestriction` for
241ca94c3ddSJeremy L Thompson   @param[out] active_rstr `CeedElemRestriction` for active input vector or NULL for composite operator
242e2f04181SAndrew T. Barker 
243e2f04181SAndrew T. Barker   @return An error code: 0 - success, otherwise - failure
244e2f04181SAndrew T. Barker 
245e2f04181SAndrew T. Barker   @ref Utility
246e2f04181SAndrew T. Barker **/
2472b730f8bSJeremy L Thompson int CeedOperatorGetActiveElemRestriction(CeedOperator op, CeedElemRestriction *active_rstr) {
248506b1a0cSSebastian Grimberg   CeedCall(CeedOperatorGetActiveElemRestrictions(op, active_rstr, NULL));
249506b1a0cSSebastian Grimberg   return CEED_ERROR_SUCCESS;
250506b1a0cSSebastian Grimberg }
251506b1a0cSSebastian Grimberg 
252506b1a0cSSebastian Grimberg /**
253ca94c3ddSJeremy L Thompson   @brief Find the active input and output vector `CeedElemRestriction` for a non-composite `CeedOperator`
254506b1a0cSSebastian Grimberg 
255ca94c3ddSJeremy L Thompson   @param[in]  op                 `CeedOperator` to find active `CeedElemRestriction` for
256ca94c3ddSJeremy L Thompson   @param[out] active_input_rstr  `CeedElemRestriction` for active input vector or NULL for composite operator
257ca94c3ddSJeremy L Thompson   @param[out] active_output_rstr `CeedElemRestriction` for active output vector or NULL for composite operator
258506b1a0cSSebastian Grimberg 
259506b1a0cSSebastian Grimberg   @return An error code: 0 - success, otherwise - failure
260506b1a0cSSebastian Grimberg 
261506b1a0cSSebastian Grimberg   @ref Utility
262506b1a0cSSebastian Grimberg **/
263506b1a0cSSebastian Grimberg int CeedOperatorGetActiveElemRestrictions(CeedOperator op, CeedElemRestriction *active_input_rstr, CeedElemRestriction *active_output_rstr) {
2641203703bSJeremy L Thompson   bool               is_composite;
2651203703bSJeremy L Thompson   CeedInt            num_input_fields, num_output_fields;
2666aaed0edSJeremy L Thompson   Ceed               ceed;
2671203703bSJeremy L Thompson   CeedOperatorField *op_input_fields, *op_output_fields;
2681c66c397SJeremy L Thompson 
2696aaed0edSJeremy L Thompson   CeedCall(CeedOperatorGetCeed(op, &ceed));
2701203703bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
2711203703bSJeremy L Thompson   CeedCall(CeedOperatorGetFields(op, &num_input_fields, &op_input_fields, &num_output_fields, &op_output_fields));
2721203703bSJeremy L Thompson 
273506b1a0cSSebastian Grimberg   if (active_input_rstr) {
274506b1a0cSSebastian Grimberg     *active_input_rstr = NULL;
2751203703bSJeremy L Thompson     if (!is_composite) {
2761203703bSJeremy L Thompson       for (CeedInt i = 0; i < num_input_fields; i++) {
2771203703bSJeremy L Thompson         CeedVector vec;
2781203703bSJeremy L Thompson 
2791203703bSJeremy L Thompson         CeedCall(CeedOperatorFieldGetVector(op_input_fields[i], &vec));
2801203703bSJeremy L Thompson         if (vec == CEED_VECTOR_ACTIVE) {
2811203703bSJeremy L Thompson           CeedElemRestriction rstr;
2821203703bSJeremy L Thompson 
2831203703bSJeremy L Thompson           CeedCall(CeedOperatorFieldGetElemRestriction(op_input_fields[i], &rstr));
2841203703bSJeremy L Thompson           CeedCheck(!*active_input_rstr || *active_input_rstr == rstr, ceed, CEED_ERROR_MINOR, "Multiple active input CeedElemRestrictions found");
2851203703bSJeremy L Thompson           *active_input_rstr = rstr;
286e2f04181SAndrew T. Barker         }
2872b730f8bSJeremy L Thompson       }
288506b1a0cSSebastian Grimberg       CeedCheck(*active_input_rstr, ceed, CEED_ERROR_INCOMPLETE, "No active input CeedElemRestriction found");
289506b1a0cSSebastian Grimberg     }
290506b1a0cSSebastian Grimberg   }
291506b1a0cSSebastian Grimberg   if (active_output_rstr) {
292506b1a0cSSebastian Grimberg     *active_output_rstr = NULL;
2931203703bSJeremy L Thompson     if (!is_composite) {
2941203703bSJeremy L Thompson       for (CeedInt i = 0; i < num_output_fields; i++) {
2951203703bSJeremy L Thompson         CeedVector vec;
2961203703bSJeremy L Thompson 
2971203703bSJeremy L Thompson         CeedCall(CeedOperatorFieldGetVector(op_output_fields[i], &vec));
2981203703bSJeremy L Thompson         if (vec == CEED_VECTOR_ACTIVE) {
2991203703bSJeremy L Thompson           CeedElemRestriction rstr;
3001203703bSJeremy L Thompson 
3011203703bSJeremy L Thompson           CeedCall(CeedOperatorFieldGetElemRestriction(op_output_fields[i], &rstr));
3021203703bSJeremy L Thompson           CeedCheck(!*active_output_rstr || *active_output_rstr == rstr, ceed, CEED_ERROR_MINOR, "Multiple active output CeedElemRestrictions found");
3031203703bSJeremy L Thompson           *active_output_rstr = rstr;
304506b1a0cSSebastian Grimberg         }
305506b1a0cSSebastian Grimberg       }
306506b1a0cSSebastian Grimberg       CeedCheck(*active_output_rstr, ceed, CEED_ERROR_INCOMPLETE, "No active output CeedElemRestriction found");
307506b1a0cSSebastian Grimberg     }
308506b1a0cSSebastian Grimberg   }
309e2f04181SAndrew T. Barker   return CEED_ERROR_SUCCESS;
310e2f04181SAndrew T. Barker }
311e2f04181SAndrew T. Barker 
312d8dd9a91SJeremy L Thompson /**
313ca94c3ddSJeremy L Thompson   @brief Set `CeedQFunctionContext` field values of the specified type.
3144385fb7fSSebastian Grimberg 
315ca94c3ddSJeremy L Thompson   For composite operators, the value is set in all sub-operator `CeedQFunctionContext` that have a matching `field_name`.
316ca94c3ddSJeremy 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.
317d8dd9a91SJeremy L Thompson 
318ca94c3ddSJeremy L Thompson   @param[in,out] op          `CeedOperator`
319ea61e9acSJeremy L Thompson   @param[in]     field_label Label of field to set
320ea61e9acSJeremy L Thompson   @param[in]     field_type  Type of field to set
3212788fa27SJeremy L Thompson   @param[in]     values      Values to set
322d8dd9a91SJeremy L Thompson 
323d8dd9a91SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
324d8dd9a91SJeremy L Thompson 
325d8dd9a91SJeremy L Thompson   @ref User
326d8dd9a91SJeremy L Thompson **/
3272788fa27SJeremy L Thompson static int CeedOperatorContextSetGeneric(CeedOperator op, CeedContextFieldLabel field_label, CeedContextFieldType field_type, void *values) {
3281c66c397SJeremy L Thompson   bool is_composite = false;
3291203703bSJeremy L Thompson   Ceed ceed;
3301c66c397SJeremy L Thompson 
3311203703bSJeremy L Thompson   CeedCall(CeedOperatorGetCeed(op, &ceed));
3321203703bSJeremy L Thompson   CeedCheck(field_label, ceed, CEED_ERROR_UNSUPPORTED, "Invalid field label");
3333668ca4bSJeremy L Thompson 
3345ac9af79SJeremy L Thompson   // Check if field_label and op correspond
3355ac9af79SJeremy L Thompson   if (field_label->from_op) {
3365ac9af79SJeremy L Thompson     CeedInt index = -1;
3375ac9af79SJeremy L Thompson 
3385ac9af79SJeremy L Thompson     for (CeedInt i = 0; i < op->num_context_labels; i++) {
3395ac9af79SJeremy L Thompson       if (op->context_labels[i] == field_label) index = i;
3405ac9af79SJeremy L Thompson     }
3411203703bSJeremy L Thompson     CeedCheck(index != -1, ceed, CEED_ERROR_UNSUPPORTED, "ContextFieldLabel does not correspond to the operator");
3425ac9af79SJeremy L Thompson   }
3435ac9af79SJeremy L Thompson 
3442b730f8bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
345d8dd9a91SJeremy L Thompson   if (is_composite) {
346d8dd9a91SJeremy L Thompson     CeedInt       num_sub;
347d8dd9a91SJeremy L Thompson     CeedOperator *sub_operators;
348d8dd9a91SJeremy L Thompson 
349c6ebc35dSJeremy L Thompson     CeedCall(CeedCompositeOperatorGetNumSub(op, &num_sub));
350c6ebc35dSJeremy L Thompson     CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators));
3511203703bSJeremy L Thompson     CeedCheck(num_sub == field_label->num_sub_labels, ceed, CEED_ERROR_UNSUPPORTED, "Composite operator modified after ContextFieldLabel created");
352d8dd9a91SJeremy L Thompson 
353d8dd9a91SJeremy L Thompson     for (CeedInt i = 0; i < num_sub; i++) {
3541203703bSJeremy L Thompson       CeedQFunction        qf;
3551203703bSJeremy L Thompson       CeedQFunctionContext ctx;
3561203703bSJeremy L Thompson 
3571203703bSJeremy L Thompson       CeedCall(CeedOperatorGetQFunction(sub_operators[i], &qf));
3581203703bSJeremy L Thompson       CeedCall(CeedQFunctionGetContext(qf, &ctx));
359d8dd9a91SJeremy L Thompson       // Try every sub-operator, ok if some sub-operators do not have field
3601203703bSJeremy L Thompson       if (field_label->sub_labels[i] && ctx) {
3611203703bSJeremy L Thompson         CeedCall(CeedQFunctionContextSetGeneric(ctx, field_label->sub_labels[i], field_type, values));
362d8dd9a91SJeremy L Thompson       }
363d8dd9a91SJeremy L Thompson     }
364d8dd9a91SJeremy L Thompson   } else {
3651203703bSJeremy L Thompson     CeedQFunction        qf;
3661203703bSJeremy L Thompson     CeedQFunctionContext ctx;
3671203703bSJeremy L Thompson 
3681203703bSJeremy L Thompson     CeedCall(CeedOperatorGetQFunction(op, &qf));
3691203703bSJeremy L Thompson     CeedCall(CeedQFunctionGetContext(qf, &ctx));
3701203703bSJeremy L Thompson     CeedCheck(ctx, ceed, CEED_ERROR_UNSUPPORTED, "QFunction does not have context data");
3711203703bSJeremy L Thompson     CeedCall(CeedQFunctionContextSetGeneric(ctx, field_label, field_type, values));
3722788fa27SJeremy L Thompson   }
3736d95ab46SJeremy L Thompson   CeedCall(CeedOperatorSetQFunctionAssemblyDataUpdateNeeded(op, true));
3742788fa27SJeremy L Thompson   return CEED_ERROR_SUCCESS;
3752788fa27SJeremy L Thompson }
3762788fa27SJeremy L Thompson 
3772788fa27SJeremy L Thompson /**
378ca94c3ddSJeremy L Thompson   @brief Get `CeedQFunctionContext` field values of the specified type, read-only.
3794385fb7fSSebastian Grimberg 
380ca94c3ddSJeremy L Thompson   For composite operators, the values retrieved are for the first sub-operator `CeedQFunctionContext` that have a matching `field_name`.
381ca94c3ddSJeremy 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.
3822788fa27SJeremy L Thompson 
383ca94c3ddSJeremy L Thompson   @param[in,out] op          `CeedOperator`
3842788fa27SJeremy L Thompson   @param[in]     field_label Label of field to set
3852788fa27SJeremy L Thompson   @param[in]     field_type  Type of field to set
386c5d0f995SJed Brown   @param[out]    num_values  Number of values of type `field_type` in array `values`
387c5d0f995SJed Brown   @param[out]    values      Values in the label
3882788fa27SJeremy L Thompson 
3892788fa27SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
3902788fa27SJeremy L Thompson 
3912788fa27SJeremy L Thompson   @ref User
3922788fa27SJeremy L Thompson **/
3932788fa27SJeremy L Thompson static int CeedOperatorContextGetGenericRead(CeedOperator op, CeedContextFieldLabel field_label, CeedContextFieldType field_type, size_t *num_values,
3942788fa27SJeremy L Thompson                                              void *values) {
3951c66c397SJeremy L Thompson   bool is_composite = false;
3961203703bSJeremy L Thompson   Ceed ceed;
3971c66c397SJeremy L Thompson 
3981203703bSJeremy L Thompson   CeedCall(CeedOperatorGetCeed(op, &ceed));
3991203703bSJeremy L Thompson   CeedCheck(field_label, ceed, CEED_ERROR_UNSUPPORTED, "Invalid field label");
4002788fa27SJeremy L Thompson 
4012788fa27SJeremy L Thompson   *(void **)values = NULL;
4022788fa27SJeremy L Thompson   *num_values      = 0;
4032788fa27SJeremy L Thompson 
4045ac9af79SJeremy L Thompson   // Check if field_label and op correspond
4055ac9af79SJeremy L Thompson   if (field_label->from_op) {
4065ac9af79SJeremy L Thompson     CeedInt index = -1;
4075ac9af79SJeremy L Thompson 
4085ac9af79SJeremy L Thompson     for (CeedInt i = 0; i < op->num_context_labels; i++) {
4095ac9af79SJeremy L Thompson       if (op->context_labels[i] == field_label) index = i;
4105ac9af79SJeremy L Thompson     }
4116574a04fSJeremy L Thompson     CeedCheck(index != -1, op->ceed, CEED_ERROR_UNSUPPORTED, "ContextFieldLabel does not correspond to the operator");
4125ac9af79SJeremy L Thompson   }
4135ac9af79SJeremy L Thompson 
4142788fa27SJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
4152788fa27SJeremy L Thompson   if (is_composite) {
4162788fa27SJeremy L Thompson     CeedInt       num_sub;
4172788fa27SJeremy L Thompson     CeedOperator *sub_operators;
4182788fa27SJeremy L Thompson 
4192788fa27SJeremy L Thompson     CeedCall(CeedCompositeOperatorGetNumSub(op, &num_sub));
4202788fa27SJeremy L Thompson     CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators));
4211203703bSJeremy L Thompson     CeedCheck(num_sub == field_label->num_sub_labels, ceed, CEED_ERROR_UNSUPPORTED, "Composite operator modified after ContextFieldLabel created");
4222788fa27SJeremy L Thompson 
4232788fa27SJeremy L Thompson     for (CeedInt i = 0; i < num_sub; i++) {
4241203703bSJeremy L Thompson       CeedQFunction        qf;
4251203703bSJeremy L Thompson       CeedQFunctionContext ctx;
4261203703bSJeremy L Thompson 
4271203703bSJeremy L Thompson       CeedCall(CeedOperatorGetQFunction(sub_operators[i], &qf));
4281203703bSJeremy L Thompson       CeedCall(CeedQFunctionGetContext(qf, &ctx));
4292788fa27SJeremy L Thompson       // Try every sub-operator, ok if some sub-operators do not have field
4301203703bSJeremy L Thompson       if (field_label->sub_labels[i] && ctx) {
4311203703bSJeremy L Thompson         CeedCall(CeedQFunctionContextGetGenericRead(ctx, field_label->sub_labels[i], field_type, num_values, values));
4322788fa27SJeremy L Thompson         return CEED_ERROR_SUCCESS;
4332788fa27SJeremy L Thompson       }
4342788fa27SJeremy L Thompson     }
4352788fa27SJeremy L Thompson   } else {
4361203703bSJeremy L Thompson     CeedQFunction        qf;
4371203703bSJeremy L Thompson     CeedQFunctionContext ctx;
4381203703bSJeremy L Thompson 
4391203703bSJeremy L Thompson     CeedCall(CeedOperatorGetQFunction(op, &qf));
4401203703bSJeremy L Thompson     CeedCall(CeedQFunctionGetContext(qf, &ctx));
4411203703bSJeremy L Thompson     CeedCheck(ctx, ceed, CEED_ERROR_UNSUPPORTED, "QFunction does not have context data");
4421203703bSJeremy L Thompson     CeedCall(CeedQFunctionContextGetGenericRead(ctx, field_label, field_type, num_values, values));
4432788fa27SJeremy L Thompson   }
4442788fa27SJeremy L Thompson   return CEED_ERROR_SUCCESS;
4452788fa27SJeremy L Thompson }
4462788fa27SJeremy L Thompson 
4472788fa27SJeremy L Thompson /**
448ca94c3ddSJeremy L Thompson   @brief Restore `CeedQFunctionContext` field values of the specified type, read-only.
4494385fb7fSSebastian Grimberg 
450ca94c3ddSJeremy L Thompson   For composite operators, the values restored are for the first sub-operator `CeedQFunctionContext` that have a matching `field_name`.
451ca94c3ddSJeremy 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.
4522788fa27SJeremy L Thompson 
453ca94c3ddSJeremy L Thompson   @param[in,out] op          `CeedOperator`
4542788fa27SJeremy L Thompson   @param[in]     field_label Label of field to set
4552788fa27SJeremy L Thompson   @param[in]     field_type  Type of field to set
456c5d0f995SJed Brown   @param[in]     values      Values array to restore
4572788fa27SJeremy L Thompson 
4582788fa27SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
4592788fa27SJeremy L Thompson 
4602788fa27SJeremy L Thompson   @ref User
4612788fa27SJeremy L Thompson **/
4622788fa27SJeremy L Thompson static int CeedOperatorContextRestoreGenericRead(CeedOperator op, CeedContextFieldLabel field_label, CeedContextFieldType field_type, void *values) {
4631c66c397SJeremy L Thompson   bool is_composite = false;
4641203703bSJeremy L Thompson   Ceed ceed;
4651c66c397SJeremy L Thompson 
4661203703bSJeremy L Thompson   CeedCall(CeedOperatorGetCeed(op, &ceed));
4671203703bSJeremy L Thompson   CeedCheck(field_label, ceed, CEED_ERROR_UNSUPPORTED, "Invalid field label");
4682788fa27SJeremy L Thompson 
4695ac9af79SJeremy L Thompson   // Check if field_label and op correspond
4705ac9af79SJeremy L Thompson   if (field_label->from_op) {
4715ac9af79SJeremy L Thompson     CeedInt index = -1;
4725ac9af79SJeremy L Thompson 
4735ac9af79SJeremy L Thompson     for (CeedInt i = 0; i < op->num_context_labels; i++) {
4745ac9af79SJeremy L Thompson       if (op->context_labels[i] == field_label) index = i;
4755ac9af79SJeremy L Thompson     }
4766574a04fSJeremy L Thompson     CeedCheck(index != -1, op->ceed, CEED_ERROR_UNSUPPORTED, "ContextFieldLabel does not correspond to the operator");
4775ac9af79SJeremy L Thompson   }
4785ac9af79SJeremy L Thompson 
4792788fa27SJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
4802788fa27SJeremy L Thompson   if (is_composite) {
4812788fa27SJeremy L Thompson     CeedInt       num_sub;
4822788fa27SJeremy L Thompson     CeedOperator *sub_operators;
4832788fa27SJeremy L Thompson 
4842788fa27SJeremy L Thompson     CeedCall(CeedCompositeOperatorGetNumSub(op, &num_sub));
4852788fa27SJeremy L Thompson     CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators));
4866574a04fSJeremy L Thompson     CeedCheck(num_sub == field_label->num_sub_labels, op->ceed, CEED_ERROR_UNSUPPORTED,
4876574a04fSJeremy L Thompson               "Composite operator modified after ContextFieldLabel created");
4882788fa27SJeremy L Thompson 
4892788fa27SJeremy L Thompson     for (CeedInt i = 0; i < num_sub; i++) {
4901203703bSJeremy L Thompson       CeedQFunction        qf;
4911203703bSJeremy L Thompson       CeedQFunctionContext ctx;
4921203703bSJeremy L Thompson 
4931203703bSJeremy L Thompson       CeedCall(CeedOperatorGetQFunction(sub_operators[i], &qf));
4941203703bSJeremy L Thompson       CeedCall(CeedQFunctionGetContext(qf, &ctx));
4952788fa27SJeremy L Thompson       // Try every sub-operator, ok if some sub-operators do not have field
4961203703bSJeremy L Thompson       if (field_label->sub_labels[i] && ctx) {
4971203703bSJeremy L Thompson         CeedCall(CeedQFunctionContextRestoreGenericRead(ctx, field_label->sub_labels[i], field_type, values));
4982788fa27SJeremy L Thompson         return CEED_ERROR_SUCCESS;
4992788fa27SJeremy L Thompson       }
5002788fa27SJeremy L Thompson     }
5012788fa27SJeremy L Thompson   } else {
5021203703bSJeremy L Thompson     CeedQFunction        qf;
5031203703bSJeremy L Thompson     CeedQFunctionContext ctx;
5041203703bSJeremy L Thompson 
5051203703bSJeremy L Thompson     CeedCall(CeedOperatorGetQFunction(op, &qf));
5061203703bSJeremy L Thompson     CeedCall(CeedQFunctionGetContext(qf, &ctx));
5071203703bSJeremy L Thompson     CeedCheck(ctx, ceed, CEED_ERROR_UNSUPPORTED, "QFunction does not have context data");
5081203703bSJeremy L Thompson     CeedCall(CeedQFunctionContextRestoreGenericRead(ctx, field_label, field_type, values));
509d8dd9a91SJeremy L Thompson   }
510d8dd9a91SJeremy L Thompson   return CEED_ERROR_SUCCESS;
511d8dd9a91SJeremy L Thompson }
512d8dd9a91SJeremy L Thompson 
5137a982d89SJeremy L. Thompson /// @}
5147a982d89SJeremy L. Thompson 
5157a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
5167a982d89SJeremy L. Thompson /// CeedOperator Backend API
5177a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
5187a982d89SJeremy L. Thompson /// @addtogroup CeedOperatorBackend
5197a982d89SJeremy L. Thompson /// @{
5207a982d89SJeremy L. Thompson 
5217a982d89SJeremy L. Thompson /**
522ca94c3ddSJeremy L Thompson   @brief Get the number of arguments associated with a `CeedOperator`
5237a982d89SJeremy L. Thompson 
524ca94c3ddSJeremy L Thompson   @param[in]  op        `CeedOperator`
525d1d35e2fSjeremylt   @param[out] num_args  Variable to store vector number of arguments
5267a982d89SJeremy L. Thompson 
5277a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5287a982d89SJeremy L. Thompson 
5297a982d89SJeremy L. Thompson   @ref Backend
5307a982d89SJeremy L. Thompson **/
531d1d35e2fSjeremylt int CeedOperatorGetNumArgs(CeedOperator op, CeedInt *num_args) {
5321203703bSJeremy L Thompson   bool is_composite;
5331203703bSJeremy L Thompson   Ceed ceed;
5341203703bSJeremy L Thompson 
5351203703bSJeremy L Thompson   CeedCall(CeedOperatorGetCeed(op, &ceed));
5361203703bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
5371203703bSJeremy L Thompson   CeedCheck(!is_composite, ceed, CEED_ERROR_MINOR, "Not defined for composite operators");
538d1d35e2fSjeremylt   *num_args = op->num_fields;
539e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5407a982d89SJeremy L. Thompson }
5417a982d89SJeremy L. Thompson 
5427a982d89SJeremy L. Thompson /**
5439463e855SJeremy L Thompson   @brief Get the tensor product status of all bases for a `CeedOperator`.
5449463e855SJeremy L Thompson 
5459463e855SJeremy L Thompson   `has_tensor_bases` is only set to `true` if every field uses a tensor-product basis.
5469463e855SJeremy L Thompson 
5479463e855SJeremy L Thompson   @param[in]  op               `CeedOperator`
5489463e855SJeremy L Thompson   @param[out] has_tensor_bases Variable to store tensor bases status
5499463e855SJeremy L Thompson 
5509463e855SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
5519463e855SJeremy L Thompson 
5529463e855SJeremy L Thompson   @ref Backend
5539463e855SJeremy L Thompson **/
5549463e855SJeremy L Thompson int CeedOperatorHasTensorBases(CeedOperator op, bool *has_tensor_bases) {
5559463e855SJeremy L Thompson   CeedInt            num_inputs, num_outputs;
5569463e855SJeremy L Thompson   CeedOperatorField *input_fields, *output_fields;
5579463e855SJeremy L Thompson 
5589463e855SJeremy L Thompson   CeedCall(CeedOperatorGetFields(op, &num_inputs, &input_fields, &num_outputs, &output_fields));
5599463e855SJeremy L Thompson   *has_tensor_bases = true;
5609463e855SJeremy L Thompson   for (CeedInt i = 0; i < num_inputs; i++) {
5619463e855SJeremy L Thompson     bool      is_tensor;
5629463e855SJeremy L Thompson     CeedBasis basis;
5639463e855SJeremy L Thompson 
5649463e855SJeremy L Thompson     CeedCall(CeedOperatorFieldGetBasis(input_fields[i], &basis));
5659463e855SJeremy L Thompson     if (basis != CEED_BASIS_NONE) {
5669463e855SJeremy L Thompson       CeedCall(CeedBasisIsTensor(basis, &is_tensor));
5679463e855SJeremy L Thompson       *has_tensor_bases &= is_tensor;
5689463e855SJeremy L Thompson     }
5699463e855SJeremy L Thompson   }
5709463e855SJeremy L Thompson   for (CeedInt i = 0; i < num_outputs; i++) {
5719463e855SJeremy L Thompson     bool      is_tensor;
5729463e855SJeremy L Thompson     CeedBasis basis;
5739463e855SJeremy L Thompson 
5749463e855SJeremy L Thompson     CeedCall(CeedOperatorFieldGetBasis(output_fields[i], &basis));
5759463e855SJeremy L Thompson     if (basis != CEED_BASIS_NONE) {
5769463e855SJeremy L Thompson       CeedCall(CeedBasisIsTensor(basis, &is_tensor));
5779463e855SJeremy L Thompson       *has_tensor_bases &= is_tensor;
5789463e855SJeremy L Thompson     }
5799463e855SJeremy L Thompson   }
5809463e855SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5819463e855SJeremy L Thompson }
5829463e855SJeremy L Thompson 
5839463e855SJeremy L Thompson /**
5841203703bSJeremy L Thompson   @brief Get a boolean value indicating if the `CeedOperator` is immutable
5851203703bSJeremy L Thompson 
5861203703bSJeremy L Thompson   @param[in]  op           `CeedOperator`
5871203703bSJeremy L Thompson   @param[out] is_immutable Variable to store immutability status
5881203703bSJeremy L Thompson 
5891203703bSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
5901203703bSJeremy L Thompson 
5911203703bSJeremy L Thompson   @ref Backend
5921203703bSJeremy L Thompson **/
5931203703bSJeremy L Thompson int CeedOperatorIsImmutable(CeedOperator op, bool *is_immutable) {
5941203703bSJeremy L Thompson   *is_immutable = op->is_immutable;
5951203703bSJeremy L Thompson   return CEED_ERROR_SUCCESS;
5961203703bSJeremy L Thompson }
5971203703bSJeremy L Thompson 
5981203703bSJeremy L Thompson /**
599ca94c3ddSJeremy L Thompson   @brief Get the setup status of a `CeedOperator`
6007a982d89SJeremy L. Thompson 
601ca94c3ddSJeremy L Thompson   @param[in]  op            `CeedOperator`
602d1d35e2fSjeremylt   @param[out] is_setup_done Variable to store setup status
6037a982d89SJeremy L. Thompson 
6047a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6057a982d89SJeremy L. Thompson 
6067a982d89SJeremy L. Thompson   @ref Backend
6077a982d89SJeremy L. Thompson **/
608d1d35e2fSjeremylt int CeedOperatorIsSetupDone(CeedOperator op, bool *is_setup_done) {
609f04ea552SJeremy L Thompson   *is_setup_done = op->is_backend_setup;
610e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6117a982d89SJeremy L. Thompson }
6127a982d89SJeremy L. Thompson 
6137a982d89SJeremy L. Thompson /**
614ca94c3ddSJeremy L Thompson   @brief Get the `CeedQFunction` associated with a `CeedOperator`
6157a982d89SJeremy L. Thompson 
616ca94c3ddSJeremy L Thompson   @param[in]  op `CeedOperator`
617ca94c3ddSJeremy L Thompson   @param[out] qf Variable to store `CeedQFunction`
6187a982d89SJeremy L. Thompson 
6197a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6207a982d89SJeremy L. Thompson 
6217a982d89SJeremy L. Thompson   @ref Backend
6227a982d89SJeremy L. Thompson **/
6237a982d89SJeremy L. Thompson int CeedOperatorGetQFunction(CeedOperator op, CeedQFunction *qf) {
6241203703bSJeremy L Thompson   bool is_composite;
6251203703bSJeremy L Thompson   Ceed ceed;
6261203703bSJeremy L Thompson 
6271203703bSJeremy L Thompson   CeedCall(CeedOperatorGetCeed(op, &ceed));
6281203703bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
6291203703bSJeremy L Thompson   CeedCheck(!is_composite, ceed, CEED_ERROR_MINOR, "Not defined for composite operator");
6307a982d89SJeremy L. Thompson   *qf = op->qf;
631e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6327a982d89SJeremy L. Thompson }
6337a982d89SJeremy L. Thompson 
6347a982d89SJeremy L. Thompson /**
635ca94c3ddSJeremy L Thompson   @brief Get a boolean value indicating if the `CeedOperator` is composite
636c04a41a7SJeremy L Thompson 
637ca94c3ddSJeremy L Thompson   @param[in]  op           `CeedOperator`
638d1d35e2fSjeremylt   @param[out] is_composite Variable to store composite status
639c04a41a7SJeremy L Thompson 
640c04a41a7SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
641c04a41a7SJeremy L Thompson 
642c04a41a7SJeremy L Thompson   @ref Backend
643c04a41a7SJeremy L Thompson **/
644d1d35e2fSjeremylt int CeedOperatorIsComposite(CeedOperator op, bool *is_composite) {
645f04ea552SJeremy L Thompson   *is_composite = op->is_composite;
646e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
647c04a41a7SJeremy L Thompson }
648c04a41a7SJeremy L Thompson 
649c04a41a7SJeremy L Thompson /**
650ca94c3ddSJeremy L Thompson   @brief Get the backend data of a `CeedOperator`
6517a982d89SJeremy L. Thompson 
652ca94c3ddSJeremy L Thompson   @param[in]  op   `CeedOperator`
6537a982d89SJeremy L. Thompson   @param[out] data Variable to store data
6547a982d89SJeremy L. Thompson 
6557a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6567a982d89SJeremy L. Thompson 
6577a982d89SJeremy L. Thompson   @ref Backend
6587a982d89SJeremy L. Thompson **/
659777ff853SJeremy L Thompson int CeedOperatorGetData(CeedOperator op, void *data) {
660777ff853SJeremy L Thompson   *(void **)data = op->data;
661e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6627a982d89SJeremy L. Thompson }
6637a982d89SJeremy L. Thompson 
6647a982d89SJeremy L. Thompson /**
665ca94c3ddSJeremy L Thompson   @brief Set the backend data of a `CeedOperator`
6667a982d89SJeremy L. Thompson 
667ca94c3ddSJeremy L Thompson   @param[in,out] op   `CeedOperator`
668ea61e9acSJeremy L Thompson   @param[in]     data Data to set
6697a982d89SJeremy L. Thompson 
6707a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6717a982d89SJeremy L. Thompson 
6727a982d89SJeremy L. Thompson   @ref Backend
6737a982d89SJeremy L. Thompson **/
674777ff853SJeremy L Thompson int CeedOperatorSetData(CeedOperator op, void *data) {
675777ff853SJeremy L Thompson   op->data = data;
676e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6777a982d89SJeremy L. Thompson }
6787a982d89SJeremy L. Thompson 
6797a982d89SJeremy L. Thompson /**
680ca94c3ddSJeremy L Thompson   @brief Increment the reference counter for a `CeedOperator`
68134359f16Sjeremylt 
682ca94c3ddSJeremy L Thompson   @param[in,out] op `CeedOperator` to increment the reference counter
68334359f16Sjeremylt 
68434359f16Sjeremylt   @return An error code: 0 - success, otherwise - failure
68534359f16Sjeremylt 
68634359f16Sjeremylt   @ref Backend
68734359f16Sjeremylt **/
6889560d06aSjeremylt int CeedOperatorReference(CeedOperator op) {
68934359f16Sjeremylt   op->ref_count++;
69034359f16Sjeremylt   return CEED_ERROR_SUCCESS;
69134359f16Sjeremylt }
69234359f16Sjeremylt 
69334359f16Sjeremylt /**
694ca94c3ddSJeremy L Thompson   @brief Set the setup flag of a `CeedOperator` to `true`
6957a982d89SJeremy L. Thompson 
696ca94c3ddSJeremy L Thompson   @param[in,out] op `CeedOperator`
6977a982d89SJeremy L. Thompson 
6987a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6997a982d89SJeremy L. Thompson 
7007a982d89SJeremy L. Thompson   @ref Backend
7017a982d89SJeremy L. Thompson **/
7027a982d89SJeremy L. Thompson int CeedOperatorSetSetupDone(CeedOperator op) {
703f04ea552SJeremy L Thompson   op->is_backend_setup = true;
704e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
7057a982d89SJeremy L. Thompson }
7067a982d89SJeremy L. Thompson 
7077a982d89SJeremy L. Thompson /// @}
7087a982d89SJeremy L. Thompson 
7097a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
7107a982d89SJeremy L. Thompson /// CeedOperator Public API
7117a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
7127a982d89SJeremy L. Thompson /// @addtogroup CeedOperatorUser
713dfdf5a53Sjeremylt /// @{
714d7b241e6Sjeremylt 
715d7b241e6Sjeremylt /**
716ca94c3ddSJeremy L Thompson   @brief Create a `CeedOperator` and associate a `CeedQFunction`.
7174385fb7fSSebastian Grimberg 
718ca94c3ddSJeremy L Thompson   A `CeedBasis` and `CeedElemRestriction` can be associated with `CeedQFunction` fields with @ref CeedOperatorSetField().
719d7b241e6Sjeremylt 
720ca94c3ddSJeremy L Thompson   @param[in]  ceed `Ceed` object used to create the `CeedOperator`
721ca94c3ddSJeremy L Thompson   @param[in]  qf   `CeedQFunction` defining the action of the operator at quadrature points
722ca94c3ddSJeremy L Thompson   @param[in]  dqf  `CeedQFunction` defining the action of the Jacobian of `qf` (or @ref CEED_QFUNCTION_NONE)
723ca94c3ddSJeremy L Thompson   @param[in]  dqfT `CeedQFunction` defining the action of the transpose of the Jacobian of `qf` (or @ref CEED_QFUNCTION_NONE)
724ca94c3ddSJeremy L Thompson   @param[out] op   Address of the variable where the newly created `CeedOperator` will be stored
725b11c1e72Sjeremylt 
726b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
727dfdf5a53Sjeremylt 
7287a982d89SJeremy L. Thompson   @ref User
729d7b241e6Sjeremylt  */
7302b730f8bSJeremy L Thompson int CeedOperatorCreate(Ceed ceed, CeedQFunction qf, CeedQFunction dqf, CeedQFunction dqfT, CeedOperator *op) {
7315fe0d4faSjeremylt   if (!ceed->OperatorCreate) {
7325fe0d4faSjeremylt     Ceed delegate;
7336574a04fSJeremy L Thompson 
7342b730f8bSJeremy L Thompson     CeedCall(CeedGetObjectDelegate(ceed, &delegate, "Operator"));
735ca94c3ddSJeremy L Thompson     CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support CeedOperatorCreate");
7362b730f8bSJeremy L Thompson     CeedCall(CeedOperatorCreate(delegate, qf, dqf, dqfT, op));
737e15f9bd0SJeremy L Thompson     return CEED_ERROR_SUCCESS;
7385fe0d4faSjeremylt   }
7395fe0d4faSjeremylt 
740ca94c3ddSJeremy L Thompson   CeedCheck(qf && qf != CEED_QFUNCTION_NONE, ceed, CEED_ERROR_MINOR, "Operator must have a valid CeedQFunction.");
741db002c03SJeremy L Thompson 
7422b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(1, op));
743db002c03SJeremy L Thompson   CeedCall(CeedReferenceCopy(ceed, &(*op)->ceed));
744d1d35e2fSjeremylt   (*op)->ref_count   = 1;
7452b104005SJeremy L Thompson   (*op)->input_size  = -1;
7462b104005SJeremy L Thompson   (*op)->output_size = -1;
747db002c03SJeremy L Thompson   CeedCall(CeedQFunctionReferenceCopy(qf, &(*op)->qf));
748db002c03SJeremy L Thompson   if (dqf && dqf != CEED_QFUNCTION_NONE) CeedCall(CeedQFunctionReferenceCopy(dqf, &(*op)->dqf));
749db002c03SJeremy L Thompson   if (dqfT && dqfT != CEED_QFUNCTION_NONE) CeedCall(CeedQFunctionReferenceCopy(dqfT, &(*op)->dqfT));
7502b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionAssemblyDataCreate(ceed, &(*op)->qf_assembled));
7512b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(CEED_FIELD_MAX, &(*op)->input_fields));
7522b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(CEED_FIELD_MAX, &(*op)->output_fields));
7532b730f8bSJeremy L Thompson   CeedCall(ceed->OperatorCreate(*op));
754e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
755d7b241e6Sjeremylt }
756d7b241e6Sjeremylt 
757d7b241e6Sjeremylt /**
758ca94c3ddSJeremy L Thompson   @brief Create a `CeedOperator` for evaluation at evaluation at arbitrary points in each element.
75948acf710SJeremy L Thompson 
760ca94c3ddSJeremy L Thompson   A `CeedBasis` and `CeedElemRestriction` can be associated with `CeedQFunction` fields with `CeedOperator` SetField.
761ca94c3ddSJeremy L Thompson   The locations of each point are set with @ref CeedOperatorAtPointsSetPoints().
76248acf710SJeremy L Thompson 
763ca94c3ddSJeremy L Thompson   @param[in]  ceed `Ceed` object used to create the `CeedOperator`
764ca94c3ddSJeremy L Thompson   @param[in]  qf   `CeedQFunction` defining the action of the operator at quadrature points
765ca94c3ddSJeremy L Thompson   @param[in]  dqf  `CeedQFunction` defining the action of the Jacobian of @a qf (or @ref CEED_QFUNCTION_NONE)
766ca94c3ddSJeremy L Thompson   @param[in]  dqfT `CeedQFunction` defining the action of the transpose of the Jacobian of @a qf (or @ref CEED_QFUNCTION_NONE)
76748acf710SJeremy L Thompson   @param[out] op   Address of the variable where the newly created CeedOperator will be stored
76848acf710SJeremy L Thompson 
76948acf710SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
77048acf710SJeremy L Thompson 
77148acf710SJeremy L Thompson   @ref User
77248acf710SJeremy L Thompson  */
77348acf710SJeremy L Thompson int CeedOperatorCreateAtPoints(Ceed ceed, CeedQFunction qf, CeedQFunction dqf, CeedQFunction dqfT, CeedOperator *op) {
77448acf710SJeremy L Thompson   if (!ceed->OperatorCreateAtPoints) {
77548acf710SJeremy L Thompson     Ceed delegate;
77648acf710SJeremy L Thompson 
77748acf710SJeremy L Thompson     CeedCall(CeedGetObjectDelegate(ceed, &delegate, "Operator"));
778ca94c3ddSJeremy L Thompson     CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not support CeedOperatorCreateAtPoints");
77948acf710SJeremy L Thompson     CeedCall(CeedOperatorCreateAtPoints(delegate, qf, dqf, dqfT, op));
78048acf710SJeremy L Thompson     return CEED_ERROR_SUCCESS;
78148acf710SJeremy L Thompson   }
78248acf710SJeremy L Thompson 
783ca94c3ddSJeremy L Thompson   CeedCheck(qf && qf != CEED_QFUNCTION_NONE, ceed, CEED_ERROR_MINOR, "Operator must have a valid CeedQFunction.");
78448acf710SJeremy L Thompson 
78548acf710SJeremy L Thompson   CeedCall(CeedCalloc(1, op));
78648acf710SJeremy L Thompson   CeedCall(CeedReferenceCopy(ceed, &(*op)->ceed));
78748acf710SJeremy L Thompson   (*op)->ref_count    = 1;
78848acf710SJeremy L Thompson   (*op)->is_at_points = true;
78948acf710SJeremy L Thompson   (*op)->input_size   = -1;
79048acf710SJeremy L Thompson   (*op)->output_size  = -1;
79148acf710SJeremy L Thompson   CeedCall(CeedQFunctionReferenceCopy(qf, &(*op)->qf));
79248acf710SJeremy L Thompson   if (dqf && dqf != CEED_QFUNCTION_NONE) CeedCall(CeedQFunctionReferenceCopy(dqf, &(*op)->dqf));
79348acf710SJeremy L Thompson   if (dqfT && dqfT != CEED_QFUNCTION_NONE) CeedCall(CeedQFunctionReferenceCopy(dqfT, &(*op)->dqfT));
79448acf710SJeremy L Thompson   CeedCall(CeedQFunctionAssemblyDataCreate(ceed, &(*op)->qf_assembled));
79548acf710SJeremy L Thompson   CeedCall(CeedCalloc(CEED_FIELD_MAX, &(*op)->input_fields));
79648acf710SJeremy L Thompson   CeedCall(CeedCalloc(CEED_FIELD_MAX, &(*op)->output_fields));
79748acf710SJeremy L Thompson   CeedCall(ceed->OperatorCreateAtPoints(*op));
79848acf710SJeremy L Thompson   return CEED_ERROR_SUCCESS;
79948acf710SJeremy L Thompson }
80048acf710SJeremy L Thompson 
80148acf710SJeremy L Thompson /**
802ca94c3ddSJeremy L Thompson   @brief Create a composite `CeedOperator` that composes the action of several `CeedOperator`
80352d6035fSJeremy L Thompson 
804ca94c3ddSJeremy L Thompson   @param[in]  ceed `Ceed` object used to create the `CeedOperator`
805ca94c3ddSJeremy L Thompson   @param[out] op   Address of the variable where the newly created composite `CeedOperator` will be stored
80652d6035fSJeremy L Thompson 
80752d6035fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
80852d6035fSJeremy L Thompson 
8097a982d89SJeremy L. Thompson   @ref User
81052d6035fSJeremy L Thompson  */
81152d6035fSJeremy L Thompson int CeedCompositeOperatorCreate(Ceed ceed, CeedOperator *op) {
81252d6035fSJeremy L Thompson   if (!ceed->CompositeOperatorCreate) {
81352d6035fSJeremy L Thompson     Ceed delegate;
81452d6035fSJeremy L Thompson 
8151c66c397SJeremy L Thompson     CeedCall(CeedGetObjectDelegate(ceed, &delegate, "Operator"));
816250756a7Sjeremylt     if (delegate) {
8172b730f8bSJeremy L Thompson       CeedCall(CeedCompositeOperatorCreate(delegate, op));
818e15f9bd0SJeremy L Thompson       return CEED_ERROR_SUCCESS;
81952d6035fSJeremy L Thompson     }
820250756a7Sjeremylt   }
82152d6035fSJeremy L Thompson 
8222b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(1, op));
823db002c03SJeremy L Thompson   CeedCall(CeedReferenceCopy(ceed, &(*op)->ceed));
824996d9ab5SJed Brown   (*op)->ref_count    = 1;
825f04ea552SJeremy L Thompson   (*op)->is_composite = true;
8262b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(CEED_COMPOSITE_MAX, &(*op)->sub_operators));
8272b104005SJeremy L Thompson   (*op)->input_size  = -1;
8282b104005SJeremy L Thompson   (*op)->output_size = -1;
829250756a7Sjeremylt 
830db002c03SJeremy L Thompson   if (ceed->CompositeOperatorCreate) CeedCall(ceed->CompositeOperatorCreate(*op));
831e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
83252d6035fSJeremy L Thompson }
83352d6035fSJeremy L Thompson 
83452d6035fSJeremy L Thompson /**
835ca94c3ddSJeremy L Thompson   @brief Copy the pointer to a `CeedOperator`.
8364385fb7fSSebastian Grimberg 
837ca94c3ddSJeremy L Thompson   Both pointers should be destroyed with @ref CeedOperatorDestroy().
838512bb800SJeremy L Thompson 
839ca94c3ddSJeremy 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`.
840ca94c3ddSJeremy L Thompson         This `CeedOperator` will be destroyed if `*op_copy` is the only reference to this `CeedOperator`.
8419560d06aSjeremylt 
842ca94c3ddSJeremy L Thompson   @param[in]     op      `CeedOperator` to copy reference to
843ea61e9acSJeremy L Thompson   @param[in,out] op_copy Variable to store copied reference
8449560d06aSjeremylt 
8459560d06aSjeremylt   @return An error code: 0 - success, otherwise - failure
8469560d06aSjeremylt 
8479560d06aSjeremylt   @ref User
8489560d06aSjeremylt **/
8499560d06aSjeremylt int CeedOperatorReferenceCopy(CeedOperator op, CeedOperator *op_copy) {
8502b730f8bSJeremy L Thompson   CeedCall(CeedOperatorReference(op));
8512b730f8bSJeremy L Thompson   CeedCall(CeedOperatorDestroy(op_copy));
8529560d06aSjeremylt   *op_copy = op;
8539560d06aSjeremylt   return CEED_ERROR_SUCCESS;
8549560d06aSjeremylt }
8559560d06aSjeremylt 
8569560d06aSjeremylt /**
857ca94c3ddSJeremy L Thompson   @brief Provide a field to a `CeedOperator` for use by its `CeedQFunction`.
858d7b241e6Sjeremylt 
859ca94c3ddSJeremy L Thompson   This function is used to specify both active and passive fields to a `CeedOperator`.
860bafebce1SSebastian Grimberg   For passive fields, a `CeedVector` `vec` must be provided.
861ea61e9acSJeremy L Thompson   Passive fields can inputs or outputs (updated in-place when operator is applied).
862d7b241e6Sjeremylt 
863ca94c3ddSJeremy L Thompson   Active fields must be specified using this function, but their data (in a `CeedVector`) is passed in @ref CeedOperatorApply().
864ca94c3ddSJeremy L Thompson   There can be at most one active input `CeedVector` and at most one active output@ref  CeedVector passed to @ref CeedOperatorApply().
865d7b241e6Sjeremylt 
866528a22edSJeremy L Thompson   The number of quadrature points must agree across all points.
867bafebce1SSebastian Grimberg   When using @ref CEED_BASIS_NONE, the number of quadrature points is determined by the element size of `rstr`.
868528a22edSJeremy L Thompson 
869ca94c3ddSJeremy L Thompson   @param[in,out] op         `CeedOperator` on which to provide the field
870ca94c3ddSJeremy L Thompson   @param[in]     field_name Name of the field (to be matched with the name used by `CeedQFunction`)
871bafebce1SSebastian Grimberg   @param[in]     rstr       `CeedElemRestriction`
872bafebce1SSebastian Grimberg   @param[in]     basis      `CeedBasis` in which the field resides or @ref CEED_BASIS_NONE if collocated with quadrature points
873bafebce1SSebastian 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`
874b11c1e72Sjeremylt 
875b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
876dfdf5a53Sjeremylt 
8777a982d89SJeremy L. Thompson   @ref User
878b11c1e72Sjeremylt **/
879bafebce1SSebastian Grimberg int CeedOperatorSetField(CeedOperator op, const char *field_name, CeedElemRestriction rstr, CeedBasis basis, CeedVector vec) {
8801203703bSJeremy L Thompson   bool               is_input = true, is_at_points, is_composite, is_immutable;
8811203703bSJeremy L Thompson   CeedInt            num_elem = 0, num_qpts = 0, num_input_fields, num_output_fields;
8821203703bSJeremy L Thompson   Ceed               ceed;
8831203703bSJeremy L Thompson   CeedQFunction      qf;
8841203703bSJeremy L Thompson   CeedQFunctionField qf_field, *qf_input_fields, *qf_output_fields;
8851c66c397SJeremy L Thompson   CeedOperatorField *op_field;
8861c66c397SJeremy L Thompson 
8871203703bSJeremy L Thompson   CeedCall(CeedOperatorGetCeed(op, &ceed));
8881203703bSJeremy L Thompson   CeedCall(CeedOperatorIsAtPoints(op, &is_at_points));
8891203703bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
8901203703bSJeremy L Thompson   CeedCall(CeedOperatorIsImmutable(op, &is_immutable));
8911203703bSJeremy L Thompson   CeedCheck(!is_composite, ceed, CEED_ERROR_INCOMPATIBLE, "Cannot add field to composite operator.");
8921203703bSJeremy L Thompson   CeedCheck(!is_immutable, ceed, CEED_ERROR_MAJOR, "Operator cannot be changed after set as immutable");
8931203703bSJeremy L Thompson   CeedCheck(rstr, ceed, CEED_ERROR_INCOMPATIBLE, "CeedElemRestriction rstr for field \"%s\" must be non-NULL.", field_name);
8941203703bSJeremy L Thompson   CeedCheck(basis, ceed, CEED_ERROR_INCOMPATIBLE, "CeedBasis basis for field \"%s\" must be non-NULL.", field_name);
8951203703bSJeremy L Thompson   CeedCheck(vec, ceed, CEED_ERROR_INCOMPATIBLE, "CeedVector vec for field \"%s\" must be non-NULL.", field_name);
89652d6035fSJeremy L Thompson 
897bafebce1SSebastian Grimberg   CeedCall(CeedElemRestrictionGetNumElements(rstr, &num_elem));
8981203703bSJeremy L Thompson   CeedCheck(rstr == CEED_ELEMRESTRICTION_NONE || !op->has_restriction || num_elem == op->num_elem, ceed, CEED_ERROR_DIMENSION,
899ca94c3ddSJeremy L Thompson             "CeedElemRestriction with %" CeedInt_FMT " elements incompatible with prior %" CeedInt_FMT " elements", num_elem, op->num_elem);
9002c7e7413SJeremy L Thompson   {
9012c7e7413SJeremy L Thompson     CeedRestrictionType rstr_type;
9022c7e7413SJeremy L Thompson 
903bafebce1SSebastian Grimberg     CeedCall(CeedElemRestrictionGetType(rstr, &rstr_type));
90448acf710SJeremy L Thompson     if (rstr_type == CEED_RESTRICTION_POINTS) {
9051203703bSJeremy L Thompson       CeedCheck(is_at_points, ceed, CEED_ERROR_UNSUPPORTED, "CeedElemRestriction AtPoints not supported for standard operator fields");
9061203703bSJeremy L Thompson       CeedCheck(basis == CEED_BASIS_NONE, ceed, CEED_ERROR_UNSUPPORTED, "CeedElemRestriction AtPoints must be used with CEED_BASIS_NONE");
90748acf710SJeremy L Thompson       if (!op->first_points_rstr) {
908bafebce1SSebastian Grimberg         CeedCall(CeedElemRestrictionReferenceCopy(rstr, &op->first_points_rstr));
90948acf710SJeremy L Thompson       } else {
91048acf710SJeremy L Thompson         bool are_compatible;
91148acf710SJeremy L Thompson 
912bafebce1SSebastian Grimberg         CeedCall(CeedElemRestrictionAtPointsAreCompatible(op->first_points_rstr, rstr, &are_compatible));
9131203703bSJeremy L Thompson         CeedCheck(are_compatible, ceed, CEED_ERROR_INCOMPATIBLE,
914ca94c3ddSJeremy L Thompson                   "CeedElemRestriction must have compatible offsets with previously set CeedElemRestriction");
91548acf710SJeremy L Thompson       }
91648acf710SJeremy L Thompson     }
9172c7e7413SJeremy L Thompson   }
918d7b241e6Sjeremylt 
919bafebce1SSebastian Grimberg   if (basis == CEED_BASIS_NONE) CeedCall(CeedElemRestrictionGetElementSize(rstr, &num_qpts));
920bafebce1SSebastian Grimberg   else CeedCall(CeedBasisGetNumQuadraturePoints(basis, &num_qpts));
9211203703bSJeremy L Thompson   CeedCheck(op->num_qpts == 0 || num_qpts == op->num_qpts, ceed, CEED_ERROR_DIMENSION,
922ca94c3ddSJeremy L Thompson             "%s must correspond to the same number of quadrature points as previously added CeedBases. Found %" CeedInt_FMT
923528a22edSJeremy L Thompson             " quadrature points but expected %" CeedInt_FMT " quadrature points.",
924bafebce1SSebastian Grimberg             basis == CEED_BASIS_NONE ? "CeedElemRestriction" : "CeedBasis", num_qpts, op->num_qpts);
9251203703bSJeremy L Thompson 
9261203703bSJeremy L Thompson   CeedCall(CeedOperatorGetQFunction(op, &qf));
9271203703bSJeremy L Thompson   CeedCall(CeedQFunctionGetFields(qf, &num_input_fields, &qf_input_fields, &num_output_fields, &qf_output_fields));
9281203703bSJeremy L Thompson   for (CeedInt i = 0; i < num_input_fields; i++) {
929*6f8994e9SJeremy L Thompson     const char *qf_field_name;
9301203703bSJeremy L Thompson 
9311203703bSJeremy L Thompson     CeedCall(CeedQFunctionFieldGetName(qf_input_fields[i], &qf_field_name));
9321203703bSJeremy L Thompson     if (!strcmp(field_name, qf_field_name)) {
9331203703bSJeremy L Thompson       qf_field = qf_input_fields[i];
934d1d35e2fSjeremylt       op_field = &op->input_fields[i];
935d7b241e6Sjeremylt       goto found;
936d7b241e6Sjeremylt     }
937d7b241e6Sjeremylt   }
9382b104005SJeremy L Thompson   is_input = false;
9391203703bSJeremy L Thompson   for (CeedInt i = 0; i < num_output_fields; i++) {
940*6f8994e9SJeremy L Thompson     const char *qf_field_name;
9411203703bSJeremy L Thompson 
9421203703bSJeremy L Thompson     CeedCall(CeedQFunctionFieldGetName(qf_output_fields[i], &qf_field_name));
9431203703bSJeremy L Thompson     if (!strcmp(field_name, qf_field_name)) {
9441203703bSJeremy L Thompson       qf_field = qf_output_fields[i];
945d1d35e2fSjeremylt       op_field = &op->output_fields[i];
946d7b241e6Sjeremylt       goto found;
947d7b241e6Sjeremylt     }
948d7b241e6Sjeremylt   }
949c042f62fSJeremy L Thompson   // LCOV_EXCL_START
9501203703bSJeremy L Thompson   return CeedError(ceed, CEED_ERROR_INCOMPLETE, "CeedQFunction has no knowledge of field '%s'", field_name);
951c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
952d7b241e6Sjeremylt found:
9531203703bSJeremy L Thompson   CeedCall(CeedOperatorCheckField(ceed, qf_field, rstr, basis));
9542b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(1, op_field));
955e15f9bd0SJeremy L Thompson 
956bafebce1SSebastian Grimberg   if (vec == CEED_VECTOR_ACTIVE) {
9572b104005SJeremy L Thompson     CeedSize l_size;
9581c66c397SJeremy L Thompson 
959bafebce1SSebastian Grimberg     CeedCall(CeedElemRestrictionGetLVectorSize(rstr, &l_size));
9602b104005SJeremy L Thompson     if (is_input) {
9612b104005SJeremy L Thompson       if (op->input_size == -1) op->input_size = l_size;
9621203703bSJeremy L Thompson       CeedCheck(l_size == op->input_size, ceed, CEED_ERROR_INCOMPATIBLE,
963249f8407SJeremy L Thompson                 "LVector size %" CeedSize_FMT " does not match previous size %" CeedSize_FMT "", l_size, op->input_size);
9642b104005SJeremy L Thompson     } else {
9652b104005SJeremy L Thompson       if (op->output_size == -1) op->output_size = l_size;
9661203703bSJeremy L Thompson       CeedCheck(l_size == op->output_size, ceed, CEED_ERROR_INCOMPATIBLE,
967249f8407SJeremy L Thompson                 "LVector size %" CeedSize_FMT " does not match previous size %" CeedSize_FMT "", l_size, op->output_size);
9682b104005SJeremy L Thompson     }
9692b730f8bSJeremy L Thompson   }
9702b104005SJeremy L Thompson 
971bafebce1SSebastian Grimberg   CeedCall(CeedVectorReferenceCopy(vec, &(*op_field)->vec));
972bafebce1SSebastian Grimberg   CeedCall(CeedElemRestrictionReferenceCopy(rstr, &(*op_field)->elem_rstr));
973bafebce1SSebastian Grimberg   if (rstr != CEED_ELEMRESTRICTION_NONE && !op->has_restriction) {
974d1d35e2fSjeremylt     op->num_elem        = num_elem;
975d1d35e2fSjeremylt     op->has_restriction = true;  // Restriction set, but num_elem may be 0
976e15f9bd0SJeremy L Thompson   }
977bafebce1SSebastian Grimberg   CeedCall(CeedBasisReferenceCopy(basis, &(*op_field)->basis));
9782a3ff1c9SZach Atkins   if (op->num_qpts == 0 && !is_at_points) op->num_qpts = num_qpts;  // no consistent number of qpts for OperatorAtPoints
979d1d35e2fSjeremylt   op->num_fields += 1;
9802b730f8bSJeremy L Thompson   CeedCall(CeedStringAllocCopy(field_name, (char **)&(*op_field)->field_name));
981e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
982d7b241e6Sjeremylt }
983d7b241e6Sjeremylt 
984d7b241e6Sjeremylt /**
985ca94c3ddSJeremy L Thompson   @brief Get the `CeedOperator` Field of a `CeedOperator`.
98643bbe138SJeremy L Thompson 
987ca94c3ddSJeremy L Thompson   Note: Calling this function asserts that setup is complete and sets the `CeedOperator` as immutable.
988f04ea552SJeremy L Thompson 
989ca94c3ddSJeremy L Thompson   @param[in]  op                `CeedOperator`
990f74ec584SJeremy L Thompson   @param[out] num_input_fields  Variable to store number of input fields
991ca94c3ddSJeremy L Thompson   @param[out] input_fields      Variable to store input fields
992f74ec584SJeremy L Thompson   @param[out] num_output_fields Variable to store number of output fields
993ca94c3ddSJeremy L Thompson   @param[out] output_fields     Variable to store output fields
99443bbe138SJeremy L Thompson 
99543bbe138SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
99643bbe138SJeremy L Thompson 
997e9b533fbSJeremy L Thompson   @ref Advanced
99843bbe138SJeremy L Thompson **/
9992b730f8bSJeremy L Thompson int CeedOperatorGetFields(CeedOperator op, CeedInt *num_input_fields, CeedOperatorField **input_fields, CeedInt *num_output_fields,
100043bbe138SJeremy L Thompson                           CeedOperatorField **output_fields) {
10011203703bSJeremy L Thompson   bool          is_composite;
10021203703bSJeremy L Thompson   Ceed          ceed;
10031203703bSJeremy L Thompson   CeedQFunction qf;
10041203703bSJeremy L Thompson 
10051203703bSJeremy L Thompson   CeedCall(CeedOperatorGetCeed(op, &ceed));
10061203703bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
10071203703bSJeremy L Thompson   CeedCheck(!is_composite, ceed, CEED_ERROR_MINOR, "Not defined for composite operator");
10082b730f8bSJeremy L Thompson   CeedCall(CeedOperatorCheckReady(op));
100943bbe138SJeremy L Thompson 
10101203703bSJeremy L Thompson   CeedCall(CeedOperatorGetQFunction(op, &qf));
10111203703bSJeremy L Thompson   CeedCall(CeedQFunctionGetFields(qf, num_input_fields, NULL, num_output_fields, NULL));
101243bbe138SJeremy L Thompson   if (input_fields) *input_fields = op->input_fields;
101343bbe138SJeremy L Thompson   if (output_fields) *output_fields = op->output_fields;
101443bbe138SJeremy L Thompson   return CEED_ERROR_SUCCESS;
101543bbe138SJeremy L Thompson }
101643bbe138SJeremy L Thompson 
101743bbe138SJeremy L Thompson /**
1018ca94c3ddSJeremy L Thompson   @brief Set the arbitrary points in each element for a `CeedOperator` at points.
101948acf710SJeremy L Thompson 
1020ca94c3ddSJeremy L Thompson   Note: Calling this function asserts that setup is complete and sets the `CeedOperator` as immutable.
102148acf710SJeremy L Thompson 
1022ca94c3ddSJeremy L Thompson   @param[in,out] op           `CeedOperator` at points
1023ca94c3ddSJeremy L Thompson   @param[in]     rstr_points  `CeedElemRestriction` for the coordinates of each point by element
1024ca94c3ddSJeremy L Thompson   @param[in]     point_coords `CeedVector` holding coordinates of each point
102548acf710SJeremy L Thompson 
102648acf710SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
102748acf710SJeremy L Thompson 
102848acf710SJeremy L Thompson   @ref Advanced
102948acf710SJeremy L Thompson **/
103048acf710SJeremy L Thompson int CeedOperatorAtPointsSetPoints(CeedOperator op, CeedElemRestriction rstr_points, CeedVector point_coords) {
10311203703bSJeremy L Thompson   bool is_at_points, is_immutable;
10321203703bSJeremy L Thompson   Ceed ceed;
10332a3ff1c9SZach Atkins 
10341203703bSJeremy L Thompson   CeedCall(CeedOperatorGetCeed(op, &ceed));
10352a3ff1c9SZach Atkins   CeedCall(CeedOperatorIsAtPoints(op, &is_at_points));
10361203703bSJeremy L Thompson   CeedCall(CeedOperatorIsImmutable(op, &is_immutable));
10371203703bSJeremy L Thompson   CeedCheck(is_at_points, ceed, CEED_ERROR_MINOR, "Only defined for operator at points");
10381203703bSJeremy L Thompson   CeedCheck(!is_immutable, ceed, CEED_ERROR_MAJOR, "Operator cannot be changed after set as immutable");
103948acf710SJeremy L Thompson 
104048acf710SJeremy L Thompson   if (!op->first_points_rstr) {
104148acf710SJeremy L Thompson     CeedCall(CeedElemRestrictionReferenceCopy(rstr_points, &op->first_points_rstr));
104248acf710SJeremy L Thompson   } else {
104348acf710SJeremy L Thompson     bool are_compatible;
104448acf710SJeremy L Thompson 
104548acf710SJeremy L Thompson     CeedCall(CeedElemRestrictionAtPointsAreCompatible(op->first_points_rstr, rstr_points, &are_compatible));
10461203703bSJeremy L Thompson     CeedCheck(are_compatible, ceed, CEED_ERROR_INCOMPATIBLE,
1047ca94c3ddSJeremy L Thompson               "CeedElemRestriction must have compatible offsets with previously set field CeedElemRestriction");
104848acf710SJeremy L Thompson   }
104948acf710SJeremy L Thompson 
105048acf710SJeremy L Thompson   CeedCall(CeedElemRestrictionReferenceCopy(rstr_points, &op->rstr_points));
105148acf710SJeremy L Thompson   CeedCall(CeedVectorReferenceCopy(point_coords, &op->point_coords));
105248acf710SJeremy L Thompson   return CEED_ERROR_SUCCESS;
105348acf710SJeremy L Thompson }
105448acf710SJeremy L Thompson 
105548acf710SJeremy L Thompson /**
1056b594f9faSZach Atkins   @brief Get a boolean value indicating if the `CeedOperator` was created with `CeedOperatorCreateAtPoints`
1057b594f9faSZach Atkins 
1058b594f9faSZach Atkins   @param[in]  op           `CeedOperator`
1059b594f9faSZach Atkins   @param[out] is_at_points Variable to store at points status
1060b594f9faSZach Atkins 
1061b594f9faSZach Atkins   @return An error code: 0 - success, otherwise - failure
1062b594f9faSZach Atkins 
1063b594f9faSZach Atkins   @ref User
1064b594f9faSZach Atkins **/
1065b594f9faSZach Atkins int CeedOperatorIsAtPoints(CeedOperator op, bool *is_at_points) {
1066b594f9faSZach Atkins   *is_at_points = op->is_at_points;
1067b594f9faSZach Atkins   return CEED_ERROR_SUCCESS;
1068b594f9faSZach Atkins }
1069b594f9faSZach Atkins 
1070b594f9faSZach Atkins /**
1071ca94c3ddSJeremy L Thompson   @brief Get the arbitrary points in each element for a `CeedOperator` at points.
107248acf710SJeremy L Thompson 
1073ca94c3ddSJeremy L Thompson   Note: Calling this function asserts that setup is complete and sets the `CeedOperator` as immutable.
107448acf710SJeremy L Thompson 
1075ca94c3ddSJeremy L Thompson   @param[in]  op           `CeedOperator` at points
1076ca94c3ddSJeremy L Thompson   @param[out] rstr_points  Variable to hold `CeedElemRestriction` for the coordinates of each point by element
1077ca94c3ddSJeremy L Thompson   @param[out] point_coords Variable to hold `CeedVector` holding coordinates of each point
107848acf710SJeremy L Thompson 
107948acf710SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
108048acf710SJeremy L Thompson 
108148acf710SJeremy L Thompson   @ref Advanced
108248acf710SJeremy L Thompson **/
108348acf710SJeremy L Thompson int CeedOperatorAtPointsGetPoints(CeedOperator op, CeedElemRestriction *rstr_points, CeedVector *point_coords) {
10842a3ff1c9SZach Atkins   bool is_at_points;
10851203703bSJeremy L Thompson   Ceed ceed;
10862a3ff1c9SZach Atkins 
10871203703bSJeremy L Thompson   CeedCall(CeedOperatorGetCeed(op, &ceed));
10882a3ff1c9SZach Atkins   CeedCall(CeedOperatorIsAtPoints(op, &is_at_points));
10891203703bSJeremy L Thompson   CeedCheck(is_at_points, ceed, CEED_ERROR_MINOR, "Only defined for operator at points");
109048acf710SJeremy L Thompson   CeedCall(CeedOperatorCheckReady(op));
109148acf710SJeremy L Thompson 
109248acf710SJeremy L Thompson   if (rstr_points) CeedCall(CeedElemRestrictionReferenceCopy(op->rstr_points, rstr_points));
109348acf710SJeremy L Thompson   if (point_coords) CeedCall(CeedVectorReferenceCopy(op->point_coords, point_coords));
109448acf710SJeremy L Thompson   return CEED_ERROR_SUCCESS;
109548acf710SJeremy L Thompson }
109648acf710SJeremy L Thompson 
109748acf710SJeremy L Thompson /**
1098be9c6463SJeremy L Thompson   @brief Get a `CeedOperator` Field of a `CeedOperator` from its name.
1099be9c6463SJeremy L Thompson 
1100be9c6463SJeremy L Thompson   `op_field` is set to `NULL` if the field is not found.
1101de5900adSJames Wright 
1102ca94c3ddSJeremy L Thompson   Note: Calling this function asserts that setup is complete and sets the `CeedOperator` as immutable.
1103de5900adSJames Wright 
1104ca94c3ddSJeremy L Thompson   @param[in]  op         `CeedOperator`
1105ca94c3ddSJeremy L Thompson   @param[in]  field_name Name of desired `CeedOperator` Field
1106ca94c3ddSJeremy L Thompson   @param[out] op_field   `CeedOperator` Field corresponding to the name
1107de5900adSJames Wright 
1108de5900adSJames Wright   @return An error code: 0 - success, otherwise - failure
1109de5900adSJames Wright 
1110de5900adSJames Wright   @ref Advanced
1111de5900adSJames Wright **/
1112de5900adSJames Wright int CeedOperatorGetFieldByName(CeedOperator op, const char *field_name, CeedOperatorField *op_field) {
1113*6f8994e9SJeremy L Thompson   const char        *name;
1114de5900adSJames Wright   CeedInt            num_input_fields, num_output_fields;
1115de5900adSJames Wright   CeedOperatorField *input_fields, *output_fields;
1116de5900adSJames Wright 
1117be9c6463SJeremy L Thompson   *op_field = NULL;
11181c66c397SJeremy L Thompson   CeedCall(CeedOperatorGetFields(op, &num_input_fields, &input_fields, &num_output_fields, &output_fields));
1119de5900adSJames Wright   for (CeedInt i = 0; i < num_input_fields; i++) {
1120de5900adSJames Wright     CeedCall(CeedOperatorFieldGetName(input_fields[i], &name));
1121de5900adSJames Wright     if (!strcmp(name, field_name)) {
1122de5900adSJames Wright       *op_field = input_fields[i];
1123de5900adSJames Wright       return CEED_ERROR_SUCCESS;
1124de5900adSJames Wright     }
1125de5900adSJames Wright   }
1126de5900adSJames Wright   for (CeedInt i = 0; i < num_output_fields; i++) {
1127de5900adSJames Wright     CeedCall(CeedOperatorFieldGetName(output_fields[i], &name));
1128de5900adSJames Wright     if (!strcmp(name, field_name)) {
1129de5900adSJames Wright       *op_field = output_fields[i];
1130de5900adSJames Wright       return CEED_ERROR_SUCCESS;
1131de5900adSJames Wright     }
1132de5900adSJames Wright   }
1133be9c6463SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1134de5900adSJames Wright }
1135de5900adSJames Wright 
1136de5900adSJames Wright /**
1137ca94c3ddSJeremy L Thompson   @brief Get the name of a `CeedOperator` Field
113828567f8fSJeremy L Thompson 
1139ca94c3ddSJeremy L Thompson   @param[in]  op_field   `CeedOperator` Field
114028567f8fSJeremy L Thompson   @param[out] field_name Variable to store the field name
114128567f8fSJeremy L Thompson 
114228567f8fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
114328567f8fSJeremy L Thompson 
1144e9b533fbSJeremy L Thompson   @ref Advanced
114528567f8fSJeremy L Thompson **/
1146*6f8994e9SJeremy L Thompson int CeedOperatorFieldGetName(CeedOperatorField op_field, const char **field_name) {
1147*6f8994e9SJeremy L Thompson   *field_name = op_field->field_name;
114828567f8fSJeremy L Thompson   return CEED_ERROR_SUCCESS;
114928567f8fSJeremy L Thompson }
115028567f8fSJeremy L Thompson 
115128567f8fSJeremy L Thompson /**
1152ca94c3ddSJeremy L Thompson   @brief Get the `CeedElemRestriction` of a `CeedOperator` Field
115343bbe138SJeremy L Thompson 
1154ca94c3ddSJeremy L Thompson   @param[in]  op_field `CeedOperator` Field
1155ca94c3ddSJeremy L Thompson   @param[out] rstr     Variable to store `CeedElemRestriction`
115643bbe138SJeremy L Thompson 
115743bbe138SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
115843bbe138SJeremy L Thompson 
1159e9b533fbSJeremy L Thompson   @ref Advanced
116043bbe138SJeremy L Thompson **/
11612b730f8bSJeremy L Thompson int CeedOperatorFieldGetElemRestriction(CeedOperatorField op_field, CeedElemRestriction *rstr) {
1162437c7c90SJeremy L Thompson   *rstr = op_field->elem_rstr;
116343bbe138SJeremy L Thompson   return CEED_ERROR_SUCCESS;
116443bbe138SJeremy L Thompson }
116543bbe138SJeremy L Thompson 
116643bbe138SJeremy L Thompson /**
1167ca94c3ddSJeremy L Thompson   @brief Get the `CeedBasis` of a `CeedOperator` Field
116843bbe138SJeremy L Thompson 
1169ca94c3ddSJeremy L Thompson   @param[in]  op_field `CeedOperator` Field
1170ca94c3ddSJeremy L Thompson   @param[out] basis    Variable to store `CeedBasis`
117143bbe138SJeremy L Thompson 
117243bbe138SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
117343bbe138SJeremy L Thompson 
1174e9b533fbSJeremy L Thompson   @ref Advanced
117543bbe138SJeremy L Thompson **/
117643bbe138SJeremy L Thompson int CeedOperatorFieldGetBasis(CeedOperatorField op_field, CeedBasis *basis) {
117743bbe138SJeremy L Thompson   *basis = op_field->basis;
117843bbe138SJeremy L Thompson   return CEED_ERROR_SUCCESS;
117943bbe138SJeremy L Thompson }
118043bbe138SJeremy L Thompson 
118143bbe138SJeremy L Thompson /**
1182ca94c3ddSJeremy L Thompson   @brief Get the `CeedVector` of a `CeedOperator` Field
118343bbe138SJeremy L Thompson 
1184ca94c3ddSJeremy L Thompson   @param[in]  op_field `CeedOperator` Field
1185ca94c3ddSJeremy L Thompson   @param[out] vec      Variable to store `CeedVector`
118643bbe138SJeremy L Thompson 
118743bbe138SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
118843bbe138SJeremy L Thompson 
1189e9b533fbSJeremy L Thompson   @ref Advanced
119043bbe138SJeremy L Thompson **/
119143bbe138SJeremy L Thompson int CeedOperatorFieldGetVector(CeedOperatorField op_field, CeedVector *vec) {
119243bbe138SJeremy L Thompson   *vec = op_field->vec;
119343bbe138SJeremy L Thompson   return CEED_ERROR_SUCCESS;
119443bbe138SJeremy L Thompson }
119543bbe138SJeremy L Thompson 
119643bbe138SJeremy L Thompson /**
1197ab747706SJeremy L Thompson   @brief Get the data of a `CeedOperator` Field.
1198ab747706SJeremy L Thompson 
1199ab747706SJeremy L Thompson   Any arguments set as `NULL` are ignored.
1200ab747706SJeremy L Thompson 
1201ab747706SJeremy L Thompson   @param[in]  op_field   `CeedOperator` Field
1202ab747706SJeremy L Thompson   @param[out] field_name Variable to store the field name
1203ab747706SJeremy L Thompson   @param[out] rstr       Variable to store `CeedElemRestriction`
1204ab747706SJeremy L Thompson   @param[out] basis      Variable to store `CeedBasis`
1205ab747706SJeremy L Thompson   @param[out] vec        Variable to store `CeedVector`
1206ab747706SJeremy L Thompson 
1207ab747706SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1208ab747706SJeremy L Thompson 
1209ab747706SJeremy L Thompson   @ref Advanced
1210ab747706SJeremy L Thompson **/
1211*6f8994e9SJeremy L Thompson int CeedOperatorFieldGetData(CeedOperatorField op_field, const char **field_name, CeedElemRestriction *rstr, CeedBasis *basis, CeedVector *vec) {
1212ab747706SJeremy L Thompson   if (field_name) CeedCall(CeedOperatorFieldGetName(op_field, field_name));
1213ab747706SJeremy L Thompson   if (rstr) CeedCall(CeedOperatorFieldGetElemRestriction(op_field, rstr));
1214ab747706SJeremy L Thompson   if (basis) CeedCall(CeedOperatorFieldGetBasis(op_field, basis));
1215ab747706SJeremy L Thompson   if (vec) CeedCall(CeedOperatorFieldGetVector(op_field, vec));
1216ab747706SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1217ab747706SJeremy L Thompson }
1218ab747706SJeremy L Thompson 
1219ab747706SJeremy L Thompson /**
1220ca94c3ddSJeremy L Thompson   @brief Add a sub-operator to a composite `CeedOperator`
1221288c0443SJeremy L Thompson 
1222ca94c3ddSJeremy L Thompson   @param[in,out] composite_op Composite `CeedOperator`
1223ca94c3ddSJeremy L Thompson   @param[in]     sub_op       Sub-operator `CeedOperator`
122452d6035fSJeremy L Thompson 
122552d6035fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
122652d6035fSJeremy L Thompson 
12277a982d89SJeremy L. Thompson   @ref User
122852d6035fSJeremy L Thompson  */
12292b730f8bSJeremy L Thompson int CeedCompositeOperatorAddSub(CeedOperator composite_op, CeedOperator sub_op) {
12301203703bSJeremy L Thompson   bool is_immutable;
12311203703bSJeremy L Thompson   Ceed ceed;
12321203703bSJeremy L Thompson 
12331203703bSJeremy L Thompson   CeedCall(CeedOperatorGetCeed(composite_op, &ceed));
12341203703bSJeremy L Thompson   CeedCheck(composite_op->is_composite, ceed, CEED_ERROR_MINOR, "CeedOperator is not a composite operator");
12351203703bSJeremy L Thompson   CeedCheck(composite_op->num_suboperators < CEED_COMPOSITE_MAX, ceed, CEED_ERROR_UNSUPPORTED, "Cannot add additional sub-operators");
12361203703bSJeremy L Thompson   CeedCall(CeedOperatorIsImmutable(composite_op, &is_immutable));
12371203703bSJeremy L Thompson   CeedCheck(!is_immutable, ceed, CEED_ERROR_MAJOR, "Operator cannot be changed after set as immutable");
12382b730f8bSJeremy L Thompson 
12392b730f8bSJeremy L Thompson   {
12402b730f8bSJeremy L Thompson     CeedSize input_size, output_size;
12411c66c397SJeremy L Thompson 
12422b730f8bSJeremy L Thompson     CeedCall(CeedOperatorGetActiveVectorLengths(sub_op, &input_size, &output_size));
12432b730f8bSJeremy L Thompson     if (composite_op->input_size == -1) composite_op->input_size = input_size;
12442b730f8bSJeremy L Thompson     if (composite_op->output_size == -1) composite_op->output_size = output_size;
12452b730f8bSJeremy L Thompson     // Note, a size of -1 means no active vector restriction set, so no incompatibility
12461203703bSJeremy L Thompson     CeedCheck((input_size == -1 || input_size == composite_op->input_size) && (output_size == -1 || output_size == composite_op->output_size), ceed,
12471203703bSJeremy L Thompson               CEED_ERROR_MAJOR,
1248249f8407SJeremy L Thompson               "Sub-operators must have compatible dimensions; composite operator of shape (%" CeedSize_FMT ", %" CeedSize_FMT
1249249f8407SJeremy L Thompson               ") not compatible with sub-operator of "
1250249f8407SJeremy L Thompson               "shape (%" CeedSize_FMT ", %" CeedSize_FMT ")",
12512b730f8bSJeremy L Thompson               composite_op->input_size, composite_op->output_size, input_size, output_size);
12522b730f8bSJeremy L Thompson   }
12532b730f8bSJeremy L Thompson 
1254d1d35e2fSjeremylt   composite_op->sub_operators[composite_op->num_suboperators] = sub_op;
12552b730f8bSJeremy L Thompson   CeedCall(CeedOperatorReference(sub_op));
1256d1d35e2fSjeremylt   composite_op->num_suboperators++;
1257e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
125852d6035fSJeremy L Thompson }
125952d6035fSJeremy L Thompson 
126052d6035fSJeremy L Thompson /**
1261ca94c3ddSJeremy L Thompson   @brief Get the number of sub-operators associated with a `CeedOperator`
126275f0d5a4SJeremy L Thompson 
1263ca94c3ddSJeremy L Thompson   @param[in]  op               `CeedOperator`
1264ca94c3ddSJeremy L Thompson   @param[out] num_suboperators Variable to store number of sub-operators
126575f0d5a4SJeremy L Thompson 
126675f0d5a4SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
126775f0d5a4SJeremy L Thompson 
126875f0d5a4SJeremy L Thompson   @ref Backend
126975f0d5a4SJeremy L Thompson **/
1270c6ebc35dSJeremy L Thompson int CeedCompositeOperatorGetNumSub(CeedOperator op, CeedInt *num_suboperators) {
12711203703bSJeremy L Thompson   bool is_composite;
12721203703bSJeremy L Thompson   Ceed ceed;
12731203703bSJeremy L Thompson 
12741203703bSJeremy L Thompson   CeedCall(CeedOperatorGetCeed(op, &ceed));
12751203703bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
12761203703bSJeremy L Thompson   CeedCheck(is_composite, ceed, CEED_ERROR_MINOR, "Only defined for a composite operator");
127775f0d5a4SJeremy L Thompson   *num_suboperators = op->num_suboperators;
127875f0d5a4SJeremy L Thompson   return CEED_ERROR_SUCCESS;
127975f0d5a4SJeremy L Thompson }
128075f0d5a4SJeremy L Thompson 
128175f0d5a4SJeremy L Thompson /**
1282ca94c3ddSJeremy L Thompson   @brief Get the list of sub-operators associated with a `CeedOperator`
128375f0d5a4SJeremy L Thompson 
1284ca94c3ddSJeremy L Thompson   @param[in]  op             `CeedOperator`
1285ca94c3ddSJeremy L Thompson   @param[out] sub_operators  Variable to store list of sub-operators
128675f0d5a4SJeremy L Thompson 
128775f0d5a4SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
128875f0d5a4SJeremy L Thompson 
128975f0d5a4SJeremy L Thompson   @ref Backend
129075f0d5a4SJeremy L Thompson **/
1291c6ebc35dSJeremy L Thompson int CeedCompositeOperatorGetSubList(CeedOperator op, CeedOperator **sub_operators) {
12921203703bSJeremy L Thompson   bool is_composite;
12931203703bSJeremy L Thompson   Ceed ceed;
12941203703bSJeremy L Thompson 
12951203703bSJeremy L Thompson   CeedCall(CeedOperatorGetCeed(op, &ceed));
12961203703bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
12971203703bSJeremy L Thompson   CeedCheck(is_composite, ceed, CEED_ERROR_MINOR, "Only defined for a composite operator");
129875f0d5a4SJeremy L Thompson   *sub_operators = op->sub_operators;
129975f0d5a4SJeremy L Thompson   return CEED_ERROR_SUCCESS;
130075f0d5a4SJeremy L Thompson }
130175f0d5a4SJeremy L Thompson 
130275f0d5a4SJeremy L Thompson /**
1303ca94c3ddSJeremy L Thompson   @brief Check if a `CeedOperator` is ready to be used.
13044db537f9SJeremy L Thompson 
1305ca94c3ddSJeremy L Thompson   @param[in] op `CeedOperator` to check
13064db537f9SJeremy L Thompson 
13074db537f9SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
13084db537f9SJeremy L Thompson 
13094db537f9SJeremy L Thompson   @ref User
13104db537f9SJeremy L Thompson **/
13114db537f9SJeremy L Thompson int CeedOperatorCheckReady(CeedOperator op) {
13121203703bSJeremy L Thompson   bool          is_at_points, is_composite;
13134db537f9SJeremy L Thompson   Ceed          ceed;
13141203703bSJeremy L Thompson   CeedQFunction qf = NULL;
13154db537f9SJeremy L Thompson 
13162b730f8bSJeremy L Thompson   if (op->is_interface_setup) return CEED_ERROR_SUCCESS;
13174db537f9SJeremy L Thompson 
13181203703bSJeremy L Thompson   CeedCall(CeedOperatorGetCeed(op, &ceed));
13191203703bSJeremy L Thompson   CeedCall(CeedOperatorIsAtPoints(op, &is_at_points));
13201203703bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
13211203703bSJeremy L Thompson   if (!is_composite) CeedCall(CeedOperatorGetQFunction(op, &qf));
13221203703bSJeremy L Thompson   if (is_composite) {
13231203703bSJeremy L Thompson     CeedInt num_suboperators;
13241203703bSJeremy L Thompson 
13251203703bSJeremy L Thompson     CeedCall(CeedCompositeOperatorGetNumSub(op, &num_suboperators));
13261203703bSJeremy L Thompson     if (!num_suboperators) {
132743622462SJeremy L Thompson       // Empty operator setup
132843622462SJeremy L Thompson       op->input_size  = 0;
132943622462SJeremy L Thompson       op->output_size = 0;
133043622462SJeremy L Thompson     } else {
13311203703bSJeremy L Thompson       CeedOperator *sub_operators;
13321203703bSJeremy L Thompson 
13331203703bSJeremy L Thompson       CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators));
13341203703bSJeremy L Thompson       for (CeedInt i = 0; i < num_suboperators; i++) {
13351203703bSJeremy L Thompson         CeedCall(CeedOperatorCheckReady(sub_operators[i]));
13364db537f9SJeremy L Thompson       }
13372b104005SJeremy L Thompson       // Sub-operators could be modified after adding to composite operator
13382b104005SJeremy L Thompson       // Need to verify no lvec incompatibility from any changes
13392b104005SJeremy L Thompson       CeedSize input_size, output_size;
13402b730f8bSJeremy L Thompson       CeedCall(CeedOperatorGetActiveVectorLengths(op, &input_size, &output_size));
134143622462SJeremy L Thompson     }
13424db537f9SJeremy L Thompson   } else {
13431203703bSJeremy L Thompson     CeedInt num_input_fields, num_output_fields;
13441203703bSJeremy L Thompson 
13456574a04fSJeremy L Thompson     CeedCheck(op->num_fields > 0, ceed, CEED_ERROR_INCOMPLETE, "No operator fields set");
13461203703bSJeremy L Thompson     CeedCall(CeedQFunctionGetFields(qf, &num_input_fields, NULL, &num_output_fields, NULL));
13471203703bSJeremy L Thompson     CeedCheck(op->num_fields == num_input_fields + num_output_fields, ceed, CEED_ERROR_INCOMPLETE, "Not all operator fields set");
13486574a04fSJeremy L Thompson     CeedCheck(op->has_restriction, ceed, CEED_ERROR_INCOMPLETE, "At least one restriction required");
13492a3ff1c9SZach Atkins     CeedCheck(op->num_qpts > 0 || is_at_points, ceed, CEED_ERROR_INCOMPLETE,
1350ca94c3ddSJeremy L Thompson               "At least one non-collocated CeedBasis is required or the number of quadrature points must be set");
13512b730f8bSJeremy L Thompson   }
13524db537f9SJeremy L Thompson 
13534db537f9SJeremy L Thompson   // Flag as immutable and ready
13544db537f9SJeremy L Thompson   op->is_interface_setup = true;
13551203703bSJeremy L Thompson   if (qf && qf != CEED_QFUNCTION_NONE) CeedCall(CeedQFunctionSetImmutable(qf));
13561203703bSJeremy L Thompson   if (op->dqf && op->dqf != CEED_QFUNCTION_NONE) CeedCall(CeedQFunctionSetImmutable(op->dqf));
13571203703bSJeremy L Thompson   if (op->dqfT && op->dqfT != CEED_QFUNCTION_NONE) CeedCall(CeedQFunctionSetImmutable(op->dqfT));
13584db537f9SJeremy L Thompson   return CEED_ERROR_SUCCESS;
13594db537f9SJeremy L Thompson }
13604db537f9SJeremy L Thompson 
13614db537f9SJeremy L Thompson /**
1362ca94c3ddSJeremy L Thompson   @brief Get vector lengths for the active input and/or output `CeedVector` of a `CeedOperator`.
13634385fb7fSSebastian Grimberg 
1364ca94c3ddSJeremy L Thompson   Note: Lengths of `-1` indicate that the CeedOperator does not have an active input and/or output.
1365c9366a6bSJeremy L Thompson 
1366ca94c3ddSJeremy L Thompson   @param[in]  op          `CeedOperator`
1367ca94c3ddSJeremy L Thompson   @param[out] input_size  Variable to store active input vector length, or `NULL`
1368ca94c3ddSJeremy L Thompson   @param[out] output_size Variable to store active output vector length, or `NULL`
1369c9366a6bSJeremy L Thompson 
1370c9366a6bSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1371c9366a6bSJeremy L Thompson 
1372c9366a6bSJeremy L Thompson   @ref User
1373c9366a6bSJeremy L Thompson **/
13742b730f8bSJeremy L Thompson int CeedOperatorGetActiveVectorLengths(CeedOperator op, CeedSize *input_size, CeedSize *output_size) {
1375c9366a6bSJeremy L Thompson   bool is_composite;
1376c9366a6bSJeremy L Thompson 
13772b104005SJeremy L Thompson   if (input_size) *input_size = op->input_size;
13782b104005SJeremy L Thompson   if (output_size) *output_size = op->output_size;
1379c9366a6bSJeremy L Thompson 
13802b730f8bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
13812b104005SJeremy L Thompson   if (is_composite && (op->input_size == -1 || op->output_size == -1)) {
13821203703bSJeremy L Thompson     CeedInt       num_suboperators;
13831203703bSJeremy L Thompson     CeedOperator *sub_operators;
13841203703bSJeremy L Thompson 
13851203703bSJeremy L Thompson     CeedCall(CeedCompositeOperatorGetNumSub(op, &num_suboperators));
13861203703bSJeremy L Thompson     CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators));
13871203703bSJeremy L Thompson     for (CeedInt i = 0; i < num_suboperators; i++) {
1388c9366a6bSJeremy L Thompson       CeedSize sub_input_size, sub_output_size;
13891c66c397SJeremy L Thompson 
13901203703bSJeremy L Thompson       CeedCall(CeedOperatorGetActiveVectorLengths(sub_operators[i], &sub_input_size, &sub_output_size));
13912b104005SJeremy L Thompson       if (op->input_size == -1) op->input_size = sub_input_size;
13922b104005SJeremy L Thompson       if (op->output_size == -1) op->output_size = sub_output_size;
13932b104005SJeremy L Thompson       // Note, a size of -1 means no active vector restriction set, so no incompatibility
13946574a04fSJeremy L Thompson       CeedCheck((sub_input_size == -1 || sub_input_size == op->input_size) && (sub_output_size == -1 || sub_output_size == op->output_size), op->ceed,
13956574a04fSJeremy L Thompson                 CEED_ERROR_MAJOR,
1396249f8407SJeremy L Thompson                 "Sub-operators must have compatible dimensions; composite operator of shape (%" CeedSize_FMT ", %" CeedSize_FMT
1397249f8407SJeremy L Thompson                 ") not compatible with sub-operator of "
1398249f8407SJeremy L Thompson                 "shape (%" CeedSize_FMT ", %" CeedSize_FMT ")",
13992b104005SJeremy L Thompson                 op->input_size, op->output_size, input_size, output_size);
1400c9366a6bSJeremy L Thompson     }
14012b730f8bSJeremy L Thompson   }
1402c9366a6bSJeremy L Thompson   return CEED_ERROR_SUCCESS;
1403c9366a6bSJeremy L Thompson }
1404c9366a6bSJeremy L Thompson 
1405c9366a6bSJeremy L Thompson /**
1406ca94c3ddSJeremy L Thompson   @brief Set reuse of `CeedQFunction` data in `CeedOperatorLinearAssemble*()` functions.
14074385fb7fSSebastian Grimberg 
1408ca94c3ddSJeremy L Thompson   When `reuse_assembly_data = false` (default), the `CeedQFunction` associated with this `CeedOperator` is re-assembled every time a `CeedOperatorLinearAssemble*()` function is called.
1409ca94c3ddSJeremy L Thompson   When `reuse_assembly_data = true`, the `CeedQFunction` associated with this `CeedOperator` is reused between calls to @ref CeedOperatorSetQFunctionAssemblyDataUpdateNeeded().
14108b919e6bSJeremy L Thompson 
1411ca94c3ddSJeremy L Thompson   @param[in] op                  `CeedOperator`
1412beecbf24SJeremy L Thompson   @param[in] reuse_assembly_data Boolean flag setting assembly data reuse
14138b919e6bSJeremy L Thompson 
14148b919e6bSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
14158b919e6bSJeremy L Thompson 
14168b919e6bSJeremy L Thompson   @ref Advanced
14178b919e6bSJeremy L Thompson **/
14182b730f8bSJeremy L Thompson int CeedOperatorSetQFunctionAssemblyReuse(CeedOperator op, bool reuse_assembly_data) {
14198b919e6bSJeremy L Thompson   bool is_composite;
14208b919e6bSJeremy L Thompson 
14212b730f8bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
14228b919e6bSJeremy L Thompson   if (is_composite) {
14238b919e6bSJeremy L Thompson     for (CeedInt i = 0; i < op->num_suboperators; i++) {
14242b730f8bSJeremy L Thompson       CeedCall(CeedOperatorSetQFunctionAssemblyReuse(op->sub_operators[i], reuse_assembly_data));
14258b919e6bSJeremy L Thompson     }
14268b919e6bSJeremy L Thompson   } else {
14272b730f8bSJeremy L Thompson     CeedCall(CeedQFunctionAssemblyDataSetReuse(op->qf_assembled, reuse_assembly_data));
1428beecbf24SJeremy L Thompson   }
1429beecbf24SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1430beecbf24SJeremy L Thompson }
1431beecbf24SJeremy L Thompson 
1432beecbf24SJeremy L Thompson /**
1433ca94c3ddSJeremy L Thompson   @brief Mark `CeedQFunction` data as updated and the `CeedQFunction` as requiring re-assembly.
1434beecbf24SJeremy L Thompson 
1435ca94c3ddSJeremy L Thompson   @param[in] op                `CeedOperator`
14366e15d496SJeremy L Thompson   @param[in] needs_data_update Boolean flag setting assembly data reuse
1437beecbf24SJeremy L Thompson 
1438beecbf24SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1439beecbf24SJeremy L Thompson 
1440beecbf24SJeremy L Thompson   @ref Advanced
1441beecbf24SJeremy L Thompson **/
14422b730f8bSJeremy L Thompson int CeedOperatorSetQFunctionAssemblyDataUpdateNeeded(CeedOperator op, bool needs_data_update) {
1443beecbf24SJeremy L Thompson   bool is_composite;
1444beecbf24SJeremy L Thompson 
14452b730f8bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
1446beecbf24SJeremy L Thompson   if (is_composite) {
14471203703bSJeremy L Thompson     CeedInt       num_suboperators;
14481203703bSJeremy L Thompson     CeedOperator *sub_operators;
14491203703bSJeremy L Thompson 
14501203703bSJeremy L Thompson     CeedCall(CeedCompositeOperatorGetNumSub(op, &num_suboperators));
14511203703bSJeremy L Thompson     CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators));
14521203703bSJeremy L Thompson     for (CeedInt i = 0; i < num_suboperators; i++) {
14531203703bSJeremy L Thompson       CeedCall(CeedOperatorSetQFunctionAssemblyDataUpdateNeeded(sub_operators[i], needs_data_update));
1454beecbf24SJeremy L Thompson     }
1455beecbf24SJeremy L Thompson   } else {
14562b730f8bSJeremy L Thompson     CeedCall(CeedQFunctionAssemblyDataSetUpdateNeeded(op->qf_assembled, needs_data_update));
14578b919e6bSJeremy L Thompson   }
14588b919e6bSJeremy L Thompson   return CEED_ERROR_SUCCESS;
14598b919e6bSJeremy L Thompson }
14608b919e6bSJeremy L Thompson 
14618b919e6bSJeremy L Thompson /**
1462ca94c3ddSJeremy L Thompson   @brief Set name of `CeedOperator` for @ref CeedOperatorView() output
1463ea6b5821SJeremy L Thompson 
1464ca94c3ddSJeremy L Thompson   @param[in,out] op   `CeedOperator`
1465ea61e9acSJeremy L Thompson   @param[in]     name Name to set, or NULL to remove previously set name
1466ea6b5821SJeremy L Thompson 
1467ea6b5821SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1468ea6b5821SJeremy L Thompson 
1469ea6b5821SJeremy L Thompson   @ref User
1470ea6b5821SJeremy L Thompson **/
1471ea6b5821SJeremy L Thompson int CeedOperatorSetName(CeedOperator op, const char *name) {
1472ea6b5821SJeremy L Thompson   char  *name_copy;
1473ea6b5821SJeremy L Thompson   size_t name_len = name ? strlen(name) : 0;
1474ea6b5821SJeremy L Thompson 
14752b730f8bSJeremy L Thompson   CeedCall(CeedFree(&op->name));
1476ea6b5821SJeremy L Thompson   if (name_len > 0) {
14772b730f8bSJeremy L Thompson     CeedCall(CeedCalloc(name_len + 1, &name_copy));
1478ea6b5821SJeremy L Thompson     memcpy(name_copy, name, name_len);
1479ea6b5821SJeremy L Thompson     op->name = name_copy;
1480ea6b5821SJeremy L Thompson   }
1481ea6b5821SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1482ea6b5821SJeremy L Thompson }
1483ea6b5821SJeremy L Thompson 
1484ea6b5821SJeremy L Thompson /**
1485ca94c3ddSJeremy L Thompson   @brief View a `CeedOperator`
14867a982d89SJeremy L. Thompson 
1487ca94c3ddSJeremy L Thompson   @param[in] op     `CeedOperator` to view
1488ca94c3ddSJeremy L Thompson   @param[in] stream Stream to write; typically `stdout` or a file
14897a982d89SJeremy L. Thompson 
14907a982d89SJeremy L. Thompson   @return Error code: 0 - success, otherwise - failure
14917a982d89SJeremy L. Thompson 
14927a982d89SJeremy L. Thompson   @ref User
14937a982d89SJeremy L. Thompson **/
14947a982d89SJeremy L. Thompson int CeedOperatorView(CeedOperator op, FILE *stream) {
14951203703bSJeremy L Thompson   bool has_name = op->name, is_composite;
14967a982d89SJeremy L. Thompson 
14971203703bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
14981203703bSJeremy L Thompson   if (is_composite) {
14991203703bSJeremy L Thompson     CeedInt       num_suboperators;
15001203703bSJeremy L Thompson     CeedOperator *sub_operators;
15011203703bSJeremy L Thompson 
15021203703bSJeremy L Thompson     CeedCall(CeedCompositeOperatorGetNumSub(op, &num_suboperators));
15031203703bSJeremy L Thompson     CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators));
15042b730f8bSJeremy L Thompson     fprintf(stream, "Composite CeedOperator%s%s\n", has_name ? " - " : "", has_name ? op->name : "");
15057a982d89SJeremy L. Thompson 
15061203703bSJeremy L Thompson     for (CeedInt i = 0; i < num_suboperators; i++) {
15071203703bSJeremy L Thompson       has_name = sub_operators[i]->name;
15081203703bSJeremy L Thompson       fprintf(stream, "  SubOperator %" CeedInt_FMT "%s%s:\n", i, has_name ? " - " : "", has_name ? sub_operators[i]->name : "");
15091203703bSJeremy L Thompson       CeedCall(CeedOperatorSingleView(sub_operators[i], 1, stream));
15107a982d89SJeremy L. Thompson     }
15117a982d89SJeremy L. Thompson   } else {
15122b730f8bSJeremy L Thompson     fprintf(stream, "CeedOperator%s%s\n", has_name ? " - " : "", has_name ? op->name : "");
15132b730f8bSJeremy L Thompson     CeedCall(CeedOperatorSingleView(op, 0, stream));
15147a982d89SJeremy L. Thompson   }
1515e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
15167a982d89SJeremy L. Thompson }
15173bd813ffSjeremylt 
15183bd813ffSjeremylt /**
1519ca94c3ddSJeremy L Thompson   @brief Get the `Ceed` associated with a `CeedOperator`
1520b7c9bbdaSJeremy L Thompson 
1521ca94c3ddSJeremy L Thompson   @param[in]  op   `CeedOperator`
1522ca94c3ddSJeremy L Thompson   @param[out] ceed Variable to store `Ceed`
1523b7c9bbdaSJeremy L Thompson 
1524b7c9bbdaSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1525b7c9bbdaSJeremy L Thompson 
1526b7c9bbdaSJeremy L Thompson   @ref Advanced
1527b7c9bbdaSJeremy L Thompson **/
1528b7c9bbdaSJeremy L Thompson int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) {
1529b7c9bbdaSJeremy L Thompson   *ceed = op->ceed;
1530b7c9bbdaSJeremy L Thompson   return CEED_ERROR_SUCCESS;
1531b7c9bbdaSJeremy L Thompson }
1532b7c9bbdaSJeremy L Thompson 
1533b7c9bbdaSJeremy L Thompson /**
1534ca94c3ddSJeremy L Thompson   @brief Get the number of elements associated with a `CeedOperator`
1535b7c9bbdaSJeremy L Thompson 
1536ca94c3ddSJeremy L Thompson   @param[in]  op       `CeedOperator`
1537b7c9bbdaSJeremy L Thompson   @param[out] num_elem Variable to store number of elements
1538b7c9bbdaSJeremy L Thompson 
1539b7c9bbdaSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1540b7c9bbdaSJeremy L Thompson 
1541b7c9bbdaSJeremy L Thompson   @ref Advanced
1542b7c9bbdaSJeremy L Thompson **/
1543b7c9bbdaSJeremy L Thompson int CeedOperatorGetNumElements(CeedOperator op, CeedInt *num_elem) {
15441203703bSJeremy L Thompson   bool is_composite;
15451203703bSJeremy L Thompson   Ceed ceed;
15461203703bSJeremy L Thompson 
15471203703bSJeremy L Thompson   CeedCall(CeedOperatorGetCeed(op, &ceed));
15481203703bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
15491203703bSJeremy L Thompson   CeedCheck(!is_composite, ceed, CEED_ERROR_MINOR, "Not defined for composite operator");
1550b7c9bbdaSJeremy L Thompson   *num_elem = op->num_elem;
1551b7c9bbdaSJeremy L Thompson   return CEED_ERROR_SUCCESS;
1552b7c9bbdaSJeremy L Thompson }
1553b7c9bbdaSJeremy L Thompson 
1554b7c9bbdaSJeremy L Thompson /**
1555ca94c3ddSJeremy L Thompson   @brief Get the number of quadrature points associated with a `CeedOperator`
1556b7c9bbdaSJeremy L Thompson 
1557ca94c3ddSJeremy L Thompson   @param[in]  op       `CeedOperator`
1558b7c9bbdaSJeremy L Thompson   @param[out] num_qpts Variable to store vector number of quadrature points
1559b7c9bbdaSJeremy L Thompson 
1560b7c9bbdaSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1561b7c9bbdaSJeremy L Thompson 
1562b7c9bbdaSJeremy L Thompson   @ref Advanced
1563b7c9bbdaSJeremy L Thompson **/
1564b7c9bbdaSJeremy L Thompson int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *num_qpts) {
15651203703bSJeremy L Thompson   bool is_composite;
15661203703bSJeremy L Thompson   Ceed ceed;
15671203703bSJeremy L Thompson 
15681203703bSJeremy L Thompson   CeedCall(CeedOperatorGetCeed(op, &ceed));
15691203703bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
15701203703bSJeremy L Thompson   CeedCheck(!is_composite, ceed, CEED_ERROR_MINOR, "Not defined for composite operator");
1571b7c9bbdaSJeremy L Thompson   *num_qpts = op->num_qpts;
1572b7c9bbdaSJeremy L Thompson   return CEED_ERROR_SUCCESS;
1573b7c9bbdaSJeremy L Thompson }
1574b7c9bbdaSJeremy L Thompson 
1575b7c9bbdaSJeremy L Thompson /**
1576ca94c3ddSJeremy L Thompson   @brief Estimate number of FLOPs required to apply `CeedOperator` on the active `CeedVector`
15776e15d496SJeremy L Thompson 
1578ca94c3ddSJeremy L Thompson   @param[in]  op    `CeedOperator` to estimate FLOPs for
1579ea61e9acSJeremy L Thompson   @param[out] flops Address of variable to hold FLOPs estimate
15806e15d496SJeremy L Thompson 
15816e15d496SJeremy L Thompson   @ref Backend
15826e15d496SJeremy L Thompson **/
15839d36ca50SJeremy L Thompson int CeedOperatorGetFlopsEstimate(CeedOperator op, CeedSize *flops) {
15846e15d496SJeremy L Thompson   bool is_composite;
15851c66c397SJeremy L Thompson 
15862b730f8bSJeremy L Thompson   CeedCall(CeedOperatorCheckReady(op));
15876e15d496SJeremy L Thompson 
15886e15d496SJeremy L Thompson   *flops = 0;
15892b730f8bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
15906e15d496SJeremy L Thompson   if (is_composite) {
15916e15d496SJeremy L Thompson     CeedInt num_suboperators;
15921c66c397SJeremy L Thompson 
1593c6ebc35dSJeremy L Thompson     CeedCall(CeedCompositeOperatorGetNumSub(op, &num_suboperators));
15946e15d496SJeremy L Thompson     CeedOperator *sub_operators;
1595c6ebc35dSJeremy L Thompson     CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators));
15966e15d496SJeremy L Thompson 
15976e15d496SJeremy L Thompson     // FLOPs for each suboperator
15986e15d496SJeremy L Thompson     for (CeedInt i = 0; i < num_suboperators; i++) {
15999d36ca50SJeremy L Thompson       CeedSize suboperator_flops;
16001c66c397SJeremy L Thompson 
16012b730f8bSJeremy L Thompson       CeedCall(CeedOperatorGetFlopsEstimate(sub_operators[i], &suboperator_flops));
16026e15d496SJeremy L Thompson       *flops += suboperator_flops;
16036e15d496SJeremy L Thompson     }
16046e15d496SJeremy L Thompson   } else {
16051c66c397SJeremy L Thompson     CeedInt             num_input_fields, num_output_fields, num_elem = 0;
16061203703bSJeremy L Thompson     CeedQFunction       qf;
16071203703bSJeremy L Thompson     CeedQFunctionField *qf_input_fields, *qf_output_fields;
16081203703bSJeremy L Thompson     CeedOperatorField  *op_input_fields, *op_output_fields;
16091c66c397SJeremy L Thompson 
16101203703bSJeremy L Thompson     CeedCall(CeedOperatorGetQFunction(op, &qf));
16111203703bSJeremy L Thompson     CeedCall(CeedQFunctionGetFields(qf, &num_input_fields, &qf_input_fields, &num_output_fields, &qf_output_fields));
16121203703bSJeremy L Thompson     CeedCall(CeedOperatorGetFields(op, NULL, &op_input_fields, NULL, &op_output_fields));
16132b730f8bSJeremy L Thompson     CeedCall(CeedOperatorGetNumElements(op, &num_elem));
16144385fb7fSSebastian Grimberg 
16156e15d496SJeremy L Thompson     // Input FLOPs
16166e15d496SJeremy L Thompson     for (CeedInt i = 0; i < num_input_fields; i++) {
16171203703bSJeremy L Thompson       CeedVector vec;
16186e15d496SJeremy L Thompson 
16191203703bSJeremy L Thompson       CeedCall(CeedOperatorFieldGetVector(op_input_fields[i], &vec));
16201203703bSJeremy L Thompson       if (vec == CEED_VECTOR_ACTIVE) {
16211203703bSJeremy L Thompson         CeedEvalMode        eval_mode;
16221203703bSJeremy L Thompson         CeedSize            rstr_flops, basis_flops;
16231203703bSJeremy L Thompson         CeedElemRestriction rstr;
16241203703bSJeremy L Thompson         CeedBasis           basis;
16251203703bSJeremy L Thompson 
16261203703bSJeremy L Thompson         CeedCall(CeedOperatorFieldGetElemRestriction(op_input_fields[i], &rstr));
16271203703bSJeremy L Thompson         CeedCall(CeedElemRestrictionGetFlopsEstimate(rstr, CEED_NOTRANSPOSE, &rstr_flops));
1628edb2538eSJeremy L Thompson         *flops += rstr_flops;
16291203703bSJeremy L Thompson         CeedCall(CeedOperatorFieldGetBasis(op_input_fields[i], &basis));
16301203703bSJeremy L Thompson         CeedCall(CeedQFunctionFieldGetEvalMode(qf_input_fields[i], &eval_mode));
16311203703bSJeremy L Thompson         CeedCall(CeedBasisGetFlopsEstimate(basis, CEED_NOTRANSPOSE, eval_mode, &basis_flops));
16326e15d496SJeremy L Thompson         *flops += basis_flops * num_elem;
16336e15d496SJeremy L Thompson       }
16346e15d496SJeremy L Thompson     }
16356e15d496SJeremy L Thompson     // QF FLOPs
16361c66c397SJeremy L Thompson     {
16379d36ca50SJeremy L Thompson       CeedInt       num_qpts;
16389d36ca50SJeremy L Thompson       CeedSize      qf_flops;
16391203703bSJeremy L Thompson       Ceed          ceed;
16401203703bSJeremy L Thompson       CeedQFunction qf;
16411c66c397SJeremy L Thompson 
16422b730f8bSJeremy L Thompson       CeedCall(CeedOperatorGetNumQuadraturePoints(op, &num_qpts));
16431203703bSJeremy L Thompson       CeedCall(CeedOperatorGetQFunction(op, &qf));
16441203703bSJeremy L Thompson       CeedCall(CeedQFunctionGetFlopsEstimate(qf, &qf_flops));
16451203703bSJeremy L Thompson       CeedCall(CeedOperatorGetCeed(op, &ceed));
16461203703bSJeremy L Thompson       CeedCheck(qf_flops > -1, ceed, CEED_ERROR_INCOMPLETE, "Must set CeedQFunction FLOPs estimate with CeedQFunctionSetUserFlopsEstimate");
16476e15d496SJeremy L Thompson       *flops += num_elem * num_qpts * qf_flops;
16481c66c397SJeremy L Thompson     }
16491c66c397SJeremy L Thompson 
16506e15d496SJeremy L Thompson     // Output FLOPs
16516e15d496SJeremy L Thompson     for (CeedInt i = 0; i < num_output_fields; i++) {
16521203703bSJeremy L Thompson       CeedVector vec;
16536e15d496SJeremy L Thompson 
16541203703bSJeremy L Thompson       CeedCall(CeedOperatorFieldGetVector(op_output_fields[i], &vec));
16551203703bSJeremy L Thompson       if (vec == CEED_VECTOR_ACTIVE) {
16561203703bSJeremy L Thompson         CeedEvalMode        eval_mode;
16571203703bSJeremy L Thompson         CeedSize            rstr_flops, basis_flops;
16581203703bSJeremy L Thompson         CeedElemRestriction rstr;
16591203703bSJeremy L Thompson         CeedBasis           basis;
16601203703bSJeremy L Thompson 
16611203703bSJeremy L Thompson         CeedCall(CeedOperatorFieldGetElemRestriction(op_output_fields[i], &rstr));
16621203703bSJeremy L Thompson         CeedCall(CeedElemRestrictionGetFlopsEstimate(rstr, CEED_TRANSPOSE, &rstr_flops));
1663edb2538eSJeremy L Thompson         *flops += rstr_flops;
16641203703bSJeremy L Thompson         CeedCall(CeedOperatorFieldGetBasis(op_output_fields[i], &basis));
16651203703bSJeremy L Thompson         CeedCall(CeedQFunctionFieldGetEvalMode(qf_output_fields[i], &eval_mode));
16661203703bSJeremy L Thompson         CeedCall(CeedBasisGetFlopsEstimate(basis, CEED_TRANSPOSE, eval_mode, &basis_flops));
16676e15d496SJeremy L Thompson         *flops += basis_flops * num_elem;
16686e15d496SJeremy L Thompson       }
16696e15d496SJeremy L Thompson     }
16706e15d496SJeremy L Thompson   }
16716e15d496SJeremy L Thompson   return CEED_ERROR_SUCCESS;
16726e15d496SJeremy L Thompson }
16736e15d496SJeremy L Thompson 
16746e15d496SJeremy L Thompson /**
1675ca94c3ddSJeremy L Thompson   @brief Get `CeedQFunction` global context for a `CeedOperator`.
16769fd66db6SSebastian Grimberg 
1677ca94c3ddSJeremy L Thompson   The caller is responsible for destroying `ctx` returned from this function via @ref CeedQFunctionContextDestroy().
1678512bb800SJeremy L Thompson 
1679ca94c3ddSJeremy 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`.
1680ca94c3ddSJeremy L Thompson         This `CeedQFunctionContext` will be destroyed if `ctx` is the only reference to this `CeedQFunctionContext`.
16810126412dSJeremy L Thompson 
1682ca94c3ddSJeremy L Thompson   @param[in]  op  `CeedOperator`
1683ca94c3ddSJeremy L Thompson   @param[out] ctx Variable to store `CeedQFunctionContext`
16840126412dSJeremy L Thompson 
16850126412dSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
16860126412dSJeremy L Thompson 
1687859c15bbSJames Wright   @ref Advanced
16880126412dSJeremy L Thompson **/
16890126412dSJeremy L Thompson int CeedOperatorGetContext(CeedOperator op, CeedQFunctionContext *ctx) {
16901203703bSJeremy L Thompson   bool                 is_composite;
16911203703bSJeremy L Thompson   Ceed                 ceed;
16921203703bSJeremy L Thompson   CeedQFunction        qf;
16931203703bSJeremy L Thompson   CeedQFunctionContext qf_ctx;
16941203703bSJeremy L Thompson 
16951203703bSJeremy L Thompson   CeedCall(CeedOperatorGetCeed(op, &ceed));
16961203703bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
16971203703bSJeremy L Thompson   CeedCheck(!is_composite, ceed, CEED_ERROR_INCOMPATIBLE, "Cannot retrieve CeedQFunctionContext for composite operator");
16981203703bSJeremy L Thompson   CeedCall(CeedOperatorGetQFunction(op, &qf));
16991203703bSJeremy L Thompson   CeedCall(CeedQFunctionGetInnerContext(qf, &qf_ctx));
17001203703bSJeremy L Thompson   if (qf_ctx) CeedCall(CeedQFunctionContextReferenceCopy(qf_ctx, ctx));
17010126412dSJeremy L Thompson   return CEED_ERROR_SUCCESS;
17020126412dSJeremy L Thompson }
17030126412dSJeremy L Thompson 
17040126412dSJeremy L Thompson /**
1705ca94c3ddSJeremy L Thompson   @brief Get label for a registered `CeedQFunctionContext` field, or `NULL` if no field has been registered with this `field_name`.
17063668ca4bSJeremy L Thompson 
1707ca94c3ddSJeremy L Thompson   Fields are registered via `CeedQFunctionContextRegister*()` functions (eg. @ref CeedQFunctionContextRegisterDouble()).
1708859c15bbSJames Wright 
1709ca94c3ddSJeremy L Thompson   @param[in]  op          `CeedOperator`
17103668ca4bSJeremy L Thompson   @param[in]  field_name  Name of field to retrieve label
17113668ca4bSJeremy L Thompson   @param[out] field_label Variable to field label
17123668ca4bSJeremy L Thompson 
17133668ca4bSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
17143668ca4bSJeremy L Thompson 
17153668ca4bSJeremy L Thompson   @ref User
17163668ca4bSJeremy L Thompson **/
171717b0d5c6SJeremy L Thompson int CeedOperatorGetContextFieldLabel(CeedOperator op, const char *field_name, CeedContextFieldLabel *field_label) {
17181c66c397SJeremy L Thompson   bool is_composite, field_found = false;
17191c66c397SJeremy L Thompson 
17202b730f8bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
17212b730f8bSJeremy L Thompson 
17223668ca4bSJeremy L Thompson   if (is_composite) {
1723a98a090bSJeremy L Thompson     // Composite operator
1724a98a090bSJeremy L Thompson     // -- Check if composite label already created
17253668ca4bSJeremy L Thompson     for (CeedInt i = 0; i < op->num_context_labels; i++) {
17263668ca4bSJeremy L Thompson       if (!strcmp(op->context_labels[i]->name, field_name)) {
17273668ca4bSJeremy L Thompson         *field_label = op->context_labels[i];
17283668ca4bSJeremy L Thompson         return CEED_ERROR_SUCCESS;
17293668ca4bSJeremy L Thompson       }
17303668ca4bSJeremy L Thompson     }
17313668ca4bSJeremy L Thompson 
1732a98a090bSJeremy L Thompson     // -- Create composite label if needed
17333668ca4bSJeremy L Thompson     CeedInt               num_sub;
17343668ca4bSJeremy L Thompson     CeedOperator         *sub_operators;
17353668ca4bSJeremy L Thompson     CeedContextFieldLabel new_field_label;
17363668ca4bSJeremy L Thompson 
17372b730f8bSJeremy L Thompson     CeedCall(CeedCalloc(1, &new_field_label));
1738c6ebc35dSJeremy L Thompson     CeedCall(CeedCompositeOperatorGetNumSub(op, &num_sub));
1739c6ebc35dSJeremy L Thompson     CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators));
17402b730f8bSJeremy L Thompson     CeedCall(CeedCalloc(num_sub, &new_field_label->sub_labels));
17413668ca4bSJeremy L Thompson     new_field_label->num_sub_labels = num_sub;
17423668ca4bSJeremy L Thompson 
17433668ca4bSJeremy L Thompson     for (CeedInt i = 0; i < num_sub; i++) {
17443668ca4bSJeremy L Thompson       if (sub_operators[i]->qf->ctx) {
17453668ca4bSJeremy L Thompson         CeedContextFieldLabel new_field_label_i;
17461c66c397SJeremy L Thompson 
17472b730f8bSJeremy L Thompson         CeedCall(CeedQFunctionContextGetFieldLabel(sub_operators[i]->qf->ctx, field_name, &new_field_label_i));
17483668ca4bSJeremy L Thompson         if (new_field_label_i) {
1749a98a090bSJeremy L Thompson           field_found                    = true;
17503668ca4bSJeremy L Thompson           new_field_label->sub_labels[i] = new_field_label_i;
17513668ca4bSJeremy L Thompson           new_field_label->name          = new_field_label_i->name;
17523668ca4bSJeremy L Thompson           new_field_label->description   = new_field_label_i->description;
17532b730f8bSJeremy L Thompson           if (new_field_label->type && new_field_label->type != new_field_label_i->type) {
17547bfe0f0eSJeremy L Thompson             // LCOV_EXCL_START
17552b730f8bSJeremy L Thompson             CeedCall(CeedFree(&new_field_label));
17562b730f8bSJeremy L Thompson             return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE, "Incompatible field types on sub-operator contexts. %s != %s",
17572b730f8bSJeremy L Thompson                              CeedContextFieldTypes[new_field_label->type], CeedContextFieldTypes[new_field_label_i->type]);
17587bfe0f0eSJeremy L Thompson             // LCOV_EXCL_STOP
17597bfe0f0eSJeremy L Thompson           } else {
17607bfe0f0eSJeremy L Thompson             new_field_label->type = new_field_label_i->type;
17617bfe0f0eSJeremy L Thompson           }
17622b730f8bSJeremy L Thompson           if (new_field_label->num_values != 0 && new_field_label->num_values != new_field_label_i->num_values) {
17637bfe0f0eSJeremy L Thompson             // LCOV_EXCL_START
17641203703bSJeremy L Thompson             Ceed ceed;
17651203703bSJeremy L Thompson 
17662b730f8bSJeremy L Thompson             CeedCall(CeedFree(&new_field_label));
17671203703bSJeremy L Thompson             CeedCall(CeedOperatorGetCeed(op, &ceed));
17681203703bSJeremy L Thompson             return CeedError(ceed, CEED_ERROR_INCOMPATIBLE, "Incompatible field number of values on sub-operator contexts. %zu != %zu",
17697bfe0f0eSJeremy L Thompson                              new_field_label->num_values, new_field_label_i->num_values);
17707bfe0f0eSJeremy L Thompson             // LCOV_EXCL_STOP
17717bfe0f0eSJeremy L Thompson           } else {
17727bfe0f0eSJeremy L Thompson             new_field_label->num_values = new_field_label_i->num_values;
17737bfe0f0eSJeremy L Thompson           }
17743668ca4bSJeremy L Thompson         }
17753668ca4bSJeremy L Thompson       }
17763668ca4bSJeremy L Thompson     }
1777a98a090bSJeremy L Thompson     // -- Cleanup if field was found
1778a98a090bSJeremy L Thompson     if (field_found) {
1779a98a090bSJeremy L Thompson       *field_label = new_field_label;
1780a98a090bSJeremy L Thompson     } else {
17813668ca4bSJeremy L Thompson       // LCOV_EXCL_START
17822b730f8bSJeremy L Thompson       CeedCall(CeedFree(&new_field_label->sub_labels));
17832b730f8bSJeremy L Thompson       CeedCall(CeedFree(&new_field_label));
17843668ca4bSJeremy L Thompson       *field_label = NULL;
17853668ca4bSJeremy L Thompson       // LCOV_EXCL_STOP
17865ac9af79SJeremy L Thompson     }
17875ac9af79SJeremy L Thompson   } else {
17881203703bSJeremy L Thompson     CeedQFunction        qf;
17891203703bSJeremy L Thompson     CeedQFunctionContext ctx;
17901203703bSJeremy L Thompson 
1791a98a090bSJeremy L Thompson     // Single, non-composite operator
17921203703bSJeremy L Thompson     CeedCall(CeedOperatorGetQFunction(op, &qf));
17931203703bSJeremy L Thompson     CeedCall(CeedQFunctionGetInnerContext(qf, &ctx));
17941203703bSJeremy L Thompson     if (ctx) {
17951203703bSJeremy L Thompson       CeedCall(CeedQFunctionContextGetFieldLabel(ctx, field_name, field_label));
1796a98a090bSJeremy L Thompson     } else {
1797a98a090bSJeremy L Thompson       *field_label = NULL;
1798a98a090bSJeremy L Thompson     }
17995ac9af79SJeremy L Thompson   }
18005ac9af79SJeremy L Thompson 
18015ac9af79SJeremy L Thompson   // Set label in operator
18025ac9af79SJeremy L Thompson   if (*field_label) {
18035ac9af79SJeremy L Thompson     (*field_label)->from_op = true;
18045ac9af79SJeremy L Thompson 
18053668ca4bSJeremy L Thompson     // Move new composite label to operator
18063668ca4bSJeremy L Thompson     if (op->num_context_labels == 0) {
18072b730f8bSJeremy L Thompson       CeedCall(CeedCalloc(1, &op->context_labels));
18083668ca4bSJeremy L Thompson       op->max_context_labels = 1;
18093668ca4bSJeremy L Thompson     } else if (op->num_context_labels == op->max_context_labels) {
18102b730f8bSJeremy L Thompson       CeedCall(CeedRealloc(2 * op->num_context_labels, &op->context_labels));
18113668ca4bSJeremy L Thompson       op->max_context_labels *= 2;
18123668ca4bSJeremy L Thompson     }
18135ac9af79SJeremy L Thompson     op->context_labels[op->num_context_labels] = *field_label;
18143668ca4bSJeremy L Thompson     op->num_context_labels++;
18153668ca4bSJeremy L Thompson   }
18163668ca4bSJeremy L Thompson   return CEED_ERROR_SUCCESS;
18173668ca4bSJeremy L Thompson }
18183668ca4bSJeremy L Thompson 
18193668ca4bSJeremy L Thompson /**
1820ca94c3ddSJeremy L Thompson   @brief Set `CeedQFunctionContext` field holding double precision values.
18214385fb7fSSebastian Grimberg 
1822ca94c3ddSJeremy L Thompson   For composite operators, the values are set in all sub-operator `CeedQFunctionContext` that have a matching `field_name`.
1823d8dd9a91SJeremy L Thompson 
1824ca94c3ddSJeremy L Thompson   @param[in,out] op          `CeedOperator`
18252788fa27SJeremy L Thompson   @param[in]     field_label Label of field to set
1826ea61e9acSJeremy L Thompson   @param[in]     values      Values to set
1827d8dd9a91SJeremy L Thompson 
1828d8dd9a91SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1829d8dd9a91SJeremy L Thompson 
1830d8dd9a91SJeremy L Thompson   @ref User
1831d8dd9a91SJeremy L Thompson **/
183217b0d5c6SJeremy L Thompson int CeedOperatorSetContextDouble(CeedOperator op, CeedContextFieldLabel field_label, double *values) {
18332b730f8bSJeremy L Thompson   return CeedOperatorContextSetGeneric(op, field_label, CEED_CONTEXT_FIELD_DOUBLE, values);
1834d8dd9a91SJeremy L Thompson }
1835d8dd9a91SJeremy L Thompson 
1836d8dd9a91SJeremy L Thompson /**
1837ca94c3ddSJeremy L Thompson   @brief Get `CeedQFunctionContext` field holding double precision values, read-only.
18384385fb7fSSebastian Grimberg 
1839ca94c3ddSJeremy L Thompson   For composite operators, the values correspond to the first sub-operator `CeedQFunctionContext` that has a matching `field_name`.
18402788fa27SJeremy L Thompson 
1841ca94c3ddSJeremy L Thompson   @param[in]  op          `CeedOperator`
18422788fa27SJeremy L Thompson   @param[in]  field_label Label of field to get
18432788fa27SJeremy L Thompson   @param[out] num_values  Number of values in the field label
18442788fa27SJeremy L Thompson   @param[out] values      Pointer to context values
18452788fa27SJeremy L Thompson 
18462788fa27SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
18472788fa27SJeremy L Thompson 
18482788fa27SJeremy L Thompson   @ref User
18492788fa27SJeremy L Thompson **/
185017b0d5c6SJeremy L Thompson int CeedOperatorGetContextDoubleRead(CeedOperator op, CeedContextFieldLabel field_label, size_t *num_values, const double **values) {
18512788fa27SJeremy L Thompson   return CeedOperatorContextGetGenericRead(op, field_label, CEED_CONTEXT_FIELD_DOUBLE, num_values, values);
18522788fa27SJeremy L Thompson }
18532788fa27SJeremy L Thompson 
18542788fa27SJeremy L Thompson /**
1855ca94c3ddSJeremy L Thompson   @brief Restore `CeedQFunctionContext` field holding double precision values, read-only.
18562788fa27SJeremy L Thompson 
1857ca94c3ddSJeremy L Thompson   @param[in]  op          `CeedOperator`
18582788fa27SJeremy L Thompson   @param[in]  field_label Label of field to restore
18592788fa27SJeremy L Thompson   @param[out] values      Pointer to context values
18602788fa27SJeremy L Thompson 
18612788fa27SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
18622788fa27SJeremy L Thompson 
18632788fa27SJeremy L Thompson   @ref User
18642788fa27SJeremy L Thompson **/
186517b0d5c6SJeremy L Thompson int CeedOperatorRestoreContextDoubleRead(CeedOperator op, CeedContextFieldLabel field_label, const double **values) {
18662788fa27SJeremy L Thompson   return CeedOperatorContextRestoreGenericRead(op, field_label, CEED_CONTEXT_FIELD_DOUBLE, values);
18672788fa27SJeremy L Thompson }
18682788fa27SJeremy L Thompson 
18692788fa27SJeremy L Thompson /**
1870ca94c3ddSJeremy L Thompson   @brief Set `CeedQFunctionContext` field holding `int32` values.
18714385fb7fSSebastian Grimberg 
1872ca94c3ddSJeremy L Thompson   For composite operators, the values are set in all sub-operator `CeedQFunctionContext` that have a matching `field_name`.
1873d8dd9a91SJeremy L Thompson 
1874ca94c3ddSJeremy L Thompson   @param[in,out] op          `CeedOperator`
1875ea61e9acSJeremy L Thompson   @param[in]     field_label Label of field to set
1876ea61e9acSJeremy L Thompson   @param[in]     values      Values to set
1877d8dd9a91SJeremy L Thompson 
1878d8dd9a91SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1879d8dd9a91SJeremy L Thompson 
1880d8dd9a91SJeremy L Thompson   @ref User
1881d8dd9a91SJeremy L Thompson **/
188223dbfd29SJeremy L Thompson int CeedOperatorSetContextInt32(CeedOperator op, CeedContextFieldLabel field_label, int32_t *values) {
18832b730f8bSJeremy L Thompson   return CeedOperatorContextSetGeneric(op, field_label, CEED_CONTEXT_FIELD_INT32, values);
1884d8dd9a91SJeremy L Thompson }
1885d8dd9a91SJeremy L Thompson 
1886d8dd9a91SJeremy L Thompson /**
1887ca94c3ddSJeremy L Thompson   @brief Get `CeedQFunctionContext` field holding `int32` values, read-only.
18884385fb7fSSebastian Grimberg 
1889ca94c3ddSJeremy L Thompson   For composite operators, the values correspond to the first sub-operator `CeedQFunctionContext` that has a matching `field_name`.
18902788fa27SJeremy L Thompson 
1891ca94c3ddSJeremy L Thompson   @param[in]  op          `CeedOperator`
18922788fa27SJeremy L Thompson   @param[in]  field_label Label of field to get
1893ca94c3ddSJeremy L Thompson   @param[out] num_values  Number of `int32` values in `values`
18942788fa27SJeremy L Thompson   @param[out] values      Pointer to context values
18952788fa27SJeremy L Thompson 
18962788fa27SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
18972788fa27SJeremy L Thompson 
18982788fa27SJeremy L Thompson   @ref User
18992788fa27SJeremy L Thompson **/
190023dbfd29SJeremy L Thompson int CeedOperatorGetContextInt32Read(CeedOperator op, CeedContextFieldLabel field_label, size_t *num_values, const int32_t **values) {
19012788fa27SJeremy L Thompson   return CeedOperatorContextGetGenericRead(op, field_label, CEED_CONTEXT_FIELD_INT32, num_values, values);
19022788fa27SJeremy L Thompson }
19032788fa27SJeremy L Thompson 
19042788fa27SJeremy L Thompson /**
1905ca94c3ddSJeremy L Thompson   @brief Restore `CeedQFunctionContext` field holding `int32` values, read-only.
19062788fa27SJeremy L Thompson 
1907ca94c3ddSJeremy L Thompson   @param[in]  op          `CeedOperator`
19082788fa27SJeremy L Thompson   @param[in]  field_label Label of field to get
19092788fa27SJeremy L Thompson   @param[out] values      Pointer to context values
19102788fa27SJeremy L Thompson 
19112788fa27SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
19122788fa27SJeremy L Thompson 
19132788fa27SJeremy L Thompson   @ref User
19142788fa27SJeremy L Thompson **/
191523dbfd29SJeremy L Thompson int CeedOperatorRestoreContextInt32Read(CeedOperator op, CeedContextFieldLabel field_label, const int32_t **values) {
19162788fa27SJeremy L Thompson   return CeedOperatorContextRestoreGenericRead(op, field_label, CEED_CONTEXT_FIELD_INT32, values);
19172788fa27SJeremy L Thompson }
19182788fa27SJeremy L Thompson 
19192788fa27SJeremy L Thompson /**
1920ca94c3ddSJeremy L Thompson   @brief Set `CeedQFunctionContext` field holding boolean values.
19215b6ec284SJeremy L Thompson 
1922ca94c3ddSJeremy L Thompson   For composite operators, the values are set in all sub-operator `CeedQFunctionContext` that have a matching `field_name`.
19235b6ec284SJeremy L Thompson 
1924ca94c3ddSJeremy L Thompson   @param[in,out] op          `CeedOperator`
19255b6ec284SJeremy L Thompson   @param[in]     field_label Label of field to set
19265b6ec284SJeremy L Thompson   @param[in]     values      Values to set
19275b6ec284SJeremy L Thompson 
19285b6ec284SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
19295b6ec284SJeremy L Thompson 
19305b6ec284SJeremy L Thompson   @ref User
19315b6ec284SJeremy L Thompson **/
19325b6ec284SJeremy L Thompson int CeedOperatorSetContextBoolean(CeedOperator op, CeedContextFieldLabel field_label, bool *values) {
19335b6ec284SJeremy L Thompson   return CeedOperatorContextSetGeneric(op, field_label, CEED_CONTEXT_FIELD_BOOL, values);
19345b6ec284SJeremy L Thompson }
19355b6ec284SJeremy L Thompson 
19365b6ec284SJeremy L Thompson /**
1937ca94c3ddSJeremy L Thompson   @brief Get `CeedQFunctionContext` field holding boolean values, read-only.
19385b6ec284SJeremy L Thompson 
1939ca94c3ddSJeremy L Thompson   For composite operators, the values correspond to the first sub-operator `CeedQFunctionContext` that has a matching `field_name`.
19405b6ec284SJeremy L Thompson 
1941ca94c3ddSJeremy L Thompson   @param[in]  op          `CeedOperator`
19425b6ec284SJeremy L Thompson   @param[in]  field_label Label of field to get
1943ca94c3ddSJeremy L Thompson   @param[out] num_values  Number of boolean values in `values`
19445b6ec284SJeremy L Thompson   @param[out] values      Pointer to context values
19455b6ec284SJeremy L Thompson 
19465b6ec284SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
19475b6ec284SJeremy L Thompson 
19485b6ec284SJeremy L Thompson   @ref User
19495b6ec284SJeremy L Thompson **/
19505b6ec284SJeremy L Thompson int CeedOperatorGetContextBooleanRead(CeedOperator op, CeedContextFieldLabel field_label, size_t *num_values, const bool **values) {
19515b6ec284SJeremy L Thompson   return CeedOperatorContextGetGenericRead(op, field_label, CEED_CONTEXT_FIELD_BOOL, num_values, values);
19525b6ec284SJeremy L Thompson }
19535b6ec284SJeremy L Thompson 
19545b6ec284SJeremy L Thompson /**
1955ca94c3ddSJeremy L Thompson   @brief Restore `CeedQFunctionContext` field holding boolean values, read-only.
19565b6ec284SJeremy L Thompson 
1957ca94c3ddSJeremy L Thompson   @param[in]  op          `CeedOperator`
19585b6ec284SJeremy L Thompson   @param[in]  field_label Label of field to get
19595b6ec284SJeremy L Thompson   @param[out] values      Pointer to context values
19605b6ec284SJeremy L Thompson 
19615b6ec284SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
19625b6ec284SJeremy L Thompson 
19635b6ec284SJeremy L Thompson   @ref User
19645b6ec284SJeremy L Thompson **/
19655b6ec284SJeremy L Thompson int CeedOperatorRestoreContextBooleanRead(CeedOperator op, CeedContextFieldLabel field_label, const bool **values) {
19665b6ec284SJeremy L Thompson   return CeedOperatorContextRestoreGenericRead(op, field_label, CEED_CONTEXT_FIELD_BOOL, values);
19675b6ec284SJeremy L Thompson }
19685b6ec284SJeremy L Thompson 
19695b6ec284SJeremy L Thompson /**
1970ca94c3ddSJeremy L Thompson   @brief Apply `CeedOperator` to a `CeedVector`.
1971d7b241e6Sjeremylt 
1972ea61e9acSJeremy L Thompson   This computes the action of the operator on the specified (active) input, yielding its (active) output.
1973ca94c3ddSJeremy L Thompson   All inputs and outputs must be specified using @ref CeedOperatorSetField().
1974d7b241e6Sjeremylt 
1975ca94c3ddSJeremy L Thompson   Note: Calling this function asserts that setup is complete and sets the `CeedOperator` as immutable.
1976f04ea552SJeremy L Thompson 
1977ca94c3ddSJeremy L Thompson   @param[in]  op      `CeedOperator` to apply
1978ca94c3ddSJeremy L Thompson   @param[in]  in      `CeedVector` containing input state or @ref CEED_VECTOR_NONE if there are no active inputs
1979ca94c3ddSJeremy 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
1980ca94c3ddSJeremy L Thompson   @param[in]  request Address of @ref CeedRequest for non-blocking completion, else @ref CEED_REQUEST_IMMEDIATE
1981b11c1e72Sjeremylt 
1982b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
1983dfdf5a53Sjeremylt 
19847a982d89SJeremy L. Thompson   @ref User
1985b11c1e72Sjeremylt **/
19862b730f8bSJeremy L Thompson int CeedOperatorApply(CeedOperator op, CeedVector in, CeedVector out, CeedRequest *request) {
19871203703bSJeremy L Thompson   bool is_composite;
19881203703bSJeremy L Thompson 
19892b730f8bSJeremy L Thompson   CeedCall(CeedOperatorCheckReady(op));
1990d7b241e6Sjeremylt 
19911203703bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
19921203703bSJeremy L Thompson   if (is_composite) {
1993250756a7Sjeremylt     // Composite Operator
1994250756a7Sjeremylt     if (op->ApplyComposite) {
19952b730f8bSJeremy L Thompson       CeedCall(op->ApplyComposite(op, in, out, request));
1996250756a7Sjeremylt     } else {
1997d1d35e2fSjeremylt       CeedInt       num_suboperators;
1998d1d35e2fSjeremylt       CeedOperator *sub_operators;
19991c66c397SJeremy L Thompson 
20001c66c397SJeremy L Thompson       CeedCall(CeedCompositeOperatorGetNumSub(op, &num_suboperators));
2001c6ebc35dSJeremy L Thompson       CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators));
2002250756a7Sjeremylt 
2003250756a7Sjeremylt       // Zero all output vectors
20043ca2b39bSJeremy L Thompson       if (out != CEED_VECTOR_NONE) CeedCall(CeedVectorSetValue(out, 0.0));
2005d1d35e2fSjeremylt       for (CeedInt i = 0; i < num_suboperators; i++) {
20061203703bSJeremy L Thompson         CeedInt            num_output_fields;
20071203703bSJeremy L Thompson         CeedOperatorField *output_fields;
20081c66c397SJeremy L Thompson 
20091203703bSJeremy L Thompson         CeedCall(CeedOperatorGetFields(sub_operators[i], NULL, NULL, &num_output_fields, &output_fields));
20101203703bSJeremy L Thompson         for (CeedInt j = 0; j < num_output_fields; j++) {
20111203703bSJeremy L Thompson           CeedVector vec;
20121203703bSJeremy L Thompson 
20131203703bSJeremy L Thompson           CeedCall(CeedOperatorFieldGetVector(output_fields[j], &vec));
2014250756a7Sjeremylt           if (vec != CEED_VECTOR_ACTIVE && vec != CEED_VECTOR_NONE) {
20152b730f8bSJeremy L Thompson             CeedCall(CeedVectorSetValue(vec, 0.0));
2016250756a7Sjeremylt           }
2017250756a7Sjeremylt         }
2018250756a7Sjeremylt       }
2019250756a7Sjeremylt       // Apply
2020f754c177SSebastian Grimberg       for (CeedInt i = 0; i < num_suboperators; i++) {
2021f754c177SSebastian Grimberg         CeedCall(CeedOperatorApplyAdd(sub_operators[i], in, out, request));
2022cae8b89aSjeremylt       }
2023cae8b89aSjeremylt     }
20243ca2b39bSJeremy L Thompson   } else {
20253ca2b39bSJeremy L Thompson     // Standard Operator
20263ca2b39bSJeremy L Thompson     if (op->Apply) {
20273ca2b39bSJeremy L Thompson       CeedCall(op->Apply(op, in, out, request));
20283ca2b39bSJeremy L Thompson     } else {
20291203703bSJeremy L Thompson       CeedInt            num_output_fields;
20301203703bSJeremy L Thompson       CeedOperatorField *output_fields;
20311203703bSJeremy L Thompson 
20321203703bSJeremy L Thompson       CeedCall(CeedOperatorGetFields(op, NULL, NULL, &num_output_fields, &output_fields));
20333ca2b39bSJeremy L Thompson       // Zero all output vectors
20341203703bSJeremy L Thompson       for (CeedInt i = 0; i < num_output_fields; i++) {
20351203703bSJeremy L Thompson         CeedVector vec;
20361c66c397SJeremy L Thompson 
20371203703bSJeremy L Thompson         CeedCall(CeedOperatorFieldGetVector(output_fields[i], &vec));
20383ca2b39bSJeremy L Thompson         if (vec == CEED_VECTOR_ACTIVE) vec = out;
20393ca2b39bSJeremy L Thompson         if (vec != CEED_VECTOR_NONE) CeedCall(CeedVectorSetValue(vec, 0.0));
20403ca2b39bSJeremy L Thompson       }
20413ca2b39bSJeremy L Thompson       // Apply
20421203703bSJeremy L Thompson       if (op->num_elem > 0) CeedCall(op->ApplyAdd(op, in, out, request));
20433ca2b39bSJeremy L Thompson     }
2044250756a7Sjeremylt   }
2045e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2046cae8b89aSjeremylt }
2047cae8b89aSjeremylt 
2048cae8b89aSjeremylt /**
2049ca94c3ddSJeremy L Thompson   @brief Apply `CeedOperator` to a `CeedVector` and add result to output `CeedVector`.
2050cae8b89aSjeremylt 
2051ea61e9acSJeremy L Thompson   This computes the action of the operator on the specified (active) input, yielding its (active) output.
2052ca94c3ddSJeremy L Thompson   All inputs and outputs must be specified using @ref CeedOperatorSetField().
2053cae8b89aSjeremylt 
2054ca94c3ddSJeremy L Thompson   @param[in]  op      `CeedOperator` to apply
2055ca94c3ddSJeremy L Thompson   @param[in]  in      `CeedVector` containing input state or @ref CEED_VECTOR_NONE if there are no active inputs
2056ca94c3ddSJeremy 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
2057ca94c3ddSJeremy L Thompson   @param[in]  request Address of @ref CeedRequest for non-blocking completion, else @ref CEED_REQUEST_IMMEDIATE
2058cae8b89aSjeremylt 
2059cae8b89aSjeremylt   @return An error code: 0 - success, otherwise - failure
2060cae8b89aSjeremylt 
20617a982d89SJeremy L. Thompson   @ref User
2062cae8b89aSjeremylt **/
20632b730f8bSJeremy L Thompson int CeedOperatorApplyAdd(CeedOperator op, CeedVector in, CeedVector out, CeedRequest *request) {
20641203703bSJeremy L Thompson   bool is_composite;
20651203703bSJeremy L Thompson 
20662b730f8bSJeremy L Thompson   CeedCall(CeedOperatorCheckReady(op));
2067cae8b89aSjeremylt 
20681203703bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
20691203703bSJeremy L Thompson   if (is_composite) {
2070250756a7Sjeremylt     // Composite Operator
2071250756a7Sjeremylt     if (op->ApplyAddComposite) {
20722b730f8bSJeremy L Thompson       CeedCall(op->ApplyAddComposite(op, in, out, request));
2073cae8b89aSjeremylt     } else {
2074d1d35e2fSjeremylt       CeedInt       num_suboperators;
2075d1d35e2fSjeremylt       CeedOperator *sub_operators;
2076250756a7Sjeremylt 
20771c66c397SJeremy L Thompson       CeedCall(CeedCompositeOperatorGetNumSub(op, &num_suboperators));
20781c66c397SJeremy L Thompson       CeedCall(CeedCompositeOperatorGetSubList(op, &sub_operators));
2079d1d35e2fSjeremylt       for (CeedInt i = 0; i < num_suboperators; i++) {
20802b730f8bSJeremy L Thompson         CeedCall(CeedOperatorApplyAdd(sub_operators[i], in, out, request));
20811d7d2407SJeremy L Thompson       }
2082250756a7Sjeremylt     }
20831203703bSJeremy L Thompson   } else if (op->num_elem > 0) {
20843ca2b39bSJeremy L Thompson     // Standard Operator
20853ca2b39bSJeremy L Thompson     CeedCall(op->ApplyAdd(op, in, out, request));
2086250756a7Sjeremylt   }
2087e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2088d7b241e6Sjeremylt }
2089d7b241e6Sjeremylt 
2090d7b241e6Sjeremylt /**
2091ca94c3ddSJeremy L Thompson   @brief Destroy a `CeedOperator`
2092d7b241e6Sjeremylt 
2093ca94c3ddSJeremy L Thompson   @param[in,out] op `CeedOperator` to destroy
2094b11c1e72Sjeremylt 
2095b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
2096dfdf5a53Sjeremylt 
20977a982d89SJeremy L. Thompson   @ref User
2098b11c1e72Sjeremylt **/
2099d7b241e6Sjeremylt int CeedOperatorDestroy(CeedOperator *op) {
2100ad6481ceSJeremy L Thompson   if (!*op || --(*op)->ref_count > 0) {
2101ad6481ceSJeremy L Thompson     *op = NULL;
2102ad6481ceSJeremy L Thompson     return CEED_ERROR_SUCCESS;
2103ad6481ceSJeremy L Thompson   }
21042b730f8bSJeremy L Thompson   if ((*op)->Destroy) CeedCall((*op)->Destroy(*op));
21052b730f8bSJeremy L Thompson   CeedCall(CeedDestroy(&(*op)->ceed));
2106fe2413ffSjeremylt   // Free fields
21072b730f8bSJeremy L Thompson   for (CeedInt i = 0; i < (*op)->num_fields; i++) {
2108d1d35e2fSjeremylt     if ((*op)->input_fields[i]) {
2109437c7c90SJeremy L Thompson       if ((*op)->input_fields[i]->elem_rstr != CEED_ELEMRESTRICTION_NONE) {
2110437c7c90SJeremy L Thompson         CeedCall(CeedElemRestrictionDestroy(&(*op)->input_fields[i]->elem_rstr));
211115910d16Sjeremylt       }
2112356036faSJeremy L Thompson       if ((*op)->input_fields[i]->basis != CEED_BASIS_NONE) {
21132b730f8bSJeremy L Thompson         CeedCall(CeedBasisDestroy(&(*op)->input_fields[i]->basis));
211471352a93Sjeremylt       }
21152b730f8bSJeremy L Thompson       if ((*op)->input_fields[i]->vec != CEED_VECTOR_ACTIVE && (*op)->input_fields[i]->vec != CEED_VECTOR_NONE) {
21162b730f8bSJeremy L Thompson         CeedCall(CeedVectorDestroy(&(*op)->input_fields[i]->vec));
211771352a93Sjeremylt       }
21182b730f8bSJeremy L Thompson       CeedCall(CeedFree(&(*op)->input_fields[i]->field_name));
21192b730f8bSJeremy L Thompson       CeedCall(CeedFree(&(*op)->input_fields[i]));
2120fe2413ffSjeremylt     }
21212b730f8bSJeremy L Thompson   }
21222b730f8bSJeremy L Thompson   for (CeedInt i = 0; i < (*op)->num_fields; i++) {
2123d1d35e2fSjeremylt     if ((*op)->output_fields[i]) {
2124437c7c90SJeremy L Thompson       CeedCall(CeedElemRestrictionDestroy(&(*op)->output_fields[i]->elem_rstr));
2125356036faSJeremy L Thompson       if ((*op)->output_fields[i]->basis != CEED_BASIS_NONE) {
21262b730f8bSJeremy L Thompson         CeedCall(CeedBasisDestroy(&(*op)->output_fields[i]->basis));
212771352a93Sjeremylt       }
21282b730f8bSJeremy L Thompson       if ((*op)->output_fields[i]->vec != CEED_VECTOR_ACTIVE && (*op)->output_fields[i]->vec != CEED_VECTOR_NONE) {
21292b730f8bSJeremy L Thompson         CeedCall(CeedVectorDestroy(&(*op)->output_fields[i]->vec));
213071352a93Sjeremylt       }
21312b730f8bSJeremy L Thompson       CeedCall(CeedFree(&(*op)->output_fields[i]->field_name));
21322b730f8bSJeremy L Thompson       CeedCall(CeedFree(&(*op)->output_fields[i]));
21332b730f8bSJeremy L Thompson     }
2134fe2413ffSjeremylt   }
213548acf710SJeremy L Thompson   // AtPoints data
213648acf710SJeremy L Thompson   CeedCall(CeedVectorDestroy(&(*op)->point_coords));
213748acf710SJeremy L Thompson   CeedCall(CeedElemRestrictionDestroy(&(*op)->rstr_points));
213848acf710SJeremy L Thompson   CeedCall(CeedElemRestrictionDestroy(&(*op)->first_points_rstr));
2139d1d35e2fSjeremylt   // Destroy sub_operators
21402b730f8bSJeremy L Thompson   for (CeedInt i = 0; i < (*op)->num_suboperators; i++) {
2141d1d35e2fSjeremylt     if ((*op)->sub_operators[i]) {
21422b730f8bSJeremy L Thompson       CeedCall(CeedOperatorDestroy(&(*op)->sub_operators[i]));
214352d6035fSJeremy L Thompson     }
21442b730f8bSJeremy L Thompson   }
21452b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionDestroy(&(*op)->qf));
21462b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionDestroy(&(*op)->dqf));
21472b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionDestroy(&(*op)->dqfT));
21483668ca4bSJeremy L Thompson   // Destroy any composite labels
21495ac9af79SJeremy L Thompson   if ((*op)->is_composite) {
21503668ca4bSJeremy L Thompson     for (CeedInt i = 0; i < (*op)->num_context_labels; i++) {
21512b730f8bSJeremy L Thompson       CeedCall(CeedFree(&(*op)->context_labels[i]->sub_labels));
21522b730f8bSJeremy L Thompson       CeedCall(CeedFree(&(*op)->context_labels[i]));
21533668ca4bSJeremy L Thompson     }
21545ac9af79SJeremy L Thompson   }
21552b730f8bSJeremy L Thompson   CeedCall(CeedFree(&(*op)->context_labels));
2156fe2413ffSjeremylt 
21575107b09fSJeremy L Thompson   // Destroy fallback
21582b730f8bSJeremy L Thompson   CeedCall(CeedOperatorDestroy(&(*op)->op_fallback));
21595107b09fSJeremy L Thompson 
2160ed9e99e6SJeremy L Thompson   // Destroy assembly data
21612b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionAssemblyDataDestroy(&(*op)->qf_assembled));
21622b730f8bSJeremy L Thompson   CeedCall(CeedOperatorAssemblyDataDestroy(&(*op)->op_assembled));
216370a7ffb3SJeremy L Thompson 
21642b730f8bSJeremy L Thompson   CeedCall(CeedFree(&(*op)->input_fields));
21652b730f8bSJeremy L Thompson   CeedCall(CeedFree(&(*op)->output_fields));
21662b730f8bSJeremy L Thompson   CeedCall(CeedFree(&(*op)->sub_operators));
21672b730f8bSJeremy L Thompson   CeedCall(CeedFree(&(*op)->name));
21682b730f8bSJeremy L Thompson   CeedCall(CeedFree(op));
2169e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2170d7b241e6Sjeremylt }
2171d7b241e6Sjeremylt 
2172d7b241e6Sjeremylt /// @}
2173