xref: /libCEED/rust/libceed-sys/c-src/interface/ceed-operator.c (revision f74ec58466a7eebc696fd6b461de38faeedc8431)
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 /**
207eaf62fffSJeremy L Thompson   @brief Find the active vector basis for a CeedOperator
208eaf62fffSJeremy L Thompson 
209eaf62fffSJeremy L Thompson   @param[in] op             CeedOperator to find active basis for
210eaf62fffSJeremy L Thompson   @param[out] active_basis  Basis for active input vector
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;
218eaf62fffSJeremy L Thompson   for (int i = 0; i < op->qf->num_input_fields; i++)
219eaf62fffSJeremy L Thompson     if (op->input_fields[i]->vec == CEED_VECTOR_ACTIVE) {
220eaf62fffSJeremy L Thompson       *active_basis = op->input_fields[i]->basis;
221eaf62fffSJeremy L Thompson       break;
222eaf62fffSJeremy L Thompson     }
223eaf62fffSJeremy L Thompson 
224eaf62fffSJeremy L Thompson   if (!*active_basis) {
225eaf62fffSJeremy L Thompson     // LCOV_EXCL_START
226eaf62fffSJeremy L Thompson     int ierr;
227eaf62fffSJeremy L Thompson     Ceed ceed;
228eaf62fffSJeremy L Thompson     ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr);
229eaf62fffSJeremy L Thompson     return CeedError(ceed, CEED_ERROR_MINOR,
230eaf62fffSJeremy L Thompson                      "No active CeedBasis found");
231eaf62fffSJeremy L Thompson     // LCOV_EXCL_STOP
232eaf62fffSJeremy L Thompson   }
233eaf62fffSJeremy L Thompson   return CEED_ERROR_SUCCESS;
234eaf62fffSJeremy L Thompson }
235eaf62fffSJeremy L Thompson 
236eaf62fffSJeremy L Thompson /**
237e2f04181SAndrew T. Barker   @brief Find the active vector ElemRestriction for a CeedOperator
238e2f04181SAndrew T. Barker 
239e2f04181SAndrew T. Barker   @param[in] op            CeedOperator to find active basis for
240d1d35e2fSjeremylt   @param[out] active_rstr  ElemRestriction for active input vector
241e2f04181SAndrew T. Barker 
242e2f04181SAndrew T. Barker   @return An error code: 0 - success, otherwise - failure
243e2f04181SAndrew T. Barker 
244e2f04181SAndrew T. Barker   @ref Utility
245e2f04181SAndrew T. Barker **/
246eaf62fffSJeremy L Thompson int CeedOperatorGetActiveElemRestriction(CeedOperator op,
247d1d35e2fSjeremylt     CeedElemRestriction *active_rstr) {
248d1d35e2fSjeremylt   *active_rstr = NULL;
249d1d35e2fSjeremylt   for (int i = 0; i < op->qf->num_input_fields; i++)
250d1d35e2fSjeremylt     if (op->input_fields[i]->vec == CEED_VECTOR_ACTIVE) {
251d1d35e2fSjeremylt       *active_rstr = op->input_fields[i]->elem_restr;
252e2f04181SAndrew T. Barker       break;
253e2f04181SAndrew T. Barker     }
254e2f04181SAndrew T. Barker 
255d1d35e2fSjeremylt   if (!*active_rstr) {
256e2f04181SAndrew T. Barker     // LCOV_EXCL_START
257e2f04181SAndrew T. Barker     int ierr;
258e2f04181SAndrew T. Barker     Ceed ceed;
259e2f04181SAndrew T. Barker     ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr);
260e2f04181SAndrew T. Barker     return CeedError(ceed, CEED_ERROR_INCOMPLETE,
261eaf62fffSJeremy L Thompson                      "No active CeedElemRestriction found");
262e2f04181SAndrew T. Barker     // LCOV_EXCL_STOP
263e2f04181SAndrew T. Barker   }
264e2f04181SAndrew T. Barker   return CEED_ERROR_SUCCESS;
265e2f04181SAndrew T. Barker }
266e2f04181SAndrew T. Barker 
2677a982d89SJeremy L. Thompson /// @}
2687a982d89SJeremy L. Thompson 
2697a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
2707a982d89SJeremy L. Thompson /// CeedOperator Backend API
2717a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
2727a982d89SJeremy L. Thompson /// @addtogroup CeedOperatorBackend
2737a982d89SJeremy L. Thompson /// @{
2747a982d89SJeremy L. Thompson 
2757a982d89SJeremy L. Thompson /**
2767a982d89SJeremy L. Thompson   @brief Get the number of arguments associated with a CeedOperator
2777a982d89SJeremy L. Thompson 
2787a982d89SJeremy L. Thompson   @param op             CeedOperator
279d1d35e2fSjeremylt   @param[out] num_args  Variable to store vector number of arguments
2807a982d89SJeremy L. Thompson 
2817a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
2827a982d89SJeremy L. Thompson 
2837a982d89SJeremy L. Thompson   @ref Backend
2847a982d89SJeremy L. Thompson **/
2857a982d89SJeremy L. Thompson 
286d1d35e2fSjeremylt int CeedOperatorGetNumArgs(CeedOperator op, CeedInt *num_args) {
287f04ea552SJeremy L Thompson   if (op->is_composite)
2887a982d89SJeremy L. Thompson     // LCOV_EXCL_START
289e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
290e15f9bd0SJeremy L Thompson                      "Not defined for composite operators");
2917a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
2927a982d89SJeremy L. Thompson 
293d1d35e2fSjeremylt   *num_args = op->num_fields;
294e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2957a982d89SJeremy L. Thompson }
2967a982d89SJeremy L. Thompson 
2977a982d89SJeremy L. Thompson /**
2987a982d89SJeremy L. Thompson   @brief Get the setup status of a CeedOperator
2997a982d89SJeremy L. Thompson 
3007a982d89SJeremy L. Thompson   @param op                  CeedOperator
301d1d35e2fSjeremylt   @param[out] is_setup_done  Variable to store setup status
3027a982d89SJeremy L. Thompson 
3037a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
3047a982d89SJeremy L. Thompson 
3057a982d89SJeremy L. Thompson   @ref Backend
3067a982d89SJeremy L. Thompson **/
3077a982d89SJeremy L. Thompson 
308d1d35e2fSjeremylt int CeedOperatorIsSetupDone(CeedOperator op, bool *is_setup_done) {
309f04ea552SJeremy L Thompson   *is_setup_done = op->is_backend_setup;
310e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
3117a982d89SJeremy L. Thompson }
3127a982d89SJeremy L. Thompson 
3137a982d89SJeremy L. Thompson /**
3147a982d89SJeremy L. Thompson   @brief Get the QFunction associated with a CeedOperator
3157a982d89SJeremy L. Thompson 
3167a982d89SJeremy L. Thompson   @param op       CeedOperator
3177a982d89SJeremy L. Thompson   @param[out] qf  Variable to store QFunction
3187a982d89SJeremy L. Thompson 
3197a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
3207a982d89SJeremy L. Thompson 
3217a982d89SJeremy L. Thompson   @ref Backend
3227a982d89SJeremy L. Thompson **/
3237a982d89SJeremy L. Thompson 
3247a982d89SJeremy L. Thompson int CeedOperatorGetQFunction(CeedOperator op, CeedQFunction *qf) {
325f04ea552SJeremy L Thompson   if (op->is_composite)
3267a982d89SJeremy L. Thompson     // LCOV_EXCL_START
327e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
328e15f9bd0SJeremy L Thompson                      "Not defined for composite operator");
3297a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
3307a982d89SJeremy L. Thompson 
3317a982d89SJeremy L. Thompson   *qf = op->qf;
332e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
3337a982d89SJeremy L. Thompson }
3347a982d89SJeremy L. Thompson 
3357a982d89SJeremy L. Thompson /**
336c04a41a7SJeremy L Thompson   @brief Get a boolean value indicating if the CeedOperator is composite
337c04a41a7SJeremy L Thompson 
338c04a41a7SJeremy L Thompson   @param op                 CeedOperator
339d1d35e2fSjeremylt   @param[out] is_composite  Variable to store composite status
340c04a41a7SJeremy L Thompson 
341c04a41a7SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
342c04a41a7SJeremy L Thompson 
343c04a41a7SJeremy L Thompson   @ref Backend
344c04a41a7SJeremy L Thompson **/
345c04a41a7SJeremy L Thompson 
346d1d35e2fSjeremylt int CeedOperatorIsComposite(CeedOperator op, bool *is_composite) {
347f04ea552SJeremy L Thompson   *is_composite = op->is_composite;
348e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
349c04a41a7SJeremy L Thompson }
350c04a41a7SJeremy L Thompson 
351c04a41a7SJeremy L Thompson /**
352d1d35e2fSjeremylt   @brief Get the number of sub_operators associated with a CeedOperator
3537a982d89SJeremy L. Thompson 
3547a982d89SJeremy L. Thompson   @param op                     CeedOperator
355d1d35e2fSjeremylt   @param[out] num_suboperators  Variable to store number of sub_operators
3567a982d89SJeremy L. Thompson 
3577a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
3587a982d89SJeremy L. Thompson 
3597a982d89SJeremy L. Thompson   @ref Backend
3607a982d89SJeremy L. Thompson **/
3617a982d89SJeremy L. Thompson 
362d1d35e2fSjeremylt int CeedOperatorGetNumSub(CeedOperator op, CeedInt *num_suboperators) {
363f04ea552SJeremy L Thompson   if (!op->is_composite)
3647a982d89SJeremy L. Thompson     // LCOV_EXCL_START
365e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR, "Not a composite operator");
3667a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
3677a982d89SJeremy L. Thompson 
368d1d35e2fSjeremylt   *num_suboperators = op->num_suboperators;
369e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
3707a982d89SJeremy L. Thompson }
3717a982d89SJeremy L. Thompson 
3727a982d89SJeremy L. Thompson /**
373d1d35e2fSjeremylt   @brief Get the list of sub_operators associated with a CeedOperator
3747a982d89SJeremy L. Thompson 
3757a982d89SJeremy L. Thompson   @param op                  CeedOperator
376d1d35e2fSjeremylt   @param[out] sub_operators  Variable to store list of sub_operators
3777a982d89SJeremy L. Thompson 
3787a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
3797a982d89SJeremy L. Thompson 
3807a982d89SJeremy L. Thompson   @ref Backend
3817a982d89SJeremy L. Thompson **/
3827a982d89SJeremy L. Thompson 
383d1d35e2fSjeremylt int CeedOperatorGetSubList(CeedOperator op, CeedOperator **sub_operators) {
384f04ea552SJeremy L Thompson   if (!op->is_composite)
3857a982d89SJeremy L. Thompson     // LCOV_EXCL_START
386e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR, "Not a composite operator");
3877a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
3887a982d89SJeremy L. Thompson 
389d1d35e2fSjeremylt   *sub_operators = op->sub_operators;
390e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
3917a982d89SJeremy L. Thompson }
3927a982d89SJeremy L. Thompson 
3937a982d89SJeremy L. Thompson /**
3947a982d89SJeremy L. Thompson   @brief Get the backend data of a CeedOperator
3957a982d89SJeremy L. Thompson 
3967a982d89SJeremy L. Thompson   @param op         CeedOperator
3977a982d89SJeremy L. Thompson   @param[out] data  Variable to store data
3987a982d89SJeremy L. Thompson 
3997a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
4007a982d89SJeremy L. Thompson 
4017a982d89SJeremy L. Thompson   @ref Backend
4027a982d89SJeremy L. Thompson **/
4037a982d89SJeremy L. Thompson 
404777ff853SJeremy L Thompson int CeedOperatorGetData(CeedOperator op, void *data) {
405777ff853SJeremy L Thompson   *(void **)data = op->data;
406e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
4077a982d89SJeremy L. Thompson }
4087a982d89SJeremy L. Thompson 
4097a982d89SJeremy L. Thompson /**
4107a982d89SJeremy L. Thompson   @brief Set the backend data of a CeedOperator
4117a982d89SJeremy L. Thompson 
4127a982d89SJeremy L. Thompson   @param[out] op  CeedOperator
4137a982d89SJeremy L. Thompson   @param data     Data to set
4147a982d89SJeremy L. Thompson 
4157a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
4167a982d89SJeremy L. Thompson 
4177a982d89SJeremy L. Thompson   @ref Backend
4187a982d89SJeremy L. Thompson **/
4197a982d89SJeremy L. Thompson 
420777ff853SJeremy L Thompson int CeedOperatorSetData(CeedOperator op, void *data) {
421777ff853SJeremy L Thompson   op->data = data;
422e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
4237a982d89SJeremy L. Thompson }
4247a982d89SJeremy L. Thompson 
4257a982d89SJeremy L. Thompson /**
42634359f16Sjeremylt   @brief Increment the reference counter for a CeedOperator
42734359f16Sjeremylt 
42834359f16Sjeremylt   @param op  CeedOperator to increment the reference counter
42934359f16Sjeremylt 
43034359f16Sjeremylt   @return An error code: 0 - success, otherwise - failure
43134359f16Sjeremylt 
43234359f16Sjeremylt   @ref Backend
43334359f16Sjeremylt **/
4349560d06aSjeremylt int CeedOperatorReference(CeedOperator op) {
43534359f16Sjeremylt   op->ref_count++;
43634359f16Sjeremylt   return CEED_ERROR_SUCCESS;
43734359f16Sjeremylt }
43834359f16Sjeremylt 
43934359f16Sjeremylt /**
4407a982d89SJeremy L. Thompson   @brief Set the setup flag of a CeedOperator to True
4417a982d89SJeremy L. Thompson 
4427a982d89SJeremy L. Thompson   @param op  CeedOperator
4437a982d89SJeremy L. Thompson 
4447a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
4457a982d89SJeremy L. Thompson 
4467a982d89SJeremy L. Thompson   @ref Backend
4477a982d89SJeremy L. Thompson **/
4487a982d89SJeremy L. Thompson 
4497a982d89SJeremy L. Thompson int CeedOperatorSetSetupDone(CeedOperator op) {
450f04ea552SJeremy L Thompson   op->is_backend_setup = true;
451e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
4527a982d89SJeremy L. Thompson }
4537a982d89SJeremy L. Thompson 
4547a982d89SJeremy L. Thompson /// @}
4557a982d89SJeremy L. Thompson 
4567a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
4577a982d89SJeremy L. Thompson /// CeedOperator Public API
4587a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
4597a982d89SJeremy L. Thompson /// @addtogroup CeedOperatorUser
460dfdf5a53Sjeremylt /// @{
461d7b241e6Sjeremylt 
462d7b241e6Sjeremylt /**
4630219ea01SJeremy L Thompson   @brief Create a CeedOperator and associate a CeedQFunction. A CeedBasis and
4640219ea01SJeremy L Thompson            CeedElemRestriction can be associated with CeedQFunction fields with
4650219ea01SJeremy L Thompson            \ref CeedOperatorSetField.
466d7b241e6Sjeremylt 
467b11c1e72Sjeremylt   @param ceed     A Ceed object where the CeedOperator will be created
468d7b241e6Sjeremylt   @param qf       QFunction defining the action of the operator at quadrature points
46934138859Sjeremylt   @param dqf      QFunction defining the action of the Jacobian of @a qf (or
4704cc79fe7SJed Brown                     @ref CEED_QFUNCTION_NONE)
471d7b241e6Sjeremylt   @param dqfT     QFunction defining the action of the transpose of the Jacobian
4724cc79fe7SJed Brown                     of @a qf (or @ref CEED_QFUNCTION_NONE)
473b11c1e72Sjeremylt   @param[out] op  Address of the variable where the newly created
474b11c1e72Sjeremylt                     CeedOperator will be stored
475b11c1e72Sjeremylt 
476b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
477dfdf5a53Sjeremylt 
4787a982d89SJeremy L. Thompson   @ref User
479d7b241e6Sjeremylt  */
480d7b241e6Sjeremylt int CeedOperatorCreate(Ceed ceed, CeedQFunction qf, CeedQFunction dqf,
481d7b241e6Sjeremylt                        CeedQFunction dqfT, CeedOperator *op) {
482d7b241e6Sjeremylt   int ierr;
483d7b241e6Sjeremylt 
4845fe0d4faSjeremylt   if (!ceed->OperatorCreate) {
4855fe0d4faSjeremylt     Ceed delegate;
486aefd8378Sjeremylt     ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr);
4875fe0d4faSjeremylt 
4885fe0d4faSjeremylt     if (!delegate)
489c042f62fSJeremy L Thompson       // LCOV_EXCL_START
490e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_UNSUPPORTED,
491e15f9bd0SJeremy L Thompson                        "Backend does not support OperatorCreate");
492c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
4935fe0d4faSjeremylt 
4945fe0d4faSjeremylt     ierr = CeedOperatorCreate(delegate, qf, dqf, dqfT, op); CeedChk(ierr);
495e15f9bd0SJeremy L Thompson     return CEED_ERROR_SUCCESS;
4965fe0d4faSjeremylt   }
4975fe0d4faSjeremylt 
498b3b7035fSJeremy L Thompson   if (!qf || qf == CEED_QFUNCTION_NONE)
499b3b7035fSJeremy L Thompson     // LCOV_EXCL_START
500e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_MINOR,
501e15f9bd0SJeremy L Thompson                      "Operator must have a valid QFunction.");
502b3b7035fSJeremy L Thompson   // LCOV_EXCL_STOP
503d7b241e6Sjeremylt   ierr = CeedCalloc(1, op); CeedChk(ierr);
504d7b241e6Sjeremylt   (*op)->ceed = ceed;
5059560d06aSjeremylt   ierr = CeedReference(ceed); CeedChk(ierr);
506d1d35e2fSjeremylt   (*op)->ref_count = 1;
507d7b241e6Sjeremylt   (*op)->qf = qf;
5089560d06aSjeremylt   ierr = CeedQFunctionReference(qf); CeedChk(ierr);
509442e7f0bSjeremylt   if (dqf && dqf != CEED_QFUNCTION_NONE) {
510d7b241e6Sjeremylt     (*op)->dqf = dqf;
5119560d06aSjeremylt     ierr = CeedQFunctionReference(dqf); CeedChk(ierr);
512442e7f0bSjeremylt   }
513442e7f0bSjeremylt   if (dqfT && dqfT != CEED_QFUNCTION_NONE) {
514d7b241e6Sjeremylt     (*op)->dqfT = dqfT;
5159560d06aSjeremylt     ierr = CeedQFunctionReference(dqfT); CeedChk(ierr);
516442e7f0bSjeremylt   }
517d1d35e2fSjeremylt   ierr = CeedCalloc(16, &(*op)->input_fields); CeedChk(ierr);
518d1d35e2fSjeremylt   ierr = CeedCalloc(16, &(*op)->output_fields); CeedChk(ierr);
519d7b241e6Sjeremylt   ierr = ceed->OperatorCreate(*op); CeedChk(ierr);
520e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
521d7b241e6Sjeremylt }
522d7b241e6Sjeremylt 
523d7b241e6Sjeremylt /**
52452d6035fSJeremy L Thompson   @brief Create an operator that composes the action of several operators
52552d6035fSJeremy L Thompson 
52652d6035fSJeremy L Thompson   @param ceed     A Ceed object where the CeedOperator will be created
52752d6035fSJeremy L Thompson   @param[out] op  Address of the variable where the newly created
52852d6035fSJeremy L Thompson                     Composite CeedOperator will be stored
52952d6035fSJeremy L Thompson 
53052d6035fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
53152d6035fSJeremy L Thompson 
5327a982d89SJeremy L. Thompson   @ref User
53352d6035fSJeremy L Thompson  */
53452d6035fSJeremy L Thompson int CeedCompositeOperatorCreate(Ceed ceed, CeedOperator *op) {
53552d6035fSJeremy L Thompson   int ierr;
53652d6035fSJeremy L Thompson 
53752d6035fSJeremy L Thompson   if (!ceed->CompositeOperatorCreate) {
53852d6035fSJeremy L Thompson     Ceed delegate;
539aefd8378Sjeremylt     ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr);
54052d6035fSJeremy L Thompson 
541250756a7Sjeremylt     if (delegate) {
54252d6035fSJeremy L Thompson       ierr = CeedCompositeOperatorCreate(delegate, op); CeedChk(ierr);
543e15f9bd0SJeremy L Thompson       return CEED_ERROR_SUCCESS;
54452d6035fSJeremy L Thompson     }
545250756a7Sjeremylt   }
54652d6035fSJeremy L Thompson 
54752d6035fSJeremy L Thompson   ierr = CeedCalloc(1, op); CeedChk(ierr);
54852d6035fSJeremy L Thompson   (*op)->ceed = ceed;
5499560d06aSjeremylt   ierr = CeedReference(ceed); CeedChk(ierr);
550f04ea552SJeremy L Thompson   (*op)->is_composite = true;
551d1d35e2fSjeremylt   ierr = CeedCalloc(16, &(*op)->sub_operators); CeedChk(ierr);
552250756a7Sjeremylt 
553250756a7Sjeremylt   if (ceed->CompositeOperatorCreate) {
55452d6035fSJeremy L Thompson     ierr = ceed->CompositeOperatorCreate(*op); CeedChk(ierr);
555250756a7Sjeremylt   }
556e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
55752d6035fSJeremy L Thompson }
55852d6035fSJeremy L Thompson 
55952d6035fSJeremy L Thompson /**
5609560d06aSjeremylt   @brief Copy the pointer to a CeedOperator. Both pointers should
5619560d06aSjeremylt            be destroyed with `CeedOperatorDestroy()`;
5629560d06aSjeremylt            Note: If `*op_copy` is non-NULL, then it is assumed that
5639560d06aSjeremylt            `*op_copy` is a pointer to a CeedOperator. This
5649560d06aSjeremylt            CeedOperator will be destroyed if `*op_copy` is the only
5659560d06aSjeremylt            reference to this CeedOperator.
5669560d06aSjeremylt 
5679560d06aSjeremylt   @param op            CeedOperator to copy reference to
5689560d06aSjeremylt   @param[out] op_copy  Variable to store copied reference
5699560d06aSjeremylt 
5709560d06aSjeremylt   @return An error code: 0 - success, otherwise - failure
5719560d06aSjeremylt 
5729560d06aSjeremylt   @ref User
5739560d06aSjeremylt **/
5749560d06aSjeremylt int CeedOperatorReferenceCopy(CeedOperator op, CeedOperator *op_copy) {
5759560d06aSjeremylt   int ierr;
5769560d06aSjeremylt 
5779560d06aSjeremylt   ierr = CeedOperatorReference(op); CeedChk(ierr);
5789560d06aSjeremylt   ierr = CeedOperatorDestroy(op_copy); CeedChk(ierr);
5799560d06aSjeremylt   *op_copy = op;
5809560d06aSjeremylt   return CEED_ERROR_SUCCESS;
5819560d06aSjeremylt }
5829560d06aSjeremylt 
5839560d06aSjeremylt /**
584b11c1e72Sjeremylt   @brief Provide a field to a CeedOperator for use by its CeedQFunction
585d7b241e6Sjeremylt 
586d7b241e6Sjeremylt   This function is used to specify both active and passive fields to a
587d7b241e6Sjeremylt   CeedOperator.  For passive fields, a vector @arg v must be provided.  Passive
588d7b241e6Sjeremylt   fields can inputs or outputs (updated in-place when operator is applied).
589d7b241e6Sjeremylt 
590d7b241e6Sjeremylt   Active fields must be specified using this function, but their data (in a
591d7b241e6Sjeremylt   CeedVector) is passed in CeedOperatorApply().  There can be at most one active
592d7b241e6Sjeremylt   input and at most one active output.
593d7b241e6Sjeremylt 
5948c91a0c9SJeremy L Thompson   @param op          CeedOperator on which to provide the field
595d1d35e2fSjeremylt   @param field_name  Name of the field (to be matched with the name used by
5968795c945Sjeremylt                        CeedQFunction)
597b11c1e72Sjeremylt   @param r           CeedElemRestriction
5984cc79fe7SJed Brown   @param b           CeedBasis in which the field resides or @ref CEED_BASIS_COLLOCATED
599b11c1e72Sjeremylt                        if collocated with quadrature points
6004cc79fe7SJed Brown   @param v           CeedVector to be used by CeedOperator or @ref CEED_VECTOR_ACTIVE
6014cc79fe7SJed Brown                        if field is active or @ref CEED_VECTOR_NONE if using
6024cc79fe7SJed Brown                        @ref CEED_EVAL_WEIGHT in the QFunction
603b11c1e72Sjeremylt 
604b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
605dfdf5a53Sjeremylt 
6067a982d89SJeremy L. Thompson   @ref User
607b11c1e72Sjeremylt **/
608d1d35e2fSjeremylt int CeedOperatorSetField(CeedOperator op, const char *field_name,
609a8d32208Sjeremylt                          CeedElemRestriction r, CeedBasis b, CeedVector v) {
610d7b241e6Sjeremylt   int ierr;
611f04ea552SJeremy L Thompson   if (op->is_composite)
612c042f62fSJeremy L Thompson     // LCOV_EXCL_START
613e1e9e29dSJed Brown     return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
614e15f9bd0SJeremy L Thompson                      "Cannot add field to composite operator.");
615c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
616f04ea552SJeremy L Thompson   if (op->is_immutable)
617f04ea552SJeremy L Thompson     // LCOV_EXCL_START
618f04ea552SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MAJOR,
619f04ea552SJeremy L Thompson                      "Operator cannot be changed after set as immutable");
620f04ea552SJeremy L Thompson   // LCOV_EXCL_STOP
6218b067b84SJed Brown   if (!r)
622c042f62fSJeremy L Thompson     // LCOV_EXCL_START
623e1e9e29dSJed Brown     return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
624c042f62fSJeremy L Thompson                      "ElemRestriction r for field \"%s\" must be non-NULL.",
625d1d35e2fSjeremylt                      field_name);
626c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
6278b067b84SJed Brown   if (!b)
628c042f62fSJeremy L Thompson     // LCOV_EXCL_START
629e1e9e29dSJed Brown     return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
630e15f9bd0SJeremy L Thompson                      "Basis b for field \"%s\" must be non-NULL.",
631d1d35e2fSjeremylt                      field_name);
632c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
6338b067b84SJed Brown   if (!v)
634c042f62fSJeremy L Thompson     // LCOV_EXCL_START
635e1e9e29dSJed Brown     return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
636e15f9bd0SJeremy L Thompson                      "Vector v for field \"%s\" must be non-NULL.",
637d1d35e2fSjeremylt                      field_name);
638c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
63952d6035fSJeremy L Thompson 
640d1d35e2fSjeremylt   CeedInt num_elem;
641d1d35e2fSjeremylt   ierr = CeedElemRestrictionGetNumElements(r, &num_elem); CeedChk(ierr);
642d1d35e2fSjeremylt   if (r != CEED_ELEMRESTRICTION_NONE && op->has_restriction &&
643d1d35e2fSjeremylt       op->num_elem != num_elem)
644c042f62fSJeremy L Thompson     // LCOV_EXCL_START
645e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_DIMENSION,
6461d102b48SJeremy L Thompson                      "ElemRestriction with %d elements incompatible with prior "
647d1d35e2fSjeremylt                      "%d elements", num_elem, op->num_elem);
648c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
649d7b241e6Sjeremylt 
65078464608Sjeremylt   CeedInt num_qpts = 0;
651e15f9bd0SJeremy L Thompson   if (b != CEED_BASIS_COLLOCATED) {
652d1d35e2fSjeremylt     ierr = CeedBasisGetNumQuadraturePoints(b, &num_qpts); CeedChk(ierr);
653d1d35e2fSjeremylt     if (op->num_qpts && op->num_qpts != num_qpts)
654c042f62fSJeremy L Thompson       // LCOV_EXCL_START
655e15f9bd0SJeremy L Thompson       return CeedError(op->ceed, CEED_ERROR_DIMENSION,
656e15f9bd0SJeremy L Thompson                        "Basis with %d quadrature points "
657d1d35e2fSjeremylt                        "incompatible with prior %d points", num_qpts,
658d1d35e2fSjeremylt                        op->num_qpts);
659c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
660d7b241e6Sjeremylt   }
661d1d35e2fSjeremylt   CeedQFunctionField qf_field;
662d1d35e2fSjeremylt   CeedOperatorField *op_field;
663d1d35e2fSjeremylt   for (CeedInt i=0; i<op->qf->num_input_fields; i++) {
664d1d35e2fSjeremylt     if (!strcmp(field_name, (*op->qf->input_fields[i]).field_name)) {
665d1d35e2fSjeremylt       qf_field = op->qf->input_fields[i];
666d1d35e2fSjeremylt       op_field = &op->input_fields[i];
667d7b241e6Sjeremylt       goto found;
668d7b241e6Sjeremylt     }
669d7b241e6Sjeremylt   }
670d1d35e2fSjeremylt   for (CeedInt i=0; i<op->qf->num_output_fields; i++) {
671d1d35e2fSjeremylt     if (!strcmp(field_name, (*op->qf->output_fields[i]).field_name)) {
672d1d35e2fSjeremylt       qf_field = op->qf->output_fields[i];
673d1d35e2fSjeremylt       op_field = &op->output_fields[i];
674d7b241e6Sjeremylt       goto found;
675d7b241e6Sjeremylt     }
676d7b241e6Sjeremylt   }
677c042f62fSJeremy L Thompson   // LCOV_EXCL_START
678e15f9bd0SJeremy L Thompson   return CeedError(op->ceed, CEED_ERROR_INCOMPLETE,
679e15f9bd0SJeremy L Thompson                    "QFunction has no knowledge of field '%s'",
680d1d35e2fSjeremylt                    field_name);
681c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
682d7b241e6Sjeremylt found:
683d1d35e2fSjeremylt   ierr = CeedOperatorCheckField(op->ceed, qf_field, r, b); CeedChk(ierr);
684d1d35e2fSjeremylt   ierr = CeedCalloc(1, op_field); CeedChk(ierr);
685e15f9bd0SJeremy L Thompson 
686d1d35e2fSjeremylt   (*op_field)->vec = v;
687e15f9bd0SJeremy L Thompson   if (v != CEED_VECTOR_ACTIVE && v != CEED_VECTOR_NONE) {
6889560d06aSjeremylt     ierr = CeedVectorReference(v); CeedChk(ierr);
689e15f9bd0SJeremy L Thompson   }
690e15f9bd0SJeremy L Thompson 
691d1d35e2fSjeremylt   (*op_field)->elem_restr = r;
6929560d06aSjeremylt   ierr = CeedElemRestrictionReference(r); CeedChk(ierr);
693e15f9bd0SJeremy L Thompson   if (r != CEED_ELEMRESTRICTION_NONE) {
694d1d35e2fSjeremylt     op->num_elem = num_elem;
695d1d35e2fSjeremylt     op->has_restriction = true; // Restriction set, but num_elem may be 0
696e15f9bd0SJeremy L Thompson   }
697d99fa3c5SJeremy L Thompson 
698d1d35e2fSjeremylt   (*op_field)->basis = b;
699e15f9bd0SJeremy L Thompson   if (b != CEED_BASIS_COLLOCATED) {
700cd4dfc48Sjeremylt     if (!op->num_qpts) {
701cd4dfc48Sjeremylt       ierr = CeedOperatorSetNumQuadraturePoints(op, num_qpts); CeedChk(ierr);
702cd4dfc48Sjeremylt     }
7039560d06aSjeremylt     ierr = CeedBasisReference(b); CeedChk(ierr);
704e15f9bd0SJeremy L Thompson   }
705e15f9bd0SJeremy L Thompson 
706d1d35e2fSjeremylt   op->num_fields += 1;
707d1d35e2fSjeremylt   size_t len = strlen(field_name);
708d99fa3c5SJeremy L Thompson   char *tmp;
709d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(len+1, &tmp); CeedChk(ierr);
710d1d35e2fSjeremylt   memcpy(tmp, field_name, len+1);
711d1d35e2fSjeremylt   (*op_field)->field_name = tmp;
712e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
713d7b241e6Sjeremylt }
714d7b241e6Sjeremylt 
715d7b241e6Sjeremylt /**
71643bbe138SJeremy L Thompson   @brief Get the CeedOperatorFields of a CeedOperator
71743bbe138SJeremy L Thompson 
718f04ea552SJeremy L Thompson   Note: Calling this function asserts that setup is complete
719f04ea552SJeremy L Thompson           and sets the CeedOperator as immutable.
720f04ea552SJeremy L Thompson 
72143bbe138SJeremy L Thompson   @param op                      CeedOperator
722*f74ec584SJeremy L Thompson   @param[out] num_input_fields   Variable to store number of input fields
72343bbe138SJeremy L Thompson   @param[out] input_fields       Variable to store input_fields
724*f74ec584SJeremy L Thompson   @param[out] num_output_fields  Variable to store number of output fields
72543bbe138SJeremy L Thompson   @param[out] output_fields      Variable to store output_fields
72643bbe138SJeremy L Thompson 
72743bbe138SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
72843bbe138SJeremy L Thompson 
729e9b533fbSJeremy L Thompson   @ref Advanced
73043bbe138SJeremy L Thompson **/
73143bbe138SJeremy L Thompson int CeedOperatorGetFields(CeedOperator op, CeedInt *num_input_fields,
73243bbe138SJeremy L Thompson                           CeedOperatorField **input_fields,
73343bbe138SJeremy L Thompson                           CeedInt *num_output_fields,
73443bbe138SJeremy L Thompson                           CeedOperatorField **output_fields) {
735f04ea552SJeremy L Thompson   int ierr;
736f04ea552SJeremy L Thompson 
737f04ea552SJeremy L Thompson   if (op->is_composite)
73843bbe138SJeremy L Thompson     // LCOV_EXCL_START
73943bbe138SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
74043bbe138SJeremy L Thompson                      "Not defined for composite operator");
74143bbe138SJeremy L Thompson   // LCOV_EXCL_STOP
742f04ea552SJeremy L Thompson   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
74343bbe138SJeremy L Thompson 
74443bbe138SJeremy L Thompson   if (num_input_fields) *num_input_fields = op->qf->num_input_fields;
74543bbe138SJeremy L Thompson   if (input_fields) *input_fields = op->input_fields;
74643bbe138SJeremy L Thompson   if (num_output_fields) *num_output_fields = op->qf->num_output_fields;
74743bbe138SJeremy L Thompson   if (output_fields) *output_fields = op->output_fields;
74843bbe138SJeremy L Thompson   return CEED_ERROR_SUCCESS;
74943bbe138SJeremy L Thompson }
75043bbe138SJeremy L Thompson 
75143bbe138SJeremy L Thompson /**
75228567f8fSJeremy L Thompson   @brief Get the name of a CeedOperatorField
75328567f8fSJeremy L Thompson 
75428567f8fSJeremy L Thompson   @param op_field         CeedOperatorField
75528567f8fSJeremy L Thompson   @param[out] field_name  Variable to store the field name
75628567f8fSJeremy L Thompson 
75728567f8fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
75828567f8fSJeremy L Thompson 
759e9b533fbSJeremy L Thompson   @ref Advanced
76028567f8fSJeremy L Thompson **/
76128567f8fSJeremy L Thompson int CeedOperatorFieldGetName(CeedOperatorField op_field, char **field_name) {
76228567f8fSJeremy L Thompson   *field_name = (char *)op_field->field_name;
76328567f8fSJeremy L Thompson   return CEED_ERROR_SUCCESS;
76428567f8fSJeremy L Thompson }
76528567f8fSJeremy L Thompson 
76628567f8fSJeremy L Thompson /**
76743bbe138SJeremy L Thompson   @brief Get the CeedElemRestriction of a CeedOperatorField
76843bbe138SJeremy L Thompson 
76943bbe138SJeremy L Thompson   @param op_field   CeedOperatorField
77043bbe138SJeremy L Thompson   @param[out] rstr  Variable to store CeedElemRestriction
77143bbe138SJeremy L Thompson 
77243bbe138SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
77343bbe138SJeremy L Thompson 
774e9b533fbSJeremy L Thompson   @ref Advanced
77543bbe138SJeremy L Thompson **/
77643bbe138SJeremy L Thompson int CeedOperatorFieldGetElemRestriction(CeedOperatorField op_field,
77743bbe138SJeremy L Thompson                                         CeedElemRestriction *rstr) {
77843bbe138SJeremy L Thompson   *rstr = op_field->elem_restr;
77943bbe138SJeremy L Thompson   return CEED_ERROR_SUCCESS;
78043bbe138SJeremy L Thompson }
78143bbe138SJeremy L Thompson 
78243bbe138SJeremy L Thompson /**
78343bbe138SJeremy L Thompson   @brief Get the CeedBasis of a CeedOperatorField
78443bbe138SJeremy L Thompson 
78543bbe138SJeremy L Thompson   @param op_field    CeedOperatorField
78643bbe138SJeremy L Thompson   @param[out] basis  Variable to store CeedBasis
78743bbe138SJeremy L Thompson 
78843bbe138SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
78943bbe138SJeremy L Thompson 
790e9b533fbSJeremy L Thompson   @ref Advanced
79143bbe138SJeremy L Thompson **/
79243bbe138SJeremy L Thompson int CeedOperatorFieldGetBasis(CeedOperatorField op_field, CeedBasis *basis) {
79343bbe138SJeremy L Thompson   *basis = op_field->basis;
79443bbe138SJeremy L Thompson   return CEED_ERROR_SUCCESS;
79543bbe138SJeremy L Thompson }
79643bbe138SJeremy L Thompson 
79743bbe138SJeremy L Thompson /**
79843bbe138SJeremy L Thompson   @brief Get the CeedVector of a CeedOperatorField
79943bbe138SJeremy L Thompson 
80043bbe138SJeremy L Thompson   @param op_field  CeedOperatorField
80143bbe138SJeremy L Thompson   @param[out] vec  Variable to store CeedVector
80243bbe138SJeremy L Thompson 
80343bbe138SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
80443bbe138SJeremy L Thompson 
805e9b533fbSJeremy L Thompson   @ref Advanced
80643bbe138SJeremy L Thompson **/
80743bbe138SJeremy L Thompson int CeedOperatorFieldGetVector(CeedOperatorField op_field, CeedVector *vec) {
80843bbe138SJeremy L Thompson   *vec = op_field->vec;
80943bbe138SJeremy L Thompson   return CEED_ERROR_SUCCESS;
81043bbe138SJeremy L Thompson }
81143bbe138SJeremy L Thompson 
81243bbe138SJeremy L Thompson /**
81352d6035fSJeremy L Thompson   @brief Add a sub-operator to a composite CeedOperator
814288c0443SJeremy L Thompson 
815d1d35e2fSjeremylt   @param[out] composite_op  Composite CeedOperator
816d1d35e2fSjeremylt   @param      sub_op        Sub-operator CeedOperator
81752d6035fSJeremy L Thompson 
81852d6035fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
81952d6035fSJeremy L Thompson 
8207a982d89SJeremy L. Thompson   @ref User
82152d6035fSJeremy L Thompson  */
822d1d35e2fSjeremylt int CeedCompositeOperatorAddSub(CeedOperator composite_op,
823d1d35e2fSjeremylt                                 CeedOperator sub_op) {
82434359f16Sjeremylt   int ierr;
82534359f16Sjeremylt 
826f04ea552SJeremy L Thompson   if (!composite_op->is_composite)
827c042f62fSJeremy L Thompson     // LCOV_EXCL_START
828d1d35e2fSjeremylt     return CeedError(composite_op->ceed, CEED_ERROR_MINOR,
829e2f04181SAndrew T. Barker                      "CeedOperator is not a composite operator");
830c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
83152d6035fSJeremy L Thompson 
832d1d35e2fSjeremylt   if (composite_op->num_suboperators == CEED_COMPOSITE_MAX)
833c042f62fSJeremy L Thompson     // LCOV_EXCL_START
834d1d35e2fSjeremylt     return CeedError(composite_op->ceed, CEED_ERROR_UNSUPPORTED,
835d1d35e2fSjeremylt                      "Cannot add additional sub_operators");
836c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
837f04ea552SJeremy L Thompson   if (composite_op->is_immutable)
838f04ea552SJeremy L Thompson     // LCOV_EXCL_START
839f04ea552SJeremy L Thompson     return CeedError(composite_op->ceed, CEED_ERROR_MAJOR,
840f04ea552SJeremy L Thompson                      "Operator cannot be changed after set as immutable");
841f04ea552SJeremy L Thompson   // LCOV_EXCL_STOP
84252d6035fSJeremy L Thompson 
843d1d35e2fSjeremylt   composite_op->sub_operators[composite_op->num_suboperators] = sub_op;
8449560d06aSjeremylt   ierr = CeedOperatorReference(sub_op); CeedChk(ierr);
845d1d35e2fSjeremylt   composite_op->num_suboperators++;
846e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
84752d6035fSJeremy L Thompson }
84852d6035fSJeremy L Thompson 
84952d6035fSJeremy L Thompson /**
8504db537f9SJeremy L Thompson   @brief Check if a CeedOperator is ready to be used.
8514db537f9SJeremy L Thompson 
8524db537f9SJeremy L Thompson   @param[in] op  CeedOperator to check
8534db537f9SJeremy L Thompson 
8544db537f9SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
8554db537f9SJeremy L Thompson 
8564db537f9SJeremy L Thompson   @ref User
8574db537f9SJeremy L Thompson **/
8584db537f9SJeremy L Thompson int CeedOperatorCheckReady(CeedOperator op) {
8594db537f9SJeremy L Thompson   int ierr;
8604db537f9SJeremy L Thompson   Ceed ceed;
8614db537f9SJeremy L Thompson   ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr);
8624db537f9SJeremy L Thompson 
8634db537f9SJeremy L Thompson   if (op->is_interface_setup)
8644db537f9SJeremy L Thompson     return CEED_ERROR_SUCCESS;
8654db537f9SJeremy L Thompson 
8664db537f9SJeremy L Thompson   CeedQFunction qf = op->qf;
8674db537f9SJeremy L Thompson   if (op->is_composite) {
8684db537f9SJeremy L Thompson     if (!op->num_suboperators)
8694db537f9SJeremy L Thompson       // LCOV_EXCL_START
8704db537f9SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_INCOMPLETE, "No sub_operators set");
8714db537f9SJeremy L Thompson     // LCOV_EXCL_STOP
8724db537f9SJeremy L Thompson     for (CeedInt i = 0; i < op->num_suboperators; i++) {
8734db537f9SJeremy L Thompson       ierr = CeedOperatorCheckReady(op->sub_operators[i]); CeedChk(ierr);
8744db537f9SJeremy L Thompson     }
8754db537f9SJeremy L Thompson   } else {
8764db537f9SJeremy L Thompson     if (op->num_fields == 0)
8774db537f9SJeremy L Thompson       // LCOV_EXCL_START
8784db537f9SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_INCOMPLETE, "No operator fields set");
8794db537f9SJeremy L Thompson     // LCOV_EXCL_STOP
8804db537f9SJeremy L Thompson     if (op->num_fields < qf->num_input_fields + qf->num_output_fields)
8814db537f9SJeremy L Thompson       // LCOV_EXCL_START
8824db537f9SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_INCOMPLETE, "Not all operator fields set");
8834db537f9SJeremy L Thompson     // LCOV_EXCL_STOP
8844db537f9SJeremy L Thompson     if (!op->has_restriction)
8854db537f9SJeremy L Thompson       // LCOV_EXCL_START
8864db537f9SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_INCOMPLETE,
8874db537f9SJeremy L Thompson                        "At least one restriction required");
8884db537f9SJeremy L Thompson     // LCOV_EXCL_STOP
8894db537f9SJeremy L Thompson     if (op->num_qpts == 0)
8904db537f9SJeremy L Thompson       // LCOV_EXCL_START
8914db537f9SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_INCOMPLETE,
8924db537f9SJeremy L Thompson                        "At least one non-collocated basis is required "
8934db537f9SJeremy L Thompson                        "or the number of quadrature points must be set");
8944db537f9SJeremy L Thompson     // LCOV_EXCL_STOP
8954db537f9SJeremy L Thompson   }
8964db537f9SJeremy L Thompson 
8974db537f9SJeremy L Thompson   // Flag as immutable and ready
8984db537f9SJeremy L Thompson   op->is_interface_setup = true;
8994db537f9SJeremy L Thompson   if (op->qf && op->qf != CEED_QFUNCTION_NONE)
9004db537f9SJeremy L Thompson     // LCOV_EXCL_START
9014db537f9SJeremy L Thompson     op->qf->is_immutable = true;
9024db537f9SJeremy L Thompson   // LCOV_EXCL_STOP
9034db537f9SJeremy L Thompson   if (op->dqf && op->dqf != CEED_QFUNCTION_NONE)
9044db537f9SJeremy L Thompson     // LCOV_EXCL_START
9054db537f9SJeremy L Thompson     op->dqf->is_immutable = true;
9064db537f9SJeremy L Thompson   // LCOV_EXCL_STOP
9074db537f9SJeremy L Thompson   if (op->dqfT && op->dqfT != CEED_QFUNCTION_NONE)
9084db537f9SJeremy L Thompson     // LCOV_EXCL_START
9094db537f9SJeremy L Thompson     op->dqfT->is_immutable = true;
9104db537f9SJeremy L Thompson   // LCOV_EXCL_STOP
9114db537f9SJeremy L Thompson   return CEED_ERROR_SUCCESS;
9124db537f9SJeremy L Thompson }
9134db537f9SJeremy L Thompson 
9144db537f9SJeremy L Thompson /**
915cd4dfc48Sjeremylt   @brief Set the number of quadrature points associated with a CeedOperator.
916cd4dfc48Sjeremylt            This should be used when creating a CeedOperator where every
917cd4dfc48Sjeremylt            field has a collocated basis. This function cannot be used for
918cd4dfc48Sjeremylt            composite CeedOperators.
919cd4dfc48Sjeremylt 
920cd4dfc48Sjeremylt   @param op        CeedOperator
921cd4dfc48Sjeremylt   @param num_qpts  Number of quadrature points to set
922cd4dfc48Sjeremylt 
923cd4dfc48Sjeremylt   @return An error code: 0 - success, otherwise - failure
924cd4dfc48Sjeremylt 
925e9b533fbSJeremy L Thompson   @ref Advanced
926cd4dfc48Sjeremylt **/
927cd4dfc48Sjeremylt int CeedOperatorSetNumQuadraturePoints(CeedOperator op, CeedInt num_qpts) {
928f04ea552SJeremy L Thompson   if (op->is_composite)
929cd4dfc48Sjeremylt     // LCOV_EXCL_START
930cd4dfc48Sjeremylt     return CeedError(op->ceed, CEED_ERROR_MINOR,
931cd4dfc48Sjeremylt                      "Not defined for composite operator");
932cd4dfc48Sjeremylt   // LCOV_EXCL_STOP
933cd4dfc48Sjeremylt   if (op->num_qpts)
934cd4dfc48Sjeremylt     // LCOV_EXCL_START
935cd4dfc48Sjeremylt     return CeedError(op->ceed, CEED_ERROR_MINOR,
936cd4dfc48Sjeremylt                      "Number of quadrature points already defined");
937cd4dfc48Sjeremylt   // LCOV_EXCL_STOP
938f04ea552SJeremy L Thompson   if (op->is_immutable)
939f04ea552SJeremy L Thompson     // LCOV_EXCL_START
940f04ea552SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MAJOR,
941f04ea552SJeremy L Thompson                      "Operator cannot be changed after set as immutable");
942f04ea552SJeremy L Thompson   // LCOV_EXCL_STOP
943cd4dfc48Sjeremylt 
944cd4dfc48Sjeremylt   op->num_qpts = num_qpts;
945cd4dfc48Sjeremylt   return CEED_ERROR_SUCCESS;
946cd4dfc48Sjeremylt }
947cd4dfc48Sjeremylt 
948cd4dfc48Sjeremylt /**
9497a982d89SJeremy L. Thompson   @brief View a CeedOperator
9507a982d89SJeremy L. Thompson 
9517a982d89SJeremy L. Thompson   @param[in] op      CeedOperator to view
9527a982d89SJeremy L. Thompson   @param[in] stream  Stream to write; typically stdout/stderr or a file
9537a982d89SJeremy L. Thompson 
9547a982d89SJeremy L. Thompson   @return Error code: 0 - success, otherwise - failure
9557a982d89SJeremy L. Thompson 
9567a982d89SJeremy L. Thompson   @ref User
9577a982d89SJeremy L. Thompson **/
9587a982d89SJeremy L. Thompson int CeedOperatorView(CeedOperator op, FILE *stream) {
9597a982d89SJeremy L. Thompson   int ierr;
9607a982d89SJeremy L. Thompson 
961f04ea552SJeremy L Thompson   if (op->is_composite) {
9627a982d89SJeremy L. Thompson     fprintf(stream, "Composite CeedOperator\n");
9637a982d89SJeremy L. Thompson 
964d1d35e2fSjeremylt     for (CeedInt i=0; i<op->num_suboperators; i++) {
9657a982d89SJeremy L. Thompson       fprintf(stream, "  SubOperator [%d]:\n", i);
966d1d35e2fSjeremylt       ierr = CeedOperatorSingleView(op->sub_operators[i], 1, stream);
9677a982d89SJeremy L. Thompson       CeedChk(ierr);
9687a982d89SJeremy L. Thompson     }
9697a982d89SJeremy L. Thompson   } else {
9707a982d89SJeremy L. Thompson     fprintf(stream, "CeedOperator\n");
9717a982d89SJeremy L. Thompson     ierr = CeedOperatorSingleView(op, 0, stream); CeedChk(ierr);
9727a982d89SJeremy L. Thompson   }
973e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
9747a982d89SJeremy L. Thompson }
9753bd813ffSjeremylt 
9763bd813ffSjeremylt /**
977b7c9bbdaSJeremy L Thompson   @brief Get the Ceed associated with a CeedOperator
978b7c9bbdaSJeremy L Thompson 
979b7c9bbdaSJeremy L Thompson   @param op         CeedOperator
980b7c9bbdaSJeremy L Thompson   @param[out] ceed  Variable to store Ceed
981b7c9bbdaSJeremy L Thompson 
982b7c9bbdaSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
983b7c9bbdaSJeremy L Thompson 
984b7c9bbdaSJeremy L Thompson   @ref Advanced
985b7c9bbdaSJeremy L Thompson **/
986b7c9bbdaSJeremy L Thompson int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) {
987b7c9bbdaSJeremy L Thompson   *ceed = op->ceed;
988b7c9bbdaSJeremy L Thompson   return CEED_ERROR_SUCCESS;
989b7c9bbdaSJeremy L Thompson }
990b7c9bbdaSJeremy L Thompson 
991b7c9bbdaSJeremy L Thompson /**
992b7c9bbdaSJeremy L Thompson   @brief Get the number of elements associated with a CeedOperator
993b7c9bbdaSJeremy L Thompson 
994b7c9bbdaSJeremy L Thompson   @param op             CeedOperator
995b7c9bbdaSJeremy L Thompson   @param[out] num_elem  Variable to store number of elements
996b7c9bbdaSJeremy L Thompson 
997b7c9bbdaSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
998b7c9bbdaSJeremy L Thompson 
999b7c9bbdaSJeremy L Thompson   @ref Advanced
1000b7c9bbdaSJeremy L Thompson **/
1001b7c9bbdaSJeremy L Thompson int CeedOperatorGetNumElements(CeedOperator op, CeedInt *num_elem) {
1002b7c9bbdaSJeremy L Thompson   if (op->is_composite)
1003b7c9bbdaSJeremy L Thompson     // LCOV_EXCL_START
1004b7c9bbdaSJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
1005b7c9bbdaSJeremy L Thompson                      "Not defined for composite operator");
1006b7c9bbdaSJeremy L Thompson   // LCOV_EXCL_STOP
1007b7c9bbdaSJeremy L Thompson 
1008b7c9bbdaSJeremy L Thompson   *num_elem = op->num_elem;
1009b7c9bbdaSJeremy L Thompson   return CEED_ERROR_SUCCESS;
1010b7c9bbdaSJeremy L Thompson }
1011b7c9bbdaSJeremy L Thompson 
1012b7c9bbdaSJeremy L Thompson /**
1013b7c9bbdaSJeremy L Thompson   @brief Get the number of quadrature points associated with a CeedOperator
1014b7c9bbdaSJeremy L Thompson 
1015b7c9bbdaSJeremy L Thompson   @param op             CeedOperator
1016b7c9bbdaSJeremy L Thompson   @param[out] num_qpts  Variable to store vector number of quadrature points
1017b7c9bbdaSJeremy L Thompson 
1018b7c9bbdaSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1019b7c9bbdaSJeremy L Thompson 
1020b7c9bbdaSJeremy L Thompson   @ref Advanced
1021b7c9bbdaSJeremy L Thompson **/
1022b7c9bbdaSJeremy L Thompson int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *num_qpts) {
1023b7c9bbdaSJeremy L Thompson   if (op->is_composite)
1024b7c9bbdaSJeremy L Thompson     // LCOV_EXCL_START
1025b7c9bbdaSJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
1026b7c9bbdaSJeremy L Thompson                      "Not defined for composite operator");
1027b7c9bbdaSJeremy L Thompson   // LCOV_EXCL_STOP
1028b7c9bbdaSJeremy L Thompson 
1029b7c9bbdaSJeremy L Thompson   *num_qpts = op->num_qpts;
1030b7c9bbdaSJeremy L Thompson   return CEED_ERROR_SUCCESS;
1031b7c9bbdaSJeremy L Thompson }
1032b7c9bbdaSJeremy L Thompson 
1033b7c9bbdaSJeremy L Thompson /**
10343bd813ffSjeremylt   @brief Apply CeedOperator to a vector
1035d7b241e6Sjeremylt 
1036d7b241e6Sjeremylt   This computes the action of the operator on the specified (active) input,
1037d7b241e6Sjeremylt   yielding its (active) output.  All inputs and outputs must be specified using
1038d7b241e6Sjeremylt   CeedOperatorSetField().
1039d7b241e6Sjeremylt 
1040f04ea552SJeremy L Thompson   Note: Calling this function asserts that setup is complete
1041f04ea552SJeremy L Thompson           and sets the CeedOperator as immutable.
1042f04ea552SJeremy L Thompson 
1043d7b241e6Sjeremylt   @param op        CeedOperator to apply
10444cc79fe7SJed Brown   @param[in] in    CeedVector containing input state or @ref CEED_VECTOR_NONE if
104534138859Sjeremylt                      there are no active inputs
1046b11c1e72Sjeremylt   @param[out] out  CeedVector to store result of applying operator (must be
10474cc79fe7SJed Brown                      distinct from @a in) or @ref CEED_VECTOR_NONE if there are no
104834138859Sjeremylt                      active outputs
1049d7b241e6Sjeremylt   @param request   Address of CeedRequest for non-blocking completion, else
10504cc79fe7SJed Brown                      @ref CEED_REQUEST_IMMEDIATE
1051b11c1e72Sjeremylt 
1052b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
1053dfdf5a53Sjeremylt 
10547a982d89SJeremy L. Thompson   @ref User
1055b11c1e72Sjeremylt **/
1056692c2638Sjeremylt int CeedOperatorApply(CeedOperator op, CeedVector in, CeedVector out,
1057692c2638Sjeremylt                       CeedRequest *request) {
1058d7b241e6Sjeremylt   int ierr;
1059e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
1060d7b241e6Sjeremylt 
1061d1d35e2fSjeremylt   if (op->num_elem)  {
1062250756a7Sjeremylt     // Standard Operator
1063cae8b89aSjeremylt     if (op->Apply) {
1064250756a7Sjeremylt       ierr = op->Apply(op, in, out, request); CeedChk(ierr);
1065cae8b89aSjeremylt     } else {
1066cae8b89aSjeremylt       // Zero all output vectors
1067250756a7Sjeremylt       CeedQFunction qf = op->qf;
1068d1d35e2fSjeremylt       for (CeedInt i=0; i<qf->num_output_fields; i++) {
1069d1d35e2fSjeremylt         CeedVector vec = op->output_fields[i]->vec;
1070cae8b89aSjeremylt         if (vec == CEED_VECTOR_ACTIVE)
1071cae8b89aSjeremylt           vec = out;
1072cae8b89aSjeremylt         if (vec != CEED_VECTOR_NONE) {
1073cae8b89aSjeremylt           ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr);
1074cae8b89aSjeremylt         }
1075cae8b89aSjeremylt       }
1076250756a7Sjeremylt       // Apply
1077250756a7Sjeremylt       ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr);
1078250756a7Sjeremylt     }
1079f04ea552SJeremy L Thompson   } else if (op->is_composite) {
1080250756a7Sjeremylt     // Composite Operator
1081250756a7Sjeremylt     if (op->ApplyComposite) {
1082250756a7Sjeremylt       ierr = op->ApplyComposite(op, in, out, request); CeedChk(ierr);
1083250756a7Sjeremylt     } else {
1084d1d35e2fSjeremylt       CeedInt num_suboperators;
1085d1d35e2fSjeremylt       ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr);
1086d1d35e2fSjeremylt       CeedOperator *sub_operators;
1087d1d35e2fSjeremylt       ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr);
1088250756a7Sjeremylt 
1089250756a7Sjeremylt       // Zero all output vectors
1090250756a7Sjeremylt       if (out != CEED_VECTOR_NONE) {
1091cae8b89aSjeremylt         ierr = CeedVectorSetValue(out, 0.0); CeedChk(ierr);
1092cae8b89aSjeremylt       }
1093d1d35e2fSjeremylt       for (CeedInt i=0; i<num_suboperators; i++) {
1094d1d35e2fSjeremylt         for (CeedInt j=0; j<sub_operators[i]->qf->num_output_fields; j++) {
1095d1d35e2fSjeremylt           CeedVector vec = sub_operators[i]->output_fields[j]->vec;
1096250756a7Sjeremylt           if (vec != CEED_VECTOR_ACTIVE && vec != CEED_VECTOR_NONE) {
1097250756a7Sjeremylt             ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr);
1098250756a7Sjeremylt           }
1099250756a7Sjeremylt         }
1100250756a7Sjeremylt       }
1101250756a7Sjeremylt       // Apply
1102d1d35e2fSjeremylt       for (CeedInt i=0; i<op->num_suboperators; i++) {
1103d1d35e2fSjeremylt         ierr = CeedOperatorApplyAdd(op->sub_operators[i], in, out, request);
1104cae8b89aSjeremylt         CeedChk(ierr);
1105cae8b89aSjeremylt       }
1106cae8b89aSjeremylt     }
1107250756a7Sjeremylt   }
1108e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1109cae8b89aSjeremylt }
1110cae8b89aSjeremylt 
1111cae8b89aSjeremylt /**
1112cae8b89aSjeremylt   @brief Apply CeedOperator to a vector and add result to output vector
1113cae8b89aSjeremylt 
1114cae8b89aSjeremylt   This computes the action of the operator on the specified (active) input,
1115cae8b89aSjeremylt   yielding its (active) output.  All inputs and outputs must be specified using
1116cae8b89aSjeremylt   CeedOperatorSetField().
1117cae8b89aSjeremylt 
1118cae8b89aSjeremylt   @param op        CeedOperator to apply
1119cae8b89aSjeremylt   @param[in] in    CeedVector containing input state or NULL if there are no
1120cae8b89aSjeremylt                      active inputs
1121cae8b89aSjeremylt   @param[out] out  CeedVector to sum in result of applying operator (must be
1122cae8b89aSjeremylt                      distinct from @a in) or NULL if there are no active outputs
1123cae8b89aSjeremylt   @param request   Address of CeedRequest for non-blocking completion, else
11244cc79fe7SJed Brown                      @ref CEED_REQUEST_IMMEDIATE
1125cae8b89aSjeremylt 
1126cae8b89aSjeremylt   @return An error code: 0 - success, otherwise - failure
1127cae8b89aSjeremylt 
11287a982d89SJeremy L. Thompson   @ref User
1129cae8b89aSjeremylt **/
1130cae8b89aSjeremylt int CeedOperatorApplyAdd(CeedOperator op, CeedVector in, CeedVector out,
1131cae8b89aSjeremylt                          CeedRequest *request) {
1132cae8b89aSjeremylt   int ierr;
1133e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
1134cae8b89aSjeremylt 
1135d1d35e2fSjeremylt   if (op->num_elem)  {
1136250756a7Sjeremylt     // Standard Operator
1137250756a7Sjeremylt     ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr);
1138f04ea552SJeremy L Thompson   } else if (op->is_composite) {
1139250756a7Sjeremylt     // Composite Operator
1140250756a7Sjeremylt     if (op->ApplyAddComposite) {
1141250756a7Sjeremylt       ierr = op->ApplyAddComposite(op, in, out, request); CeedChk(ierr);
1142cae8b89aSjeremylt     } else {
1143d1d35e2fSjeremylt       CeedInt num_suboperators;
1144d1d35e2fSjeremylt       ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr);
1145d1d35e2fSjeremylt       CeedOperator *sub_operators;
1146d1d35e2fSjeremylt       ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr);
1147250756a7Sjeremylt 
1148d1d35e2fSjeremylt       for (CeedInt i=0; i<num_suboperators; i++) {
1149d1d35e2fSjeremylt         ierr = CeedOperatorApplyAdd(sub_operators[i], in, out, request);
1150cae8b89aSjeremylt         CeedChk(ierr);
11511d7d2407SJeremy L Thompson       }
1152250756a7Sjeremylt     }
1153250756a7Sjeremylt   }
1154e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1155d7b241e6Sjeremylt }
1156d7b241e6Sjeremylt 
1157d7b241e6Sjeremylt /**
1158b11c1e72Sjeremylt   @brief Destroy a CeedOperator
1159d7b241e6Sjeremylt 
1160d7b241e6Sjeremylt   @param op  CeedOperator to destroy
1161b11c1e72Sjeremylt 
1162b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
1163dfdf5a53Sjeremylt 
11647a982d89SJeremy L. Thompson   @ref User
1165b11c1e72Sjeremylt **/
1166d7b241e6Sjeremylt int CeedOperatorDestroy(CeedOperator *op) {
1167d7b241e6Sjeremylt   int ierr;
1168d7b241e6Sjeremylt 
1169d1d35e2fSjeremylt   if (!*op || --(*op)->ref_count > 0) return CEED_ERROR_SUCCESS;
1170d7b241e6Sjeremylt   if ((*op)->Destroy) {
1171d7b241e6Sjeremylt     ierr = (*op)->Destroy(*op); CeedChk(ierr);
1172d7b241e6Sjeremylt   }
1173fe2413ffSjeremylt   ierr = CeedDestroy(&(*op)->ceed); CeedChk(ierr);
1174fe2413ffSjeremylt   // Free fields
1175d1d35e2fSjeremylt   for (int i=0; i<(*op)->num_fields; i++)
1176d1d35e2fSjeremylt     if ((*op)->input_fields[i]) {
1177d1d35e2fSjeremylt       if ((*op)->input_fields[i]->elem_restr != CEED_ELEMRESTRICTION_NONE) {
1178d1d35e2fSjeremylt         ierr = CeedElemRestrictionDestroy(&(*op)->input_fields[i]->elem_restr);
117971352a93Sjeremylt         CeedChk(ierr);
118015910d16Sjeremylt       }
1181d1d35e2fSjeremylt       if ((*op)->input_fields[i]->basis != CEED_BASIS_COLLOCATED) {
1182d1d35e2fSjeremylt         ierr = CeedBasisDestroy(&(*op)->input_fields[i]->basis); CeedChk(ierr);
118371352a93Sjeremylt       }
1184d1d35e2fSjeremylt       if ((*op)->input_fields[i]->vec != CEED_VECTOR_ACTIVE &&
1185d1d35e2fSjeremylt           (*op)->input_fields[i]->vec != CEED_VECTOR_NONE ) {
1186d1d35e2fSjeremylt         ierr = CeedVectorDestroy(&(*op)->input_fields[i]->vec); CeedChk(ierr);
118771352a93Sjeremylt       }
1188d1d35e2fSjeremylt       ierr = CeedFree(&(*op)->input_fields[i]->field_name); CeedChk(ierr);
1189d1d35e2fSjeremylt       ierr = CeedFree(&(*op)->input_fields[i]); CeedChk(ierr);
1190fe2413ffSjeremylt     }
1191d1d35e2fSjeremylt   for (int i=0; i<(*op)->num_fields; i++)
1192d1d35e2fSjeremylt     if ((*op)->output_fields[i]) {
1193d1d35e2fSjeremylt       ierr = CeedElemRestrictionDestroy(&(*op)->output_fields[i]->elem_restr);
119471352a93Sjeremylt       CeedChk(ierr);
1195d1d35e2fSjeremylt       if ((*op)->output_fields[i]->basis != CEED_BASIS_COLLOCATED) {
1196d1d35e2fSjeremylt         ierr = CeedBasisDestroy(&(*op)->output_fields[i]->basis); CeedChk(ierr);
119771352a93Sjeremylt       }
1198d1d35e2fSjeremylt       if ((*op)->output_fields[i]->vec != CEED_VECTOR_ACTIVE &&
1199d1d35e2fSjeremylt           (*op)->output_fields[i]->vec != CEED_VECTOR_NONE ) {
1200d1d35e2fSjeremylt         ierr = CeedVectorDestroy(&(*op)->output_fields[i]->vec); CeedChk(ierr);
120171352a93Sjeremylt       }
1202d1d35e2fSjeremylt       ierr = CeedFree(&(*op)->output_fields[i]->field_name); CeedChk(ierr);
1203d1d35e2fSjeremylt       ierr = CeedFree(&(*op)->output_fields[i]); CeedChk(ierr);
1204fe2413ffSjeremylt     }
1205d1d35e2fSjeremylt   // Destroy sub_operators
1206d1d35e2fSjeremylt   for (int i=0; i<(*op)->num_suboperators; i++)
1207d1d35e2fSjeremylt     if ((*op)->sub_operators[i]) {
1208d1d35e2fSjeremylt       ierr = CeedOperatorDestroy(&(*op)->sub_operators[i]); CeedChk(ierr);
120952d6035fSJeremy L Thompson     }
1210d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->qf); CeedChk(ierr);
1211d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->dqf); CeedChk(ierr);
1212d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->dqfT); CeedChk(ierr);
1213fe2413ffSjeremylt 
12145107b09fSJeremy L Thompson   // Destroy fallback
1215d1d35e2fSjeremylt   if ((*op)->op_fallback) {
1216d1d35e2fSjeremylt     ierr = (*op)->qf_fallback->Destroy((*op)->qf_fallback); CeedChk(ierr);
1217d1d35e2fSjeremylt     ierr = CeedFree(&(*op)->qf_fallback); CeedChk(ierr);
121870a7ffb3SJeremy L Thompson     ierr = CeedVectorDestroy(&(*op)->op_fallback->qf_assembled); CeedChk(ierr);
121970a7ffb3SJeremy L Thompson     ierr = CeedElemRestrictionDestroy(&(*op)->op_fallback->qf_assembled_rstr);
122070a7ffb3SJeremy L Thompson     CeedChk(ierr);
1221d1d35e2fSjeremylt     ierr = (*op)->op_fallback->Destroy((*op)->op_fallback); CeedChk(ierr);
1222d1d35e2fSjeremylt     ierr = CeedFree(&(*op)->op_fallback); CeedChk(ierr);
12235107b09fSJeremy L Thompson   }
12245107b09fSJeremy L Thompson 
122570a7ffb3SJeremy L Thompson   // Destroy QF assembly cache
122670a7ffb3SJeremy L Thompson   ierr = CeedVectorDestroy(&(*op)->qf_assembled); CeedChk(ierr);
122770a7ffb3SJeremy L Thompson   ierr = CeedElemRestrictionDestroy(&(*op)->qf_assembled_rstr); CeedChk(ierr);
122870a7ffb3SJeremy L Thompson 
1229d1d35e2fSjeremylt   ierr = CeedFree(&(*op)->input_fields); CeedChk(ierr);
1230d1d35e2fSjeremylt   ierr = CeedFree(&(*op)->output_fields); CeedChk(ierr);
1231d1d35e2fSjeremylt   ierr = CeedFree(&(*op)->sub_operators); CeedChk(ierr);
1232d7b241e6Sjeremylt   ierr = CeedFree(op); CeedChk(ierr);
1233e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1234d7b241e6Sjeremylt }
1235d7b241e6Sjeremylt 
1236d7b241e6Sjeremylt /// @}
1237