xref: /libCEED/rust/libceed-sys/c-src/interface/ceed-operator.c (revision b0f67a9c1aeeb4d82b4724afaae1227ff4e81f15)
19ba83ac0SJeremy L Thompson // Copyright (c) 2017-2026, Lawrence Livermore National Security, LLC and other CEED contributors.
23d8e8822SJeremy L Thompson // All Rights Reserved. See the top-level LICENSE and NOTICE files for details.
3d7b241e6Sjeremylt //
43d8e8822SJeremy L Thompson // SPDX-License-Identifier: BSD-2-Clause
5d7b241e6Sjeremylt //
63d8e8822SJeremy L Thompson // This file is part of CEED:  http://github.com/ceed
7d7b241e6Sjeremylt 
83d576824SJeremy L Thompson #include <ceed-impl.h>
949aac155SJeremy L Thompson #include <ceed.h>
102b730f8bSJeremy L Thompson #include <ceed/backend.h>
113d576824SJeremy L Thompson #include <stdbool.h>
123d576824SJeremy L Thompson #include <stdio.h>
133d576824SJeremy L Thompson #include <string.h>
14d7b241e6Sjeremylt 
15dfdf5a53Sjeremylt /// @file
167a982d89SJeremy L. Thompson /// Implementation of CeedOperator interfaces
177a982d89SJeremy L. Thompson 
187a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
197a982d89SJeremy L. Thompson /// CeedOperator Library Internal Functions
207a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
217a982d89SJeremy L. Thompson /// @addtogroup CeedOperatorDeveloper
227a982d89SJeremy L. Thompson /// @{
237a982d89SJeremy L. Thompson 
247a982d89SJeremy L. Thompson /**
25ca94c3ddSJeremy L Thompson   @brief Check if a `CeedOperator` Field matches the `CeedQFunction` Field
26e15f9bd0SJeremy L Thompson 
27ca94c3ddSJeremy L Thompson   @param[in] ceed     `Ceed` object for error handling
28ca94c3ddSJeremy L Thompson   @param[in] qf_field `CeedQFunction` Field matching `CeedOperator` Field
29bafebce1SSebastian Grimberg   @param[in] rstr     `CeedOperator` Field `CeedElemRestriction`
30bafebce1SSebastian Grimberg   @param[in] basis    `CeedOperator` Field `CeedBasis`
31e15f9bd0SJeremy L Thompson 
32e15f9bd0SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
33e15f9bd0SJeremy L Thompson 
34e15f9bd0SJeremy L Thompson   @ref Developer
35e15f9bd0SJeremy L Thompson **/
36bafebce1SSebastian Grimberg static int CeedOperatorCheckField(Ceed ceed, CeedQFunctionField qf_field, CeedElemRestriction rstr, CeedBasis basis) {
376f8994e9SJeremy L Thompson   const char  *field_name;
381203703bSJeremy L Thompson   CeedInt      dim = 1, num_comp = 1, q_comp = 1, rstr_num_comp = 1, size;
391203703bSJeremy L Thompson   CeedEvalMode eval_mode;
401203703bSJeremy L Thompson 
411203703bSJeremy L Thompson   // Field data
42ab747706SJeremy L Thompson   CeedCall(CeedQFunctionFieldGetData(qf_field, &field_name, &size, &eval_mode));
432b730f8bSJeremy L Thompson 
44e15f9bd0SJeremy L Thompson   // Restriction
45bafebce1SSebastian Grimberg   CeedCheck((rstr == CEED_ELEMRESTRICTION_NONE) == (eval_mode == CEED_EVAL_WEIGHT), ceed, CEED_ERROR_INCOMPATIBLE,
466574a04fSJeremy L Thompson             "CEED_ELEMRESTRICTION_NONE and CEED_EVAL_WEIGHT must be used together.");
47bafebce1SSebastian Grimberg   if (rstr != CEED_ELEMRESTRICTION_NONE) {
48bafebce1SSebastian Grimberg     CeedCall(CeedElemRestrictionGetNumComponents(rstr, &rstr_num_comp));
49e1e9e29dSJed Brown   }
50e15f9bd0SJeremy L Thompson   // Basis
51bafebce1SSebastian Grimberg   CeedCheck((basis == CEED_BASIS_NONE) == (eval_mode == CEED_EVAL_NONE), ceed, CEED_ERROR_INCOMPATIBLE,
52356036faSJeremy L Thompson             "CEED_BASIS_NONE and CEED_EVAL_NONE must be used together.");
53bafebce1SSebastian Grimberg   if (basis != CEED_BASIS_NONE) {
54bafebce1SSebastian Grimberg     CeedCall(CeedBasisGetDimension(basis, &dim));
55bafebce1SSebastian Grimberg     CeedCall(CeedBasisGetNumComponents(basis, &num_comp));
56bafebce1SSebastian Grimberg     CeedCall(CeedBasisGetNumQuadratureComponents(basis, eval_mode, &q_comp));
57bafebce1SSebastian Grimberg     CeedCheck(rstr == CEED_ELEMRESTRICTION_NONE || rstr_num_comp == num_comp, ceed, CEED_ERROR_DIMENSION,
58ca94c3ddSJeremy L Thompson               "Field '%s' of size %" CeedInt_FMT " and EvalMode %s: CeedElemRestriction has %" CeedInt_FMT
59ca94c3ddSJeremy L Thompson               " components, but CeedBasis has %" CeedInt_FMT " components",
601203703bSJeremy L Thompson               field_name, size, CeedEvalModes[eval_mode], rstr_num_comp, num_comp);
61e15f9bd0SJeremy L Thompson   }
62e15f9bd0SJeremy L Thompson   // Field size
63d1d35e2fSjeremylt   switch (eval_mode) {
64e15f9bd0SJeremy L Thompson     case CEED_EVAL_NONE:
65edb2538eSJeremy L Thompson       CeedCheck(size == rstr_num_comp, ceed, CEED_ERROR_DIMENSION,
661203703bSJeremy L Thompson                 "Field '%s' of size %" CeedInt_FMT " and EvalMode %s: CeedElemRestriction has %" CeedInt_FMT " components", field_name, size,
671203703bSJeremy L Thompson                 CeedEvalModes[eval_mode], rstr_num_comp);
68e15f9bd0SJeremy L Thompson       break;
69e15f9bd0SJeremy L Thompson     case CEED_EVAL_INTERP:
70c4e3f59bSSebastian Grimberg     case CEED_EVAL_GRAD:
71c4e3f59bSSebastian Grimberg     case CEED_EVAL_DIV:
72c4e3f59bSSebastian Grimberg     case CEED_EVAL_CURL:
736574a04fSJeremy L Thompson       CeedCheck(size == num_comp * q_comp, ceed, CEED_ERROR_DIMENSION,
741203703bSJeremy L Thompson                 "Field '%s' of size %" CeedInt_FMT " and EvalMode %s: CeedElemRestriction/Basis has %" CeedInt_FMT " components", field_name, size,
751203703bSJeremy L Thompson                 CeedEvalModes[eval_mode], num_comp * q_comp);
76e15f9bd0SJeremy L Thompson       break;
77e15f9bd0SJeremy L Thompson     case CEED_EVAL_WEIGHT:
78d1d35e2fSjeremylt       // No additional checks required
79e15f9bd0SJeremy L Thompson       break;
80e15f9bd0SJeremy L Thompson   }
81e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
827a982d89SJeremy L. Thompson }
837a982d89SJeremy L. Thompson 
847a982d89SJeremy L. Thompson /**
85ca94c3ddSJeremy L Thompson   @brief View a field of a `CeedOperator`
867a982d89SJeremy L. Thompson 
871203703bSJeremy L Thompson   @param[in] op_field     `CeedOperator` Field to view
88ca94c3ddSJeremy L Thompson   @param[in] qf_field     `CeedQFunction` Field (carries field name)
89d1d35e2fSjeremylt   @param[in] field_number Number of field being viewed
905a526491SJeremy L Thompson   @param[in] tabs         Tabs to append before each line
91b7fd8817SJeremy L Thompson   @param[in] is_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 **/
98b7fd8817SJeremy L Thompson static int CeedOperatorFieldView(CeedOperatorField op_field, CeedQFunctionField qf_field, CeedInt field_number, const char *tabs, bool is_input,
995a526491SJeremy L Thompson                                  FILE *stream) {
100b7fd8817SJeremy L Thompson   const char  *field_type = is_input ? "Input" : "Output";
1016f8994e9SJeremy L Thompson   const char  *field_name;
1021203703bSJeremy L Thompson   CeedInt      size;
1031203703bSJeremy L Thompson   CeedEvalMode eval_mode;
1041203703bSJeremy L Thompson   CeedVector   vec;
1051203703bSJeremy L Thompson   CeedBasis    basis;
1061203703bSJeremy L Thompson 
1071203703bSJeremy L Thompson   // Field data
108ab747706SJeremy L Thompson   CeedCall(CeedQFunctionFieldGetData(qf_field, &field_name, &size, &eval_mode));
109ab747706SJeremy L Thompson   CeedCall(CeedOperatorFieldGetData(op_field, NULL, NULL, &basis, &vec));
1107a982d89SJeremy L. Thompson 
1112b730f8bSJeremy L Thompson   fprintf(stream,
1122b730f8bSJeremy L Thompson           "%s    %s field %" CeedInt_FMT
1132b730f8bSJeremy L Thompson           ":\n"
1147a982d89SJeremy L. Thompson           "%s      Name: \"%s\"\n",
115b7fd8817SJeremy L Thompson           tabs, field_type, field_number, tabs, field_name);
1165a526491SJeremy L Thompson   fprintf(stream, "%s      Size: %" CeedInt_FMT "\n", tabs, size);
1175a526491SJeremy L Thompson   fprintf(stream, "%s      EvalMode: %s\n", tabs, CeedEvalModes[eval_mode]);
1185a526491SJeremy L Thompson   if (basis == CEED_BASIS_NONE) fprintf(stream, "%s      No basis\n", tabs);
1195a526491SJeremy L Thompson   if (vec == CEED_VECTOR_ACTIVE) fprintf(stream, "%s      Active vector\n", tabs);
1205a526491SJeremy L Thompson   else if (vec == CEED_VECTOR_NONE) fprintf(stream, "%s      No vector\n", tabs);
121681d0ea7SJeremy L Thompson 
122681d0ea7SJeremy L Thompson   CeedCall(CeedVectorDestroy(&vec));
123681d0ea7SJeremy L Thompson   CeedCall(CeedBasisDestroy(&basis));
124e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1257a982d89SJeremy L. Thompson }
1267a982d89SJeremy L. Thompson 
1277a982d89SJeremy L. Thompson /**
128ca94c3ddSJeremy L Thompson   @brief View a single `CeedOperator`
1297a982d89SJeremy L. Thompson 
130ca94c3ddSJeremy L Thompson   @param[in] op     `CeedOperator` to view
1315a526491SJeremy L Thompson   @param[in] tabs   Tabs to append before each new line
132ca94c3ddSJeremy L Thompson   @param[in] stream Stream to write; typically `stdout` or a file
1337a982d89SJeremy L. Thompson 
1347a982d89SJeremy L. Thompson   @return Error code: 0 - success, otherwise - failure
1357a982d89SJeremy L. Thompson 
1367a982d89SJeremy L. Thompson   @ref Utility
1377a982d89SJeremy L. Thompson **/
1385a526491SJeremy L Thompson int CeedOperatorSingleView(CeedOperator op, const char *tabs, FILE *stream) {
13999f7f61fSJeremy L Thompson   bool                is_at_points;
1401203703bSJeremy L Thompson   CeedInt             num_elem, num_qpts, total_fields = 0, num_input_fields, num_output_fields;
1411203703bSJeremy L Thompson   CeedQFunction       qf;
1421203703bSJeremy L Thompson   CeedQFunctionField *qf_input_fields, *qf_output_fields;
1431203703bSJeremy L Thompson   CeedOperatorField  *op_input_fields, *op_output_fields;
1447a982d89SJeremy L. Thompson 
14599f7f61fSJeremy L Thompson   CeedCall(CeedOperatorIsAtPoints(op, &is_at_points));
1462b730f8bSJeremy L Thompson   CeedCall(CeedOperatorGetNumElements(op, &num_elem));
1472b730f8bSJeremy L Thompson   CeedCall(CeedOperatorGetNumQuadraturePoints(op, &num_qpts));
1482b730f8bSJeremy L Thompson   CeedCall(CeedOperatorGetNumArgs(op, &total_fields));
1491203703bSJeremy L Thompson   CeedCall(CeedOperatorGetFields(op, &num_input_fields, &op_input_fields, &num_output_fields, &op_output_fields));
1501203703bSJeremy L Thompson   CeedCall(CeedOperatorGetQFunction(op, &qf));
1511203703bSJeremy L Thompson   CeedCall(CeedQFunctionGetFields(qf, NULL, &qf_input_fields, NULL, &qf_output_fields));
152c11e12f4SJeremy L Thompson   CeedCall(CeedQFunctionDestroy(&qf));
1531c66c397SJeremy L Thompson 
15499f7f61fSJeremy L Thompson   if (is_at_points) {
15599f7f61fSJeremy L Thompson     CeedInt             max_points = 0;
15699f7f61fSJeremy L Thompson     CeedElemRestriction rstr_points;
15799f7f61fSJeremy L Thompson 
15899f7f61fSJeremy L Thompson     CeedCall(CeedOperatorAtPointsGetPoints(op, &rstr_points, NULL));
15999f7f61fSJeremy L Thompson     CeedCall(CeedElemRestrictionGetMaxPointsInElement(rstr_points, &max_points));
1605a526491SJeremy L Thompson     fprintf(stream, "%s  %" CeedInt_FMT " elements with %" CeedInt_FMT " max points each\n", tabs, num_elem, max_points);
16199f7f61fSJeremy L Thompson     CeedCall(CeedElemRestrictionDestroy(&rstr_points));
16299f7f61fSJeremy L Thompson   } else {
1635a526491SJeremy L Thompson     fprintf(stream, "%s  %" CeedInt_FMT " elements with %" CeedInt_FMT " quadrature points each\n", tabs, num_elem, num_qpts);
16499f7f61fSJeremy L Thompson   }
1655a526491SJeremy L Thompson   fprintf(stream, "%s  %" CeedInt_FMT " field%s\n", tabs, total_fields, total_fields > 1 ? "s" : "");
1665a526491SJeremy L Thompson   fprintf(stream, "%s  %" CeedInt_FMT " input field%s:\n", tabs, num_input_fields, num_input_fields > 1 ? "s" : "");
1671203703bSJeremy L Thompson   for (CeedInt i = 0; i < num_input_fields; i++) {
1685a526491SJeremy L Thompson     CeedCall(CeedOperatorFieldView(op_input_fields[i], qf_input_fields[i], i, tabs, 1, stream));
1697a982d89SJeremy L. Thompson   }
1705a526491SJeremy L Thompson   fprintf(stream, "%s  %" CeedInt_FMT " output field%s:\n", tabs, num_output_fields, num_output_fields > 1 ? "s" : "");
1711203703bSJeremy L Thompson   for (CeedInt i = 0; i < num_output_fields; i++) {
1725a526491SJeremy L Thompson     CeedCall(CeedOperatorFieldView(op_output_fields[i], qf_output_fields[i], i, tabs, 0, stream));
1737a982d89SJeremy L. Thompson   }
174e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1757a982d89SJeremy L. Thompson }
1767a982d89SJeremy L. Thompson 
177d99fa3c5SJeremy L Thompson /**
178*b0f67a9cSJeremy L Thompson   @brief View a `CeedOperator` passed as a `CeedObject`
179*b0f67a9cSJeremy L Thompson 
180*b0f67a9cSJeremy L Thompson   @param[in] op     `CeedOperator` to view
181*b0f67a9cSJeremy L Thompson   @param[in] stream Filestream to write to
182*b0f67a9cSJeremy L Thompson 
183*b0f67a9cSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
184*b0f67a9cSJeremy L Thompson 
185*b0f67a9cSJeremy L Thompson   @ref Developer
186*b0f67a9cSJeremy L Thompson **/
187*b0f67a9cSJeremy L Thompson static int CeedOperatorView_Object(CeedObject op, FILE *stream) {
188*b0f67a9cSJeremy L Thompson   CeedCall(CeedOperatorView((CeedOperator)op, stream));
189*b0f67a9cSJeremy L Thompson   return CEED_ERROR_SUCCESS;
190*b0f67a9cSJeremy L Thompson }
191*b0f67a9cSJeremy L Thompson 
192*b0f67a9cSJeremy L Thompson /**
193681d0ea7SJeremy L Thompson   @brief Find the active input vector `CeedBasis` for a non-composite `CeedOperator`.
194681d0ea7SJeremy L Thompson 
195681d0ea7SJeremy L Thompson   Note: Caller is responsible for destroying the `active_basis` with @ref CeedBasisDestroy().
196eaf62fffSJeremy L Thompson 
197ca94c3ddSJeremy L Thompson   @param[in]  op           `CeedOperator` to find active `CeedBasis` for
198ca94c3ddSJeremy L Thompson   @param[out] active_basis `CeedBasis` for active input vector or `NULL` for composite operator
199eaf62fffSJeremy L Thompson 
200eaf62fffSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
201eaf62fffSJeremy L Thompson 
202eaf62fffSJeremy L Thompson   @ref Developer
203eaf62fffSJeremy L Thompson **/
204eaf62fffSJeremy L Thompson int CeedOperatorGetActiveBasis(CeedOperator op, CeedBasis *active_basis) {
205506b1a0cSSebastian Grimberg   CeedCall(CeedOperatorGetActiveBases(op, active_basis, NULL));
206506b1a0cSSebastian Grimberg   return CEED_ERROR_SUCCESS;
207506b1a0cSSebastian Grimberg }
208506b1a0cSSebastian Grimberg 
209506b1a0cSSebastian Grimberg /**
210681d0ea7SJeremy L Thompson   @brief Find the active input and output vector `CeedBasis` for a non-composite `CeedOperator`.
211681d0ea7SJeremy L Thompson 
212681d0ea7SJeremy L Thompson   Note: Caller is responsible for destroying the bases with @ref CeedBasisDestroy().
213506b1a0cSSebastian Grimberg 
214ca94c3ddSJeremy L Thompson   @param[in]  op                  `CeedOperator` to find active `CeedBasis` for
215ca94c3ddSJeremy L Thompson   @param[out] active_input_basis  `CeedBasis` for active input vector or `NULL` for composite operator
216ca94c3ddSJeremy L Thompson   @param[out] active_output_basis `CeedBasis` for active output vector or `NULL` for composite operator
217506b1a0cSSebastian Grimberg 
218506b1a0cSSebastian Grimberg   @return An error code: 0 - success, otherwise - failure
219506b1a0cSSebastian Grimberg 
220506b1a0cSSebastian Grimberg   @ref Developer
221506b1a0cSSebastian Grimberg **/
222506b1a0cSSebastian Grimberg int CeedOperatorGetActiveBases(CeedOperator op, CeedBasis *active_input_basis, CeedBasis *active_output_basis) {
2231203703bSJeremy L Thompson   bool               is_composite;
2241203703bSJeremy L Thompson   CeedInt            num_input_fields, num_output_fields;
2251203703bSJeremy L Thompson   CeedOperatorField *op_input_fields, *op_output_fields;
2261c66c397SJeremy L Thompson 
2271203703bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
2281203703bSJeremy L Thompson   CeedCall(CeedOperatorGetFields(op, &num_input_fields, &op_input_fields, &num_output_fields, &op_output_fields));
2291203703bSJeremy L Thompson 
230506b1a0cSSebastian Grimberg   if (active_input_basis) {
231506b1a0cSSebastian Grimberg     *active_input_basis = NULL;
2321203703bSJeremy L Thompson     if (!is_composite) {
2331203703bSJeremy L Thompson       for (CeedInt i = 0; i < num_input_fields; i++) {
2341203703bSJeremy L Thompson         CeedVector vec;
2351203703bSJeremy L Thompson 
2361203703bSJeremy L Thompson         CeedCall(CeedOperatorFieldGetVector(op_input_fields[i], &vec));
2371203703bSJeremy L Thompson         if (vec == CEED_VECTOR_ACTIVE) {
2381203703bSJeremy L Thompson           CeedBasis basis;
2391203703bSJeremy L Thompson 
2401203703bSJeremy L Thompson           CeedCall(CeedOperatorFieldGetBasis(op_input_fields[i], &basis));
2419bc66399SJeremy L Thompson           CeedCheck(!*active_input_basis || *active_input_basis == basis, CeedOperatorReturnCeed(op), CEED_ERROR_MINOR,
2429bc66399SJeremy L Thompson                     "Multiple active input CeedBases found");
243681d0ea7SJeremy L Thompson           if (!*active_input_basis) CeedCall(CeedBasisReferenceCopy(basis, active_input_basis));
244681d0ea7SJeremy L Thompson           CeedCall(CeedBasisDestroy(&basis));
245eaf62fffSJeremy L Thompson         }
246681d0ea7SJeremy L Thompson         CeedCall(CeedVectorDestroy(&vec));
2472b730f8bSJeremy L Thompson       }
2489bc66399SJeremy L Thompson       CeedCheck(*active_input_basis, CeedOperatorReturnCeed(op), CEED_ERROR_INCOMPLETE, "No active input CeedBasis found");
249506b1a0cSSebastian Grimberg     }
250506b1a0cSSebastian Grimberg   }
251506b1a0cSSebastian Grimberg   if (active_output_basis) {
252506b1a0cSSebastian Grimberg     *active_output_basis = NULL;
2531203703bSJeremy L Thompson     if (!is_composite) {
2541203703bSJeremy L Thompson       for (CeedInt i = 0; i < num_output_fields; i++) {
2551203703bSJeremy L Thompson         CeedVector vec;
2561203703bSJeremy L Thompson 
2571203703bSJeremy L Thompson         CeedCall(CeedOperatorFieldGetVector(op_output_fields[i], &vec));
2581203703bSJeremy L Thompson         if (vec == CEED_VECTOR_ACTIVE) {
2591203703bSJeremy L Thompson           CeedBasis basis;
2601203703bSJeremy L Thompson 
2611203703bSJeremy L Thompson           CeedCall(CeedOperatorFieldGetBasis(op_output_fields[i], &basis));
2629bc66399SJeremy L Thompson           CeedCheck(!*active_output_basis || *active_output_basis == basis, CeedOperatorReturnCeed(op), CEED_ERROR_MINOR,
2639bc66399SJeremy L Thompson                     "Multiple active output CeedBases found");
264681d0ea7SJeremy L Thompson           if (!*active_output_basis) CeedCall(CeedBasisReferenceCopy(basis, active_output_basis));
265681d0ea7SJeremy L Thompson           CeedCall(CeedBasisDestroy(&basis));
266506b1a0cSSebastian Grimberg         }
267681d0ea7SJeremy L Thompson         CeedCall(CeedVectorDestroy(&vec));
268506b1a0cSSebastian Grimberg       }
2699bc66399SJeremy L Thompson       CeedCheck(*active_output_basis, CeedOperatorReturnCeed(op), CEED_ERROR_INCOMPLETE, "No active output CeedBasis found");
270506b1a0cSSebastian Grimberg     }
271506b1a0cSSebastian Grimberg   }
272eaf62fffSJeremy L Thompson   return CEED_ERROR_SUCCESS;
273eaf62fffSJeremy L Thompson }
274eaf62fffSJeremy L Thompson 
275eaf62fffSJeremy L Thompson /**
276681d0ea7SJeremy L Thompson   @brief Find the active vector `CeedElemRestriction` for a non-composite `CeedOperator`.
277681d0ea7SJeremy L Thompson 
278681d0ea7SJeremy L Thompson   Note: Caller is responsible for destroying the `active_rstr` with @ref CeedElemRestrictionDestroy().
279e2f04181SAndrew T. Barker 
280ca94c3ddSJeremy L Thompson   @param[in]  op          `CeedOperator` to find active `CeedElemRestriction` for
281ca94c3ddSJeremy L Thompson   @param[out] active_rstr `CeedElemRestriction` for active input vector or NULL for composite operator
282e2f04181SAndrew T. Barker 
283e2f04181SAndrew T. Barker   @return An error code: 0 - success, otherwise - failure
284e2f04181SAndrew T. Barker 
285e2f04181SAndrew T. Barker   @ref Utility
286e2f04181SAndrew T. Barker **/
2872b730f8bSJeremy L Thompson int CeedOperatorGetActiveElemRestriction(CeedOperator op, CeedElemRestriction *active_rstr) {
288506b1a0cSSebastian Grimberg   CeedCall(CeedOperatorGetActiveElemRestrictions(op, active_rstr, NULL));
289506b1a0cSSebastian Grimberg   return CEED_ERROR_SUCCESS;
290506b1a0cSSebastian Grimberg }
291506b1a0cSSebastian Grimberg 
292506b1a0cSSebastian Grimberg /**
293681d0ea7SJeremy L Thompson   @brief Find the active input and output vector `CeedElemRestriction` for a non-composite `CeedOperator`.
294681d0ea7SJeremy L Thompson 
295681d0ea7SJeremy L Thompson   Note: Caller is responsible for destroying the restrictions with @ref CeedElemRestrictionDestroy().
296506b1a0cSSebastian Grimberg 
297ca94c3ddSJeremy L Thompson   @param[in]  op                 `CeedOperator` to find active `CeedElemRestriction` for
298ca94c3ddSJeremy L Thompson   @param[out] active_input_rstr  `CeedElemRestriction` for active input vector or NULL for composite operator
299ca94c3ddSJeremy L Thompson   @param[out] active_output_rstr `CeedElemRestriction` for active output vector or NULL for composite operator
300506b1a0cSSebastian Grimberg 
301506b1a0cSSebastian Grimberg   @return An error code: 0 - success, otherwise - failure
302506b1a0cSSebastian Grimberg 
303506b1a0cSSebastian Grimberg   @ref Utility
304506b1a0cSSebastian Grimberg **/
305506b1a0cSSebastian Grimberg int CeedOperatorGetActiveElemRestrictions(CeedOperator op, CeedElemRestriction *active_input_rstr, CeedElemRestriction *active_output_rstr) {
3061203703bSJeremy L Thompson   bool               is_composite;
3071203703bSJeremy L Thompson   CeedInt            num_input_fields, num_output_fields;
3081203703bSJeremy L Thompson   CeedOperatorField *op_input_fields, *op_output_fields;
3091c66c397SJeremy L Thompson 
3101203703bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
3111203703bSJeremy L Thompson   CeedCall(CeedOperatorGetFields(op, &num_input_fields, &op_input_fields, &num_output_fields, &op_output_fields));
3121203703bSJeremy L Thompson 
313506b1a0cSSebastian Grimberg   if (active_input_rstr) {
314506b1a0cSSebastian Grimberg     *active_input_rstr = NULL;
3151203703bSJeremy L Thompson     if (!is_composite) {
3161203703bSJeremy L Thompson       for (CeedInt i = 0; i < num_input_fields; i++) {
3171203703bSJeremy L Thompson         CeedVector vec;
3181203703bSJeremy L Thompson 
3191203703bSJeremy L Thompson         CeedCall(CeedOperatorFieldGetVector(op_input_fields[i], &vec));
3201203703bSJeremy L Thompson         if (vec == CEED_VECTOR_ACTIVE) {
3211203703bSJeremy L Thompson           CeedElemRestriction rstr;
3221203703bSJeremy L Thompson 
3231203703bSJeremy L Thompson           CeedCall(CeedOperatorFieldGetElemRestriction(op_input_fields[i], &rstr));
3249bc66399SJeremy L Thompson           CeedCheck(!*active_input_rstr || *active_input_rstr == rstr, CeedOperatorReturnCeed(op), CEED_ERROR_MINOR,
3259bc66399SJeremy L Thompson                     "Multiple active input CeedElemRestrictions found");
326681d0ea7SJeremy L Thompson           if (!*active_input_rstr) CeedCall(CeedElemRestrictionReferenceCopy(rstr, active_input_rstr));
327681d0ea7SJeremy L Thompson           CeedCall(CeedElemRestrictionDestroy(&rstr));
328e2f04181SAndrew T. Barker         }
329681d0ea7SJeremy L Thompson         CeedCall(CeedVectorDestroy(&vec));
3302b730f8bSJeremy L Thompson       }
3319bc66399SJeremy L Thompson       CeedCheck(*active_input_rstr, CeedOperatorReturnCeed(op), CEED_ERROR_INCOMPLETE, "No active input CeedElemRestriction found");
332506b1a0cSSebastian Grimberg     }
333506b1a0cSSebastian Grimberg   }
334506b1a0cSSebastian Grimberg   if (active_output_rstr) {
335506b1a0cSSebastian Grimberg     *active_output_rstr = NULL;
3361203703bSJeremy L Thompson     if (!is_composite) {
3371203703bSJeremy L Thompson       for (CeedInt i = 0; i < num_output_fields; i++) {
3381203703bSJeremy L Thompson         CeedVector vec;
3391203703bSJeremy L Thompson 
3401203703bSJeremy L Thompson         CeedCall(CeedOperatorFieldGetVector(op_output_fields[i], &vec));
3411203703bSJeremy L Thompson         if (vec == CEED_VECTOR_ACTIVE) {
3421203703bSJeremy L Thompson           CeedElemRestriction rstr;
3431203703bSJeremy L Thompson 
3441203703bSJeremy L Thompson           CeedCall(CeedOperatorFieldGetElemRestriction(op_output_fields[i], &rstr));
3459bc66399SJeremy L Thompson           CeedCheck(!*active_output_rstr || *active_output_rstr == rstr, CeedOperatorReturnCeed(op), CEED_ERROR_MINOR,
3469bc66399SJeremy L Thompson                     "Multiple active output CeedElemRestrictions found");
347681d0ea7SJeremy L Thompson           if (!*active_output_rstr) CeedCall(CeedElemRestrictionReferenceCopy(rstr, active_output_rstr));
348681d0ea7SJeremy L Thompson           CeedCall(CeedElemRestrictionDestroy(&rstr));
349506b1a0cSSebastian Grimberg         }
350681d0ea7SJeremy L Thompson         CeedCall(CeedVectorDestroy(&vec));
351506b1a0cSSebastian Grimberg       }
3529bc66399SJeremy L Thompson       CeedCheck(*active_output_rstr, CeedOperatorReturnCeed(op), CEED_ERROR_INCOMPLETE, "No active output CeedElemRestriction found");
353506b1a0cSSebastian Grimberg     }
354506b1a0cSSebastian Grimberg   }
355e2f04181SAndrew T. Barker   return CEED_ERROR_SUCCESS;
356e2f04181SAndrew T. Barker }
357e2f04181SAndrew T. Barker 
358d8dd9a91SJeremy L Thompson /**
359ca94c3ddSJeremy L Thompson   @brief Set `CeedQFunctionContext` field values of the specified type.
3604385fb7fSSebastian Grimberg 
361ca94c3ddSJeremy L Thompson   For composite operators, the value is set in all sub-operator `CeedQFunctionContext` that have a matching `field_name`.
362ca94c3ddSJeremy 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.
363d8dd9a91SJeremy L Thompson 
364ca94c3ddSJeremy L Thompson   @param[in,out] op          `CeedOperator`
365ea61e9acSJeremy L Thompson   @param[in]     field_label Label of field to set
366ea61e9acSJeremy L Thompson   @param[in]     field_type  Type of field to set
3672788fa27SJeremy L Thompson   @param[in]     values      Values to set
368d8dd9a91SJeremy L Thompson 
369d8dd9a91SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
370d8dd9a91SJeremy L Thompson 
3716ab8e59fSJames Wright   @ref Developer
372d8dd9a91SJeremy L Thompson **/
3732788fa27SJeremy L Thompson static int CeedOperatorContextSetGeneric(CeedOperator op, CeedContextFieldLabel field_label, CeedContextFieldType field_type, void *values) {
3741c66c397SJeremy L Thompson   bool is_composite = false;
3751c66c397SJeremy L Thompson 
3769bc66399SJeremy L Thompson   CeedCheck(field_label, CeedOperatorReturnCeed(op), CEED_ERROR_UNSUPPORTED, "Invalid field label");
3773668ca4bSJeremy L Thompson 
3785ac9af79SJeremy L Thompson   // Check if field_label and op correspond
3795ac9af79SJeremy L Thompson   if (field_label->from_op) {
3805ac9af79SJeremy L Thompson     CeedInt index = -1;
3815ac9af79SJeremy L Thompson 
3825ac9af79SJeremy L Thompson     for (CeedInt i = 0; i < op->num_context_labels; i++) {
3835ac9af79SJeremy L Thompson       if (op->context_labels[i] == field_label) index = i;
3845ac9af79SJeremy L Thompson     }
3859bc66399SJeremy L Thompson     CeedCheck(index != -1, CeedOperatorReturnCeed(op), CEED_ERROR_UNSUPPORTED, "ContextFieldLabel does not correspond to the operator");
3865ac9af79SJeremy L Thompson   }
3875ac9af79SJeremy L Thompson 
3882b730f8bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
389d8dd9a91SJeremy L Thompson   if (is_composite) {
390d8dd9a91SJeremy L Thompson     CeedInt       num_sub;
391d8dd9a91SJeremy L Thompson     CeedOperator *sub_operators;
392d8dd9a91SJeremy L Thompson 
393ed094490SJeremy L Thompson     CeedCall(CeedOperatorCompositeGetNumSub(op, &num_sub));
394ed094490SJeremy L Thompson     CeedCall(CeedOperatorCompositeGetSubList(op, &sub_operators));
3959bc66399SJeremy L Thompson     CeedCheck(num_sub == field_label->num_sub_labels, CeedOperatorReturnCeed(op), CEED_ERROR_UNSUPPORTED,
3969bc66399SJeremy L Thompson               "Composite operator modified after ContextFieldLabel created");
397d8dd9a91SJeremy L Thompson 
398d8dd9a91SJeremy L Thompson     for (CeedInt i = 0; i < num_sub; i++) {
3991203703bSJeremy L Thompson       CeedQFunctionContext ctx;
4001203703bSJeremy L Thompson 
4011485364cSJeremy L Thompson       CeedCall(CeedOperatorGetContext(sub_operators[i], &ctx));
402d8dd9a91SJeremy L Thompson       // Try every sub-operator, ok if some sub-operators do not have field
4031485364cSJeremy L Thompson       if (ctx && field_label->sub_labels[i]) {
4041203703bSJeremy L Thompson         CeedCall(CeedQFunctionContextSetGeneric(ctx, field_label->sub_labels[i], field_type, values));
405d8dd9a91SJeremy L Thompson       }
4061485364cSJeremy L Thompson       CeedCall(CeedQFunctionContextDestroy(&ctx));
407d8dd9a91SJeremy L Thompson     }
408d8dd9a91SJeremy L Thompson   } else {
4091203703bSJeremy L Thompson     CeedQFunctionContext ctx;
4101203703bSJeremy L Thompson 
4111485364cSJeremy L Thompson     CeedCall(CeedOperatorGetContext(op, &ctx));
4129bc66399SJeremy L Thompson     CeedCheck(ctx, CeedOperatorReturnCeed(op), CEED_ERROR_UNSUPPORTED, "QFunction does not have context data");
4131203703bSJeremy L Thompson     CeedCall(CeedQFunctionContextSetGeneric(ctx, field_label, field_type, values));
4141485364cSJeremy L Thompson     CeedCall(CeedQFunctionContextDestroy(&ctx));
4152788fa27SJeremy L Thompson   }
4166d95ab46SJeremy L Thompson   CeedCall(CeedOperatorSetQFunctionAssemblyDataUpdateNeeded(op, true));
4172788fa27SJeremy L Thompson   return CEED_ERROR_SUCCESS;
4182788fa27SJeremy L Thompson }
4192788fa27SJeremy L Thompson 
4202788fa27SJeremy L Thompson /**
421ca94c3ddSJeremy L Thompson   @brief Get `CeedQFunctionContext` field values of the specified type, read-only.
4224385fb7fSSebastian Grimberg 
423ca94c3ddSJeremy L Thompson   For composite operators, the values retrieved are for the first sub-operator `CeedQFunctionContext` that have a matching `field_name`.
424ca94c3ddSJeremy 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.
4252788fa27SJeremy L Thompson 
426ca94c3ddSJeremy L Thompson   @param[in,out] op          `CeedOperator`
4272788fa27SJeremy L Thompson   @param[in]     field_label Label of field to set
4282788fa27SJeremy L Thompson   @param[in]     field_type  Type of field to set
429c5d0f995SJed Brown   @param[out]    num_values  Number of values of type `field_type` in array `values`
430c5d0f995SJed Brown   @param[out]    values      Values in the label
4312788fa27SJeremy L Thompson 
4322788fa27SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
4332788fa27SJeremy L Thompson 
4346ab8e59fSJames Wright   @ref Developer
4352788fa27SJeremy L Thompson **/
4362788fa27SJeremy L Thompson static int CeedOperatorContextGetGenericRead(CeedOperator op, CeedContextFieldLabel field_label, CeedContextFieldType field_type, size_t *num_values,
4372788fa27SJeremy L Thompson                                              void *values) {
4381c66c397SJeremy L Thompson   bool is_composite = false;
4391c66c397SJeremy L Thompson 
4409bc66399SJeremy L Thompson   CeedCheck(field_label, CeedOperatorReturnCeed(op), CEED_ERROR_UNSUPPORTED, "Invalid field label");
4412788fa27SJeremy L Thompson 
4422788fa27SJeremy L Thompson   *(void **)values = NULL;
4432788fa27SJeremy L Thompson   *num_values      = 0;
4442788fa27SJeremy L Thompson 
4455ac9af79SJeremy L Thompson   // Check if field_label and op correspond
4465ac9af79SJeremy L Thompson   if (field_label->from_op) {
4475ac9af79SJeremy L Thompson     CeedInt index = -1;
4485ac9af79SJeremy L Thompson 
4495ac9af79SJeremy L Thompson     for (CeedInt i = 0; i < op->num_context_labels; i++) {
4505ac9af79SJeremy L Thompson       if (op->context_labels[i] == field_label) index = i;
4515ac9af79SJeremy L Thompson     }
4529bc66399SJeremy L Thompson     CeedCheck(index != -1, CeedOperatorReturnCeed(op), CEED_ERROR_UNSUPPORTED, "ContextFieldLabel does not correspond to the operator");
4535ac9af79SJeremy L Thompson   }
4545ac9af79SJeremy L Thompson 
4552788fa27SJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
4562788fa27SJeremy L Thompson   if (is_composite) {
4572788fa27SJeremy L Thompson     CeedInt       num_sub;
4582788fa27SJeremy L Thompson     CeedOperator *sub_operators;
4592788fa27SJeremy L Thompson 
460ed094490SJeremy L Thompson     CeedCall(CeedOperatorCompositeGetNumSub(op, &num_sub));
461ed094490SJeremy L Thompson     CeedCall(CeedOperatorCompositeGetSubList(op, &sub_operators));
4629bc66399SJeremy L Thompson     CeedCheck(num_sub == field_label->num_sub_labels, CeedOperatorReturnCeed(op), CEED_ERROR_UNSUPPORTED,
4639bc66399SJeremy L Thompson               "Composite operator modified after ContextFieldLabel created");
4642788fa27SJeremy L Thompson 
4652788fa27SJeremy L Thompson     for (CeedInt i = 0; i < num_sub; i++) {
4661203703bSJeremy L Thompson       CeedQFunctionContext ctx;
4671203703bSJeremy L Thompson 
4681485364cSJeremy L Thompson       CeedCall(CeedOperatorGetContext(sub_operators[i], &ctx));
4692788fa27SJeremy L Thompson       // Try every sub-operator, ok if some sub-operators do not have field
4701485364cSJeremy L Thompson       if (ctx && field_label->sub_labels[i]) {
4711203703bSJeremy L Thompson         CeedCall(CeedQFunctionContextGetGenericRead(ctx, field_label->sub_labels[i], field_type, num_values, values));
4721485364cSJeremy L Thompson         CeedCall(CeedQFunctionContextDestroy(&ctx));
4732788fa27SJeremy L Thompson         return CEED_ERROR_SUCCESS;
4742788fa27SJeremy L Thompson       }
4751485364cSJeremy L Thompson       CeedCall(CeedQFunctionContextDestroy(&ctx));
4762788fa27SJeremy L Thompson     }
4772788fa27SJeremy L Thompson   } else {
4781203703bSJeremy L Thompson     CeedQFunctionContext ctx;
4791203703bSJeremy L Thompson 
4801485364cSJeremy L Thompson     CeedCall(CeedOperatorGetContext(op, &ctx));
4819bc66399SJeremy L Thompson     CeedCheck(ctx, CeedOperatorReturnCeed(op), CEED_ERROR_UNSUPPORTED, "QFunction does not have context data");
4821203703bSJeremy L Thompson     CeedCall(CeedQFunctionContextGetGenericRead(ctx, field_label, field_type, num_values, values));
4831485364cSJeremy L Thompson     CeedCall(CeedQFunctionContextDestroy(&ctx));
4842788fa27SJeremy L Thompson   }
4852788fa27SJeremy L Thompson   return CEED_ERROR_SUCCESS;
4862788fa27SJeremy L Thompson }
4872788fa27SJeremy L Thompson 
4882788fa27SJeremy L Thompson /**
489ca94c3ddSJeremy L Thompson   @brief Restore `CeedQFunctionContext` field values of the specified type, read-only.
4904385fb7fSSebastian Grimberg 
491ca94c3ddSJeremy L Thompson   For composite operators, the values restored are for the first sub-operator `CeedQFunctionContext` that have a matching `field_name`.
492ca94c3ddSJeremy 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.
4932788fa27SJeremy L Thompson 
494ca94c3ddSJeremy L Thompson   @param[in,out] op          `CeedOperator`
4952788fa27SJeremy L Thompson   @param[in]     field_label Label of field to set
4962788fa27SJeremy L Thompson   @param[in]     field_type  Type of field to set
497c5d0f995SJed Brown   @param[in]     values      Values array to restore
4982788fa27SJeremy L Thompson 
4992788fa27SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
5002788fa27SJeremy L Thompson 
5016ab8e59fSJames Wright   @ref Developer
5022788fa27SJeremy L Thompson **/
5032788fa27SJeremy L Thompson static int CeedOperatorContextRestoreGenericRead(CeedOperator op, CeedContextFieldLabel field_label, CeedContextFieldType field_type, void *values) {
5041c66c397SJeremy L Thompson   bool is_composite = false;
5051c66c397SJeremy L Thompson 
5069bc66399SJeremy L Thompson   CeedCheck(field_label, CeedOperatorReturnCeed(op), CEED_ERROR_UNSUPPORTED, "Invalid field label");
5072788fa27SJeremy L Thompson 
5085ac9af79SJeremy L Thompson   // Check if field_label and op correspond
5095ac9af79SJeremy L Thompson   if (field_label->from_op) {
5105ac9af79SJeremy L Thompson     CeedInt index = -1;
5115ac9af79SJeremy L Thompson 
5125ac9af79SJeremy L Thompson     for (CeedInt i = 0; i < op->num_context_labels; i++) {
5135ac9af79SJeremy L Thompson       if (op->context_labels[i] == field_label) index = i;
5145ac9af79SJeremy L Thompson     }
5159bc66399SJeremy L Thompson     CeedCheck(index != -1, CeedOperatorReturnCeed(op), CEED_ERROR_UNSUPPORTED, "ContextFieldLabel does not correspond to the operator");
5165ac9af79SJeremy L Thompson   }
5175ac9af79SJeremy L Thompson 
5182788fa27SJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
5192788fa27SJeremy L Thompson   if (is_composite) {
5202788fa27SJeremy L Thompson     CeedInt       num_sub;
5212788fa27SJeremy L Thompson     CeedOperator *sub_operators;
5222788fa27SJeremy L Thompson 
523ed094490SJeremy L Thompson     CeedCall(CeedOperatorCompositeGetNumSub(op, &num_sub));
524ed094490SJeremy L Thompson     CeedCall(CeedOperatorCompositeGetSubList(op, &sub_operators));
5259bc66399SJeremy L Thompson     CeedCheck(num_sub == field_label->num_sub_labels, CeedOperatorReturnCeed(op), CEED_ERROR_UNSUPPORTED,
5269bc66399SJeremy L Thompson               "Composite operator modified after ContextFieldLabel created");
5272788fa27SJeremy L Thompson 
5282788fa27SJeremy L Thompson     for (CeedInt i = 0; i < num_sub; i++) {
5291203703bSJeremy L Thompson       CeedQFunctionContext ctx;
5301203703bSJeremy L Thompson 
5311485364cSJeremy L Thompson       CeedCall(CeedOperatorGetContext(sub_operators[i], &ctx));
5322788fa27SJeremy L Thompson       // Try every sub-operator, ok if some sub-operators do not have field
5331485364cSJeremy L Thompson       if (ctx && field_label->sub_labels[i]) {
5341203703bSJeremy L Thompson         CeedCall(CeedQFunctionContextRestoreGenericRead(ctx, field_label->sub_labels[i], field_type, values));
5351485364cSJeremy L Thompson         CeedCall(CeedQFunctionContextDestroy(&ctx));
5362788fa27SJeremy L Thompson         return CEED_ERROR_SUCCESS;
5372788fa27SJeremy L Thompson       }
5381485364cSJeremy L Thompson       CeedCall(CeedQFunctionContextDestroy(&ctx));
5392788fa27SJeremy L Thompson     }
5402788fa27SJeremy L Thompson   } else {
5411203703bSJeremy L Thompson     CeedQFunctionContext ctx;
5421203703bSJeremy L Thompson 
5431485364cSJeremy L Thompson     CeedCall(CeedOperatorGetContext(op, &ctx));
5449bc66399SJeremy L Thompson     CeedCheck(ctx, CeedOperatorReturnCeed(op), CEED_ERROR_UNSUPPORTED, "QFunction does not have context data");
5451203703bSJeremy L Thompson     CeedCall(CeedQFunctionContextRestoreGenericRead(ctx, field_label, field_type, values));
5461485364cSJeremy L Thompson     CeedCall(CeedQFunctionContextDestroy(&ctx));
547d8dd9a91SJeremy L Thompson   }
548d8dd9a91SJeremy L Thompson   return CEED_ERROR_SUCCESS;
549d8dd9a91SJeremy L Thompson }
550d8dd9a91SJeremy L Thompson 
5517a982d89SJeremy L. Thompson /// @}
5527a982d89SJeremy L. Thompson 
5537a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
5547a982d89SJeremy L. Thompson /// CeedOperator Backend API
5557a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
5567a982d89SJeremy L. Thompson /// @addtogroup CeedOperatorBackend
5577a982d89SJeremy L. Thompson /// @{
5587a982d89SJeremy L. Thompson 
5597a982d89SJeremy L. Thompson /**
560ca94c3ddSJeremy L Thompson   @brief Get the number of arguments associated with a `CeedOperator`
5617a982d89SJeremy L. Thompson 
562ca94c3ddSJeremy L Thompson   @param[in]  op        `CeedOperator`
563d1d35e2fSjeremylt   @param[out] num_args  Variable to store vector number of arguments
5647a982d89SJeremy L. Thompson 
5657a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5667a982d89SJeremy L. Thompson 
5677a982d89SJeremy L. Thompson   @ref Backend
5687a982d89SJeremy L. Thompson **/
569d1d35e2fSjeremylt int CeedOperatorGetNumArgs(CeedOperator op, CeedInt *num_args) {
5701203703bSJeremy L Thompson   bool is_composite;
5711203703bSJeremy L Thompson 
5721203703bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
5736e536b99SJeremy L Thompson   CeedCheck(!is_composite, CeedOperatorReturnCeed(op), CEED_ERROR_MINOR, "Not defined for composite operators");
574d1d35e2fSjeremylt   *num_args = op->num_fields;
575e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5767a982d89SJeremy L. Thompson }
5777a982d89SJeremy L. Thompson 
5787a982d89SJeremy L. Thompson /**
5799463e855SJeremy L Thompson   @brief Get the tensor product status of all bases for a `CeedOperator`.
5809463e855SJeremy L Thompson 
5819463e855SJeremy L Thompson   `has_tensor_bases` is only set to `true` if every field uses a tensor-product basis.
5829463e855SJeremy L Thompson 
5839463e855SJeremy L Thompson   @param[in]  op               `CeedOperator`
5849463e855SJeremy L Thompson   @param[out] has_tensor_bases Variable to store tensor bases status
5859463e855SJeremy L Thompson 
5869463e855SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
5879463e855SJeremy L Thompson 
5889463e855SJeremy L Thompson   @ref Backend
5899463e855SJeremy L Thompson **/
5909463e855SJeremy L Thompson int CeedOperatorHasTensorBases(CeedOperator op, bool *has_tensor_bases) {
5919463e855SJeremy L Thompson   CeedInt            num_inputs, num_outputs;
5929463e855SJeremy L Thompson   CeedOperatorField *input_fields, *output_fields;
5939463e855SJeremy L Thompson 
5949463e855SJeremy L Thompson   CeedCall(CeedOperatorGetFields(op, &num_inputs, &input_fields, &num_outputs, &output_fields));
5959463e855SJeremy L Thompson   *has_tensor_bases = true;
5969463e855SJeremy L Thompson   for (CeedInt i = 0; i < num_inputs; i++) {
5979463e855SJeremy L Thompson     bool      is_tensor;
5989463e855SJeremy L Thompson     CeedBasis basis;
5999463e855SJeremy L Thompson 
6009463e855SJeremy L Thompson     CeedCall(CeedOperatorFieldGetBasis(input_fields[i], &basis));
6019463e855SJeremy L Thompson     if (basis != CEED_BASIS_NONE) {
6029463e855SJeremy L Thompson       CeedCall(CeedBasisIsTensor(basis, &is_tensor));
603025ec10cSJeremy L Thompson       *has_tensor_bases = *has_tensor_bases & is_tensor;
6049463e855SJeremy L Thompson     }
605681d0ea7SJeremy L Thompson     CeedCall(CeedBasisDestroy(&basis));
6069463e855SJeremy L Thompson   }
6079463e855SJeremy L Thompson   for (CeedInt i = 0; i < num_outputs; i++) {
6089463e855SJeremy L Thompson     bool      is_tensor;
6099463e855SJeremy L Thompson     CeedBasis basis;
6109463e855SJeremy L Thompson 
6119463e855SJeremy L Thompson     CeedCall(CeedOperatorFieldGetBasis(output_fields[i], &basis));
6129463e855SJeremy L Thompson     if (basis != CEED_BASIS_NONE) {
6139463e855SJeremy L Thompson       CeedCall(CeedBasisIsTensor(basis, &is_tensor));
614025ec10cSJeremy L Thompson       *has_tensor_bases = *has_tensor_bases & is_tensor;
6159463e855SJeremy L Thompson     }
616681d0ea7SJeremy L Thompson     CeedCall(CeedBasisDestroy(&basis));
6179463e855SJeremy L Thompson   }
6189463e855SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6199463e855SJeremy L Thompson }
6209463e855SJeremy L Thompson 
6219463e855SJeremy L Thompson /**
6221203703bSJeremy L Thompson   @brief Get a boolean value indicating if the `CeedOperator` is immutable
6231203703bSJeremy L Thompson 
6241203703bSJeremy L Thompson   @param[in]  op           `CeedOperator`
6251203703bSJeremy L Thompson   @param[out] is_immutable Variable to store immutability status
6261203703bSJeremy L Thompson 
6271203703bSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
6281203703bSJeremy L Thompson 
6291203703bSJeremy L Thompson   @ref Backend
6301203703bSJeremy L Thompson **/
6311203703bSJeremy L Thompson int CeedOperatorIsImmutable(CeedOperator op, bool *is_immutable) {
6321203703bSJeremy L Thompson   *is_immutable = op->is_immutable;
6331203703bSJeremy L Thompson   return CEED_ERROR_SUCCESS;
6341203703bSJeremy L Thompson }
6351203703bSJeremy L Thompson 
6361203703bSJeremy L Thompson /**
637ca94c3ddSJeremy L Thompson   @brief Get the setup status of a `CeedOperator`
6387a982d89SJeremy L. Thompson 
639ca94c3ddSJeremy L Thompson   @param[in]  op            `CeedOperator`
640d1d35e2fSjeremylt   @param[out] is_setup_done Variable to store setup status
6417a982d89SJeremy L. Thompson 
6427a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6437a982d89SJeremy L. Thompson 
6447a982d89SJeremy L. Thompson   @ref Backend
6457a982d89SJeremy L. Thompson **/
646d1d35e2fSjeremylt int CeedOperatorIsSetupDone(CeedOperator op, bool *is_setup_done) {
647f04ea552SJeremy L Thompson   *is_setup_done = op->is_backend_setup;
648e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6497a982d89SJeremy L. Thompson }
6507a982d89SJeremy L. Thompson 
6517a982d89SJeremy L. Thompson /**
652ca94c3ddSJeremy L Thompson   @brief Get the `CeedQFunction` associated with a `CeedOperator`
6537a982d89SJeremy L. Thompson 
654ca94c3ddSJeremy L Thompson   @param[in]  op `CeedOperator`
655ca94c3ddSJeremy L Thompson   @param[out] qf Variable to store `CeedQFunction`
6567a982d89SJeremy L. Thompson 
6577a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6587a982d89SJeremy L. Thompson 
6597a982d89SJeremy L. Thompson   @ref Backend
6607a982d89SJeremy L. Thompson **/
6617a982d89SJeremy L. Thompson int CeedOperatorGetQFunction(CeedOperator op, CeedQFunction *qf) {
6621203703bSJeremy L Thompson   bool is_composite;
6631203703bSJeremy L Thompson 
6641203703bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
6656e536b99SJeremy L Thompson   CeedCheck(!is_composite, CeedOperatorReturnCeed(op), CEED_ERROR_MINOR, "Not defined for composite operator");
666c11e12f4SJeremy L Thompson   *qf = NULL;
667c11e12f4SJeremy L Thompson   CeedCall(CeedQFunctionReferenceCopy(op->qf, qf));
668e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6697a982d89SJeremy L. Thompson }
6707a982d89SJeremy L. Thompson 
6717a982d89SJeremy L. Thompson /**
672ca94c3ddSJeremy L Thompson   @brief Get a boolean value indicating if the `CeedOperator` is composite
673c04a41a7SJeremy L Thompson 
674ca94c3ddSJeremy L Thompson   @param[in]  op           `CeedOperator`
675d1d35e2fSjeremylt   @param[out] is_composite Variable to store composite status
676c04a41a7SJeremy L Thompson 
677c04a41a7SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
678c04a41a7SJeremy L Thompson 
679c04a41a7SJeremy L Thompson   @ref Backend
680c04a41a7SJeremy L Thompson **/
681d1d35e2fSjeremylt int CeedOperatorIsComposite(CeedOperator op, bool *is_composite) {
682f04ea552SJeremy L Thompson   *is_composite = op->is_composite;
683e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
684c04a41a7SJeremy L Thompson }
685c04a41a7SJeremy L Thompson 
686c04a41a7SJeremy L Thompson /**
687ca94c3ddSJeremy L Thompson   @brief Get the backend data of a `CeedOperator`
6887a982d89SJeremy L. Thompson 
689ca94c3ddSJeremy L Thompson   @param[in]  op   `CeedOperator`
6907a982d89SJeremy L. Thompson   @param[out] data Variable to store data
6917a982d89SJeremy L. Thompson 
6927a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6937a982d89SJeremy L. Thompson 
6947a982d89SJeremy L. Thompson   @ref Backend
6957a982d89SJeremy L. Thompson **/
696777ff853SJeremy L Thompson int CeedOperatorGetData(CeedOperator op, void *data) {
697777ff853SJeremy L Thompson   *(void **)data = op->data;
698e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6997a982d89SJeremy L. Thompson }
7007a982d89SJeremy L. Thompson 
7017a982d89SJeremy L. Thompson /**
702ca94c3ddSJeremy L Thompson   @brief Set the backend data of a `CeedOperator`
7037a982d89SJeremy L. Thompson 
704ca94c3ddSJeremy L Thompson   @param[in,out] op   `CeedOperator`
705ea61e9acSJeremy L Thompson   @param[in]     data Data to set
7067a982d89SJeremy L. Thompson 
7077a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
7087a982d89SJeremy L. Thompson 
7097a982d89SJeremy L. Thompson   @ref Backend
7107a982d89SJeremy L. Thompson **/
711777ff853SJeremy L Thompson int CeedOperatorSetData(CeedOperator op, void *data) {
712777ff853SJeremy L Thompson   op->data = data;
713e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
7147a982d89SJeremy L. Thompson }
7157a982d89SJeremy L. Thompson 
7167a982d89SJeremy L. Thompson /**
717ca94c3ddSJeremy L Thompson   @brief Increment the reference counter for a `CeedOperator`
71834359f16Sjeremylt 
719ca94c3ddSJeremy L Thompson   @param[in,out] op `CeedOperator` to increment the reference counter
72034359f16Sjeremylt 
72134359f16Sjeremylt   @return An error code: 0 - success, otherwise - failure
72234359f16Sjeremylt 
72334359f16Sjeremylt   @ref Backend
72434359f16Sjeremylt **/
7259560d06aSjeremylt int CeedOperatorReference(CeedOperator op) {
726*b0f67a9cSJeremy L Thompson   CeedCall(CeedObjectReference((CeedObject)op));
72734359f16Sjeremylt   return CEED_ERROR_SUCCESS;
72834359f16Sjeremylt }
72934359f16Sjeremylt 
73034359f16Sjeremylt /**
731ca94c3ddSJeremy L Thompson   @brief Set the setup flag of a `CeedOperator` to `true`
7327a982d89SJeremy L. Thompson 
733ca94c3ddSJeremy L Thompson   @param[in,out] op `CeedOperator`
7347a982d89SJeremy L. Thompson 
7357a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
7367a982d89SJeremy L. Thompson 
7377a982d89SJeremy L. Thompson   @ref Backend
7387a982d89SJeremy L. Thompson **/
7397a982d89SJeremy L. Thompson int CeedOperatorSetSetupDone(CeedOperator op) {
740f04ea552SJeremy L Thompson   op->is_backend_setup = true;
741e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
7427a982d89SJeremy L. Thompson }
7437a982d89SJeremy L. Thompson 
7447a982d89SJeremy L. Thompson /// @}
7457a982d89SJeremy L. Thompson 
7467a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
7477a982d89SJeremy L. Thompson /// CeedOperator Public API
7487a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
7497a982d89SJeremy L. Thompson /// @addtogroup CeedOperatorUser
750dfdf5a53Sjeremylt /// @{
751d7b241e6Sjeremylt 
752d7b241e6Sjeremylt /**
753ca94c3ddSJeremy L Thompson   @brief Create a `CeedOperator` and associate a `CeedQFunction`.
7544385fb7fSSebastian Grimberg 
755ca94c3ddSJeremy L Thompson   A `CeedBasis` and `CeedElemRestriction` can be associated with `CeedQFunction` fields with @ref CeedOperatorSetField().
756d7b241e6Sjeremylt 
757ca94c3ddSJeremy L Thompson   @param[in]  ceed `Ceed` object used to create the `CeedOperator`
758ca94c3ddSJeremy L Thompson   @param[in]  qf   `CeedQFunction` defining the action of the operator at quadrature points
759ca94c3ddSJeremy L Thompson   @param[in]  dqf  `CeedQFunction` defining the action of the Jacobian of `qf` (or @ref CEED_QFUNCTION_NONE)
760ca94c3ddSJeremy L Thompson   @param[in]  dqfT `CeedQFunction` defining the action of the transpose of the Jacobian of `qf` (or @ref CEED_QFUNCTION_NONE)
761ca94c3ddSJeremy L Thompson   @param[out] op   Address of the variable where the newly created `CeedOperator` will be stored
762b11c1e72Sjeremylt 
763b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
764dfdf5a53Sjeremylt 
7657a982d89SJeremy L. Thompson   @ref User
766d7b241e6Sjeremylt  */
7672b730f8bSJeremy L Thompson int CeedOperatorCreate(Ceed ceed, CeedQFunction qf, CeedQFunction dqf, CeedQFunction dqfT, CeedOperator *op) {
7685fe0d4faSjeremylt   if (!ceed->OperatorCreate) {
7695fe0d4faSjeremylt     Ceed delegate;
7706574a04fSJeremy L Thompson 
7712b730f8bSJeremy L Thompson     CeedCall(CeedGetObjectDelegate(ceed, &delegate, "Operator"));
7721ef3a2a9SJeremy L Thompson     CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement CeedOperatorCreate");
7732b730f8bSJeremy L Thompson     CeedCall(CeedOperatorCreate(delegate, qf, dqf, dqfT, op));
7749bc66399SJeremy L Thompson     CeedCall(CeedDestroy(&delegate));
775e15f9bd0SJeremy L Thompson     return CEED_ERROR_SUCCESS;
7765fe0d4faSjeremylt   }
7775fe0d4faSjeremylt 
778ca94c3ddSJeremy L Thompson   CeedCheck(qf && qf != CEED_QFUNCTION_NONE, ceed, CEED_ERROR_MINOR, "Operator must have a valid CeedQFunction.");
779db002c03SJeremy L Thompson 
7802b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(1, op));
781*b0f67a9cSJeremy L Thompson   CeedCall(CeedObjectCreate(ceed, CeedOperatorView_Object, &(*op)->obj));
7822b104005SJeremy L Thompson   (*op)->input_size  = -1;
7832b104005SJeremy L Thompson   (*op)->output_size = -1;
784db002c03SJeremy L Thompson   CeedCall(CeedQFunctionReferenceCopy(qf, &(*op)->qf));
785db002c03SJeremy L Thompson   if (dqf && dqf != CEED_QFUNCTION_NONE) CeedCall(CeedQFunctionReferenceCopy(dqf, &(*op)->dqf));
786db002c03SJeremy L Thompson   if (dqfT && dqfT != CEED_QFUNCTION_NONE) CeedCall(CeedQFunctionReferenceCopy(dqfT, &(*op)->dqfT));
7872b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(CEED_FIELD_MAX, &(*op)->input_fields));
7882b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(CEED_FIELD_MAX, &(*op)->output_fields));
7892b730f8bSJeremy L Thompson   CeedCall(ceed->OperatorCreate(*op));
790e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
791d7b241e6Sjeremylt }
792d7b241e6Sjeremylt 
793d7b241e6Sjeremylt /**
794ca94c3ddSJeremy L Thompson   @brief Create a `CeedOperator` for evaluation at evaluation at arbitrary points in each element.
79548acf710SJeremy L Thompson 
796ca94c3ddSJeremy L Thompson   A `CeedBasis` and `CeedElemRestriction` can be associated with `CeedQFunction` fields with `CeedOperator` SetField.
797ca94c3ddSJeremy L Thompson   The locations of each point are set with @ref CeedOperatorAtPointsSetPoints().
79848acf710SJeremy L Thompson 
799ca94c3ddSJeremy L Thompson   @param[in]  ceed `Ceed` object used to create the `CeedOperator`
800ca94c3ddSJeremy L Thompson   @param[in]  qf   `CeedQFunction` defining the action of the operator at quadrature points
801ca94c3ddSJeremy L Thompson   @param[in]  dqf  `CeedQFunction` defining the action of the Jacobian of @a qf (or @ref CEED_QFUNCTION_NONE)
802ca94c3ddSJeremy L Thompson   @param[in]  dqfT `CeedQFunction` defining the action of the transpose of the Jacobian of @a qf (or @ref CEED_QFUNCTION_NONE)
80348acf710SJeremy L Thompson   @param[out] op   Address of the variable where the newly created CeedOperator will be stored
80448acf710SJeremy L Thompson 
80548acf710SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
80648acf710SJeremy L Thompson 
80748acf710SJeremy L Thompson   @ref User
80848acf710SJeremy L Thompson  */
80948acf710SJeremy L Thompson int CeedOperatorCreateAtPoints(Ceed ceed, CeedQFunction qf, CeedQFunction dqf, CeedQFunction dqfT, CeedOperator *op) {
81048acf710SJeremy L Thompson   if (!ceed->OperatorCreateAtPoints) {
81148acf710SJeremy L Thompson     Ceed delegate;
81248acf710SJeremy L Thompson 
81348acf710SJeremy L Thompson     CeedCall(CeedGetObjectDelegate(ceed, &delegate, "Operator"));
8141ef3a2a9SJeremy L Thompson     CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement CeedOperatorCreateAtPoints");
81548acf710SJeremy L Thompson     CeedCall(CeedOperatorCreateAtPoints(delegate, qf, dqf, dqfT, op));
8169bc66399SJeremy L Thompson     CeedCall(CeedDestroy(&delegate));
81748acf710SJeremy L Thompson     return CEED_ERROR_SUCCESS;
81848acf710SJeremy L Thompson   }
81948acf710SJeremy L Thompson 
820ca94c3ddSJeremy L Thompson   CeedCheck(qf && qf != CEED_QFUNCTION_NONE, ceed, CEED_ERROR_MINOR, "Operator must have a valid CeedQFunction.");
82148acf710SJeremy L Thompson 
82248acf710SJeremy L Thompson   CeedCall(CeedCalloc(1, op));
823*b0f67a9cSJeremy L Thompson   CeedCall(CeedObjectCreate(ceed, CeedOperatorView_Object, &(*op)->obj));
82448acf710SJeremy L Thompson   (*op)->is_at_points = true;
82548acf710SJeremy L Thompson   (*op)->input_size   = -1;
82648acf710SJeremy L Thompson   (*op)->output_size  = -1;
82748acf710SJeremy L Thompson   CeedCall(CeedQFunctionReferenceCopy(qf, &(*op)->qf));
82848acf710SJeremy L Thompson   if (dqf && dqf != CEED_QFUNCTION_NONE) CeedCall(CeedQFunctionReferenceCopy(dqf, &(*op)->dqf));
82948acf710SJeremy L Thompson   if (dqfT && dqfT != CEED_QFUNCTION_NONE) CeedCall(CeedQFunctionReferenceCopy(dqfT, &(*op)->dqfT));
83048acf710SJeremy L Thompson   CeedCall(CeedCalloc(CEED_FIELD_MAX, &(*op)->input_fields));
83148acf710SJeremy L Thompson   CeedCall(CeedCalloc(CEED_FIELD_MAX, &(*op)->output_fields));
83248acf710SJeremy L Thompson   CeedCall(ceed->OperatorCreateAtPoints(*op));
83348acf710SJeremy L Thompson   return CEED_ERROR_SUCCESS;
83448acf710SJeremy L Thompson }
83548acf710SJeremy L Thompson 
83648acf710SJeremy L Thompson /**
837ca94c3ddSJeremy L Thompson   @brief Create a composite `CeedOperator` that composes the action of several `CeedOperator`
83852d6035fSJeremy L Thompson 
839ca94c3ddSJeremy L Thompson   @param[in]  ceed `Ceed` object used to create the `CeedOperator`
840ca94c3ddSJeremy L Thompson   @param[out] op   Address of the variable where the newly created composite `CeedOperator` will be stored
84152d6035fSJeremy L Thompson 
84252d6035fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
84352d6035fSJeremy L Thompson 
8447a982d89SJeremy L. Thompson   @ref User
84552d6035fSJeremy L Thompson  */
846ed094490SJeremy L Thompson int CeedOperatorCreateComposite(Ceed ceed, CeedOperator *op) {
84752d6035fSJeremy L Thompson   if (!ceed->CompositeOperatorCreate) {
84852d6035fSJeremy L Thompson     Ceed delegate;
84952d6035fSJeremy L Thompson 
8501c66c397SJeremy L Thompson     CeedCall(CeedGetObjectDelegate(ceed, &delegate, "Operator"));
851250756a7Sjeremylt     if (delegate) {
852ed094490SJeremy L Thompson       CeedCall(CeedOperatorCreateComposite(delegate, op));
8539bc66399SJeremy L Thompson       CeedCall(CeedDestroy(&delegate));
854e15f9bd0SJeremy L Thompson       return CEED_ERROR_SUCCESS;
85552d6035fSJeremy L Thompson     }
856250756a7Sjeremylt   }
85752d6035fSJeremy L Thompson 
8582b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(1, op));
859*b0f67a9cSJeremy L Thompson   CeedCall(CeedObjectCreate(ceed, CeedOperatorView_Object, &(*op)->obj));
860f04ea552SJeremy L Thompson   (*op)->is_composite = true;
8612b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(CEED_COMPOSITE_MAX, &(*op)->sub_operators));
8622b104005SJeremy L Thompson   (*op)->input_size  = -1;
8632b104005SJeremy L Thompson   (*op)->output_size = -1;
864250756a7Sjeremylt 
865db002c03SJeremy L Thompson   if (ceed->CompositeOperatorCreate) CeedCall(ceed->CompositeOperatorCreate(*op));
866e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
86752d6035fSJeremy L Thompson }
86852d6035fSJeremy L Thompson 
86952d6035fSJeremy L Thompson /**
870ca94c3ddSJeremy L Thompson   @brief Copy the pointer to a `CeedOperator`.
8714385fb7fSSebastian Grimberg 
872ca94c3ddSJeremy L Thompson   Both pointers should be destroyed with @ref CeedOperatorDestroy().
873512bb800SJeremy L Thompson 
874ca94c3ddSJeremy 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`.
875ca94c3ddSJeremy L Thompson         This `CeedOperator` will be destroyed if `*op_copy` is the only reference to this `CeedOperator`.
8769560d06aSjeremylt 
877ca94c3ddSJeremy L Thompson   @param[in]     op      `CeedOperator` to copy reference to
878ea61e9acSJeremy L Thompson   @param[in,out] op_copy Variable to store copied reference
8799560d06aSjeremylt 
8809560d06aSjeremylt   @return An error code: 0 - success, otherwise - failure
8819560d06aSjeremylt 
8829560d06aSjeremylt   @ref User
8839560d06aSjeremylt **/
8849560d06aSjeremylt int CeedOperatorReferenceCopy(CeedOperator op, CeedOperator *op_copy) {
8852b730f8bSJeremy L Thompson   CeedCall(CeedOperatorReference(op));
8862b730f8bSJeremy L Thompson   CeedCall(CeedOperatorDestroy(op_copy));
8879560d06aSjeremylt   *op_copy = op;
8889560d06aSjeremylt   return CEED_ERROR_SUCCESS;
8899560d06aSjeremylt }
8909560d06aSjeremylt 
8919560d06aSjeremylt /**
892ca94c3ddSJeremy L Thompson   @brief Provide a field to a `CeedOperator` for use by its `CeedQFunction`.
893d7b241e6Sjeremylt 
894ca94c3ddSJeremy L Thompson   This function is used to specify both active and passive fields to a `CeedOperator`.
895bafebce1SSebastian Grimberg   For passive fields, a `CeedVector` `vec` must be provided.
896ea61e9acSJeremy L Thompson   Passive fields can inputs or outputs (updated in-place when operator is applied).
897d7b241e6Sjeremylt 
898ca94c3ddSJeremy L Thompson   Active fields must be specified using this function, but their data (in a `CeedVector`) is passed in @ref CeedOperatorApply().
899ca94c3ddSJeremy L Thompson   There can be at most one active input `CeedVector` and at most one active output@ref  CeedVector passed to @ref CeedOperatorApply().
900d7b241e6Sjeremylt 
901528a22edSJeremy L Thompson   The number of quadrature points must agree across all points.
902bafebce1SSebastian Grimberg   When using @ref CEED_BASIS_NONE, the number of quadrature points is determined by the element size of `rstr`.
903528a22edSJeremy L Thompson 
904ca94c3ddSJeremy L Thompson   @param[in,out] op         `CeedOperator` on which to provide the field
905ca94c3ddSJeremy L Thompson   @param[in]     field_name Name of the field (to be matched with the name used by `CeedQFunction`)
906bafebce1SSebastian Grimberg   @param[in]     rstr       `CeedElemRestriction`
907bafebce1SSebastian Grimberg   @param[in]     basis      `CeedBasis` in which the field resides or @ref CEED_BASIS_NONE if collocated with quadrature points
908bafebce1SSebastian 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`
909b11c1e72Sjeremylt 
910b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
911dfdf5a53Sjeremylt 
9127a982d89SJeremy L. Thompson   @ref User
913b11c1e72Sjeremylt **/
914bafebce1SSebastian Grimberg int CeedOperatorSetField(CeedOperator op, const char *field_name, CeedElemRestriction rstr, CeedBasis basis, CeedVector vec) {
9151203703bSJeremy L Thompson   bool               is_input = true, is_at_points, is_composite, is_immutable;
9161203703bSJeremy L Thompson   CeedInt            num_elem = 0, num_qpts = 0, num_input_fields, num_output_fields;
9171203703bSJeremy L Thompson   CeedQFunction      qf;
9181203703bSJeremy L Thompson   CeedQFunctionField qf_field, *qf_input_fields, *qf_output_fields;
9191c66c397SJeremy L Thompson   CeedOperatorField *op_field;
9201c66c397SJeremy L Thompson 
9211203703bSJeremy L Thompson   CeedCall(CeedOperatorIsAtPoints(op, &is_at_points));
9221203703bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
9231203703bSJeremy L Thompson   CeedCall(CeedOperatorIsImmutable(op, &is_immutable));
9249bc66399SJeremy L Thompson   CeedCheck(!is_composite, CeedOperatorReturnCeed(op), CEED_ERROR_INCOMPATIBLE, "Cannot add field to composite operator.");
9259bc66399SJeremy L Thompson   CeedCheck(!is_immutable, CeedOperatorReturnCeed(op), CEED_ERROR_MAJOR, "Operator cannot be changed after set as immutable");
9269bc66399SJeremy L Thompson   CeedCheck(rstr, CeedOperatorReturnCeed(op), CEED_ERROR_INCOMPATIBLE, "CeedElemRestriction rstr for field \"%s\" must be non-NULL.", field_name);
9279bc66399SJeremy L Thompson   CeedCheck(basis, CeedOperatorReturnCeed(op), CEED_ERROR_INCOMPATIBLE, "CeedBasis basis for field \"%s\" must be non-NULL.", field_name);
9289bc66399SJeremy L Thompson   CeedCheck(vec, CeedOperatorReturnCeed(op), CEED_ERROR_INCOMPATIBLE, "CeedVector vec for field \"%s\" must be non-NULL.", field_name);
92952d6035fSJeremy L Thompson 
930bafebce1SSebastian Grimberg   CeedCall(CeedElemRestrictionGetNumElements(rstr, &num_elem));
9319bc66399SJeremy L Thompson   CeedCheck(rstr == CEED_ELEMRESTRICTION_NONE || !op->has_restriction || num_elem == op->num_elem, CeedOperatorReturnCeed(op), CEED_ERROR_DIMENSION,
932ca94c3ddSJeremy L Thompson             "CeedElemRestriction with %" CeedInt_FMT " elements incompatible with prior %" CeedInt_FMT " elements", num_elem, op->num_elem);
9332c7e7413SJeremy L Thompson   {
9342c7e7413SJeremy L Thompson     CeedRestrictionType rstr_type;
9352c7e7413SJeremy L Thompson 
936bafebce1SSebastian Grimberg     CeedCall(CeedElemRestrictionGetType(rstr, &rstr_type));
93748acf710SJeremy L Thompson     if (rstr_type == CEED_RESTRICTION_POINTS) {
9389bc66399SJeremy L Thompson       CeedCheck(is_at_points, CeedOperatorReturnCeed(op), CEED_ERROR_UNSUPPORTED,
9399bc66399SJeremy L Thompson                 "CeedElemRestriction AtPoints not supported for standard operator fields");
9409bc66399SJeremy L Thompson       CeedCheck(basis == CEED_BASIS_NONE, CeedOperatorReturnCeed(op), CEED_ERROR_UNSUPPORTED,
9419bc66399SJeremy L Thompson                 "CeedElemRestriction AtPoints must be used with CEED_BASIS_NONE");
94248acf710SJeremy L Thompson       if (!op->first_points_rstr) {
943bafebce1SSebastian Grimberg         CeedCall(CeedElemRestrictionReferenceCopy(rstr, &op->first_points_rstr));
94448acf710SJeremy L Thompson       } else {
94548acf710SJeremy L Thompson         bool are_compatible;
94648acf710SJeremy L Thompson 
947bafebce1SSebastian Grimberg         CeedCall(CeedElemRestrictionAtPointsAreCompatible(op->first_points_rstr, rstr, &are_compatible));
9489bc66399SJeremy L Thompson         CeedCheck(are_compatible, CeedOperatorReturnCeed(op), CEED_ERROR_INCOMPATIBLE,
949ca94c3ddSJeremy L Thompson                   "CeedElemRestriction must have compatible offsets with previously set CeedElemRestriction");
95048acf710SJeremy L Thompson       }
95148acf710SJeremy L Thompson     }
9522c7e7413SJeremy L Thompson   }
953d7b241e6Sjeremylt 
954bafebce1SSebastian Grimberg   if (basis == CEED_BASIS_NONE) CeedCall(CeedElemRestrictionGetElementSize(rstr, &num_qpts));
955bafebce1SSebastian Grimberg   else CeedCall(CeedBasisGetNumQuadraturePoints(basis, &num_qpts));
9569bc66399SJeremy L Thompson   CeedCheck(op->num_qpts == 0 || num_qpts == op->num_qpts, CeedOperatorReturnCeed(op), CEED_ERROR_DIMENSION,
957ca94c3ddSJeremy L Thompson             "%s must correspond to the same number of quadrature points as previously added CeedBases. Found %" CeedInt_FMT
958528a22edSJeremy L Thompson             " quadrature points but expected %" CeedInt_FMT " quadrature points.",
959bafebce1SSebastian Grimberg             basis == CEED_BASIS_NONE ? "CeedElemRestriction" : "CeedBasis", num_qpts, op->num_qpts);
9601203703bSJeremy L Thompson 
9611203703bSJeremy L Thompson   CeedCall(CeedOperatorGetQFunction(op, &qf));
9621203703bSJeremy L Thompson   CeedCall(CeedQFunctionGetFields(qf, &num_input_fields, &qf_input_fields, &num_output_fields, &qf_output_fields));
963c11e12f4SJeremy L Thompson   CeedCall(CeedQFunctionDestroy(&qf));
9641203703bSJeremy L Thompson   for (CeedInt i = 0; i < num_input_fields; i++) {
9656f8994e9SJeremy L Thompson     const char *qf_field_name;
9661203703bSJeremy L Thompson 
9671203703bSJeremy L Thompson     CeedCall(CeedQFunctionFieldGetName(qf_input_fields[i], &qf_field_name));
9681203703bSJeremy L Thompson     if (!strcmp(field_name, qf_field_name)) {
9691203703bSJeremy L Thompson       qf_field = qf_input_fields[i];
970d1d35e2fSjeremylt       op_field = &op->input_fields[i];
971d7b241e6Sjeremylt       goto found;
972d7b241e6Sjeremylt     }
973d7b241e6Sjeremylt   }
9742b104005SJeremy L Thompson   is_input = false;
9751203703bSJeremy L Thompson   for (CeedInt i = 0; i < num_output_fields; i++) {
9766f8994e9SJeremy L Thompson     const char *qf_field_name;
9771203703bSJeremy L Thompson 
9781203703bSJeremy L Thompson     CeedCall(CeedQFunctionFieldGetName(qf_output_fields[i], &qf_field_name));
9791203703bSJeremy L Thompson     if (!strcmp(field_name, qf_field_name)) {
9801203703bSJeremy L Thompson       qf_field = qf_output_fields[i];
981d1d35e2fSjeremylt       op_field = &op->output_fields[i];
982d7b241e6Sjeremylt       goto found;
983d7b241e6Sjeremylt     }
984d7b241e6Sjeremylt   }
985c042f62fSJeremy L Thompson   // LCOV_EXCL_START
9869bc66399SJeremy L Thompson   return CeedError(CeedOperatorReturnCeed(op), CEED_ERROR_INCOMPLETE, "CeedQFunction has no knowledge of field '%s'", field_name);
987c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
988d7b241e6Sjeremylt found:
9899bc66399SJeremy L Thompson   CeedCall(CeedOperatorCheckField(CeedOperatorReturnCeed(op), qf_field, rstr, basis));
9902b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(1, op_field));
991e15f9bd0SJeremy L Thompson 
992bafebce1SSebastian Grimberg   if (vec == CEED_VECTOR_ACTIVE) {
9932b104005SJeremy L Thompson     CeedSize l_size;
9941c66c397SJeremy L Thompson 
995bafebce1SSebastian Grimberg     CeedCall(CeedElemRestrictionGetLVectorSize(rstr, &l_size));
9962b104005SJeremy L Thompson     if (is_input) {
9972b104005SJeremy L Thompson       if (op->input_size == -1) op->input_size = l_size;
9989bc66399SJeremy L Thompson       CeedCheck(l_size == op->input_size, CeedOperatorReturnCeed(op), CEED_ERROR_INCOMPATIBLE,
999249f8407SJeremy L Thompson                 "LVector size %" CeedSize_FMT " does not match previous size %" CeedSize_FMT "", l_size, op->input_size);
10002b104005SJeremy L Thompson     } else {
10012b104005SJeremy L Thompson       if (op->output_size == -1) op->output_size = l_size;
10029bc66399SJeremy L Thompson       CeedCheck(l_size == op->output_size, CeedOperatorReturnCeed(op), CEED_ERROR_INCOMPATIBLE,
1003249f8407SJeremy L Thompson                 "LVector size %" CeedSize_FMT " does not match previous size %" CeedSize_FMT "", l_size, op->output_size);
10042b104005SJeremy L Thompson     }
10052b730f8bSJeremy L Thompson   }
10062b104005SJeremy L Thompson 
1007bafebce1SSebastian Grimberg   CeedCall(CeedVectorReferenceCopy(vec, &(*op_field)->vec));
1008bafebce1SSebastian Grimberg   CeedCall(CeedElemRestrictionReferenceCopy(rstr, &(*op_field)->elem_rstr));
1009bafebce1SSebastian Grimberg   if (rstr != CEED_ELEMRESTRICTION_NONE && !op->has_restriction) {
1010d1d35e2fSjeremylt     op->num_elem        = num_elem;
1011d1d35e2fSjeremylt     op->has_restriction = true;  // Restriction set, but num_elem may be 0
1012e15f9bd0SJeremy L Thompson   }
1013bafebce1SSebastian Grimberg   CeedCall(CeedBasisReferenceCopy(basis, &(*op_field)->basis));
10142a3ff1c9SZach Atkins   if (op->num_qpts == 0 && !is_at_points) op->num_qpts = num_qpts;  // no consistent number of qpts for OperatorAtPoints
1015d1d35e2fSjeremylt   op->num_fields += 1;
10162b730f8bSJeremy L Thompson   CeedCall(CeedStringAllocCopy(field_name, (char **)&(*op_field)->field_name));
1017e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1018d7b241e6Sjeremylt }
1019d7b241e6Sjeremylt 
1020d7b241e6Sjeremylt /**
1021ca94c3ddSJeremy L Thompson   @brief Get the `CeedOperator` Field of a `CeedOperator`.
102243bbe138SJeremy L Thompson 
1023ca94c3ddSJeremy L Thompson   Note: Calling this function asserts that setup is complete and sets the `CeedOperator` as immutable.
1024f04ea552SJeremy L Thompson 
1025ca94c3ddSJeremy L Thompson   @param[in]  op                `CeedOperator`
1026f74ec584SJeremy L Thompson   @param[out] num_input_fields  Variable to store number of input fields
1027ca94c3ddSJeremy L Thompson   @param[out] input_fields      Variable to store input fields
1028f74ec584SJeremy L Thompson   @param[out] num_output_fields Variable to store number of output fields
1029ca94c3ddSJeremy L Thompson   @param[out] output_fields     Variable to store output fields
103043bbe138SJeremy L Thompson 
103143bbe138SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
103243bbe138SJeremy L Thompson 
1033e9b533fbSJeremy L Thompson   @ref Advanced
103443bbe138SJeremy L Thompson **/
10352b730f8bSJeremy L Thompson int CeedOperatorGetFields(CeedOperator op, CeedInt *num_input_fields, CeedOperatorField **input_fields, CeedInt *num_output_fields,
103643bbe138SJeremy L Thompson                           CeedOperatorField **output_fields) {
10371203703bSJeremy L Thompson   bool          is_composite;
10381203703bSJeremy L Thompson   CeedQFunction qf;
10391203703bSJeremy L Thompson 
10401203703bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
10416e536b99SJeremy L Thompson   CeedCheck(!is_composite, CeedOperatorReturnCeed(op), CEED_ERROR_MINOR, "Not defined for composite operator");
10422b730f8bSJeremy L Thompson   CeedCall(CeedOperatorCheckReady(op));
104343bbe138SJeremy L Thompson 
10441203703bSJeremy L Thompson   CeedCall(CeedOperatorGetQFunction(op, &qf));
10451203703bSJeremy L Thompson   CeedCall(CeedQFunctionGetFields(qf, num_input_fields, NULL, num_output_fields, NULL));
1046c11e12f4SJeremy L Thompson   CeedCall(CeedQFunctionDestroy(&qf));
104743bbe138SJeremy L Thompson   if (input_fields) *input_fields = op->input_fields;
104843bbe138SJeremy L Thompson   if (output_fields) *output_fields = op->output_fields;
104943bbe138SJeremy L Thompson   return CEED_ERROR_SUCCESS;
105043bbe138SJeremy L Thompson }
105143bbe138SJeremy L Thompson 
105243bbe138SJeremy L Thompson /**
1053ca94c3ddSJeremy L Thompson   @brief Set the arbitrary points in each element for a `CeedOperator` at points.
105448acf710SJeremy L Thompson 
1055ca94c3ddSJeremy L Thompson   Note: Calling this function asserts that setup is complete and sets the `CeedOperator` as immutable.
105648acf710SJeremy L Thompson 
1057ca94c3ddSJeremy L Thompson   @param[in,out] op           `CeedOperator` at points
1058ca94c3ddSJeremy L Thompson   @param[in]     rstr_points  `CeedElemRestriction` for the coordinates of each point by element
1059ca94c3ddSJeremy L Thompson   @param[in]     point_coords `CeedVector` holding coordinates of each point
106048acf710SJeremy L Thompson 
106148acf710SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
106248acf710SJeremy L Thompson 
106348acf710SJeremy L Thompson   @ref Advanced
106448acf710SJeremy L Thompson **/
106548acf710SJeremy L Thompson int CeedOperatorAtPointsSetPoints(CeedOperator op, CeedElemRestriction rstr_points, CeedVector point_coords) {
10661203703bSJeremy L Thompson   bool is_at_points, is_immutable;
10672a3ff1c9SZach Atkins 
10682a3ff1c9SZach Atkins   CeedCall(CeedOperatorIsAtPoints(op, &is_at_points));
10691203703bSJeremy L Thompson   CeedCall(CeedOperatorIsImmutable(op, &is_immutable));
10709bc66399SJeremy L Thompson   CeedCheck(is_at_points, CeedOperatorReturnCeed(op), CEED_ERROR_MINOR, "Only defined for operator at points");
10719bc66399SJeremy L Thompson   CeedCheck(!is_immutable, CeedOperatorReturnCeed(op), CEED_ERROR_MAJOR, "Operator cannot be changed after set as immutable");
107248acf710SJeremy L Thompson 
107348acf710SJeremy L Thompson   if (!op->first_points_rstr) {
107448acf710SJeremy L Thompson     CeedCall(CeedElemRestrictionReferenceCopy(rstr_points, &op->first_points_rstr));
107548acf710SJeremy L Thompson   } else {
107648acf710SJeremy L Thompson     bool are_compatible;
107748acf710SJeremy L Thompson 
107848acf710SJeremy L Thompson     CeedCall(CeedElemRestrictionAtPointsAreCompatible(op->first_points_rstr, rstr_points, &are_compatible));
10799bc66399SJeremy L Thompson     CeedCheck(are_compatible, CeedOperatorReturnCeed(op), CEED_ERROR_INCOMPATIBLE,
1080ca94c3ddSJeremy L Thompson               "CeedElemRestriction must have compatible offsets with previously set field CeedElemRestriction");
108148acf710SJeremy L Thompson   }
108248acf710SJeremy L Thompson 
108348acf710SJeremy L Thompson   CeedCall(CeedElemRestrictionReferenceCopy(rstr_points, &op->rstr_points));
108448acf710SJeremy L Thompson   CeedCall(CeedVectorReferenceCopy(point_coords, &op->point_coords));
108548acf710SJeremy L Thompson   return CEED_ERROR_SUCCESS;
108648acf710SJeremy L Thompson }
108748acf710SJeremy L Thompson 
108848acf710SJeremy L Thompson /**
1089b594f9faSZach Atkins   @brief Get a boolean value indicating if the `CeedOperator` was created with `CeedOperatorCreateAtPoints`
1090b594f9faSZach Atkins 
1091b594f9faSZach Atkins   @param[in]  op           `CeedOperator`
1092b594f9faSZach Atkins   @param[out] is_at_points Variable to store at points status
1093b594f9faSZach Atkins 
1094b594f9faSZach Atkins   @return An error code: 0 - success, otherwise - failure
1095b594f9faSZach Atkins 
1096b594f9faSZach Atkins   @ref User
1097b594f9faSZach Atkins **/
1098b594f9faSZach Atkins int CeedOperatorIsAtPoints(CeedOperator op, bool *is_at_points) {
1099b594f9faSZach Atkins   *is_at_points = op->is_at_points;
1100b594f9faSZach Atkins   return CEED_ERROR_SUCCESS;
1101b594f9faSZach Atkins }
1102b594f9faSZach Atkins 
1103b594f9faSZach Atkins /**
1104ca94c3ddSJeremy L Thompson   @brief Get the arbitrary points in each element for a `CeedOperator` at points.
110548acf710SJeremy L Thompson 
1106ca94c3ddSJeremy L Thompson   Note: Calling this function asserts that setup is complete and sets the `CeedOperator` as immutable.
110748acf710SJeremy L Thompson 
1108ca94c3ddSJeremy L Thompson   @param[in]  op           `CeedOperator` at points
1109ca94c3ddSJeremy L Thompson   @param[out] rstr_points  Variable to hold `CeedElemRestriction` for the coordinates of each point by element
1110ca94c3ddSJeremy L Thompson   @param[out] point_coords Variable to hold `CeedVector` holding coordinates of each point
111148acf710SJeremy L Thompson 
111248acf710SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
111348acf710SJeremy L Thompson 
111448acf710SJeremy L Thompson   @ref Advanced
111548acf710SJeremy L Thompson **/
111648acf710SJeremy L Thompson int CeedOperatorAtPointsGetPoints(CeedOperator op, CeedElemRestriction *rstr_points, CeedVector *point_coords) {
11172a3ff1c9SZach Atkins   bool is_at_points;
11182a3ff1c9SZach Atkins 
11192a3ff1c9SZach Atkins   CeedCall(CeedOperatorIsAtPoints(op, &is_at_points));
11206e536b99SJeremy L Thompson   CeedCheck(is_at_points, CeedOperatorReturnCeed(op), CEED_ERROR_MINOR, "Only defined for operator at points");
112148acf710SJeremy L Thompson   CeedCall(CeedOperatorCheckReady(op));
112248acf710SJeremy L Thompson 
11233f919cbcSJeremy L Thompson   if (rstr_points) {
11243f919cbcSJeremy L Thompson     *rstr_points = NULL;
11253f919cbcSJeremy L Thompson     CeedCall(CeedElemRestrictionReferenceCopy(op->rstr_points, rstr_points));
11263f919cbcSJeremy L Thompson   }
11273f919cbcSJeremy L Thompson   if (point_coords) {
11283f919cbcSJeremy L Thompson     *point_coords = NULL;
11293f919cbcSJeremy L Thompson     CeedCall(CeedVectorReferenceCopy(op->point_coords, point_coords));
11303f919cbcSJeremy L Thompson   }
113148acf710SJeremy L Thompson   return CEED_ERROR_SUCCESS;
113248acf710SJeremy L Thompson }
113348acf710SJeremy L Thompson 
113448acf710SJeremy L Thompson /**
1135be9c6463SJeremy L Thompson   @brief Get a `CeedOperator` Field of a `CeedOperator` from its name.
1136be9c6463SJeremy L Thompson 
1137be9c6463SJeremy L Thompson   `op_field` is set to `NULL` if the field is not found.
1138de5900adSJames Wright 
1139ca94c3ddSJeremy L Thompson   Note: Calling this function asserts that setup is complete and sets the `CeedOperator` as immutable.
1140de5900adSJames Wright 
1141ca94c3ddSJeremy L Thompson   @param[in]  op         `CeedOperator`
1142ca94c3ddSJeremy L Thompson   @param[in]  field_name Name of desired `CeedOperator` Field
1143ca94c3ddSJeremy L Thompson   @param[out] op_field   `CeedOperator` Field corresponding to the name
1144de5900adSJames Wright 
1145de5900adSJames Wright   @return An error code: 0 - success, otherwise - failure
1146de5900adSJames Wright 
1147de5900adSJames Wright   @ref Advanced
1148de5900adSJames Wright **/
1149de5900adSJames Wright int CeedOperatorGetFieldByName(CeedOperator op, const char *field_name, CeedOperatorField *op_field) {
11506f8994e9SJeremy L Thompson   const char        *name;
1151de5900adSJames Wright   CeedInt            num_input_fields, num_output_fields;
1152de5900adSJames Wright   CeedOperatorField *input_fields, *output_fields;
1153de5900adSJames Wright 
1154be9c6463SJeremy L Thompson   *op_field = NULL;
11551c66c397SJeremy L Thompson   CeedCall(CeedOperatorGetFields(op, &num_input_fields, &input_fields, &num_output_fields, &output_fields));
1156de5900adSJames Wright   for (CeedInt i = 0; i < num_input_fields; i++) {
1157de5900adSJames Wright     CeedCall(CeedOperatorFieldGetName(input_fields[i], &name));
1158de5900adSJames Wright     if (!strcmp(name, field_name)) {
1159de5900adSJames Wright       *op_field = input_fields[i];
1160de5900adSJames Wright       return CEED_ERROR_SUCCESS;
1161de5900adSJames Wright     }
1162de5900adSJames Wright   }
1163de5900adSJames Wright   for (CeedInt i = 0; i < num_output_fields; i++) {
1164de5900adSJames Wright     CeedCall(CeedOperatorFieldGetName(output_fields[i], &name));
1165de5900adSJames Wright     if (!strcmp(name, field_name)) {
1166de5900adSJames Wright       *op_field = output_fields[i];
1167de5900adSJames Wright       return CEED_ERROR_SUCCESS;
1168de5900adSJames Wright     }
1169de5900adSJames Wright   }
1170be9c6463SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1171de5900adSJames Wright }
1172de5900adSJames Wright 
1173de5900adSJames Wright /**
1174ca94c3ddSJeremy L Thompson   @brief Get the name of a `CeedOperator` Field
117528567f8fSJeremy L Thompson 
1176ca94c3ddSJeremy L Thompson   @param[in]  op_field   `CeedOperator` Field
117728567f8fSJeremy L Thompson   @param[out] field_name Variable to store the field name
117828567f8fSJeremy L Thompson 
117928567f8fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
118028567f8fSJeremy L Thompson 
1181e9b533fbSJeremy L Thompson   @ref Advanced
118228567f8fSJeremy L Thompson **/
11836f8994e9SJeremy L Thompson int CeedOperatorFieldGetName(CeedOperatorField op_field, const char **field_name) {
11846f8994e9SJeremy L Thompson   *field_name = op_field->field_name;
118528567f8fSJeremy L Thompson   return CEED_ERROR_SUCCESS;
118628567f8fSJeremy L Thompson }
118728567f8fSJeremy L Thompson 
118828567f8fSJeremy L Thompson /**
1189681d0ea7SJeremy L Thompson   @brief Get the `CeedElemRestriction` of a `CeedOperator` Field.
1190681d0ea7SJeremy L Thompson 
1191681d0ea7SJeremy L Thompson   Note: Caller is responsible for destroying the `rstr` with @ref CeedElemRestrictionDestroy().
119243bbe138SJeremy L Thompson 
1193ca94c3ddSJeremy L Thompson   @param[in]  op_field `CeedOperator` Field
1194ca94c3ddSJeremy L Thompson   @param[out] rstr     Variable to store `CeedElemRestriction`
119543bbe138SJeremy L Thompson 
119643bbe138SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
119743bbe138SJeremy L Thompson 
1198e9b533fbSJeremy L Thompson   @ref Advanced
119943bbe138SJeremy L Thompson **/
12002b730f8bSJeremy L Thompson int CeedOperatorFieldGetElemRestriction(CeedOperatorField op_field, CeedElemRestriction *rstr) {
1201681d0ea7SJeremy L Thompson   *rstr = NULL;
1202681d0ea7SJeremy L Thompson   CeedCall(CeedElemRestrictionReferenceCopy(op_field->elem_rstr, rstr));
120343bbe138SJeremy L Thompson   return CEED_ERROR_SUCCESS;
120443bbe138SJeremy L Thompson }
120543bbe138SJeremy L Thompson 
120643bbe138SJeremy L Thompson /**
1207681d0ea7SJeremy L Thompson   @brief Get the `CeedBasis` of a `CeedOperator` Field.
1208681d0ea7SJeremy L Thompson 
1209681d0ea7SJeremy L Thompson   Note: Caller is responsible for destroying the `basis` with @ref CeedBasisDestroy().
121043bbe138SJeremy L Thompson 
1211ca94c3ddSJeremy L Thompson   @param[in]  op_field `CeedOperator` Field
1212ca94c3ddSJeremy L Thompson   @param[out] basis    Variable to store `CeedBasis`
121343bbe138SJeremy L Thompson 
121443bbe138SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
121543bbe138SJeremy L Thompson 
1216e9b533fbSJeremy L Thompson   @ref Advanced
121743bbe138SJeremy L Thompson **/
121843bbe138SJeremy L Thompson int CeedOperatorFieldGetBasis(CeedOperatorField op_field, CeedBasis *basis) {
1219681d0ea7SJeremy L Thompson   *basis = NULL;
1220681d0ea7SJeremy L Thompson   CeedCall(CeedBasisReferenceCopy(op_field->basis, basis));
122143bbe138SJeremy L Thompson   return CEED_ERROR_SUCCESS;
122243bbe138SJeremy L Thompson }
122343bbe138SJeremy L Thompson 
122443bbe138SJeremy L Thompson /**
1225681d0ea7SJeremy L Thompson   @brief Get the `CeedVector` of a `CeedOperator` Field.
1226681d0ea7SJeremy L Thompson 
1227681d0ea7SJeremy L Thompson   Note: Caller is responsible for destroying the `vec` with @ref CeedVectorDestroy().
122843bbe138SJeremy L Thompson 
1229ca94c3ddSJeremy L Thompson   @param[in]  op_field `CeedOperator` Field
1230ca94c3ddSJeremy L Thompson   @param[out] vec      Variable to store `CeedVector`
123143bbe138SJeremy L Thompson 
123243bbe138SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
123343bbe138SJeremy L Thompson 
1234e9b533fbSJeremy L Thompson   @ref Advanced
123543bbe138SJeremy L Thompson **/
123643bbe138SJeremy L Thompson int CeedOperatorFieldGetVector(CeedOperatorField op_field, CeedVector *vec) {
1237681d0ea7SJeremy L Thompson   *vec = NULL;
1238681d0ea7SJeremy L Thompson   CeedCall(CeedVectorReferenceCopy(op_field->vec, vec));
123943bbe138SJeremy L Thompson   return CEED_ERROR_SUCCESS;
124043bbe138SJeremy L Thompson }
124143bbe138SJeremy L Thompson 
124243bbe138SJeremy L Thompson /**
1243ab747706SJeremy L Thompson   @brief Get the data of a `CeedOperator` Field.
1244ab747706SJeremy L Thompson 
1245681d0ea7SJeremy L Thompson   Any arguments set as `NULL` are ignored..
1246681d0ea7SJeremy L Thompson 
1247681d0ea7SJeremy L Thompson   Note: Caller is responsible for destroying the `rstr`, `basis`, and `vec`.
1248ab747706SJeremy L Thompson 
1249ab747706SJeremy L Thompson   @param[in]  op_field   `CeedOperator` Field
1250ab747706SJeremy L Thompson   @param[out] field_name Variable to store the field name
1251ab747706SJeremy L Thompson   @param[out] rstr       Variable to store `CeedElemRestriction`
1252ab747706SJeremy L Thompson   @param[out] basis      Variable to store `CeedBasis`
1253ab747706SJeremy L Thompson   @param[out] vec        Variable to store `CeedVector`
1254ab747706SJeremy L Thompson 
1255ab747706SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1256ab747706SJeremy L Thompson 
1257ab747706SJeremy L Thompson   @ref Advanced
1258ab747706SJeremy L Thompson **/
12596f8994e9SJeremy L Thompson int CeedOperatorFieldGetData(CeedOperatorField op_field, const char **field_name, CeedElemRestriction *rstr, CeedBasis *basis, CeedVector *vec) {
1260ab747706SJeremy L Thompson   if (field_name) CeedCall(CeedOperatorFieldGetName(op_field, field_name));
1261ab747706SJeremy L Thompson   if (rstr) CeedCall(CeedOperatorFieldGetElemRestriction(op_field, rstr));
1262ab747706SJeremy L Thompson   if (basis) CeedCall(CeedOperatorFieldGetBasis(op_field, basis));
1263ab747706SJeremy L Thompson   if (vec) CeedCall(CeedOperatorFieldGetVector(op_field, vec));
1264ab747706SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1265ab747706SJeremy L Thompson }
1266ab747706SJeremy L Thompson 
1267ab747706SJeremy L Thompson /**
1268ca94c3ddSJeremy L Thompson   @brief Add a sub-operator to a composite `CeedOperator`
1269288c0443SJeremy L Thompson 
1270ca94c3ddSJeremy L Thompson   @param[in,out] composite_op Composite `CeedOperator`
1271ca94c3ddSJeremy L Thompson   @param[in]     sub_op       Sub-operator `CeedOperator`
127252d6035fSJeremy L Thompson 
127352d6035fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
127452d6035fSJeremy L Thompson 
12757a982d89SJeremy L. Thompson   @ref User
127652d6035fSJeremy L Thompson  */
1277ed094490SJeremy L Thompson int CeedOperatorCompositeAddSub(CeedOperator composite_op, CeedOperator sub_op) {
12781203703bSJeremy L Thompson   bool is_immutable;
12791203703bSJeremy L Thompson 
12809bc66399SJeremy L Thompson   CeedCheck(composite_op->is_composite, CeedOperatorReturnCeed(composite_op), CEED_ERROR_MINOR, "CeedOperator is not a composite operator");
12819bc66399SJeremy L Thompson   CeedCheck(composite_op->num_suboperators < CEED_COMPOSITE_MAX, CeedOperatorReturnCeed(composite_op), CEED_ERROR_UNSUPPORTED,
12829bc66399SJeremy L Thompson             "Cannot add additional sub-operators");
12831203703bSJeremy L Thompson   CeedCall(CeedOperatorIsImmutable(composite_op, &is_immutable));
12849bc66399SJeremy L Thompson   CeedCheck(!is_immutable, CeedOperatorReturnCeed(composite_op), CEED_ERROR_MAJOR, "Operator cannot be changed after set as immutable");
12852b730f8bSJeremy L Thompson 
12862b730f8bSJeremy L Thompson   {
12872b730f8bSJeremy L Thompson     CeedSize input_size, output_size;
12881c66c397SJeremy L Thompson 
12892b730f8bSJeremy L Thompson     CeedCall(CeedOperatorGetActiveVectorLengths(sub_op, &input_size, &output_size));
12902b730f8bSJeremy L Thompson     if (composite_op->input_size == -1) composite_op->input_size = input_size;
12912b730f8bSJeremy L Thompson     if (composite_op->output_size == -1) composite_op->output_size = output_size;
12922b730f8bSJeremy L Thompson     // Note, a size of -1 means no active vector restriction set, so no incompatibility
12939bc66399SJeremy L Thompson     CeedCheck((input_size == -1 || input_size == composite_op->input_size) && (output_size == -1 || output_size == composite_op->output_size),
12949bc66399SJeremy L Thompson               CeedOperatorReturnCeed(composite_op), CEED_ERROR_MAJOR,
1295249f8407SJeremy L Thompson               "Sub-operators must have compatible dimensions; composite operator of shape (%" CeedSize_FMT ", %" CeedSize_FMT
1296249f8407SJeremy L Thompson               ") not compatible with sub-operator of "
1297249f8407SJeremy L Thompson               "shape (%" CeedSize_FMT ", %" CeedSize_FMT ")",
12982b730f8bSJeremy L Thompson               composite_op->input_size, composite_op->output_size, input_size, output_size);
12992b730f8bSJeremy L Thompson   }
13002b730f8bSJeremy L Thompson 
1301d1d35e2fSjeremylt   composite_op->sub_operators[composite_op->num_suboperators] = sub_op;
13022b730f8bSJeremy L Thompson   CeedCall(CeedOperatorReference(sub_op));
1303d1d35e2fSjeremylt   composite_op->num_suboperators++;
1304e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
130552d6035fSJeremy L Thompson }
130652d6035fSJeremy L Thompson 
130752d6035fSJeremy L Thompson /**
1308ca94c3ddSJeremy L Thompson   @brief Get the number of sub-operators associated with a `CeedOperator`
130975f0d5a4SJeremy L Thompson 
1310ca94c3ddSJeremy L Thompson   @param[in]  op               `CeedOperator`
1311ca94c3ddSJeremy L Thompson   @param[out] num_suboperators Variable to store number of sub-operators
131275f0d5a4SJeremy L Thompson 
131375f0d5a4SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
131475f0d5a4SJeremy L Thompson 
131575f0d5a4SJeremy L Thompson   @ref Backend
131675f0d5a4SJeremy L Thompson **/
1317ed094490SJeremy L Thompson int CeedOperatorCompositeGetNumSub(CeedOperator op, CeedInt *num_suboperators) {
13181203703bSJeremy L Thompson   bool is_composite;
13191203703bSJeremy L Thompson 
13201203703bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
13216e536b99SJeremy L Thompson   CeedCheck(is_composite, CeedOperatorReturnCeed(op), CEED_ERROR_MINOR, "Only defined for a composite operator");
132275f0d5a4SJeremy L Thompson   *num_suboperators = op->num_suboperators;
132375f0d5a4SJeremy L Thompson   return CEED_ERROR_SUCCESS;
132475f0d5a4SJeremy L Thompson }
132575f0d5a4SJeremy L Thompson 
132675f0d5a4SJeremy L Thompson /**
1327ca94c3ddSJeremy L Thompson   @brief Get the list of sub-operators associated with a `CeedOperator`
132875f0d5a4SJeremy L Thompson 
1329ca94c3ddSJeremy L Thompson   @param[in]  op             `CeedOperator`
1330ca94c3ddSJeremy L Thompson   @param[out] sub_operators  Variable to store list of sub-operators
133175f0d5a4SJeremy L Thompson 
133275f0d5a4SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
133375f0d5a4SJeremy L Thompson 
133475f0d5a4SJeremy L Thompson   @ref Backend
133575f0d5a4SJeremy L Thompson **/
1336ed094490SJeremy L Thompson int CeedOperatorCompositeGetSubList(CeedOperator op, CeedOperator **sub_operators) {
13371203703bSJeremy L Thompson   bool is_composite;
13381203703bSJeremy L Thompson 
13391203703bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
13406e536b99SJeremy L Thompson   CeedCheck(is_composite, CeedOperatorReturnCeed(op), CEED_ERROR_MINOR, "Only defined for a composite operator");
134175f0d5a4SJeremy L Thompson   *sub_operators = op->sub_operators;
134275f0d5a4SJeremy L Thompson   return CEED_ERROR_SUCCESS;
134375f0d5a4SJeremy L Thompson }
134475f0d5a4SJeremy L Thompson 
134575f0d5a4SJeremy L Thompson /**
13468a297abdSJames Wright   @brief Get a sub `CeedOperator` of a composite `CeedOperator` from its name.
13478a297abdSJames Wright 
13488a297abdSJames Wright   `sub_op` is set to `NULL` if the sub operator is not found.
13498a297abdSJames Wright 
13508a297abdSJames Wright   Note: Calling this function asserts that setup is complete and sets the `CeedOperator` as immutable.
13518a297abdSJames Wright 
13528a297abdSJames Wright   @param[in]  op      Composite `CeedOperator`
13538a297abdSJames Wright   @param[in]  op_name Name of desired sub `CeedOperator`
13548a297abdSJames Wright   @param[out] sub_op  Sub `CeedOperator` corresponding to the name
13558a297abdSJames Wright 
13568a297abdSJames Wright   @return An error code: 0 - success, otherwise - failure
13578a297abdSJames Wright 
13588a297abdSJames Wright   @ref Advanced
13598a297abdSJames Wright **/
1360ed094490SJeremy L Thompson int CeedOperatorCompositeGetSubByName(CeedOperator op, const char *op_name, CeedOperator *sub_op) {
13618a297abdSJames Wright   bool          is_composite;
13628a297abdSJames Wright   CeedInt       num_sub_ops;
13638a297abdSJames Wright   CeedOperator *sub_ops;
13648a297abdSJames Wright 
13658a297abdSJames Wright   CeedCall(CeedOperatorIsComposite(op, &is_composite));
13668a297abdSJames Wright   CeedCheck(is_composite, CeedOperatorReturnCeed(op), CEED_ERROR_MINOR, "Only defined for a composite operator");
13678a297abdSJames Wright   *sub_op = NULL;
1368ed094490SJeremy L Thompson   CeedCall(CeedOperatorCompositeGetNumSub(op, &num_sub_ops));
1369ed094490SJeremy L Thompson   CeedCall(CeedOperatorCompositeGetSubList(op, &sub_ops));
13708a297abdSJames Wright   for (CeedInt i = 0; i < num_sub_ops; i++) {
13718a297abdSJames Wright     if (sub_ops[i]->name && !strcmp(op_name, sub_ops[i]->name)) {
13728a297abdSJames Wright       *sub_op = sub_ops[i];
13738a297abdSJames Wright       return CEED_ERROR_SUCCESS;
13748a297abdSJames Wright     }
13758a297abdSJames Wright   }
13768a297abdSJames Wright   return CEED_ERROR_SUCCESS;
13778a297abdSJames Wright }
13788a297abdSJames Wright 
13798a297abdSJames Wright /**
1380ca94c3ddSJeremy L Thompson   @brief Check if a `CeedOperator` is ready to be used.
13814db537f9SJeremy L Thompson 
1382ca94c3ddSJeremy L Thompson   @param[in] op `CeedOperator` to check
13834db537f9SJeremy L Thompson 
13844db537f9SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
13854db537f9SJeremy L Thompson 
13864db537f9SJeremy L Thompson   @ref User
13874db537f9SJeremy L Thompson **/
13884db537f9SJeremy L Thompson int CeedOperatorCheckReady(CeedOperator op) {
13891203703bSJeremy L Thompson   bool          is_at_points, is_composite;
13901203703bSJeremy L Thompson   CeedQFunction qf = NULL;
13914db537f9SJeremy L Thompson 
13922b730f8bSJeremy L Thompson   if (op->is_interface_setup) return CEED_ERROR_SUCCESS;
13934db537f9SJeremy L Thompson 
13941203703bSJeremy L Thompson   CeedCall(CeedOperatorIsAtPoints(op, &is_at_points));
13951203703bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
13961203703bSJeremy L Thompson   if (!is_composite) CeedCall(CeedOperatorGetQFunction(op, &qf));
13971203703bSJeremy L Thompson   if (is_composite) {
13981203703bSJeremy L Thompson     CeedInt num_suboperators;
13991203703bSJeremy L Thompson 
1400ed094490SJeremy L Thompson     CeedCall(CeedOperatorCompositeGetNumSub(op, &num_suboperators));
14011203703bSJeremy L Thompson     if (!num_suboperators) {
140243622462SJeremy L Thompson       // Empty operator setup
140343622462SJeremy L Thompson       op->input_size  = 0;
140443622462SJeremy L Thompson       op->output_size = 0;
140543622462SJeremy L Thompson     } else {
14061203703bSJeremy L Thompson       CeedOperator *sub_operators;
14071203703bSJeremy L Thompson 
1408ed094490SJeremy L Thompson       CeedCall(CeedOperatorCompositeGetSubList(op, &sub_operators));
14091203703bSJeremy L Thompson       for (CeedInt i = 0; i < num_suboperators; i++) {
14101203703bSJeremy L Thompson         CeedCall(CeedOperatorCheckReady(sub_operators[i]));
14114db537f9SJeremy L Thompson       }
14122b104005SJeremy L Thompson       // Sub-operators could be modified after adding to composite operator
14132b104005SJeremy L Thompson       // Need to verify no lvec incompatibility from any changes
14142b104005SJeremy L Thompson       CeedSize input_size, output_size;
14152b730f8bSJeremy L Thompson       CeedCall(CeedOperatorGetActiveVectorLengths(op, &input_size, &output_size));
141643622462SJeremy L Thompson     }
14174db537f9SJeremy L Thompson   } else {
14181203703bSJeremy L Thompson     CeedInt num_input_fields, num_output_fields;
14191203703bSJeremy L Thompson 
14209bc66399SJeremy L Thompson     CeedCheck(op->num_fields > 0, CeedOperatorReturnCeed(op), CEED_ERROR_INCOMPLETE, "No operator fields set");
14211203703bSJeremy L Thompson     CeedCall(CeedQFunctionGetFields(qf, &num_input_fields, NULL, &num_output_fields, NULL));
14229bc66399SJeremy L Thompson     CeedCheck(op->num_fields == num_input_fields + num_output_fields, CeedOperatorReturnCeed(op), CEED_ERROR_INCOMPLETE,
14239bc66399SJeremy L Thompson               "Not all operator fields set");
14249bc66399SJeremy L Thompson     CeedCheck(op->has_restriction, CeedOperatorReturnCeed(op), CEED_ERROR_INCOMPLETE, "At least one restriction required");
14259bc66399SJeremy L Thompson     CeedCheck(op->num_qpts > 0 || is_at_points, CeedOperatorReturnCeed(op), CEED_ERROR_INCOMPLETE,
1426ca94c3ddSJeremy L Thompson               "At least one non-collocated CeedBasis is required or the number of quadrature points must be set");
14272b730f8bSJeremy L Thompson   }
14284db537f9SJeremy L Thompson 
14294db537f9SJeremy L Thompson   // Flag as immutable and ready
14304db537f9SJeremy L Thompson   op->is_interface_setup = true;
14311203703bSJeremy L Thompson   if (qf && qf != CEED_QFUNCTION_NONE) CeedCall(CeedQFunctionSetImmutable(qf));
1432c11e12f4SJeremy L Thompson   CeedCall(CeedQFunctionDestroy(&qf));
14331203703bSJeremy L Thompson   if (op->dqf && op->dqf != CEED_QFUNCTION_NONE) CeedCall(CeedQFunctionSetImmutable(op->dqf));
14341203703bSJeremy L Thompson   if (op->dqfT && op->dqfT != CEED_QFUNCTION_NONE) CeedCall(CeedQFunctionSetImmutable(op->dqfT));
14354db537f9SJeremy L Thompson   return CEED_ERROR_SUCCESS;
14364db537f9SJeremy L Thompson }
14374db537f9SJeremy L Thompson 
14384db537f9SJeremy L Thompson /**
1439ca94c3ddSJeremy L Thompson   @brief Get vector lengths for the active input and/or output `CeedVector` of a `CeedOperator`.
14404385fb7fSSebastian Grimberg 
1441ca94c3ddSJeremy L Thompson   Note: Lengths of `-1` indicate that the CeedOperator does not have an active input and/or output.
1442c9366a6bSJeremy L Thompson 
1443ca94c3ddSJeremy L Thompson   @param[in]  op          `CeedOperator`
1444ca94c3ddSJeremy L Thompson   @param[out] input_size  Variable to store active input vector length, or `NULL`
1445ca94c3ddSJeremy L Thompson   @param[out] output_size Variable to store active output vector length, or `NULL`
1446c9366a6bSJeremy L Thompson 
1447c9366a6bSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1448c9366a6bSJeremy L Thompson 
1449c9366a6bSJeremy L Thompson   @ref User
1450c9366a6bSJeremy L Thompson **/
14512b730f8bSJeremy L Thompson int CeedOperatorGetActiveVectorLengths(CeedOperator op, CeedSize *input_size, CeedSize *output_size) {
1452c9366a6bSJeremy L Thompson   bool is_composite;
1453c9366a6bSJeremy L Thompson 
14542b104005SJeremy L Thompson   if (input_size) *input_size = op->input_size;
14552b104005SJeremy L Thompson   if (output_size) *output_size = op->output_size;
1456c9366a6bSJeremy L Thompson 
14572b730f8bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
14582b104005SJeremy L Thompson   if (is_composite && (op->input_size == -1 || op->output_size == -1)) {
14591203703bSJeremy L Thompson     CeedInt       num_suboperators;
14601203703bSJeremy L Thompson     CeedOperator *sub_operators;
14611203703bSJeremy L Thompson 
1462ed094490SJeremy L Thompson     CeedCall(CeedOperatorCompositeGetNumSub(op, &num_suboperators));
1463ed094490SJeremy L Thompson     CeedCall(CeedOperatorCompositeGetSubList(op, &sub_operators));
14641203703bSJeremy L Thompson     for (CeedInt i = 0; i < num_suboperators; i++) {
1465c9366a6bSJeremy L Thompson       CeedSize sub_input_size, sub_output_size;
14661c66c397SJeremy L Thompson 
14671203703bSJeremy L Thompson       CeedCall(CeedOperatorGetActiveVectorLengths(sub_operators[i], &sub_input_size, &sub_output_size));
14682b104005SJeremy L Thompson       if (op->input_size == -1) op->input_size = sub_input_size;
14692b104005SJeremy L Thompson       if (op->output_size == -1) op->output_size = sub_output_size;
14702b104005SJeremy L Thompson       // Note, a size of -1 means no active vector restriction set, so no incompatibility
14716e536b99SJeremy L Thompson       CeedCheck((sub_input_size == -1 || sub_input_size == op->input_size) && (sub_output_size == -1 || sub_output_size == op->output_size),
14726e536b99SJeremy L Thompson                 CeedOperatorReturnCeed(op), CEED_ERROR_MAJOR,
1473249f8407SJeremy L Thompson                 "Sub-operators must have compatible dimensions; composite operator of shape (%" CeedSize_FMT ", %" CeedSize_FMT
1474249f8407SJeremy L Thompson                 ") not compatible with sub-operator of "
1475249f8407SJeremy L Thompson                 "shape (%" CeedSize_FMT ", %" CeedSize_FMT ")",
14762b104005SJeremy L Thompson                 op->input_size, op->output_size, input_size, output_size);
1477c9366a6bSJeremy L Thompson     }
14782b730f8bSJeremy L Thompson   }
1479c9366a6bSJeremy L Thompson   return CEED_ERROR_SUCCESS;
1480c9366a6bSJeremy L Thompson }
1481c9366a6bSJeremy L Thompson 
1482c9366a6bSJeremy L Thompson /**
1483ca94c3ddSJeremy L Thompson   @brief Set reuse of `CeedQFunction` data in `CeedOperatorLinearAssemble*()` functions.
14844385fb7fSSebastian Grimberg 
1485ca94c3ddSJeremy L Thompson   When `reuse_assembly_data = false` (default), the `CeedQFunction` associated with this `CeedOperator` is re-assembled every time a `CeedOperatorLinearAssemble*()` function is called.
1486ca94c3ddSJeremy L Thompson   When `reuse_assembly_data = true`, the `CeedQFunction` associated with this `CeedOperator` is reused between calls to @ref CeedOperatorSetQFunctionAssemblyDataUpdateNeeded().
14878b919e6bSJeremy L Thompson 
1488ca94c3ddSJeremy L Thompson   @param[in] op                  `CeedOperator`
1489beecbf24SJeremy L Thompson   @param[in] reuse_assembly_data Boolean flag setting assembly data reuse
14908b919e6bSJeremy L Thompson 
14918b919e6bSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
14928b919e6bSJeremy L Thompson 
14938b919e6bSJeremy L Thompson   @ref Advanced
14948b919e6bSJeremy L Thompson **/
14952b730f8bSJeremy L Thompson int CeedOperatorSetQFunctionAssemblyReuse(CeedOperator op, bool reuse_assembly_data) {
14968b919e6bSJeremy L Thompson   bool is_composite;
14978b919e6bSJeremy L Thompson 
14982b730f8bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
14998b919e6bSJeremy L Thompson   if (is_composite) {
15008b919e6bSJeremy L Thompson     for (CeedInt i = 0; i < op->num_suboperators; i++) {
15012b730f8bSJeremy L Thompson       CeedCall(CeedOperatorSetQFunctionAssemblyReuse(op->sub_operators[i], reuse_assembly_data));
15028b919e6bSJeremy L Thompson     }
15038b919e6bSJeremy L Thompson   } else {
15047d5185d7SSebastian Grimberg     CeedQFunctionAssemblyData data;
15057d5185d7SSebastian Grimberg 
15067d5185d7SSebastian Grimberg     CeedCall(CeedOperatorGetQFunctionAssemblyData(op, &data));
15077d5185d7SSebastian Grimberg     CeedCall(CeedQFunctionAssemblyDataSetReuse(data, reuse_assembly_data));
1508beecbf24SJeremy L Thompson   }
1509beecbf24SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1510beecbf24SJeremy L Thompson }
1511beecbf24SJeremy L Thompson 
1512beecbf24SJeremy L Thompson /**
1513ca94c3ddSJeremy L Thompson   @brief Mark `CeedQFunction` data as updated and the `CeedQFunction` as requiring re-assembly.
1514beecbf24SJeremy L Thompson 
1515ca94c3ddSJeremy L Thompson   @param[in] op                `CeedOperator`
15166e15d496SJeremy L Thompson   @param[in] needs_data_update Boolean flag setting assembly data reuse
1517beecbf24SJeremy L Thompson 
1518beecbf24SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1519beecbf24SJeremy L Thompson 
1520beecbf24SJeremy L Thompson   @ref Advanced
1521beecbf24SJeremy L Thompson **/
15222b730f8bSJeremy L Thompson int CeedOperatorSetQFunctionAssemblyDataUpdateNeeded(CeedOperator op, bool needs_data_update) {
1523beecbf24SJeremy L Thompson   bool is_composite;
1524beecbf24SJeremy L Thompson 
15252b730f8bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
1526beecbf24SJeremy L Thompson   if (is_composite) {
15271203703bSJeremy L Thompson     CeedInt       num_suboperators;
15281203703bSJeremy L Thompson     CeedOperator *sub_operators;
15291203703bSJeremy L Thompson 
1530ed094490SJeremy L Thompson     CeedCall(CeedOperatorCompositeGetNumSub(op, &num_suboperators));
1531ed094490SJeremy L Thompson     CeedCall(CeedOperatorCompositeGetSubList(op, &sub_operators));
15321203703bSJeremy L Thompson     for (CeedInt i = 0; i < num_suboperators; i++) {
15331203703bSJeremy L Thompson       CeedCall(CeedOperatorSetQFunctionAssemblyDataUpdateNeeded(sub_operators[i], needs_data_update));
1534beecbf24SJeremy L Thompson     }
1535beecbf24SJeremy L Thompson   } else {
15367d5185d7SSebastian Grimberg     CeedQFunctionAssemblyData data;
15377d5185d7SSebastian Grimberg 
15387d5185d7SSebastian Grimberg     CeedCall(CeedOperatorGetQFunctionAssemblyData(op, &data));
15397d5185d7SSebastian Grimberg     CeedCall(CeedQFunctionAssemblyDataSetUpdateNeeded(data, needs_data_update));
15408b919e6bSJeremy L Thompson   }
15418b919e6bSJeremy L Thompson   return CEED_ERROR_SUCCESS;
15428b919e6bSJeremy L Thompson }
15438b919e6bSJeremy L Thompson 
15448b919e6bSJeremy L Thompson /**
1545ca94c3ddSJeremy L Thompson   @brief Set name of `CeedOperator` for @ref CeedOperatorView() output
1546ea6b5821SJeremy L Thompson 
1547ca94c3ddSJeremy L Thompson   @param[in,out] op   `CeedOperator`
1548ea61e9acSJeremy L Thompson   @param[in]     name Name to set, or NULL to remove previously set name
1549ea6b5821SJeremy L Thompson 
1550ea6b5821SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1551ea6b5821SJeremy L Thompson 
1552ea6b5821SJeremy L Thompson   @ref User
1553ea6b5821SJeremy L Thompson **/
1554ea6b5821SJeremy L Thompson int CeedOperatorSetName(CeedOperator op, const char *name) {
1555ea6b5821SJeremy L Thompson   char  *name_copy;
1556ea6b5821SJeremy L Thompson   size_t name_len = name ? strlen(name) : 0;
1557ea6b5821SJeremy L Thompson 
15582b730f8bSJeremy L Thompson   CeedCall(CeedFree(&op->name));
1559ea6b5821SJeremy L Thompson   if (name_len > 0) {
15602b730f8bSJeremy L Thompson     CeedCall(CeedCalloc(name_len + 1, &name_copy));
1561ea6b5821SJeremy L Thompson     memcpy(name_copy, name, name_len);
1562ea6b5821SJeremy L Thompson     op->name = name_copy;
1563ea6b5821SJeremy L Thompson   }
1564ea6b5821SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1565ea6b5821SJeremy L Thompson }
1566ea6b5821SJeremy L Thompson 
1567ea6b5821SJeremy L Thompson /**
1568d3d5610dSJeremy L Thompson   @brief Get name of `CeedOperator`
1569d3d5610dSJeremy L Thompson 
1570d3d5610dSJeremy L Thompson   @param[in]     op   `CeedOperator`
1571d3d5610dSJeremy L Thompson   @param[in,out] name Address of variable to hold currently set name
1572d3d5610dSJeremy L Thompson 
1573d3d5610dSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1574d3d5610dSJeremy L Thompson 
1575d3d5610dSJeremy L Thompson   @ref User
1576d3d5610dSJeremy L Thompson **/
1577d3d5610dSJeremy L Thompson int CeedOperatorGetName(CeedOperator op, const char **name) {
1578d3d5610dSJeremy L Thompson   if (op->name) {
1579d3d5610dSJeremy L Thompson     *name = op->name;
1580d3d5610dSJeremy L Thompson   } else if (!op->is_composite) {
1581d3d5610dSJeremy L Thompson     CeedQFunction qf;
1582d3d5610dSJeremy L Thompson 
1583d3d5610dSJeremy L Thompson     CeedCall(CeedOperatorGetQFunction(op, &qf));
1584d3d5610dSJeremy L Thompson     if (qf) CeedCall(CeedQFunctionGetName(qf, name));
1585d3d5610dSJeremy L Thompson     CeedCall(CeedQFunctionDestroy(&qf));
1586d3d5610dSJeremy L Thompson   }
1587d3d5610dSJeremy L Thompson   return CEED_ERROR_SUCCESS;
1588d3d5610dSJeremy L Thompson }
1589d3d5610dSJeremy L Thompson 
1590d3d5610dSJeremy L Thompson /**
1591935f026aSJeremy L Thompson   @brief Core logic for viewing a `CeedOperator`
15927a982d89SJeremy L. Thompson 
1593935f026aSJeremy L Thompson   @param[in] op     `CeedOperator` to view brief summary
1594ca94c3ddSJeremy L Thompson   @param[in] stream  Stream to write; typically `stdout` or a file
15958bf1b130SJames Wright   @param[in] is_full Whether to write full operator view or terse
15967a982d89SJeremy L. Thompson 
15977a982d89SJeremy L. Thompson   @return Error code: 0 - success, otherwise - failure
15986ab8e59fSJames Wright 
15996ab8e59fSJames Wright   @ref Developer
16007a982d89SJeremy L. Thompson **/
16018bf1b130SJames Wright static int CeedOperatorView_Core(CeedOperator op, FILE *stream, bool is_full) {
1602d3d5610dSJeremy L Thompson   bool        has_name, is_composite, is_at_points;
16035a526491SJeremy L Thompson   char       *tabs     = NULL;
1604d3d5610dSJeremy L Thompson   const char *name     = NULL;
16055a526491SJeremy L Thompson   CeedInt     num_tabs = 0;
16067a982d89SJeremy L. Thompson 
1607d3d5610dSJeremy L Thompson   CeedCall(CeedOperatorGetName(op, &name));
1608d3d5610dSJeremy L Thompson   has_name = name ? strlen(name) : false;
16091203703bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
161099f7f61fSJeremy L Thompson   CeedCall(CeedOperatorIsAtPoints(op, &is_at_points));
16115a526491SJeremy L Thompson   // Set tabs
16125a526491SJeremy L Thompson   CeedCall(CeedOperatorGetNumViewTabs(op, &num_tabs));
16134c789ea2SJeremy L Thompson   CeedCall(CeedCalloc(CEED_TAB_WIDTH * (num_tabs + is_composite) + 1, &tabs));
16144c789ea2SJeremy L Thompson   for (CeedInt i = 0; i < CEED_TAB_WIDTH * num_tabs; i++) tabs[i] = ' ';
16151203703bSJeremy L Thompson   if (is_composite) {
16161203703bSJeremy L Thompson     CeedInt       num_suboperators;
16171203703bSJeremy L Thompson     CeedOperator *sub_operators;
16181203703bSJeremy L Thompson 
1619ed094490SJeremy L Thompson     CeedCall(CeedOperatorCompositeGetNumSub(op, &num_suboperators));
1620ed094490SJeremy L Thompson     CeedCall(CeedOperatorCompositeGetSubList(op, &sub_operators));
1621df1daa62SZach Atkins     fprintf(stream, "%s", tabs);
1622d3d5610dSJeremy L Thompson     fprintf(stream, "Composite CeedOperator%s%s\n", has_name ? " - " : "", has_name ? name : "");
16234c789ea2SJeremy L Thompson     for (CeedInt i = 0; i < CEED_TAB_WIDTH; i++) tabs[CEED_TAB_WIDTH * num_tabs + i] = ' ';
16241203703bSJeremy L Thompson     for (CeedInt i = 0; i < num_suboperators; i++) {
16251203703bSJeremy L Thompson       has_name = sub_operators[i]->name;
1626df1daa62SZach Atkins       fprintf(stream, "%s", tabs);
162799f7f61fSJeremy L Thompson       fprintf(stream, "SubOperator%s %" CeedInt_FMT "%s%s%s\n", is_at_points ? " AtPoints" : "", i, has_name ? " - " : "",
162899f7f61fSJeremy L Thompson               has_name ? sub_operators[i]->name : "", is_full ? ":" : "");
16295a526491SJeremy L Thompson       if (is_full) CeedCall(CeedOperatorSingleView(sub_operators[i], tabs, stream));
16307a982d89SJeremy L. Thompson     }
16317a982d89SJeremy L. Thompson   } else {
1632df1daa62SZach Atkins     fprintf(stream, "%s", tabs);
1633d3d5610dSJeremy L Thompson     fprintf(stream, "CeedOperator%s%s%s\n", is_at_points ? " AtPoints" : "", has_name ? " - " : "", has_name ? name : "");
16345a526491SJeremy L Thompson     if (is_full) CeedCall(CeedOperatorSingleView(op, tabs, stream));
16357a982d89SJeremy L. Thompson   }
16365a526491SJeremy L Thompson   CeedCall(CeedFree(&tabs));
16375a526491SJeremy L Thompson   return CEED_ERROR_SUCCESS;
16385a526491SJeremy L Thompson }
16395a526491SJeremy L Thompson 
16405a526491SJeremy L Thompson /**
16415a526491SJeremy L Thompson   @brief Set the number of tabs to indent for @ref CeedOperatorView() output
16425a526491SJeremy L Thompson 
16435a526491SJeremy L Thompson   @param[in] op       `CeedOperator` to set the number of view tabs
16445a526491SJeremy L Thompson   @param[in] num_tabs Number of view tabs to set
16455a526491SJeremy L Thompson 
16465a526491SJeremy L Thompson   @return Error code: 0 - success, otherwise - failure
16475a526491SJeremy L Thompson 
16485a526491SJeremy L Thompson   @ref User
16495a526491SJeremy L Thompson **/
16505a526491SJeremy L Thompson int CeedOperatorSetNumViewTabs(CeedOperator op, CeedInt num_tabs) {
16515a526491SJeremy L Thompson   CeedCheck(num_tabs >= 0, CeedOperatorReturnCeed(op), CEED_ERROR_MINOR, "Number of view tabs must be non-negative");
16525a526491SJeremy L Thompson   op->num_tabs = num_tabs;
1653e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
16547a982d89SJeremy L. Thompson }
16553bd813ffSjeremylt 
16563bd813ffSjeremylt /**
1657690992b2SZach Atkins   @brief Get the number of tabs to indent for @ref CeedOperatorView() output
1658690992b2SZach Atkins 
1659690992b2SZach Atkins   @param[in]  op       `CeedOperator` to get the number of view tabs
1660690992b2SZach Atkins   @param[out] num_tabs Number of view tabs
1661690992b2SZach Atkins 
1662690992b2SZach Atkins   @return Error code: 0 - success, otherwise - failure
1663690992b2SZach Atkins 
1664690992b2SZach Atkins   @ref User
1665690992b2SZach Atkins **/
1666690992b2SZach Atkins int CeedOperatorGetNumViewTabs(CeedOperator op, CeedInt *num_tabs) {
1667690992b2SZach Atkins   *num_tabs = op->num_tabs;
1668690992b2SZach Atkins   return CEED_ERROR_SUCCESS;
1669690992b2SZach Atkins }
1670690992b2SZach Atkins 
1671690992b2SZach Atkins /**
1672935f026aSJeremy L Thompson   @brief View a `CeedOperator`
1673935f026aSJeremy L Thompson 
1674935f026aSJeremy L Thompson   @param[in] op     `CeedOperator` to view
1675935f026aSJeremy L Thompson   @param[in] stream Stream to write; typically `stdout` or a file
1676935f026aSJeremy L Thompson 
1677935f026aSJeremy L Thompson   @return Error code: 0 - success, otherwise - failure
1678935f026aSJeremy L Thompson 
1679935f026aSJeremy L Thompson   @ref User
1680935f026aSJeremy L Thompson **/
1681935f026aSJeremy L Thompson int CeedOperatorView(CeedOperator op, FILE *stream) {
1682935f026aSJeremy L Thompson   CeedCall(CeedOperatorView_Core(op, stream, true));
1683935f026aSJeremy L Thompson   return CEED_ERROR_SUCCESS;
1684935f026aSJeremy L Thompson }
1685935f026aSJeremy L Thompson 
1686935f026aSJeremy L Thompson /**
1687935f026aSJeremy L Thompson   @brief View a brief summary `CeedOperator`
1688935f026aSJeremy L Thompson 
1689935f026aSJeremy L Thompson   @param[in] op     `CeedOperator` to view brief summary
1690935f026aSJeremy L Thompson   @param[in] stream Stream to write; typically `stdout` or a file
1691935f026aSJeremy L Thompson 
1692935f026aSJeremy L Thompson   @return Error code: 0 - success, otherwise - failure
1693935f026aSJeremy L Thompson 
1694935f026aSJeremy L Thompson   @ref User
1695935f026aSJeremy L Thompson **/
1696935f026aSJeremy L Thompson int CeedOperatorViewTerse(CeedOperator op, FILE *stream) {
1697935f026aSJeremy L Thompson   CeedCall(CeedOperatorView_Core(op, stream, false));
1698935f026aSJeremy L Thompson   return CEED_ERROR_SUCCESS;
1699935f026aSJeremy L Thompson }
1700935f026aSJeremy L Thompson 
1701935f026aSJeremy L Thompson /**
1702ca94c3ddSJeremy L Thompson   @brief Get the `Ceed` associated with a `CeedOperator`
1703b7c9bbdaSJeremy L Thompson 
1704ca94c3ddSJeremy L Thompson   @param[in]  op   `CeedOperator`
1705ca94c3ddSJeremy L Thompson   @param[out] ceed Variable to store `Ceed`
1706b7c9bbdaSJeremy L Thompson 
1707b7c9bbdaSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1708b7c9bbdaSJeremy L Thompson 
1709b7c9bbdaSJeremy L Thompson   @ref Advanced
1710b7c9bbdaSJeremy L Thompson **/
1711b7c9bbdaSJeremy L Thompson int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) {
1712*b0f67a9cSJeremy L Thompson   CeedCall(CeedObjectGetCeed((CeedObject)op, ceed));
1713b7c9bbdaSJeremy L Thompson   return CEED_ERROR_SUCCESS;
1714b7c9bbdaSJeremy L Thompson }
1715b7c9bbdaSJeremy L Thompson 
1716b7c9bbdaSJeremy L Thompson /**
17176e536b99SJeremy L Thompson   @brief Return the `Ceed` associated with a `CeedOperator`
17186e536b99SJeremy L Thompson 
17196e536b99SJeremy L Thompson   @param[in]  op `CeedOperator`
17206e536b99SJeremy L Thompson 
17216e536b99SJeremy L Thompson   @return `Ceed` associated with the `op`
17226e536b99SJeremy L Thompson 
17236e536b99SJeremy L Thompson   @ref Advanced
17246e536b99SJeremy L Thompson **/
1725*b0f67a9cSJeremy L Thompson Ceed CeedOperatorReturnCeed(CeedOperator op) { return CeedObjectReturnCeed((CeedObject)op); }
17266e536b99SJeremy L Thompson 
17276e536b99SJeremy L Thompson /**
1728ca94c3ddSJeremy L Thompson   @brief Get the number of elements associated with a `CeedOperator`
1729b7c9bbdaSJeremy L Thompson 
1730ca94c3ddSJeremy L Thompson   @param[in]  op       `CeedOperator`
1731b7c9bbdaSJeremy L Thompson   @param[out] num_elem Variable to store number of elements
1732b7c9bbdaSJeremy L Thompson 
1733b7c9bbdaSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1734b7c9bbdaSJeremy L Thompson 
1735b7c9bbdaSJeremy L Thompson   @ref Advanced
1736b7c9bbdaSJeremy L Thompson **/
1737b7c9bbdaSJeremy L Thompson int CeedOperatorGetNumElements(CeedOperator op, CeedInt *num_elem) {
17381203703bSJeremy L Thompson   bool is_composite;
17391203703bSJeremy L Thompson 
17401203703bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
17416e536b99SJeremy L Thompson   CeedCheck(!is_composite, CeedOperatorReturnCeed(op), CEED_ERROR_MINOR, "Not defined for composite operator");
1742b7c9bbdaSJeremy L Thompson   *num_elem = op->num_elem;
1743b7c9bbdaSJeremy L Thompson   return CEED_ERROR_SUCCESS;
1744b7c9bbdaSJeremy L Thompson }
1745b7c9bbdaSJeremy L Thompson 
1746b7c9bbdaSJeremy L Thompson /**
1747ca94c3ddSJeremy L Thompson   @brief Get the number of quadrature points associated with a `CeedOperator`
1748b7c9bbdaSJeremy L Thompson 
1749ca94c3ddSJeremy L Thompson   @param[in]  op       `CeedOperator`
1750b7c9bbdaSJeremy L Thompson   @param[out] num_qpts Variable to store vector number of quadrature points
1751b7c9bbdaSJeremy L Thompson 
1752b7c9bbdaSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1753b7c9bbdaSJeremy L Thompson 
1754b7c9bbdaSJeremy L Thompson   @ref Advanced
1755b7c9bbdaSJeremy L Thompson **/
1756b7c9bbdaSJeremy L Thompson int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *num_qpts) {
17571203703bSJeremy L Thompson   bool is_composite;
17581203703bSJeremy L Thompson 
17591203703bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
17606e536b99SJeremy L Thompson   CeedCheck(!is_composite, CeedOperatorReturnCeed(op), CEED_ERROR_MINOR, "Not defined for composite operator");
1761b7c9bbdaSJeremy L Thompson   *num_qpts = op->num_qpts;
1762b7c9bbdaSJeremy L Thompson   return CEED_ERROR_SUCCESS;
1763b7c9bbdaSJeremy L Thompson }
1764b7c9bbdaSJeremy L Thompson 
1765b7c9bbdaSJeremy L Thompson /**
1766ca94c3ddSJeremy L Thompson   @brief Estimate number of FLOPs required to apply `CeedOperator` on the active `CeedVector`
17676e15d496SJeremy L Thompson 
1768ca94c3ddSJeremy L Thompson   @param[in]  op    `CeedOperator` to estimate FLOPs for
1769ea61e9acSJeremy L Thompson   @param[out] flops Address of variable to hold FLOPs estimate
17706e15d496SJeremy L Thompson 
17716e15d496SJeremy L Thompson   @ref Backend
17726e15d496SJeremy L Thompson **/
17739d36ca50SJeremy L Thompson int CeedOperatorGetFlopsEstimate(CeedOperator op, CeedSize *flops) {
17746e15d496SJeremy L Thompson   bool is_composite;
17751c66c397SJeremy L Thompson 
17762b730f8bSJeremy L Thompson   CeedCall(CeedOperatorCheckReady(op));
17776e15d496SJeremy L Thompson 
17786e15d496SJeremy L Thompson   *flops = 0;
17792b730f8bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
17806e15d496SJeremy L Thompson   if (is_composite) {
17816e15d496SJeremy L Thompson     CeedInt num_suboperators;
17821c66c397SJeremy L Thompson 
1783ed094490SJeremy L Thompson     CeedCall(CeedOperatorCompositeGetNumSub(op, &num_suboperators));
17846e15d496SJeremy L Thompson     CeedOperator *sub_operators;
1785ed094490SJeremy L Thompson     CeedCall(CeedOperatorCompositeGetSubList(op, &sub_operators));
17866e15d496SJeremy L Thompson 
17876e15d496SJeremy L Thompson     // FLOPs for each suboperator
17886e15d496SJeremy L Thompson     for (CeedInt i = 0; i < num_suboperators; i++) {
17899d36ca50SJeremy L Thompson       CeedSize suboperator_flops;
17901c66c397SJeremy L Thompson 
17912b730f8bSJeremy L Thompson       CeedCall(CeedOperatorGetFlopsEstimate(sub_operators[i], &suboperator_flops));
17926e15d496SJeremy L Thompson       *flops += suboperator_flops;
17936e15d496SJeremy L Thompson     }
17946e15d496SJeremy L Thompson   } else {
17953f919cbcSJeremy L Thompson     bool                is_at_points;
17963f919cbcSJeremy L Thompson     CeedInt             num_input_fields, num_output_fields, num_elem = 0, num_points = 0;
17971203703bSJeremy L Thompson     CeedQFunction       qf;
17981203703bSJeremy L Thompson     CeedQFunctionField *qf_input_fields, *qf_output_fields;
17991203703bSJeremy L Thompson     CeedOperatorField  *op_input_fields, *op_output_fields;
18001c66c397SJeremy L Thompson 
18013f919cbcSJeremy L Thompson     CeedCall(CeedOperatorGetNumElements(op, &num_elem));
180219feff82SJeremy L Thompson     if (num_elem == 0) return CEED_ERROR_SUCCESS;
180319feff82SJeremy L Thompson     CeedCall(CeedOperatorIsAtPoints(op, &is_at_points));
18043f919cbcSJeremy L Thompson     if (is_at_points) {
18053f919cbcSJeremy L Thompson       CeedMemType         mem_type;
18063f919cbcSJeremy L Thompson       CeedElemRestriction rstr_points = NULL;
18073f919cbcSJeremy L Thompson 
18083f919cbcSJeremy L Thompson       CeedCall(CeedOperatorAtPointsGetPoints(op, &rstr_points, NULL));
18093f919cbcSJeremy L Thompson       CeedCall(CeedGetPreferredMemType(CeedOperatorReturnCeed(op), &mem_type));
18103f919cbcSJeremy L Thompson       if (mem_type == CEED_MEM_DEVICE) {
18113f919cbcSJeremy L Thompson         // Device backends pad out to the same number of points per element
18123f919cbcSJeremy L Thompson         CeedCall(CeedElemRestrictionGetMaxPointsInElement(rstr_points, &num_points));
18133f919cbcSJeremy L Thompson       } else {
18143f919cbcSJeremy L Thompson         num_points = 0;
18153f919cbcSJeremy L Thompson         for (CeedInt i = 0; i < num_elem; i++) {
18163f919cbcSJeremy L Thompson           CeedInt points_in_elem = 0;
18173f919cbcSJeremy L Thompson 
18183f919cbcSJeremy L Thompson           CeedCall(CeedElemRestrictionGetNumPointsInElement(rstr_points, i, &points_in_elem));
18193f919cbcSJeremy L Thompson           num_points += points_in_elem;
18203f919cbcSJeremy L Thompson         }
18213f919cbcSJeremy L Thompson         num_points = num_points / num_elem + (num_points % num_elem > 0);
18223f919cbcSJeremy L Thompson       }
18233f919cbcSJeremy L Thompson       CeedCall(CeedElemRestrictionDestroy(&rstr_points));
18243f919cbcSJeremy L Thompson     }
18251203703bSJeremy L Thompson     CeedCall(CeedOperatorGetQFunction(op, &qf));
18261203703bSJeremy L Thompson     CeedCall(CeedQFunctionGetFields(qf, &num_input_fields, &qf_input_fields, &num_output_fields, &qf_output_fields));
1827c11e12f4SJeremy L Thompson     CeedCall(CeedQFunctionDestroy(&qf));
18281203703bSJeremy L Thompson     CeedCall(CeedOperatorGetFields(op, NULL, &op_input_fields, NULL, &op_output_fields));
18294385fb7fSSebastian Grimberg 
18306e15d496SJeremy L Thompson     // Input FLOPs
18316e15d496SJeremy L Thompson     for (CeedInt i = 0; i < num_input_fields; i++) {
18321203703bSJeremy L Thompson       CeedVector vec;
18336e15d496SJeremy L Thompson 
18341203703bSJeremy L Thompson       CeedCall(CeedOperatorFieldGetVector(op_input_fields[i], &vec));
18351203703bSJeremy L Thompson       if (vec == CEED_VECTOR_ACTIVE) {
18361203703bSJeremy L Thompson         CeedEvalMode        eval_mode;
18371203703bSJeremy L Thompson         CeedSize            rstr_flops, basis_flops;
18381203703bSJeremy L Thompson         CeedElemRestriction rstr;
18391203703bSJeremy L Thompson         CeedBasis           basis;
18401203703bSJeremy L Thompson 
18411203703bSJeremy L Thompson         CeedCall(CeedOperatorFieldGetElemRestriction(op_input_fields[i], &rstr));
18421203703bSJeremy L Thompson         CeedCall(CeedElemRestrictionGetFlopsEstimate(rstr, CEED_NOTRANSPOSE, &rstr_flops));
1843681d0ea7SJeremy L Thompson         CeedCall(CeedElemRestrictionDestroy(&rstr));
1844edb2538eSJeremy L Thompson         *flops += rstr_flops;
18451203703bSJeremy L Thompson         CeedCall(CeedOperatorFieldGetBasis(op_input_fields[i], &basis));
18461203703bSJeremy L Thompson         CeedCall(CeedQFunctionFieldGetEvalMode(qf_input_fields[i], &eval_mode));
18473f919cbcSJeremy L Thompson         CeedCall(CeedBasisGetFlopsEstimate(basis, CEED_NOTRANSPOSE, eval_mode, is_at_points, num_points, &basis_flops));
1848681d0ea7SJeremy L Thompson         CeedCall(CeedBasisDestroy(&basis));
18496e15d496SJeremy L Thompson         *flops += basis_flops * num_elem;
18506e15d496SJeremy L Thompson       }
1851681d0ea7SJeremy L Thompson       CeedCall(CeedVectorDestroy(&vec));
18526e15d496SJeremy L Thompson     }
18536e15d496SJeremy L Thompson     // QF FLOPs
18541c66c397SJeremy L Thompson     {
18559d36ca50SJeremy L Thompson       CeedInt       num_qpts;
18569d36ca50SJeremy L Thompson       CeedSize      qf_flops;
18571203703bSJeremy L Thompson       CeedQFunction qf;
18581c66c397SJeremy L Thompson 
18593f919cbcSJeremy L Thompson       if (is_at_points) num_qpts = num_points;
18603f919cbcSJeremy L Thompson       else CeedCall(CeedOperatorGetNumQuadraturePoints(op, &num_qpts));
18611203703bSJeremy L Thompson       CeedCall(CeedOperatorGetQFunction(op, &qf));
18621203703bSJeremy L Thompson       CeedCall(CeedQFunctionGetFlopsEstimate(qf, &qf_flops));
1863c11e12f4SJeremy L Thompson       CeedCall(CeedQFunctionDestroy(&qf));
18646e536b99SJeremy L Thompson       CeedCheck(qf_flops > -1, CeedOperatorReturnCeed(op), CEED_ERROR_INCOMPLETE,
18656e536b99SJeremy L Thompson                 "Must set CeedQFunction FLOPs estimate with CeedQFunctionSetUserFlopsEstimate");
18666e15d496SJeremy L Thompson       *flops += num_elem * num_qpts * qf_flops;
18671c66c397SJeremy L Thompson     }
18681c66c397SJeremy L Thompson 
18696e15d496SJeremy L Thompson     // Output FLOPs
18706e15d496SJeremy L Thompson     for (CeedInt i = 0; i < num_output_fields; i++) {
18711203703bSJeremy L Thompson       CeedVector vec;
18726e15d496SJeremy L Thompson 
18731203703bSJeremy L Thompson       CeedCall(CeedOperatorFieldGetVector(op_output_fields[i], &vec));
18741203703bSJeremy L Thompson       if (vec == CEED_VECTOR_ACTIVE) {
18751203703bSJeremy L Thompson         CeedEvalMode        eval_mode;
18761203703bSJeremy L Thompson         CeedSize            rstr_flops, basis_flops;
18771203703bSJeremy L Thompson         CeedElemRestriction rstr;
18781203703bSJeremy L Thompson         CeedBasis           basis;
18791203703bSJeremy L Thompson 
18801203703bSJeremy L Thompson         CeedCall(CeedOperatorFieldGetElemRestriction(op_output_fields[i], &rstr));
18811203703bSJeremy L Thompson         CeedCall(CeedElemRestrictionGetFlopsEstimate(rstr, CEED_TRANSPOSE, &rstr_flops));
1882681d0ea7SJeremy L Thompson         CeedCall(CeedElemRestrictionDestroy(&rstr));
1883edb2538eSJeremy L Thompson         *flops += rstr_flops;
18841203703bSJeremy L Thompson         CeedCall(CeedOperatorFieldGetBasis(op_output_fields[i], &basis));
18851203703bSJeremy L Thompson         CeedCall(CeedQFunctionFieldGetEvalMode(qf_output_fields[i], &eval_mode));
18863f919cbcSJeremy L Thompson         CeedCall(CeedBasisGetFlopsEstimate(basis, CEED_TRANSPOSE, eval_mode, is_at_points, num_points, &basis_flops));
1887681d0ea7SJeremy L Thompson         CeedCall(CeedBasisDestroy(&basis));
18886e15d496SJeremy L Thompson         *flops += basis_flops * num_elem;
18896e15d496SJeremy L Thompson       }
1890681d0ea7SJeremy L Thompson       CeedCall(CeedVectorDestroy(&vec));
18916e15d496SJeremy L Thompson     }
18926e15d496SJeremy L Thompson   }
18936e15d496SJeremy L Thompson   return CEED_ERROR_SUCCESS;
18946e15d496SJeremy L Thompson }
18956e15d496SJeremy L Thompson 
18966e15d496SJeremy L Thompson /**
1897ca94c3ddSJeremy L Thompson   @brief Get `CeedQFunction` global context for a `CeedOperator`.
18989fd66db6SSebastian Grimberg 
1899ca94c3ddSJeremy L Thompson   The caller is responsible for destroying `ctx` returned from this function via @ref CeedQFunctionContextDestroy().
1900512bb800SJeremy L Thompson 
1901ca94c3ddSJeremy 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`.
1902ca94c3ddSJeremy L Thompson         This `CeedQFunctionContext` will be destroyed if `ctx` is the only reference to this `CeedQFunctionContext`.
19030126412dSJeremy L Thompson 
1904ca94c3ddSJeremy L Thompson   @param[in]  op  `CeedOperator`
1905ca94c3ddSJeremy L Thompson   @param[out] ctx Variable to store `CeedQFunctionContext`
19060126412dSJeremy L Thompson 
19070126412dSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
19080126412dSJeremy L Thompson 
1909859c15bbSJames Wright   @ref Advanced
19100126412dSJeremy L Thompson **/
19110126412dSJeremy L Thompson int CeedOperatorGetContext(CeedOperator op, CeedQFunctionContext *ctx) {
19121203703bSJeremy L Thompson   bool                 is_composite;
19131203703bSJeremy L Thompson   CeedQFunction        qf;
19141203703bSJeremy L Thompson   CeedQFunctionContext qf_ctx;
19151203703bSJeremy L Thompson 
19161203703bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
19176e536b99SJeremy L Thompson   CeedCheck(!is_composite, CeedOperatorReturnCeed(op), CEED_ERROR_INCOMPATIBLE, "Cannot retrieve CeedQFunctionContext for composite operator");
19181203703bSJeremy L Thompson   CeedCall(CeedOperatorGetQFunction(op, &qf));
19191203703bSJeremy L Thompson   CeedCall(CeedQFunctionGetInnerContext(qf, &qf_ctx));
1920c11e12f4SJeremy L Thompson   CeedCall(CeedQFunctionDestroy(&qf));
19211485364cSJeremy L Thompson   *ctx = NULL;
19221203703bSJeremy L Thompson   if (qf_ctx) CeedCall(CeedQFunctionContextReferenceCopy(qf_ctx, ctx));
19230126412dSJeremy L Thompson   return CEED_ERROR_SUCCESS;
19240126412dSJeremy L Thompson }
19250126412dSJeremy L Thompson 
19260126412dSJeremy L Thompson /**
1927ca94c3ddSJeremy L Thompson   @brief Get label for a registered `CeedQFunctionContext` field, or `NULL` if no field has been registered with this `field_name`.
19283668ca4bSJeremy L Thompson 
1929ca94c3ddSJeremy L Thompson   Fields are registered via `CeedQFunctionContextRegister*()` functions (eg. @ref CeedQFunctionContextRegisterDouble()).
1930859c15bbSJames Wright 
1931ca94c3ddSJeremy L Thompson   @param[in]  op          `CeedOperator`
19323668ca4bSJeremy L Thompson   @param[in]  field_name  Name of field to retrieve label
19333668ca4bSJeremy L Thompson   @param[out] field_label Variable to field label
19343668ca4bSJeremy L Thompson 
19353668ca4bSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
19363668ca4bSJeremy L Thompson 
19373668ca4bSJeremy L Thompson   @ref User
19383668ca4bSJeremy L Thompson **/
193917b0d5c6SJeremy L Thompson int CeedOperatorGetContextFieldLabel(CeedOperator op, const char *field_name, CeedContextFieldLabel *field_label) {
19401c66c397SJeremy L Thompson   bool is_composite, field_found = false;
19411c66c397SJeremy L Thompson 
19422b730f8bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
19432b730f8bSJeremy L Thompson 
19443668ca4bSJeremy L Thompson   if (is_composite) {
1945a98a090bSJeremy L Thompson     // Composite operator
1946a98a090bSJeremy L Thompson     // -- Check if composite label already created
19473668ca4bSJeremy L Thompson     for (CeedInt i = 0; i < op->num_context_labels; i++) {
19483668ca4bSJeremy L Thompson       if (!strcmp(op->context_labels[i]->name, field_name)) {
19493668ca4bSJeremy L Thompson         *field_label = op->context_labels[i];
19503668ca4bSJeremy L Thompson         return CEED_ERROR_SUCCESS;
19513668ca4bSJeremy L Thompson       }
19523668ca4bSJeremy L Thompson     }
19533668ca4bSJeremy L Thompson 
1954a98a090bSJeremy L Thompson     // -- Create composite label if needed
19553668ca4bSJeremy L Thompson     CeedInt               num_sub;
19563668ca4bSJeremy L Thompson     CeedOperator         *sub_operators;
19573668ca4bSJeremy L Thompson     CeedContextFieldLabel new_field_label;
19583668ca4bSJeremy L Thompson 
19592b730f8bSJeremy L Thompson     CeedCall(CeedCalloc(1, &new_field_label));
1960ed094490SJeremy L Thompson     CeedCall(CeedOperatorCompositeGetNumSub(op, &num_sub));
1961ed094490SJeremy L Thompson     CeedCall(CeedOperatorCompositeGetSubList(op, &sub_operators));
19622b730f8bSJeremy L Thompson     CeedCall(CeedCalloc(num_sub, &new_field_label->sub_labels));
19633668ca4bSJeremy L Thompson     new_field_label->num_sub_labels = num_sub;
19643668ca4bSJeremy L Thompson 
19653668ca4bSJeremy L Thompson     for (CeedInt i = 0; i < num_sub; i++) {
19663668ca4bSJeremy L Thompson       if (sub_operators[i]->qf->ctx) {
19673668ca4bSJeremy L Thompson         CeedContextFieldLabel new_field_label_i;
19681c66c397SJeremy L Thompson 
19692b730f8bSJeremy L Thompson         CeedCall(CeedQFunctionContextGetFieldLabel(sub_operators[i]->qf->ctx, field_name, &new_field_label_i));
19703668ca4bSJeremy L Thompson         if (new_field_label_i) {
1971a98a090bSJeremy L Thompson           field_found                    = true;
19723668ca4bSJeremy L Thompson           new_field_label->sub_labels[i] = new_field_label_i;
19733668ca4bSJeremy L Thompson           new_field_label->name          = new_field_label_i->name;
19743668ca4bSJeremy L Thompson           new_field_label->description   = new_field_label_i->description;
19752b730f8bSJeremy L Thompson           if (new_field_label->type && new_field_label->type != new_field_label_i->type) {
19767bfe0f0eSJeremy L Thompson             // LCOV_EXCL_START
19772b730f8bSJeremy L Thompson             CeedCall(CeedFree(&new_field_label));
19786e536b99SJeremy L Thompson             return CeedError(CeedOperatorReturnCeed(op), CEED_ERROR_INCOMPATIBLE, "Incompatible field types on sub-operator contexts. %s != %s",
19792b730f8bSJeremy L Thompson                              CeedContextFieldTypes[new_field_label->type], CeedContextFieldTypes[new_field_label_i->type]);
19807bfe0f0eSJeremy L Thompson             // LCOV_EXCL_STOP
19817bfe0f0eSJeremy L Thompson           } else {
19827bfe0f0eSJeremy L Thompson             new_field_label->type = new_field_label_i->type;
19837bfe0f0eSJeremy L Thompson           }
19842b730f8bSJeremy L Thompson           if (new_field_label->num_values != 0 && new_field_label->num_values != new_field_label_i->num_values) {
19857bfe0f0eSJeremy L Thompson             // LCOV_EXCL_START
19862b730f8bSJeremy L Thompson             CeedCall(CeedFree(&new_field_label));
19876e536b99SJeremy L Thompson             return CeedError(CeedOperatorReturnCeed(op), CEED_ERROR_INCOMPATIBLE,
19886e536b99SJeremy L Thompson                              "Incompatible field number of values on sub-operator contexts. %zu != %zu", new_field_label->num_values,
19896e536b99SJeremy L Thompson                              new_field_label_i->num_values);
19907bfe0f0eSJeremy L Thompson             // LCOV_EXCL_STOP
19917bfe0f0eSJeremy L Thompson           } else {
19927bfe0f0eSJeremy L Thompson             new_field_label->num_values = new_field_label_i->num_values;
19937bfe0f0eSJeremy L Thompson           }
19943668ca4bSJeremy L Thompson         }
19953668ca4bSJeremy L Thompson       }
19963668ca4bSJeremy L Thompson     }
1997a98a090bSJeremy L Thompson     // -- Cleanup if field was found
1998a98a090bSJeremy L Thompson     if (field_found) {
1999a98a090bSJeremy L Thompson       *field_label = new_field_label;
2000a98a090bSJeremy L Thompson     } else {
20013668ca4bSJeremy L Thompson       // LCOV_EXCL_START
20022b730f8bSJeremy L Thompson       CeedCall(CeedFree(&new_field_label->sub_labels));
20032b730f8bSJeremy L Thompson       CeedCall(CeedFree(&new_field_label));
20043668ca4bSJeremy L Thompson       *field_label = NULL;
20053668ca4bSJeremy L Thompson       // LCOV_EXCL_STOP
20065ac9af79SJeremy L Thompson     }
20075ac9af79SJeremy L Thompson   } else {
20081203703bSJeremy L Thompson     CeedQFunction        qf;
20091203703bSJeremy L Thompson     CeedQFunctionContext ctx;
20101203703bSJeremy L Thompson 
2011a98a090bSJeremy L Thompson     // Single, non-composite operator
20121203703bSJeremy L Thompson     CeedCall(CeedOperatorGetQFunction(op, &qf));
20131203703bSJeremy L Thompson     CeedCall(CeedQFunctionGetInnerContext(qf, &ctx));
2014c11e12f4SJeremy L Thompson     CeedCall(CeedQFunctionDestroy(&qf));
20151203703bSJeremy L Thompson     if (ctx) {
20161203703bSJeremy L Thompson       CeedCall(CeedQFunctionContextGetFieldLabel(ctx, field_name, field_label));
2017a98a090bSJeremy L Thompson     } else {
2018a98a090bSJeremy L Thompson       *field_label = NULL;
2019a98a090bSJeremy L Thompson     }
20205ac9af79SJeremy L Thompson   }
20215ac9af79SJeremy L Thompson 
20225ac9af79SJeremy L Thompson   // Set label in operator
20235ac9af79SJeremy L Thompson   if (*field_label) {
20245ac9af79SJeremy L Thompson     (*field_label)->from_op = true;
20255ac9af79SJeremy L Thompson 
20263668ca4bSJeremy L Thompson     // Move new composite label to operator
20273668ca4bSJeremy L Thompson     if (op->num_context_labels == 0) {
20282b730f8bSJeremy L Thompson       CeedCall(CeedCalloc(1, &op->context_labels));
20293668ca4bSJeremy L Thompson       op->max_context_labels = 1;
20303668ca4bSJeremy L Thompson     } else if (op->num_context_labels == op->max_context_labels) {
20312b730f8bSJeremy L Thompson       CeedCall(CeedRealloc(2 * op->num_context_labels, &op->context_labels));
20323668ca4bSJeremy L Thompson       op->max_context_labels *= 2;
20333668ca4bSJeremy L Thompson     }
20345ac9af79SJeremy L Thompson     op->context_labels[op->num_context_labels] = *field_label;
20353668ca4bSJeremy L Thompson     op->num_context_labels++;
20363668ca4bSJeremy L Thompson   }
20373668ca4bSJeremy L Thompson   return CEED_ERROR_SUCCESS;
20383668ca4bSJeremy L Thompson }
20393668ca4bSJeremy L Thompson 
20403668ca4bSJeremy L Thompson /**
2041ca94c3ddSJeremy L Thompson   @brief Set `CeedQFunctionContext` field holding double precision values.
20424385fb7fSSebastian Grimberg 
2043ca94c3ddSJeremy L Thompson   For composite operators, the values are set in all sub-operator `CeedQFunctionContext` that have a matching `field_name`.
2044d8dd9a91SJeremy L Thompson 
2045ca94c3ddSJeremy L Thompson   @param[in,out] op          `CeedOperator`
20462788fa27SJeremy L Thompson   @param[in]     field_label Label of field to set
2047ea61e9acSJeremy L Thompson   @param[in]     values      Values to set
2048d8dd9a91SJeremy L Thompson 
2049d8dd9a91SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
2050d8dd9a91SJeremy L Thompson 
2051d8dd9a91SJeremy L Thompson   @ref User
2052d8dd9a91SJeremy L Thompson **/
205317b0d5c6SJeremy L Thompson int CeedOperatorSetContextDouble(CeedOperator op, CeedContextFieldLabel field_label, double *values) {
20542b730f8bSJeremy L Thompson   return CeedOperatorContextSetGeneric(op, field_label, CEED_CONTEXT_FIELD_DOUBLE, values);
2055d8dd9a91SJeremy L Thompson }
2056d8dd9a91SJeremy L Thompson 
2057d8dd9a91SJeremy L Thompson /**
2058ca94c3ddSJeremy L Thompson   @brief Get `CeedQFunctionContext` field holding double precision values, read-only.
20594385fb7fSSebastian Grimberg 
2060ca94c3ddSJeremy L Thompson   For composite operators, the values correspond to the first sub-operator `CeedQFunctionContext` that has a matching `field_name`.
20612788fa27SJeremy L Thompson 
2062ca94c3ddSJeremy L Thompson   @param[in]  op          `CeedOperator`
20632788fa27SJeremy L Thompson   @param[in]  field_label Label of field to get
20642788fa27SJeremy L Thompson   @param[out] num_values  Number of values in the field label
20652788fa27SJeremy L Thompson   @param[out] values      Pointer to context values
20662788fa27SJeremy L Thompson 
20672788fa27SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
20682788fa27SJeremy L Thompson 
20692788fa27SJeremy L Thompson   @ref User
20702788fa27SJeremy L Thompson **/
207117b0d5c6SJeremy L Thompson int CeedOperatorGetContextDoubleRead(CeedOperator op, CeedContextFieldLabel field_label, size_t *num_values, const double **values) {
20722788fa27SJeremy L Thompson   return CeedOperatorContextGetGenericRead(op, field_label, CEED_CONTEXT_FIELD_DOUBLE, num_values, values);
20732788fa27SJeremy L Thompson }
20742788fa27SJeremy L Thompson 
20752788fa27SJeremy L Thompson /**
2076ca94c3ddSJeremy L Thompson   @brief Restore `CeedQFunctionContext` field holding double precision values, read-only.
20772788fa27SJeremy L Thompson 
2078ca94c3ddSJeremy L Thompson   @param[in]  op          `CeedOperator`
20792788fa27SJeremy L Thompson   @param[in]  field_label Label of field to restore
20802788fa27SJeremy L Thompson   @param[out] values      Pointer to context values
20812788fa27SJeremy L Thompson 
20822788fa27SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
20832788fa27SJeremy L Thompson 
20842788fa27SJeremy L Thompson   @ref User
20852788fa27SJeremy L Thompson **/
208617b0d5c6SJeremy L Thompson int CeedOperatorRestoreContextDoubleRead(CeedOperator op, CeedContextFieldLabel field_label, const double **values) {
20872788fa27SJeremy L Thompson   return CeedOperatorContextRestoreGenericRead(op, field_label, CEED_CONTEXT_FIELD_DOUBLE, values);
20882788fa27SJeremy L Thompson }
20892788fa27SJeremy L Thompson 
20902788fa27SJeremy L Thompson /**
2091ca94c3ddSJeremy L Thompson   @brief Set `CeedQFunctionContext` field holding `int32` values.
20924385fb7fSSebastian Grimberg 
2093ca94c3ddSJeremy L Thompson   For composite operators, the values are set in all sub-operator `CeedQFunctionContext` that have a matching `field_name`.
2094d8dd9a91SJeremy L Thompson 
2095ca94c3ddSJeremy L Thompson   @param[in,out] op          `CeedOperator`
2096ea61e9acSJeremy L Thompson   @param[in]     field_label Label of field to set
2097ea61e9acSJeremy L Thompson   @param[in]     values      Values to set
2098d8dd9a91SJeremy L Thompson 
2099d8dd9a91SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
2100d8dd9a91SJeremy L Thompson 
2101d8dd9a91SJeremy L Thompson   @ref User
2102d8dd9a91SJeremy L Thompson **/
210323dbfd29SJeremy L Thompson int CeedOperatorSetContextInt32(CeedOperator op, CeedContextFieldLabel field_label, int32_t *values) {
21042b730f8bSJeremy L Thompson   return CeedOperatorContextSetGeneric(op, field_label, CEED_CONTEXT_FIELD_INT32, values);
2105d8dd9a91SJeremy L Thompson }
2106d8dd9a91SJeremy L Thompson 
2107d8dd9a91SJeremy L Thompson /**
2108ca94c3ddSJeremy L Thompson   @brief Get `CeedQFunctionContext` field holding `int32` values, read-only.
21094385fb7fSSebastian Grimberg 
2110ca94c3ddSJeremy L Thompson   For composite operators, the values correspond to the first sub-operator `CeedQFunctionContext` that has a matching `field_name`.
21112788fa27SJeremy L Thompson 
2112ca94c3ddSJeremy L Thompson   @param[in]  op          `CeedOperator`
21132788fa27SJeremy L Thompson   @param[in]  field_label Label of field to get
2114ca94c3ddSJeremy L Thompson   @param[out] num_values  Number of `int32` values in `values`
21152788fa27SJeremy L Thompson   @param[out] values      Pointer to context values
21162788fa27SJeremy L Thompson 
21172788fa27SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
21182788fa27SJeremy L Thompson 
21192788fa27SJeremy L Thompson   @ref User
21202788fa27SJeremy L Thompson **/
212123dbfd29SJeremy L Thompson int CeedOperatorGetContextInt32Read(CeedOperator op, CeedContextFieldLabel field_label, size_t *num_values, const int32_t **values) {
21222788fa27SJeremy L Thompson   return CeedOperatorContextGetGenericRead(op, field_label, CEED_CONTEXT_FIELD_INT32, num_values, values);
21232788fa27SJeremy L Thompson }
21242788fa27SJeremy L Thompson 
21252788fa27SJeremy L Thompson /**
2126ca94c3ddSJeremy L Thompson   @brief Restore `CeedQFunctionContext` field holding `int32` values, read-only.
21272788fa27SJeremy L Thompson 
2128ca94c3ddSJeremy L Thompson   @param[in]  op          `CeedOperator`
21292788fa27SJeremy L Thompson   @param[in]  field_label Label of field to get
21302788fa27SJeremy L Thompson   @param[out] values      Pointer to context values
21312788fa27SJeremy L Thompson 
21322788fa27SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
21332788fa27SJeremy L Thompson 
21342788fa27SJeremy L Thompson   @ref User
21352788fa27SJeremy L Thompson **/
213623dbfd29SJeremy L Thompson int CeedOperatorRestoreContextInt32Read(CeedOperator op, CeedContextFieldLabel field_label, const int32_t **values) {
21372788fa27SJeremy L Thompson   return CeedOperatorContextRestoreGenericRead(op, field_label, CEED_CONTEXT_FIELD_INT32, values);
21382788fa27SJeremy L Thompson }
21392788fa27SJeremy L Thompson 
21402788fa27SJeremy L Thompson /**
2141ca94c3ddSJeremy L Thompson   @brief Set `CeedQFunctionContext` field holding boolean values.
21425b6ec284SJeremy L Thompson 
2143ca94c3ddSJeremy L Thompson   For composite operators, the values are set in all sub-operator `CeedQFunctionContext` that have a matching `field_name`.
21445b6ec284SJeremy L Thompson 
2145ca94c3ddSJeremy L Thompson   @param[in,out] op          `CeedOperator`
21465b6ec284SJeremy L Thompson   @param[in]     field_label Label of field to set
21475b6ec284SJeremy L Thompson   @param[in]     values      Values to set
21485b6ec284SJeremy L Thompson 
21495b6ec284SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
21505b6ec284SJeremy L Thompson 
21515b6ec284SJeremy L Thompson   @ref User
21525b6ec284SJeremy L Thompson **/
21535b6ec284SJeremy L Thompson int CeedOperatorSetContextBoolean(CeedOperator op, CeedContextFieldLabel field_label, bool *values) {
21545b6ec284SJeremy L Thompson   return CeedOperatorContextSetGeneric(op, field_label, CEED_CONTEXT_FIELD_BOOL, values);
21555b6ec284SJeremy L Thompson }
21565b6ec284SJeremy L Thompson 
21575b6ec284SJeremy L Thompson /**
2158ca94c3ddSJeremy L Thompson   @brief Get `CeedQFunctionContext` field holding boolean values, read-only.
21595b6ec284SJeremy L Thompson 
2160ca94c3ddSJeremy L Thompson   For composite operators, the values correspond to the first sub-operator `CeedQFunctionContext` that has a matching `field_name`.
21615b6ec284SJeremy L Thompson 
2162ca94c3ddSJeremy L Thompson   @param[in]  op          `CeedOperator`
21635b6ec284SJeremy L Thompson   @param[in]  field_label Label of field to get
2164ca94c3ddSJeremy L Thompson   @param[out] num_values  Number of boolean values in `values`
21655b6ec284SJeremy L Thompson   @param[out] values      Pointer to context values
21665b6ec284SJeremy L Thompson 
21675b6ec284SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
21685b6ec284SJeremy L Thompson 
21695b6ec284SJeremy L Thompson   @ref User
21705b6ec284SJeremy L Thompson **/
21715b6ec284SJeremy L Thompson int CeedOperatorGetContextBooleanRead(CeedOperator op, CeedContextFieldLabel field_label, size_t *num_values, const bool **values) {
21725b6ec284SJeremy L Thompson   return CeedOperatorContextGetGenericRead(op, field_label, CEED_CONTEXT_FIELD_BOOL, num_values, values);
21735b6ec284SJeremy L Thompson }
21745b6ec284SJeremy L Thompson 
21755b6ec284SJeremy L Thompson /**
2176ca94c3ddSJeremy L Thompson   @brief Restore `CeedQFunctionContext` field holding boolean values, read-only.
21775b6ec284SJeremy L Thompson 
2178ca94c3ddSJeremy L Thompson   @param[in]  op          `CeedOperator`
21795b6ec284SJeremy L Thompson   @param[in]  field_label Label of field to get
21805b6ec284SJeremy L Thompson   @param[out] values      Pointer to context values
21815b6ec284SJeremy L Thompson 
21825b6ec284SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
21835b6ec284SJeremy L Thompson 
21845b6ec284SJeremy L Thompson   @ref User
21855b6ec284SJeremy L Thompson **/
21865b6ec284SJeremy L Thompson int CeedOperatorRestoreContextBooleanRead(CeedOperator op, CeedContextFieldLabel field_label, const bool **values) {
21875b6ec284SJeremy L Thompson   return CeedOperatorContextRestoreGenericRead(op, field_label, CEED_CONTEXT_FIELD_BOOL, values);
21885b6ec284SJeremy L Thompson }
21895b6ec284SJeremy L Thompson 
21905b6ec284SJeremy L Thompson /**
2191ca94c3ddSJeremy L Thompson   @brief Apply `CeedOperator` to a `CeedVector`.
2192d7b241e6Sjeremylt 
2193ea61e9acSJeremy L Thompson   This computes the action of the operator on the specified (active) input, yielding its (active) output.
2194ca94c3ddSJeremy L Thompson   All inputs and outputs must be specified using @ref CeedOperatorSetField().
2195d7b241e6Sjeremylt 
21965da5ab9fSZach Atkins   @note Calling this function asserts that setup is complete and sets the `CeedOperator` as immutable.
2197f04ea552SJeremy L Thompson 
2198ca94c3ddSJeremy L Thompson   @param[in]  op      `CeedOperator` to apply
2199ca94c3ddSJeremy L Thompson   @param[in]  in      `CeedVector` containing input state or @ref CEED_VECTOR_NONE if there are no active inputs
2200ca94c3ddSJeremy 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
2201ca94c3ddSJeremy L Thompson   @param[in]  request Address of @ref CeedRequest for non-blocking completion, else @ref CEED_REQUEST_IMMEDIATE
2202b11c1e72Sjeremylt 
2203b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
2204dfdf5a53Sjeremylt 
22057a982d89SJeremy L. Thompson   @ref User
2206b11c1e72Sjeremylt **/
22072b730f8bSJeremy L Thompson int CeedOperatorApply(CeedOperator op, CeedVector in, CeedVector out, CeedRequest *request) {
22081203703bSJeremy L Thompson   bool is_composite;
22091203703bSJeremy L Thompson 
22102b730f8bSJeremy L Thompson   CeedCall(CeedOperatorCheckReady(op));
2211d7b241e6Sjeremylt 
22121203703bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
22130db52efcSZach Atkins   if (is_composite && op->ApplyComposite) {
2214250756a7Sjeremylt     // Composite Operator
22152b730f8bSJeremy L Thompson     CeedCall(op->ApplyComposite(op, in, out, request));
22160db52efcSZach Atkins   } else if (!is_composite && op->Apply) {
22173ca2b39bSJeremy L Thompson     // Standard Operator
22183ca2b39bSJeremy L Thompson     CeedCall(op->Apply(op, in, out, request));
22193ca2b39bSJeremy L Thompson   } else {
22200db52efcSZach Atkins     // Standard or composite, default to zeroing out and calling ApplyAddActive
22210db52efcSZach Atkins     // Zero active output
22220db52efcSZach Atkins     if (out != CEED_VECTOR_NONE) CeedCall(CeedVectorSetValue(out, 0.0));
22231203703bSJeremy L Thompson 
22240db52efcSZach Atkins     // ApplyAddActive
22250db52efcSZach Atkins     CeedCall(CeedOperatorApplyAddActive(op, in, out, request));
2226250756a7Sjeremylt   }
2227e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2228cae8b89aSjeremylt }
2229cae8b89aSjeremylt 
2230cae8b89aSjeremylt /**
2231ca94c3ddSJeremy L Thompson   @brief Apply `CeedOperator` to a `CeedVector` and add result to output `CeedVector`.
2232cae8b89aSjeremylt 
2233ea61e9acSJeremy L Thompson   This computes the action of the operator on the specified (active) input, yielding its (active) output.
2234ca94c3ddSJeremy L Thompson   All inputs and outputs must be specified using @ref CeedOperatorSetField().
2235cae8b89aSjeremylt 
22365da5ab9fSZach Atkins   @note Calling this function asserts that setup is complete and sets the `CeedOperator` as immutable.
22375da5ab9fSZach Atkins   @warning This function adds into ALL outputs, including passive outputs. To only add into the active output, use `CeedOperatorApplyAddActive()`.
22385da5ab9fSZach Atkins   @see `CeedOperatorApplyAddActive()`
22395da5ab9fSZach Atkins 
2240ca94c3ddSJeremy L Thompson   @param[in]  op      `CeedOperator` to apply
2241ca94c3ddSJeremy L Thompson   @param[in]  in      `CeedVector` containing input state or @ref CEED_VECTOR_NONE if there are no active inputs
2242ca94c3ddSJeremy 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
2243ca94c3ddSJeremy L Thompson   @param[in]  request Address of @ref CeedRequest for non-blocking completion, else @ref CEED_REQUEST_IMMEDIATE
2244cae8b89aSjeremylt 
2245cae8b89aSjeremylt   @return An error code: 0 - success, otherwise - failure
2246cae8b89aSjeremylt 
22477a982d89SJeremy L. Thompson   @ref User
2248cae8b89aSjeremylt **/
22492b730f8bSJeremy L Thompson int CeedOperatorApplyAdd(CeedOperator op, CeedVector in, CeedVector out, CeedRequest *request) {
22501203703bSJeremy L Thompson   bool is_composite;
22511203703bSJeremy L Thompson 
22522b730f8bSJeremy L Thompson   CeedCall(CeedOperatorCheckReady(op));
2253cae8b89aSjeremylt 
22541203703bSJeremy L Thompson   CeedCall(CeedOperatorIsComposite(op, &is_composite));
22551203703bSJeremy L Thompson   if (is_composite) {
2256250756a7Sjeremylt     // Composite Operator
2257250756a7Sjeremylt     if (op->ApplyAddComposite) {
22582b730f8bSJeremy L Thompson       CeedCall(op->ApplyAddComposite(op, in, out, request));
2259cae8b89aSjeremylt     } else {
2260d1d35e2fSjeremylt       CeedInt       num_suboperators;
2261d1d35e2fSjeremylt       CeedOperator *sub_operators;
2262250756a7Sjeremylt 
2263ed094490SJeremy L Thompson       CeedCall(CeedOperatorCompositeGetNumSub(op, &num_suboperators));
2264ed094490SJeremy L Thompson       CeedCall(CeedOperatorCompositeGetSubList(op, &sub_operators));
2265d1d35e2fSjeremylt       for (CeedInt i = 0; i < num_suboperators; i++) {
22662b730f8bSJeremy L Thompson         CeedCall(CeedOperatorApplyAdd(sub_operators[i], in, out, request));
22671d7d2407SJeremy L Thompson       }
2268250756a7Sjeremylt     }
22691203703bSJeremy L Thompson   } else if (op->num_elem > 0) {
22703ca2b39bSJeremy L Thompson     // Standard Operator
22713ca2b39bSJeremy L Thompson     CeedCall(op->ApplyAdd(op, in, out, request));
2272250756a7Sjeremylt   }
2273e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2274d7b241e6Sjeremylt }
2275d7b241e6Sjeremylt 
2276d7b241e6Sjeremylt /**
22775da5ab9fSZach Atkins   @brief Apply `CeedOperator` to a `CeedVector` and add result to output `CeedVector`. Only sums into active outputs, overwrites passive outputs.
22785da5ab9fSZach Atkins 
22795da5ab9fSZach Atkins   This computes the action of the operator on the specified (active) input, yielding its (active) output.
22805da5ab9fSZach Atkins   All inputs and outputs must be specified using @ref CeedOperatorSetField().
22815da5ab9fSZach Atkins 
22825da5ab9fSZach Atkins   @note Calling this function asserts that setup is complete and sets the `CeedOperator` as immutable.
22835da5ab9fSZach Atkins 
22845da5ab9fSZach Atkins   @param[in]  op      `CeedOperator` to apply
22855da5ab9fSZach Atkins   @param[in]  in      `CeedVector` containing input state or @ref CEED_VECTOR_NONE if there are no active inputs
22865da5ab9fSZach Atkins   @param[out] out     `CeedVector` to sum in result of applying operator (must be distinct from `in`) or @ref CEED_VECTOR_NONE if there are no active outputs
22875da5ab9fSZach Atkins   @param[in]  request Address of @ref CeedRequest for non-blocking completion, else @ref CEED_REQUEST_IMMEDIATE
22885da5ab9fSZach Atkins 
22895da5ab9fSZach Atkins   @return An error code: 0 - success, otherwise - failure
22905da5ab9fSZach Atkins 
22915da5ab9fSZach Atkins   @ref User
22925da5ab9fSZach Atkins **/
22935da5ab9fSZach Atkins int CeedOperatorApplyAddActive(CeedOperator op, CeedVector in, CeedVector out, CeedRequest *request) {
22945da5ab9fSZach Atkins   bool is_composite;
22955da5ab9fSZach Atkins 
22965da5ab9fSZach Atkins   CeedCall(CeedOperatorCheckReady(op));
22975da5ab9fSZach Atkins 
22985da5ab9fSZach Atkins   CeedCall(CeedOperatorIsComposite(op, &is_composite));
22995da5ab9fSZach Atkins   if (is_composite) {
23005da5ab9fSZach Atkins     // Composite Operator
23015da5ab9fSZach Atkins     CeedInt       num_suboperators;
23025da5ab9fSZach Atkins     CeedOperator *sub_operators;
23035da5ab9fSZach Atkins 
2304ed094490SJeremy L Thompson     CeedCall(CeedOperatorCompositeGetNumSub(op, &num_suboperators));
2305ed094490SJeremy L Thompson     CeedCall(CeedOperatorCompositeGetSubList(op, &sub_operators));
23065da5ab9fSZach Atkins 
23075da5ab9fSZach Atkins     // Zero all output vectors
23085da5ab9fSZach Atkins     for (CeedInt i = 0; i < num_suboperators; i++) {
23095da5ab9fSZach Atkins       CeedInt            num_output_fields;
23105da5ab9fSZach Atkins       CeedOperatorField *output_fields;
23115da5ab9fSZach Atkins 
23125da5ab9fSZach Atkins       CeedCall(CeedOperatorGetFields(sub_operators[i], NULL, NULL, &num_output_fields, &output_fields));
23135da5ab9fSZach Atkins       for (CeedInt j = 0; j < num_output_fields; j++) {
23145da5ab9fSZach Atkins         CeedVector vec;
23155da5ab9fSZach Atkins 
23165da5ab9fSZach Atkins         CeedCall(CeedOperatorFieldGetVector(output_fields[j], &vec));
23175da5ab9fSZach Atkins         if (vec != CEED_VECTOR_ACTIVE && vec != CEED_VECTOR_NONE) CeedCall(CeedVectorSetValue(vec, 0.0));
23185da5ab9fSZach Atkins         CeedCall(CeedVectorDestroy(&vec));
23195da5ab9fSZach Atkins       }
23205da5ab9fSZach Atkins     }
23215da5ab9fSZach Atkins     // ApplyAdd
23225da5ab9fSZach Atkins     CeedCall(CeedOperatorApplyAdd(op, in, out, request));
23235da5ab9fSZach Atkins   } else {
23245da5ab9fSZach Atkins     // Standard Operator
23255da5ab9fSZach Atkins     CeedInt            num_output_fields;
23265da5ab9fSZach Atkins     CeedOperatorField *output_fields;
23275da5ab9fSZach Atkins 
23285da5ab9fSZach Atkins     CeedCall(CeedOperatorGetFields(op, NULL, NULL, &num_output_fields, &output_fields));
23295da5ab9fSZach Atkins     // Zero all output vectors
23305da5ab9fSZach Atkins     for (CeedInt i = 0; i < num_output_fields; i++) {
23315da5ab9fSZach Atkins       CeedVector vec;
23325da5ab9fSZach Atkins 
23335da5ab9fSZach Atkins       CeedCall(CeedOperatorFieldGetVector(output_fields[i], &vec));
23345da5ab9fSZach Atkins       if (vec != CEED_VECTOR_ACTIVE && vec != CEED_VECTOR_NONE) CeedCall(CeedVectorSetValue(vec, 0.0));
23355da5ab9fSZach Atkins       CeedCall(CeedVectorDestroy(&vec));
23365da5ab9fSZach Atkins     }
23375da5ab9fSZach Atkins     // ApplyAdd
23385da5ab9fSZach Atkins     CeedCall(CeedOperatorApplyAdd(op, in, out, request));
23395da5ab9fSZach Atkins   }
23405da5ab9fSZach Atkins   return CEED_ERROR_SUCCESS;
23415da5ab9fSZach Atkins }
23425da5ab9fSZach Atkins 
23435da5ab9fSZach Atkins /**
2344536b928cSSebastian Grimberg   @brief Destroy temporary assembly data associated with a `CeedOperator`
2345536b928cSSebastian Grimberg 
2346536b928cSSebastian Grimberg   @param[in,out] op `CeedOperator` whose assembly data to destroy
2347536b928cSSebastian Grimberg 
2348536b928cSSebastian Grimberg   @return An error code: 0 - success, otherwise - failure
2349536b928cSSebastian Grimberg 
2350536b928cSSebastian Grimberg   @ref User
2351536b928cSSebastian Grimberg **/
2352536b928cSSebastian Grimberg int CeedOperatorAssemblyDataStrip(CeedOperator op) {
2353536b928cSSebastian Grimberg   bool is_composite;
2354536b928cSSebastian Grimberg 
2355536b928cSSebastian Grimberg   CeedCall(CeedQFunctionAssemblyDataDestroy(&op->qf_assembled));
2356536b928cSSebastian Grimberg   CeedCall(CeedOperatorAssemblyDataDestroy(&op->op_assembled));
2357536b928cSSebastian Grimberg   CeedCall(CeedOperatorIsComposite(op, &is_composite));
2358536b928cSSebastian Grimberg   if (is_composite) {
2359536b928cSSebastian Grimberg     CeedInt       num_suboperators;
2360536b928cSSebastian Grimberg     CeedOperator *sub_operators;
2361536b928cSSebastian Grimberg 
2362ed094490SJeremy L Thompson     CeedCall(CeedOperatorCompositeGetNumSub(op, &num_suboperators));
2363ed094490SJeremy L Thompson     CeedCall(CeedOperatorCompositeGetSubList(op, &sub_operators));
2364536b928cSSebastian Grimberg     for (CeedInt i = 0; i < num_suboperators; i++) {
2365536b928cSSebastian Grimberg       CeedCall(CeedQFunctionAssemblyDataDestroy(&sub_operators[i]->qf_assembled));
2366536b928cSSebastian Grimberg       CeedCall(CeedOperatorAssemblyDataDestroy(&sub_operators[i]->op_assembled));
2367536b928cSSebastian Grimberg     }
2368536b928cSSebastian Grimberg   }
2369536b928cSSebastian Grimberg   return CEED_ERROR_SUCCESS;
2370536b928cSSebastian Grimberg }
2371536b928cSSebastian Grimberg 
2372536b928cSSebastian Grimberg /**
2373ca94c3ddSJeremy L Thompson   @brief Destroy a `CeedOperator`
2374d7b241e6Sjeremylt 
2375ca94c3ddSJeremy L Thompson   @param[in,out] op `CeedOperator` to destroy
2376b11c1e72Sjeremylt 
2377b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
2378dfdf5a53Sjeremylt 
23797a982d89SJeremy L. Thompson   @ref User
2380b11c1e72Sjeremylt **/
2381d7b241e6Sjeremylt int CeedOperatorDestroy(CeedOperator *op) {
2382*b0f67a9cSJeremy L Thompson   if (!*op || CeedObjectDereference((CeedObject)*op) > 0) {
2383ad6481ceSJeremy L Thompson     *op = NULL;
2384ad6481ceSJeremy L Thompson     return CEED_ERROR_SUCCESS;
2385ad6481ceSJeremy L Thompson   }
2386f883f0a5SSebastian Grimberg   // Backend destroy
2387f883f0a5SSebastian Grimberg   if ((*op)->Destroy) {
2388f883f0a5SSebastian Grimberg     CeedCall((*op)->Destroy(*op));
2389f883f0a5SSebastian Grimberg   }
2390fe2413ffSjeremylt   // Free fields
23912b730f8bSJeremy L Thompson   for (CeedInt i = 0; i < (*op)->num_fields; i++) {
2392d1d35e2fSjeremylt     if ((*op)->input_fields[i]) {
2393437c7c90SJeremy L Thompson       if ((*op)->input_fields[i]->elem_rstr != CEED_ELEMRESTRICTION_NONE) {
2394437c7c90SJeremy L Thompson         CeedCall(CeedElemRestrictionDestroy(&(*op)->input_fields[i]->elem_rstr));
239515910d16Sjeremylt       }
2396356036faSJeremy L Thompson       if ((*op)->input_fields[i]->basis != CEED_BASIS_NONE) {
23972b730f8bSJeremy L Thompson         CeedCall(CeedBasisDestroy(&(*op)->input_fields[i]->basis));
239871352a93Sjeremylt       }
23992b730f8bSJeremy L Thompson       if ((*op)->input_fields[i]->vec != CEED_VECTOR_ACTIVE && (*op)->input_fields[i]->vec != CEED_VECTOR_NONE) {
24002b730f8bSJeremy L Thompson         CeedCall(CeedVectorDestroy(&(*op)->input_fields[i]->vec));
240171352a93Sjeremylt       }
24022b730f8bSJeremy L Thompson       CeedCall(CeedFree(&(*op)->input_fields[i]->field_name));
24032b730f8bSJeremy L Thompson       CeedCall(CeedFree(&(*op)->input_fields[i]));
2404fe2413ffSjeremylt     }
24052b730f8bSJeremy L Thompson   }
24062b730f8bSJeremy L Thompson   for (CeedInt i = 0; i < (*op)->num_fields; i++) {
2407d1d35e2fSjeremylt     if ((*op)->output_fields[i]) {
2408437c7c90SJeremy L Thompson       CeedCall(CeedElemRestrictionDestroy(&(*op)->output_fields[i]->elem_rstr));
2409356036faSJeremy L Thompson       if ((*op)->output_fields[i]->basis != CEED_BASIS_NONE) {
24102b730f8bSJeremy L Thompson         CeedCall(CeedBasisDestroy(&(*op)->output_fields[i]->basis));
241171352a93Sjeremylt       }
24122b730f8bSJeremy L Thompson       if ((*op)->output_fields[i]->vec != CEED_VECTOR_ACTIVE && (*op)->output_fields[i]->vec != CEED_VECTOR_NONE) {
24132b730f8bSJeremy L Thompson         CeedCall(CeedVectorDestroy(&(*op)->output_fields[i]->vec));
241471352a93Sjeremylt       }
24152b730f8bSJeremy L Thompson       CeedCall(CeedFree(&(*op)->output_fields[i]->field_name));
24162b730f8bSJeremy L Thompson       CeedCall(CeedFree(&(*op)->output_fields[i]));
24172b730f8bSJeremy L Thompson     }
2418fe2413ffSjeremylt   }
2419f883f0a5SSebastian Grimberg   CeedCall(CeedFree(&(*op)->input_fields));
2420f883f0a5SSebastian Grimberg   CeedCall(CeedFree(&(*op)->output_fields));
2421f883f0a5SSebastian Grimberg   // Destroy AtPoints data
242248acf710SJeremy L Thompson   CeedCall(CeedVectorDestroy(&(*op)->point_coords));
242348acf710SJeremy L Thompson   CeedCall(CeedElemRestrictionDestroy(&(*op)->rstr_points));
242448acf710SJeremy L Thompson   CeedCall(CeedElemRestrictionDestroy(&(*op)->first_points_rstr));
2425c6b536a8SSebastian Grimberg   // Destroy assembly data (must happen before destroying sub_operators)
2426f883f0a5SSebastian Grimberg   CeedCall(CeedOperatorAssemblyDataStrip(*op));
2427d1d35e2fSjeremylt   // Destroy sub_operators
24282b730f8bSJeremy L Thompson   for (CeedInt i = 0; i < (*op)->num_suboperators; i++) {
2429d1d35e2fSjeremylt     if ((*op)->sub_operators[i]) {
24302b730f8bSJeremy L Thompson       CeedCall(CeedOperatorDestroy(&(*op)->sub_operators[i]));
243152d6035fSJeremy L Thompson     }
24322b730f8bSJeremy L Thompson   }
2433f883f0a5SSebastian Grimberg   CeedCall(CeedFree(&(*op)->sub_operators));
24342b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionDestroy(&(*op)->qf));
24352b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionDestroy(&(*op)->dqf));
24362b730f8bSJeremy L Thompson   CeedCall(CeedQFunctionDestroy(&(*op)->dqfT));
24373668ca4bSJeremy L Thompson   // Destroy any composite labels
24385ac9af79SJeremy L Thompson   if ((*op)->is_composite) {
24393668ca4bSJeremy L Thompson     for (CeedInt i = 0; i < (*op)->num_context_labels; i++) {
24402b730f8bSJeremy L Thompson       CeedCall(CeedFree(&(*op)->context_labels[i]->sub_labels));
24412b730f8bSJeremy L Thompson       CeedCall(CeedFree(&(*op)->context_labels[i]));
24423668ca4bSJeremy L Thompson     }
24435ac9af79SJeremy L Thompson   }
24442b730f8bSJeremy L Thompson   CeedCall(CeedFree(&(*op)->context_labels));
2445fe2413ffSjeremylt 
24465107b09fSJeremy L Thompson   // Destroy fallback
24472b730f8bSJeremy L Thompson   CeedCall(CeedOperatorDestroy(&(*op)->op_fallback));
24485107b09fSJeremy L Thompson 
24492b730f8bSJeremy L Thompson   CeedCall(CeedFree(&(*op)->name));
2450*b0f67a9cSJeremy L Thompson   CeedCall(CeedObjectDestroy(&(*op)->obj));
24512b730f8bSJeremy L Thompson   CeedCall(CeedFree(op));
2452e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2453d7b241e6Sjeremylt }
2454d7b241e6Sjeremylt 
2455d7b241e6Sjeremylt /// @}
2456