xref: /libCEED/interface/ceed-operator.c (revision 2b1040054b5938b34f5a4d46939a1d44eddbfbb8)
1d7b241e6Sjeremylt // Copyright (c) 2017, Lawrence Livermore National Security, LLC. Produced at
2d7b241e6Sjeremylt // the Lawrence Livermore National Laboratory. LLNL-CODE-734707. All Rights
3d7b241e6Sjeremylt // reserved. See files LICENSE and NOTICE for details.
4d7b241e6Sjeremylt //
5d7b241e6Sjeremylt // This file is part of CEED, a collection of benchmarks, miniapps, software
6d7b241e6Sjeremylt // libraries and APIs for efficient high-order finite element and spectral
7d7b241e6Sjeremylt // element discretizations for exascale applications. For more information and
8d7b241e6Sjeremylt // source code availability see http://github.com/ceed.
9d7b241e6Sjeremylt //
10d7b241e6Sjeremylt // The CEED research is supported by the Exascale Computing Project 17-SC-20-SC,
11d7b241e6Sjeremylt // a collaborative effort of two U.S. Department of Energy organizations (Office
12d7b241e6Sjeremylt // of Science and the National Nuclear Security Administration) responsible for
13d7b241e6Sjeremylt // the planning and preparation of a capable exascale ecosystem, including
14d7b241e6Sjeremylt // software, applications, hardware, advanced system engineering and early
15d7b241e6Sjeremylt // testbed platforms, in support of the nation's exascale computing imperative.
16d7b241e6Sjeremylt 
17ec3da8bcSJed Brown #include <ceed/ceed.h>
18ec3da8bcSJed Brown #include <ceed/backend.h>
193d576824SJeremy L Thompson #include <ceed-impl.h>
203d576824SJeremy L Thompson #include <stdbool.h>
213d576824SJeremy L Thompson #include <stdio.h>
223d576824SJeremy L Thompson #include <string.h>
23d7b241e6Sjeremylt 
24dfdf5a53Sjeremylt /// @file
257a982d89SJeremy L. Thompson /// Implementation of CeedOperator interfaces
267a982d89SJeremy L. Thompson 
277a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
287a982d89SJeremy L. Thompson /// CeedOperator Library Internal Functions
297a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
307a982d89SJeremy L. Thompson /// @addtogroup CeedOperatorDeveloper
317a982d89SJeremy L. Thompson /// @{
327a982d89SJeremy L. Thompson 
337a982d89SJeremy L. Thompson /**
34e15f9bd0SJeremy L Thompson   @brief Check if a CeedOperator Field matches the QFunction Field
35e15f9bd0SJeremy L Thompson 
36e15f9bd0SJeremy L Thompson   @param[in] ceed      Ceed object for error handling
37d1d35e2fSjeremylt   @param[in] qf_field  QFunction Field matching Operator Field
38e15f9bd0SJeremy L Thompson   @param[in] r         Operator Field ElemRestriction
39e15f9bd0SJeremy L Thompson   @param[in] b         Operator Field Basis
40e15f9bd0SJeremy L Thompson 
41e15f9bd0SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
42e15f9bd0SJeremy L Thompson 
43e15f9bd0SJeremy L Thompson   @ref Developer
44e15f9bd0SJeremy L Thompson **/
45d1d35e2fSjeremylt static int CeedOperatorCheckField(Ceed ceed, CeedQFunctionField qf_field,
46e15f9bd0SJeremy L Thompson                                   CeedElemRestriction r, CeedBasis b) {
47e15f9bd0SJeremy L Thompson   int ierr;
48d1d35e2fSjeremylt   CeedEvalMode eval_mode = qf_field->eval_mode;
49d1d35e2fSjeremylt   CeedInt dim = 1, num_comp = 1, restr_num_comp = 1, size = qf_field->size;
50e15f9bd0SJeremy L Thompson   // Restriction
51e15f9bd0SJeremy L Thompson   if (r != CEED_ELEMRESTRICTION_NONE) {
52d1d35e2fSjeremylt     if (eval_mode == CEED_EVAL_WEIGHT) {
53e15f9bd0SJeremy L Thompson       // LCOV_EXCL_START
54e1e9e29dSJed Brown       return CeedError(ceed, CEED_ERROR_INCOMPATIBLE,
55e1e9e29dSJed Brown                        "CEED_ELEMRESTRICTION_NONE should be used "
56e15f9bd0SJeremy L Thompson                        "for a field with eval mode CEED_EVAL_WEIGHT");
57e15f9bd0SJeremy L Thompson       // LCOV_EXCL_STOP
58e15f9bd0SJeremy L Thompson     }
59d1d35e2fSjeremylt     ierr = CeedElemRestrictionGetNumComponents(r, &restr_num_comp);
6078464608Sjeremylt     CeedChk(ierr);
61e1e9e29dSJed Brown   }
62d1d35e2fSjeremylt   if ((r == CEED_ELEMRESTRICTION_NONE) != (eval_mode == CEED_EVAL_WEIGHT)) {
63e1e9e29dSJed Brown     // LCOV_EXCL_START
64e1e9e29dSJed Brown     return CeedError(ceed, CEED_ERROR_INCOMPATIBLE,
65e1e9e29dSJed Brown                      "CEED_ELEMRESTRICTION_NONE and CEED_EVAL_WEIGHT "
66e1e9e29dSJed Brown                      "must be used together.");
67e1e9e29dSJed Brown     // LCOV_EXCL_STOP
68e1e9e29dSJed Brown   }
69e15f9bd0SJeremy L Thompson   // Basis
70e15f9bd0SJeremy L Thompson   if (b != CEED_BASIS_COLLOCATED) {
71d1d35e2fSjeremylt     if (eval_mode == CEED_EVAL_NONE)
728229195eSjeremylt       // LCOV_EXCL_START
73e1e9e29dSJed Brown       return CeedError(ceed, CEED_ERROR_INCOMPATIBLE,
74d1d35e2fSjeremylt                        "Field '%s' configured with CEED_EVAL_NONE must "
75d1d35e2fSjeremylt                        "be used with CEED_BASIS_COLLOCATED",
768229195eSjeremylt                        // LCOV_EXCL_STOP
77d1d35e2fSjeremylt                        qf_field->field_name);
78e15f9bd0SJeremy L Thompson     ierr = CeedBasisGetDimension(b, &dim); CeedChk(ierr);
79d1d35e2fSjeremylt     ierr = CeedBasisGetNumComponents(b, &num_comp); CeedChk(ierr);
80d1d35e2fSjeremylt     if (r != CEED_ELEMRESTRICTION_NONE && restr_num_comp != num_comp) {
81e15f9bd0SJeremy L Thompson       // LCOV_EXCL_START
82e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_DIMENSION,
83d1d35e2fSjeremylt                        "Field '%s' of size %d and EvalMode %s: ElemRestriction "
84d1d35e2fSjeremylt                        "has %d components, but Basis has %d components",
85d1d35e2fSjeremylt                        qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode],
86d1d35e2fSjeremylt                        restr_num_comp,
87d1d35e2fSjeremylt                        num_comp);
88e15f9bd0SJeremy L Thompson       // LCOV_EXCL_STOP
89e15f9bd0SJeremy L Thompson     }
90e15f9bd0SJeremy L Thompson   }
91e15f9bd0SJeremy L Thompson   // Field size
92d1d35e2fSjeremylt   switch(eval_mode) {
93e15f9bd0SJeremy L Thompson   case CEED_EVAL_NONE:
94d1d35e2fSjeremylt     if (size != restr_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 has %d components",
98d1d35e2fSjeremylt                        qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode],
99d1d35e2fSjeremylt                        restr_num_comp);
100e15f9bd0SJeremy L Thompson     // LCOV_EXCL_STOP
101e15f9bd0SJeremy L Thompson     break;
102e15f9bd0SJeremy L Thompson   case CEED_EVAL_INTERP:
103d1d35e2fSjeremylt     if (size != num_comp)
104e15f9bd0SJeremy L Thompson       // LCOV_EXCL_START
105e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_DIMENSION,
106e1e9e29dSJed Brown                        "Field '%s' of size %d and EvalMode %s: ElemRestriction/Basis has %d components",
107d1d35e2fSjeremylt                        qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode],
108d1d35e2fSjeremylt                        num_comp);
109e15f9bd0SJeremy L Thompson     // LCOV_EXCL_STOP
110e15f9bd0SJeremy L Thompson     break;
111e15f9bd0SJeremy L Thompson   case CEED_EVAL_GRAD:
112d1d35e2fSjeremylt     if (size != num_comp * dim)
113e15f9bd0SJeremy L Thompson       // LCOV_EXCL_START
114e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_DIMENSION,
115d1d35e2fSjeremylt                        "Field '%s' of size %d and EvalMode %s in %d dimensions: "
116d1d35e2fSjeremylt                        "ElemRestriction/Basis has %d components",
117d1d35e2fSjeremylt                        qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode], dim,
118d1d35e2fSjeremylt                        num_comp);
119e15f9bd0SJeremy L Thompson     // LCOV_EXCL_STOP
120e15f9bd0SJeremy L Thompson     break;
121e15f9bd0SJeremy L Thompson   case CEED_EVAL_WEIGHT:
122d1d35e2fSjeremylt     // No additional checks required
123e15f9bd0SJeremy L Thompson     break;
124e15f9bd0SJeremy L Thompson   case CEED_EVAL_DIV:
125e15f9bd0SJeremy L Thompson     // Not implemented
126e15f9bd0SJeremy L Thompson     break;
127e15f9bd0SJeremy L Thompson   case CEED_EVAL_CURL:
128e15f9bd0SJeremy L Thompson     // Not implemented
129e15f9bd0SJeremy L Thompson     break;
130e15f9bd0SJeremy L Thompson   }
131e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1327a982d89SJeremy L. Thompson }
1337a982d89SJeremy L. Thompson 
1347a982d89SJeremy L. Thompson /**
1357a982d89SJeremy L. Thompson   @brief View a field of a CeedOperator
1367a982d89SJeremy L. Thompson 
1377a982d89SJeremy L. Thompson   @param[in] field         Operator field to view
138d1d35e2fSjeremylt   @param[in] qf_field      QFunction field (carries field name)
139d1d35e2fSjeremylt   @param[in] field_number  Number of field being viewed
1404c4400c7SValeria Barra   @param[in] sub           true indicates sub-operator, which increases indentation; false for top-level operator
141d1d35e2fSjeremylt   @param[in] input         true for an input field; false for output field
1427a982d89SJeremy L. Thompson   @param[in] stream        Stream to view to, e.g., stdout
1437a982d89SJeremy L. Thompson 
1447a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
1457a982d89SJeremy L. Thompson 
1467a982d89SJeremy L. Thompson   @ref Utility
1477a982d89SJeremy L. Thompson **/
1487a982d89SJeremy L. Thompson static int CeedOperatorFieldView(CeedOperatorField field,
149d1d35e2fSjeremylt                                  CeedQFunctionField qf_field,
150d1d35e2fSjeremylt                                  CeedInt field_number, bool sub, bool input,
1517a982d89SJeremy L. Thompson                                  FILE *stream) {
1527a982d89SJeremy L. Thompson   const char *pre = sub ? "  " : "";
153d1d35e2fSjeremylt   const char *in_out = input ? "Input" : "Output";
1547a982d89SJeremy L. Thompson 
1557a982d89SJeremy L. Thompson   fprintf(stream, "%s    %s Field [%d]:\n"
1567a982d89SJeremy L. Thompson           "%s      Name: \"%s\"\n",
157d1d35e2fSjeremylt           pre, in_out, field_number, pre, qf_field->field_name);
1587a982d89SJeremy L. Thompson 
1597a982d89SJeremy L. Thompson   if (field->basis == CEED_BASIS_COLLOCATED)
1607a982d89SJeremy L. Thompson     fprintf(stream, "%s      Collocated basis\n", pre);
1617a982d89SJeremy L. Thompson 
1627a982d89SJeremy L. Thompson   if (field->vec == CEED_VECTOR_ACTIVE)
1637a982d89SJeremy L. Thompson     fprintf(stream, "%s      Active vector\n", pre);
1647a982d89SJeremy L. Thompson   else if (field->vec == CEED_VECTOR_NONE)
1657a982d89SJeremy L. Thompson     fprintf(stream, "%s      No vector\n", pre);
166e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1677a982d89SJeremy L. Thompson }
1687a982d89SJeremy L. Thompson 
1697a982d89SJeremy L. Thompson /**
1707a982d89SJeremy L. Thompson   @brief View a single CeedOperator
1717a982d89SJeremy L. Thompson 
1727a982d89SJeremy L. Thompson   @param[in] op      CeedOperator to view
1737a982d89SJeremy L. Thompson   @param[in] sub     Boolean flag for sub-operator
1747a982d89SJeremy L. Thompson   @param[in] stream  Stream to write; typically stdout/stderr or a file
1757a982d89SJeremy L. Thompson 
1767a982d89SJeremy L. Thompson   @return Error code: 0 - success, otherwise - failure
1777a982d89SJeremy L. Thompson 
1787a982d89SJeremy L. Thompson   @ref Utility
1797a982d89SJeremy L. Thompson **/
1807a982d89SJeremy L. Thompson int CeedOperatorSingleView(CeedOperator op, bool sub, FILE *stream) {
1817a982d89SJeremy L. Thompson   int ierr;
1827a982d89SJeremy L. Thompson   const char *pre = sub ? "  " : "";
1837a982d89SJeremy L. Thompson 
18478464608Sjeremylt   CeedInt total_fields = 0;
18578464608Sjeremylt   ierr = CeedOperatorGetNumArgs(op, &total_fields); CeedChk(ierr);
1867a982d89SJeremy L. Thompson 
18778464608Sjeremylt   fprintf(stream, "%s  %d Field%s\n", pre, total_fields,
18878464608Sjeremylt           total_fields>1 ? "s" : "");
1897a982d89SJeremy L. Thompson 
190d1d35e2fSjeremylt   fprintf(stream, "%s  %d Input Field%s:\n", pre, op->qf->num_input_fields,
191d1d35e2fSjeremylt           op->qf->num_input_fields>1 ? "s" : "");
192d1d35e2fSjeremylt   for (CeedInt i=0; i<op->qf->num_input_fields; i++) {
193d1d35e2fSjeremylt     ierr = CeedOperatorFieldView(op->input_fields[i], op->qf->input_fields[i],
1947a982d89SJeremy L. Thompson                                  i, sub, 1, stream); CeedChk(ierr);
1957a982d89SJeremy L. Thompson   }
1967a982d89SJeremy L. Thompson 
197d1d35e2fSjeremylt   fprintf(stream, "%s  %d Output Field%s:\n", pre, op->qf->num_output_fields,
198d1d35e2fSjeremylt           op->qf->num_output_fields>1 ? "s" : "");
199d1d35e2fSjeremylt   for (CeedInt i=0; i<op->qf->num_output_fields; i++) {
200d1d35e2fSjeremylt     ierr = CeedOperatorFieldView(op->output_fields[i], op->qf->output_fields[i],
2017a982d89SJeremy L. Thompson                                  i, sub, 0, stream); CeedChk(ierr);
2027a982d89SJeremy L. Thompson   }
203e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2047a982d89SJeremy L. Thompson }
2057a982d89SJeremy L. Thompson 
206d99fa3c5SJeremy L Thompson /**
2070f60e0a8SJeremy L Thompson   @brief Find the active vector basis for a non-composite CeedOperator
208eaf62fffSJeremy L Thompson 
209eaf62fffSJeremy L Thompson   @param[in] op             CeedOperator to find active basis for
2100f60e0a8SJeremy L Thompson   @param[out] active_basis  Basis for active input vector or NULL for composite operator
211eaf62fffSJeremy L Thompson 
212eaf62fffSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
213eaf62fffSJeremy L Thompson 
214eaf62fffSJeremy L Thompson   @ ref Developer
215eaf62fffSJeremy L Thompson **/
216eaf62fffSJeremy L Thompson int CeedOperatorGetActiveBasis(CeedOperator op, CeedBasis *active_basis) {
217eaf62fffSJeremy L Thompson   *active_basis = NULL;
2180f60e0a8SJeremy L Thompson   if (op->is_composite) return CEED_ERROR_SUCCESS;
219eaf62fffSJeremy L Thompson   for (int i = 0; i < op->qf->num_input_fields; i++)
220eaf62fffSJeremy L Thompson     if (op->input_fields[i]->vec == CEED_VECTOR_ACTIVE) {
221eaf62fffSJeremy L Thompson       *active_basis = op->input_fields[i]->basis;
222eaf62fffSJeremy L Thompson       break;
223eaf62fffSJeremy L Thompson     }
224eaf62fffSJeremy L Thompson 
225eaf62fffSJeremy L Thompson   if (!*active_basis) {
226eaf62fffSJeremy L Thompson     // LCOV_EXCL_START
227eaf62fffSJeremy L Thompson     int ierr;
228eaf62fffSJeremy L Thompson     Ceed ceed;
229eaf62fffSJeremy L Thompson     ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr);
230eaf62fffSJeremy L Thompson     return CeedError(ceed, CEED_ERROR_MINOR,
231eaf62fffSJeremy L Thompson                      "No active CeedBasis found");
232eaf62fffSJeremy L Thompson     // LCOV_EXCL_STOP
233eaf62fffSJeremy L Thompson   }
234eaf62fffSJeremy L Thompson   return CEED_ERROR_SUCCESS;
235eaf62fffSJeremy L Thompson }
236eaf62fffSJeremy L Thompson 
237eaf62fffSJeremy L Thompson /**
2380f60e0a8SJeremy L Thompson   @brief Find the active vector ElemRestriction for a non-composite CeedOperator
239e2f04181SAndrew T. Barker 
240e2f04181SAndrew T. Barker   @param[in] op            CeedOperator to find active basis for
2410f60e0a8SJeremy L Thompson   @param[out] active_rstr  ElemRestriction for active input vector or NULL for composite operator
242e2f04181SAndrew T. Barker 
243e2f04181SAndrew T. Barker   @return An error code: 0 - success, otherwise - failure
244e2f04181SAndrew T. Barker 
245e2f04181SAndrew T. Barker   @ref Utility
246e2f04181SAndrew T. Barker **/
247eaf62fffSJeremy L Thompson int CeedOperatorGetActiveElemRestriction(CeedOperator op,
248d1d35e2fSjeremylt     CeedElemRestriction *active_rstr) {
249d1d35e2fSjeremylt   *active_rstr = NULL;
2500f60e0a8SJeremy L Thompson   if (op->is_composite) return CEED_ERROR_SUCCESS;
251d1d35e2fSjeremylt   for (int i = 0; i < op->qf->num_input_fields; i++)
252d1d35e2fSjeremylt     if (op->input_fields[i]->vec == CEED_VECTOR_ACTIVE) {
253d1d35e2fSjeremylt       *active_rstr = op->input_fields[i]->elem_restr;
254e2f04181SAndrew T. Barker       break;
255e2f04181SAndrew T. Barker     }
256e2f04181SAndrew T. Barker 
257d1d35e2fSjeremylt   if (!*active_rstr) {
258e2f04181SAndrew T. Barker     // LCOV_EXCL_START
259e2f04181SAndrew T. Barker     int ierr;
260e2f04181SAndrew T. Barker     Ceed ceed;
261e2f04181SAndrew T. Barker     ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr);
262e2f04181SAndrew T. Barker     return CeedError(ceed, CEED_ERROR_INCOMPLETE,
263eaf62fffSJeremy L Thompson                      "No active CeedElemRestriction found");
264e2f04181SAndrew T. Barker     // LCOV_EXCL_STOP
265e2f04181SAndrew T. Barker   }
266e2f04181SAndrew T. Barker   return CEED_ERROR_SUCCESS;
267e2f04181SAndrew T. Barker }
268e2f04181SAndrew T. Barker 
269d8dd9a91SJeremy L Thompson /**
270d8dd9a91SJeremy L Thompson   @brief Set QFunctionContext field value of the specified type.
271d8dd9a91SJeremy L Thompson            For composite operators, the value is set in all
272d8dd9a91SJeremy L Thompson            sub-operator QFunctionContexts that have a matching `field_name`.
273d8dd9a91SJeremy L Thompson            A non-zero error code is returned for single operators
274d8dd9a91SJeremy L Thompson            that do not have a matching field of the same type or composite
275d8dd9a91SJeremy L Thompson            operators that do not have any field of a matching type.
276d8dd9a91SJeremy L Thompson 
277d8dd9a91SJeremy L Thompson   @param op          CeedOperator
2783668ca4bSJeremy L Thompson   @param field_label Label of field to set
279d8dd9a91SJeremy L Thompson   @param field_type  Type of field to set
280d8dd9a91SJeremy L Thompson   @param value       Value to set
281d8dd9a91SJeremy L Thompson 
282d8dd9a91SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
283d8dd9a91SJeremy L Thompson 
284d8dd9a91SJeremy L Thompson   @ref User
285d8dd9a91SJeremy L Thompson **/
286d8dd9a91SJeremy L Thompson static int CeedOperatorContextSetGeneric(CeedOperator op,
2873668ca4bSJeremy L Thompson     CeedContextFieldLabel field_label, CeedContextFieldType field_type,
2883668ca4bSJeremy L Thompson     void *value) {
289d8dd9a91SJeremy L Thompson   int ierr;
290d8dd9a91SJeremy L Thompson 
2913668ca4bSJeremy L Thompson   if (!field_label)
2923668ca4bSJeremy L Thompson     // LCOV_EXCL_START
2933668ca4bSJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED,
2943668ca4bSJeremy L Thompson                      "Invalid field label");
2953668ca4bSJeremy L Thompson   // LCOV_EXCL_STOP
2963668ca4bSJeremy L Thompson 
2973668ca4bSJeremy L Thompson   bool is_composite = false;
298d8dd9a91SJeremy L Thompson   ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr);
299d8dd9a91SJeremy L Thompson   if (is_composite) {
300d8dd9a91SJeremy L Thompson     CeedInt num_sub;
301d8dd9a91SJeremy L Thompson     CeedOperator *sub_operators;
302d8dd9a91SJeremy L Thompson 
303d8dd9a91SJeremy L Thompson     ierr = CeedOperatorGetNumSub(op, &num_sub); CeedChk(ierr);
304d8dd9a91SJeremy L Thompson     ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr);
3053668ca4bSJeremy L Thompson     if (num_sub != field_label->num_sub_labels)
3063668ca4bSJeremy L Thompson       // LCOV_EXCL_START
3073668ca4bSJeremy L Thompson       return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED,
3083668ca4bSJeremy L Thompson                        "ContextLabel does not correspond to composite operator.\n"
3093668ca4bSJeremy L Thompson                        "Use CeedOperatorGetContextFieldLabel().");
3103668ca4bSJeremy L Thompson     // LCOV_EXCL_STOP
311d8dd9a91SJeremy L Thompson 
312d8dd9a91SJeremy L Thompson     for (CeedInt i = 0; i < num_sub; i++) {
313d8dd9a91SJeremy L Thompson       // Try every sub-operator, ok if some sub-operators do not have field
3143668ca4bSJeremy L Thompson       if (field_label->sub_labels[i] && sub_operators[i]->qf->ctx) {
3153668ca4bSJeremy L Thompson         ierr = CeedQFunctionContextSetGeneric(sub_operators[i]->qf->ctx,
3163668ca4bSJeremy L Thompson                                               field_label->sub_labels[i],
3173668ca4bSJeremy L Thompson                                               field_type, value); CeedChk(ierr);
318d8dd9a91SJeremy L Thompson       }
319d8dd9a91SJeremy L Thompson     }
320d8dd9a91SJeremy L Thompson   } else {
321d8dd9a91SJeremy L Thompson     if (!op->qf->ctx)
322d8dd9a91SJeremy L Thompson       // LCOV_EXCL_START
323d8dd9a91SJeremy L Thompson       return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED,
324d8dd9a91SJeremy L Thompson                        "QFunction does not have context data");
325d8dd9a91SJeremy L Thompson     // LCOV_EXCL_STOP
326d8dd9a91SJeremy L Thompson 
3273668ca4bSJeremy L Thompson     ierr = CeedQFunctionContextSetGeneric(op->qf->ctx, field_label,
3283668ca4bSJeremy L Thompson                                           field_type, value); CeedChk(ierr);
329d8dd9a91SJeremy L Thompson   }
330d8dd9a91SJeremy L Thompson 
331d8dd9a91SJeremy L Thompson   return CEED_ERROR_SUCCESS;
332d8dd9a91SJeremy L Thompson }
333d8dd9a91SJeremy L Thompson 
3347a982d89SJeremy L. Thompson /// @}
3357a982d89SJeremy L. Thompson 
3367a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
3377a982d89SJeremy L. Thompson /// CeedOperator Backend API
3387a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
3397a982d89SJeremy L. Thompson /// @addtogroup CeedOperatorBackend
3407a982d89SJeremy L. Thompson /// @{
3417a982d89SJeremy L. Thompson 
3427a982d89SJeremy L. Thompson /**
3437a982d89SJeremy L. Thompson   @brief Get the number of arguments associated with a CeedOperator
3447a982d89SJeremy L. Thompson 
3457a982d89SJeremy L. Thompson   @param op             CeedOperator
346d1d35e2fSjeremylt   @param[out] num_args  Variable to store vector number of arguments
3477a982d89SJeremy L. Thompson 
3487a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
3497a982d89SJeremy L. Thompson 
3507a982d89SJeremy L. Thompson   @ref Backend
3517a982d89SJeremy L. Thompson **/
3527a982d89SJeremy L. Thompson 
353d1d35e2fSjeremylt int CeedOperatorGetNumArgs(CeedOperator op, CeedInt *num_args) {
354f04ea552SJeremy L Thompson   if (op->is_composite)
3557a982d89SJeremy L. Thompson     // LCOV_EXCL_START
356e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
357e15f9bd0SJeremy L Thompson                      "Not defined for composite operators");
3587a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
3597a982d89SJeremy L. Thompson 
360d1d35e2fSjeremylt   *num_args = op->num_fields;
361e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
3627a982d89SJeremy L. Thompson }
3637a982d89SJeremy L. Thompson 
3647a982d89SJeremy L. Thompson /**
3657a982d89SJeremy L. Thompson   @brief Get the setup status of a CeedOperator
3667a982d89SJeremy L. Thompson 
3677a982d89SJeremy L. Thompson   @param op                  CeedOperator
368d1d35e2fSjeremylt   @param[out] is_setup_done  Variable to store setup status
3697a982d89SJeremy L. Thompson 
3707a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
3717a982d89SJeremy L. Thompson 
3727a982d89SJeremy L. Thompson   @ref Backend
3737a982d89SJeremy L. Thompson **/
3747a982d89SJeremy L. Thompson 
375d1d35e2fSjeremylt int CeedOperatorIsSetupDone(CeedOperator op, bool *is_setup_done) {
376f04ea552SJeremy L Thompson   *is_setup_done = op->is_backend_setup;
377e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
3787a982d89SJeremy L. Thompson }
3797a982d89SJeremy L. Thompson 
3807a982d89SJeremy L. Thompson /**
3817a982d89SJeremy L. Thompson   @brief Get the QFunction associated with a CeedOperator
3827a982d89SJeremy L. Thompson 
3837a982d89SJeremy L. Thompson   @param op       CeedOperator
3847a982d89SJeremy L. Thompson   @param[out] qf  Variable to store QFunction
3857a982d89SJeremy L. Thompson 
3867a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
3877a982d89SJeremy L. Thompson 
3887a982d89SJeremy L. Thompson   @ref Backend
3897a982d89SJeremy L. Thompson **/
3907a982d89SJeremy L. Thompson 
3917a982d89SJeremy L. Thompson int CeedOperatorGetQFunction(CeedOperator op, CeedQFunction *qf) {
392f04ea552SJeremy L Thompson   if (op->is_composite)
3937a982d89SJeremy L. Thompson     // LCOV_EXCL_START
394e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
395e15f9bd0SJeremy L Thompson                      "Not defined for composite operator");
3967a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
3977a982d89SJeremy L. Thompson 
3987a982d89SJeremy L. Thompson   *qf = op->qf;
399e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
4007a982d89SJeremy L. Thompson }
4017a982d89SJeremy L. Thompson 
4027a982d89SJeremy L. Thompson /**
403c04a41a7SJeremy L Thompson   @brief Get a boolean value indicating if the CeedOperator is composite
404c04a41a7SJeremy L Thompson 
405c04a41a7SJeremy L Thompson   @param op                 CeedOperator
406d1d35e2fSjeremylt   @param[out] is_composite  Variable to store composite status
407c04a41a7SJeremy L Thompson 
408c04a41a7SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
409c04a41a7SJeremy L Thompson 
410c04a41a7SJeremy L Thompson   @ref Backend
411c04a41a7SJeremy L Thompson **/
412c04a41a7SJeremy L Thompson 
413d1d35e2fSjeremylt int CeedOperatorIsComposite(CeedOperator op, bool *is_composite) {
414f04ea552SJeremy L Thompson   *is_composite = op->is_composite;
415e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
416c04a41a7SJeremy L Thompson }
417c04a41a7SJeremy L Thompson 
418c04a41a7SJeremy L Thompson /**
419d1d35e2fSjeremylt   @brief Get the number of sub_operators associated with a CeedOperator
4207a982d89SJeremy L. Thompson 
4217a982d89SJeremy L. Thompson   @param op                     CeedOperator
422d1d35e2fSjeremylt   @param[out] num_suboperators  Variable to store number of sub_operators
4237a982d89SJeremy L. Thompson 
4247a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
4257a982d89SJeremy L. Thompson 
4267a982d89SJeremy L. Thompson   @ref Backend
4277a982d89SJeremy L. Thompson **/
4287a982d89SJeremy L. Thompson 
429d1d35e2fSjeremylt int CeedOperatorGetNumSub(CeedOperator op, CeedInt *num_suboperators) {
430f04ea552SJeremy L Thompson   if (!op->is_composite)
4317a982d89SJeremy L. Thompson     // LCOV_EXCL_START
432e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR, "Not a composite operator");
4337a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
4347a982d89SJeremy L. Thompson 
435d1d35e2fSjeremylt   *num_suboperators = op->num_suboperators;
436e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
4377a982d89SJeremy L. Thompson }
4387a982d89SJeremy L. Thompson 
4397a982d89SJeremy L. Thompson /**
440d1d35e2fSjeremylt   @brief Get the list of sub_operators associated with a CeedOperator
4417a982d89SJeremy L. Thompson 
4427a982d89SJeremy L. Thompson   @param op                  CeedOperator
443d1d35e2fSjeremylt   @param[out] sub_operators  Variable to store list of sub_operators
4447a982d89SJeremy L. Thompson 
4457a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
4467a982d89SJeremy L. Thompson 
4477a982d89SJeremy L. Thompson   @ref Backend
4487a982d89SJeremy L. Thompson **/
4497a982d89SJeremy L. Thompson 
450d1d35e2fSjeremylt int CeedOperatorGetSubList(CeedOperator op, CeedOperator **sub_operators) {
451f04ea552SJeremy L Thompson   if (!op->is_composite)
4527a982d89SJeremy L. Thompson     // LCOV_EXCL_START
453e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR, "Not a composite operator");
4547a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
4557a982d89SJeremy L. Thompson 
456d1d35e2fSjeremylt   *sub_operators = op->sub_operators;
457e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
4587a982d89SJeremy L. Thompson }
4597a982d89SJeremy L. Thompson 
4607a982d89SJeremy L. Thompson /**
4617a982d89SJeremy L. Thompson   @brief Get the backend data of a CeedOperator
4627a982d89SJeremy L. Thompson 
4637a982d89SJeremy L. Thompson   @param op         CeedOperator
4647a982d89SJeremy L. Thompson   @param[out] data  Variable to store data
4657a982d89SJeremy L. Thompson 
4667a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
4677a982d89SJeremy L. Thompson 
4687a982d89SJeremy L. Thompson   @ref Backend
4697a982d89SJeremy L. Thompson **/
4707a982d89SJeremy L. Thompson 
471777ff853SJeremy L Thompson int CeedOperatorGetData(CeedOperator op, void *data) {
472777ff853SJeremy L Thompson   *(void **)data = op->data;
473e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
4747a982d89SJeremy L. Thompson }
4757a982d89SJeremy L. Thompson 
4767a982d89SJeremy L. Thompson /**
4777a982d89SJeremy L. Thompson   @brief Set the backend data of a CeedOperator
4787a982d89SJeremy L. Thompson 
4797a982d89SJeremy L. Thompson   @param[out] op  CeedOperator
4807a982d89SJeremy L. Thompson   @param data     Data to set
4817a982d89SJeremy L. Thompson 
4827a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
4837a982d89SJeremy L. Thompson 
4847a982d89SJeremy L. Thompson   @ref Backend
4857a982d89SJeremy L. Thompson **/
4867a982d89SJeremy L. Thompson 
487777ff853SJeremy L Thompson int CeedOperatorSetData(CeedOperator op, void *data) {
488777ff853SJeremy L Thompson   op->data = data;
489e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
4907a982d89SJeremy L. Thompson }
4917a982d89SJeremy L. Thompson 
4927a982d89SJeremy L. Thompson /**
49334359f16Sjeremylt   @brief Increment the reference counter for a CeedOperator
49434359f16Sjeremylt 
49534359f16Sjeremylt   @param op  CeedOperator to increment the reference counter
49634359f16Sjeremylt 
49734359f16Sjeremylt   @return An error code: 0 - success, otherwise - failure
49834359f16Sjeremylt 
49934359f16Sjeremylt   @ref Backend
50034359f16Sjeremylt **/
5019560d06aSjeremylt int CeedOperatorReference(CeedOperator op) {
50234359f16Sjeremylt   op->ref_count++;
50334359f16Sjeremylt   return CEED_ERROR_SUCCESS;
50434359f16Sjeremylt }
50534359f16Sjeremylt 
50634359f16Sjeremylt /**
5077a982d89SJeremy L. Thompson   @brief Set the setup flag of a CeedOperator to True
5087a982d89SJeremy L. Thompson 
5097a982d89SJeremy L. Thompson   @param op  CeedOperator
5107a982d89SJeremy L. Thompson 
5117a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5127a982d89SJeremy L. Thompson 
5137a982d89SJeremy L. Thompson   @ref Backend
5147a982d89SJeremy L. Thompson **/
5157a982d89SJeremy L. Thompson 
5167a982d89SJeremy L. Thompson int CeedOperatorSetSetupDone(CeedOperator op) {
517f04ea552SJeremy L Thompson   op->is_backend_setup = true;
518e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5197a982d89SJeremy L. Thompson }
5207a982d89SJeremy L. Thompson 
5217a982d89SJeremy L. Thompson /// @}
5227a982d89SJeremy L. Thompson 
5237a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
5247a982d89SJeremy L. Thompson /// CeedOperator Public API
5257a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
5267a982d89SJeremy L. Thompson /// @addtogroup CeedOperatorUser
527dfdf5a53Sjeremylt /// @{
528d7b241e6Sjeremylt 
529d7b241e6Sjeremylt /**
5300219ea01SJeremy L Thompson   @brief Create a CeedOperator and associate a CeedQFunction. A CeedBasis and
5310219ea01SJeremy L Thompson            CeedElemRestriction can be associated with CeedQFunction fields with
5320219ea01SJeremy L Thompson            \ref CeedOperatorSetField.
533d7b241e6Sjeremylt 
534b11c1e72Sjeremylt   @param ceed     A Ceed object where the CeedOperator will be created
535d7b241e6Sjeremylt   @param qf       QFunction defining the action of the operator at quadrature points
53634138859Sjeremylt   @param dqf      QFunction defining the action of the Jacobian of @a qf (or
5374cc79fe7SJed Brown                     @ref CEED_QFUNCTION_NONE)
538d7b241e6Sjeremylt   @param dqfT     QFunction defining the action of the transpose of the Jacobian
5394cc79fe7SJed Brown                     of @a qf (or @ref CEED_QFUNCTION_NONE)
540b11c1e72Sjeremylt   @param[out] op  Address of the variable where the newly created
541b11c1e72Sjeremylt                     CeedOperator will be stored
542b11c1e72Sjeremylt 
543b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
544dfdf5a53Sjeremylt 
5457a982d89SJeremy L. Thompson   @ref User
546d7b241e6Sjeremylt  */
547d7b241e6Sjeremylt int CeedOperatorCreate(Ceed ceed, CeedQFunction qf, CeedQFunction dqf,
548d7b241e6Sjeremylt                        CeedQFunction dqfT, CeedOperator *op) {
549d7b241e6Sjeremylt   int ierr;
550d7b241e6Sjeremylt 
5515fe0d4faSjeremylt   if (!ceed->OperatorCreate) {
5525fe0d4faSjeremylt     Ceed delegate;
553aefd8378Sjeremylt     ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr);
5545fe0d4faSjeremylt 
5555fe0d4faSjeremylt     if (!delegate)
556c042f62fSJeremy L Thompson       // LCOV_EXCL_START
557e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_UNSUPPORTED,
558e15f9bd0SJeremy L Thompson                        "Backend does not support OperatorCreate");
559c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
5605fe0d4faSjeremylt 
5615fe0d4faSjeremylt     ierr = CeedOperatorCreate(delegate, qf, dqf, dqfT, op); CeedChk(ierr);
562e15f9bd0SJeremy L Thompson     return CEED_ERROR_SUCCESS;
5635fe0d4faSjeremylt   }
5645fe0d4faSjeremylt 
565b3b7035fSJeremy L Thompson   if (!qf || qf == CEED_QFUNCTION_NONE)
566b3b7035fSJeremy L Thompson     // LCOV_EXCL_START
567e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_MINOR,
568e15f9bd0SJeremy L Thompson                      "Operator must have a valid QFunction.");
569b3b7035fSJeremy L Thompson   // LCOV_EXCL_STOP
570d7b241e6Sjeremylt   ierr = CeedCalloc(1, op); CeedChk(ierr);
571d7b241e6Sjeremylt   (*op)->ceed = ceed;
5729560d06aSjeremylt   ierr = CeedReference(ceed); CeedChk(ierr);
573d1d35e2fSjeremylt   (*op)->ref_count = 1;
574d7b241e6Sjeremylt   (*op)->qf = qf;
575*2b104005SJeremy L Thompson   (*op)->input_size = -1;
576*2b104005SJeremy L Thompson   (*op)->output_size = -1;
5779560d06aSjeremylt   ierr = CeedQFunctionReference(qf); CeedChk(ierr);
578442e7f0bSjeremylt   if (dqf && dqf != CEED_QFUNCTION_NONE) {
579d7b241e6Sjeremylt     (*op)->dqf = dqf;
5809560d06aSjeremylt     ierr = CeedQFunctionReference(dqf); CeedChk(ierr);
581442e7f0bSjeremylt   }
582442e7f0bSjeremylt   if (dqfT && dqfT != CEED_QFUNCTION_NONE) {
583d7b241e6Sjeremylt     (*op)->dqfT = dqfT;
5849560d06aSjeremylt     ierr = CeedQFunctionReference(dqfT); CeedChk(ierr);
585442e7f0bSjeremylt   }
586480fae85SJeremy L Thompson   ierr = CeedQFunctionAssemblyDataCreate(ceed, &(*op)->qf_assembled);
587480fae85SJeremy L Thompson   CeedChk(ierr);
588bf4cb664SJeremy L Thompson   ierr = CeedCalloc(CEED_FIELD_MAX, &(*op)->input_fields); CeedChk(ierr);
589bf4cb664SJeremy L Thompson   ierr = CeedCalloc(CEED_FIELD_MAX, &(*op)->output_fields); CeedChk(ierr);
590d7b241e6Sjeremylt   ierr = ceed->OperatorCreate(*op); CeedChk(ierr);
591e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
592d7b241e6Sjeremylt }
593d7b241e6Sjeremylt 
594d7b241e6Sjeremylt /**
59552d6035fSJeremy L Thompson   @brief Create an operator that composes the action of several operators
59652d6035fSJeremy L Thompson 
59752d6035fSJeremy L Thompson   @param ceed     A Ceed object where the CeedOperator will be created
59852d6035fSJeremy L Thompson   @param[out] op  Address of the variable where the newly created
59952d6035fSJeremy L Thompson                     Composite CeedOperator will be stored
60052d6035fSJeremy L Thompson 
60152d6035fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
60252d6035fSJeremy L Thompson 
6037a982d89SJeremy L. Thompson   @ref User
60452d6035fSJeremy L Thompson  */
60552d6035fSJeremy L Thompson int CeedCompositeOperatorCreate(Ceed ceed, CeedOperator *op) {
60652d6035fSJeremy L Thompson   int ierr;
60752d6035fSJeremy L Thompson 
60852d6035fSJeremy L Thompson   if (!ceed->CompositeOperatorCreate) {
60952d6035fSJeremy L Thompson     Ceed delegate;
610aefd8378Sjeremylt     ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr);
61152d6035fSJeremy L Thompson 
612250756a7Sjeremylt     if (delegate) {
61352d6035fSJeremy L Thompson       ierr = CeedCompositeOperatorCreate(delegate, op); CeedChk(ierr);
614e15f9bd0SJeremy L Thompson       return CEED_ERROR_SUCCESS;
61552d6035fSJeremy L Thompson     }
616250756a7Sjeremylt   }
61752d6035fSJeremy L Thompson 
61852d6035fSJeremy L Thompson   ierr = CeedCalloc(1, op); CeedChk(ierr);
61952d6035fSJeremy L Thompson   (*op)->ceed = ceed;
6209560d06aSjeremylt   ierr = CeedReference(ceed); CeedChk(ierr);
621f04ea552SJeremy L Thompson   (*op)->is_composite = true;
622bf4cb664SJeremy L Thompson   ierr = CeedCalloc(CEED_COMPOSITE_MAX, &(*op)->sub_operators); CeedChk(ierr);
623*2b104005SJeremy L Thompson   (*op)->input_size = -1;
624*2b104005SJeremy L Thompson   (*op)->output_size = -1;
625250756a7Sjeremylt 
626250756a7Sjeremylt   if (ceed->CompositeOperatorCreate) {
62752d6035fSJeremy L Thompson     ierr = ceed->CompositeOperatorCreate(*op); CeedChk(ierr);
628250756a7Sjeremylt   }
629e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
63052d6035fSJeremy L Thompson }
63152d6035fSJeremy L Thompson 
63252d6035fSJeremy L Thompson /**
6339560d06aSjeremylt   @brief Copy the pointer to a CeedOperator. Both pointers should
6349560d06aSjeremylt            be destroyed with `CeedOperatorDestroy()`;
6359560d06aSjeremylt            Note: If `*op_copy` is non-NULL, then it is assumed that
6369560d06aSjeremylt            `*op_copy` is a pointer to a CeedOperator. This
6379560d06aSjeremylt            CeedOperator will be destroyed if `*op_copy` is the only
6389560d06aSjeremylt            reference to this CeedOperator.
6399560d06aSjeremylt 
6409560d06aSjeremylt   @param op            CeedOperator to copy reference to
6419560d06aSjeremylt   @param[out] op_copy  Variable to store copied reference
6429560d06aSjeremylt 
6439560d06aSjeremylt   @return An error code: 0 - success, otherwise - failure
6449560d06aSjeremylt 
6459560d06aSjeremylt   @ref User
6469560d06aSjeremylt **/
6479560d06aSjeremylt int CeedOperatorReferenceCopy(CeedOperator op, CeedOperator *op_copy) {
6489560d06aSjeremylt   int ierr;
6499560d06aSjeremylt 
6509560d06aSjeremylt   ierr = CeedOperatorReference(op); CeedChk(ierr);
6519560d06aSjeremylt   ierr = CeedOperatorDestroy(op_copy); CeedChk(ierr);
6529560d06aSjeremylt   *op_copy = op;
6539560d06aSjeremylt   return CEED_ERROR_SUCCESS;
6549560d06aSjeremylt }
6559560d06aSjeremylt 
6569560d06aSjeremylt /**
657b11c1e72Sjeremylt   @brief Provide a field to a CeedOperator for use by its CeedQFunction
658d7b241e6Sjeremylt 
659d7b241e6Sjeremylt   This function is used to specify both active and passive fields to a
660d7b241e6Sjeremylt   CeedOperator.  For passive fields, a vector @arg v must be provided.  Passive
661d7b241e6Sjeremylt   fields can inputs or outputs (updated in-place when operator is applied).
662d7b241e6Sjeremylt 
663d7b241e6Sjeremylt   Active fields must be specified using this function, but their data (in a
664d7b241e6Sjeremylt   CeedVector) is passed in CeedOperatorApply().  There can be at most one active
665d7b241e6Sjeremylt   input and at most one active output.
666d7b241e6Sjeremylt 
6678c91a0c9SJeremy L Thompson   @param op          CeedOperator on which to provide the field
668d1d35e2fSjeremylt   @param field_name  Name of the field (to be matched with the name used by
6698795c945Sjeremylt                        CeedQFunction)
670b11c1e72Sjeremylt   @param r           CeedElemRestriction
6714cc79fe7SJed Brown   @param b           CeedBasis in which the field resides or @ref CEED_BASIS_COLLOCATED
672b11c1e72Sjeremylt                        if collocated with quadrature points
6734cc79fe7SJed Brown   @param v           CeedVector to be used by CeedOperator or @ref CEED_VECTOR_ACTIVE
6744cc79fe7SJed Brown                        if field is active or @ref CEED_VECTOR_NONE if using
6754cc79fe7SJed Brown                        @ref CEED_EVAL_WEIGHT in the QFunction
676b11c1e72Sjeremylt 
677b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
678dfdf5a53Sjeremylt 
6797a982d89SJeremy L. Thompson   @ref User
680b11c1e72Sjeremylt **/
681d1d35e2fSjeremylt int CeedOperatorSetField(CeedOperator op, const char *field_name,
682a8d32208Sjeremylt                          CeedElemRestriction r, CeedBasis b, CeedVector v) {
683d7b241e6Sjeremylt   int ierr;
684f04ea552SJeremy L Thompson   if (op->is_composite)
685c042f62fSJeremy L Thompson     // LCOV_EXCL_START
686e1e9e29dSJed Brown     return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
687e15f9bd0SJeremy L Thompson                      "Cannot add field to composite operator.");
688c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
689f04ea552SJeremy L Thompson   if (op->is_immutable)
690f04ea552SJeremy L Thompson     // LCOV_EXCL_START
691f04ea552SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MAJOR,
692f04ea552SJeremy L Thompson                      "Operator cannot be changed after set as immutable");
693f04ea552SJeremy L Thompson   // LCOV_EXCL_STOP
6948b067b84SJed Brown   if (!r)
695c042f62fSJeremy L Thompson     // LCOV_EXCL_START
696e1e9e29dSJed Brown     return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
697c042f62fSJeremy L Thompson                      "ElemRestriction r for field \"%s\" must be non-NULL.",
698d1d35e2fSjeremylt                      field_name);
699c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
7008b067b84SJed Brown   if (!b)
701c042f62fSJeremy L Thompson     // LCOV_EXCL_START
702e1e9e29dSJed Brown     return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
703e15f9bd0SJeremy L Thompson                      "Basis b for field \"%s\" must be non-NULL.",
704d1d35e2fSjeremylt                      field_name);
705c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
7068b067b84SJed Brown   if (!v)
707c042f62fSJeremy L Thompson     // LCOV_EXCL_START
708e1e9e29dSJed Brown     return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
709e15f9bd0SJeremy L Thompson                      "Vector v for field \"%s\" must be non-NULL.",
710d1d35e2fSjeremylt                      field_name);
711c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
71252d6035fSJeremy L Thompson 
713d1d35e2fSjeremylt   CeedInt num_elem;
714d1d35e2fSjeremylt   ierr = CeedElemRestrictionGetNumElements(r, &num_elem); CeedChk(ierr);
715d1d35e2fSjeremylt   if (r != CEED_ELEMRESTRICTION_NONE && op->has_restriction &&
716d1d35e2fSjeremylt       op->num_elem != num_elem)
717c042f62fSJeremy L Thompson     // LCOV_EXCL_START
718e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_DIMENSION,
7191d102b48SJeremy L Thompson                      "ElemRestriction with %d elements incompatible with prior "
720d1d35e2fSjeremylt                      "%d elements", num_elem, op->num_elem);
721c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
722d7b241e6Sjeremylt 
72378464608Sjeremylt   CeedInt num_qpts = 0;
724e15f9bd0SJeremy L Thompson   if (b != CEED_BASIS_COLLOCATED) {
725d1d35e2fSjeremylt     ierr = CeedBasisGetNumQuadraturePoints(b, &num_qpts); CeedChk(ierr);
726d1d35e2fSjeremylt     if (op->num_qpts && op->num_qpts != num_qpts)
727c042f62fSJeremy L Thompson       // LCOV_EXCL_START
728e15f9bd0SJeremy L Thompson       return CeedError(op->ceed, CEED_ERROR_DIMENSION,
729e15f9bd0SJeremy L Thompson                        "Basis with %d quadrature points "
730d1d35e2fSjeremylt                        "incompatible with prior %d points", num_qpts,
731d1d35e2fSjeremylt                        op->num_qpts);
732c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
733d7b241e6Sjeremylt   }
734d1d35e2fSjeremylt   CeedQFunctionField qf_field;
735d1d35e2fSjeremylt   CeedOperatorField *op_field;
736*2b104005SJeremy L Thompson   bool is_input = true;
737d1d35e2fSjeremylt   for (CeedInt i=0; i<op->qf->num_input_fields; i++) {
738d1d35e2fSjeremylt     if (!strcmp(field_name, (*op->qf->input_fields[i]).field_name)) {
739d1d35e2fSjeremylt       qf_field = op->qf->input_fields[i];
740d1d35e2fSjeremylt       op_field = &op->input_fields[i];
741d7b241e6Sjeremylt       goto found;
742d7b241e6Sjeremylt     }
743d7b241e6Sjeremylt   }
744*2b104005SJeremy L Thompson   is_input = false;
745d1d35e2fSjeremylt   for (CeedInt i=0; i<op->qf->num_output_fields; i++) {
746d1d35e2fSjeremylt     if (!strcmp(field_name, (*op->qf->output_fields[i]).field_name)) {
747d1d35e2fSjeremylt       qf_field = op->qf->output_fields[i];
748d1d35e2fSjeremylt       op_field = &op->output_fields[i];
749d7b241e6Sjeremylt       goto found;
750d7b241e6Sjeremylt     }
751d7b241e6Sjeremylt   }
752c042f62fSJeremy L Thompson   // LCOV_EXCL_START
753e15f9bd0SJeremy L Thompson   return CeedError(op->ceed, CEED_ERROR_INCOMPLETE,
754e15f9bd0SJeremy L Thompson                    "QFunction has no knowledge of field '%s'",
755d1d35e2fSjeremylt                    field_name);
756c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
757d7b241e6Sjeremylt found:
758d1d35e2fSjeremylt   ierr = CeedOperatorCheckField(op->ceed, qf_field, r, b); CeedChk(ierr);
759d1d35e2fSjeremylt   ierr = CeedCalloc(1, op_field); CeedChk(ierr);
760e15f9bd0SJeremy L Thompson 
761*2b104005SJeremy L Thompson   if (v == CEED_VECTOR_ACTIVE) {
762*2b104005SJeremy L Thompson     CeedSize l_size;
763*2b104005SJeremy L Thompson     ierr = CeedElemRestrictionGetLVectorSize(r, &l_size); CeedChk(ierr);
764*2b104005SJeremy L Thompson     if (is_input) {
765*2b104005SJeremy L Thompson       if (op->input_size == -1) op->input_size = l_size;
766*2b104005SJeremy L Thompson       if (l_size != op->input_size)
767*2b104005SJeremy L Thompson         // LCOV_EXCL_START
768*2b104005SJeremy L Thompson         return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
769*2b104005SJeremy L Thompson                          "LVector size %td does not match previous size %td",
770*2b104005SJeremy L Thompson                          l_size, op->input_size);
771*2b104005SJeremy L Thompson       // LCOV_EXCL_STOP
772*2b104005SJeremy L Thompson     } else {
773*2b104005SJeremy L Thompson       if (op->output_size == -1) op->output_size = l_size;
774*2b104005SJeremy L Thompson       if (l_size != op->output_size)
775*2b104005SJeremy L Thompson         // LCOV_EXCL_START
776*2b104005SJeremy L Thompson         return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
777*2b104005SJeremy L Thompson                          "LVector size %td does not match previous size %td",
778*2b104005SJeremy L Thompson                          l_size, op->output_size);
779*2b104005SJeremy L Thompson       // LCOV_EXCL_STOP
780*2b104005SJeremy L Thompson     }
781*2b104005SJeremy L Thompson   }
782*2b104005SJeremy L Thompson 
783d1d35e2fSjeremylt   (*op_field)->vec = v;
784e15f9bd0SJeremy L Thompson   if (v != CEED_VECTOR_ACTIVE && v != CEED_VECTOR_NONE) {
7859560d06aSjeremylt     ierr = CeedVectorReference(v); CeedChk(ierr);
786e15f9bd0SJeremy L Thompson   }
787e15f9bd0SJeremy L Thompson 
788d1d35e2fSjeremylt   (*op_field)->elem_restr = r;
7899560d06aSjeremylt   ierr = CeedElemRestrictionReference(r); CeedChk(ierr);
790e15f9bd0SJeremy L Thompson   if (r != CEED_ELEMRESTRICTION_NONE) {
791d1d35e2fSjeremylt     op->num_elem = num_elem;
792d1d35e2fSjeremylt     op->has_restriction = true; // Restriction set, but num_elem may be 0
793e15f9bd0SJeremy L Thompson   }
794d99fa3c5SJeremy L Thompson 
795d1d35e2fSjeremylt   (*op_field)->basis = b;
796e15f9bd0SJeremy L Thompson   if (b != CEED_BASIS_COLLOCATED) {
797cd4dfc48Sjeremylt     if (!op->num_qpts) {
798cd4dfc48Sjeremylt       ierr = CeedOperatorSetNumQuadraturePoints(op, num_qpts); CeedChk(ierr);
799cd4dfc48Sjeremylt     }
8009560d06aSjeremylt     ierr = CeedBasisReference(b); CeedChk(ierr);
801e15f9bd0SJeremy L Thompson   }
802e15f9bd0SJeremy L Thompson 
803d1d35e2fSjeremylt   op->num_fields += 1;
804f7e22acaSJeremy L Thompson   ierr = CeedStringAllocCopy(field_name, (char **)&(*op_field)->field_name);
805f7e22acaSJeremy L Thompson   CeedChk(ierr);
806e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
807d7b241e6Sjeremylt }
808d7b241e6Sjeremylt 
809d7b241e6Sjeremylt /**
81043bbe138SJeremy L Thompson   @brief Get the CeedOperatorFields of a CeedOperator
81143bbe138SJeremy L Thompson 
812f04ea552SJeremy L Thompson   Note: Calling this function asserts that setup is complete
813f04ea552SJeremy L Thompson           and sets the CeedOperator as immutable.
814f04ea552SJeremy L Thompson 
81543bbe138SJeremy L Thompson   @param op                      CeedOperator
816f74ec584SJeremy L Thompson   @param[out] num_input_fields   Variable to store number of input fields
81743bbe138SJeremy L Thompson   @param[out] input_fields       Variable to store input_fields
818f74ec584SJeremy L Thompson   @param[out] num_output_fields  Variable to store number of output fields
81943bbe138SJeremy L Thompson   @param[out] output_fields      Variable to store output_fields
82043bbe138SJeremy L Thompson 
82143bbe138SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
82243bbe138SJeremy L Thompson 
823e9b533fbSJeremy L Thompson   @ref Advanced
82443bbe138SJeremy L Thompson **/
82543bbe138SJeremy L Thompson int CeedOperatorGetFields(CeedOperator op, CeedInt *num_input_fields,
82643bbe138SJeremy L Thompson                           CeedOperatorField **input_fields,
82743bbe138SJeremy L Thompson                           CeedInt *num_output_fields,
82843bbe138SJeremy L Thompson                           CeedOperatorField **output_fields) {
829f04ea552SJeremy L Thompson   int ierr;
830f04ea552SJeremy L Thompson 
831f04ea552SJeremy L Thompson   if (op->is_composite)
83243bbe138SJeremy L Thompson     // LCOV_EXCL_START
83343bbe138SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
83443bbe138SJeremy L Thompson                      "Not defined for composite operator");
83543bbe138SJeremy L Thompson   // LCOV_EXCL_STOP
836f04ea552SJeremy L Thompson   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
83743bbe138SJeremy L Thompson 
83843bbe138SJeremy L Thompson   if (num_input_fields) *num_input_fields = op->qf->num_input_fields;
83943bbe138SJeremy L Thompson   if (input_fields) *input_fields = op->input_fields;
84043bbe138SJeremy L Thompson   if (num_output_fields) *num_output_fields = op->qf->num_output_fields;
84143bbe138SJeremy L Thompson   if (output_fields) *output_fields = op->output_fields;
84243bbe138SJeremy L Thompson   return CEED_ERROR_SUCCESS;
84343bbe138SJeremy L Thompson }
84443bbe138SJeremy L Thompson 
84543bbe138SJeremy L Thompson /**
84628567f8fSJeremy L Thompson   @brief Get the name of a CeedOperatorField
84728567f8fSJeremy L Thompson 
84828567f8fSJeremy L Thompson   @param op_field         CeedOperatorField
84928567f8fSJeremy L Thompson   @param[out] field_name  Variable to store the field name
85028567f8fSJeremy L Thompson 
85128567f8fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
85228567f8fSJeremy L Thompson 
853e9b533fbSJeremy L Thompson   @ref Advanced
85428567f8fSJeremy L Thompson **/
85528567f8fSJeremy L Thompson int CeedOperatorFieldGetName(CeedOperatorField op_field, char **field_name) {
85628567f8fSJeremy L Thompson   *field_name = (char *)op_field->field_name;
85728567f8fSJeremy L Thompson   return CEED_ERROR_SUCCESS;
85828567f8fSJeremy L Thompson }
85928567f8fSJeremy L Thompson 
86028567f8fSJeremy L Thompson /**
86143bbe138SJeremy L Thompson   @brief Get the CeedElemRestriction of a CeedOperatorField
86243bbe138SJeremy L Thompson 
86343bbe138SJeremy L Thompson   @param op_field   CeedOperatorField
86443bbe138SJeremy L Thompson   @param[out] rstr  Variable to store CeedElemRestriction
86543bbe138SJeremy L Thompson 
86643bbe138SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
86743bbe138SJeremy L Thompson 
868e9b533fbSJeremy L Thompson   @ref Advanced
86943bbe138SJeremy L Thompson **/
87043bbe138SJeremy L Thompson int CeedOperatorFieldGetElemRestriction(CeedOperatorField op_field,
87143bbe138SJeremy L Thompson                                         CeedElemRestriction *rstr) {
87243bbe138SJeremy L Thompson   *rstr = op_field->elem_restr;
87343bbe138SJeremy L Thompson   return CEED_ERROR_SUCCESS;
87443bbe138SJeremy L Thompson }
87543bbe138SJeremy L Thompson 
87643bbe138SJeremy L Thompson /**
87743bbe138SJeremy L Thompson   @brief Get the CeedBasis of a CeedOperatorField
87843bbe138SJeremy L Thompson 
87943bbe138SJeremy L Thompson   @param op_field    CeedOperatorField
88043bbe138SJeremy L Thompson   @param[out] basis  Variable to store CeedBasis
88143bbe138SJeremy L Thompson 
88243bbe138SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
88343bbe138SJeremy L Thompson 
884e9b533fbSJeremy L Thompson   @ref Advanced
88543bbe138SJeremy L Thompson **/
88643bbe138SJeremy L Thompson int CeedOperatorFieldGetBasis(CeedOperatorField op_field, CeedBasis *basis) {
88743bbe138SJeremy L Thompson   *basis = op_field->basis;
88843bbe138SJeremy L Thompson   return CEED_ERROR_SUCCESS;
88943bbe138SJeremy L Thompson }
89043bbe138SJeremy L Thompson 
89143bbe138SJeremy L Thompson /**
89243bbe138SJeremy L Thompson   @brief Get the CeedVector of a CeedOperatorField
89343bbe138SJeremy L Thompson 
89443bbe138SJeremy L Thompson   @param op_field  CeedOperatorField
89543bbe138SJeremy L Thompson   @param[out] vec  Variable to store CeedVector
89643bbe138SJeremy L Thompson 
89743bbe138SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
89843bbe138SJeremy L Thompson 
899e9b533fbSJeremy L Thompson   @ref Advanced
90043bbe138SJeremy L Thompson **/
90143bbe138SJeremy L Thompson int CeedOperatorFieldGetVector(CeedOperatorField op_field, CeedVector *vec) {
90243bbe138SJeremy L Thompson   *vec = op_field->vec;
90343bbe138SJeremy L Thompson   return CEED_ERROR_SUCCESS;
90443bbe138SJeremy L Thompson }
90543bbe138SJeremy L Thompson 
90643bbe138SJeremy L Thompson /**
90752d6035fSJeremy L Thompson   @brief Add a sub-operator to a composite CeedOperator
908288c0443SJeremy L Thompson 
909d1d35e2fSjeremylt   @param[out] composite_op  Composite CeedOperator
910d1d35e2fSjeremylt   @param      sub_op        Sub-operator CeedOperator
91152d6035fSJeremy L Thompson 
91252d6035fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
91352d6035fSJeremy L Thompson 
9147a982d89SJeremy L. Thompson   @ref User
91552d6035fSJeremy L Thompson  */
916d1d35e2fSjeremylt int CeedCompositeOperatorAddSub(CeedOperator composite_op,
917d1d35e2fSjeremylt                                 CeedOperator sub_op) {
91834359f16Sjeremylt   int ierr;
91934359f16Sjeremylt 
920f04ea552SJeremy L Thompson   if (!composite_op->is_composite)
921c042f62fSJeremy L Thompson     // LCOV_EXCL_START
922d1d35e2fSjeremylt     return CeedError(composite_op->ceed, CEED_ERROR_MINOR,
923e2f04181SAndrew T. Barker                      "CeedOperator is not a composite operator");
924c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
92552d6035fSJeremy L Thompson 
926d1d35e2fSjeremylt   if (composite_op->num_suboperators == CEED_COMPOSITE_MAX)
927c042f62fSJeremy L Thompson     // LCOV_EXCL_START
928d1d35e2fSjeremylt     return CeedError(composite_op->ceed, CEED_ERROR_UNSUPPORTED,
929*2b104005SJeremy L Thompson                      "Cannot add additional sub-operators");
930c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
931f04ea552SJeremy L Thompson   if (composite_op->is_immutable)
932f04ea552SJeremy L Thompson     // LCOV_EXCL_START
933f04ea552SJeremy L Thompson     return CeedError(composite_op->ceed, CEED_ERROR_MAJOR,
934f04ea552SJeremy L Thompson                      "Operator cannot be changed after set as immutable");
935f04ea552SJeremy L Thompson   // LCOV_EXCL_STOP
93652d6035fSJeremy L Thompson 
937*2b104005SJeremy L Thompson   {
938*2b104005SJeremy L Thompson     CeedSize input_size, output_size;
939*2b104005SJeremy L Thompson     ierr = CeedOperatorGetActiveVectorLengths(sub_op, &input_size, &output_size);
940*2b104005SJeremy L Thompson     CeedChk(ierr);
941*2b104005SJeremy L Thompson     if (composite_op->input_size == -1) composite_op->input_size = input_size;
942*2b104005SJeremy L Thompson     if (composite_op->output_size == -1) composite_op->output_size = output_size;
943*2b104005SJeremy L Thompson     // Note, a size of -1 means no active vector restriction set, so no incompatibility
944*2b104005SJeremy L Thompson     if ((input_size != -1 && input_size != composite_op->input_size) ||
945*2b104005SJeremy L Thompson         (output_size != -1 && output_size != composite_op->output_size))
946*2b104005SJeremy L Thompson       // LCOV_EXCL_START
947*2b104005SJeremy L Thompson       return CeedError(composite_op->ceed, CEED_ERROR_MAJOR,
948*2b104005SJeremy L Thompson                        "Sub-operators must have compatible dimensions; "
949*2b104005SJeremy L Thompson                        "composite operator of shape (%td, %td) not compatible with "
950*2b104005SJeremy L Thompson                        "sub-operator of shape (%td, %td)",
951*2b104005SJeremy L Thompson                        composite_op->input_size, composite_op->output_size, input_size, output_size);
952*2b104005SJeremy L Thompson     // LCOV_EXCL_STOP
953*2b104005SJeremy L Thompson   }
954*2b104005SJeremy L Thompson 
955d1d35e2fSjeremylt   composite_op->sub_operators[composite_op->num_suboperators] = sub_op;
9569560d06aSjeremylt   ierr = CeedOperatorReference(sub_op); CeedChk(ierr);
957d1d35e2fSjeremylt   composite_op->num_suboperators++;
958e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
95952d6035fSJeremy L Thompson }
96052d6035fSJeremy L Thompson 
96152d6035fSJeremy L Thompson /**
9624db537f9SJeremy L Thompson   @brief Check if a CeedOperator is ready to be used.
9634db537f9SJeremy L Thompson 
9644db537f9SJeremy L Thompson   @param[in] op  CeedOperator to check
9654db537f9SJeremy L Thompson 
9664db537f9SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
9674db537f9SJeremy L Thompson 
9684db537f9SJeremy L Thompson   @ref User
9694db537f9SJeremy L Thompson **/
9704db537f9SJeremy L Thompson int CeedOperatorCheckReady(CeedOperator op) {
9714db537f9SJeremy L Thompson   int ierr;
9724db537f9SJeremy L Thompson   Ceed ceed;
9734db537f9SJeremy L Thompson   ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr);
9744db537f9SJeremy L Thompson 
9754db537f9SJeremy L Thompson   if (op->is_interface_setup)
9764db537f9SJeremy L Thompson     return CEED_ERROR_SUCCESS;
9774db537f9SJeremy L Thompson 
9784db537f9SJeremy L Thompson   CeedQFunction qf = op->qf;
9794db537f9SJeremy L Thompson   if (op->is_composite) {
9804db537f9SJeremy L Thompson     if (!op->num_suboperators)
9814db537f9SJeremy L Thompson       // LCOV_EXCL_START
9824db537f9SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_INCOMPLETE, "No sub_operators set");
9834db537f9SJeremy L Thompson     // LCOV_EXCL_STOP
9844db537f9SJeremy L Thompson     for (CeedInt i = 0; i < op->num_suboperators; i++) {
9854db537f9SJeremy L Thompson       ierr = CeedOperatorCheckReady(op->sub_operators[i]); CeedChk(ierr);
9864db537f9SJeremy L Thompson     }
987*2b104005SJeremy L Thompson     // Sub-operators could be modified after adding to composite operator
988*2b104005SJeremy L Thompson     // Need to verify no lvec incompatibility from any changes
989*2b104005SJeremy L Thompson     CeedSize input_size, output_size;
990*2b104005SJeremy L Thompson     ierr = CeedOperatorGetActiveVectorLengths(op, &input_size, &output_size);
991*2b104005SJeremy L Thompson     CeedChk(ierr);
9924db537f9SJeremy L Thompson   } else {
9934db537f9SJeremy L Thompson     if (op->num_fields == 0)
9944db537f9SJeremy L Thompson       // LCOV_EXCL_START
9954db537f9SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_INCOMPLETE, "No operator fields set");
9964db537f9SJeremy L Thompson     // LCOV_EXCL_STOP
9974db537f9SJeremy L Thompson     if (op->num_fields < qf->num_input_fields + qf->num_output_fields)
9984db537f9SJeremy L Thompson       // LCOV_EXCL_START
9994db537f9SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_INCOMPLETE, "Not all operator fields set");
10004db537f9SJeremy L Thompson     // LCOV_EXCL_STOP
10014db537f9SJeremy L Thompson     if (!op->has_restriction)
10024db537f9SJeremy L Thompson       // LCOV_EXCL_START
10034db537f9SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_INCOMPLETE,
10044db537f9SJeremy L Thompson                        "At least one restriction required");
10054db537f9SJeremy L Thompson     // LCOV_EXCL_STOP
10064db537f9SJeremy L Thompson     if (op->num_qpts == 0)
10074db537f9SJeremy L Thompson       // LCOV_EXCL_START
10084db537f9SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_INCOMPLETE,
10094db537f9SJeremy L Thompson                        "At least one non-collocated basis is required "
10104db537f9SJeremy L Thompson                        "or the number of quadrature points must be set");
10114db537f9SJeremy L Thompson     // LCOV_EXCL_STOP
10124db537f9SJeremy L Thompson   }
10134db537f9SJeremy L Thompson 
10144db537f9SJeremy L Thompson   // Flag as immutable and ready
10154db537f9SJeremy L Thompson   op->is_interface_setup = true;
10164db537f9SJeremy L Thompson   if (op->qf && op->qf != CEED_QFUNCTION_NONE)
10174db537f9SJeremy L Thompson     // LCOV_EXCL_START
10184db537f9SJeremy L Thompson     op->qf->is_immutable = true;
10194db537f9SJeremy L Thompson   // LCOV_EXCL_STOP
10204db537f9SJeremy L Thompson   if (op->dqf && op->dqf != CEED_QFUNCTION_NONE)
10214db537f9SJeremy L Thompson     // LCOV_EXCL_START
10224db537f9SJeremy L Thompson     op->dqf->is_immutable = true;
10234db537f9SJeremy L Thompson   // LCOV_EXCL_STOP
10244db537f9SJeremy L Thompson   if (op->dqfT && op->dqfT != CEED_QFUNCTION_NONE)
10254db537f9SJeremy L Thompson     // LCOV_EXCL_START
10264db537f9SJeremy L Thompson     op->dqfT->is_immutable = true;
10274db537f9SJeremy L Thompson   // LCOV_EXCL_STOP
10284db537f9SJeremy L Thompson   return CEED_ERROR_SUCCESS;
10294db537f9SJeremy L Thompson }
10304db537f9SJeremy L Thompson 
10314db537f9SJeremy L Thompson /**
1032c9366a6bSJeremy L Thompson   @brief Get vector lengths for the active input and/or output vectors of a CeedOperator.
1033c9366a6bSJeremy L Thompson            Note: Lengths of -1 indicate that the CeedOperator does not have an
1034c9366a6bSJeremy L Thompson            active input and/or output.
1035c9366a6bSJeremy L Thompson 
1036c9366a6bSJeremy L Thompson   @param[in] op           CeedOperator
1037c9366a6bSJeremy L Thompson   @param[out] input_size  Variable to store active input vector length, or NULL
1038c9366a6bSJeremy L Thompson   @param[out] output_size Variable to store active output vector length, or NULL
1039c9366a6bSJeremy L Thompson 
1040c9366a6bSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1041c9366a6bSJeremy L Thompson 
1042c9366a6bSJeremy L Thompson   @ref User
1043c9366a6bSJeremy L Thompson **/
1044c9366a6bSJeremy L Thompson int CeedOperatorGetActiveVectorLengths(CeedOperator op, CeedSize *input_size,
1045c9366a6bSJeremy L Thompson                                        CeedSize *output_size) {
1046c9366a6bSJeremy L Thompson   int ierr;
1047c9366a6bSJeremy L Thompson   bool is_composite;
1048c9366a6bSJeremy L Thompson 
1049*2b104005SJeremy L Thompson   if (input_size) *input_size = op->input_size;
1050*2b104005SJeremy L Thompson   if (output_size) *output_size = op->output_size;
1051c9366a6bSJeremy L Thompson 
1052c9366a6bSJeremy L Thompson   ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr);
1053*2b104005SJeremy L Thompson   if (is_composite && (op->input_size == -1 || op->output_size == -1)) {
1054c9366a6bSJeremy L Thompson     for (CeedInt i = 0; i < op->num_suboperators; i++) {
1055c9366a6bSJeremy L Thompson       CeedSize sub_input_size, sub_output_size;
1056c9366a6bSJeremy L Thompson       ierr = CeedOperatorGetActiveVectorLengths(op->sub_operators[i],
1057*2b104005SJeremy L Thompson              &sub_input_size, &sub_output_size); CeedChk(ierr);
1058*2b104005SJeremy L Thompson       if (op->input_size == -1) op->input_size = sub_input_size;
1059*2b104005SJeremy L Thompson       if (op->output_size == -1) op->output_size = sub_output_size;
1060*2b104005SJeremy L Thompson       // Note, a size of -1 means no active vector restriction set, so no incompatibility
1061*2b104005SJeremy L Thompson       if ((sub_input_size != -1 && sub_input_size != op->input_size) ||
1062*2b104005SJeremy L Thompson           (sub_output_size != -1 && sub_output_size != op->output_size))
1063*2b104005SJeremy L Thompson         // LCOV_EXCL_START
1064*2b104005SJeremy L Thompson         return CeedError(op->ceed, CEED_ERROR_MAJOR,
1065*2b104005SJeremy L Thompson                          "Sub-operators must have compatible dimensions; "
1066*2b104005SJeremy L Thompson                          "composite operator of shape (%td, %td) not compatible with "
1067*2b104005SJeremy L Thompson                          "sub-operator of shape (%td, %td)",
1068*2b104005SJeremy L Thompson                          op->input_size, op->output_size, input_size, output_size);
1069*2b104005SJeremy L Thompson       // LCOV_EXCL_STOP
1070c9366a6bSJeremy L Thompson     }
1071c9366a6bSJeremy L Thompson   }
1072c9366a6bSJeremy L Thompson 
1073c9366a6bSJeremy L Thompson   return CEED_ERROR_SUCCESS;
1074c9366a6bSJeremy L Thompson }
1075c9366a6bSJeremy L Thompson 
1076c9366a6bSJeremy L Thompson /**
1077beecbf24SJeremy L Thompson   @brief Set reuse of CeedQFunction data in CeedOperatorLinearAssemble* functions.
1078beecbf24SJeremy L Thompson            When `reuse_assembly_data = false` (default), the CeedQFunction associated
1079beecbf24SJeremy L Thompson            with this CeedOperator is re-assembled every time a `CeedOperatorLinearAssemble*`
1080beecbf24SJeremy L Thompson            function is called.
1081beecbf24SJeremy L Thompson            When `reuse_assembly_data = true`, the CeedQFunction associated with
1082beecbf24SJeremy L Thompson            this CeedOperator is reused between calls to
1083beecbf24SJeremy L Thompson            `CeedOperatorSetQFunctionAssemblyDataUpdated`.
10848b919e6bSJeremy L Thompson 
1085beecbf24SJeremy L Thompson   @param[in] op                  CeedOperator
1086beecbf24SJeremy L Thompson   @param[in] reuse_assembly_data Boolean flag setting assembly data reuse
10878b919e6bSJeremy L Thompson 
10888b919e6bSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
10898b919e6bSJeremy L Thompson 
10908b919e6bSJeremy L Thompson   @ref Advanced
10918b919e6bSJeremy L Thompson **/
1092beecbf24SJeremy L Thompson int CeedOperatorSetQFunctionAssemblyReuse(CeedOperator op,
1093beecbf24SJeremy L Thompson     bool reuse_assembly_data) {
10948b919e6bSJeremy L Thompson   int ierr;
10958b919e6bSJeremy L Thompson   bool is_composite;
10968b919e6bSJeremy L Thompson 
10978b919e6bSJeremy L Thompson   ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr);
10988b919e6bSJeremy L Thompson   if (is_composite) {
10998b919e6bSJeremy L Thompson     for (CeedInt i = 0; i < op->num_suboperators; i++) {
1100beecbf24SJeremy L Thompson       ierr = CeedOperatorSetQFunctionAssemblyReuse(op->sub_operators[i],
1101beecbf24SJeremy L Thompson              reuse_assembly_data); CeedChk(ierr);
11028b919e6bSJeremy L Thompson     }
11038b919e6bSJeremy L Thompson   } else {
1104beecbf24SJeremy L Thompson     ierr = CeedQFunctionAssemblyDataSetReuse(op->qf_assembled, reuse_assembly_data);
1105beecbf24SJeremy L Thompson     CeedChk(ierr);
1106beecbf24SJeremy L Thompson   }
1107beecbf24SJeremy L Thompson 
1108beecbf24SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1109beecbf24SJeremy L Thompson }
1110beecbf24SJeremy L Thompson 
1111beecbf24SJeremy L Thompson /**
1112beecbf24SJeremy L Thompson   @brief Mark CeedQFunction data as updated and the CeedQFunction as requiring re-assembly.
1113beecbf24SJeremy L Thompson 
1114beecbf24SJeremy L Thompson   @param[in] op                  CeedOperator
1115beecbf24SJeremy L Thompson   @param[in] reuse_assembly_data Boolean flag setting assembly data reuse
1116beecbf24SJeremy L Thompson 
1117beecbf24SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1118beecbf24SJeremy L Thompson 
1119beecbf24SJeremy L Thompson   @ref Advanced
1120beecbf24SJeremy L Thompson **/
1121beecbf24SJeremy L Thompson int CeedOperatorSetQFunctionAssemblyDataUpdateNeeded(CeedOperator op,
1122beecbf24SJeremy L Thompson     bool needs_data_update) {
1123beecbf24SJeremy L Thompson   int ierr;
1124beecbf24SJeremy L Thompson   bool is_composite;
1125beecbf24SJeremy L Thompson 
1126beecbf24SJeremy L Thompson   ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr);
1127beecbf24SJeremy L Thompson   if (is_composite) {
1128beecbf24SJeremy L Thompson     for (CeedInt i = 0; i < op->num_suboperators; i++) {
1129beecbf24SJeremy L Thompson       ierr = CeedOperatorSetQFunctionAssemblyDataUpdateNeeded(op->sub_operators[i],
1130beecbf24SJeremy L Thompson              needs_data_update); CeedChk(ierr);
1131beecbf24SJeremy L Thompson     }
1132beecbf24SJeremy L Thompson   } else {
1133beecbf24SJeremy L Thompson     ierr = CeedQFunctionAssemblyDataSetUpdateNeeded(op->qf_assembled,
1134beecbf24SJeremy L Thompson            needs_data_update);
11358b919e6bSJeremy L Thompson     CeedChk(ierr);
11368b919e6bSJeremy L Thompson   }
11378b919e6bSJeremy L Thompson 
11388b919e6bSJeremy L Thompson   return CEED_ERROR_SUCCESS;
11398b919e6bSJeremy L Thompson }
11408b919e6bSJeremy L Thompson 
11418b919e6bSJeremy L Thompson /**
1142cd4dfc48Sjeremylt   @brief Set the number of quadrature points associated with a CeedOperator.
1143cd4dfc48Sjeremylt            This should be used when creating a CeedOperator where every
1144cd4dfc48Sjeremylt            field has a collocated basis. This function cannot be used for
1145cd4dfc48Sjeremylt            composite CeedOperators.
1146cd4dfc48Sjeremylt 
1147cd4dfc48Sjeremylt   @param op        CeedOperator
1148cd4dfc48Sjeremylt   @param num_qpts  Number of quadrature points to set
1149cd4dfc48Sjeremylt 
1150cd4dfc48Sjeremylt   @return An error code: 0 - success, otherwise - failure
1151cd4dfc48Sjeremylt 
1152e9b533fbSJeremy L Thompson   @ref Advanced
1153cd4dfc48Sjeremylt **/
1154cd4dfc48Sjeremylt int CeedOperatorSetNumQuadraturePoints(CeedOperator op, CeedInt num_qpts) {
1155f04ea552SJeremy L Thompson   if (op->is_composite)
1156cd4dfc48Sjeremylt     // LCOV_EXCL_START
1157cd4dfc48Sjeremylt     return CeedError(op->ceed, CEED_ERROR_MINOR,
1158cd4dfc48Sjeremylt                      "Not defined for composite operator");
1159cd4dfc48Sjeremylt   // LCOV_EXCL_STOP
1160cd4dfc48Sjeremylt   if (op->num_qpts)
1161cd4dfc48Sjeremylt     // LCOV_EXCL_START
1162cd4dfc48Sjeremylt     return CeedError(op->ceed, CEED_ERROR_MINOR,
1163cd4dfc48Sjeremylt                      "Number of quadrature points already defined");
1164cd4dfc48Sjeremylt   // LCOV_EXCL_STOP
1165f04ea552SJeremy L Thompson   if (op->is_immutable)
1166f04ea552SJeremy L Thompson     // LCOV_EXCL_START
1167f04ea552SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MAJOR,
1168f04ea552SJeremy L Thompson                      "Operator cannot be changed after set as immutable");
1169f04ea552SJeremy L Thompson   // LCOV_EXCL_STOP
1170cd4dfc48Sjeremylt 
1171cd4dfc48Sjeremylt   op->num_qpts = num_qpts;
1172cd4dfc48Sjeremylt   return CEED_ERROR_SUCCESS;
1173cd4dfc48Sjeremylt }
1174cd4dfc48Sjeremylt 
1175cd4dfc48Sjeremylt /**
11767a982d89SJeremy L. Thompson   @brief View a CeedOperator
11777a982d89SJeremy L. Thompson 
11787a982d89SJeremy L. Thompson   @param[in] op      CeedOperator to view
11797a982d89SJeremy L. Thompson   @param[in] stream  Stream to write; typically stdout/stderr or a file
11807a982d89SJeremy L. Thompson 
11817a982d89SJeremy L. Thompson   @return Error code: 0 - success, otherwise - failure
11827a982d89SJeremy L. Thompson 
11837a982d89SJeremy L. Thompson   @ref User
11847a982d89SJeremy L. Thompson **/
11857a982d89SJeremy L. Thompson int CeedOperatorView(CeedOperator op, FILE *stream) {
11867a982d89SJeremy L. Thompson   int ierr;
11877a982d89SJeremy L. Thompson 
1188f04ea552SJeremy L Thompson   if (op->is_composite) {
11897a982d89SJeremy L. Thompson     fprintf(stream, "Composite CeedOperator\n");
11907a982d89SJeremy L. Thompson 
1191d1d35e2fSjeremylt     for (CeedInt i=0; i<op->num_suboperators; i++) {
11927a982d89SJeremy L. Thompson       fprintf(stream, "  SubOperator [%d]:\n", i);
1193d1d35e2fSjeremylt       ierr = CeedOperatorSingleView(op->sub_operators[i], 1, stream);
11947a982d89SJeremy L. Thompson       CeedChk(ierr);
11957a982d89SJeremy L. Thompson     }
11967a982d89SJeremy L. Thompson   } else {
11977a982d89SJeremy L. Thompson     fprintf(stream, "CeedOperator\n");
11987a982d89SJeremy L. Thompson     ierr = CeedOperatorSingleView(op, 0, stream); CeedChk(ierr);
11997a982d89SJeremy L. Thompson   }
1200e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
12017a982d89SJeremy L. Thompson }
12023bd813ffSjeremylt 
12033bd813ffSjeremylt /**
1204b7c9bbdaSJeremy L Thompson   @brief Get the Ceed associated with a CeedOperator
1205b7c9bbdaSJeremy L Thompson 
1206b7c9bbdaSJeremy L Thompson   @param op         CeedOperator
1207b7c9bbdaSJeremy L Thompson   @param[out] ceed  Variable to store Ceed
1208b7c9bbdaSJeremy L Thompson 
1209b7c9bbdaSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1210b7c9bbdaSJeremy L Thompson 
1211b7c9bbdaSJeremy L Thompson   @ref Advanced
1212b7c9bbdaSJeremy L Thompson **/
1213b7c9bbdaSJeremy L Thompson int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) {
1214b7c9bbdaSJeremy L Thompson   *ceed = op->ceed;
1215b7c9bbdaSJeremy L Thompson   return CEED_ERROR_SUCCESS;
1216b7c9bbdaSJeremy L Thompson }
1217b7c9bbdaSJeremy L Thompson 
1218b7c9bbdaSJeremy L Thompson /**
1219b7c9bbdaSJeremy L Thompson   @brief Get the number of elements associated with a CeedOperator
1220b7c9bbdaSJeremy L Thompson 
1221b7c9bbdaSJeremy L Thompson   @param op             CeedOperator
1222b7c9bbdaSJeremy L Thompson   @param[out] num_elem  Variable to store number of elements
1223b7c9bbdaSJeremy L Thompson 
1224b7c9bbdaSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1225b7c9bbdaSJeremy L Thompson 
1226b7c9bbdaSJeremy L Thompson   @ref Advanced
1227b7c9bbdaSJeremy L Thompson **/
1228b7c9bbdaSJeremy L Thompson int CeedOperatorGetNumElements(CeedOperator op, CeedInt *num_elem) {
1229b7c9bbdaSJeremy L Thompson   if (op->is_composite)
1230b7c9bbdaSJeremy L Thompson     // LCOV_EXCL_START
1231b7c9bbdaSJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
1232b7c9bbdaSJeremy L Thompson                      "Not defined for composite operator");
1233b7c9bbdaSJeremy L Thompson   // LCOV_EXCL_STOP
1234b7c9bbdaSJeremy L Thompson 
1235b7c9bbdaSJeremy L Thompson   *num_elem = op->num_elem;
1236b7c9bbdaSJeremy L Thompson   return CEED_ERROR_SUCCESS;
1237b7c9bbdaSJeremy L Thompson }
1238b7c9bbdaSJeremy L Thompson 
1239b7c9bbdaSJeremy L Thompson /**
1240b7c9bbdaSJeremy L Thompson   @brief Get the number of quadrature points associated with a CeedOperator
1241b7c9bbdaSJeremy L Thompson 
1242b7c9bbdaSJeremy L Thompson   @param op             CeedOperator
1243b7c9bbdaSJeremy L Thompson   @param[out] num_qpts  Variable to store vector number of quadrature points
1244b7c9bbdaSJeremy L Thompson 
1245b7c9bbdaSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1246b7c9bbdaSJeremy L Thompson 
1247b7c9bbdaSJeremy L Thompson   @ref Advanced
1248b7c9bbdaSJeremy L Thompson **/
1249b7c9bbdaSJeremy L Thompson int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *num_qpts) {
1250b7c9bbdaSJeremy L Thompson   if (op->is_composite)
1251b7c9bbdaSJeremy L Thompson     // LCOV_EXCL_START
1252b7c9bbdaSJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
1253b7c9bbdaSJeremy L Thompson                      "Not defined for composite operator");
1254b7c9bbdaSJeremy L Thompson   // LCOV_EXCL_STOP
1255b7c9bbdaSJeremy L Thompson 
1256b7c9bbdaSJeremy L Thompson   *num_qpts = op->num_qpts;
1257b7c9bbdaSJeremy L Thompson   return CEED_ERROR_SUCCESS;
1258b7c9bbdaSJeremy L Thompson }
1259b7c9bbdaSJeremy L Thompson 
1260b7c9bbdaSJeremy L Thompson /**
12613668ca4bSJeremy L Thompson   @brief Get label for a registered QFunctionContext field, or `NULL` if no
12623668ca4bSJeremy L Thompson            field has been registered with this `field_name`.
12633668ca4bSJeremy L Thompson 
12643668ca4bSJeremy L Thompson   @param[in] op            CeedOperator
12653668ca4bSJeremy L Thompson   @param[in] field_name    Name of field to retrieve label
12663668ca4bSJeremy L Thompson   @param[out] field_label  Variable to field label
12673668ca4bSJeremy L Thompson 
12683668ca4bSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
12693668ca4bSJeremy L Thompson 
12703668ca4bSJeremy L Thompson   @ref User
12713668ca4bSJeremy L Thompson **/
12723668ca4bSJeremy L Thompson int CeedOperatorContextGetFieldLabel(CeedOperator op,
12733668ca4bSJeremy L Thompson                                      const char *field_name,
12743668ca4bSJeremy L Thompson                                      CeedContextFieldLabel *field_label) {
12753668ca4bSJeremy L Thompson   int ierr;
12763668ca4bSJeremy L Thompson 
12773668ca4bSJeremy L Thompson   bool is_composite;
12783668ca4bSJeremy L Thompson   ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr);
12793668ca4bSJeremy L Thompson   if (is_composite) {
12803668ca4bSJeremy L Thompson     // Check if composite label already created
12813668ca4bSJeremy L Thompson     for (CeedInt i=0; i<op->num_context_labels; i++) {
12823668ca4bSJeremy L Thompson       if (!strcmp(op->context_labels[i]->name, field_name)) {
12833668ca4bSJeremy L Thompson         *field_label = op->context_labels[i];
12843668ca4bSJeremy L Thompson         return CEED_ERROR_SUCCESS;
12853668ca4bSJeremy L Thompson       }
12863668ca4bSJeremy L Thompson     }
12873668ca4bSJeremy L Thompson 
12883668ca4bSJeremy L Thompson     // Create composite label if needed
12893668ca4bSJeremy L Thompson     CeedInt num_sub;
12903668ca4bSJeremy L Thompson     CeedOperator *sub_operators;
12913668ca4bSJeremy L Thompson     CeedContextFieldLabel new_field_label;
12923668ca4bSJeremy L Thompson 
12933668ca4bSJeremy L Thompson     ierr = CeedCalloc(1, &new_field_label); CeedChk(ierr);
12943668ca4bSJeremy L Thompson     ierr = CeedOperatorGetNumSub(op, &num_sub); CeedChk(ierr);
12953668ca4bSJeremy L Thompson     ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr);
12963668ca4bSJeremy L Thompson     ierr = CeedCalloc(num_sub, &new_field_label->sub_labels); CeedChk(ierr);
12973668ca4bSJeremy L Thompson     new_field_label->num_sub_labels = num_sub;
12983668ca4bSJeremy L Thompson 
12993668ca4bSJeremy L Thompson     bool label_found = false;
13003668ca4bSJeremy L Thompson     for (CeedInt i=0; i<num_sub; i++) {
13013668ca4bSJeremy L Thompson       if (sub_operators[i]->qf->ctx) {
13023668ca4bSJeremy L Thompson         CeedContextFieldLabel new_field_label_i;
13033668ca4bSJeremy L Thompson         ierr = CeedQFunctionContextGetFieldLabel(sub_operators[i]->qf->ctx, field_name,
13043668ca4bSJeremy L Thompson                &new_field_label_i); CeedChk(ierr);
13053668ca4bSJeremy L Thompson         if (new_field_label_i) {
13063668ca4bSJeremy L Thompson           label_found = true;
13073668ca4bSJeremy L Thompson           new_field_label->sub_labels[i] = new_field_label_i;
13083668ca4bSJeremy L Thompson           new_field_label->name = new_field_label_i->name;
13093668ca4bSJeremy L Thompson           new_field_label->description = new_field_label_i->description;
13107bfe0f0eSJeremy L Thompson           if (new_field_label->type &&
13117bfe0f0eSJeremy L Thompson               new_field_label->type != new_field_label_i->type) {
13127bfe0f0eSJeremy L Thompson             // LCOV_EXCL_START
13137bfe0f0eSJeremy L Thompson             ierr = CeedFree(&new_field_label); CeedChk(ierr);
13147bfe0f0eSJeremy L Thompson             return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
13157bfe0f0eSJeremy L Thompson                              "Incompatible field types on sub-operator contexts. "
13167bfe0f0eSJeremy L Thompson                              "%s != %s",
13177bfe0f0eSJeremy L Thompson                              CeedContextFieldTypes[new_field_label->type],
13187bfe0f0eSJeremy L Thompson                              CeedContextFieldTypes[new_field_label_i->type]);
13197bfe0f0eSJeremy L Thompson             // LCOV_EXCL_STOP
13207bfe0f0eSJeremy L Thompson           } else {
13217bfe0f0eSJeremy L Thompson             new_field_label->type = new_field_label_i->type;
13227bfe0f0eSJeremy L Thompson           }
13237bfe0f0eSJeremy L Thompson           if (new_field_label->num_values != 0 &&
13247bfe0f0eSJeremy L Thompson               new_field_label->num_values != new_field_label_i->num_values) {
13257bfe0f0eSJeremy L Thompson             // LCOV_EXCL_START
13267bfe0f0eSJeremy L Thompson             ierr = CeedFree(&new_field_label); CeedChk(ierr);
13277bfe0f0eSJeremy L Thompson             return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
13287bfe0f0eSJeremy L Thompson                              "Incompatible field number of values on sub-operator"
13297bfe0f0eSJeremy L Thompson                              " contexts. %ld != %ld",
13307bfe0f0eSJeremy L Thompson                              new_field_label->num_values, new_field_label_i->num_values);
13317bfe0f0eSJeremy L Thompson             // LCOV_EXCL_STOP
13327bfe0f0eSJeremy L Thompson           } else {
13337bfe0f0eSJeremy L Thompson             new_field_label->num_values = new_field_label_i->num_values;
13347bfe0f0eSJeremy L Thompson           }
13353668ca4bSJeremy L Thompson         }
13363668ca4bSJeremy L Thompson       }
13373668ca4bSJeremy L Thompson     }
13383668ca4bSJeremy L Thompson     if (!label_found) {
13393668ca4bSJeremy L Thompson       // LCOV_EXCL_START
1340a48e5f43SJeremy L Thompson       ierr = CeedFree(&new_field_label->sub_labels); CeedChk(ierr);
13413668ca4bSJeremy L Thompson       ierr = CeedFree(&new_field_label); CeedChk(ierr);
13423668ca4bSJeremy L Thompson       *field_label = NULL;
13433668ca4bSJeremy L Thompson       // LCOV_EXCL_STOP
13443668ca4bSJeremy L Thompson     } else {
13453668ca4bSJeremy L Thompson       // Move new composite label to operator
13463668ca4bSJeremy L Thompson       if (op->num_context_labels == 0) {
13473668ca4bSJeremy L Thompson         ierr = CeedCalloc(1, &op->context_labels); CeedChk(ierr);
13483668ca4bSJeremy L Thompson         op->max_context_labels = 1;
13493668ca4bSJeremy L Thompson       } else if (op->num_context_labels == op->max_context_labels) {
13503668ca4bSJeremy L Thompson         ierr = CeedRealloc(2*op->num_context_labels, &op->context_labels);
13513668ca4bSJeremy L Thompson         CeedChk(ierr);
13523668ca4bSJeremy L Thompson         op->max_context_labels *= 2;
13533668ca4bSJeremy L Thompson       }
13543668ca4bSJeremy L Thompson       op->context_labels[op->num_context_labels] = new_field_label;
13553668ca4bSJeremy L Thompson       *field_label = new_field_label;
13563668ca4bSJeremy L Thompson       op->num_context_labels++;
13573668ca4bSJeremy L Thompson     }
13583668ca4bSJeremy L Thompson 
13593668ca4bSJeremy L Thompson     return CEED_ERROR_SUCCESS;
13603668ca4bSJeremy L Thompson   } else {
13613668ca4bSJeremy L Thompson     return CeedQFunctionContextGetFieldLabel(op->qf->ctx, field_name, field_label);
13623668ca4bSJeremy L Thompson   }
13633668ca4bSJeremy L Thompson }
13643668ca4bSJeremy L Thompson 
13653668ca4bSJeremy L Thompson /**
1366d8dd9a91SJeremy L Thompson   @brief Set QFunctionContext field holding a double precision value.
1367d8dd9a91SJeremy L Thompson            For composite operators, the value is set in all
1368d8dd9a91SJeremy L Thompson            sub-operator QFunctionContexts that have a matching `field_name`.
1369d8dd9a91SJeremy L Thompson 
1370d8dd9a91SJeremy L Thompson   @param op          CeedOperator
13713668ca4bSJeremy L Thompson   @param field_label Label of field to register
13727bfe0f0eSJeremy L Thompson   @param values      Values to set
1373d8dd9a91SJeremy L Thompson 
1374d8dd9a91SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1375d8dd9a91SJeremy L Thompson 
1376d8dd9a91SJeremy L Thompson   @ref User
1377d8dd9a91SJeremy L Thompson **/
13783668ca4bSJeremy L Thompson int CeedOperatorContextSetDouble(CeedOperator op,
13793668ca4bSJeremy L Thompson                                  CeedContextFieldLabel field_label,
13807bfe0f0eSJeremy L Thompson                                  double *values) {
13813668ca4bSJeremy L Thompson   return CeedOperatorContextSetGeneric(op, field_label, CEED_CONTEXT_FIELD_DOUBLE,
13827bfe0f0eSJeremy L Thompson                                        values);
1383d8dd9a91SJeremy L Thompson }
1384d8dd9a91SJeremy L Thompson 
1385d8dd9a91SJeremy L Thompson /**
1386d8dd9a91SJeremy L Thompson   @brief Set QFunctionContext field holding an int32 value.
1387d8dd9a91SJeremy L Thompson            For composite operators, the value is set in all
1388d8dd9a91SJeremy L Thompson            sub-operator QFunctionContexts that have a matching `field_name`.
1389d8dd9a91SJeremy L Thompson 
1390d8dd9a91SJeremy L Thompson   @param op          CeedOperator
13913668ca4bSJeremy L Thompson   @param field_label Label of field to set
13927bfe0f0eSJeremy L Thompson   @param values      Values to set
1393d8dd9a91SJeremy L Thompson 
1394d8dd9a91SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1395d8dd9a91SJeremy L Thompson 
1396d8dd9a91SJeremy L Thompson   @ref User
1397d8dd9a91SJeremy L Thompson **/
13983668ca4bSJeremy L Thompson int CeedOperatorContextSetInt32(CeedOperator op,
13993668ca4bSJeremy L Thompson                                 CeedContextFieldLabel field_label,
14007bfe0f0eSJeremy L Thompson                                 int *values) {
14013668ca4bSJeremy L Thompson   return CeedOperatorContextSetGeneric(op, field_label, CEED_CONTEXT_FIELD_INT32,
14027bfe0f0eSJeremy L Thompson                                        values);
1403d8dd9a91SJeremy L Thompson }
1404d8dd9a91SJeremy L Thompson 
1405d8dd9a91SJeremy L Thompson /**
14063bd813ffSjeremylt   @brief Apply CeedOperator to a vector
1407d7b241e6Sjeremylt 
1408d7b241e6Sjeremylt   This computes the action of the operator on the specified (active) input,
1409d7b241e6Sjeremylt   yielding its (active) output.  All inputs and outputs must be specified using
1410d7b241e6Sjeremylt   CeedOperatorSetField().
1411d7b241e6Sjeremylt 
1412f04ea552SJeremy L Thompson   Note: Calling this function asserts that setup is complete
1413f04ea552SJeremy L Thompson           and sets the CeedOperator as immutable.
1414f04ea552SJeremy L Thompson 
1415d7b241e6Sjeremylt   @param op        CeedOperator to apply
14164cc79fe7SJed Brown   @param[in] in    CeedVector containing input state or @ref CEED_VECTOR_NONE if
141734138859Sjeremylt                      there are no active inputs
1418b11c1e72Sjeremylt   @param[out] out  CeedVector to store result of applying operator (must be
14194cc79fe7SJed Brown                      distinct from @a in) or @ref CEED_VECTOR_NONE if there are no
142034138859Sjeremylt                      active outputs
1421d7b241e6Sjeremylt   @param request   Address of CeedRequest for non-blocking completion, else
14224cc79fe7SJed Brown                      @ref CEED_REQUEST_IMMEDIATE
1423b11c1e72Sjeremylt 
1424b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
1425dfdf5a53Sjeremylt 
14267a982d89SJeremy L. Thompson   @ref User
1427b11c1e72Sjeremylt **/
1428692c2638Sjeremylt int CeedOperatorApply(CeedOperator op, CeedVector in, CeedVector out,
1429692c2638Sjeremylt                       CeedRequest *request) {
1430d7b241e6Sjeremylt   int ierr;
1431e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
1432d7b241e6Sjeremylt 
1433d1d35e2fSjeremylt   if (op->num_elem)  {
1434250756a7Sjeremylt     // Standard Operator
1435cae8b89aSjeremylt     if (op->Apply) {
1436250756a7Sjeremylt       ierr = op->Apply(op, in, out, request); CeedChk(ierr);
1437cae8b89aSjeremylt     } else {
1438cae8b89aSjeremylt       // Zero all output vectors
1439250756a7Sjeremylt       CeedQFunction qf = op->qf;
1440d1d35e2fSjeremylt       for (CeedInt i=0; i<qf->num_output_fields; i++) {
1441d1d35e2fSjeremylt         CeedVector vec = op->output_fields[i]->vec;
1442cae8b89aSjeremylt         if (vec == CEED_VECTOR_ACTIVE)
1443cae8b89aSjeremylt           vec = out;
1444cae8b89aSjeremylt         if (vec != CEED_VECTOR_NONE) {
1445cae8b89aSjeremylt           ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr);
1446cae8b89aSjeremylt         }
1447cae8b89aSjeremylt       }
1448250756a7Sjeremylt       // Apply
1449250756a7Sjeremylt       ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr);
1450250756a7Sjeremylt     }
1451f04ea552SJeremy L Thompson   } else if (op->is_composite) {
1452250756a7Sjeremylt     // Composite Operator
1453250756a7Sjeremylt     if (op->ApplyComposite) {
1454250756a7Sjeremylt       ierr = op->ApplyComposite(op, in, out, request); CeedChk(ierr);
1455250756a7Sjeremylt     } else {
1456d1d35e2fSjeremylt       CeedInt num_suboperators;
1457d1d35e2fSjeremylt       ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr);
1458d1d35e2fSjeremylt       CeedOperator *sub_operators;
1459d1d35e2fSjeremylt       ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr);
1460250756a7Sjeremylt 
1461250756a7Sjeremylt       // Zero all output vectors
1462250756a7Sjeremylt       if (out != CEED_VECTOR_NONE) {
1463cae8b89aSjeremylt         ierr = CeedVectorSetValue(out, 0.0); CeedChk(ierr);
1464cae8b89aSjeremylt       }
1465d1d35e2fSjeremylt       for (CeedInt i=0; i<num_suboperators; i++) {
1466d1d35e2fSjeremylt         for (CeedInt j=0; j<sub_operators[i]->qf->num_output_fields; j++) {
1467d1d35e2fSjeremylt           CeedVector vec = sub_operators[i]->output_fields[j]->vec;
1468250756a7Sjeremylt           if (vec != CEED_VECTOR_ACTIVE && vec != CEED_VECTOR_NONE) {
1469250756a7Sjeremylt             ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr);
1470250756a7Sjeremylt           }
1471250756a7Sjeremylt         }
1472250756a7Sjeremylt       }
1473250756a7Sjeremylt       // Apply
1474d1d35e2fSjeremylt       for (CeedInt i=0; i<op->num_suboperators; i++) {
1475d1d35e2fSjeremylt         ierr = CeedOperatorApplyAdd(op->sub_operators[i], in, out, request);
1476cae8b89aSjeremylt         CeedChk(ierr);
1477cae8b89aSjeremylt       }
1478cae8b89aSjeremylt     }
1479250756a7Sjeremylt   }
1480e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1481cae8b89aSjeremylt }
1482cae8b89aSjeremylt 
1483cae8b89aSjeremylt /**
1484cae8b89aSjeremylt   @brief Apply CeedOperator to a vector and add result to output vector
1485cae8b89aSjeremylt 
1486cae8b89aSjeremylt   This computes the action of the operator on the specified (active) input,
1487cae8b89aSjeremylt   yielding its (active) output.  All inputs and outputs must be specified using
1488cae8b89aSjeremylt   CeedOperatorSetField().
1489cae8b89aSjeremylt 
1490cae8b89aSjeremylt   @param op        CeedOperator to apply
1491cae8b89aSjeremylt   @param[in] in    CeedVector containing input state or NULL if there are no
1492cae8b89aSjeremylt                      active inputs
1493cae8b89aSjeremylt   @param[out] out  CeedVector to sum in result of applying operator (must be
1494cae8b89aSjeremylt                      distinct from @a in) or NULL if there are no active outputs
1495cae8b89aSjeremylt   @param request   Address of CeedRequest for non-blocking completion, else
14964cc79fe7SJed Brown                      @ref CEED_REQUEST_IMMEDIATE
1497cae8b89aSjeremylt 
1498cae8b89aSjeremylt   @return An error code: 0 - success, otherwise - failure
1499cae8b89aSjeremylt 
15007a982d89SJeremy L. Thompson   @ref User
1501cae8b89aSjeremylt **/
1502cae8b89aSjeremylt int CeedOperatorApplyAdd(CeedOperator op, CeedVector in, CeedVector out,
1503cae8b89aSjeremylt                          CeedRequest *request) {
1504cae8b89aSjeremylt   int ierr;
1505e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
1506cae8b89aSjeremylt 
1507d1d35e2fSjeremylt   if (op->num_elem)  {
1508250756a7Sjeremylt     // Standard Operator
1509250756a7Sjeremylt     ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr);
1510f04ea552SJeremy L Thompson   } else if (op->is_composite) {
1511250756a7Sjeremylt     // Composite Operator
1512250756a7Sjeremylt     if (op->ApplyAddComposite) {
1513250756a7Sjeremylt       ierr = op->ApplyAddComposite(op, in, out, request); CeedChk(ierr);
1514cae8b89aSjeremylt     } else {
1515d1d35e2fSjeremylt       CeedInt num_suboperators;
1516d1d35e2fSjeremylt       ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr);
1517d1d35e2fSjeremylt       CeedOperator *sub_operators;
1518d1d35e2fSjeremylt       ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr);
1519250756a7Sjeremylt 
1520d1d35e2fSjeremylt       for (CeedInt i=0; i<num_suboperators; i++) {
1521d1d35e2fSjeremylt         ierr = CeedOperatorApplyAdd(sub_operators[i], in, out, request);
1522cae8b89aSjeremylt         CeedChk(ierr);
15231d7d2407SJeremy L Thompson       }
1524250756a7Sjeremylt     }
1525250756a7Sjeremylt   }
1526e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1527d7b241e6Sjeremylt }
1528d7b241e6Sjeremylt 
1529d7b241e6Sjeremylt /**
1530b11c1e72Sjeremylt   @brief Destroy a CeedOperator
1531d7b241e6Sjeremylt 
1532d7b241e6Sjeremylt   @param op  CeedOperator to destroy
1533b11c1e72Sjeremylt 
1534b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
1535dfdf5a53Sjeremylt 
15367a982d89SJeremy L. Thompson   @ref User
1537b11c1e72Sjeremylt **/
1538d7b241e6Sjeremylt int CeedOperatorDestroy(CeedOperator *op) {
1539d7b241e6Sjeremylt   int ierr;
1540d7b241e6Sjeremylt 
1541d1d35e2fSjeremylt   if (!*op || --(*op)->ref_count > 0) return CEED_ERROR_SUCCESS;
1542d7b241e6Sjeremylt   if ((*op)->Destroy) {
1543d7b241e6Sjeremylt     ierr = (*op)->Destroy(*op); CeedChk(ierr);
1544d7b241e6Sjeremylt   }
1545fe2413ffSjeremylt   ierr = CeedDestroy(&(*op)->ceed); CeedChk(ierr);
1546fe2413ffSjeremylt   // Free fields
15473668ca4bSJeremy L Thompson   for (CeedInt i=0; i<(*op)->num_fields; i++)
1548d1d35e2fSjeremylt     if ((*op)->input_fields[i]) {
1549d1d35e2fSjeremylt       if ((*op)->input_fields[i]->elem_restr != CEED_ELEMRESTRICTION_NONE) {
1550d1d35e2fSjeremylt         ierr = CeedElemRestrictionDestroy(&(*op)->input_fields[i]->elem_restr);
155171352a93Sjeremylt         CeedChk(ierr);
155215910d16Sjeremylt       }
1553d1d35e2fSjeremylt       if ((*op)->input_fields[i]->basis != CEED_BASIS_COLLOCATED) {
1554d1d35e2fSjeremylt         ierr = CeedBasisDestroy(&(*op)->input_fields[i]->basis); CeedChk(ierr);
155571352a93Sjeremylt       }
1556d1d35e2fSjeremylt       if ((*op)->input_fields[i]->vec != CEED_VECTOR_ACTIVE &&
1557d1d35e2fSjeremylt           (*op)->input_fields[i]->vec != CEED_VECTOR_NONE ) {
1558d1d35e2fSjeremylt         ierr = CeedVectorDestroy(&(*op)->input_fields[i]->vec); CeedChk(ierr);
155971352a93Sjeremylt       }
1560d1d35e2fSjeremylt       ierr = CeedFree(&(*op)->input_fields[i]->field_name); CeedChk(ierr);
1561d1d35e2fSjeremylt       ierr = CeedFree(&(*op)->input_fields[i]); CeedChk(ierr);
1562fe2413ffSjeremylt     }
15633668ca4bSJeremy L Thompson   for (CeedInt i=0; i<(*op)->num_fields; i++)
1564d1d35e2fSjeremylt     if ((*op)->output_fields[i]) {
1565d1d35e2fSjeremylt       ierr = CeedElemRestrictionDestroy(&(*op)->output_fields[i]->elem_restr);
156671352a93Sjeremylt       CeedChk(ierr);
1567d1d35e2fSjeremylt       if ((*op)->output_fields[i]->basis != CEED_BASIS_COLLOCATED) {
1568d1d35e2fSjeremylt         ierr = CeedBasisDestroy(&(*op)->output_fields[i]->basis); CeedChk(ierr);
156971352a93Sjeremylt       }
1570d1d35e2fSjeremylt       if ((*op)->output_fields[i]->vec != CEED_VECTOR_ACTIVE &&
1571d1d35e2fSjeremylt           (*op)->output_fields[i]->vec != CEED_VECTOR_NONE ) {
1572d1d35e2fSjeremylt         ierr = CeedVectorDestroy(&(*op)->output_fields[i]->vec); CeedChk(ierr);
157371352a93Sjeremylt       }
1574d1d35e2fSjeremylt       ierr = CeedFree(&(*op)->output_fields[i]->field_name); CeedChk(ierr);
1575d1d35e2fSjeremylt       ierr = CeedFree(&(*op)->output_fields[i]); CeedChk(ierr);
1576fe2413ffSjeremylt     }
1577d1d35e2fSjeremylt   // Destroy sub_operators
15783668ca4bSJeremy L Thompson   for (CeedInt i=0; i<(*op)->num_suboperators; i++)
1579d1d35e2fSjeremylt     if ((*op)->sub_operators[i]) {
1580d1d35e2fSjeremylt       ierr = CeedOperatorDestroy(&(*op)->sub_operators[i]); CeedChk(ierr);
158152d6035fSJeremy L Thompson     }
1582d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->qf); CeedChk(ierr);
1583d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->dqf); CeedChk(ierr);
1584d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->dqfT); CeedChk(ierr);
15853668ca4bSJeremy L Thompson   // Destroy any composite labels
15863668ca4bSJeremy L Thompson   for (CeedInt i=0; i<(*op)->num_context_labels; i++) {
15873668ca4bSJeremy L Thompson     ierr = CeedFree(&(*op)->context_labels[i]->sub_labels); CeedChk(ierr);
15883668ca4bSJeremy L Thompson     ierr = CeedFree(&(*op)->context_labels[i]); CeedChk(ierr);
15893668ca4bSJeremy L Thompson   }
15903668ca4bSJeremy L Thompson   ierr = CeedFree(&(*op)->context_labels); CeedChk(ierr);
1591fe2413ffSjeremylt 
15925107b09fSJeremy L Thompson   // Destroy fallback
1593d1d35e2fSjeremylt   if ((*op)->op_fallback) {
1594d1d35e2fSjeremylt     ierr = (*op)->qf_fallback->Destroy((*op)->qf_fallback); CeedChk(ierr);
1595d1d35e2fSjeremylt     ierr = CeedFree(&(*op)->qf_fallback); CeedChk(ierr);
1596d1d35e2fSjeremylt     ierr = (*op)->op_fallback->Destroy((*op)->op_fallback); CeedChk(ierr);
1597d1d35e2fSjeremylt     ierr = CeedFree(&(*op)->op_fallback); CeedChk(ierr);
15985107b09fSJeremy L Thompson   }
15995107b09fSJeremy L Thompson 
160070a7ffb3SJeremy L Thompson   // Destroy QF assembly cache
1601480fae85SJeremy L Thompson   ierr = CeedQFunctionAssemblyDataDestroy(&(*op)->qf_assembled); CeedChk(ierr);
160270a7ffb3SJeremy L Thompson 
1603d1d35e2fSjeremylt   ierr = CeedFree(&(*op)->input_fields); CeedChk(ierr);
1604d1d35e2fSjeremylt   ierr = CeedFree(&(*op)->output_fields); CeedChk(ierr);
1605d1d35e2fSjeremylt   ierr = CeedFree(&(*op)->sub_operators); CeedChk(ierr);
1606d7b241e6Sjeremylt   ierr = CeedFree(op); CeedChk(ierr);
1607e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1608d7b241e6Sjeremylt }
1609d7b241e6Sjeremylt 
1610d7b241e6Sjeremylt /// @}
1611