xref: /libCEED/rust/libceed-sys/c-src/interface/ceed-operator.c (revision 43622462ff3b1e6f216f011e0b35418088f3edba)
13d8e8822SJeremy L Thompson // Copyright (c) 2017-2022, Lawrence Livermore National Security, LLC and other CEED contributors.
23d8e8822SJeremy L Thompson // All Rights Reserved. See the top-level LICENSE and NOTICE files for details.
3d7b241e6Sjeremylt //
43d8e8822SJeremy L Thompson // SPDX-License-Identifier: BSD-2-Clause
5d7b241e6Sjeremylt //
63d8e8822SJeremy L Thompson // This file is part of CEED:  http://github.com/ceed
7d7b241e6Sjeremylt 
8ec3da8bcSJed Brown #include <ceed/ceed.h>
9ec3da8bcSJed Brown #include <ceed/backend.h>
103d576824SJeremy L Thompson #include <ceed-impl.h>
113d576824SJeremy L Thompson #include <stdbool.h>
123d576824SJeremy L Thompson #include <stdio.h>
133d576824SJeremy L Thompson #include <string.h>
14d7b241e6Sjeremylt 
15dfdf5a53Sjeremylt /// @file
167a982d89SJeremy L. Thompson /// Implementation of CeedOperator interfaces
177a982d89SJeremy L. Thompson 
187a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
197a982d89SJeremy L. Thompson /// CeedOperator Library Internal Functions
207a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
217a982d89SJeremy L. Thompson /// @addtogroup CeedOperatorDeveloper
227a982d89SJeremy L. Thompson /// @{
237a982d89SJeremy L. Thompson 
247a982d89SJeremy L. Thompson /**
25e15f9bd0SJeremy L Thompson   @brief Check if a CeedOperator Field matches the QFunction Field
26e15f9bd0SJeremy L Thompson 
27e15f9bd0SJeremy L Thompson   @param[in] ceed      Ceed object for error handling
28d1d35e2fSjeremylt   @param[in] qf_field  QFunction Field matching Operator Field
29e15f9bd0SJeremy L Thompson   @param[in] r         Operator Field ElemRestriction
30e15f9bd0SJeremy L Thompson   @param[in] b         Operator Field Basis
31e15f9bd0SJeremy L Thompson 
32e15f9bd0SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
33e15f9bd0SJeremy L Thompson 
34e15f9bd0SJeremy L Thompson   @ref Developer
35e15f9bd0SJeremy L Thompson **/
36d1d35e2fSjeremylt static int CeedOperatorCheckField(Ceed ceed, CeedQFunctionField qf_field,
37e15f9bd0SJeremy L Thompson                                   CeedElemRestriction r, CeedBasis b) {
38e15f9bd0SJeremy L Thompson   int ierr;
39d1d35e2fSjeremylt   CeedEvalMode eval_mode = qf_field->eval_mode;
404d5194faSrezgarshakeri   CeedInt dim = 1, num_comp = 1, Q_comp = 1, restr_num_comp = 1,
414d5194faSrezgarshakeri           size = qf_field->size;
42e15f9bd0SJeremy L Thompson   // Restriction
43e15f9bd0SJeremy L Thompson   if (r != CEED_ELEMRESTRICTION_NONE) {
44d1d35e2fSjeremylt     if (eval_mode == CEED_EVAL_WEIGHT) {
45e15f9bd0SJeremy L Thompson       // LCOV_EXCL_START
46e1e9e29dSJed Brown       return CeedError(ceed, CEED_ERROR_INCOMPATIBLE,
47e1e9e29dSJed Brown                        "CEED_ELEMRESTRICTION_NONE should be used "
48e15f9bd0SJeremy L Thompson                        "for a field with eval mode CEED_EVAL_WEIGHT");
49e15f9bd0SJeremy L Thompson       // LCOV_EXCL_STOP
50e15f9bd0SJeremy L Thompson     }
51d1d35e2fSjeremylt     ierr = CeedElemRestrictionGetNumComponents(r, &restr_num_comp);
5278464608Sjeremylt     CeedChk(ierr);
53e1e9e29dSJed Brown   }
54d1d35e2fSjeremylt   if ((r == CEED_ELEMRESTRICTION_NONE) != (eval_mode == CEED_EVAL_WEIGHT)) {
55e1e9e29dSJed Brown     // LCOV_EXCL_START
56e1e9e29dSJed Brown     return CeedError(ceed, CEED_ERROR_INCOMPATIBLE,
57e1e9e29dSJed Brown                      "CEED_ELEMRESTRICTION_NONE and CEED_EVAL_WEIGHT "
58e1e9e29dSJed Brown                      "must be used together.");
59e1e9e29dSJed Brown     // LCOV_EXCL_STOP
60e1e9e29dSJed Brown   }
61e15f9bd0SJeremy L Thompson   // Basis
62e15f9bd0SJeremy L Thompson   if (b != CEED_BASIS_COLLOCATED) {
63d1d35e2fSjeremylt     if (eval_mode == CEED_EVAL_NONE)
648229195eSjeremylt       // LCOV_EXCL_START
65e1e9e29dSJed Brown       return CeedError(ceed, CEED_ERROR_INCOMPATIBLE,
66d1d35e2fSjeremylt                        "Field '%s' configured with CEED_EVAL_NONE must "
67d1d35e2fSjeremylt                        "be used with CEED_BASIS_COLLOCATED",
68d1d35e2fSjeremylt                        qf_field->field_name);
6941bdf1c9SJeremy L Thompson     // LCOV_EXCL_STOP
70e15f9bd0SJeremy L Thompson     ierr = CeedBasisGetDimension(b, &dim); CeedChk(ierr);
71d1d35e2fSjeremylt     ierr = CeedBasisGetNumComponents(b, &num_comp); CeedChk(ierr);
724d5194faSrezgarshakeri     ierr = CeedBasisGetNumQuadratureComponents(b, &Q_comp); CeedChk(ierr);
73d1d35e2fSjeremylt     if (r != CEED_ELEMRESTRICTION_NONE && restr_num_comp != num_comp) {
74e15f9bd0SJeremy L Thompson       // LCOV_EXCL_START
75e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_DIMENSION,
76990fdeb6SJeremy L Thompson                        "Field '%s' of size %" CeedInt_FMT " and EvalMode %s: ElemRestriction "
77990fdeb6SJeremy L Thompson                        "has %" CeedInt_FMT " components, but Basis has %" CeedInt_FMT " components",
78d1d35e2fSjeremylt                        qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode],
794d5194faSrezgarshakeri                        restr_num_comp, num_comp);
80e15f9bd0SJeremy L Thompson       // LCOV_EXCL_STOP
81e15f9bd0SJeremy L Thompson     }
8241bdf1c9SJeremy L Thompson   } else if (eval_mode != CEED_EVAL_NONE) {
8341bdf1c9SJeremy L Thompson     // LCOV_EXCL_START
8441bdf1c9SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_INCOMPATIBLE,
8541bdf1c9SJeremy L Thompson                      "Field '%s' configured with %s cannot "
8641bdf1c9SJeremy L Thompson                      "be used with CEED_BASIS_COLLOCATED",
8741bdf1c9SJeremy L Thompson                      qf_field->field_name, CeedEvalModes[eval_mode]);
8841bdf1c9SJeremy L Thompson     // LCOV_EXCL_STOP
8941bdf1c9SJeremy 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,
97990fdeb6SJeremy L Thompson                        "Field '%s' of size %" CeedInt_FMT " and EvalMode %s: ElemRestriction has "
98990fdeb6SJeremy L Thompson                        CeedInt_FMT " components",
99d1d35e2fSjeremylt                        qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode],
100d1d35e2fSjeremylt                        restr_num_comp);
101e15f9bd0SJeremy L Thompson     // LCOV_EXCL_STOP
102e15f9bd0SJeremy L Thompson     break;
103e15f9bd0SJeremy L Thompson   case CEED_EVAL_INTERP:
104a0c16c2cSrezgarshakeri     if (size != num_comp*Q_comp)
105e15f9bd0SJeremy L Thompson       // LCOV_EXCL_START
106e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_DIMENSION,
107990fdeb6SJeremy L Thompson                        "Field '%s' of size %" CeedInt_FMT
108990fdeb6SJeremy L Thompson                        " and EvalMode %s: ElemRestriction/Basis has "
109990fdeb6SJeremy L Thompson                        CeedInt_FMT " components",
110d1d35e2fSjeremylt                        qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode],
111a0c16c2cSrezgarshakeri                        num_comp*Q_comp);
112e15f9bd0SJeremy L Thompson     // LCOV_EXCL_STOP
113e15f9bd0SJeremy L Thompson     break;
114e15f9bd0SJeremy L Thompson   case CEED_EVAL_GRAD:
115d1d35e2fSjeremylt     if (size != num_comp * dim)
116e15f9bd0SJeremy L Thompson       // LCOV_EXCL_START
117e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_DIMENSION,
118990fdeb6SJeremy L Thompson                        "Field '%s' of size %" CeedInt_FMT " and EvalMode %s in %" CeedInt_FMT
119990fdeb6SJeremy L Thompson                        " dimensions: "
120990fdeb6SJeremy L Thompson                        "ElemRestriction/Basis has %" CeedInt_FMT " components",
121d1d35e2fSjeremylt                        qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode], dim,
122d1d35e2fSjeremylt                        num_comp);
123e15f9bd0SJeremy L Thompson     // LCOV_EXCL_STOP
124e15f9bd0SJeremy L Thompson     break;
125e15f9bd0SJeremy L Thompson   case CEED_EVAL_WEIGHT:
126d1d35e2fSjeremylt     // No additional checks required
127e15f9bd0SJeremy L Thompson     break;
128e15f9bd0SJeremy L Thompson   case CEED_EVAL_DIV:
129a0c16c2cSrezgarshakeri     if (size != num_comp)
130a0c16c2cSrezgarshakeri       // LCOV_EXCL_START
131a0c16c2cSrezgarshakeri       return CeedError(ceed, CEED_ERROR_DIMENSION,
132a0c16c2cSrezgarshakeri                        "Field '%s' of size %" CeedInt_FMT
133a0c16c2cSrezgarshakeri                        " and EvalMode %s: ElemRestriction/Basis has "
134a0c16c2cSrezgarshakeri                        CeedInt_FMT " components",
135a0c16c2cSrezgarshakeri                        qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode],
136a0c16c2cSrezgarshakeri                        num_comp);
137a0c16c2cSrezgarshakeri     // LCOV_EXCL_STOP
138e15f9bd0SJeremy L Thompson     break;
139e15f9bd0SJeremy L Thompson   case CEED_EVAL_CURL:
140e15f9bd0SJeremy L Thompson     // Not implemented
141e15f9bd0SJeremy L Thompson     break;
142e15f9bd0SJeremy L Thompson   }
143e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1447a982d89SJeremy L. Thompson }
1457a982d89SJeremy L. Thompson 
1467a982d89SJeremy L. Thompson /**
1477a982d89SJeremy L. Thompson   @brief View a field of a CeedOperator
1487a982d89SJeremy L. Thompson 
1497a982d89SJeremy L. Thompson   @param[in] field         Operator field to view
150d1d35e2fSjeremylt   @param[in] qf_field      QFunction field (carries field name)
151d1d35e2fSjeremylt   @param[in] field_number  Number of field being viewed
1524c4400c7SValeria Barra   @param[in] sub           true indicates sub-operator, which increases indentation; false for top-level operator
153d1d35e2fSjeremylt   @param[in] input         true for an input field; false for output field
1547a982d89SJeremy L. Thompson   @param[in] stream        Stream to view to, e.g., stdout
1557a982d89SJeremy L. Thompson 
1567a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
1577a982d89SJeremy L. Thompson 
1587a982d89SJeremy L. Thompson   @ref Utility
1597a982d89SJeremy L. Thompson **/
1607a982d89SJeremy L. Thompson static int CeedOperatorFieldView(CeedOperatorField field,
161d1d35e2fSjeremylt                                  CeedQFunctionField qf_field,
162d1d35e2fSjeremylt                                  CeedInt field_number, bool sub, bool input,
1637a982d89SJeremy L. Thompson                                  FILE *stream) {
1647a982d89SJeremy L. Thompson   const char *pre = sub ? "  " : "";
165d1d35e2fSjeremylt   const char *in_out = input ? "Input" : "Output";
1667a982d89SJeremy L. Thompson 
167990fdeb6SJeremy L Thompson   fprintf(stream, "%s    %s field %" CeedInt_FMT ":\n"
1687a982d89SJeremy L. Thompson           "%s      Name: \"%s\"\n",
169d1d35e2fSjeremylt           pre, in_out, field_number, pre, qf_field->field_name);
1707a982d89SJeremy L. Thompson 
171990fdeb6SJeremy L Thompson   fprintf(stream, "%s      Size: %" CeedInt_FMT "\n", pre, qf_field->size);
172f5ebfb90SJeremy L Thompson 
173f5ebfb90SJeremy L Thompson   fprintf(stream, "%s      EvalMode: %s\n", pre,
174f5ebfb90SJeremy L Thompson           CeedEvalModes[qf_field->eval_mode]);
175f5ebfb90SJeremy L Thompson 
1767a982d89SJeremy L. Thompson   if (field->basis == CEED_BASIS_COLLOCATED)
1777a982d89SJeremy L. Thompson     fprintf(stream, "%s      Collocated basis\n", pre);
1787a982d89SJeremy L. Thompson 
1797a982d89SJeremy L. Thompson   if (field->vec == CEED_VECTOR_ACTIVE)
1807a982d89SJeremy L. Thompson     fprintf(stream, "%s      Active vector\n", pre);
1817a982d89SJeremy L. Thompson   else if (field->vec == CEED_VECTOR_NONE)
1827a982d89SJeremy L. Thompson     fprintf(stream, "%s      No vector\n", pre);
183f5ebfb90SJeremy L Thompson 
184e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1857a982d89SJeremy L. Thompson }
1867a982d89SJeremy L. Thompson 
1877a982d89SJeremy L. Thompson /**
1887a982d89SJeremy L. Thompson   @brief View a single CeedOperator
1897a982d89SJeremy L. Thompson 
1907a982d89SJeremy L. Thompson   @param[in] op      CeedOperator to view
1917a982d89SJeremy L. Thompson   @param[in] sub     Boolean flag for sub-operator
1927a982d89SJeremy L. Thompson   @param[in] stream  Stream to write; typically stdout/stderr or a file
1937a982d89SJeremy L. Thompson 
1947a982d89SJeremy L. Thompson   @return Error code: 0 - success, otherwise - failure
1957a982d89SJeremy L. Thompson 
1967a982d89SJeremy L. Thompson   @ref Utility
1977a982d89SJeremy L. Thompson **/
1987a982d89SJeremy L. Thompson int CeedOperatorSingleView(CeedOperator op, bool sub, FILE *stream) {
1997a982d89SJeremy L. Thompson   int ierr;
2007a982d89SJeremy L. Thompson   const char *pre = sub ? "  " : "";
2017a982d89SJeremy L. Thompson 
202381e6593SJeremy L Thompson   CeedInt num_elem, num_qpts;
203381e6593SJeremy L Thompson   ierr = CeedOperatorGetNumElements(op, &num_elem); CeedChk(ierr);
204381e6593SJeremy L Thompson   ierr = CeedOperatorGetNumQuadraturePoints(op, &num_qpts); CeedChk(ierr);
205381e6593SJeremy L Thompson 
20678464608Sjeremylt   CeedInt total_fields = 0;
20778464608Sjeremylt   ierr = CeedOperatorGetNumArgs(op, &total_fields); CeedChk(ierr);
208990fdeb6SJeremy L Thompson   fprintf(stream, "%s  %" CeedInt_FMT " elements with %" CeedInt_FMT
209990fdeb6SJeremy L Thompson           " quadrature points each\n",
210381e6593SJeremy L Thompson           pre, num_elem, num_qpts);
2117a982d89SJeremy L. Thompson 
212990fdeb6SJeremy L Thompson   fprintf(stream, "%s  %" CeedInt_FMT " field%s\n", pre, total_fields,
21378464608Sjeremylt           total_fields>1 ? "s" : "");
2147a982d89SJeremy L. Thompson 
215990fdeb6SJeremy L Thompson   fprintf(stream, "%s  %" CeedInt_FMT " input field%s:\n", pre,
216990fdeb6SJeremy L Thompson           op->qf->num_input_fields,
217d1d35e2fSjeremylt           op->qf->num_input_fields>1 ? "s" : "");
218d1d35e2fSjeremylt   for (CeedInt i=0; i<op->qf->num_input_fields; i++) {
219d1d35e2fSjeremylt     ierr = CeedOperatorFieldView(op->input_fields[i], op->qf->input_fields[i],
2207a982d89SJeremy L. Thompson                                  i, sub, 1, stream); CeedChk(ierr);
2217a982d89SJeremy L. Thompson   }
2227a982d89SJeremy L. Thompson 
223990fdeb6SJeremy L Thompson   fprintf(stream, "%s  %" CeedInt_FMT " output field%s:\n", pre,
224990fdeb6SJeremy L Thompson           op->qf->num_output_fields,
225d1d35e2fSjeremylt           op->qf->num_output_fields>1 ? "s" : "");
226d1d35e2fSjeremylt   for (CeedInt i=0; i<op->qf->num_output_fields; i++) {
227d1d35e2fSjeremylt     ierr = CeedOperatorFieldView(op->output_fields[i], op->qf->output_fields[i],
2287a982d89SJeremy L. Thompson                                  i, sub, 0, stream); CeedChk(ierr);
2297a982d89SJeremy L. Thompson   }
230e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2317a982d89SJeremy L. Thompson }
2327a982d89SJeremy L. Thompson 
233d99fa3c5SJeremy L Thompson /**
2340f60e0a8SJeremy L Thompson   @brief Find the active vector basis for a non-composite CeedOperator
235eaf62fffSJeremy L Thompson 
236eaf62fffSJeremy L Thompson   @param[in] op             CeedOperator to find active basis for
2370f60e0a8SJeremy L Thompson   @param[out] active_basis  Basis for active input vector or NULL for composite operator
238eaf62fffSJeremy L Thompson 
239eaf62fffSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
240eaf62fffSJeremy L Thompson 
241eaf62fffSJeremy L Thompson   @ ref Developer
242eaf62fffSJeremy L Thompson **/
243eaf62fffSJeremy L Thompson int CeedOperatorGetActiveBasis(CeedOperator op, CeedBasis *active_basis) {
244eaf62fffSJeremy L Thompson   *active_basis = NULL;
2450f60e0a8SJeremy L Thompson   if (op->is_composite) return CEED_ERROR_SUCCESS;
24692ae7e47SJeremy L Thompson   for (CeedInt i = 0; i < op->qf->num_input_fields; i++)
247eaf62fffSJeremy L Thompson     if (op->input_fields[i]->vec == CEED_VECTOR_ACTIVE) {
248eaf62fffSJeremy L Thompson       *active_basis = op->input_fields[i]->basis;
249eaf62fffSJeremy L Thompson       break;
250eaf62fffSJeremy L Thompson     }
251eaf62fffSJeremy L Thompson 
252eaf62fffSJeremy L Thompson   if (!*active_basis) {
253eaf62fffSJeremy L Thompson     // LCOV_EXCL_START
254eaf62fffSJeremy L Thompson     int ierr;
255eaf62fffSJeremy L Thompson     Ceed ceed;
256eaf62fffSJeremy L Thompson     ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr);
257eaf62fffSJeremy L Thompson     return CeedError(ceed, CEED_ERROR_MINOR,
258eaf62fffSJeremy L Thompson                      "No active CeedBasis found");
259eaf62fffSJeremy L Thompson     // LCOV_EXCL_STOP
260eaf62fffSJeremy L Thompson   }
261eaf62fffSJeremy L Thompson   return CEED_ERROR_SUCCESS;
262eaf62fffSJeremy L Thompson }
263eaf62fffSJeremy L Thompson 
264eaf62fffSJeremy L Thompson /**
2650f60e0a8SJeremy L Thompson   @brief Find the active vector ElemRestriction for a non-composite CeedOperator
266e2f04181SAndrew T. Barker 
267e2f04181SAndrew T. Barker   @param[in] op            CeedOperator to find active basis for
2680f60e0a8SJeremy L Thompson   @param[out] active_rstr  ElemRestriction for active input vector or NULL for composite operator
269e2f04181SAndrew T. Barker 
270e2f04181SAndrew T. Barker   @return An error code: 0 - success, otherwise - failure
271e2f04181SAndrew T. Barker 
272e2f04181SAndrew T. Barker   @ref Utility
273e2f04181SAndrew T. Barker **/
274eaf62fffSJeremy L Thompson int CeedOperatorGetActiveElemRestriction(CeedOperator op,
275d1d35e2fSjeremylt     CeedElemRestriction *active_rstr) {
276d1d35e2fSjeremylt   *active_rstr = NULL;
2770f60e0a8SJeremy L Thompson   if (op->is_composite) return CEED_ERROR_SUCCESS;
27892ae7e47SJeremy L Thompson   for (CeedInt i = 0; i < op->qf->num_input_fields; i++)
279d1d35e2fSjeremylt     if (op->input_fields[i]->vec == CEED_VECTOR_ACTIVE) {
280d1d35e2fSjeremylt       *active_rstr = op->input_fields[i]->elem_restr;
281e2f04181SAndrew T. Barker       break;
282e2f04181SAndrew T. Barker     }
283e2f04181SAndrew T. Barker 
284d1d35e2fSjeremylt   if (!*active_rstr) {
285e2f04181SAndrew T. Barker     // LCOV_EXCL_START
286e2f04181SAndrew T. Barker     int ierr;
287e2f04181SAndrew T. Barker     Ceed ceed;
288e2f04181SAndrew T. Barker     ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr);
289e2f04181SAndrew T. Barker     return CeedError(ceed, CEED_ERROR_INCOMPLETE,
290eaf62fffSJeremy L Thompson                      "No active CeedElemRestriction found");
291e2f04181SAndrew T. Barker     // LCOV_EXCL_STOP
292e2f04181SAndrew T. Barker   }
293e2f04181SAndrew T. Barker   return CEED_ERROR_SUCCESS;
294e2f04181SAndrew T. Barker }
295e2f04181SAndrew T. Barker 
296d8dd9a91SJeremy L Thompson /**
297d8dd9a91SJeremy L Thompson   @brief Set QFunctionContext field value of the specified type.
298d8dd9a91SJeremy L Thompson            For composite operators, the value is set in all
299d8dd9a91SJeremy L Thompson            sub-operator QFunctionContexts that have a matching `field_name`.
300d8dd9a91SJeremy L Thompson            A non-zero error code is returned for single operators
301d8dd9a91SJeremy L Thompson            that do not have a matching field of the same type or composite
302d8dd9a91SJeremy L Thompson            operators that do not have any field of a matching type.
303d8dd9a91SJeremy L Thompson 
304d8dd9a91SJeremy L Thompson   @param op          CeedOperator
3053668ca4bSJeremy L Thompson   @param field_label Label of field to set
306d8dd9a91SJeremy L Thompson   @param field_type  Type of field to set
307d8dd9a91SJeremy L Thompson   @param value       Value to set
308d8dd9a91SJeremy L Thompson 
309d8dd9a91SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
310d8dd9a91SJeremy L Thompson 
311d8dd9a91SJeremy L Thompson   @ref User
312d8dd9a91SJeremy L Thompson **/
313d8dd9a91SJeremy L Thompson static int CeedOperatorContextSetGeneric(CeedOperator op,
3143668ca4bSJeremy L Thompson     CeedContextFieldLabel field_label, CeedContextFieldType field_type,
3153668ca4bSJeremy L Thompson     void *value) {
316d8dd9a91SJeremy L Thompson   int ierr;
317d8dd9a91SJeremy L Thompson 
3183668ca4bSJeremy L Thompson   if (!field_label)
3193668ca4bSJeremy L Thompson     // LCOV_EXCL_START
3203668ca4bSJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED,
3213668ca4bSJeremy L Thompson                      "Invalid field label");
3223668ca4bSJeremy L Thompson   // LCOV_EXCL_STOP
3233668ca4bSJeremy L Thompson 
3243668ca4bSJeremy L Thompson   bool is_composite = false;
325d8dd9a91SJeremy L Thompson   ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr);
326d8dd9a91SJeremy L Thompson   if (is_composite) {
327d8dd9a91SJeremy L Thompson     CeedInt num_sub;
328d8dd9a91SJeremy L Thompson     CeedOperator *sub_operators;
329d8dd9a91SJeremy L Thompson 
330d8dd9a91SJeremy L Thompson     ierr = CeedOperatorGetNumSub(op, &num_sub); CeedChk(ierr);
331d8dd9a91SJeremy L Thompson     ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr);
3323668ca4bSJeremy L Thompson     if (num_sub != field_label->num_sub_labels)
3333668ca4bSJeremy L Thompson       // LCOV_EXCL_START
3343668ca4bSJeremy L Thompson       return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED,
3353668ca4bSJeremy L Thompson                        "ContextLabel does not correspond to composite operator.\n"
3363668ca4bSJeremy L Thompson                        "Use CeedOperatorGetContextFieldLabel().");
3373668ca4bSJeremy L Thompson     // LCOV_EXCL_STOP
338d8dd9a91SJeremy L Thompson 
339d8dd9a91SJeremy L Thompson     for (CeedInt i = 0; i < num_sub; i++) {
340d8dd9a91SJeremy L Thompson       // Try every sub-operator, ok if some sub-operators do not have field
3413668ca4bSJeremy L Thompson       if (field_label->sub_labels[i] && sub_operators[i]->qf->ctx) {
3423668ca4bSJeremy L Thompson         ierr = CeedQFunctionContextSetGeneric(sub_operators[i]->qf->ctx,
3433668ca4bSJeremy L Thompson                                               field_label->sub_labels[i],
3443668ca4bSJeremy L Thompson                                               field_type, value); CeedChk(ierr);
345d8dd9a91SJeremy L Thompson       }
346d8dd9a91SJeremy L Thompson     }
347d8dd9a91SJeremy L Thompson   } else {
348d8dd9a91SJeremy L Thompson     if (!op->qf->ctx)
349d8dd9a91SJeremy L Thompson       // LCOV_EXCL_START
350d8dd9a91SJeremy L Thompson       return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED,
351d8dd9a91SJeremy L Thompson                        "QFunction does not have context data");
352d8dd9a91SJeremy L Thompson     // LCOV_EXCL_STOP
353d8dd9a91SJeremy L Thompson 
3543668ca4bSJeremy L Thompson     ierr = CeedQFunctionContextSetGeneric(op->qf->ctx, field_label,
3553668ca4bSJeremy L Thompson                                           field_type, value); CeedChk(ierr);
356d8dd9a91SJeremy L Thompson   }
357d8dd9a91SJeremy L Thompson 
358d8dd9a91SJeremy L Thompson   return CEED_ERROR_SUCCESS;
359d8dd9a91SJeremy L Thompson }
360d8dd9a91SJeremy L Thompson 
3617a982d89SJeremy L. Thompson /// @}
3627a982d89SJeremy L. Thompson 
3637a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
3647a982d89SJeremy L. Thompson /// CeedOperator Backend API
3657a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
3667a982d89SJeremy L. Thompson /// @addtogroup CeedOperatorBackend
3677a982d89SJeremy L. Thompson /// @{
3687a982d89SJeremy L. Thompson 
3697a982d89SJeremy L. Thompson /**
3707a982d89SJeremy L. Thompson   @brief Get the number of arguments associated with a CeedOperator
3717a982d89SJeremy L. Thompson 
3727a982d89SJeremy L. Thompson   @param op             CeedOperator
373d1d35e2fSjeremylt   @param[out] num_args  Variable to store vector number of arguments
3747a982d89SJeremy L. Thompson 
3757a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
3767a982d89SJeremy L. Thompson 
3777a982d89SJeremy L. Thompson   @ref Backend
3787a982d89SJeremy L. Thompson **/
3797a982d89SJeremy L. Thompson 
380d1d35e2fSjeremylt int CeedOperatorGetNumArgs(CeedOperator op, CeedInt *num_args) {
381f04ea552SJeremy L Thompson   if (op->is_composite)
3827a982d89SJeremy L. Thompson     // LCOV_EXCL_START
383e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
384e15f9bd0SJeremy L Thompson                      "Not defined for composite operators");
3857a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
3867a982d89SJeremy L. Thompson 
387d1d35e2fSjeremylt   *num_args = op->num_fields;
388e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
3897a982d89SJeremy L. Thompson }
3907a982d89SJeremy L. Thompson 
3917a982d89SJeremy L. Thompson /**
3927a982d89SJeremy L. Thompson   @brief Get the setup status of a CeedOperator
3937a982d89SJeremy L. Thompson 
3947a982d89SJeremy L. Thompson   @param op                  CeedOperator
395d1d35e2fSjeremylt   @param[out] is_setup_done  Variable to store setup status
3967a982d89SJeremy L. Thompson 
3977a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
3987a982d89SJeremy L. Thompson 
3997a982d89SJeremy L. Thompson   @ref Backend
4007a982d89SJeremy L. Thompson **/
4017a982d89SJeremy L. Thompson 
402d1d35e2fSjeremylt int CeedOperatorIsSetupDone(CeedOperator op, bool *is_setup_done) {
403f04ea552SJeremy L Thompson   *is_setup_done = op->is_backend_setup;
404e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
4057a982d89SJeremy L. Thompson }
4067a982d89SJeremy L. Thompson 
4077a982d89SJeremy L. Thompson /**
4087a982d89SJeremy L. Thompson   @brief Get the QFunction associated with a CeedOperator
4097a982d89SJeremy L. Thompson 
4107a982d89SJeremy L. Thompson   @param op       CeedOperator
4117a982d89SJeremy L. Thompson   @param[out] qf  Variable to store QFunction
4127a982d89SJeremy L. Thompson 
4137a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
4147a982d89SJeremy L. Thompson 
4157a982d89SJeremy L. Thompson   @ref Backend
4167a982d89SJeremy L. Thompson **/
4177a982d89SJeremy L. Thompson 
4187a982d89SJeremy L. Thompson int CeedOperatorGetQFunction(CeedOperator op, CeedQFunction *qf) {
419f04ea552SJeremy L Thompson   if (op->is_composite)
4207a982d89SJeremy L. Thompson     // LCOV_EXCL_START
421e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
422e15f9bd0SJeremy L Thompson                      "Not defined for composite operator");
4237a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
4247a982d89SJeremy L. Thompson 
4257a982d89SJeremy L. Thompson   *qf = op->qf;
426e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
4277a982d89SJeremy L. Thompson }
4287a982d89SJeremy L. Thompson 
4297a982d89SJeremy L. Thompson /**
430c04a41a7SJeremy L Thompson   @brief Get a boolean value indicating if the CeedOperator is composite
431c04a41a7SJeremy L Thompson 
432c04a41a7SJeremy L Thompson   @param op                 CeedOperator
433d1d35e2fSjeremylt   @param[out] is_composite  Variable to store composite status
434c04a41a7SJeremy L Thompson 
435c04a41a7SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
436c04a41a7SJeremy L Thompson 
437c04a41a7SJeremy L Thompson   @ref Backend
438c04a41a7SJeremy L Thompson **/
439c04a41a7SJeremy L Thompson 
440d1d35e2fSjeremylt int CeedOperatorIsComposite(CeedOperator op, bool *is_composite) {
441f04ea552SJeremy L Thompson   *is_composite = op->is_composite;
442e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
443c04a41a7SJeremy L Thompson }
444c04a41a7SJeremy L Thompson 
445c04a41a7SJeremy L Thompson /**
446d1d35e2fSjeremylt   @brief Get the number of sub_operators associated with a CeedOperator
4477a982d89SJeremy L. Thompson 
4487a982d89SJeremy L. Thompson   @param op                     CeedOperator
449d1d35e2fSjeremylt   @param[out] num_suboperators  Variable to store number of sub_operators
4507a982d89SJeremy L. Thompson 
4517a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
4527a982d89SJeremy L. Thompson 
4537a982d89SJeremy L. Thompson   @ref Backend
4547a982d89SJeremy L. Thompson **/
4557a982d89SJeremy L. Thompson 
456d1d35e2fSjeremylt int CeedOperatorGetNumSub(CeedOperator op, CeedInt *num_suboperators) {
457f04ea552SJeremy L Thompson   if (!op->is_composite)
4587a982d89SJeremy L. Thompson     // LCOV_EXCL_START
459e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR, "Not a composite operator");
4607a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
4617a982d89SJeremy L. Thompson 
462d1d35e2fSjeremylt   *num_suboperators = op->num_suboperators;
463e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
4647a982d89SJeremy L. Thompson }
4657a982d89SJeremy L. Thompson 
4667a982d89SJeremy L. Thompson /**
467d1d35e2fSjeremylt   @brief Get the list of sub_operators associated with a CeedOperator
4687a982d89SJeremy L. Thompson 
4697a982d89SJeremy L. Thompson   @param op                  CeedOperator
470d1d35e2fSjeremylt   @param[out] sub_operators  Variable to store list of sub_operators
4717a982d89SJeremy L. Thompson 
4727a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
4737a982d89SJeremy L. Thompson 
4747a982d89SJeremy L. Thompson   @ref Backend
4757a982d89SJeremy L. Thompson **/
4767a982d89SJeremy L. Thompson 
477d1d35e2fSjeremylt int CeedOperatorGetSubList(CeedOperator op, CeedOperator **sub_operators) {
478f04ea552SJeremy L Thompson   if (!op->is_composite)
4797a982d89SJeremy L. Thompson     // LCOV_EXCL_START
480e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR, "Not a composite operator");
4817a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
4827a982d89SJeremy L. Thompson 
483d1d35e2fSjeremylt   *sub_operators = op->sub_operators;
484e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
4857a982d89SJeremy L. Thompson }
4867a982d89SJeremy L. Thompson 
4877a982d89SJeremy L. Thompson /**
4887a982d89SJeremy L. Thompson   @brief Get the backend data of a CeedOperator
4897a982d89SJeremy L. Thompson 
4907a982d89SJeremy L. Thompson   @param op         CeedOperator
4917a982d89SJeremy L. Thompson   @param[out] data  Variable to store data
4927a982d89SJeremy L. Thompson 
4937a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
4947a982d89SJeremy L. Thompson 
4957a982d89SJeremy L. Thompson   @ref Backend
4967a982d89SJeremy L. Thompson **/
4977a982d89SJeremy L. Thompson 
498777ff853SJeremy L Thompson int CeedOperatorGetData(CeedOperator op, void *data) {
499777ff853SJeremy L Thompson   *(void **)data = op->data;
500e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5017a982d89SJeremy L. Thompson }
5027a982d89SJeremy L. Thompson 
5037a982d89SJeremy L. Thompson /**
5047a982d89SJeremy L. Thompson   @brief Set the backend data of a CeedOperator
5057a982d89SJeremy L. Thompson 
5067a982d89SJeremy L. Thompson   @param[out] op  CeedOperator
5077a982d89SJeremy L. Thompson   @param data     Data to set
5087a982d89SJeremy L. Thompson 
5097a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5107a982d89SJeremy L. Thompson 
5117a982d89SJeremy L. Thompson   @ref Backend
5127a982d89SJeremy L. Thompson **/
5137a982d89SJeremy L. Thompson 
514777ff853SJeremy L Thompson int CeedOperatorSetData(CeedOperator op, void *data) {
515777ff853SJeremy L Thompson   op->data = data;
516e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5177a982d89SJeremy L. Thompson }
5187a982d89SJeremy L. Thompson 
5197a982d89SJeremy L. Thompson /**
52034359f16Sjeremylt   @brief Increment the reference counter for a CeedOperator
52134359f16Sjeremylt 
52234359f16Sjeremylt   @param op  CeedOperator to increment the reference counter
52334359f16Sjeremylt 
52434359f16Sjeremylt   @return An error code: 0 - success, otherwise - failure
52534359f16Sjeremylt 
52634359f16Sjeremylt   @ref Backend
52734359f16Sjeremylt **/
5289560d06aSjeremylt int CeedOperatorReference(CeedOperator op) {
52934359f16Sjeremylt   op->ref_count++;
53034359f16Sjeremylt   return CEED_ERROR_SUCCESS;
53134359f16Sjeremylt }
53234359f16Sjeremylt 
53334359f16Sjeremylt /**
5347a982d89SJeremy L. Thompson   @brief Set the setup flag of a CeedOperator to True
5357a982d89SJeremy L. Thompson 
5367a982d89SJeremy L. Thompson   @param op  CeedOperator
5377a982d89SJeremy L. Thompson 
5387a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5397a982d89SJeremy L. Thompson 
5407a982d89SJeremy L. Thompson   @ref Backend
5417a982d89SJeremy L. Thompson **/
5427a982d89SJeremy L. Thompson 
5437a982d89SJeremy L. Thompson int CeedOperatorSetSetupDone(CeedOperator op) {
544f04ea552SJeremy L Thompson   op->is_backend_setup = true;
545e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5467a982d89SJeremy L. Thompson }
5477a982d89SJeremy L. Thompson 
5487a982d89SJeremy L. Thompson /// @}
5497a982d89SJeremy L. Thompson 
5507a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
5517a982d89SJeremy L. Thompson /// CeedOperator Public API
5527a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
5537a982d89SJeremy L. Thompson /// @addtogroup CeedOperatorUser
554dfdf5a53Sjeremylt /// @{
555d7b241e6Sjeremylt 
556d7b241e6Sjeremylt /**
5570219ea01SJeremy L Thompson   @brief Create a CeedOperator and associate a CeedQFunction. A CeedBasis and
5580219ea01SJeremy L Thompson            CeedElemRestriction can be associated with CeedQFunction fields with
5590219ea01SJeremy L Thompson            \ref CeedOperatorSetField.
560d7b241e6Sjeremylt 
561b11c1e72Sjeremylt   @param ceed     A Ceed object where the CeedOperator will be created
562d7b241e6Sjeremylt   @param qf       QFunction defining the action of the operator at quadrature points
56334138859Sjeremylt   @param dqf      QFunction defining the action of the Jacobian of @a qf (or
5644cc79fe7SJed Brown                     @ref CEED_QFUNCTION_NONE)
565d7b241e6Sjeremylt   @param dqfT     QFunction defining the action of the transpose of the Jacobian
5664cc79fe7SJed Brown                     of @a qf (or @ref CEED_QFUNCTION_NONE)
567b11c1e72Sjeremylt   @param[out] op  Address of the variable where the newly created
568b11c1e72Sjeremylt                     CeedOperator will be stored
569b11c1e72Sjeremylt 
570b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
571dfdf5a53Sjeremylt 
5727a982d89SJeremy L. Thompson   @ref User
573d7b241e6Sjeremylt  */
574d7b241e6Sjeremylt int CeedOperatorCreate(Ceed ceed, CeedQFunction qf, CeedQFunction dqf,
575d7b241e6Sjeremylt                        CeedQFunction dqfT, CeedOperator *op) {
576d7b241e6Sjeremylt   int ierr;
577d7b241e6Sjeremylt 
5785fe0d4faSjeremylt   if (!ceed->OperatorCreate) {
5795fe0d4faSjeremylt     Ceed delegate;
580aefd8378Sjeremylt     ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr);
5815fe0d4faSjeremylt 
5825fe0d4faSjeremylt     if (!delegate)
583c042f62fSJeremy L Thompson       // LCOV_EXCL_START
584e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_UNSUPPORTED,
585e15f9bd0SJeremy L Thompson                        "Backend does not support OperatorCreate");
586c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
5875fe0d4faSjeremylt 
5885fe0d4faSjeremylt     ierr = CeedOperatorCreate(delegate, qf, dqf, dqfT, op); CeedChk(ierr);
589e15f9bd0SJeremy L Thompson     return CEED_ERROR_SUCCESS;
5905fe0d4faSjeremylt   }
5915fe0d4faSjeremylt 
592b3b7035fSJeremy L Thompson   if (!qf || qf == CEED_QFUNCTION_NONE)
593b3b7035fSJeremy L Thompson     // LCOV_EXCL_START
594e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_MINOR,
595e15f9bd0SJeremy L Thompson                      "Operator must have a valid QFunction.");
596b3b7035fSJeremy L Thompson   // LCOV_EXCL_STOP
597d7b241e6Sjeremylt   ierr = CeedCalloc(1, op); CeedChk(ierr);
598d7b241e6Sjeremylt   (*op)->ceed = ceed;
5999560d06aSjeremylt   ierr = CeedReference(ceed); CeedChk(ierr);
600d1d35e2fSjeremylt   (*op)->ref_count = 1;
601d7b241e6Sjeremylt   (*op)->qf = qf;
6022b104005SJeremy L Thompson   (*op)->input_size = -1;
6032b104005SJeremy L Thompson   (*op)->output_size = -1;
6049560d06aSjeremylt   ierr = CeedQFunctionReference(qf); CeedChk(ierr);
605442e7f0bSjeremylt   if (dqf && dqf != CEED_QFUNCTION_NONE) {
606d7b241e6Sjeremylt     (*op)->dqf = dqf;
6079560d06aSjeremylt     ierr = CeedQFunctionReference(dqf); CeedChk(ierr);
608442e7f0bSjeremylt   }
609442e7f0bSjeremylt   if (dqfT && dqfT != CEED_QFUNCTION_NONE) {
610d7b241e6Sjeremylt     (*op)->dqfT = dqfT;
6119560d06aSjeremylt     ierr = CeedQFunctionReference(dqfT); CeedChk(ierr);
612442e7f0bSjeremylt   }
613480fae85SJeremy L Thompson   ierr = CeedQFunctionAssemblyDataCreate(ceed, &(*op)->qf_assembled);
614480fae85SJeremy L Thompson   CeedChk(ierr);
615bf4cb664SJeremy L Thompson   ierr = CeedCalloc(CEED_FIELD_MAX, &(*op)->input_fields); CeedChk(ierr);
616bf4cb664SJeremy L Thompson   ierr = CeedCalloc(CEED_FIELD_MAX, &(*op)->output_fields); CeedChk(ierr);
617d7b241e6Sjeremylt   ierr = ceed->OperatorCreate(*op); CeedChk(ierr);
618e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
619d7b241e6Sjeremylt }
620d7b241e6Sjeremylt 
621d7b241e6Sjeremylt /**
62252d6035fSJeremy L Thompson   @brief Create an operator that composes the action of several operators
62352d6035fSJeremy L Thompson 
62452d6035fSJeremy L Thompson   @param ceed     A Ceed object where the CeedOperator will be created
62552d6035fSJeremy L Thompson   @param[out] op  Address of the variable where the newly created
62652d6035fSJeremy L Thompson                     Composite CeedOperator will be stored
62752d6035fSJeremy L Thompson 
62852d6035fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
62952d6035fSJeremy L Thompson 
6307a982d89SJeremy L. Thompson   @ref User
63152d6035fSJeremy L Thompson  */
63252d6035fSJeremy L Thompson int CeedCompositeOperatorCreate(Ceed ceed, CeedOperator *op) {
63352d6035fSJeremy L Thompson   int ierr;
63452d6035fSJeremy L Thompson 
63552d6035fSJeremy L Thompson   if (!ceed->CompositeOperatorCreate) {
63652d6035fSJeremy L Thompson     Ceed delegate;
637aefd8378Sjeremylt     ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr);
63852d6035fSJeremy L Thompson 
639250756a7Sjeremylt     if (delegate) {
64052d6035fSJeremy L Thompson       ierr = CeedCompositeOperatorCreate(delegate, op); CeedChk(ierr);
641e15f9bd0SJeremy L Thompson       return CEED_ERROR_SUCCESS;
64252d6035fSJeremy L Thompson     }
643250756a7Sjeremylt   }
64452d6035fSJeremy L Thompson 
64552d6035fSJeremy L Thompson   ierr = CeedCalloc(1, op); CeedChk(ierr);
64652d6035fSJeremy L Thompson   (*op)->ceed = ceed;
6479560d06aSjeremylt   ierr = CeedReference(ceed); CeedChk(ierr);
648996d9ab5SJed Brown   (*op)->ref_count = 1;
649f04ea552SJeremy L Thompson   (*op)->is_composite = true;
650bf4cb664SJeremy L Thompson   ierr = CeedCalloc(CEED_COMPOSITE_MAX, &(*op)->sub_operators); CeedChk(ierr);
6512b104005SJeremy L Thompson   (*op)->input_size = -1;
6522b104005SJeremy L Thompson   (*op)->output_size = -1;
653250756a7Sjeremylt 
654250756a7Sjeremylt   if (ceed->CompositeOperatorCreate) {
65552d6035fSJeremy L Thompson     ierr = ceed->CompositeOperatorCreate(*op); CeedChk(ierr);
656250756a7Sjeremylt   }
657e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
65852d6035fSJeremy L Thompson }
65952d6035fSJeremy L Thompson 
66052d6035fSJeremy L Thompson /**
6619560d06aSjeremylt   @brief Copy the pointer to a CeedOperator. Both pointers should
6629560d06aSjeremylt            be destroyed with `CeedOperatorDestroy()`;
6639560d06aSjeremylt            Note: If `*op_copy` is non-NULL, then it is assumed that
6649560d06aSjeremylt            `*op_copy` is a pointer to a CeedOperator. This
6659560d06aSjeremylt            CeedOperator will be destroyed if `*op_copy` is the only
6669560d06aSjeremylt            reference to this CeedOperator.
6679560d06aSjeremylt 
6689560d06aSjeremylt   @param op            CeedOperator to copy reference to
6699560d06aSjeremylt   @param[out] op_copy  Variable to store copied reference
6709560d06aSjeremylt 
6719560d06aSjeremylt   @return An error code: 0 - success, otherwise - failure
6729560d06aSjeremylt 
6739560d06aSjeremylt   @ref User
6749560d06aSjeremylt **/
6759560d06aSjeremylt int CeedOperatorReferenceCopy(CeedOperator op, CeedOperator *op_copy) {
6769560d06aSjeremylt   int ierr;
6779560d06aSjeremylt 
6789560d06aSjeremylt   ierr = CeedOperatorReference(op); CeedChk(ierr);
6799560d06aSjeremylt   ierr = CeedOperatorDestroy(op_copy); CeedChk(ierr);
6809560d06aSjeremylt   *op_copy = op;
6819560d06aSjeremylt   return CEED_ERROR_SUCCESS;
6829560d06aSjeremylt }
6839560d06aSjeremylt 
6849560d06aSjeremylt /**
685b11c1e72Sjeremylt   @brief Provide a field to a CeedOperator for use by its CeedQFunction
686d7b241e6Sjeremylt 
687d7b241e6Sjeremylt   This function is used to specify both active and passive fields to a
688d7b241e6Sjeremylt   CeedOperator.  For passive fields, a vector @arg v must be provided.  Passive
689d7b241e6Sjeremylt   fields can inputs or outputs (updated in-place when operator is applied).
690d7b241e6Sjeremylt 
691d7b241e6Sjeremylt   Active fields must be specified using this function, but their data (in a
692d7b241e6Sjeremylt   CeedVector) is passed in CeedOperatorApply().  There can be at most one active
693979e564eSJames Wright   input CeedVector and at most one active output CeedVector passed to
694979e564eSJames Wright   CeedOperatorApply().
695d7b241e6Sjeremylt 
6968c91a0c9SJeremy L Thompson   @param op          CeedOperator on which to provide the field
697d1d35e2fSjeremylt   @param field_name  Name of the field (to be matched with the name used by
6988795c945Sjeremylt                        CeedQFunction)
699b11c1e72Sjeremylt   @param r           CeedElemRestriction
7004cc79fe7SJed Brown   @param b           CeedBasis in which the field resides or @ref CEED_BASIS_COLLOCATED
701b11c1e72Sjeremylt                        if collocated with quadrature points
7024cc79fe7SJed Brown   @param v           CeedVector to be used by CeedOperator or @ref CEED_VECTOR_ACTIVE
7034cc79fe7SJed Brown                        if field is active or @ref CEED_VECTOR_NONE if using
7044cc79fe7SJed Brown                        @ref CEED_EVAL_WEIGHT in the QFunction
705b11c1e72Sjeremylt 
706b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
707dfdf5a53Sjeremylt 
7087a982d89SJeremy L. Thompson   @ref User
709b11c1e72Sjeremylt **/
710d1d35e2fSjeremylt int CeedOperatorSetField(CeedOperator op, const char *field_name,
711a8d32208Sjeremylt                          CeedElemRestriction r, CeedBasis b, CeedVector v) {
712d7b241e6Sjeremylt   int ierr;
713f04ea552SJeremy L Thompson   if (op->is_composite)
714c042f62fSJeremy L Thompson     // LCOV_EXCL_START
715e1e9e29dSJed Brown     return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
716e15f9bd0SJeremy L Thompson                      "Cannot add field to composite operator.");
717c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
718f04ea552SJeremy L Thompson   if (op->is_immutable)
719f04ea552SJeremy L Thompson     // LCOV_EXCL_START
720f04ea552SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MAJOR,
721f04ea552SJeremy L Thompson                      "Operator cannot be changed after set as immutable");
722f04ea552SJeremy L Thompson   // LCOV_EXCL_STOP
7238b067b84SJed Brown   if (!r)
724c042f62fSJeremy L Thompson     // LCOV_EXCL_START
725e1e9e29dSJed Brown     return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
726c042f62fSJeremy L Thompson                      "ElemRestriction r for field \"%s\" must be non-NULL.",
727d1d35e2fSjeremylt                      field_name);
728c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
7298b067b84SJed Brown   if (!b)
730c042f62fSJeremy L Thompson     // LCOV_EXCL_START
731e1e9e29dSJed Brown     return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
732e15f9bd0SJeremy L Thompson                      "Basis b for field \"%s\" must be non-NULL.",
733d1d35e2fSjeremylt                      field_name);
734c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
7358b067b84SJed Brown   if (!v)
736c042f62fSJeremy L Thompson     // LCOV_EXCL_START
737e1e9e29dSJed Brown     return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
738e15f9bd0SJeremy L Thompson                      "Vector v for field \"%s\" must be non-NULL.",
739d1d35e2fSjeremylt                      field_name);
740c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
74152d6035fSJeremy L Thompson 
742d1d35e2fSjeremylt   CeedInt num_elem;
743d1d35e2fSjeremylt   ierr = CeedElemRestrictionGetNumElements(r, &num_elem); CeedChk(ierr);
744d1d35e2fSjeremylt   if (r != CEED_ELEMRESTRICTION_NONE && op->has_restriction &&
745d1d35e2fSjeremylt       op->num_elem != num_elem)
746c042f62fSJeremy L Thompson     // LCOV_EXCL_START
747e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_DIMENSION,
7486222cb59SJeremy L Thompson                      "ElemRestriction with %" CeedInt_FMT " elements incompatible with prior %"
749990fdeb6SJeremy L Thompson                      CeedInt_FMT " elements", num_elem, op->num_elem);
750c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
751d7b241e6Sjeremylt 
75278464608Sjeremylt   CeedInt num_qpts = 0;
753e15f9bd0SJeremy L Thompson   if (b != CEED_BASIS_COLLOCATED) {
754d1d35e2fSjeremylt     ierr = CeedBasisGetNumQuadraturePoints(b, &num_qpts); CeedChk(ierr);
755d1d35e2fSjeremylt     if (op->num_qpts && op->num_qpts != num_qpts)
756c042f62fSJeremy L Thompson       // LCOV_EXCL_START
757e15f9bd0SJeremy L Thompson       return CeedError(op->ceed, CEED_ERROR_DIMENSION,
758990fdeb6SJeremy L Thompson                        "Basis with %" CeedInt_FMT " quadrature points "
759990fdeb6SJeremy L Thompson                        "incompatible with prior %" CeedInt_FMT " points", num_qpts,
760d1d35e2fSjeremylt                        op->num_qpts);
761c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
762d7b241e6Sjeremylt   }
763d1d35e2fSjeremylt   CeedQFunctionField qf_field;
764d1d35e2fSjeremylt   CeedOperatorField *op_field;
7652b104005SJeremy L Thompson   bool is_input = true;
766d1d35e2fSjeremylt   for (CeedInt i=0; i<op->qf->num_input_fields; i++) {
767d1d35e2fSjeremylt     if (!strcmp(field_name, (*op->qf->input_fields[i]).field_name)) {
768d1d35e2fSjeremylt       qf_field = op->qf->input_fields[i];
769d1d35e2fSjeremylt       op_field = &op->input_fields[i];
770d7b241e6Sjeremylt       goto found;
771d7b241e6Sjeremylt     }
772d7b241e6Sjeremylt   }
7732b104005SJeremy L Thompson   is_input = false;
774d1d35e2fSjeremylt   for (CeedInt i=0; i<op->qf->num_output_fields; i++) {
775d1d35e2fSjeremylt     if (!strcmp(field_name, (*op->qf->output_fields[i]).field_name)) {
776d1d35e2fSjeremylt       qf_field = op->qf->output_fields[i];
777d1d35e2fSjeremylt       op_field = &op->output_fields[i];
778d7b241e6Sjeremylt       goto found;
779d7b241e6Sjeremylt     }
780d7b241e6Sjeremylt   }
781c042f62fSJeremy L Thompson   // LCOV_EXCL_START
782e15f9bd0SJeremy L Thompson   return CeedError(op->ceed, CEED_ERROR_INCOMPLETE,
783e15f9bd0SJeremy L Thompson                    "QFunction has no knowledge of field '%s'",
784d1d35e2fSjeremylt                    field_name);
785c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
786d7b241e6Sjeremylt found:
787d1d35e2fSjeremylt   ierr = CeedOperatorCheckField(op->ceed, qf_field, r, b); CeedChk(ierr);
788d1d35e2fSjeremylt   ierr = CeedCalloc(1, op_field); CeedChk(ierr);
789e15f9bd0SJeremy L Thompson 
7902b104005SJeremy L Thompson   if (v == CEED_VECTOR_ACTIVE) {
7912b104005SJeremy L Thompson     CeedSize l_size;
7922b104005SJeremy L Thompson     ierr = CeedElemRestrictionGetLVectorSize(r, &l_size); CeedChk(ierr);
7932b104005SJeremy L Thompson     if (is_input) {
7942b104005SJeremy L Thompson       if (op->input_size == -1) op->input_size = l_size;
7952b104005SJeremy L Thompson       if (l_size != op->input_size)
7962b104005SJeremy L Thompson         // LCOV_EXCL_START
7972b104005SJeremy L Thompson         return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
7982b104005SJeremy L Thompson                          "LVector size %td does not match previous size %td",
7992b104005SJeremy L Thompson                          l_size, op->input_size);
8002b104005SJeremy L Thompson       // LCOV_EXCL_STOP
8012b104005SJeremy L Thompson     } else {
8022b104005SJeremy L Thompson       if (op->output_size == -1) op->output_size = l_size;
8032b104005SJeremy L Thompson       if (l_size != op->output_size)
8042b104005SJeremy L Thompson         // LCOV_EXCL_START
8052b104005SJeremy L Thompson         return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
8062b104005SJeremy L Thompson                          "LVector size %td does not match previous size %td",
8072b104005SJeremy L Thompson                          l_size, op->output_size);
8082b104005SJeremy L Thompson       // LCOV_EXCL_STOP
8092b104005SJeremy L Thompson     }
8102b104005SJeremy L Thompson   }
8112b104005SJeremy L Thompson 
812d1d35e2fSjeremylt   (*op_field)->vec = v;
813e15f9bd0SJeremy L Thompson   if (v != CEED_VECTOR_ACTIVE && v != CEED_VECTOR_NONE) {
8149560d06aSjeremylt     ierr = CeedVectorReference(v); CeedChk(ierr);
815e15f9bd0SJeremy L Thompson   }
816e15f9bd0SJeremy L Thompson 
817d1d35e2fSjeremylt   (*op_field)->elem_restr = r;
8189560d06aSjeremylt   ierr = CeedElemRestrictionReference(r); CeedChk(ierr);
819e15f9bd0SJeremy L Thompson   if (r != CEED_ELEMRESTRICTION_NONE) {
820d1d35e2fSjeremylt     op->num_elem = num_elem;
821d1d35e2fSjeremylt     op->has_restriction = true; // Restriction set, but num_elem may be 0
822e15f9bd0SJeremy L Thompson   }
823d99fa3c5SJeremy L Thompson 
824d1d35e2fSjeremylt   (*op_field)->basis = b;
825e15f9bd0SJeremy L Thompson   if (b != CEED_BASIS_COLLOCATED) {
826cd4dfc48Sjeremylt     if (!op->num_qpts) {
827cd4dfc48Sjeremylt       ierr = CeedOperatorSetNumQuadraturePoints(op, num_qpts); CeedChk(ierr);
828cd4dfc48Sjeremylt     }
8299560d06aSjeremylt     ierr = CeedBasisReference(b); CeedChk(ierr);
830e15f9bd0SJeremy L Thompson   }
831e15f9bd0SJeremy L Thompson 
832d1d35e2fSjeremylt   op->num_fields += 1;
833f7e22acaSJeremy L Thompson   ierr = CeedStringAllocCopy(field_name, (char **)&(*op_field)->field_name);
834f7e22acaSJeremy L Thompson   CeedChk(ierr);
835e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
836d7b241e6Sjeremylt }
837d7b241e6Sjeremylt 
838d7b241e6Sjeremylt /**
83943bbe138SJeremy L Thompson   @brief Get the CeedOperatorFields of a CeedOperator
84043bbe138SJeremy L Thompson 
841f04ea552SJeremy L Thompson   Note: Calling this function asserts that setup is complete
842f04ea552SJeremy L Thompson           and sets the CeedOperator as immutable.
843f04ea552SJeremy L Thompson 
84443bbe138SJeremy L Thompson   @param op                      CeedOperator
845f74ec584SJeremy L Thompson   @param[out] num_input_fields   Variable to store number of input fields
84643bbe138SJeremy L Thompson   @param[out] input_fields       Variable to store input_fields
847f74ec584SJeremy L Thompson   @param[out] num_output_fields  Variable to store number of output fields
84843bbe138SJeremy L Thompson   @param[out] output_fields      Variable to store output_fields
84943bbe138SJeremy L Thompson 
85043bbe138SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
85143bbe138SJeremy L Thompson 
852e9b533fbSJeremy L Thompson   @ref Advanced
85343bbe138SJeremy L Thompson **/
85443bbe138SJeremy L Thompson int CeedOperatorGetFields(CeedOperator op, CeedInt *num_input_fields,
85543bbe138SJeremy L Thompson                           CeedOperatorField **input_fields,
85643bbe138SJeremy L Thompson                           CeedInt *num_output_fields,
85743bbe138SJeremy L Thompson                           CeedOperatorField **output_fields) {
858f04ea552SJeremy L Thompson   int ierr;
859f04ea552SJeremy L Thompson 
860f04ea552SJeremy L Thompson   if (op->is_composite)
86143bbe138SJeremy L Thompson     // LCOV_EXCL_START
86243bbe138SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
86343bbe138SJeremy L Thompson                      "Not defined for composite operator");
86443bbe138SJeremy L Thompson   // LCOV_EXCL_STOP
865f04ea552SJeremy L Thompson   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
86643bbe138SJeremy L Thompson 
86743bbe138SJeremy L Thompson   if (num_input_fields) *num_input_fields = op->qf->num_input_fields;
86843bbe138SJeremy L Thompson   if (input_fields) *input_fields = op->input_fields;
86943bbe138SJeremy L Thompson   if (num_output_fields) *num_output_fields = op->qf->num_output_fields;
87043bbe138SJeremy L Thompson   if (output_fields) *output_fields = op->output_fields;
87143bbe138SJeremy L Thompson   return CEED_ERROR_SUCCESS;
87243bbe138SJeremy L Thompson }
87343bbe138SJeremy L Thompson 
87443bbe138SJeremy L Thompson /**
87528567f8fSJeremy L Thompson   @brief Get the name of a CeedOperatorField
87628567f8fSJeremy L Thompson 
87728567f8fSJeremy L Thompson   @param op_field         CeedOperatorField
87828567f8fSJeremy L Thompson   @param[out] field_name  Variable to store the field name
87928567f8fSJeremy L Thompson 
88028567f8fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
88128567f8fSJeremy L Thompson 
882e9b533fbSJeremy L Thompson   @ref Advanced
88328567f8fSJeremy L Thompson **/
88428567f8fSJeremy L Thompson int CeedOperatorFieldGetName(CeedOperatorField op_field, char **field_name) {
88528567f8fSJeremy L Thompson   *field_name = (char *)op_field->field_name;
88628567f8fSJeremy L Thompson   return CEED_ERROR_SUCCESS;
88728567f8fSJeremy L Thompson }
88828567f8fSJeremy L Thompson 
88928567f8fSJeremy L Thompson /**
89043bbe138SJeremy L Thompson   @brief Get the CeedElemRestriction of a CeedOperatorField
89143bbe138SJeremy L Thompson 
89243bbe138SJeremy L Thompson   @param op_field   CeedOperatorField
89343bbe138SJeremy L Thompson   @param[out] rstr  Variable to store CeedElemRestriction
89443bbe138SJeremy L Thompson 
89543bbe138SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
89643bbe138SJeremy L Thompson 
897e9b533fbSJeremy L Thompson   @ref Advanced
89843bbe138SJeremy L Thompson **/
89943bbe138SJeremy L Thompson int CeedOperatorFieldGetElemRestriction(CeedOperatorField op_field,
90043bbe138SJeremy L Thompson                                         CeedElemRestriction *rstr) {
90143bbe138SJeremy L Thompson   *rstr = op_field->elem_restr;
90243bbe138SJeremy L Thompson   return CEED_ERROR_SUCCESS;
90343bbe138SJeremy L Thompson }
90443bbe138SJeremy L Thompson 
90543bbe138SJeremy L Thompson /**
90643bbe138SJeremy L Thompson   @brief Get the CeedBasis of a CeedOperatorField
90743bbe138SJeremy L Thompson 
90843bbe138SJeremy L Thompson   @param op_field    CeedOperatorField
90943bbe138SJeremy L Thompson   @param[out] basis  Variable to store CeedBasis
91043bbe138SJeremy L Thompson 
91143bbe138SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
91243bbe138SJeremy L Thompson 
913e9b533fbSJeremy L Thompson   @ref Advanced
91443bbe138SJeremy L Thompson **/
91543bbe138SJeremy L Thompson int CeedOperatorFieldGetBasis(CeedOperatorField op_field, CeedBasis *basis) {
91643bbe138SJeremy L Thompson   *basis = op_field->basis;
91743bbe138SJeremy L Thompson   return CEED_ERROR_SUCCESS;
91843bbe138SJeremy L Thompson }
91943bbe138SJeremy L Thompson 
92043bbe138SJeremy L Thompson /**
92143bbe138SJeremy L Thompson   @brief Get the CeedVector of a CeedOperatorField
92243bbe138SJeremy L Thompson 
92343bbe138SJeremy L Thompson   @param op_field  CeedOperatorField
92443bbe138SJeremy L Thompson   @param[out] vec  Variable to store CeedVector
92543bbe138SJeremy L Thompson 
92643bbe138SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
92743bbe138SJeremy L Thompson 
928e9b533fbSJeremy L Thompson   @ref Advanced
92943bbe138SJeremy L Thompson **/
93043bbe138SJeremy L Thompson int CeedOperatorFieldGetVector(CeedOperatorField op_field, CeedVector *vec) {
93143bbe138SJeremy L Thompson   *vec = op_field->vec;
93243bbe138SJeremy L Thompson   return CEED_ERROR_SUCCESS;
93343bbe138SJeremy L Thompson }
93443bbe138SJeremy L Thompson 
93543bbe138SJeremy L Thompson /**
93652d6035fSJeremy L Thompson   @brief Add a sub-operator to a composite CeedOperator
937288c0443SJeremy L Thompson 
938d1d35e2fSjeremylt   @param[out] composite_op  Composite CeedOperator
939d1d35e2fSjeremylt   @param      sub_op        Sub-operator CeedOperator
94052d6035fSJeremy L Thompson 
94152d6035fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
94252d6035fSJeremy L Thompson 
9437a982d89SJeremy L. Thompson   @ref User
94452d6035fSJeremy L Thompson  */
945d1d35e2fSjeremylt int CeedCompositeOperatorAddSub(CeedOperator composite_op,
946d1d35e2fSjeremylt                                 CeedOperator sub_op) {
94734359f16Sjeremylt   int ierr;
94834359f16Sjeremylt 
949f04ea552SJeremy L Thompson   if (!composite_op->is_composite)
950c042f62fSJeremy L Thompson     // LCOV_EXCL_START
951d1d35e2fSjeremylt     return CeedError(composite_op->ceed, CEED_ERROR_MINOR,
952e2f04181SAndrew T. Barker                      "CeedOperator is not a composite operator");
953c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
95452d6035fSJeremy L Thompson 
955d1d35e2fSjeremylt   if (composite_op->num_suboperators == CEED_COMPOSITE_MAX)
956c042f62fSJeremy L Thompson     // LCOV_EXCL_START
957d1d35e2fSjeremylt     return CeedError(composite_op->ceed, CEED_ERROR_UNSUPPORTED,
9582b104005SJeremy L Thompson                      "Cannot add additional sub-operators");
959c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
960f04ea552SJeremy L Thompson   if (composite_op->is_immutable)
961f04ea552SJeremy L Thompson     // LCOV_EXCL_START
962f04ea552SJeremy L Thompson     return CeedError(composite_op->ceed, CEED_ERROR_MAJOR,
963f04ea552SJeremy L Thompson                      "Operator cannot be changed after set as immutable");
964f04ea552SJeremy L Thompson   // LCOV_EXCL_STOP
96552d6035fSJeremy L Thompson 
9662b104005SJeremy L Thompson   {
9672b104005SJeremy L Thompson     CeedSize input_size, output_size;
9682b104005SJeremy L Thompson     ierr = CeedOperatorGetActiveVectorLengths(sub_op, &input_size, &output_size);
9692b104005SJeremy L Thompson     CeedChk(ierr);
9702b104005SJeremy L Thompson     if (composite_op->input_size == -1) composite_op->input_size = input_size;
9712b104005SJeremy L Thompson     if (composite_op->output_size == -1) composite_op->output_size = output_size;
9722b104005SJeremy L Thompson     // Note, a size of -1 means no active vector restriction set, so no incompatibility
9732b104005SJeremy L Thompson     if ((input_size != -1 && input_size != composite_op->input_size) ||
9742b104005SJeremy L Thompson         (output_size != -1 && output_size != composite_op->output_size))
9752b104005SJeremy L Thompson       // LCOV_EXCL_START
9762b104005SJeremy L Thompson       return CeedError(composite_op->ceed, CEED_ERROR_MAJOR,
9772b104005SJeremy L Thompson                        "Sub-operators must have compatible dimensions; "
9782b104005SJeremy L Thompson                        "composite operator of shape (%td, %td) not compatible with "
9792b104005SJeremy L Thompson                        "sub-operator of shape (%td, %td)",
9802b104005SJeremy L Thompson                        composite_op->input_size, composite_op->output_size, input_size, output_size);
9812b104005SJeremy L Thompson     // LCOV_EXCL_STOP
9822b104005SJeremy L Thompson   }
9832b104005SJeremy L Thompson 
984d1d35e2fSjeremylt   composite_op->sub_operators[composite_op->num_suboperators] = sub_op;
9859560d06aSjeremylt   ierr = CeedOperatorReference(sub_op); CeedChk(ierr);
986d1d35e2fSjeremylt   composite_op->num_suboperators++;
987e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
98852d6035fSJeremy L Thompson }
98952d6035fSJeremy L Thompson 
99052d6035fSJeremy L Thompson /**
9914db537f9SJeremy L Thompson   @brief Check if a CeedOperator is ready to be used.
9924db537f9SJeremy L Thompson 
9934db537f9SJeremy L Thompson   @param[in] op  CeedOperator to check
9944db537f9SJeremy L Thompson 
9954db537f9SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
9964db537f9SJeremy L Thompson 
9974db537f9SJeremy L Thompson   @ref User
9984db537f9SJeremy L Thompson **/
9994db537f9SJeremy L Thompson int CeedOperatorCheckReady(CeedOperator op) {
10004db537f9SJeremy L Thompson   int ierr;
10014db537f9SJeremy L Thompson   Ceed ceed;
10024db537f9SJeremy L Thompson   ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr);
10034db537f9SJeremy L Thompson 
10044db537f9SJeremy L Thompson   if (op->is_interface_setup)
10054db537f9SJeremy L Thompson     return CEED_ERROR_SUCCESS;
10064db537f9SJeremy L Thompson 
10074db537f9SJeremy L Thompson   CeedQFunction qf = op->qf;
10084db537f9SJeremy L Thompson   if (op->is_composite) {
1009*43622462SJeremy L Thompson     if (!op->num_suboperators) {
1010*43622462SJeremy L Thompson       // Empty operator setup
1011*43622462SJeremy L Thompson       op->input_size = 0;
1012*43622462SJeremy L Thompson       op->output_size = 0;
1013*43622462SJeremy L Thompson     } else {
10144db537f9SJeremy L Thompson       for (CeedInt i = 0; i < op->num_suboperators; i++) {
10154db537f9SJeremy L Thompson         ierr = CeedOperatorCheckReady(op->sub_operators[i]); CeedChk(ierr);
10164db537f9SJeremy L Thompson       }
10172b104005SJeremy L Thompson       // Sub-operators could be modified after adding to composite operator
10182b104005SJeremy L Thompson       // Need to verify no lvec incompatibility from any changes
10192b104005SJeremy L Thompson       CeedSize input_size, output_size;
10202b104005SJeremy L Thompson       ierr = CeedOperatorGetActiveVectorLengths(op, &input_size, &output_size);
10212b104005SJeremy L Thompson       CeedChk(ierr);
1022*43622462SJeremy L Thompson     }
10234db537f9SJeremy L Thompson   } else {
10244db537f9SJeremy L Thompson     if (op->num_fields == 0)
10254db537f9SJeremy L Thompson       // LCOV_EXCL_START
10264db537f9SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_INCOMPLETE, "No operator fields set");
10274db537f9SJeremy L Thompson     // LCOV_EXCL_STOP
10284db537f9SJeremy L Thompson     if (op->num_fields < qf->num_input_fields + qf->num_output_fields)
10294db537f9SJeremy L Thompson       // LCOV_EXCL_START
10304db537f9SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_INCOMPLETE, "Not all operator fields set");
10314db537f9SJeremy L Thompson     // LCOV_EXCL_STOP
10324db537f9SJeremy L Thompson     if (!op->has_restriction)
10334db537f9SJeremy L Thompson       // LCOV_EXCL_START
10344db537f9SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_INCOMPLETE,
10354db537f9SJeremy L Thompson                        "At least one restriction required");
10364db537f9SJeremy L Thompson     // LCOV_EXCL_STOP
10374db537f9SJeremy L Thompson     if (op->num_qpts == 0)
10384db537f9SJeremy L Thompson       // LCOV_EXCL_START
10394db537f9SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_INCOMPLETE,
10404db537f9SJeremy L Thompson                        "At least one non-collocated basis is required "
10414db537f9SJeremy L Thompson                        "or the number of quadrature points must be set");
10424db537f9SJeremy L Thompson     // LCOV_EXCL_STOP
10434db537f9SJeremy L Thompson   }
10444db537f9SJeremy L Thompson 
10454db537f9SJeremy L Thompson   // Flag as immutable and ready
10464db537f9SJeremy L Thompson   op->is_interface_setup = true;
10474db537f9SJeremy L Thompson   if (op->qf && op->qf != CEED_QFUNCTION_NONE)
10484db537f9SJeremy L Thompson     // LCOV_EXCL_START
10494db537f9SJeremy L Thompson     op->qf->is_immutable = true;
10504db537f9SJeremy L Thompson   // LCOV_EXCL_STOP
10514db537f9SJeremy L Thompson   if (op->dqf && op->dqf != CEED_QFUNCTION_NONE)
10524db537f9SJeremy L Thompson     // LCOV_EXCL_START
10534db537f9SJeremy L Thompson     op->dqf->is_immutable = true;
10544db537f9SJeremy L Thompson   // LCOV_EXCL_STOP
10554db537f9SJeremy L Thompson   if (op->dqfT && op->dqfT != CEED_QFUNCTION_NONE)
10564db537f9SJeremy L Thompson     // LCOV_EXCL_START
10574db537f9SJeremy L Thompson     op->dqfT->is_immutable = true;
10584db537f9SJeremy L Thompson   // LCOV_EXCL_STOP
10594db537f9SJeremy L Thompson   return CEED_ERROR_SUCCESS;
10604db537f9SJeremy L Thompson }
10614db537f9SJeremy L Thompson 
10624db537f9SJeremy L Thompson /**
1063c9366a6bSJeremy L Thompson   @brief Get vector lengths for the active input and/or output vectors of a CeedOperator.
1064c9366a6bSJeremy L Thompson            Note: Lengths of -1 indicate that the CeedOperator does not have an
1065c9366a6bSJeremy L Thompson            active input and/or output.
1066c9366a6bSJeremy L Thompson 
1067c9366a6bSJeremy L Thompson   @param[in] op           CeedOperator
1068c9366a6bSJeremy L Thompson   @param[out] input_size  Variable to store active input vector length, or NULL
1069c9366a6bSJeremy L Thompson   @param[out] output_size Variable to store active output vector length, or NULL
1070c9366a6bSJeremy L Thompson 
1071c9366a6bSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1072c9366a6bSJeremy L Thompson 
1073c9366a6bSJeremy L Thompson   @ref User
1074c9366a6bSJeremy L Thompson **/
1075c9366a6bSJeremy L Thompson int CeedOperatorGetActiveVectorLengths(CeedOperator op, CeedSize *input_size,
1076c9366a6bSJeremy L Thompson                                        CeedSize *output_size) {
1077c9366a6bSJeremy L Thompson   int ierr;
1078c9366a6bSJeremy L Thompson   bool is_composite;
1079c9366a6bSJeremy L Thompson 
10802b104005SJeremy L Thompson   if (input_size) *input_size = op->input_size;
10812b104005SJeremy L Thompson   if (output_size) *output_size = op->output_size;
1082c9366a6bSJeremy L Thompson 
1083c9366a6bSJeremy L Thompson   ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr);
10842b104005SJeremy L Thompson   if (is_composite && (op->input_size == -1 || op->output_size == -1)) {
1085c9366a6bSJeremy L Thompson     for (CeedInt i = 0; i < op->num_suboperators; i++) {
1086c9366a6bSJeremy L Thompson       CeedSize sub_input_size, sub_output_size;
1087c9366a6bSJeremy L Thompson       ierr = CeedOperatorGetActiveVectorLengths(op->sub_operators[i],
10882b104005SJeremy L Thompson              &sub_input_size, &sub_output_size); CeedChk(ierr);
10892b104005SJeremy L Thompson       if (op->input_size == -1) op->input_size = sub_input_size;
10902b104005SJeremy L Thompson       if (op->output_size == -1) op->output_size = sub_output_size;
10912b104005SJeremy L Thompson       // Note, a size of -1 means no active vector restriction set, so no incompatibility
10922b104005SJeremy L Thompson       if ((sub_input_size != -1 && sub_input_size != op->input_size) ||
10932b104005SJeremy L Thompson           (sub_output_size != -1 && sub_output_size != op->output_size))
10942b104005SJeremy L Thompson         // LCOV_EXCL_START
10952b104005SJeremy L Thompson         return CeedError(op->ceed, CEED_ERROR_MAJOR,
10962b104005SJeremy L Thompson                          "Sub-operators must have compatible dimensions; "
10972b104005SJeremy L Thompson                          "composite operator of shape (%td, %td) not compatible with "
10982b104005SJeremy L Thompson                          "sub-operator of shape (%td, %td)",
10992b104005SJeremy L Thompson                          op->input_size, op->output_size, input_size, output_size);
11002b104005SJeremy L Thompson       // LCOV_EXCL_STOP
1101c9366a6bSJeremy L Thompson     }
1102c9366a6bSJeremy L Thompson   }
1103c9366a6bSJeremy L Thompson 
1104c9366a6bSJeremy L Thompson   return CEED_ERROR_SUCCESS;
1105c9366a6bSJeremy L Thompson }
1106c9366a6bSJeremy L Thompson 
1107c9366a6bSJeremy L Thompson /**
1108beecbf24SJeremy L Thompson   @brief Set reuse of CeedQFunction data in CeedOperatorLinearAssemble* functions.
1109beecbf24SJeremy L Thompson            When `reuse_assembly_data = false` (default), the CeedQFunction associated
1110beecbf24SJeremy L Thompson            with this CeedOperator is re-assembled every time a `CeedOperatorLinearAssemble*`
1111beecbf24SJeremy L Thompson            function is called.
1112beecbf24SJeremy L Thompson            When `reuse_assembly_data = true`, the CeedQFunction associated with
1113beecbf24SJeremy L Thompson            this CeedOperator is reused between calls to
1114beecbf24SJeremy L Thompson            `CeedOperatorSetQFunctionAssemblyDataUpdated`.
11158b919e6bSJeremy L Thompson 
1116beecbf24SJeremy L Thompson   @param[in] op                  CeedOperator
1117beecbf24SJeremy L Thompson   @param[in] reuse_assembly_data Boolean flag setting assembly data reuse
11188b919e6bSJeremy L Thompson 
11198b919e6bSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
11208b919e6bSJeremy L Thompson 
11218b919e6bSJeremy L Thompson   @ref Advanced
11228b919e6bSJeremy L Thompson **/
1123beecbf24SJeremy L Thompson int CeedOperatorSetQFunctionAssemblyReuse(CeedOperator op,
1124beecbf24SJeremy L Thompson     bool reuse_assembly_data) {
11258b919e6bSJeremy L Thompson   int ierr;
11268b919e6bSJeremy L Thompson   bool is_composite;
11278b919e6bSJeremy L Thompson 
11288b919e6bSJeremy L Thompson   ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr);
11298b919e6bSJeremy L Thompson   if (is_composite) {
11308b919e6bSJeremy L Thompson     for (CeedInt i = 0; i < op->num_suboperators; i++) {
1131beecbf24SJeremy L Thompson       ierr = CeedOperatorSetQFunctionAssemblyReuse(op->sub_operators[i],
1132beecbf24SJeremy L Thompson              reuse_assembly_data); CeedChk(ierr);
11338b919e6bSJeremy L Thompson     }
11348b919e6bSJeremy L Thompson   } else {
1135beecbf24SJeremy L Thompson     ierr = CeedQFunctionAssemblyDataSetReuse(op->qf_assembled, reuse_assembly_data);
1136beecbf24SJeremy L Thompson     CeedChk(ierr);
1137beecbf24SJeremy L Thompson   }
1138beecbf24SJeremy L Thompson 
1139beecbf24SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1140beecbf24SJeremy L Thompson }
1141beecbf24SJeremy L Thompson 
1142beecbf24SJeremy L Thompson /**
1143beecbf24SJeremy L Thompson   @brief Mark CeedQFunction data as updated and the CeedQFunction as requiring re-assembly.
1144beecbf24SJeremy L Thompson 
1145beecbf24SJeremy L Thompson   @param[in] op                CeedOperator
11466e15d496SJeremy L Thompson   @param[in] needs_data_update Boolean flag setting assembly data reuse
1147beecbf24SJeremy L Thompson 
1148beecbf24SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1149beecbf24SJeremy L Thompson 
1150beecbf24SJeremy L Thompson   @ref Advanced
1151beecbf24SJeremy L Thompson **/
1152beecbf24SJeremy L Thompson int CeedOperatorSetQFunctionAssemblyDataUpdateNeeded(CeedOperator op,
1153beecbf24SJeremy L Thompson     bool needs_data_update) {
1154beecbf24SJeremy L Thompson   int ierr;
1155beecbf24SJeremy L Thompson   bool is_composite;
1156beecbf24SJeremy L Thompson 
1157beecbf24SJeremy L Thompson   ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr);
1158beecbf24SJeremy L Thompson   if (is_composite) {
1159beecbf24SJeremy L Thompson     for (CeedInt i = 0; i < op->num_suboperators; i++) {
1160beecbf24SJeremy L Thompson       ierr = CeedOperatorSetQFunctionAssemblyDataUpdateNeeded(op->sub_operators[i],
1161beecbf24SJeremy L Thompson              needs_data_update); CeedChk(ierr);
1162beecbf24SJeremy L Thompson     }
1163beecbf24SJeremy L Thompson   } else {
1164beecbf24SJeremy L Thompson     ierr = CeedQFunctionAssemblyDataSetUpdateNeeded(op->qf_assembled,
1165beecbf24SJeremy L Thompson            needs_data_update);
11668b919e6bSJeremy L Thompson     CeedChk(ierr);
11678b919e6bSJeremy L Thompson   }
11688b919e6bSJeremy L Thompson 
11698b919e6bSJeremy L Thompson   return CEED_ERROR_SUCCESS;
11708b919e6bSJeremy L Thompson }
11718b919e6bSJeremy L Thompson 
11728b919e6bSJeremy L Thompson /**
1173cd4dfc48Sjeremylt   @brief Set the number of quadrature points associated with a CeedOperator.
1174cd4dfc48Sjeremylt            This should be used when creating a CeedOperator where every
1175cd4dfc48Sjeremylt            field has a collocated basis. This function cannot be used for
1176cd4dfc48Sjeremylt            composite CeedOperators.
1177cd4dfc48Sjeremylt 
1178cd4dfc48Sjeremylt   @param op        CeedOperator
1179cd4dfc48Sjeremylt   @param num_qpts  Number of quadrature points to set
1180cd4dfc48Sjeremylt 
1181cd4dfc48Sjeremylt   @return An error code: 0 - success, otherwise - failure
1182cd4dfc48Sjeremylt 
1183e9b533fbSJeremy L Thompson   @ref Advanced
1184cd4dfc48Sjeremylt **/
1185cd4dfc48Sjeremylt int CeedOperatorSetNumQuadraturePoints(CeedOperator op, CeedInt num_qpts) {
1186f04ea552SJeremy L Thompson   if (op->is_composite)
1187cd4dfc48Sjeremylt     // LCOV_EXCL_START
1188cd4dfc48Sjeremylt     return CeedError(op->ceed, CEED_ERROR_MINOR,
1189cd4dfc48Sjeremylt                      "Not defined for composite operator");
1190cd4dfc48Sjeremylt   // LCOV_EXCL_STOP
1191cd4dfc48Sjeremylt   if (op->num_qpts)
1192cd4dfc48Sjeremylt     // LCOV_EXCL_START
1193cd4dfc48Sjeremylt     return CeedError(op->ceed, CEED_ERROR_MINOR,
1194cd4dfc48Sjeremylt                      "Number of quadrature points already defined");
1195cd4dfc48Sjeremylt   // LCOV_EXCL_STOP
1196f04ea552SJeremy L Thompson   if (op->is_immutable)
1197f04ea552SJeremy L Thompson     // LCOV_EXCL_START
1198f04ea552SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MAJOR,
1199f04ea552SJeremy L Thompson                      "Operator cannot be changed after set as immutable");
1200f04ea552SJeremy L Thompson   // LCOV_EXCL_STOP
1201cd4dfc48Sjeremylt 
1202cd4dfc48Sjeremylt   op->num_qpts = num_qpts;
1203cd4dfc48Sjeremylt   return CEED_ERROR_SUCCESS;
1204cd4dfc48Sjeremylt }
1205cd4dfc48Sjeremylt 
1206cd4dfc48Sjeremylt /**
1207ea6b5821SJeremy L Thompson   @brief Set name of CeedOperator for CeedOperatorView output
1208ea6b5821SJeremy L Thompson 
1209ea6b5821SJeremy L Thompson   @param op    CeedOperator
1210ea6b5821SJeremy L Thompson   @param name  Name to set, or NULL to remove previously set name
1211ea6b5821SJeremy L Thompson 
1212ea6b5821SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1213ea6b5821SJeremy L Thompson 
1214ea6b5821SJeremy L Thompson   @ref User
1215ea6b5821SJeremy L Thompson **/
1216ea6b5821SJeremy L Thompson int CeedOperatorSetName(CeedOperator op, const char *name) {
1217ea6b5821SJeremy L Thompson   int ierr;
1218ea6b5821SJeremy L Thompson   char *name_copy;
1219ea6b5821SJeremy L Thompson   size_t name_len = name ? strlen(name) : 0;
1220ea6b5821SJeremy L Thompson 
1221ea6b5821SJeremy L Thompson   ierr = CeedFree(&op->name); CeedChk(ierr);
1222ea6b5821SJeremy L Thompson   if (name_len > 0) {
1223ea6b5821SJeremy L Thompson     ierr = CeedCalloc(name_len + 1, &name_copy); CeedChk(ierr);
1224ea6b5821SJeremy L Thompson     memcpy(name_copy, name, name_len);
1225ea6b5821SJeremy L Thompson     op->name = name_copy;
1226ea6b5821SJeremy L Thompson   }
1227ea6b5821SJeremy L Thompson 
1228ea6b5821SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1229ea6b5821SJeremy L Thompson }
1230ea6b5821SJeremy L Thompson 
1231ea6b5821SJeremy L Thompson /**
12327a982d89SJeremy L. Thompson   @brief View a CeedOperator
12337a982d89SJeremy L. Thompson 
12347a982d89SJeremy L. Thompson   @param[in] op      CeedOperator to view
12357a982d89SJeremy L. Thompson   @param[in] stream  Stream to write; typically stdout/stderr or a file
12367a982d89SJeremy L. Thompson 
12377a982d89SJeremy L. Thompson   @return Error code: 0 - success, otherwise - failure
12387a982d89SJeremy L. Thompson 
12397a982d89SJeremy L. Thompson   @ref User
12407a982d89SJeremy L. Thompson **/
12417a982d89SJeremy L. Thompson int CeedOperatorView(CeedOperator op, FILE *stream) {
12427a982d89SJeremy L. Thompson   int ierr;
1243ea6b5821SJeremy L Thompson   bool has_name = op->name;
12447a982d89SJeremy L. Thompson 
1245f04ea552SJeremy L Thompson   if (op->is_composite) {
1246ea6b5821SJeremy L Thompson     fprintf(stream, "Composite CeedOperator%s%s\n",
1247ea6b5821SJeremy L Thompson             has_name ? " - " : "", has_name ? op->name : "");
12487a982d89SJeremy L. Thompson 
1249d1d35e2fSjeremylt     for (CeedInt i=0; i<op->num_suboperators; i++) {
1250ea6b5821SJeremy L Thompson       has_name = op->sub_operators[i]->name;
1251990fdeb6SJeremy L Thompson       fprintf(stream, "  SubOperator %" CeedInt_FMT "%s%s:\n", i,
1252ea6b5821SJeremy L Thompson               has_name ? " - " : "",
1253ea6b5821SJeremy L Thompson               has_name ? op->sub_operators[i]->name : "");
1254d1d35e2fSjeremylt       ierr = CeedOperatorSingleView(op->sub_operators[i], 1, stream);
12557a982d89SJeremy L. Thompson       CeedChk(ierr);
12567a982d89SJeremy L. Thompson     }
12577a982d89SJeremy L. Thompson   } else {
1258ea6b5821SJeremy L Thompson     fprintf(stream, "CeedOperator%s%s\n",
1259ea6b5821SJeremy L Thompson             has_name ? " - " : "", has_name ? op->name : "");
12607a982d89SJeremy L. Thompson     ierr = CeedOperatorSingleView(op, 0, stream); CeedChk(ierr);
12617a982d89SJeremy L. Thompson   }
1262e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
12637a982d89SJeremy L. Thompson }
12643bd813ffSjeremylt 
12653bd813ffSjeremylt /**
1266b7c9bbdaSJeremy L Thompson   @brief Get the Ceed associated with a CeedOperator
1267b7c9bbdaSJeremy L Thompson 
1268b7c9bbdaSJeremy L Thompson   @param op         CeedOperator
1269b7c9bbdaSJeremy L Thompson   @param[out] ceed  Variable to store Ceed
1270b7c9bbdaSJeremy L Thompson 
1271b7c9bbdaSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1272b7c9bbdaSJeremy L Thompson 
1273b7c9bbdaSJeremy L Thompson   @ref Advanced
1274b7c9bbdaSJeremy L Thompson **/
1275b7c9bbdaSJeremy L Thompson int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) {
1276b7c9bbdaSJeremy L Thompson   *ceed = op->ceed;
1277b7c9bbdaSJeremy L Thompson   return CEED_ERROR_SUCCESS;
1278b7c9bbdaSJeremy L Thompson }
1279b7c9bbdaSJeremy L Thompson 
1280b7c9bbdaSJeremy L Thompson /**
1281b7c9bbdaSJeremy L Thompson   @brief Get the number of elements associated with a CeedOperator
1282b7c9bbdaSJeremy L Thompson 
1283b7c9bbdaSJeremy L Thompson   @param op             CeedOperator
1284b7c9bbdaSJeremy L Thompson   @param[out] num_elem  Variable to store number of elements
1285b7c9bbdaSJeremy L Thompson 
1286b7c9bbdaSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1287b7c9bbdaSJeremy L Thompson 
1288b7c9bbdaSJeremy L Thompson   @ref Advanced
1289b7c9bbdaSJeremy L Thompson **/
1290b7c9bbdaSJeremy L Thompson int CeedOperatorGetNumElements(CeedOperator op, CeedInt *num_elem) {
1291b7c9bbdaSJeremy L Thompson   if (op->is_composite)
1292b7c9bbdaSJeremy L Thompson     // LCOV_EXCL_START
1293b7c9bbdaSJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
1294b7c9bbdaSJeremy L Thompson                      "Not defined for composite operator");
1295b7c9bbdaSJeremy L Thompson   // LCOV_EXCL_STOP
1296b7c9bbdaSJeremy L Thompson 
1297b7c9bbdaSJeremy L Thompson   *num_elem = op->num_elem;
1298b7c9bbdaSJeremy L Thompson   return CEED_ERROR_SUCCESS;
1299b7c9bbdaSJeremy L Thompson }
1300b7c9bbdaSJeremy L Thompson 
1301b7c9bbdaSJeremy L Thompson /**
1302b7c9bbdaSJeremy L Thompson   @brief Get the number of quadrature points associated with a CeedOperator
1303b7c9bbdaSJeremy L Thompson 
1304b7c9bbdaSJeremy L Thompson   @param op             CeedOperator
1305b7c9bbdaSJeremy L Thompson   @param[out] num_qpts  Variable to store vector number of quadrature points
1306b7c9bbdaSJeremy L Thompson 
1307b7c9bbdaSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1308b7c9bbdaSJeremy L Thompson 
1309b7c9bbdaSJeremy L Thompson   @ref Advanced
1310b7c9bbdaSJeremy L Thompson **/
1311b7c9bbdaSJeremy L Thompson int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *num_qpts) {
1312b7c9bbdaSJeremy L Thompson   if (op->is_composite)
1313b7c9bbdaSJeremy L Thompson     // LCOV_EXCL_START
1314b7c9bbdaSJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
1315b7c9bbdaSJeremy L Thompson                      "Not defined for composite operator");
1316b7c9bbdaSJeremy L Thompson   // LCOV_EXCL_STOP
1317b7c9bbdaSJeremy L Thompson 
1318b7c9bbdaSJeremy L Thompson   *num_qpts = op->num_qpts;
1319b7c9bbdaSJeremy L Thompson   return CEED_ERROR_SUCCESS;
1320b7c9bbdaSJeremy L Thompson }
1321b7c9bbdaSJeremy L Thompson 
1322b7c9bbdaSJeremy L Thompson /**
13236e15d496SJeremy L Thompson   @brief Estimate number of FLOPs required to apply CeedOperator on the active vector
13246e15d496SJeremy L Thompson 
13256e15d496SJeremy L Thompson   @param op    Operator to estimate FLOPs for
13266e15d496SJeremy L Thompson   @param flops Address of variable to hold FLOPs estimate
13276e15d496SJeremy L Thompson 
13286e15d496SJeremy L Thompson   @ref Backend
13296e15d496SJeremy L Thompson **/
13309d36ca50SJeremy L Thompson int CeedOperatorGetFlopsEstimate(CeedOperator op, CeedSize *flops) {
13316e15d496SJeremy L Thompson   int ierr;
13326e15d496SJeremy L Thompson   bool is_composite;
13336e15d496SJeremy L Thompson   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
13346e15d496SJeremy L Thompson 
13356e15d496SJeremy L Thompson   *flops = 0;
13366e15d496SJeremy L Thompson   ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr);
13376e15d496SJeremy L Thompson   if (is_composite) {
13386e15d496SJeremy L Thompson     CeedInt num_suboperators;
13396e15d496SJeremy L Thompson     ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr);
13406e15d496SJeremy L Thompson     CeedOperator *sub_operators;
13416e15d496SJeremy L Thompson     ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr);
13426e15d496SJeremy L Thompson 
13436e15d496SJeremy L Thompson     // FLOPs for each suboperator
13446e15d496SJeremy L Thompson     for (CeedInt i = 0; i < num_suboperators; i++) {
13459d36ca50SJeremy L Thompson       CeedSize suboperator_flops;
13466e15d496SJeremy L Thompson       ierr = CeedOperatorGetFlopsEstimate(sub_operators[i], &suboperator_flops);
13476e15d496SJeremy L Thompson       CeedChk(ierr);
13486e15d496SJeremy L Thompson       *flops += suboperator_flops;
13496e15d496SJeremy L Thompson     }
13506e15d496SJeremy L Thompson   } else {
13516e15d496SJeremy L Thompson     CeedInt num_input_fields, num_output_fields;
13526e15d496SJeremy L Thompson     CeedOperatorField *input_fields, *output_fields;
13536e15d496SJeremy L Thompson 
13546e15d496SJeremy L Thompson     ierr = CeedOperatorGetFields(op, &num_input_fields, &input_fields,
13556e15d496SJeremy L Thompson                                  &num_output_fields, &output_fields); CeedChk(ierr);
13566e15d496SJeremy L Thompson 
13576e15d496SJeremy L Thompson     CeedInt num_elem = 0;
13586e15d496SJeremy L Thompson     ierr = CeedOperatorGetNumElements(op, &num_elem); CeedChk(ierr);
13596e15d496SJeremy L Thompson     // Input FLOPs
13606e15d496SJeremy L Thompson     for (CeedInt i = 0; i < num_input_fields; i++) {
13616e15d496SJeremy L Thompson       if (input_fields[i]->vec == CEED_VECTOR_ACTIVE) {
13629d36ca50SJeremy L Thompson         CeedSize restr_flops, basis_flops;
13636e15d496SJeremy L Thompson 
13646e15d496SJeremy L Thompson         ierr = CeedElemRestrictionGetFlopsEstimate(input_fields[i]->elem_restr,
13656e15d496SJeremy L Thompson                CEED_NOTRANSPOSE, &restr_flops); CeedChk(ierr);
13666e15d496SJeremy L Thompson         *flops += restr_flops;
13676e15d496SJeremy L Thompson         ierr = CeedBasisGetFlopsEstimate(input_fields[i]->basis, CEED_NOTRANSPOSE,
13686e15d496SJeremy L Thompson                                          op->qf->input_fields[i]->eval_mode, &basis_flops); CeedChk(ierr);
13696e15d496SJeremy L Thompson         *flops += basis_flops * num_elem;
13706e15d496SJeremy L Thompson       }
13716e15d496SJeremy L Thompson     }
13726e15d496SJeremy L Thompson     // QF FLOPs
13739d36ca50SJeremy L Thompson     CeedInt num_qpts;
13749d36ca50SJeremy L Thompson     CeedSize qf_flops;
13756e15d496SJeremy L Thompson     ierr = CeedOperatorGetNumQuadraturePoints(op, &num_qpts); CeedChk(ierr);
13766e15d496SJeremy L Thompson     ierr = CeedQFunctionGetFlopsEstimate(op->qf, &qf_flops); CeedChk(ierr);
13776e15d496SJeremy L Thompson     *flops += num_elem * num_qpts * qf_flops;
13786e15d496SJeremy L Thompson     // Output FLOPs
13796e15d496SJeremy L Thompson     for (CeedInt i = 0; i < num_output_fields; i++) {
13806e15d496SJeremy L Thompson       if (output_fields[i]->vec == CEED_VECTOR_ACTIVE) {
13819d36ca50SJeremy L Thompson         CeedSize restr_flops, basis_flops;
13826e15d496SJeremy L Thompson 
13836e15d496SJeremy L Thompson         ierr = CeedElemRestrictionGetFlopsEstimate(output_fields[i]->elem_restr,
13846e15d496SJeremy L Thompson                CEED_TRANSPOSE, &restr_flops); CeedChk(ierr);
13856e15d496SJeremy L Thompson         *flops += restr_flops;
13866e15d496SJeremy L Thompson         ierr = CeedBasisGetFlopsEstimate(output_fields[i]->basis, CEED_TRANSPOSE,
13876e15d496SJeremy L Thompson                                          op->qf->output_fields[i]->eval_mode, &basis_flops); CeedChk(ierr);
13886e15d496SJeremy L Thompson         *flops += basis_flops * num_elem;
13896e15d496SJeremy L Thompson       }
13906e15d496SJeremy L Thompson     }
13916e15d496SJeremy L Thompson   }
13926e15d496SJeremy L Thompson 
13936e15d496SJeremy L Thompson   return CEED_ERROR_SUCCESS;
13946e15d496SJeremy L Thompson }
13956e15d496SJeremy L Thompson 
13966e15d496SJeremy L Thompson /**
13973668ca4bSJeremy L Thompson   @brief Get label for a registered QFunctionContext field, or `NULL` if no
13983668ca4bSJeremy L Thompson            field has been registered with this `field_name`.
13993668ca4bSJeremy L Thompson 
14003668ca4bSJeremy L Thompson   @param[in] op            CeedOperator
14013668ca4bSJeremy L Thompson   @param[in] field_name    Name of field to retrieve label
14023668ca4bSJeremy L Thompson   @param[out] field_label  Variable to field label
14033668ca4bSJeremy L Thompson 
14043668ca4bSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
14053668ca4bSJeremy L Thompson 
14063668ca4bSJeremy L Thompson   @ref User
14073668ca4bSJeremy L Thompson **/
14083668ca4bSJeremy L Thompson int CeedOperatorContextGetFieldLabel(CeedOperator op,
14093668ca4bSJeremy L Thompson                                      const char *field_name,
14103668ca4bSJeremy L Thompson                                      CeedContextFieldLabel *field_label) {
14113668ca4bSJeremy L Thompson   int ierr;
14123668ca4bSJeremy L Thompson 
14133668ca4bSJeremy L Thompson   bool is_composite;
14143668ca4bSJeremy L Thompson   ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr);
14153668ca4bSJeremy L Thompson   if (is_composite) {
14163668ca4bSJeremy L Thompson     // Check if composite label already created
14173668ca4bSJeremy L Thompson     for (CeedInt i=0; i<op->num_context_labels; i++) {
14183668ca4bSJeremy L Thompson       if (!strcmp(op->context_labels[i]->name, field_name)) {
14193668ca4bSJeremy L Thompson         *field_label = op->context_labels[i];
14203668ca4bSJeremy L Thompson         return CEED_ERROR_SUCCESS;
14213668ca4bSJeremy L Thompson       }
14223668ca4bSJeremy L Thompson     }
14233668ca4bSJeremy L Thompson 
14243668ca4bSJeremy L Thompson     // Create composite label if needed
14253668ca4bSJeremy L Thompson     CeedInt num_sub;
14263668ca4bSJeremy L Thompson     CeedOperator *sub_operators;
14273668ca4bSJeremy L Thompson     CeedContextFieldLabel new_field_label;
14283668ca4bSJeremy L Thompson 
14293668ca4bSJeremy L Thompson     ierr = CeedCalloc(1, &new_field_label); CeedChk(ierr);
14303668ca4bSJeremy L Thompson     ierr = CeedOperatorGetNumSub(op, &num_sub); CeedChk(ierr);
14313668ca4bSJeremy L Thompson     ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr);
14323668ca4bSJeremy L Thompson     ierr = CeedCalloc(num_sub, &new_field_label->sub_labels); CeedChk(ierr);
14333668ca4bSJeremy L Thompson     new_field_label->num_sub_labels = num_sub;
14343668ca4bSJeremy L Thompson 
14353668ca4bSJeremy L Thompson     bool label_found = false;
14363668ca4bSJeremy L Thompson     for (CeedInt i=0; i<num_sub; i++) {
14373668ca4bSJeremy L Thompson       if (sub_operators[i]->qf->ctx) {
14383668ca4bSJeremy L Thompson         CeedContextFieldLabel new_field_label_i;
14393668ca4bSJeremy L Thompson         ierr = CeedQFunctionContextGetFieldLabel(sub_operators[i]->qf->ctx, field_name,
14403668ca4bSJeremy L Thompson                &new_field_label_i); CeedChk(ierr);
14413668ca4bSJeremy L Thompson         if (new_field_label_i) {
14423668ca4bSJeremy L Thompson           label_found = true;
14433668ca4bSJeremy L Thompson           new_field_label->sub_labels[i] = new_field_label_i;
14443668ca4bSJeremy L Thompson           new_field_label->name = new_field_label_i->name;
14453668ca4bSJeremy L Thompson           new_field_label->description = new_field_label_i->description;
14467bfe0f0eSJeremy L Thompson           if (new_field_label->type &&
14477bfe0f0eSJeremy L Thompson               new_field_label->type != new_field_label_i->type) {
14487bfe0f0eSJeremy L Thompson             // LCOV_EXCL_START
14497bfe0f0eSJeremy L Thompson             ierr = CeedFree(&new_field_label); CeedChk(ierr);
14507bfe0f0eSJeremy L Thompson             return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
14517bfe0f0eSJeremy L Thompson                              "Incompatible field types on sub-operator contexts. "
14527bfe0f0eSJeremy L Thompson                              "%s != %s",
14537bfe0f0eSJeremy L Thompson                              CeedContextFieldTypes[new_field_label->type],
14547bfe0f0eSJeremy L Thompson                              CeedContextFieldTypes[new_field_label_i->type]);
14557bfe0f0eSJeremy L Thompson             // LCOV_EXCL_STOP
14567bfe0f0eSJeremy L Thompson           } else {
14577bfe0f0eSJeremy L Thompson             new_field_label->type = new_field_label_i->type;
14587bfe0f0eSJeremy L Thompson           }
14597bfe0f0eSJeremy L Thompson           if (new_field_label->num_values != 0 &&
14607bfe0f0eSJeremy L Thompson               new_field_label->num_values != new_field_label_i->num_values) {
14617bfe0f0eSJeremy L Thompson             // LCOV_EXCL_START
14627bfe0f0eSJeremy L Thompson             ierr = CeedFree(&new_field_label); CeedChk(ierr);
14637bfe0f0eSJeremy L Thompson             return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
14647bfe0f0eSJeremy L Thompson                              "Incompatible field number of values on sub-operator"
14657bfe0f0eSJeremy L Thompson                              " contexts. %ld != %ld",
14667bfe0f0eSJeremy L Thompson                              new_field_label->num_values, new_field_label_i->num_values);
14677bfe0f0eSJeremy L Thompson             // LCOV_EXCL_STOP
14687bfe0f0eSJeremy L Thompson           } else {
14697bfe0f0eSJeremy L Thompson             new_field_label->num_values = new_field_label_i->num_values;
14707bfe0f0eSJeremy L Thompson           }
14713668ca4bSJeremy L Thompson         }
14723668ca4bSJeremy L Thompson       }
14733668ca4bSJeremy L Thompson     }
14743668ca4bSJeremy L Thompson     if (!label_found) {
14753668ca4bSJeremy L Thompson       // LCOV_EXCL_START
1476a48e5f43SJeremy L Thompson       ierr = CeedFree(&new_field_label->sub_labels); CeedChk(ierr);
14773668ca4bSJeremy L Thompson       ierr = CeedFree(&new_field_label); CeedChk(ierr);
14783668ca4bSJeremy L Thompson       *field_label = NULL;
14793668ca4bSJeremy L Thompson       // LCOV_EXCL_STOP
14803668ca4bSJeremy L Thompson     } else {
14813668ca4bSJeremy L Thompson       // Move new composite label to operator
14823668ca4bSJeremy L Thompson       if (op->num_context_labels == 0) {
14833668ca4bSJeremy L Thompson         ierr = CeedCalloc(1, &op->context_labels); CeedChk(ierr);
14843668ca4bSJeremy L Thompson         op->max_context_labels = 1;
14853668ca4bSJeremy L Thompson       } else if (op->num_context_labels == op->max_context_labels) {
14863668ca4bSJeremy L Thompson         ierr = CeedRealloc(2*op->num_context_labels, &op->context_labels);
14873668ca4bSJeremy L Thompson         CeedChk(ierr);
14883668ca4bSJeremy L Thompson         op->max_context_labels *= 2;
14893668ca4bSJeremy L Thompson       }
14903668ca4bSJeremy L Thompson       op->context_labels[op->num_context_labels] = new_field_label;
14913668ca4bSJeremy L Thompson       *field_label = new_field_label;
14923668ca4bSJeremy L Thompson       op->num_context_labels++;
14933668ca4bSJeremy L Thompson     }
14943668ca4bSJeremy L Thompson 
14953668ca4bSJeremy L Thompson     return CEED_ERROR_SUCCESS;
14963668ca4bSJeremy L Thompson   } else {
14973668ca4bSJeremy L Thompson     return CeedQFunctionContextGetFieldLabel(op->qf->ctx, field_name, field_label);
14983668ca4bSJeremy L Thompson   }
14993668ca4bSJeremy L Thompson }
15003668ca4bSJeremy L Thompson 
15013668ca4bSJeremy L Thompson /**
1502d8dd9a91SJeremy L Thompson   @brief Set QFunctionContext field holding a double precision value.
1503d8dd9a91SJeremy L Thompson            For composite operators, the value is set in all
1504d8dd9a91SJeremy L Thompson            sub-operator QFunctionContexts that have a matching `field_name`.
1505d8dd9a91SJeremy L Thompson 
1506d8dd9a91SJeremy L Thompson   @param op          CeedOperator
15073668ca4bSJeremy L Thompson   @param field_label Label of field to register
15087bfe0f0eSJeremy L Thompson   @param values      Values to set
1509d8dd9a91SJeremy L Thompson 
1510d8dd9a91SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1511d8dd9a91SJeremy L Thompson 
1512d8dd9a91SJeremy L Thompson   @ref User
1513d8dd9a91SJeremy L Thompson **/
15143668ca4bSJeremy L Thompson int CeedOperatorContextSetDouble(CeedOperator op,
15153668ca4bSJeremy L Thompson                                  CeedContextFieldLabel field_label,
15167bfe0f0eSJeremy L Thompson                                  double *values) {
15173668ca4bSJeremy L Thompson   return CeedOperatorContextSetGeneric(op, field_label, CEED_CONTEXT_FIELD_DOUBLE,
15187bfe0f0eSJeremy L Thompson                                        values);
1519d8dd9a91SJeremy L Thompson }
1520d8dd9a91SJeremy L Thompson 
1521d8dd9a91SJeremy L Thompson /**
1522d8dd9a91SJeremy L Thompson   @brief Set QFunctionContext field holding an int32 value.
1523d8dd9a91SJeremy L Thompson            For composite operators, the value is set in all
1524d8dd9a91SJeremy L Thompson            sub-operator QFunctionContexts that have a matching `field_name`.
1525d8dd9a91SJeremy L Thompson 
1526d8dd9a91SJeremy L Thompson   @param op          CeedOperator
15273668ca4bSJeremy L Thompson   @param field_label Label of field to set
15287bfe0f0eSJeremy L Thompson   @param values      Values to set
1529d8dd9a91SJeremy L Thompson 
1530d8dd9a91SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1531d8dd9a91SJeremy L Thompson 
1532d8dd9a91SJeremy L Thompson   @ref User
1533d8dd9a91SJeremy L Thompson **/
15343668ca4bSJeremy L Thompson int CeedOperatorContextSetInt32(CeedOperator op,
15353668ca4bSJeremy L Thompson                                 CeedContextFieldLabel field_label,
15367bfe0f0eSJeremy L Thompson                                 int *values) {
15373668ca4bSJeremy L Thompson   return CeedOperatorContextSetGeneric(op, field_label, CEED_CONTEXT_FIELD_INT32,
15387bfe0f0eSJeremy L Thompson                                        values);
1539d8dd9a91SJeremy L Thompson }
1540d8dd9a91SJeremy L Thompson 
1541d8dd9a91SJeremy L Thompson /**
15423bd813ffSjeremylt   @brief Apply CeedOperator to a vector
1543d7b241e6Sjeremylt 
1544d7b241e6Sjeremylt   This computes the action of the operator on the specified (active) input,
1545d7b241e6Sjeremylt   yielding its (active) output.  All inputs and outputs must be specified using
1546d7b241e6Sjeremylt   CeedOperatorSetField().
1547d7b241e6Sjeremylt 
1548f04ea552SJeremy L Thompson   Note: Calling this function asserts that setup is complete
1549f04ea552SJeremy L Thompson           and sets the CeedOperator as immutable.
1550f04ea552SJeremy L Thompson 
1551d7b241e6Sjeremylt   @param op        CeedOperator to apply
15524cc79fe7SJed Brown   @param[in] in    CeedVector containing input state or @ref CEED_VECTOR_NONE if
155334138859Sjeremylt                      there are no active inputs
1554b11c1e72Sjeremylt   @param[out] out  CeedVector to store result of applying operator (must be
15554cc79fe7SJed Brown                      distinct from @a in) or @ref CEED_VECTOR_NONE if there are no
155634138859Sjeremylt                      active outputs
1557d7b241e6Sjeremylt   @param request   Address of CeedRequest for non-blocking completion, else
15584cc79fe7SJed Brown                      @ref CEED_REQUEST_IMMEDIATE
1559b11c1e72Sjeremylt 
1560b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
1561dfdf5a53Sjeremylt 
15627a982d89SJeremy L. Thompson   @ref User
1563b11c1e72Sjeremylt **/
1564692c2638Sjeremylt int CeedOperatorApply(CeedOperator op, CeedVector in, CeedVector out,
1565692c2638Sjeremylt                       CeedRequest *request) {
1566d7b241e6Sjeremylt   int ierr;
1567e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
1568d7b241e6Sjeremylt 
1569d1d35e2fSjeremylt   if (op->num_elem)  {
1570250756a7Sjeremylt     // Standard Operator
1571cae8b89aSjeremylt     if (op->Apply) {
1572250756a7Sjeremylt       ierr = op->Apply(op, in, out, request); CeedChk(ierr);
1573cae8b89aSjeremylt     } else {
1574cae8b89aSjeremylt       // Zero all output vectors
1575250756a7Sjeremylt       CeedQFunction qf = op->qf;
1576d1d35e2fSjeremylt       for (CeedInt i=0; i<qf->num_output_fields; i++) {
1577d1d35e2fSjeremylt         CeedVector vec = op->output_fields[i]->vec;
1578cae8b89aSjeremylt         if (vec == CEED_VECTOR_ACTIVE)
1579cae8b89aSjeremylt           vec = out;
1580cae8b89aSjeremylt         if (vec != CEED_VECTOR_NONE) {
1581cae8b89aSjeremylt           ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr);
1582cae8b89aSjeremylt         }
1583cae8b89aSjeremylt       }
1584250756a7Sjeremylt       // Apply
1585250756a7Sjeremylt       ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr);
1586250756a7Sjeremylt     }
1587f04ea552SJeremy L Thompson   } else if (op->is_composite) {
1588250756a7Sjeremylt     // Composite Operator
1589250756a7Sjeremylt     if (op->ApplyComposite) {
1590250756a7Sjeremylt       ierr = op->ApplyComposite(op, in, out, request); CeedChk(ierr);
1591250756a7Sjeremylt     } else {
1592d1d35e2fSjeremylt       CeedInt num_suboperators;
1593d1d35e2fSjeremylt       ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr);
1594d1d35e2fSjeremylt       CeedOperator *sub_operators;
1595d1d35e2fSjeremylt       ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr);
1596250756a7Sjeremylt 
1597250756a7Sjeremylt       // Zero all output vectors
1598250756a7Sjeremylt       if (out != CEED_VECTOR_NONE) {
1599cae8b89aSjeremylt         ierr = CeedVectorSetValue(out, 0.0); CeedChk(ierr);
1600cae8b89aSjeremylt       }
1601d1d35e2fSjeremylt       for (CeedInt i=0; i<num_suboperators; i++) {
1602d1d35e2fSjeremylt         for (CeedInt j=0; j<sub_operators[i]->qf->num_output_fields; j++) {
1603d1d35e2fSjeremylt           CeedVector vec = sub_operators[i]->output_fields[j]->vec;
1604250756a7Sjeremylt           if (vec != CEED_VECTOR_ACTIVE && vec != CEED_VECTOR_NONE) {
1605250756a7Sjeremylt             ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr);
1606250756a7Sjeremylt           }
1607250756a7Sjeremylt         }
1608250756a7Sjeremylt       }
1609250756a7Sjeremylt       // Apply
1610d1d35e2fSjeremylt       for (CeedInt i=0; i<op->num_suboperators; i++) {
1611d1d35e2fSjeremylt         ierr = CeedOperatorApplyAdd(op->sub_operators[i], in, out, request);
1612cae8b89aSjeremylt         CeedChk(ierr);
1613cae8b89aSjeremylt       }
1614cae8b89aSjeremylt     }
1615250756a7Sjeremylt   }
1616e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1617cae8b89aSjeremylt }
1618cae8b89aSjeremylt 
1619cae8b89aSjeremylt /**
1620cae8b89aSjeremylt   @brief Apply CeedOperator to a vector and add result to output vector
1621cae8b89aSjeremylt 
1622cae8b89aSjeremylt   This computes the action of the operator on the specified (active) input,
1623cae8b89aSjeremylt   yielding its (active) output.  All inputs and outputs must be specified using
1624cae8b89aSjeremylt   CeedOperatorSetField().
1625cae8b89aSjeremylt 
1626cae8b89aSjeremylt   @param op        CeedOperator to apply
1627cae8b89aSjeremylt   @param[in] in    CeedVector containing input state or NULL if there are no
1628cae8b89aSjeremylt                      active inputs
1629cae8b89aSjeremylt   @param[out] out  CeedVector to sum in result of applying operator (must be
1630cae8b89aSjeremylt                      distinct from @a in) or NULL if there are no active outputs
1631cae8b89aSjeremylt   @param request   Address of CeedRequest for non-blocking completion, else
16324cc79fe7SJed Brown                      @ref CEED_REQUEST_IMMEDIATE
1633cae8b89aSjeremylt 
1634cae8b89aSjeremylt   @return An error code: 0 - success, otherwise - failure
1635cae8b89aSjeremylt 
16367a982d89SJeremy L. Thompson   @ref User
1637cae8b89aSjeremylt **/
1638cae8b89aSjeremylt int CeedOperatorApplyAdd(CeedOperator op, CeedVector in, CeedVector out,
1639cae8b89aSjeremylt                          CeedRequest *request) {
1640cae8b89aSjeremylt   int ierr;
1641e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
1642cae8b89aSjeremylt 
1643d1d35e2fSjeremylt   if (op->num_elem)  {
1644250756a7Sjeremylt     // Standard Operator
1645250756a7Sjeremylt     ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr);
1646f04ea552SJeremy L Thompson   } else if (op->is_composite) {
1647250756a7Sjeremylt     // Composite Operator
1648250756a7Sjeremylt     if (op->ApplyAddComposite) {
1649250756a7Sjeremylt       ierr = op->ApplyAddComposite(op, in, out, request); CeedChk(ierr);
1650cae8b89aSjeremylt     } else {
1651d1d35e2fSjeremylt       CeedInt num_suboperators;
1652d1d35e2fSjeremylt       ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr);
1653d1d35e2fSjeremylt       CeedOperator *sub_operators;
1654d1d35e2fSjeremylt       ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr);
1655250756a7Sjeremylt 
1656d1d35e2fSjeremylt       for (CeedInt i=0; i<num_suboperators; i++) {
1657d1d35e2fSjeremylt         ierr = CeedOperatorApplyAdd(sub_operators[i], in, out, request);
1658cae8b89aSjeremylt         CeedChk(ierr);
16591d7d2407SJeremy L Thompson       }
1660250756a7Sjeremylt     }
1661250756a7Sjeremylt   }
1662e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1663d7b241e6Sjeremylt }
1664d7b241e6Sjeremylt 
1665d7b241e6Sjeremylt /**
1666b11c1e72Sjeremylt   @brief Destroy a CeedOperator
1667d7b241e6Sjeremylt 
1668d7b241e6Sjeremylt   @param op  CeedOperator to destroy
1669b11c1e72Sjeremylt 
1670b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
1671dfdf5a53Sjeremylt 
16727a982d89SJeremy L. Thompson   @ref User
1673b11c1e72Sjeremylt **/
1674d7b241e6Sjeremylt int CeedOperatorDestroy(CeedOperator *op) {
1675d7b241e6Sjeremylt   int ierr;
1676d7b241e6Sjeremylt 
1677d1d35e2fSjeremylt   if (!*op || --(*op)->ref_count > 0) return CEED_ERROR_SUCCESS;
1678d7b241e6Sjeremylt   if ((*op)->Destroy) {
1679d7b241e6Sjeremylt     ierr = (*op)->Destroy(*op); CeedChk(ierr);
1680d7b241e6Sjeremylt   }
1681fe2413ffSjeremylt   ierr = CeedDestroy(&(*op)->ceed); CeedChk(ierr);
1682fe2413ffSjeremylt   // Free fields
16833668ca4bSJeremy L Thompson   for (CeedInt i=0; i<(*op)->num_fields; i++)
1684d1d35e2fSjeremylt     if ((*op)->input_fields[i]) {
1685d1d35e2fSjeremylt       if ((*op)->input_fields[i]->elem_restr != CEED_ELEMRESTRICTION_NONE) {
1686d1d35e2fSjeremylt         ierr = CeedElemRestrictionDestroy(&(*op)->input_fields[i]->elem_restr);
168771352a93Sjeremylt         CeedChk(ierr);
168815910d16Sjeremylt       }
1689d1d35e2fSjeremylt       if ((*op)->input_fields[i]->basis != CEED_BASIS_COLLOCATED) {
1690d1d35e2fSjeremylt         ierr = CeedBasisDestroy(&(*op)->input_fields[i]->basis); CeedChk(ierr);
169171352a93Sjeremylt       }
1692d1d35e2fSjeremylt       if ((*op)->input_fields[i]->vec != CEED_VECTOR_ACTIVE &&
1693d1d35e2fSjeremylt           (*op)->input_fields[i]->vec != CEED_VECTOR_NONE ) {
1694d1d35e2fSjeremylt         ierr = CeedVectorDestroy(&(*op)->input_fields[i]->vec); CeedChk(ierr);
169571352a93Sjeremylt       }
1696d1d35e2fSjeremylt       ierr = CeedFree(&(*op)->input_fields[i]->field_name); CeedChk(ierr);
1697d1d35e2fSjeremylt       ierr = CeedFree(&(*op)->input_fields[i]); CeedChk(ierr);
1698fe2413ffSjeremylt     }
16993668ca4bSJeremy L Thompson   for (CeedInt i=0; i<(*op)->num_fields; i++)
1700d1d35e2fSjeremylt     if ((*op)->output_fields[i]) {
1701d1d35e2fSjeremylt       ierr = CeedElemRestrictionDestroy(&(*op)->output_fields[i]->elem_restr);
170271352a93Sjeremylt       CeedChk(ierr);
1703d1d35e2fSjeremylt       if ((*op)->output_fields[i]->basis != CEED_BASIS_COLLOCATED) {
1704d1d35e2fSjeremylt         ierr = CeedBasisDestroy(&(*op)->output_fields[i]->basis); CeedChk(ierr);
170571352a93Sjeremylt       }
1706d1d35e2fSjeremylt       if ((*op)->output_fields[i]->vec != CEED_VECTOR_ACTIVE &&
1707d1d35e2fSjeremylt           (*op)->output_fields[i]->vec != CEED_VECTOR_NONE ) {
1708d1d35e2fSjeremylt         ierr = CeedVectorDestroy(&(*op)->output_fields[i]->vec); CeedChk(ierr);
170971352a93Sjeremylt       }
1710d1d35e2fSjeremylt       ierr = CeedFree(&(*op)->output_fields[i]->field_name); CeedChk(ierr);
1711d1d35e2fSjeremylt       ierr = CeedFree(&(*op)->output_fields[i]); CeedChk(ierr);
1712fe2413ffSjeremylt     }
1713d1d35e2fSjeremylt   // Destroy sub_operators
17143668ca4bSJeremy L Thompson   for (CeedInt i=0; i<(*op)->num_suboperators; i++)
1715d1d35e2fSjeremylt     if ((*op)->sub_operators[i]) {
1716d1d35e2fSjeremylt       ierr = CeedOperatorDestroy(&(*op)->sub_operators[i]); CeedChk(ierr);
171752d6035fSJeremy L Thompson     }
1718d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->qf); CeedChk(ierr);
1719d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->dqf); CeedChk(ierr);
1720d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->dqfT); CeedChk(ierr);
17213668ca4bSJeremy L Thompson   // Destroy any composite labels
17223668ca4bSJeremy L Thompson   for (CeedInt i=0; i<(*op)->num_context_labels; i++) {
17233668ca4bSJeremy L Thompson     ierr = CeedFree(&(*op)->context_labels[i]->sub_labels); CeedChk(ierr);
17243668ca4bSJeremy L Thompson     ierr = CeedFree(&(*op)->context_labels[i]); CeedChk(ierr);
17253668ca4bSJeremy L Thompson   }
17263668ca4bSJeremy L Thompson   ierr = CeedFree(&(*op)->context_labels); CeedChk(ierr);
1727fe2413ffSjeremylt 
17285107b09fSJeremy L Thompson   // Destroy fallback
1729805fe78eSJeremy L Thompson   ierr = CeedOperatorDestroy(&(*op)->op_fallback); CeedChk(ierr);
17305107b09fSJeremy L Thompson 
1731ed9e99e6SJeremy L Thompson   // Destroy assembly data
1732480fae85SJeremy L Thompson   ierr = CeedQFunctionAssemblyDataDestroy(&(*op)->qf_assembled); CeedChk(ierr);
1733ed9e99e6SJeremy L Thompson   ierr = CeedOperatorAssemblyDataDestroy(&(*op)->op_assembled); CeedChk(ierr);
173470a7ffb3SJeremy L Thompson 
1735d1d35e2fSjeremylt   ierr = CeedFree(&(*op)->input_fields); CeedChk(ierr);
1736d1d35e2fSjeremylt   ierr = CeedFree(&(*op)->output_fields); CeedChk(ierr);
1737d1d35e2fSjeremylt   ierr = CeedFree(&(*op)->sub_operators); CeedChk(ierr);
1738ea6b5821SJeremy L Thompson   ierr = CeedFree(&(*op)->name); CeedChk(ierr);
1739d7b241e6Sjeremylt   ierr = CeedFree(op); CeedChk(ierr);
1740e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1741d7b241e6Sjeremylt }
1742d7b241e6Sjeremylt 
1743d7b241e6Sjeremylt /// @}
1744