xref: /libCEED/rust/libceed-sys/c-src/interface/ceed-operator.c (revision ed9e99e6e9123568081837e7b4e9e23f10209a71)
13d8e8822SJeremy L Thompson // Copyright (c) 2017-2022, Lawrence Livermore National Security, LLC and other CEED contributors.
23d8e8822SJeremy L Thompson // All Rights Reserved. See the top-level LICENSE and NOTICE files for details.
3d7b241e6Sjeremylt //
43d8e8822SJeremy L Thompson // SPDX-License-Identifier: BSD-2-Clause
5d7b241e6Sjeremylt //
63d8e8822SJeremy L Thompson // This file is part of CEED:  http://github.com/ceed
7d7b241e6Sjeremylt 
8ec3da8bcSJed Brown #include <ceed/ceed.h>
9ec3da8bcSJed Brown #include <ceed/backend.h>
103d576824SJeremy L Thompson #include <ceed-impl.h>
113d576824SJeremy L Thompson #include <stdbool.h>
123d576824SJeremy L Thompson #include <stdio.h>
133d576824SJeremy L Thompson #include <string.h>
14d7b241e6Sjeremylt 
15dfdf5a53Sjeremylt /// @file
167a982d89SJeremy L. Thompson /// Implementation of CeedOperator interfaces
177a982d89SJeremy L. Thompson 
187a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
197a982d89SJeremy L. Thompson /// CeedOperator Library Internal Functions
207a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
217a982d89SJeremy L. Thompson /// @addtogroup CeedOperatorDeveloper
227a982d89SJeremy L. Thompson /// @{
237a982d89SJeremy L. Thompson 
247a982d89SJeremy L. Thompson /**
25e15f9bd0SJeremy L Thompson   @brief Check if a CeedOperator Field matches the QFunction Field
26e15f9bd0SJeremy L Thompson 
27e15f9bd0SJeremy L Thompson   @param[in] ceed      Ceed object for error handling
28d1d35e2fSjeremylt   @param[in] qf_field  QFunction Field matching Operator Field
29e15f9bd0SJeremy L Thompson   @param[in] r         Operator Field ElemRestriction
30e15f9bd0SJeremy L Thompson   @param[in] b         Operator Field Basis
31e15f9bd0SJeremy L Thompson 
32e15f9bd0SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
33e15f9bd0SJeremy L Thompson 
34e15f9bd0SJeremy L Thompson   @ref Developer
35e15f9bd0SJeremy L Thompson **/
36d1d35e2fSjeremylt static int CeedOperatorCheckField(Ceed ceed, CeedQFunctionField qf_field,
37e15f9bd0SJeremy L Thompson                                   CeedElemRestriction r, CeedBasis b) {
38e15f9bd0SJeremy L Thompson   int ierr;
39d1d35e2fSjeremylt   CeedEvalMode eval_mode = qf_field->eval_mode;
40d1d35e2fSjeremylt   CeedInt dim = 1, num_comp = 1, restr_num_comp = 1, size = qf_field->size;
41e15f9bd0SJeremy L Thompson   // Restriction
42e15f9bd0SJeremy L Thompson   if (r != CEED_ELEMRESTRICTION_NONE) {
43d1d35e2fSjeremylt     if (eval_mode == CEED_EVAL_WEIGHT) {
44e15f9bd0SJeremy L Thompson       // LCOV_EXCL_START
45e1e9e29dSJed Brown       return CeedError(ceed, CEED_ERROR_INCOMPATIBLE,
46e1e9e29dSJed Brown                        "CEED_ELEMRESTRICTION_NONE should be used "
47e15f9bd0SJeremy L Thompson                        "for a field with eval mode CEED_EVAL_WEIGHT");
48e15f9bd0SJeremy L Thompson       // LCOV_EXCL_STOP
49e15f9bd0SJeremy L Thompson     }
50d1d35e2fSjeremylt     ierr = CeedElemRestrictionGetNumComponents(r, &restr_num_comp);
5178464608Sjeremylt     CeedChk(ierr);
52e1e9e29dSJed Brown   }
53d1d35e2fSjeremylt   if ((r == CEED_ELEMRESTRICTION_NONE) != (eval_mode == CEED_EVAL_WEIGHT)) {
54e1e9e29dSJed Brown     // LCOV_EXCL_START
55e1e9e29dSJed Brown     return CeedError(ceed, CEED_ERROR_INCOMPATIBLE,
56e1e9e29dSJed Brown                      "CEED_ELEMRESTRICTION_NONE and CEED_EVAL_WEIGHT "
57e1e9e29dSJed Brown                      "must be used together.");
58e1e9e29dSJed Brown     // LCOV_EXCL_STOP
59e1e9e29dSJed Brown   }
60e15f9bd0SJeremy L Thompson   // Basis
61e15f9bd0SJeremy L Thompson   if (b != CEED_BASIS_COLLOCATED) {
62d1d35e2fSjeremylt     if (eval_mode == CEED_EVAL_NONE)
638229195eSjeremylt       // LCOV_EXCL_START
64e1e9e29dSJed Brown       return CeedError(ceed, CEED_ERROR_INCOMPATIBLE,
65d1d35e2fSjeremylt                        "Field '%s' configured with CEED_EVAL_NONE must "
66d1d35e2fSjeremylt                        "be used with CEED_BASIS_COLLOCATED",
678229195eSjeremylt                        // LCOV_EXCL_STOP
68d1d35e2fSjeremylt                        qf_field->field_name);
69e15f9bd0SJeremy L Thompson     ierr = CeedBasisGetDimension(b, &dim); CeedChk(ierr);
70d1d35e2fSjeremylt     ierr = CeedBasisGetNumComponents(b, &num_comp); CeedChk(ierr);
71d1d35e2fSjeremylt     if (r != CEED_ELEMRESTRICTION_NONE && restr_num_comp != num_comp) {
72e15f9bd0SJeremy L Thompson       // LCOV_EXCL_START
73e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_DIMENSION,
74d1d35e2fSjeremylt                        "Field '%s' of size %d and EvalMode %s: ElemRestriction "
75d1d35e2fSjeremylt                        "has %d components, but Basis has %d components",
76d1d35e2fSjeremylt                        qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode],
77d1d35e2fSjeremylt                        restr_num_comp,
78d1d35e2fSjeremylt                        num_comp);
79e15f9bd0SJeremy L Thompson       // LCOV_EXCL_STOP
80e15f9bd0SJeremy L Thompson     }
81e15f9bd0SJeremy L Thompson   }
82e15f9bd0SJeremy L Thompson   // Field size
83d1d35e2fSjeremylt   switch(eval_mode) {
84e15f9bd0SJeremy L Thompson   case CEED_EVAL_NONE:
85d1d35e2fSjeremylt     if (size != restr_num_comp)
86e15f9bd0SJeremy L Thompson       // LCOV_EXCL_START
87e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_DIMENSION,
88e1e9e29dSJed Brown                        "Field '%s' of size %d and EvalMode %s: ElemRestriction has %d components",
89d1d35e2fSjeremylt                        qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode],
90d1d35e2fSjeremylt                        restr_num_comp);
91e15f9bd0SJeremy L Thompson     // LCOV_EXCL_STOP
92e15f9bd0SJeremy L Thompson     break;
93e15f9bd0SJeremy L Thompson   case CEED_EVAL_INTERP:
94d1d35e2fSjeremylt     if (size != num_comp)
95e15f9bd0SJeremy L Thompson       // LCOV_EXCL_START
96e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_DIMENSION,
97e1e9e29dSJed Brown                        "Field '%s' of size %d and EvalMode %s: ElemRestriction/Basis has %d components",
98d1d35e2fSjeremylt                        qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode],
99d1d35e2fSjeremylt                        num_comp);
100e15f9bd0SJeremy L Thompson     // LCOV_EXCL_STOP
101e15f9bd0SJeremy L Thompson     break;
102e15f9bd0SJeremy L Thompson   case CEED_EVAL_GRAD:
103d1d35e2fSjeremylt     if (size != num_comp * dim)
104e15f9bd0SJeremy L Thompson       // LCOV_EXCL_START
105e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_DIMENSION,
106d1d35e2fSjeremylt                        "Field '%s' of size %d and EvalMode %s in %d dimensions: "
107d1d35e2fSjeremylt                        "ElemRestriction/Basis has %d components",
108d1d35e2fSjeremylt                        qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode], dim,
109d1d35e2fSjeremylt                        num_comp);
110e15f9bd0SJeremy L Thompson     // LCOV_EXCL_STOP
111e15f9bd0SJeremy L Thompson     break;
112e15f9bd0SJeremy L Thompson   case CEED_EVAL_WEIGHT:
113d1d35e2fSjeremylt     // No additional checks required
114e15f9bd0SJeremy L Thompson     break;
115e15f9bd0SJeremy L Thompson   case CEED_EVAL_DIV:
116e15f9bd0SJeremy L Thompson     // Not implemented
117e15f9bd0SJeremy L Thompson     break;
118e15f9bd0SJeremy L Thompson   case CEED_EVAL_CURL:
119e15f9bd0SJeremy L Thompson     // Not implemented
120e15f9bd0SJeremy L Thompson     break;
121e15f9bd0SJeremy L Thompson   }
122e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1237a982d89SJeremy L. Thompson }
1247a982d89SJeremy L. Thompson 
1257a982d89SJeremy L. Thompson /**
1267a982d89SJeremy L. Thompson   @brief View a field of a CeedOperator
1277a982d89SJeremy L. Thompson 
1287a982d89SJeremy L. Thompson   @param[in] field         Operator field to view
129d1d35e2fSjeremylt   @param[in] qf_field      QFunction field (carries field name)
130d1d35e2fSjeremylt   @param[in] field_number  Number of field being viewed
1314c4400c7SValeria Barra   @param[in] sub           true indicates sub-operator, which increases indentation; false for top-level operator
132d1d35e2fSjeremylt   @param[in] input         true for an input field; false for output field
1337a982d89SJeremy L. Thompson   @param[in] stream        Stream to view to, e.g., stdout
1347a982d89SJeremy L. Thompson 
1357a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
1367a982d89SJeremy L. Thompson 
1377a982d89SJeremy L. Thompson   @ref Utility
1387a982d89SJeremy L. Thompson **/
1397a982d89SJeremy L. Thompson static int CeedOperatorFieldView(CeedOperatorField field,
140d1d35e2fSjeremylt                                  CeedQFunctionField qf_field,
141d1d35e2fSjeremylt                                  CeedInt field_number, bool sub, bool input,
1427a982d89SJeremy L. Thompson                                  FILE *stream) {
1437a982d89SJeremy L. Thompson   const char *pre = sub ? "  " : "";
144d1d35e2fSjeremylt   const char *in_out = input ? "Input" : "Output";
1457a982d89SJeremy L. Thompson 
146b8bf0bcaSJeremy L Thompson   fprintf(stream, "%s    %s field %d:\n"
1477a982d89SJeremy L. Thompson           "%s      Name: \"%s\"\n",
148d1d35e2fSjeremylt           pre, in_out, field_number, pre, qf_field->field_name);
1497a982d89SJeremy L. Thompson 
150f5ebfb90SJeremy L Thompson   fprintf(stream, "%s      Size: %d\n", pre, qf_field->size);
151f5ebfb90SJeremy L Thompson 
152f5ebfb90SJeremy L Thompson   fprintf(stream, "%s      EvalMode: %s\n", pre,
153f5ebfb90SJeremy L Thompson           CeedEvalModes[qf_field->eval_mode]);
154f5ebfb90SJeremy L Thompson 
1557a982d89SJeremy L. Thompson   if (field->basis == CEED_BASIS_COLLOCATED)
1567a982d89SJeremy L. Thompson     fprintf(stream, "%s      Collocated basis\n", pre);
1577a982d89SJeremy L. Thompson 
1587a982d89SJeremy L. Thompson   if (field->vec == CEED_VECTOR_ACTIVE)
1597a982d89SJeremy L. Thompson     fprintf(stream, "%s      Active vector\n", pre);
1607a982d89SJeremy L. Thompson   else if (field->vec == CEED_VECTOR_NONE)
1617a982d89SJeremy L. Thompson     fprintf(stream, "%s      No vector\n", pre);
162f5ebfb90SJeremy L Thompson 
163e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1647a982d89SJeremy L. Thompson }
1657a982d89SJeremy L. Thompson 
1667a982d89SJeremy L. Thompson /**
1677a982d89SJeremy L. Thompson   @brief View a single CeedOperator
1687a982d89SJeremy L. Thompson 
1697a982d89SJeremy L. Thompson   @param[in] op      CeedOperator to view
1707a982d89SJeremy L. Thompson   @param[in] sub     Boolean flag for sub-operator
1717a982d89SJeremy L. Thompson   @param[in] stream  Stream to write; typically stdout/stderr or a file
1727a982d89SJeremy L. Thompson 
1737a982d89SJeremy L. Thompson   @return Error code: 0 - success, otherwise - failure
1747a982d89SJeremy L. Thompson 
1757a982d89SJeremy L. Thompson   @ref Utility
1767a982d89SJeremy L. Thompson **/
1777a982d89SJeremy L. Thompson int CeedOperatorSingleView(CeedOperator op, bool sub, FILE *stream) {
1787a982d89SJeremy L. Thompson   int ierr;
1797a982d89SJeremy L. Thompson   const char *pre = sub ? "  " : "";
1807a982d89SJeremy L. Thompson 
181381e6593SJeremy L Thompson   CeedInt num_elem, num_qpts;
182381e6593SJeremy L Thompson   ierr = CeedOperatorGetNumElements(op, &num_elem); CeedChk(ierr);
183381e6593SJeremy L Thompson   ierr = CeedOperatorGetNumQuadraturePoints(op, &num_qpts); CeedChk(ierr);
184381e6593SJeremy L Thompson 
18578464608Sjeremylt   CeedInt total_fields = 0;
18678464608Sjeremylt   ierr = CeedOperatorGetNumArgs(op, &total_fields); CeedChk(ierr);
187381e6593SJeremy L Thompson   fprintf(stream, "%s  %d elements with %d quadrature points each\n",
188381e6593SJeremy L Thompson           pre, num_elem, num_qpts);
1897a982d89SJeremy L. Thompson 
190b8bf0bcaSJeremy L Thompson   fprintf(stream, "%s  %d field%s\n", pre, total_fields,
19178464608Sjeremylt           total_fields>1 ? "s" : "");
1927a982d89SJeremy L. Thompson 
193b8bf0bcaSJeremy L Thompson   fprintf(stream, "%s  %d input field%s:\n", pre, op->qf->num_input_fields,
194d1d35e2fSjeremylt           op->qf->num_input_fields>1 ? "s" : "");
195d1d35e2fSjeremylt   for (CeedInt i=0; i<op->qf->num_input_fields; i++) {
196d1d35e2fSjeremylt     ierr = CeedOperatorFieldView(op->input_fields[i], op->qf->input_fields[i],
1977a982d89SJeremy L. Thompson                                  i, sub, 1, stream); CeedChk(ierr);
1987a982d89SJeremy L. Thompson   }
1997a982d89SJeremy L. Thompson 
200b8bf0bcaSJeremy L Thompson   fprintf(stream, "%s  %d output field%s:\n", pre, op->qf->num_output_fields,
201d1d35e2fSjeremylt           op->qf->num_output_fields>1 ? "s" : "");
202d1d35e2fSjeremylt   for (CeedInt i=0; i<op->qf->num_output_fields; i++) {
203d1d35e2fSjeremylt     ierr = CeedOperatorFieldView(op->output_fields[i], op->qf->output_fields[i],
2047a982d89SJeremy L. Thompson                                  i, sub, 0, stream); CeedChk(ierr);
2057a982d89SJeremy L. Thompson   }
206e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2077a982d89SJeremy L. Thompson }
2087a982d89SJeremy L. Thompson 
209d99fa3c5SJeremy L Thompson /**
2100f60e0a8SJeremy L Thompson   @brief Find the active vector basis for a non-composite CeedOperator
211eaf62fffSJeremy L Thompson 
212eaf62fffSJeremy L Thompson   @param[in] op             CeedOperator to find active basis for
2130f60e0a8SJeremy L Thompson   @param[out] active_basis  Basis for active input vector or NULL for composite operator
214eaf62fffSJeremy L Thompson 
215eaf62fffSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
216eaf62fffSJeremy L Thompson 
217eaf62fffSJeremy L Thompson   @ ref Developer
218eaf62fffSJeremy L Thompson **/
219eaf62fffSJeremy L Thompson int CeedOperatorGetActiveBasis(CeedOperator op, CeedBasis *active_basis) {
220eaf62fffSJeremy L Thompson   *active_basis = NULL;
2210f60e0a8SJeremy L Thompson   if (op->is_composite) return CEED_ERROR_SUCCESS;
22292ae7e47SJeremy L Thompson   for (CeedInt i = 0; i < op->qf->num_input_fields; i++)
223eaf62fffSJeremy L Thompson     if (op->input_fields[i]->vec == CEED_VECTOR_ACTIVE) {
224eaf62fffSJeremy L Thompson       *active_basis = op->input_fields[i]->basis;
225eaf62fffSJeremy L Thompson       break;
226eaf62fffSJeremy L Thompson     }
227eaf62fffSJeremy L Thompson 
228eaf62fffSJeremy L Thompson   if (!*active_basis) {
229eaf62fffSJeremy L Thompson     // LCOV_EXCL_START
230eaf62fffSJeremy L Thompson     int ierr;
231eaf62fffSJeremy L Thompson     Ceed ceed;
232eaf62fffSJeremy L Thompson     ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr);
233eaf62fffSJeremy L Thompson     return CeedError(ceed, CEED_ERROR_MINOR,
234eaf62fffSJeremy L Thompson                      "No active CeedBasis found");
235eaf62fffSJeremy L Thompson     // LCOV_EXCL_STOP
236eaf62fffSJeremy L Thompson   }
237eaf62fffSJeremy L Thompson   return CEED_ERROR_SUCCESS;
238eaf62fffSJeremy L Thompson }
239eaf62fffSJeremy L Thompson 
240eaf62fffSJeremy L Thompson /**
2410f60e0a8SJeremy L Thompson   @brief Find the active vector ElemRestriction for a non-composite CeedOperator
242e2f04181SAndrew T. Barker 
243e2f04181SAndrew T. Barker   @param[in] op            CeedOperator to find active basis for
2440f60e0a8SJeremy L Thompson   @param[out] active_rstr  ElemRestriction for active input vector or NULL for composite operator
245e2f04181SAndrew T. Barker 
246e2f04181SAndrew T. Barker   @return An error code: 0 - success, otherwise - failure
247e2f04181SAndrew T. Barker 
248e2f04181SAndrew T. Barker   @ref Utility
249e2f04181SAndrew T. Barker **/
250eaf62fffSJeremy L Thompson int CeedOperatorGetActiveElemRestriction(CeedOperator op,
251d1d35e2fSjeremylt     CeedElemRestriction *active_rstr) {
252d1d35e2fSjeremylt   *active_rstr = NULL;
2530f60e0a8SJeremy L Thompson   if (op->is_composite) return CEED_ERROR_SUCCESS;
25492ae7e47SJeremy L Thompson   for (CeedInt i = 0; i < op->qf->num_input_fields; i++)
255d1d35e2fSjeremylt     if (op->input_fields[i]->vec == CEED_VECTOR_ACTIVE) {
256d1d35e2fSjeremylt       *active_rstr = op->input_fields[i]->elem_restr;
257e2f04181SAndrew T. Barker       break;
258e2f04181SAndrew T. Barker     }
259e2f04181SAndrew T. Barker 
260d1d35e2fSjeremylt   if (!*active_rstr) {
261e2f04181SAndrew T. Barker     // LCOV_EXCL_START
262e2f04181SAndrew T. Barker     int ierr;
263e2f04181SAndrew T. Barker     Ceed ceed;
264e2f04181SAndrew T. Barker     ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr);
265e2f04181SAndrew T. Barker     return CeedError(ceed, CEED_ERROR_INCOMPLETE,
266eaf62fffSJeremy L Thompson                      "No active CeedElemRestriction found");
267e2f04181SAndrew T. Barker     // LCOV_EXCL_STOP
268e2f04181SAndrew T. Barker   }
269e2f04181SAndrew T. Barker   return CEED_ERROR_SUCCESS;
270e2f04181SAndrew T. Barker }
271e2f04181SAndrew T. Barker 
272d8dd9a91SJeremy L Thompson /**
273d8dd9a91SJeremy L Thompson   @brief Set QFunctionContext field value of the specified type.
274d8dd9a91SJeremy L Thompson            For composite operators, the value is set in all
275d8dd9a91SJeremy L Thompson            sub-operator QFunctionContexts that have a matching `field_name`.
276d8dd9a91SJeremy L Thompson            A non-zero error code is returned for single operators
277d8dd9a91SJeremy L Thompson            that do not have a matching field of the same type or composite
278d8dd9a91SJeremy L Thompson            operators that do not have any field of a matching type.
279d8dd9a91SJeremy L Thompson 
280d8dd9a91SJeremy L Thompson   @param op          CeedOperator
2813668ca4bSJeremy L Thompson   @param field_label Label of field to set
282d8dd9a91SJeremy L Thompson   @param field_type  Type of field to set
283d8dd9a91SJeremy L Thompson   @param value       Value to set
284d8dd9a91SJeremy L Thompson 
285d8dd9a91SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
286d8dd9a91SJeremy L Thompson 
287d8dd9a91SJeremy L Thompson   @ref User
288d8dd9a91SJeremy L Thompson **/
289d8dd9a91SJeremy L Thompson static int CeedOperatorContextSetGeneric(CeedOperator op,
2903668ca4bSJeremy L Thompson     CeedContextFieldLabel field_label, CeedContextFieldType field_type,
2913668ca4bSJeremy L Thompson     void *value) {
292d8dd9a91SJeremy L Thompson   int ierr;
293d8dd9a91SJeremy L Thompson 
2943668ca4bSJeremy L Thompson   if (!field_label)
2953668ca4bSJeremy L Thompson     // LCOV_EXCL_START
2963668ca4bSJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED,
2973668ca4bSJeremy L Thompson                      "Invalid field label");
2983668ca4bSJeremy L Thompson   // LCOV_EXCL_STOP
2993668ca4bSJeremy L Thompson 
3003668ca4bSJeremy L Thompson   bool is_composite = false;
301d8dd9a91SJeremy L Thompson   ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr);
302d8dd9a91SJeremy L Thompson   if (is_composite) {
303d8dd9a91SJeremy L Thompson     CeedInt num_sub;
304d8dd9a91SJeremy L Thompson     CeedOperator *sub_operators;
305d8dd9a91SJeremy L Thompson 
306d8dd9a91SJeremy L Thompson     ierr = CeedOperatorGetNumSub(op, &num_sub); CeedChk(ierr);
307d8dd9a91SJeremy L Thompson     ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr);
3083668ca4bSJeremy L Thompson     if (num_sub != field_label->num_sub_labels)
3093668ca4bSJeremy L Thompson       // LCOV_EXCL_START
3103668ca4bSJeremy L Thompson       return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED,
3113668ca4bSJeremy L Thompson                        "ContextLabel does not correspond to composite operator.\n"
3123668ca4bSJeremy L Thompson                        "Use CeedOperatorGetContextFieldLabel().");
3133668ca4bSJeremy L Thompson     // LCOV_EXCL_STOP
314d8dd9a91SJeremy L Thompson 
315d8dd9a91SJeremy L Thompson     for (CeedInt i = 0; i < num_sub; i++) {
316d8dd9a91SJeremy L Thompson       // Try every sub-operator, ok if some sub-operators do not have field
3173668ca4bSJeremy L Thompson       if (field_label->sub_labels[i] && sub_operators[i]->qf->ctx) {
3183668ca4bSJeremy L Thompson         ierr = CeedQFunctionContextSetGeneric(sub_operators[i]->qf->ctx,
3193668ca4bSJeremy L Thompson                                               field_label->sub_labels[i],
3203668ca4bSJeremy L Thompson                                               field_type, value); CeedChk(ierr);
321d8dd9a91SJeremy L Thompson       }
322d8dd9a91SJeremy L Thompson     }
323d8dd9a91SJeremy L Thompson   } else {
324d8dd9a91SJeremy L Thompson     if (!op->qf->ctx)
325d8dd9a91SJeremy L Thompson       // LCOV_EXCL_START
326d8dd9a91SJeremy L Thompson       return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED,
327d8dd9a91SJeremy L Thompson                        "QFunction does not have context data");
328d8dd9a91SJeremy L Thompson     // LCOV_EXCL_STOP
329d8dd9a91SJeremy L Thompson 
3303668ca4bSJeremy L Thompson     ierr = CeedQFunctionContextSetGeneric(op->qf->ctx, field_label,
3313668ca4bSJeremy L Thompson                                           field_type, value); CeedChk(ierr);
332d8dd9a91SJeremy L Thompson   }
333d8dd9a91SJeremy L Thompson 
334d8dd9a91SJeremy L Thompson   return CEED_ERROR_SUCCESS;
335d8dd9a91SJeremy L Thompson }
336d8dd9a91SJeremy L Thompson 
3377a982d89SJeremy L. Thompson /// @}
3387a982d89SJeremy L. Thompson 
3397a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
3407a982d89SJeremy L. Thompson /// CeedOperator Backend API
3417a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
3427a982d89SJeremy L. Thompson /// @addtogroup CeedOperatorBackend
3437a982d89SJeremy L. Thompson /// @{
3447a982d89SJeremy L. Thompson 
3457a982d89SJeremy L. Thompson /**
3467a982d89SJeremy L. Thompson   @brief Get the number of arguments associated with a CeedOperator
3477a982d89SJeremy L. Thompson 
3487a982d89SJeremy L. Thompson   @param op             CeedOperator
349d1d35e2fSjeremylt   @param[out] num_args  Variable to store vector number of arguments
3507a982d89SJeremy L. Thompson 
3517a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
3527a982d89SJeremy L. Thompson 
3537a982d89SJeremy L. Thompson   @ref Backend
3547a982d89SJeremy L. Thompson **/
3557a982d89SJeremy L. Thompson 
356d1d35e2fSjeremylt int CeedOperatorGetNumArgs(CeedOperator op, CeedInt *num_args) {
357f04ea552SJeremy L Thompson   if (op->is_composite)
3587a982d89SJeremy L. Thompson     // LCOV_EXCL_START
359e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
360e15f9bd0SJeremy L Thompson                      "Not defined for composite operators");
3617a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
3627a982d89SJeremy L. Thompson 
363d1d35e2fSjeremylt   *num_args = op->num_fields;
364e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
3657a982d89SJeremy L. Thompson }
3667a982d89SJeremy L. Thompson 
3677a982d89SJeremy L. Thompson /**
3687a982d89SJeremy L. Thompson   @brief Get the setup status of a CeedOperator
3697a982d89SJeremy L. Thompson 
3707a982d89SJeremy L. Thompson   @param op                  CeedOperator
371d1d35e2fSjeremylt   @param[out] is_setup_done  Variable to store setup status
3727a982d89SJeremy L. Thompson 
3737a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
3747a982d89SJeremy L. Thompson 
3757a982d89SJeremy L. Thompson   @ref Backend
3767a982d89SJeremy L. Thompson **/
3777a982d89SJeremy L. Thompson 
378d1d35e2fSjeremylt int CeedOperatorIsSetupDone(CeedOperator op, bool *is_setup_done) {
379f04ea552SJeremy L Thompson   *is_setup_done = op->is_backend_setup;
380e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
3817a982d89SJeremy L. Thompson }
3827a982d89SJeremy L. Thompson 
3837a982d89SJeremy L. Thompson /**
3847a982d89SJeremy L. Thompson   @brief Get the QFunction associated with a CeedOperator
3857a982d89SJeremy L. Thompson 
3867a982d89SJeremy L. Thompson   @param op       CeedOperator
3877a982d89SJeremy L. Thompson   @param[out] qf  Variable to store QFunction
3887a982d89SJeremy L. Thompson 
3897a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
3907a982d89SJeremy L. Thompson 
3917a982d89SJeremy L. Thompson   @ref Backend
3927a982d89SJeremy L. Thompson **/
3937a982d89SJeremy L. Thompson 
3947a982d89SJeremy L. Thompson int CeedOperatorGetQFunction(CeedOperator op, CeedQFunction *qf) {
395f04ea552SJeremy L Thompson   if (op->is_composite)
3967a982d89SJeremy L. Thompson     // LCOV_EXCL_START
397e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
398e15f9bd0SJeremy L Thompson                      "Not defined for composite operator");
3997a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
4007a982d89SJeremy L. Thompson 
4017a982d89SJeremy L. Thompson   *qf = op->qf;
402e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
4037a982d89SJeremy L. Thompson }
4047a982d89SJeremy L. Thompson 
4057a982d89SJeremy L. Thompson /**
406c04a41a7SJeremy L Thompson   @brief Get a boolean value indicating if the CeedOperator is composite
407c04a41a7SJeremy L Thompson 
408c04a41a7SJeremy L Thompson   @param op                 CeedOperator
409d1d35e2fSjeremylt   @param[out] is_composite  Variable to store composite status
410c04a41a7SJeremy L Thompson 
411c04a41a7SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
412c04a41a7SJeremy L Thompson 
413c04a41a7SJeremy L Thompson   @ref Backend
414c04a41a7SJeremy L Thompson **/
415c04a41a7SJeremy L Thompson 
416d1d35e2fSjeremylt int CeedOperatorIsComposite(CeedOperator op, bool *is_composite) {
417f04ea552SJeremy L Thompson   *is_composite = op->is_composite;
418e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
419c04a41a7SJeremy L Thompson }
420c04a41a7SJeremy L Thompson 
421c04a41a7SJeremy L Thompson /**
422d1d35e2fSjeremylt   @brief Get the number of sub_operators associated with a CeedOperator
4237a982d89SJeremy L. Thompson 
4247a982d89SJeremy L. Thompson   @param op                     CeedOperator
425d1d35e2fSjeremylt   @param[out] num_suboperators  Variable to store number of sub_operators
4267a982d89SJeremy L. Thompson 
4277a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
4287a982d89SJeremy L. Thompson 
4297a982d89SJeremy L. Thompson   @ref Backend
4307a982d89SJeremy L. Thompson **/
4317a982d89SJeremy L. Thompson 
432d1d35e2fSjeremylt int CeedOperatorGetNumSub(CeedOperator op, CeedInt *num_suboperators) {
433f04ea552SJeremy L Thompson   if (!op->is_composite)
4347a982d89SJeremy L. Thompson     // LCOV_EXCL_START
435e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR, "Not a composite operator");
4367a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
4377a982d89SJeremy L. Thompson 
438d1d35e2fSjeremylt   *num_suboperators = op->num_suboperators;
439e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
4407a982d89SJeremy L. Thompson }
4417a982d89SJeremy L. Thompson 
4427a982d89SJeremy L. Thompson /**
443d1d35e2fSjeremylt   @brief Get the list of sub_operators associated with a CeedOperator
4447a982d89SJeremy L. Thompson 
4457a982d89SJeremy L. Thompson   @param op                  CeedOperator
446d1d35e2fSjeremylt   @param[out] sub_operators  Variable to store list of sub_operators
4477a982d89SJeremy L. Thompson 
4487a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
4497a982d89SJeremy L. Thompson 
4507a982d89SJeremy L. Thompson   @ref Backend
4517a982d89SJeremy L. Thompson **/
4527a982d89SJeremy L. Thompson 
453d1d35e2fSjeremylt int CeedOperatorGetSubList(CeedOperator op, CeedOperator **sub_operators) {
454f04ea552SJeremy L Thompson   if (!op->is_composite)
4557a982d89SJeremy L. Thompson     // LCOV_EXCL_START
456e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR, "Not a composite operator");
4577a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
4587a982d89SJeremy L. Thompson 
459d1d35e2fSjeremylt   *sub_operators = op->sub_operators;
460e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
4617a982d89SJeremy L. Thompson }
4627a982d89SJeremy L. Thompson 
4637a982d89SJeremy L. Thompson /**
4647a982d89SJeremy L. Thompson   @brief Get the backend data of a CeedOperator
4657a982d89SJeremy L. Thompson 
4667a982d89SJeremy L. Thompson   @param op         CeedOperator
4677a982d89SJeremy L. Thompson   @param[out] data  Variable to store data
4687a982d89SJeremy L. Thompson 
4697a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
4707a982d89SJeremy L. Thompson 
4717a982d89SJeremy L. Thompson   @ref Backend
4727a982d89SJeremy L. Thompson **/
4737a982d89SJeremy L. Thompson 
474777ff853SJeremy L Thompson int CeedOperatorGetData(CeedOperator op, void *data) {
475777ff853SJeremy L Thompson   *(void **)data = op->data;
476e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
4777a982d89SJeremy L. Thompson }
4787a982d89SJeremy L. Thompson 
4797a982d89SJeremy L. Thompson /**
4807a982d89SJeremy L. Thompson   @brief Set the backend data of a CeedOperator
4817a982d89SJeremy L. Thompson 
4827a982d89SJeremy L. Thompson   @param[out] op  CeedOperator
4837a982d89SJeremy L. Thompson   @param data     Data to set
4847a982d89SJeremy L. Thompson 
4857a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
4867a982d89SJeremy L. Thompson 
4877a982d89SJeremy L. Thompson   @ref Backend
4887a982d89SJeremy L. Thompson **/
4897a982d89SJeremy L. Thompson 
490777ff853SJeremy L Thompson int CeedOperatorSetData(CeedOperator op, void *data) {
491777ff853SJeremy L Thompson   op->data = data;
492e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
4937a982d89SJeremy L. Thompson }
4947a982d89SJeremy L. Thompson 
4957a982d89SJeremy L. Thompson /**
49634359f16Sjeremylt   @brief Increment the reference counter for a CeedOperator
49734359f16Sjeremylt 
49834359f16Sjeremylt   @param op  CeedOperator to increment the reference counter
49934359f16Sjeremylt 
50034359f16Sjeremylt   @return An error code: 0 - success, otherwise - failure
50134359f16Sjeremylt 
50234359f16Sjeremylt   @ref Backend
50334359f16Sjeremylt **/
5049560d06aSjeremylt int CeedOperatorReference(CeedOperator op) {
50534359f16Sjeremylt   op->ref_count++;
50634359f16Sjeremylt   return CEED_ERROR_SUCCESS;
50734359f16Sjeremylt }
50834359f16Sjeremylt 
50934359f16Sjeremylt /**
5107a982d89SJeremy L. Thompson   @brief Set the setup flag of a CeedOperator to True
5117a982d89SJeremy L. Thompson 
5127a982d89SJeremy L. Thompson   @param op  CeedOperator
5137a982d89SJeremy L. Thompson 
5147a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5157a982d89SJeremy L. Thompson 
5167a982d89SJeremy L. Thompson   @ref Backend
5177a982d89SJeremy L. Thompson **/
5187a982d89SJeremy L. Thompson 
5197a982d89SJeremy L. Thompson int CeedOperatorSetSetupDone(CeedOperator op) {
520f04ea552SJeremy L Thompson   op->is_backend_setup = true;
521e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5227a982d89SJeremy L. Thompson }
5237a982d89SJeremy L. Thompson 
5247a982d89SJeremy L. Thompson /// @}
5257a982d89SJeremy L. Thompson 
5267a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
5277a982d89SJeremy L. Thompson /// CeedOperator Public API
5287a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
5297a982d89SJeremy L. Thompson /// @addtogroup CeedOperatorUser
530dfdf5a53Sjeremylt /// @{
531d7b241e6Sjeremylt 
532d7b241e6Sjeremylt /**
5330219ea01SJeremy L Thompson   @brief Create a CeedOperator and associate a CeedQFunction. A CeedBasis and
5340219ea01SJeremy L Thompson            CeedElemRestriction can be associated with CeedQFunction fields with
5350219ea01SJeremy L Thompson            \ref CeedOperatorSetField.
536d7b241e6Sjeremylt 
537b11c1e72Sjeremylt   @param ceed     A Ceed object where the CeedOperator will be created
538d7b241e6Sjeremylt   @param qf       QFunction defining the action of the operator at quadrature points
53934138859Sjeremylt   @param dqf      QFunction defining the action of the Jacobian of @a qf (or
5404cc79fe7SJed Brown                     @ref CEED_QFUNCTION_NONE)
541d7b241e6Sjeremylt   @param dqfT     QFunction defining the action of the transpose of the Jacobian
5424cc79fe7SJed Brown                     of @a qf (or @ref CEED_QFUNCTION_NONE)
543b11c1e72Sjeremylt   @param[out] op  Address of the variable where the newly created
544b11c1e72Sjeremylt                     CeedOperator will be stored
545b11c1e72Sjeremylt 
546b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
547dfdf5a53Sjeremylt 
5487a982d89SJeremy L. Thompson   @ref User
549d7b241e6Sjeremylt  */
550d7b241e6Sjeremylt int CeedOperatorCreate(Ceed ceed, CeedQFunction qf, CeedQFunction dqf,
551d7b241e6Sjeremylt                        CeedQFunction dqfT, CeedOperator *op) {
552d7b241e6Sjeremylt   int ierr;
553d7b241e6Sjeremylt 
5545fe0d4faSjeremylt   if (!ceed->OperatorCreate) {
5555fe0d4faSjeremylt     Ceed delegate;
556aefd8378Sjeremylt     ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr);
5575fe0d4faSjeremylt 
5585fe0d4faSjeremylt     if (!delegate)
559c042f62fSJeremy L Thompson       // LCOV_EXCL_START
560e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_UNSUPPORTED,
561e15f9bd0SJeremy L Thompson                        "Backend does not support OperatorCreate");
562c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
5635fe0d4faSjeremylt 
5645fe0d4faSjeremylt     ierr = CeedOperatorCreate(delegate, qf, dqf, dqfT, op); CeedChk(ierr);
565e15f9bd0SJeremy L Thompson     return CEED_ERROR_SUCCESS;
5665fe0d4faSjeremylt   }
5675fe0d4faSjeremylt 
568b3b7035fSJeremy L Thompson   if (!qf || qf == CEED_QFUNCTION_NONE)
569b3b7035fSJeremy L Thompson     // LCOV_EXCL_START
570e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_MINOR,
571e15f9bd0SJeremy L Thompson                      "Operator must have a valid QFunction.");
572b3b7035fSJeremy L Thompson   // LCOV_EXCL_STOP
573d7b241e6Sjeremylt   ierr = CeedCalloc(1, op); CeedChk(ierr);
574d7b241e6Sjeremylt   (*op)->ceed = ceed;
5759560d06aSjeremylt   ierr = CeedReference(ceed); CeedChk(ierr);
576d1d35e2fSjeremylt   (*op)->ref_count = 1;
577d7b241e6Sjeremylt   (*op)->qf = qf;
5782b104005SJeremy L Thompson   (*op)->input_size = -1;
5792b104005SJeremy L Thompson   (*op)->output_size = -1;
5809560d06aSjeremylt   ierr = CeedQFunctionReference(qf); CeedChk(ierr);
581442e7f0bSjeremylt   if (dqf && dqf != CEED_QFUNCTION_NONE) {
582d7b241e6Sjeremylt     (*op)->dqf = dqf;
5839560d06aSjeremylt     ierr = CeedQFunctionReference(dqf); CeedChk(ierr);
584442e7f0bSjeremylt   }
585442e7f0bSjeremylt   if (dqfT && dqfT != CEED_QFUNCTION_NONE) {
586d7b241e6Sjeremylt     (*op)->dqfT = dqfT;
5879560d06aSjeremylt     ierr = CeedQFunctionReference(dqfT); CeedChk(ierr);
588442e7f0bSjeremylt   }
589480fae85SJeremy L Thompson   ierr = CeedQFunctionAssemblyDataCreate(ceed, &(*op)->qf_assembled);
590480fae85SJeremy L Thompson   CeedChk(ierr);
591bf4cb664SJeremy L Thompson   ierr = CeedCalloc(CEED_FIELD_MAX, &(*op)->input_fields); CeedChk(ierr);
592bf4cb664SJeremy L Thompson   ierr = CeedCalloc(CEED_FIELD_MAX, &(*op)->output_fields); CeedChk(ierr);
593d7b241e6Sjeremylt   ierr = ceed->OperatorCreate(*op); CeedChk(ierr);
594e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
595d7b241e6Sjeremylt }
596d7b241e6Sjeremylt 
597d7b241e6Sjeremylt /**
59852d6035fSJeremy L Thompson   @brief Create an operator that composes the action of several operators
59952d6035fSJeremy L Thompson 
60052d6035fSJeremy L Thompson   @param ceed     A Ceed object where the CeedOperator will be created
60152d6035fSJeremy L Thompson   @param[out] op  Address of the variable where the newly created
60252d6035fSJeremy L Thompson                     Composite CeedOperator will be stored
60352d6035fSJeremy L Thompson 
60452d6035fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
60552d6035fSJeremy L Thompson 
6067a982d89SJeremy L. Thompson   @ref User
60752d6035fSJeremy L Thompson  */
60852d6035fSJeremy L Thompson int CeedCompositeOperatorCreate(Ceed ceed, CeedOperator *op) {
60952d6035fSJeremy L Thompson   int ierr;
61052d6035fSJeremy L Thompson 
61152d6035fSJeremy L Thompson   if (!ceed->CompositeOperatorCreate) {
61252d6035fSJeremy L Thompson     Ceed delegate;
613aefd8378Sjeremylt     ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr);
61452d6035fSJeremy L Thompson 
615250756a7Sjeremylt     if (delegate) {
61652d6035fSJeremy L Thompson       ierr = CeedCompositeOperatorCreate(delegate, op); CeedChk(ierr);
617e15f9bd0SJeremy L Thompson       return CEED_ERROR_SUCCESS;
61852d6035fSJeremy L Thompson     }
619250756a7Sjeremylt   }
62052d6035fSJeremy L Thompson 
62152d6035fSJeremy L Thompson   ierr = CeedCalloc(1, op); CeedChk(ierr);
62252d6035fSJeremy L Thompson   (*op)->ceed = ceed;
6239560d06aSjeremylt   ierr = CeedReference(ceed); CeedChk(ierr);
624f04ea552SJeremy L Thompson   (*op)->is_composite = true;
625bf4cb664SJeremy L Thompson   ierr = CeedCalloc(CEED_COMPOSITE_MAX, &(*op)->sub_operators); CeedChk(ierr);
6262b104005SJeremy L Thompson   (*op)->input_size = -1;
6272b104005SJeremy L Thompson   (*op)->output_size = -1;
628250756a7Sjeremylt 
629250756a7Sjeremylt   if (ceed->CompositeOperatorCreate) {
63052d6035fSJeremy L Thompson     ierr = ceed->CompositeOperatorCreate(*op); CeedChk(ierr);
631250756a7Sjeremylt   }
632e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
63352d6035fSJeremy L Thompson }
63452d6035fSJeremy L Thompson 
63552d6035fSJeremy L Thompson /**
6369560d06aSjeremylt   @brief Copy the pointer to a CeedOperator. Both pointers should
6379560d06aSjeremylt            be destroyed with `CeedOperatorDestroy()`;
6389560d06aSjeremylt            Note: If `*op_copy` is non-NULL, then it is assumed that
6399560d06aSjeremylt            `*op_copy` is a pointer to a CeedOperator. This
6409560d06aSjeremylt            CeedOperator will be destroyed if `*op_copy` is the only
6419560d06aSjeremylt            reference to this CeedOperator.
6429560d06aSjeremylt 
6439560d06aSjeremylt   @param op            CeedOperator to copy reference to
6449560d06aSjeremylt   @param[out] op_copy  Variable to store copied reference
6459560d06aSjeremylt 
6469560d06aSjeremylt   @return An error code: 0 - success, otherwise - failure
6479560d06aSjeremylt 
6489560d06aSjeremylt   @ref User
6499560d06aSjeremylt **/
6509560d06aSjeremylt int CeedOperatorReferenceCopy(CeedOperator op, CeedOperator *op_copy) {
6519560d06aSjeremylt   int ierr;
6529560d06aSjeremylt 
6539560d06aSjeremylt   ierr = CeedOperatorReference(op); CeedChk(ierr);
6549560d06aSjeremylt   ierr = CeedOperatorDestroy(op_copy); CeedChk(ierr);
6559560d06aSjeremylt   *op_copy = op;
6569560d06aSjeremylt   return CEED_ERROR_SUCCESS;
6579560d06aSjeremylt }
6589560d06aSjeremylt 
6599560d06aSjeremylt /**
660b11c1e72Sjeremylt   @brief Provide a field to a CeedOperator for use by its CeedQFunction
661d7b241e6Sjeremylt 
662d7b241e6Sjeremylt   This function is used to specify both active and passive fields to a
663d7b241e6Sjeremylt   CeedOperator.  For passive fields, a vector @arg v must be provided.  Passive
664d7b241e6Sjeremylt   fields can inputs or outputs (updated in-place when operator is applied).
665d7b241e6Sjeremylt 
666d7b241e6Sjeremylt   Active fields must be specified using this function, but their data (in a
667d7b241e6Sjeremylt   CeedVector) is passed in CeedOperatorApply().  There can be at most one active
668979e564eSJames Wright   input CeedVector and at most one active output CeedVector passed to
669979e564eSJames Wright   CeedOperatorApply().
670d7b241e6Sjeremylt 
6718c91a0c9SJeremy L Thompson   @param op          CeedOperator on which to provide the field
672d1d35e2fSjeremylt   @param field_name  Name of the field (to be matched with the name used by
6738795c945Sjeremylt                        CeedQFunction)
674b11c1e72Sjeremylt   @param r           CeedElemRestriction
6754cc79fe7SJed Brown   @param b           CeedBasis in which the field resides or @ref CEED_BASIS_COLLOCATED
676b11c1e72Sjeremylt                        if collocated with quadrature points
6774cc79fe7SJed Brown   @param v           CeedVector to be used by CeedOperator or @ref CEED_VECTOR_ACTIVE
6784cc79fe7SJed Brown                        if field is active or @ref CEED_VECTOR_NONE if using
6794cc79fe7SJed Brown                        @ref CEED_EVAL_WEIGHT in the QFunction
680b11c1e72Sjeremylt 
681b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
682dfdf5a53Sjeremylt 
6837a982d89SJeremy L. Thompson   @ref User
684b11c1e72Sjeremylt **/
685d1d35e2fSjeremylt int CeedOperatorSetField(CeedOperator op, const char *field_name,
686a8d32208Sjeremylt                          CeedElemRestriction r, CeedBasis b, CeedVector v) {
687d7b241e6Sjeremylt   int ierr;
688f04ea552SJeremy L Thompson   if (op->is_composite)
689c042f62fSJeremy L Thompson     // LCOV_EXCL_START
690e1e9e29dSJed Brown     return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
691e15f9bd0SJeremy L Thompson                      "Cannot add field to composite operator.");
692c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
693f04ea552SJeremy L Thompson   if (op->is_immutable)
694f04ea552SJeremy L Thompson     // LCOV_EXCL_START
695f04ea552SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MAJOR,
696f04ea552SJeremy L Thompson                      "Operator cannot be changed after set as immutable");
697f04ea552SJeremy L Thompson   // LCOV_EXCL_STOP
6988b067b84SJed Brown   if (!r)
699c042f62fSJeremy L Thompson     // LCOV_EXCL_START
700e1e9e29dSJed Brown     return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
701c042f62fSJeremy L Thompson                      "ElemRestriction r for field \"%s\" must be non-NULL.",
702d1d35e2fSjeremylt                      field_name);
703c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
7048b067b84SJed Brown   if (!b)
705c042f62fSJeremy L Thompson     // LCOV_EXCL_START
706e1e9e29dSJed Brown     return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
707e15f9bd0SJeremy L Thompson                      "Basis b for field \"%s\" must be non-NULL.",
708d1d35e2fSjeremylt                      field_name);
709c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
7108b067b84SJed Brown   if (!v)
711c042f62fSJeremy L Thompson     // LCOV_EXCL_START
712e1e9e29dSJed Brown     return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
713e15f9bd0SJeremy L Thompson                      "Vector v for field \"%s\" must be non-NULL.",
714d1d35e2fSjeremylt                      field_name);
715c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
71652d6035fSJeremy L Thompson 
717d1d35e2fSjeremylt   CeedInt num_elem;
718d1d35e2fSjeremylt   ierr = CeedElemRestrictionGetNumElements(r, &num_elem); CeedChk(ierr);
719d1d35e2fSjeremylt   if (r != CEED_ELEMRESTRICTION_NONE && op->has_restriction &&
720d1d35e2fSjeremylt       op->num_elem != num_elem)
721c042f62fSJeremy L Thompson     // LCOV_EXCL_START
722e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_DIMENSION,
7231d102b48SJeremy L Thompson                      "ElemRestriction with %d elements incompatible with prior "
724d1d35e2fSjeremylt                      "%d elements", num_elem, op->num_elem);
725c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
726d7b241e6Sjeremylt 
72778464608Sjeremylt   CeedInt num_qpts = 0;
728e15f9bd0SJeremy L Thompson   if (b != CEED_BASIS_COLLOCATED) {
729d1d35e2fSjeremylt     ierr = CeedBasisGetNumQuadraturePoints(b, &num_qpts); CeedChk(ierr);
730d1d35e2fSjeremylt     if (op->num_qpts && op->num_qpts != num_qpts)
731c042f62fSJeremy L Thompson       // LCOV_EXCL_START
732e15f9bd0SJeremy L Thompson       return CeedError(op->ceed, CEED_ERROR_DIMENSION,
733e15f9bd0SJeremy L Thompson                        "Basis with %d quadrature points "
734d1d35e2fSjeremylt                        "incompatible with prior %d points", num_qpts,
735d1d35e2fSjeremylt                        op->num_qpts);
736c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
737d7b241e6Sjeremylt   }
738d1d35e2fSjeremylt   CeedQFunctionField qf_field;
739d1d35e2fSjeremylt   CeedOperatorField *op_field;
7402b104005SJeremy L Thompson   bool is_input = true;
741d1d35e2fSjeremylt   for (CeedInt i=0; i<op->qf->num_input_fields; i++) {
742d1d35e2fSjeremylt     if (!strcmp(field_name, (*op->qf->input_fields[i]).field_name)) {
743d1d35e2fSjeremylt       qf_field = op->qf->input_fields[i];
744d1d35e2fSjeremylt       op_field = &op->input_fields[i];
745d7b241e6Sjeremylt       goto found;
746d7b241e6Sjeremylt     }
747d7b241e6Sjeremylt   }
7482b104005SJeremy L Thompson   is_input = false;
749d1d35e2fSjeremylt   for (CeedInt i=0; i<op->qf->num_output_fields; i++) {
750d1d35e2fSjeremylt     if (!strcmp(field_name, (*op->qf->output_fields[i]).field_name)) {
751d1d35e2fSjeremylt       qf_field = op->qf->output_fields[i];
752d1d35e2fSjeremylt       op_field = &op->output_fields[i];
753d7b241e6Sjeremylt       goto found;
754d7b241e6Sjeremylt     }
755d7b241e6Sjeremylt   }
756c042f62fSJeremy L Thompson   // LCOV_EXCL_START
757e15f9bd0SJeremy L Thompson   return CeedError(op->ceed, CEED_ERROR_INCOMPLETE,
758e15f9bd0SJeremy L Thompson                    "QFunction has no knowledge of field '%s'",
759d1d35e2fSjeremylt                    field_name);
760c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
761d7b241e6Sjeremylt found:
762d1d35e2fSjeremylt   ierr = CeedOperatorCheckField(op->ceed, qf_field, r, b); CeedChk(ierr);
763d1d35e2fSjeremylt   ierr = CeedCalloc(1, op_field); CeedChk(ierr);
764e15f9bd0SJeremy L Thompson 
7652b104005SJeremy L Thompson   if (v == CEED_VECTOR_ACTIVE) {
7662b104005SJeremy L Thompson     CeedSize l_size;
7672b104005SJeremy L Thompson     ierr = CeedElemRestrictionGetLVectorSize(r, &l_size); CeedChk(ierr);
7682b104005SJeremy L Thompson     if (is_input) {
7692b104005SJeremy L Thompson       if (op->input_size == -1) op->input_size = l_size;
7702b104005SJeremy L Thompson       if (l_size != op->input_size)
7712b104005SJeremy L Thompson         // LCOV_EXCL_START
7722b104005SJeremy L Thompson         return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
7732b104005SJeremy L Thompson                          "LVector size %td does not match previous size %td",
7742b104005SJeremy L Thompson                          l_size, op->input_size);
7752b104005SJeremy L Thompson       // LCOV_EXCL_STOP
7762b104005SJeremy L Thompson     } else {
7772b104005SJeremy L Thompson       if (op->output_size == -1) op->output_size = l_size;
7782b104005SJeremy L Thompson       if (l_size != op->output_size)
7792b104005SJeremy L Thompson         // LCOV_EXCL_START
7802b104005SJeremy L Thompson         return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
7812b104005SJeremy L Thompson                          "LVector size %td does not match previous size %td",
7822b104005SJeremy L Thompson                          l_size, op->output_size);
7832b104005SJeremy L Thompson       // LCOV_EXCL_STOP
7842b104005SJeremy L Thompson     }
7852b104005SJeremy L Thompson   }
7862b104005SJeremy L Thompson 
787d1d35e2fSjeremylt   (*op_field)->vec = v;
788e15f9bd0SJeremy L Thompson   if (v != CEED_VECTOR_ACTIVE && v != CEED_VECTOR_NONE) {
7899560d06aSjeremylt     ierr = CeedVectorReference(v); CeedChk(ierr);
790e15f9bd0SJeremy L Thompson   }
791e15f9bd0SJeremy L Thompson 
792d1d35e2fSjeremylt   (*op_field)->elem_restr = r;
7939560d06aSjeremylt   ierr = CeedElemRestrictionReference(r); CeedChk(ierr);
794e15f9bd0SJeremy L Thompson   if (r != CEED_ELEMRESTRICTION_NONE) {
795d1d35e2fSjeremylt     op->num_elem = num_elem;
796d1d35e2fSjeremylt     op->has_restriction = true; // Restriction set, but num_elem may be 0
797e15f9bd0SJeremy L Thompson   }
798d99fa3c5SJeremy L Thompson 
799d1d35e2fSjeremylt   (*op_field)->basis = b;
800e15f9bd0SJeremy L Thompson   if (b != CEED_BASIS_COLLOCATED) {
801cd4dfc48Sjeremylt     if (!op->num_qpts) {
802cd4dfc48Sjeremylt       ierr = CeedOperatorSetNumQuadraturePoints(op, num_qpts); CeedChk(ierr);
803cd4dfc48Sjeremylt     }
8049560d06aSjeremylt     ierr = CeedBasisReference(b); CeedChk(ierr);
805e15f9bd0SJeremy L Thompson   }
806e15f9bd0SJeremy L Thompson 
807d1d35e2fSjeremylt   op->num_fields += 1;
808f7e22acaSJeremy L Thompson   ierr = CeedStringAllocCopy(field_name, (char **)&(*op_field)->field_name);
809f7e22acaSJeremy L Thompson   CeedChk(ierr);
810e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
811d7b241e6Sjeremylt }
812d7b241e6Sjeremylt 
813d7b241e6Sjeremylt /**
81443bbe138SJeremy L Thompson   @brief Get the CeedOperatorFields of a CeedOperator
81543bbe138SJeremy L Thompson 
816f04ea552SJeremy L Thompson   Note: Calling this function asserts that setup is complete
817f04ea552SJeremy L Thompson           and sets the CeedOperator as immutable.
818f04ea552SJeremy L Thompson 
81943bbe138SJeremy L Thompson   @param op                      CeedOperator
820f74ec584SJeremy L Thompson   @param[out] num_input_fields   Variable to store number of input fields
82143bbe138SJeremy L Thompson   @param[out] input_fields       Variable to store input_fields
822f74ec584SJeremy L Thompson   @param[out] num_output_fields  Variable to store number of output fields
82343bbe138SJeremy L Thompson   @param[out] output_fields      Variable to store output_fields
82443bbe138SJeremy L Thompson 
82543bbe138SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
82643bbe138SJeremy L Thompson 
827e9b533fbSJeremy L Thompson   @ref Advanced
82843bbe138SJeremy L Thompson **/
82943bbe138SJeremy L Thompson int CeedOperatorGetFields(CeedOperator op, CeedInt *num_input_fields,
83043bbe138SJeremy L Thompson                           CeedOperatorField **input_fields,
83143bbe138SJeremy L Thompson                           CeedInt *num_output_fields,
83243bbe138SJeremy L Thompson                           CeedOperatorField **output_fields) {
833f04ea552SJeremy L Thompson   int ierr;
834f04ea552SJeremy L Thompson 
835f04ea552SJeremy L Thompson   if (op->is_composite)
83643bbe138SJeremy L Thompson     // LCOV_EXCL_START
83743bbe138SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
83843bbe138SJeremy L Thompson                      "Not defined for composite operator");
83943bbe138SJeremy L Thompson   // LCOV_EXCL_STOP
840f04ea552SJeremy L Thompson   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
84143bbe138SJeremy L Thompson 
84243bbe138SJeremy L Thompson   if (num_input_fields) *num_input_fields = op->qf->num_input_fields;
84343bbe138SJeremy L Thompson   if (input_fields) *input_fields = op->input_fields;
84443bbe138SJeremy L Thompson   if (num_output_fields) *num_output_fields = op->qf->num_output_fields;
84543bbe138SJeremy L Thompson   if (output_fields) *output_fields = op->output_fields;
84643bbe138SJeremy L Thompson   return CEED_ERROR_SUCCESS;
84743bbe138SJeremy L Thompson }
84843bbe138SJeremy L Thompson 
84943bbe138SJeremy L Thompson /**
85028567f8fSJeremy L Thompson   @brief Get the name of a CeedOperatorField
85128567f8fSJeremy L Thompson 
85228567f8fSJeremy L Thompson   @param op_field         CeedOperatorField
85328567f8fSJeremy L Thompson   @param[out] field_name  Variable to store the field name
85428567f8fSJeremy L Thompson 
85528567f8fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
85628567f8fSJeremy L Thompson 
857e9b533fbSJeremy L Thompson   @ref Advanced
85828567f8fSJeremy L Thompson **/
85928567f8fSJeremy L Thompson int CeedOperatorFieldGetName(CeedOperatorField op_field, char **field_name) {
86028567f8fSJeremy L Thompson   *field_name = (char *)op_field->field_name;
86128567f8fSJeremy L Thompson   return CEED_ERROR_SUCCESS;
86228567f8fSJeremy L Thompson }
86328567f8fSJeremy L Thompson 
86428567f8fSJeremy L Thompson /**
86543bbe138SJeremy L Thompson   @brief Get the CeedElemRestriction of a CeedOperatorField
86643bbe138SJeremy L Thompson 
86743bbe138SJeremy L Thompson   @param op_field   CeedOperatorField
86843bbe138SJeremy L Thompson   @param[out] rstr  Variable to store CeedElemRestriction
86943bbe138SJeremy L Thompson 
87043bbe138SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
87143bbe138SJeremy L Thompson 
872e9b533fbSJeremy L Thompson   @ref Advanced
87343bbe138SJeremy L Thompson **/
87443bbe138SJeremy L Thompson int CeedOperatorFieldGetElemRestriction(CeedOperatorField op_field,
87543bbe138SJeremy L Thompson                                         CeedElemRestriction *rstr) {
87643bbe138SJeremy L Thompson   *rstr = op_field->elem_restr;
87743bbe138SJeremy L Thompson   return CEED_ERROR_SUCCESS;
87843bbe138SJeremy L Thompson }
87943bbe138SJeremy L Thompson 
88043bbe138SJeremy L Thompson /**
88143bbe138SJeremy L Thompson   @brief Get the CeedBasis of a CeedOperatorField
88243bbe138SJeremy L Thompson 
88343bbe138SJeremy L Thompson   @param op_field    CeedOperatorField
88443bbe138SJeremy L Thompson   @param[out] basis  Variable to store CeedBasis
88543bbe138SJeremy L Thompson 
88643bbe138SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
88743bbe138SJeremy L Thompson 
888e9b533fbSJeremy L Thompson   @ref Advanced
88943bbe138SJeremy L Thompson **/
89043bbe138SJeremy L Thompson int CeedOperatorFieldGetBasis(CeedOperatorField op_field, CeedBasis *basis) {
89143bbe138SJeremy L Thompson   *basis = op_field->basis;
89243bbe138SJeremy L Thompson   return CEED_ERROR_SUCCESS;
89343bbe138SJeremy L Thompson }
89443bbe138SJeremy L Thompson 
89543bbe138SJeremy L Thompson /**
89643bbe138SJeremy L Thompson   @brief Get the CeedVector of a CeedOperatorField
89743bbe138SJeremy L Thompson 
89843bbe138SJeremy L Thompson   @param op_field  CeedOperatorField
89943bbe138SJeremy L Thompson   @param[out] vec  Variable to store CeedVector
90043bbe138SJeremy L Thompson 
90143bbe138SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
90243bbe138SJeremy L Thompson 
903e9b533fbSJeremy L Thompson   @ref Advanced
90443bbe138SJeremy L Thompson **/
90543bbe138SJeremy L Thompson int CeedOperatorFieldGetVector(CeedOperatorField op_field, CeedVector *vec) {
90643bbe138SJeremy L Thompson   *vec = op_field->vec;
90743bbe138SJeremy L Thompson   return CEED_ERROR_SUCCESS;
90843bbe138SJeremy L Thompson }
90943bbe138SJeremy L Thompson 
91043bbe138SJeremy L Thompson /**
91152d6035fSJeremy L Thompson   @brief Add a sub-operator to a composite CeedOperator
912288c0443SJeremy L Thompson 
913d1d35e2fSjeremylt   @param[out] composite_op  Composite CeedOperator
914d1d35e2fSjeremylt   @param      sub_op        Sub-operator CeedOperator
91552d6035fSJeremy L Thompson 
91652d6035fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
91752d6035fSJeremy L Thompson 
9187a982d89SJeremy L. Thompson   @ref User
91952d6035fSJeremy L Thompson  */
920d1d35e2fSjeremylt int CeedCompositeOperatorAddSub(CeedOperator composite_op,
921d1d35e2fSjeremylt                                 CeedOperator sub_op) {
92234359f16Sjeremylt   int ierr;
92334359f16Sjeremylt 
924f04ea552SJeremy L Thompson   if (!composite_op->is_composite)
925c042f62fSJeremy L Thompson     // LCOV_EXCL_START
926d1d35e2fSjeremylt     return CeedError(composite_op->ceed, CEED_ERROR_MINOR,
927e2f04181SAndrew T. Barker                      "CeedOperator is not a composite operator");
928c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
92952d6035fSJeremy L Thompson 
930d1d35e2fSjeremylt   if (composite_op->num_suboperators == CEED_COMPOSITE_MAX)
931c042f62fSJeremy L Thompson     // LCOV_EXCL_START
932d1d35e2fSjeremylt     return CeedError(composite_op->ceed, CEED_ERROR_UNSUPPORTED,
9332b104005SJeremy L Thompson                      "Cannot add additional sub-operators");
934c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
935f04ea552SJeremy L Thompson   if (composite_op->is_immutable)
936f04ea552SJeremy L Thompson     // LCOV_EXCL_START
937f04ea552SJeremy L Thompson     return CeedError(composite_op->ceed, CEED_ERROR_MAJOR,
938f04ea552SJeremy L Thompson                      "Operator cannot be changed after set as immutable");
939f04ea552SJeremy L Thompson   // LCOV_EXCL_STOP
94052d6035fSJeremy L Thompson 
9412b104005SJeremy L Thompson   {
9422b104005SJeremy L Thompson     CeedSize input_size, output_size;
9432b104005SJeremy L Thompson     ierr = CeedOperatorGetActiveVectorLengths(sub_op, &input_size, &output_size);
9442b104005SJeremy L Thompson     CeedChk(ierr);
9452b104005SJeremy L Thompson     if (composite_op->input_size == -1) composite_op->input_size = input_size;
9462b104005SJeremy L Thompson     if (composite_op->output_size == -1) composite_op->output_size = output_size;
9472b104005SJeremy L Thompson     // Note, a size of -1 means no active vector restriction set, so no incompatibility
9482b104005SJeremy L Thompson     if ((input_size != -1 && input_size != composite_op->input_size) ||
9492b104005SJeremy L Thompson         (output_size != -1 && output_size != composite_op->output_size))
9502b104005SJeremy L Thompson       // LCOV_EXCL_START
9512b104005SJeremy L Thompson       return CeedError(composite_op->ceed, CEED_ERROR_MAJOR,
9522b104005SJeremy L Thompson                        "Sub-operators must have compatible dimensions; "
9532b104005SJeremy L Thompson                        "composite operator of shape (%td, %td) not compatible with "
9542b104005SJeremy L Thompson                        "sub-operator of shape (%td, %td)",
9552b104005SJeremy L Thompson                        composite_op->input_size, composite_op->output_size, input_size, output_size);
9562b104005SJeremy L Thompson     // LCOV_EXCL_STOP
9572b104005SJeremy L Thompson   }
9582b104005SJeremy L Thompson 
959d1d35e2fSjeremylt   composite_op->sub_operators[composite_op->num_suboperators] = sub_op;
9609560d06aSjeremylt   ierr = CeedOperatorReference(sub_op); CeedChk(ierr);
961d1d35e2fSjeremylt   composite_op->num_suboperators++;
962e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
96352d6035fSJeremy L Thompson }
96452d6035fSJeremy L Thompson 
96552d6035fSJeremy L Thompson /**
9664db537f9SJeremy L Thompson   @brief Check if a CeedOperator is ready to be used.
9674db537f9SJeremy L Thompson 
9684db537f9SJeremy L Thompson   @param[in] op  CeedOperator to check
9694db537f9SJeremy L Thompson 
9704db537f9SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
9714db537f9SJeremy L Thompson 
9724db537f9SJeremy L Thompson   @ref User
9734db537f9SJeremy L Thompson **/
9744db537f9SJeremy L Thompson int CeedOperatorCheckReady(CeedOperator op) {
9754db537f9SJeremy L Thompson   int ierr;
9764db537f9SJeremy L Thompson   Ceed ceed;
9774db537f9SJeremy L Thompson   ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr);
9784db537f9SJeremy L Thompson 
9794db537f9SJeremy L Thompson   if (op->is_interface_setup)
9804db537f9SJeremy L Thompson     return CEED_ERROR_SUCCESS;
9814db537f9SJeremy L Thompson 
9824db537f9SJeremy L Thompson   CeedQFunction qf = op->qf;
9834db537f9SJeremy L Thompson   if (op->is_composite) {
9844db537f9SJeremy L Thompson     if (!op->num_suboperators)
9854db537f9SJeremy L Thompson       // LCOV_EXCL_START
9864db537f9SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_INCOMPLETE, "No sub_operators set");
9874db537f9SJeremy L Thompson     // LCOV_EXCL_STOP
9884db537f9SJeremy L Thompson     for (CeedInt i = 0; i < op->num_suboperators; i++) {
9894db537f9SJeremy L Thompson       ierr = CeedOperatorCheckReady(op->sub_operators[i]); CeedChk(ierr);
9904db537f9SJeremy L Thompson     }
9912b104005SJeremy L Thompson     // Sub-operators could be modified after adding to composite operator
9922b104005SJeremy L Thompson     // Need to verify no lvec incompatibility from any changes
9932b104005SJeremy L Thompson     CeedSize input_size, output_size;
9942b104005SJeremy L Thompson     ierr = CeedOperatorGetActiveVectorLengths(op, &input_size, &output_size);
9952b104005SJeremy L Thompson     CeedChk(ierr);
9964db537f9SJeremy L Thompson   } else {
9974db537f9SJeremy L Thompson     if (op->num_fields == 0)
9984db537f9SJeremy L Thompson       // LCOV_EXCL_START
9994db537f9SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_INCOMPLETE, "No operator fields set");
10004db537f9SJeremy L Thompson     // LCOV_EXCL_STOP
10014db537f9SJeremy L Thompson     if (op->num_fields < qf->num_input_fields + qf->num_output_fields)
10024db537f9SJeremy L Thompson       // LCOV_EXCL_START
10034db537f9SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_INCOMPLETE, "Not all operator fields set");
10044db537f9SJeremy L Thompson     // LCOV_EXCL_STOP
10054db537f9SJeremy L Thompson     if (!op->has_restriction)
10064db537f9SJeremy L Thompson       // LCOV_EXCL_START
10074db537f9SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_INCOMPLETE,
10084db537f9SJeremy L Thompson                        "At least one restriction required");
10094db537f9SJeremy L Thompson     // LCOV_EXCL_STOP
10104db537f9SJeremy L Thompson     if (op->num_qpts == 0)
10114db537f9SJeremy L Thompson       // LCOV_EXCL_START
10124db537f9SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_INCOMPLETE,
10134db537f9SJeremy L Thompson                        "At least one non-collocated basis is required "
10144db537f9SJeremy L Thompson                        "or the number of quadrature points must be set");
10154db537f9SJeremy L Thompson     // LCOV_EXCL_STOP
10164db537f9SJeremy L Thompson   }
10174db537f9SJeremy L Thompson 
10184db537f9SJeremy L Thompson   // Flag as immutable and ready
10194db537f9SJeremy L Thompson   op->is_interface_setup = true;
10204db537f9SJeremy L Thompson   if (op->qf && op->qf != CEED_QFUNCTION_NONE)
10214db537f9SJeremy L Thompson     // LCOV_EXCL_START
10224db537f9SJeremy L Thompson     op->qf->is_immutable = true;
10234db537f9SJeremy L Thompson   // LCOV_EXCL_STOP
10244db537f9SJeremy L Thompson   if (op->dqf && op->dqf != CEED_QFUNCTION_NONE)
10254db537f9SJeremy L Thompson     // LCOV_EXCL_START
10264db537f9SJeremy L Thompson     op->dqf->is_immutable = true;
10274db537f9SJeremy L Thompson   // LCOV_EXCL_STOP
10284db537f9SJeremy L Thompson   if (op->dqfT && op->dqfT != CEED_QFUNCTION_NONE)
10294db537f9SJeremy L Thompson     // LCOV_EXCL_START
10304db537f9SJeremy L Thompson     op->dqfT->is_immutable = true;
10314db537f9SJeremy L Thompson   // LCOV_EXCL_STOP
10324db537f9SJeremy L Thompson   return CEED_ERROR_SUCCESS;
10334db537f9SJeremy L Thompson }
10344db537f9SJeremy L Thompson 
10354db537f9SJeremy L Thompson /**
1036c9366a6bSJeremy L Thompson   @brief Get vector lengths for the active input and/or output vectors of a CeedOperator.
1037c9366a6bSJeremy L Thompson            Note: Lengths of -1 indicate that the CeedOperator does not have an
1038c9366a6bSJeremy L Thompson            active input and/or output.
1039c9366a6bSJeremy L Thompson 
1040c9366a6bSJeremy L Thompson   @param[in] op           CeedOperator
1041c9366a6bSJeremy L Thompson   @param[out] input_size  Variable to store active input vector length, or NULL
1042c9366a6bSJeremy L Thompson   @param[out] output_size Variable to store active output vector length, or NULL
1043c9366a6bSJeremy L Thompson 
1044c9366a6bSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1045c9366a6bSJeremy L Thompson 
1046c9366a6bSJeremy L Thompson   @ref User
1047c9366a6bSJeremy L Thompson **/
1048c9366a6bSJeremy L Thompson int CeedOperatorGetActiveVectorLengths(CeedOperator op, CeedSize *input_size,
1049c9366a6bSJeremy L Thompson                                        CeedSize *output_size) {
1050c9366a6bSJeremy L Thompson   int ierr;
1051c9366a6bSJeremy L Thompson   bool is_composite;
1052c9366a6bSJeremy L Thompson 
10532b104005SJeremy L Thompson   if (input_size) *input_size = op->input_size;
10542b104005SJeremy L Thompson   if (output_size) *output_size = op->output_size;
1055c9366a6bSJeremy L Thompson 
1056c9366a6bSJeremy L Thompson   ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr);
10572b104005SJeremy L Thompson   if (is_composite && (op->input_size == -1 || op->output_size == -1)) {
1058c9366a6bSJeremy L Thompson     for (CeedInt i = 0; i < op->num_suboperators; i++) {
1059c9366a6bSJeremy L Thompson       CeedSize sub_input_size, sub_output_size;
1060c9366a6bSJeremy L Thompson       ierr = CeedOperatorGetActiveVectorLengths(op->sub_operators[i],
10612b104005SJeremy L Thompson              &sub_input_size, &sub_output_size); CeedChk(ierr);
10622b104005SJeremy L Thompson       if (op->input_size == -1) op->input_size = sub_input_size;
10632b104005SJeremy L Thompson       if (op->output_size == -1) op->output_size = sub_output_size;
10642b104005SJeremy L Thompson       // Note, a size of -1 means no active vector restriction set, so no incompatibility
10652b104005SJeremy L Thompson       if ((sub_input_size != -1 && sub_input_size != op->input_size) ||
10662b104005SJeremy L Thompson           (sub_output_size != -1 && sub_output_size != op->output_size))
10672b104005SJeremy L Thompson         // LCOV_EXCL_START
10682b104005SJeremy L Thompson         return CeedError(op->ceed, CEED_ERROR_MAJOR,
10692b104005SJeremy L Thompson                          "Sub-operators must have compatible dimensions; "
10702b104005SJeremy L Thompson                          "composite operator of shape (%td, %td) not compatible with "
10712b104005SJeremy L Thompson                          "sub-operator of shape (%td, %td)",
10722b104005SJeremy L Thompson                          op->input_size, op->output_size, input_size, output_size);
10732b104005SJeremy L Thompson       // LCOV_EXCL_STOP
1074c9366a6bSJeremy L Thompson     }
1075c9366a6bSJeremy L Thompson   }
1076c9366a6bSJeremy L Thompson 
1077c9366a6bSJeremy L Thompson   return CEED_ERROR_SUCCESS;
1078c9366a6bSJeremy L Thompson }
1079c9366a6bSJeremy L Thompson 
1080c9366a6bSJeremy L Thompson /**
1081beecbf24SJeremy L Thompson   @brief Set reuse of CeedQFunction data in CeedOperatorLinearAssemble* functions.
1082beecbf24SJeremy L Thompson            When `reuse_assembly_data = false` (default), the CeedQFunction associated
1083beecbf24SJeremy L Thompson            with this CeedOperator is re-assembled every time a `CeedOperatorLinearAssemble*`
1084beecbf24SJeremy L Thompson            function is called.
1085beecbf24SJeremy L Thompson            When `reuse_assembly_data = true`, the CeedQFunction associated with
1086beecbf24SJeremy L Thompson            this CeedOperator is reused between calls to
1087beecbf24SJeremy L Thompson            `CeedOperatorSetQFunctionAssemblyDataUpdated`.
10888b919e6bSJeremy L Thompson 
1089beecbf24SJeremy L Thompson   @param[in] op                  CeedOperator
1090beecbf24SJeremy L Thompson   @param[in] reuse_assembly_data Boolean flag setting assembly data reuse
10918b919e6bSJeremy L Thompson 
10928b919e6bSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
10938b919e6bSJeremy L Thompson 
10948b919e6bSJeremy L Thompson   @ref Advanced
10958b919e6bSJeremy L Thompson **/
1096beecbf24SJeremy L Thompson int CeedOperatorSetQFunctionAssemblyReuse(CeedOperator op,
1097beecbf24SJeremy L Thompson     bool reuse_assembly_data) {
10988b919e6bSJeremy L Thompson   int ierr;
10998b919e6bSJeremy L Thompson   bool is_composite;
11008b919e6bSJeremy L Thompson 
11018b919e6bSJeremy L Thompson   ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr);
11028b919e6bSJeremy L Thompson   if (is_composite) {
11038b919e6bSJeremy L Thompson     for (CeedInt i = 0; i < op->num_suboperators; i++) {
1104beecbf24SJeremy L Thompson       ierr = CeedOperatorSetQFunctionAssemblyReuse(op->sub_operators[i],
1105beecbf24SJeremy L Thompson              reuse_assembly_data); CeedChk(ierr);
11068b919e6bSJeremy L Thompson     }
11078b919e6bSJeremy L Thompson   } else {
1108beecbf24SJeremy L Thompson     ierr = CeedQFunctionAssemblyDataSetReuse(op->qf_assembled, reuse_assembly_data);
1109beecbf24SJeremy L Thompson     CeedChk(ierr);
1110beecbf24SJeremy L Thompson   }
1111beecbf24SJeremy L Thompson 
1112beecbf24SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1113beecbf24SJeremy L Thompson }
1114beecbf24SJeremy L Thompson 
1115beecbf24SJeremy L Thompson /**
1116beecbf24SJeremy L Thompson   @brief Mark CeedQFunction data as updated and the CeedQFunction as requiring re-assembly.
1117beecbf24SJeremy L Thompson 
1118beecbf24SJeremy L Thompson   @param[in] op                CeedOperator
11196e15d496SJeremy L Thompson   @param[in] needs_data_update Boolean flag setting assembly data reuse
1120beecbf24SJeremy L Thompson 
1121beecbf24SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1122beecbf24SJeremy L Thompson 
1123beecbf24SJeremy L Thompson   @ref Advanced
1124beecbf24SJeremy L Thompson **/
1125beecbf24SJeremy L Thompson int CeedOperatorSetQFunctionAssemblyDataUpdateNeeded(CeedOperator op,
1126beecbf24SJeremy L Thompson     bool needs_data_update) {
1127beecbf24SJeremy L Thompson   int ierr;
1128beecbf24SJeremy L Thompson   bool is_composite;
1129beecbf24SJeremy L Thompson 
1130beecbf24SJeremy L Thompson   ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr);
1131beecbf24SJeremy L Thompson   if (is_composite) {
1132beecbf24SJeremy L Thompson     for (CeedInt i = 0; i < op->num_suboperators; i++) {
1133beecbf24SJeremy L Thompson       ierr = CeedOperatorSetQFunctionAssemblyDataUpdateNeeded(op->sub_operators[i],
1134beecbf24SJeremy L Thompson              needs_data_update); CeedChk(ierr);
1135beecbf24SJeremy L Thompson     }
1136beecbf24SJeremy L Thompson   } else {
1137beecbf24SJeremy L Thompson     ierr = CeedQFunctionAssemblyDataSetUpdateNeeded(op->qf_assembled,
1138beecbf24SJeremy L Thompson            needs_data_update);
11398b919e6bSJeremy L Thompson     CeedChk(ierr);
11408b919e6bSJeremy L Thompson   }
11418b919e6bSJeremy L Thompson 
11428b919e6bSJeremy L Thompson   return CEED_ERROR_SUCCESS;
11438b919e6bSJeremy L Thompson }
11448b919e6bSJeremy L Thompson 
11458b919e6bSJeremy L Thompson /**
1146cd4dfc48Sjeremylt   @brief Set the number of quadrature points associated with a CeedOperator.
1147cd4dfc48Sjeremylt            This should be used when creating a CeedOperator where every
1148cd4dfc48Sjeremylt            field has a collocated basis. This function cannot be used for
1149cd4dfc48Sjeremylt            composite CeedOperators.
1150cd4dfc48Sjeremylt 
1151cd4dfc48Sjeremylt   @param op        CeedOperator
1152cd4dfc48Sjeremylt   @param num_qpts  Number of quadrature points to set
1153cd4dfc48Sjeremylt 
1154cd4dfc48Sjeremylt   @return An error code: 0 - success, otherwise - failure
1155cd4dfc48Sjeremylt 
1156e9b533fbSJeremy L Thompson   @ref Advanced
1157cd4dfc48Sjeremylt **/
1158cd4dfc48Sjeremylt int CeedOperatorSetNumQuadraturePoints(CeedOperator op, CeedInt num_qpts) {
1159f04ea552SJeremy L Thompson   if (op->is_composite)
1160cd4dfc48Sjeremylt     // LCOV_EXCL_START
1161cd4dfc48Sjeremylt     return CeedError(op->ceed, CEED_ERROR_MINOR,
1162cd4dfc48Sjeremylt                      "Not defined for composite operator");
1163cd4dfc48Sjeremylt   // LCOV_EXCL_STOP
1164cd4dfc48Sjeremylt   if (op->num_qpts)
1165cd4dfc48Sjeremylt     // LCOV_EXCL_START
1166cd4dfc48Sjeremylt     return CeedError(op->ceed, CEED_ERROR_MINOR,
1167cd4dfc48Sjeremylt                      "Number of quadrature points already defined");
1168cd4dfc48Sjeremylt   // LCOV_EXCL_STOP
1169f04ea552SJeremy L Thompson   if (op->is_immutable)
1170f04ea552SJeremy L Thompson     // LCOV_EXCL_START
1171f04ea552SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MAJOR,
1172f04ea552SJeremy L Thompson                      "Operator cannot be changed after set as immutable");
1173f04ea552SJeremy L Thompson   // LCOV_EXCL_STOP
1174cd4dfc48Sjeremylt 
1175cd4dfc48Sjeremylt   op->num_qpts = num_qpts;
1176cd4dfc48Sjeremylt   return CEED_ERROR_SUCCESS;
1177cd4dfc48Sjeremylt }
1178cd4dfc48Sjeremylt 
1179cd4dfc48Sjeremylt /**
1180ea6b5821SJeremy L Thompson   @brief Set name of CeedOperator for CeedOperatorView output
1181ea6b5821SJeremy L Thompson 
1182ea6b5821SJeremy L Thompson   @param op    CeedOperator
1183ea6b5821SJeremy L Thompson   @param name  Name to set, or NULL to remove previously set name
1184ea6b5821SJeremy L Thompson 
1185ea6b5821SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1186ea6b5821SJeremy L Thompson 
1187ea6b5821SJeremy L Thompson   @ref User
1188ea6b5821SJeremy L Thompson **/
1189ea6b5821SJeremy L Thompson int CeedOperatorSetName(CeedOperator op, const char *name) {
1190ea6b5821SJeremy L Thompson   int ierr;
1191ea6b5821SJeremy L Thompson   char *name_copy;
1192ea6b5821SJeremy L Thompson   size_t name_len = name ? strlen(name) : 0;
1193ea6b5821SJeremy L Thompson 
1194ea6b5821SJeremy L Thompson   ierr = CeedFree(&op->name); CeedChk(ierr);
1195ea6b5821SJeremy L Thompson   if (name_len > 0) {
1196ea6b5821SJeremy L Thompson     ierr = CeedCalloc(name_len + 1, &name_copy); CeedChk(ierr);
1197ea6b5821SJeremy L Thompson     memcpy(name_copy, name, name_len);
1198ea6b5821SJeremy L Thompson     op->name = name_copy;
1199ea6b5821SJeremy L Thompson   }
1200ea6b5821SJeremy L Thompson 
1201ea6b5821SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1202ea6b5821SJeremy L Thompson }
1203ea6b5821SJeremy L Thompson 
1204ea6b5821SJeremy L Thompson /**
12057a982d89SJeremy L. Thompson   @brief View a CeedOperator
12067a982d89SJeremy L. Thompson 
12077a982d89SJeremy L. Thompson   @param[in] op      CeedOperator to view
12087a982d89SJeremy L. Thompson   @param[in] stream  Stream to write; typically stdout/stderr or a file
12097a982d89SJeremy L. Thompson 
12107a982d89SJeremy L. Thompson   @return Error code: 0 - success, otherwise - failure
12117a982d89SJeremy L. Thompson 
12127a982d89SJeremy L. Thompson   @ref User
12137a982d89SJeremy L. Thompson **/
12147a982d89SJeremy L. Thompson int CeedOperatorView(CeedOperator op, FILE *stream) {
12157a982d89SJeremy L. Thompson   int ierr;
1216ea6b5821SJeremy L Thompson   bool has_name = op->name;
12177a982d89SJeremy L. Thompson 
1218f04ea552SJeremy L Thompson   if (op->is_composite) {
1219ea6b5821SJeremy L Thompson     fprintf(stream, "Composite CeedOperator%s%s\n",
1220ea6b5821SJeremy L Thompson             has_name ? " - " : "", has_name ? op->name : "");
12217a982d89SJeremy L. Thompson 
1222d1d35e2fSjeremylt     for (CeedInt i=0; i<op->num_suboperators; i++) {
1223ea6b5821SJeremy L Thompson       has_name = op->sub_operators[i]->name;
1224ea6b5821SJeremy L Thompson       fprintf(stream, "  SubOperator %d%s%s:\n", i,
1225ea6b5821SJeremy L Thompson               has_name ? " - " : "",
1226ea6b5821SJeremy L Thompson               has_name ? op->sub_operators[i]->name : "");
1227d1d35e2fSjeremylt       ierr = CeedOperatorSingleView(op->sub_operators[i], 1, stream);
12287a982d89SJeremy L. Thompson       CeedChk(ierr);
12297a982d89SJeremy L. Thompson     }
12307a982d89SJeremy L. Thompson   } else {
1231ea6b5821SJeremy L Thompson     fprintf(stream, "CeedOperator%s%s\n",
1232ea6b5821SJeremy L Thompson             has_name ? " - " : "", has_name ? op->name : "");
12337a982d89SJeremy L. Thompson     ierr = CeedOperatorSingleView(op, 0, stream); CeedChk(ierr);
12347a982d89SJeremy L. Thompson   }
1235e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
12367a982d89SJeremy L. Thompson }
12373bd813ffSjeremylt 
12383bd813ffSjeremylt /**
1239b7c9bbdaSJeremy L Thompson   @brief Get the Ceed associated with a CeedOperator
1240b7c9bbdaSJeremy L Thompson 
1241b7c9bbdaSJeremy L Thompson   @param op         CeedOperator
1242b7c9bbdaSJeremy L Thompson   @param[out] ceed  Variable to store Ceed
1243b7c9bbdaSJeremy L Thompson 
1244b7c9bbdaSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1245b7c9bbdaSJeremy L Thompson 
1246b7c9bbdaSJeremy L Thompson   @ref Advanced
1247b7c9bbdaSJeremy L Thompson **/
1248b7c9bbdaSJeremy L Thompson int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) {
1249b7c9bbdaSJeremy L Thompson   *ceed = op->ceed;
1250b7c9bbdaSJeremy L Thompson   return CEED_ERROR_SUCCESS;
1251b7c9bbdaSJeremy L Thompson }
1252b7c9bbdaSJeremy L Thompson 
1253b7c9bbdaSJeremy L Thompson /**
1254b7c9bbdaSJeremy L Thompson   @brief Get the number of elements associated with a CeedOperator
1255b7c9bbdaSJeremy L Thompson 
1256b7c9bbdaSJeremy L Thompson   @param op             CeedOperator
1257b7c9bbdaSJeremy L Thompson   @param[out] num_elem  Variable to store number of elements
1258b7c9bbdaSJeremy L Thompson 
1259b7c9bbdaSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1260b7c9bbdaSJeremy L Thompson 
1261b7c9bbdaSJeremy L Thompson   @ref Advanced
1262b7c9bbdaSJeremy L Thompson **/
1263b7c9bbdaSJeremy L Thompson int CeedOperatorGetNumElements(CeedOperator op, CeedInt *num_elem) {
1264b7c9bbdaSJeremy L Thompson   if (op->is_composite)
1265b7c9bbdaSJeremy L Thompson     // LCOV_EXCL_START
1266b7c9bbdaSJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
1267b7c9bbdaSJeremy L Thompson                      "Not defined for composite operator");
1268b7c9bbdaSJeremy L Thompson   // LCOV_EXCL_STOP
1269b7c9bbdaSJeremy L Thompson 
1270b7c9bbdaSJeremy L Thompson   *num_elem = op->num_elem;
1271b7c9bbdaSJeremy L Thompson   return CEED_ERROR_SUCCESS;
1272b7c9bbdaSJeremy L Thompson }
1273b7c9bbdaSJeremy L Thompson 
1274b7c9bbdaSJeremy L Thompson /**
1275b7c9bbdaSJeremy L Thompson   @brief Get the number of quadrature points associated with a CeedOperator
1276b7c9bbdaSJeremy L Thompson 
1277b7c9bbdaSJeremy L Thompson   @param op             CeedOperator
1278b7c9bbdaSJeremy L Thompson   @param[out] num_qpts  Variable to store vector number of quadrature points
1279b7c9bbdaSJeremy L Thompson 
1280b7c9bbdaSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1281b7c9bbdaSJeremy L Thompson 
1282b7c9bbdaSJeremy L Thompson   @ref Advanced
1283b7c9bbdaSJeremy L Thompson **/
1284b7c9bbdaSJeremy L Thompson int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *num_qpts) {
1285b7c9bbdaSJeremy L Thompson   if (op->is_composite)
1286b7c9bbdaSJeremy L Thompson     // LCOV_EXCL_START
1287b7c9bbdaSJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
1288b7c9bbdaSJeremy L Thompson                      "Not defined for composite operator");
1289b7c9bbdaSJeremy L Thompson   // LCOV_EXCL_STOP
1290b7c9bbdaSJeremy L Thompson 
1291b7c9bbdaSJeremy L Thompson   *num_qpts = op->num_qpts;
1292b7c9bbdaSJeremy L Thompson   return CEED_ERROR_SUCCESS;
1293b7c9bbdaSJeremy L Thompson }
1294b7c9bbdaSJeremy L Thompson 
1295b7c9bbdaSJeremy L Thompson /**
12966e15d496SJeremy L Thompson   @brief Estimate number of FLOPs required to apply CeedOperator on the active vector
12976e15d496SJeremy L Thompson 
12986e15d496SJeremy L Thompson   @param op    Operator to estimate FLOPs for
12996e15d496SJeremy L Thompson   @param flops Address of variable to hold FLOPs estimate
13006e15d496SJeremy L Thompson 
13016e15d496SJeremy L Thompson   @ref Backend
13026e15d496SJeremy L Thompson **/
13039d36ca50SJeremy L Thompson int CeedOperatorGetFlopsEstimate(CeedOperator op, CeedSize *flops) {
13046e15d496SJeremy L Thompson   int ierr;
13056e15d496SJeremy L Thompson   bool is_composite;
13066e15d496SJeremy L Thompson   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
13076e15d496SJeremy L Thompson 
13086e15d496SJeremy L Thompson   *flops = 0;
13096e15d496SJeremy L Thompson   ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr);
13106e15d496SJeremy L Thompson   if (is_composite) {
13116e15d496SJeremy L Thompson     CeedInt num_suboperators;
13126e15d496SJeremy L Thompson     ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr);
13136e15d496SJeremy L Thompson     CeedOperator *sub_operators;
13146e15d496SJeremy L Thompson     ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr);
13156e15d496SJeremy L Thompson 
13166e15d496SJeremy L Thompson     // FLOPs for each suboperator
13176e15d496SJeremy L Thompson     for (CeedInt i = 0; i < num_suboperators; i++) {
13189d36ca50SJeremy L Thompson       CeedSize suboperator_flops;
13196e15d496SJeremy L Thompson       ierr = CeedOperatorGetFlopsEstimate(sub_operators[i], &suboperator_flops);
13206e15d496SJeremy L Thompson       CeedChk(ierr);
13216e15d496SJeremy L Thompson       *flops += suboperator_flops;
13226e15d496SJeremy L Thompson     }
13236e15d496SJeremy L Thompson   } else {
13246e15d496SJeremy L Thompson     CeedInt num_input_fields, num_output_fields;
13256e15d496SJeremy L Thompson     CeedOperatorField *input_fields, *output_fields;
13266e15d496SJeremy L Thompson 
13276e15d496SJeremy L Thompson     ierr = CeedOperatorGetFields(op, &num_input_fields, &input_fields,
13286e15d496SJeremy L Thompson                                  &num_output_fields, &output_fields); CeedChk(ierr);
13296e15d496SJeremy L Thompson 
13306e15d496SJeremy L Thompson     CeedInt num_elem = 0;
13316e15d496SJeremy L Thompson     ierr = CeedOperatorGetNumElements(op, &num_elem); CeedChk(ierr);
13326e15d496SJeremy L Thompson     // Input FLOPs
13336e15d496SJeremy L Thompson     for (CeedInt i = 0; i < num_input_fields; i++) {
13346e15d496SJeremy L Thompson       if (input_fields[i]->vec == CEED_VECTOR_ACTIVE) {
13359d36ca50SJeremy L Thompson         CeedSize restr_flops, basis_flops;
13366e15d496SJeremy L Thompson 
13376e15d496SJeremy L Thompson         ierr = CeedElemRestrictionGetFlopsEstimate(input_fields[i]->elem_restr,
13386e15d496SJeremy L Thompson                CEED_NOTRANSPOSE, &restr_flops); CeedChk(ierr);
13396e15d496SJeremy L Thompson         *flops += restr_flops;
13406e15d496SJeremy L Thompson         ierr = CeedBasisGetFlopsEstimate(input_fields[i]->basis, CEED_NOTRANSPOSE,
13416e15d496SJeremy L Thompson                                          op->qf->input_fields[i]->eval_mode, &basis_flops); CeedChk(ierr);
13426e15d496SJeremy L Thompson         *flops += basis_flops * num_elem;
13436e15d496SJeremy L Thompson       }
13446e15d496SJeremy L Thompson     }
13456e15d496SJeremy L Thompson     // QF FLOPs
13469d36ca50SJeremy L Thompson     CeedInt num_qpts;
13479d36ca50SJeremy L Thompson     CeedSize qf_flops;
13486e15d496SJeremy L Thompson     ierr = CeedOperatorGetNumQuadraturePoints(op, &num_qpts); CeedChk(ierr);
13496e15d496SJeremy L Thompson     ierr = CeedQFunctionGetFlopsEstimate(op->qf, &qf_flops); CeedChk(ierr);
13506e15d496SJeremy L Thompson     *flops += num_elem * num_qpts * qf_flops;
13516e15d496SJeremy L Thompson     // Output FLOPs
13526e15d496SJeremy L Thompson     for (CeedInt i = 0; i < num_output_fields; i++) {
13536e15d496SJeremy L Thompson       if (output_fields[i]->vec == CEED_VECTOR_ACTIVE) {
13549d36ca50SJeremy L Thompson         CeedSize restr_flops, basis_flops;
13556e15d496SJeremy L Thompson 
13566e15d496SJeremy L Thompson         ierr = CeedElemRestrictionGetFlopsEstimate(output_fields[i]->elem_restr,
13576e15d496SJeremy L Thompson                CEED_TRANSPOSE, &restr_flops); CeedChk(ierr);
13586e15d496SJeremy L Thompson         *flops += restr_flops;
13596e15d496SJeremy L Thompson         ierr = CeedBasisGetFlopsEstimate(output_fields[i]->basis, CEED_TRANSPOSE,
13606e15d496SJeremy L Thompson                                          op->qf->output_fields[i]->eval_mode, &basis_flops); CeedChk(ierr);
13616e15d496SJeremy L Thompson         *flops += basis_flops * num_elem;
13626e15d496SJeremy L Thompson       }
13636e15d496SJeremy L Thompson     }
13646e15d496SJeremy L Thompson   }
13656e15d496SJeremy L Thompson 
13666e15d496SJeremy L Thompson   return CEED_ERROR_SUCCESS;
13676e15d496SJeremy L Thompson }
13686e15d496SJeremy L Thompson 
13696e15d496SJeremy L Thompson /**
13703668ca4bSJeremy L Thompson   @brief Get label for a registered QFunctionContext field, or `NULL` if no
13713668ca4bSJeremy L Thompson            field has been registered with this `field_name`.
13723668ca4bSJeremy L Thompson 
13733668ca4bSJeremy L Thompson   @param[in] op            CeedOperator
13743668ca4bSJeremy L Thompson   @param[in] field_name    Name of field to retrieve label
13753668ca4bSJeremy L Thompson   @param[out] field_label  Variable to field label
13763668ca4bSJeremy L Thompson 
13773668ca4bSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
13783668ca4bSJeremy L Thompson 
13793668ca4bSJeremy L Thompson   @ref User
13803668ca4bSJeremy L Thompson **/
13813668ca4bSJeremy L Thompson int CeedOperatorContextGetFieldLabel(CeedOperator op,
13823668ca4bSJeremy L Thompson                                      const char *field_name,
13833668ca4bSJeremy L Thompson                                      CeedContextFieldLabel *field_label) {
13843668ca4bSJeremy L Thompson   int ierr;
13853668ca4bSJeremy L Thompson 
13863668ca4bSJeremy L Thompson   bool is_composite;
13873668ca4bSJeremy L Thompson   ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr);
13883668ca4bSJeremy L Thompson   if (is_composite) {
13893668ca4bSJeremy L Thompson     // Check if composite label already created
13903668ca4bSJeremy L Thompson     for (CeedInt i=0; i<op->num_context_labels; i++) {
13913668ca4bSJeremy L Thompson       if (!strcmp(op->context_labels[i]->name, field_name)) {
13923668ca4bSJeremy L Thompson         *field_label = op->context_labels[i];
13933668ca4bSJeremy L Thompson         return CEED_ERROR_SUCCESS;
13943668ca4bSJeremy L Thompson       }
13953668ca4bSJeremy L Thompson     }
13963668ca4bSJeremy L Thompson 
13973668ca4bSJeremy L Thompson     // Create composite label if needed
13983668ca4bSJeremy L Thompson     CeedInt num_sub;
13993668ca4bSJeremy L Thompson     CeedOperator *sub_operators;
14003668ca4bSJeremy L Thompson     CeedContextFieldLabel new_field_label;
14013668ca4bSJeremy L Thompson 
14023668ca4bSJeremy L Thompson     ierr = CeedCalloc(1, &new_field_label); CeedChk(ierr);
14033668ca4bSJeremy L Thompson     ierr = CeedOperatorGetNumSub(op, &num_sub); CeedChk(ierr);
14043668ca4bSJeremy L Thompson     ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr);
14053668ca4bSJeremy L Thompson     ierr = CeedCalloc(num_sub, &new_field_label->sub_labels); CeedChk(ierr);
14063668ca4bSJeremy L Thompson     new_field_label->num_sub_labels = num_sub;
14073668ca4bSJeremy L Thompson 
14083668ca4bSJeremy L Thompson     bool label_found = false;
14093668ca4bSJeremy L Thompson     for (CeedInt i=0; i<num_sub; i++) {
14103668ca4bSJeremy L Thompson       if (sub_operators[i]->qf->ctx) {
14113668ca4bSJeremy L Thompson         CeedContextFieldLabel new_field_label_i;
14123668ca4bSJeremy L Thompson         ierr = CeedQFunctionContextGetFieldLabel(sub_operators[i]->qf->ctx, field_name,
14133668ca4bSJeremy L Thompson                &new_field_label_i); CeedChk(ierr);
14143668ca4bSJeremy L Thompson         if (new_field_label_i) {
14153668ca4bSJeremy L Thompson           label_found = true;
14163668ca4bSJeremy L Thompson           new_field_label->sub_labels[i] = new_field_label_i;
14173668ca4bSJeremy L Thompson           new_field_label->name = new_field_label_i->name;
14183668ca4bSJeremy L Thompson           new_field_label->description = new_field_label_i->description;
14197bfe0f0eSJeremy L Thompson           if (new_field_label->type &&
14207bfe0f0eSJeremy L Thompson               new_field_label->type != new_field_label_i->type) {
14217bfe0f0eSJeremy L Thompson             // LCOV_EXCL_START
14227bfe0f0eSJeremy L Thompson             ierr = CeedFree(&new_field_label); CeedChk(ierr);
14237bfe0f0eSJeremy L Thompson             return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
14247bfe0f0eSJeremy L Thompson                              "Incompatible field types on sub-operator contexts. "
14257bfe0f0eSJeremy L Thompson                              "%s != %s",
14267bfe0f0eSJeremy L Thompson                              CeedContextFieldTypes[new_field_label->type],
14277bfe0f0eSJeremy L Thompson                              CeedContextFieldTypes[new_field_label_i->type]);
14287bfe0f0eSJeremy L Thompson             // LCOV_EXCL_STOP
14297bfe0f0eSJeremy L Thompson           } else {
14307bfe0f0eSJeremy L Thompson             new_field_label->type = new_field_label_i->type;
14317bfe0f0eSJeremy L Thompson           }
14327bfe0f0eSJeremy L Thompson           if (new_field_label->num_values != 0 &&
14337bfe0f0eSJeremy L Thompson               new_field_label->num_values != new_field_label_i->num_values) {
14347bfe0f0eSJeremy L Thompson             // LCOV_EXCL_START
14357bfe0f0eSJeremy L Thompson             ierr = CeedFree(&new_field_label); CeedChk(ierr);
14367bfe0f0eSJeremy L Thompson             return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
14377bfe0f0eSJeremy L Thompson                              "Incompatible field number of values on sub-operator"
14387bfe0f0eSJeremy L Thompson                              " contexts. %ld != %ld",
14397bfe0f0eSJeremy L Thompson                              new_field_label->num_values, new_field_label_i->num_values);
14407bfe0f0eSJeremy L Thompson             // LCOV_EXCL_STOP
14417bfe0f0eSJeremy L Thompson           } else {
14427bfe0f0eSJeremy L Thompson             new_field_label->num_values = new_field_label_i->num_values;
14437bfe0f0eSJeremy L Thompson           }
14443668ca4bSJeremy L Thompson         }
14453668ca4bSJeremy L Thompson       }
14463668ca4bSJeremy L Thompson     }
14473668ca4bSJeremy L Thompson     if (!label_found) {
14483668ca4bSJeremy L Thompson       // LCOV_EXCL_START
1449a48e5f43SJeremy L Thompson       ierr = CeedFree(&new_field_label->sub_labels); CeedChk(ierr);
14503668ca4bSJeremy L Thompson       ierr = CeedFree(&new_field_label); CeedChk(ierr);
14513668ca4bSJeremy L Thompson       *field_label = NULL;
14523668ca4bSJeremy L Thompson       // LCOV_EXCL_STOP
14533668ca4bSJeremy L Thompson     } else {
14543668ca4bSJeremy L Thompson       // Move new composite label to operator
14553668ca4bSJeremy L Thompson       if (op->num_context_labels == 0) {
14563668ca4bSJeremy L Thompson         ierr = CeedCalloc(1, &op->context_labels); CeedChk(ierr);
14573668ca4bSJeremy L Thompson         op->max_context_labels = 1;
14583668ca4bSJeremy L Thompson       } else if (op->num_context_labels == op->max_context_labels) {
14593668ca4bSJeremy L Thompson         ierr = CeedRealloc(2*op->num_context_labels, &op->context_labels);
14603668ca4bSJeremy L Thompson         CeedChk(ierr);
14613668ca4bSJeremy L Thompson         op->max_context_labels *= 2;
14623668ca4bSJeremy L Thompson       }
14633668ca4bSJeremy L Thompson       op->context_labels[op->num_context_labels] = new_field_label;
14643668ca4bSJeremy L Thompson       *field_label = new_field_label;
14653668ca4bSJeremy L Thompson       op->num_context_labels++;
14663668ca4bSJeremy L Thompson     }
14673668ca4bSJeremy L Thompson 
14683668ca4bSJeremy L Thompson     return CEED_ERROR_SUCCESS;
14693668ca4bSJeremy L Thompson   } else {
14703668ca4bSJeremy L Thompson     return CeedQFunctionContextGetFieldLabel(op->qf->ctx, field_name, field_label);
14713668ca4bSJeremy L Thompson   }
14723668ca4bSJeremy L Thompson }
14733668ca4bSJeremy L Thompson 
14743668ca4bSJeremy L Thompson /**
1475d8dd9a91SJeremy L Thompson   @brief Set QFunctionContext field holding a double precision value.
1476d8dd9a91SJeremy L Thompson            For composite operators, the value is set in all
1477d8dd9a91SJeremy L Thompson            sub-operator QFunctionContexts that have a matching `field_name`.
1478d8dd9a91SJeremy L Thompson 
1479d8dd9a91SJeremy L Thompson   @param op          CeedOperator
14803668ca4bSJeremy L Thompson   @param field_label Label of field to register
14817bfe0f0eSJeremy L Thompson   @param values      Values to set
1482d8dd9a91SJeremy L Thompson 
1483d8dd9a91SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1484d8dd9a91SJeremy L Thompson 
1485d8dd9a91SJeremy L Thompson   @ref User
1486d8dd9a91SJeremy L Thompson **/
14873668ca4bSJeremy L Thompson int CeedOperatorContextSetDouble(CeedOperator op,
14883668ca4bSJeremy L Thompson                                  CeedContextFieldLabel field_label,
14897bfe0f0eSJeremy L Thompson                                  double *values) {
14903668ca4bSJeremy L Thompson   return CeedOperatorContextSetGeneric(op, field_label, CEED_CONTEXT_FIELD_DOUBLE,
14917bfe0f0eSJeremy L Thompson                                        values);
1492d8dd9a91SJeremy L Thompson }
1493d8dd9a91SJeremy L Thompson 
1494d8dd9a91SJeremy L Thompson /**
1495d8dd9a91SJeremy L Thompson   @brief Set QFunctionContext field holding an int32 value.
1496d8dd9a91SJeremy L Thompson            For composite operators, the value is set in all
1497d8dd9a91SJeremy L Thompson            sub-operator QFunctionContexts that have a matching `field_name`.
1498d8dd9a91SJeremy L Thompson 
1499d8dd9a91SJeremy L Thompson   @param op          CeedOperator
15003668ca4bSJeremy L Thompson   @param field_label Label of field to set
15017bfe0f0eSJeremy L Thompson   @param values      Values to set
1502d8dd9a91SJeremy L Thompson 
1503d8dd9a91SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1504d8dd9a91SJeremy L Thompson 
1505d8dd9a91SJeremy L Thompson   @ref User
1506d8dd9a91SJeremy L Thompson **/
15073668ca4bSJeremy L Thompson int CeedOperatorContextSetInt32(CeedOperator op,
15083668ca4bSJeremy L Thompson                                 CeedContextFieldLabel field_label,
15097bfe0f0eSJeremy L Thompson                                 int *values) {
15103668ca4bSJeremy L Thompson   return CeedOperatorContextSetGeneric(op, field_label, CEED_CONTEXT_FIELD_INT32,
15117bfe0f0eSJeremy L Thompson                                        values);
1512d8dd9a91SJeremy L Thompson }
1513d8dd9a91SJeremy L Thompson 
1514d8dd9a91SJeremy L Thompson /**
15153bd813ffSjeremylt   @brief Apply CeedOperator to a vector
1516d7b241e6Sjeremylt 
1517d7b241e6Sjeremylt   This computes the action of the operator on the specified (active) input,
1518d7b241e6Sjeremylt   yielding its (active) output.  All inputs and outputs must be specified using
1519d7b241e6Sjeremylt   CeedOperatorSetField().
1520d7b241e6Sjeremylt 
1521f04ea552SJeremy L Thompson   Note: Calling this function asserts that setup is complete
1522f04ea552SJeremy L Thompson           and sets the CeedOperator as immutable.
1523f04ea552SJeremy L Thompson 
1524d7b241e6Sjeremylt   @param op        CeedOperator to apply
15254cc79fe7SJed Brown   @param[in] in    CeedVector containing input state or @ref CEED_VECTOR_NONE if
152634138859Sjeremylt                      there are no active inputs
1527b11c1e72Sjeremylt   @param[out] out  CeedVector to store result of applying operator (must be
15284cc79fe7SJed Brown                      distinct from @a in) or @ref CEED_VECTOR_NONE if there are no
152934138859Sjeremylt                      active outputs
1530d7b241e6Sjeremylt   @param request   Address of CeedRequest for non-blocking completion, else
15314cc79fe7SJed Brown                      @ref CEED_REQUEST_IMMEDIATE
1532b11c1e72Sjeremylt 
1533b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
1534dfdf5a53Sjeremylt 
15357a982d89SJeremy L. Thompson   @ref User
1536b11c1e72Sjeremylt **/
1537692c2638Sjeremylt int CeedOperatorApply(CeedOperator op, CeedVector in, CeedVector out,
1538692c2638Sjeremylt                       CeedRequest *request) {
1539d7b241e6Sjeremylt   int ierr;
1540e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
1541d7b241e6Sjeremylt 
1542d1d35e2fSjeremylt   if (op->num_elem)  {
1543250756a7Sjeremylt     // Standard Operator
1544cae8b89aSjeremylt     if (op->Apply) {
1545250756a7Sjeremylt       ierr = op->Apply(op, in, out, request); CeedChk(ierr);
1546cae8b89aSjeremylt     } else {
1547cae8b89aSjeremylt       // Zero all output vectors
1548250756a7Sjeremylt       CeedQFunction qf = op->qf;
1549d1d35e2fSjeremylt       for (CeedInt i=0; i<qf->num_output_fields; i++) {
1550d1d35e2fSjeremylt         CeedVector vec = op->output_fields[i]->vec;
1551cae8b89aSjeremylt         if (vec == CEED_VECTOR_ACTIVE)
1552cae8b89aSjeremylt           vec = out;
1553cae8b89aSjeremylt         if (vec != CEED_VECTOR_NONE) {
1554cae8b89aSjeremylt           ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr);
1555cae8b89aSjeremylt         }
1556cae8b89aSjeremylt       }
1557250756a7Sjeremylt       // Apply
1558250756a7Sjeremylt       ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr);
1559250756a7Sjeremylt     }
1560f04ea552SJeremy L Thompson   } else if (op->is_composite) {
1561250756a7Sjeremylt     // Composite Operator
1562250756a7Sjeremylt     if (op->ApplyComposite) {
1563250756a7Sjeremylt       ierr = op->ApplyComposite(op, in, out, request); CeedChk(ierr);
1564250756a7Sjeremylt     } else {
1565d1d35e2fSjeremylt       CeedInt num_suboperators;
1566d1d35e2fSjeremylt       ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr);
1567d1d35e2fSjeremylt       CeedOperator *sub_operators;
1568d1d35e2fSjeremylt       ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr);
1569250756a7Sjeremylt 
1570250756a7Sjeremylt       // Zero all output vectors
1571250756a7Sjeremylt       if (out != CEED_VECTOR_NONE) {
1572cae8b89aSjeremylt         ierr = CeedVectorSetValue(out, 0.0); CeedChk(ierr);
1573cae8b89aSjeremylt       }
1574d1d35e2fSjeremylt       for (CeedInt i=0; i<num_suboperators; i++) {
1575d1d35e2fSjeremylt         for (CeedInt j=0; j<sub_operators[i]->qf->num_output_fields; j++) {
1576d1d35e2fSjeremylt           CeedVector vec = sub_operators[i]->output_fields[j]->vec;
1577250756a7Sjeremylt           if (vec != CEED_VECTOR_ACTIVE && vec != CEED_VECTOR_NONE) {
1578250756a7Sjeremylt             ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr);
1579250756a7Sjeremylt           }
1580250756a7Sjeremylt         }
1581250756a7Sjeremylt       }
1582250756a7Sjeremylt       // Apply
1583d1d35e2fSjeremylt       for (CeedInt i=0; i<op->num_suboperators; i++) {
1584d1d35e2fSjeremylt         ierr = CeedOperatorApplyAdd(op->sub_operators[i], in, out, request);
1585cae8b89aSjeremylt         CeedChk(ierr);
1586cae8b89aSjeremylt       }
1587cae8b89aSjeremylt     }
1588250756a7Sjeremylt   }
1589e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1590cae8b89aSjeremylt }
1591cae8b89aSjeremylt 
1592cae8b89aSjeremylt /**
1593cae8b89aSjeremylt   @brief Apply CeedOperator to a vector and add result to output vector
1594cae8b89aSjeremylt 
1595cae8b89aSjeremylt   This computes the action of the operator on the specified (active) input,
1596cae8b89aSjeremylt   yielding its (active) output.  All inputs and outputs must be specified using
1597cae8b89aSjeremylt   CeedOperatorSetField().
1598cae8b89aSjeremylt 
1599cae8b89aSjeremylt   @param op        CeedOperator to apply
1600cae8b89aSjeremylt   @param[in] in    CeedVector containing input state or NULL if there are no
1601cae8b89aSjeremylt                      active inputs
1602cae8b89aSjeremylt   @param[out] out  CeedVector to sum in result of applying operator (must be
1603cae8b89aSjeremylt                      distinct from @a in) or NULL if there are no active outputs
1604cae8b89aSjeremylt   @param request   Address of CeedRequest for non-blocking completion, else
16054cc79fe7SJed Brown                      @ref CEED_REQUEST_IMMEDIATE
1606cae8b89aSjeremylt 
1607cae8b89aSjeremylt   @return An error code: 0 - success, otherwise - failure
1608cae8b89aSjeremylt 
16097a982d89SJeremy L. Thompson   @ref User
1610cae8b89aSjeremylt **/
1611cae8b89aSjeremylt int CeedOperatorApplyAdd(CeedOperator op, CeedVector in, CeedVector out,
1612cae8b89aSjeremylt                          CeedRequest *request) {
1613cae8b89aSjeremylt   int ierr;
1614e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
1615cae8b89aSjeremylt 
1616d1d35e2fSjeremylt   if (op->num_elem)  {
1617250756a7Sjeremylt     // Standard Operator
1618250756a7Sjeremylt     ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr);
1619f04ea552SJeremy L Thompson   } else if (op->is_composite) {
1620250756a7Sjeremylt     // Composite Operator
1621250756a7Sjeremylt     if (op->ApplyAddComposite) {
1622250756a7Sjeremylt       ierr = op->ApplyAddComposite(op, in, out, request); CeedChk(ierr);
1623cae8b89aSjeremylt     } else {
1624d1d35e2fSjeremylt       CeedInt num_suboperators;
1625d1d35e2fSjeremylt       ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr);
1626d1d35e2fSjeremylt       CeedOperator *sub_operators;
1627d1d35e2fSjeremylt       ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr);
1628250756a7Sjeremylt 
1629d1d35e2fSjeremylt       for (CeedInt i=0; i<num_suboperators; i++) {
1630d1d35e2fSjeremylt         ierr = CeedOperatorApplyAdd(sub_operators[i], in, out, request);
1631cae8b89aSjeremylt         CeedChk(ierr);
16321d7d2407SJeremy L Thompson       }
1633250756a7Sjeremylt     }
1634250756a7Sjeremylt   }
1635e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1636d7b241e6Sjeremylt }
1637d7b241e6Sjeremylt 
1638d7b241e6Sjeremylt /**
1639b11c1e72Sjeremylt   @brief Destroy a CeedOperator
1640d7b241e6Sjeremylt 
1641d7b241e6Sjeremylt   @param op  CeedOperator to destroy
1642b11c1e72Sjeremylt 
1643b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
1644dfdf5a53Sjeremylt 
16457a982d89SJeremy L. Thompson   @ref User
1646b11c1e72Sjeremylt **/
1647d7b241e6Sjeremylt int CeedOperatorDestroy(CeedOperator *op) {
1648d7b241e6Sjeremylt   int ierr;
1649d7b241e6Sjeremylt 
1650d1d35e2fSjeremylt   if (!*op || --(*op)->ref_count > 0) return CEED_ERROR_SUCCESS;
1651d7b241e6Sjeremylt   if ((*op)->Destroy) {
1652d7b241e6Sjeremylt     ierr = (*op)->Destroy(*op); CeedChk(ierr);
1653d7b241e6Sjeremylt   }
1654fe2413ffSjeremylt   ierr = CeedDestroy(&(*op)->ceed); CeedChk(ierr);
1655fe2413ffSjeremylt   // Free fields
16563668ca4bSJeremy L Thompson   for (CeedInt i=0; i<(*op)->num_fields; i++)
1657d1d35e2fSjeremylt     if ((*op)->input_fields[i]) {
1658d1d35e2fSjeremylt       if ((*op)->input_fields[i]->elem_restr != CEED_ELEMRESTRICTION_NONE) {
1659d1d35e2fSjeremylt         ierr = CeedElemRestrictionDestroy(&(*op)->input_fields[i]->elem_restr);
166071352a93Sjeremylt         CeedChk(ierr);
166115910d16Sjeremylt       }
1662d1d35e2fSjeremylt       if ((*op)->input_fields[i]->basis != CEED_BASIS_COLLOCATED) {
1663d1d35e2fSjeremylt         ierr = CeedBasisDestroy(&(*op)->input_fields[i]->basis); CeedChk(ierr);
166471352a93Sjeremylt       }
1665d1d35e2fSjeremylt       if ((*op)->input_fields[i]->vec != CEED_VECTOR_ACTIVE &&
1666d1d35e2fSjeremylt           (*op)->input_fields[i]->vec != CEED_VECTOR_NONE ) {
1667d1d35e2fSjeremylt         ierr = CeedVectorDestroy(&(*op)->input_fields[i]->vec); CeedChk(ierr);
166871352a93Sjeremylt       }
1669d1d35e2fSjeremylt       ierr = CeedFree(&(*op)->input_fields[i]->field_name); CeedChk(ierr);
1670d1d35e2fSjeremylt       ierr = CeedFree(&(*op)->input_fields[i]); CeedChk(ierr);
1671fe2413ffSjeremylt     }
16723668ca4bSJeremy L Thompson   for (CeedInt i=0; i<(*op)->num_fields; i++)
1673d1d35e2fSjeremylt     if ((*op)->output_fields[i]) {
1674d1d35e2fSjeremylt       ierr = CeedElemRestrictionDestroy(&(*op)->output_fields[i]->elem_restr);
167571352a93Sjeremylt       CeedChk(ierr);
1676d1d35e2fSjeremylt       if ((*op)->output_fields[i]->basis != CEED_BASIS_COLLOCATED) {
1677d1d35e2fSjeremylt         ierr = CeedBasisDestroy(&(*op)->output_fields[i]->basis); CeedChk(ierr);
167871352a93Sjeremylt       }
1679d1d35e2fSjeremylt       if ((*op)->output_fields[i]->vec != CEED_VECTOR_ACTIVE &&
1680d1d35e2fSjeremylt           (*op)->output_fields[i]->vec != CEED_VECTOR_NONE ) {
1681d1d35e2fSjeremylt         ierr = CeedVectorDestroy(&(*op)->output_fields[i]->vec); CeedChk(ierr);
168271352a93Sjeremylt       }
1683d1d35e2fSjeremylt       ierr = CeedFree(&(*op)->output_fields[i]->field_name); CeedChk(ierr);
1684d1d35e2fSjeremylt       ierr = CeedFree(&(*op)->output_fields[i]); CeedChk(ierr);
1685fe2413ffSjeremylt     }
1686d1d35e2fSjeremylt   // Destroy sub_operators
16873668ca4bSJeremy L Thompson   for (CeedInt i=0; i<(*op)->num_suboperators; i++)
1688d1d35e2fSjeremylt     if ((*op)->sub_operators[i]) {
1689d1d35e2fSjeremylt       ierr = CeedOperatorDestroy(&(*op)->sub_operators[i]); CeedChk(ierr);
169052d6035fSJeremy L Thompson     }
1691d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->qf); CeedChk(ierr);
1692d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->dqf); CeedChk(ierr);
1693d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->dqfT); CeedChk(ierr);
16943668ca4bSJeremy L Thompson   // Destroy any composite labels
16953668ca4bSJeremy L Thompson   for (CeedInt i=0; i<(*op)->num_context_labels; i++) {
16963668ca4bSJeremy L Thompson     ierr = CeedFree(&(*op)->context_labels[i]->sub_labels); CeedChk(ierr);
16973668ca4bSJeremy L Thompson     ierr = CeedFree(&(*op)->context_labels[i]); CeedChk(ierr);
16983668ca4bSJeremy L Thompson   }
16993668ca4bSJeremy L Thompson   ierr = CeedFree(&(*op)->context_labels); CeedChk(ierr);
1700fe2413ffSjeremylt 
17015107b09fSJeremy L Thompson   // Destroy fallback
1702805fe78eSJeremy L Thompson   ierr = CeedOperatorDestroy(&(*op)->op_fallback); CeedChk(ierr);
17035107b09fSJeremy L Thompson 
1704*ed9e99e6SJeremy L Thompson   // Destroy assembly data
1705480fae85SJeremy L Thompson   ierr = CeedQFunctionAssemblyDataDestroy(&(*op)->qf_assembled); CeedChk(ierr);
1706*ed9e99e6SJeremy L Thompson   ierr = CeedOperatorAssemblyDataDestroy(&(*op)->op_assembled); CeedChk(ierr);
170770a7ffb3SJeremy L Thompson 
1708d1d35e2fSjeremylt   ierr = CeedFree(&(*op)->input_fields); CeedChk(ierr);
1709d1d35e2fSjeremylt   ierr = CeedFree(&(*op)->output_fields); CeedChk(ierr);
1710d1d35e2fSjeremylt   ierr = CeedFree(&(*op)->sub_operators); CeedChk(ierr);
1711ea6b5821SJeremy L Thompson   ierr = CeedFree(&(*op)->name); CeedChk(ierr);
1712d7b241e6Sjeremylt   ierr = CeedFree(op); CeedChk(ierr);
1713e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1714d7b241e6Sjeremylt }
1715d7b241e6Sjeremylt 
1716d7b241e6Sjeremylt /// @}
1717