xref: /libCEED/rust/libceed-sys/c-src/interface/ceed-operator.c (revision 9560d06a92c065fb7d600a8c20ade8d9a4cda324)
1d7b241e6Sjeremylt // Copyright (c) 2017, Lawrence Livermore National Security, LLC. Produced at
2d7b241e6Sjeremylt // the Lawrence Livermore National Laboratory. LLNL-CODE-734707. All Rights
3d7b241e6Sjeremylt // reserved. See files LICENSE and NOTICE for details.
4d7b241e6Sjeremylt //
5d7b241e6Sjeremylt // This file is part of CEED, a collection of benchmarks, miniapps, software
6d7b241e6Sjeremylt // libraries and APIs for efficient high-order finite element and spectral
7d7b241e6Sjeremylt // element discretizations for exascale applications. For more information and
8d7b241e6Sjeremylt // source code availability see http://github.com/ceed.
9d7b241e6Sjeremylt //
10d7b241e6Sjeremylt // The CEED research is supported by the Exascale Computing Project 17-SC-20-SC,
11d7b241e6Sjeremylt // a collaborative effort of two U.S. Department of Energy organizations (Office
12d7b241e6Sjeremylt // of Science and the National Nuclear Security Administration) responsible for
13d7b241e6Sjeremylt // the planning and preparation of a capable exascale ecosystem, including
14d7b241e6Sjeremylt // software, applications, hardware, advanced system engineering and early
15d7b241e6Sjeremylt // testbed platforms, in support of the nation's exascale computing imperative.
16d7b241e6Sjeremylt 
17ec3da8bcSJed Brown #include <ceed/ceed.h>
18ec3da8bcSJed Brown #include <ceed/backend.h>
193d576824SJeremy L Thompson #include <ceed-impl.h>
203bd813ffSjeremylt #include <math.h>
213d576824SJeremy L Thompson #include <stdbool.h>
223d576824SJeremy L Thompson #include <stdio.h>
233d576824SJeremy L Thompson #include <string.h>
24d7b241e6Sjeremylt 
25dfdf5a53Sjeremylt /// @file
267a982d89SJeremy L. Thompson /// Implementation of CeedOperator interfaces
277a982d89SJeremy L. Thompson 
287a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
297a982d89SJeremy L. Thompson /// CeedOperator Library Internal Functions
307a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
317a982d89SJeremy L. Thompson /// @addtogroup CeedOperatorDeveloper
327a982d89SJeremy L. Thompson /// @{
337a982d89SJeremy L. Thompson 
347a982d89SJeremy L. Thompson /**
357a982d89SJeremy L. Thompson   @brief Duplicate a CeedOperator with a reference Ceed to fallback for advanced
367a982d89SJeremy L. Thompson            CeedOperator functionality
377a982d89SJeremy L. Thompson 
387a982d89SJeremy L. Thompson   @param op  CeedOperator to create fallback for
397a982d89SJeremy L. Thompson 
407a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
417a982d89SJeremy L. Thompson 
427a982d89SJeremy L. Thompson   @ref Developer
437a982d89SJeremy L. Thompson **/
447a982d89SJeremy L. Thompson int CeedOperatorCreateFallback(CeedOperator op) {
457a982d89SJeremy L. Thompson   int ierr;
467a982d89SJeremy L. Thompson 
477a982d89SJeremy L. Thompson   // Fallback Ceed
48d1d35e2fSjeremylt   const char *resource, *fallback_resource;
497a982d89SJeremy L. Thompson   ierr = CeedGetResource(op->ceed, &resource); CeedChk(ierr);
50d1d35e2fSjeremylt   ierr = CeedGetOperatorFallbackResource(op->ceed, &fallback_resource);
517a982d89SJeremy L. Thompson   CeedChk(ierr);
52d1d35e2fSjeremylt   if (!strcmp(resource, fallback_resource))
537a982d89SJeremy L. Thompson     // LCOV_EXCL_START
54e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED,
55e15f9bd0SJeremy L Thompson                      "Backend %s cannot create an operator"
56d1d35e2fSjeremylt                      "fallback to resource %s", resource, fallback_resource);
577a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
587a982d89SJeremy L. Thompson 
597a982d89SJeremy L. Thompson   // Fallback Ceed
60d1d35e2fSjeremylt   Ceed ceed_ref;
61d1d35e2fSjeremylt   if (!op->ceed->op_fallback_ceed) {
62d1d35e2fSjeremylt     ierr = CeedInit(fallback_resource, &ceed_ref); CeedChk(ierr);
63d1d35e2fSjeremylt     ceed_ref->op_fallback_parent = op->ceed;
64d1d35e2fSjeremylt     ceed_ref->Error = op->ceed->Error;
65d1d35e2fSjeremylt     op->ceed->op_fallback_ceed = ceed_ref;
667a982d89SJeremy L. Thompson   }
67d1d35e2fSjeremylt   ceed_ref = op->ceed->op_fallback_ceed;
687a982d89SJeremy L. Thompson 
697a982d89SJeremy L. Thompson   // Clone Op
70d1d35e2fSjeremylt   CeedOperator op_ref;
71d1d35e2fSjeremylt   ierr = CeedCalloc(1, &op_ref); CeedChk(ierr);
72d1d35e2fSjeremylt   memcpy(op_ref, op, sizeof(*op_ref));
73d1d35e2fSjeremylt   op_ref->data = NULL;
74d1d35e2fSjeremylt   op_ref->interface_setup = false;
75d1d35e2fSjeremylt   op_ref->backend_setup = false;
76d1d35e2fSjeremylt   op_ref->ceed = ceed_ref;
77d1d35e2fSjeremylt   ierr = ceed_ref->OperatorCreate(op_ref); CeedChk(ierr);
78d1d35e2fSjeremylt   op->op_fallback = op_ref;
797a982d89SJeremy L. Thompson 
807a982d89SJeremy L. Thompson   // Clone QF
81d1d35e2fSjeremylt   CeedQFunction qf_ref;
82d1d35e2fSjeremylt   ierr = CeedCalloc(1, &qf_ref); CeedChk(ierr);
83d1d35e2fSjeremylt   memcpy(qf_ref, (op->qf), sizeof(*qf_ref));
84d1d35e2fSjeremylt   qf_ref->data = NULL;
85d1d35e2fSjeremylt   qf_ref->ceed = ceed_ref;
86d1d35e2fSjeremylt   ierr = ceed_ref->QFunctionCreate(qf_ref); CeedChk(ierr);
87d1d35e2fSjeremylt   op_ref->qf = qf_ref;
88d1d35e2fSjeremylt   op->qf_fallback = qf_ref;
89e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
90e15f9bd0SJeremy L Thompson }
917a982d89SJeremy L. Thompson 
92e15f9bd0SJeremy L Thompson /**
93e15f9bd0SJeremy L Thompson   @brief Check if a CeedOperator Field matches the QFunction Field
94e15f9bd0SJeremy L Thompson 
95e15f9bd0SJeremy L Thompson   @param[in] ceed      Ceed object for error handling
96d1d35e2fSjeremylt   @param[in] qf_field  QFunction Field matching Operator Field
97e15f9bd0SJeremy L Thompson   @param[in] r         Operator Field ElemRestriction
98e15f9bd0SJeremy L Thompson   @param[in] b         Operator Field Basis
99e15f9bd0SJeremy L Thompson 
100e15f9bd0SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
101e15f9bd0SJeremy L Thompson 
102e15f9bd0SJeremy L Thompson   @ref Developer
103e15f9bd0SJeremy L Thompson **/
104d1d35e2fSjeremylt static int CeedOperatorCheckField(Ceed ceed, CeedQFunctionField qf_field,
105e15f9bd0SJeremy L Thompson                                   CeedElemRestriction r, CeedBasis b) {
106e15f9bd0SJeremy L Thompson   int ierr;
107d1d35e2fSjeremylt   CeedEvalMode eval_mode = qf_field->eval_mode;
108d1d35e2fSjeremylt   CeedInt dim = 1, num_comp = 1, restr_num_comp = 1, size = qf_field->size;
109e15f9bd0SJeremy L Thompson   // Restriction
110e15f9bd0SJeremy L Thompson   if (r != CEED_ELEMRESTRICTION_NONE) {
111d1d35e2fSjeremylt     if (eval_mode == CEED_EVAL_WEIGHT) {
112e15f9bd0SJeremy L Thompson       // LCOV_EXCL_START
113e1e9e29dSJed Brown       return CeedError(ceed, CEED_ERROR_INCOMPATIBLE,
114e1e9e29dSJed Brown                        "CEED_ELEMRESTRICTION_NONE should be used "
115e15f9bd0SJeremy L Thompson                        "for a field with eval mode CEED_EVAL_WEIGHT");
116e15f9bd0SJeremy L Thompson       // LCOV_EXCL_STOP
117e15f9bd0SJeremy L Thompson     }
118d1d35e2fSjeremylt     ierr = CeedElemRestrictionGetNumComponents(r, &restr_num_comp);
119e1e9e29dSJed Brown   }
120d1d35e2fSjeremylt   if ((r == CEED_ELEMRESTRICTION_NONE) != (eval_mode == CEED_EVAL_WEIGHT)) {
121e1e9e29dSJed Brown     // LCOV_EXCL_START
122e1e9e29dSJed Brown     return CeedError(ceed, CEED_ERROR_INCOMPATIBLE,
123e1e9e29dSJed Brown                      "CEED_ELEMRESTRICTION_NONE and CEED_EVAL_WEIGHT "
124e1e9e29dSJed Brown                      "must be used together.");
125e1e9e29dSJed Brown     // LCOV_EXCL_STOP
126e1e9e29dSJed Brown   }
127e15f9bd0SJeremy L Thompson   // Basis
128e15f9bd0SJeremy L Thompson   if (b != CEED_BASIS_COLLOCATED) {
129d1d35e2fSjeremylt     if (eval_mode == CEED_EVAL_NONE)
130e1e9e29dSJed Brown       return CeedError(ceed, CEED_ERROR_INCOMPATIBLE,
131d1d35e2fSjeremylt                        "Field '%s' configured with CEED_EVAL_NONE must "
132d1d35e2fSjeremylt                        "be used with CEED_BASIS_COLLOCATED",
133d1d35e2fSjeremylt                        qf_field->field_name);
134e15f9bd0SJeremy L Thompson     ierr = CeedBasisGetDimension(b, &dim); CeedChk(ierr);
135d1d35e2fSjeremylt     ierr = CeedBasisGetNumComponents(b, &num_comp); CeedChk(ierr);
136d1d35e2fSjeremylt     if (r != CEED_ELEMRESTRICTION_NONE && restr_num_comp != num_comp) {
137e15f9bd0SJeremy L Thompson       // LCOV_EXCL_START
138e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_DIMENSION,
139d1d35e2fSjeremylt                        "Field '%s' of size %d and EvalMode %s: ElemRestriction "
140d1d35e2fSjeremylt                        "has %d components, but Basis has %d components",
141d1d35e2fSjeremylt                        qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode],
142d1d35e2fSjeremylt                        restr_num_comp,
143d1d35e2fSjeremylt                        num_comp);
144e15f9bd0SJeremy L Thompson       // LCOV_EXCL_STOP
145e15f9bd0SJeremy L Thompson     }
146e15f9bd0SJeremy L Thompson   }
147e15f9bd0SJeremy L Thompson   // Field size
148d1d35e2fSjeremylt   switch(eval_mode) {
149e15f9bd0SJeremy L Thompson   case CEED_EVAL_NONE:
150d1d35e2fSjeremylt     if (size != restr_num_comp)
151e15f9bd0SJeremy L Thompson       // LCOV_EXCL_START
152e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_DIMENSION,
153e1e9e29dSJed Brown                        "Field '%s' of size %d and EvalMode %s: ElemRestriction has %d components",
154d1d35e2fSjeremylt                        qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode],
155d1d35e2fSjeremylt                        restr_num_comp);
156e15f9bd0SJeremy L Thompson     // LCOV_EXCL_STOP
157e15f9bd0SJeremy L Thompson     break;
158e15f9bd0SJeremy L Thompson   case CEED_EVAL_INTERP:
159d1d35e2fSjeremylt     if (size != num_comp)
160e15f9bd0SJeremy L Thompson       // LCOV_EXCL_START
161e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_DIMENSION,
162e1e9e29dSJed Brown                        "Field '%s' of size %d and EvalMode %s: ElemRestriction/Basis has %d components",
163d1d35e2fSjeremylt                        qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode],
164d1d35e2fSjeremylt                        num_comp);
165e15f9bd0SJeremy L Thompson     // LCOV_EXCL_STOP
166e15f9bd0SJeremy L Thompson     break;
167e15f9bd0SJeremy L Thompson   case CEED_EVAL_GRAD:
168d1d35e2fSjeremylt     if (size != num_comp * dim)
169e15f9bd0SJeremy L Thompson       // LCOV_EXCL_START
170e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_DIMENSION,
171d1d35e2fSjeremylt                        "Field '%s' of size %d and EvalMode %s in %d dimensions: "
172d1d35e2fSjeremylt                        "ElemRestriction/Basis has %d components",
173d1d35e2fSjeremylt                        qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode], dim,
174d1d35e2fSjeremylt                        num_comp);
175e15f9bd0SJeremy L Thompson     // LCOV_EXCL_STOP
176e15f9bd0SJeremy L Thompson     break;
177e15f9bd0SJeremy L Thompson   case CEED_EVAL_WEIGHT:
178d1d35e2fSjeremylt     // No additional checks required
179e15f9bd0SJeremy L Thompson     break;
180e15f9bd0SJeremy L Thompson   case CEED_EVAL_DIV:
181e15f9bd0SJeremy L Thompson     // Not implemented
182e15f9bd0SJeremy L Thompson     break;
183e15f9bd0SJeremy L Thompson   case CEED_EVAL_CURL:
184e15f9bd0SJeremy L Thompson     // Not implemented
185e15f9bd0SJeremy L Thompson     break;
186e15f9bd0SJeremy L Thompson   }
187e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1887a982d89SJeremy L. Thompson }
1897a982d89SJeremy L. Thompson 
1907a982d89SJeremy L. Thompson /**
1917a982d89SJeremy L. Thompson   @brief Check if a CeedOperator is ready to be used.
1927a982d89SJeremy L. Thompson 
1937a982d89SJeremy L. Thompson   @param[in] op  CeedOperator to check
1947a982d89SJeremy L. Thompson 
1957a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
1967a982d89SJeremy L. Thompson 
1977a982d89SJeremy L. Thompson   @ref Developer
1987a982d89SJeremy L. Thompson **/
199e2f04181SAndrew T. Barker static int CeedOperatorCheckReady(CeedOperator op) {
200e2f04181SAndrew T. Barker   int ierr;
201e2f04181SAndrew T. Barker   Ceed ceed;
202e2f04181SAndrew T. Barker   ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr);
203e2f04181SAndrew T. Barker 
204d1d35e2fSjeremylt   if (op->interface_setup)
205e15f9bd0SJeremy L Thompson     return CEED_ERROR_SUCCESS;
2067a982d89SJeremy L. Thompson 
207e15f9bd0SJeremy L Thompson   CeedQFunction qf = op->qf;
2087a982d89SJeremy L. Thompson   if (op->composite) {
209d1d35e2fSjeremylt     if (!op->num_suboperators)
2107a982d89SJeremy L. Thompson       // LCOV_EXCL_START
211d1d35e2fSjeremylt       return CeedError(ceed, CEED_ERROR_INCOMPLETE, "No sub_operators set");
2127a982d89SJeremy L. Thompson     // LCOV_EXCL_STOP
2137a982d89SJeremy L. Thompson   } else {
214d1d35e2fSjeremylt     if (op->num_fields == 0)
2157a982d89SJeremy L. Thompson       // LCOV_EXCL_START
216e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_INCOMPLETE, "No operator fields set");
2177a982d89SJeremy L. Thompson     // LCOV_EXCL_STOP
218d1d35e2fSjeremylt     if (op->num_fields < qf->num_input_fields + qf->num_output_fields)
2197a982d89SJeremy L. Thompson       // LCOV_EXCL_START
220e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_INCOMPLETE, "Not all operator fields set");
2217a982d89SJeremy L. Thompson     // LCOV_EXCL_STOP
222d1d35e2fSjeremylt     if (!op->has_restriction)
2237a982d89SJeremy L. Thompson       // LCOV_EXCL_START
224e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_INCOMPLETE,
225e15f9bd0SJeremy L Thompson                        "At least one restriction required");
2267a982d89SJeremy L. Thompson     // LCOV_EXCL_STOP
227d1d35e2fSjeremylt     if (op->num_qpts == 0)
2287a982d89SJeremy L. Thompson       // LCOV_EXCL_START
229e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_INCOMPLETE,
230e15f9bd0SJeremy L Thompson                        "At least one non-collocated basis required");
2317a982d89SJeremy L. Thompson     // LCOV_EXCL_STOP
2327a982d89SJeremy L. Thompson   }
2337a982d89SJeremy L. Thompson 
234e15f9bd0SJeremy L Thompson   // Flag as immutable and ready
235d1d35e2fSjeremylt   op->interface_setup = true;
236e15f9bd0SJeremy L Thompson   if (op->qf && op->qf != CEED_QFUNCTION_NONE)
237e15f9bd0SJeremy L Thompson     // LCOV_EXCL_START
238d1d35e2fSjeremylt     op->qf->operators_set++;
239e15f9bd0SJeremy L Thompson   // LCOV_EXCL_STOP
240e15f9bd0SJeremy L Thompson   if (op->dqf && op->dqf != CEED_QFUNCTION_NONE)
241e15f9bd0SJeremy L Thompson     // LCOV_EXCL_START
242d1d35e2fSjeremylt     op->dqf->operators_set++;
243e15f9bd0SJeremy L Thompson   // LCOV_EXCL_STOP
244e15f9bd0SJeremy L Thompson   if (op->dqfT && op->dqfT != CEED_QFUNCTION_NONE)
245e15f9bd0SJeremy L Thompson     // LCOV_EXCL_START
246d1d35e2fSjeremylt     op->dqfT->operators_set++;
247e15f9bd0SJeremy L Thompson   // LCOV_EXCL_STOP
248e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2497a982d89SJeremy L. Thompson }
2507a982d89SJeremy L. Thompson 
2517a982d89SJeremy L. Thompson /**
2527a982d89SJeremy L. Thompson   @brief View a field of a CeedOperator
2537a982d89SJeremy L. Thompson 
2547a982d89SJeremy L. Thompson   @param[in] field         Operator field to view
255d1d35e2fSjeremylt   @param[in] qf_field      QFunction field (carries field name)
256d1d35e2fSjeremylt   @param[in] field_number  Number of field being viewed
2574c4400c7SValeria Barra   @param[in] sub           true indicates sub-operator, which increases indentation; false for top-level operator
258d1d35e2fSjeremylt   @param[in] input         true for an input field; false for output field
2597a982d89SJeremy L. Thompson   @param[in] stream        Stream to view to, e.g., stdout
2607a982d89SJeremy L. Thompson 
2617a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
2627a982d89SJeremy L. Thompson 
2637a982d89SJeremy L. Thompson   @ref Utility
2647a982d89SJeremy L. Thompson **/
2657a982d89SJeremy L. Thompson static int CeedOperatorFieldView(CeedOperatorField field,
266d1d35e2fSjeremylt                                  CeedQFunctionField qf_field,
267d1d35e2fSjeremylt                                  CeedInt field_number, bool sub, bool input,
2687a982d89SJeremy L. Thompson                                  FILE *stream) {
2697a982d89SJeremy L. Thompson   const char *pre = sub ? "  " : "";
270d1d35e2fSjeremylt   const char *in_out = input ? "Input" : "Output";
2717a982d89SJeremy L. Thompson 
2727a982d89SJeremy L. Thompson   fprintf(stream, "%s    %s Field [%d]:\n"
2737a982d89SJeremy L. Thompson           "%s      Name: \"%s\"\n",
274d1d35e2fSjeremylt           pre, in_out, field_number, pre, qf_field->field_name);
2757a982d89SJeremy L. Thompson 
2767a982d89SJeremy L. Thompson   if (field->basis == CEED_BASIS_COLLOCATED)
2777a982d89SJeremy L. Thompson     fprintf(stream, "%s      Collocated basis\n", pre);
2787a982d89SJeremy L. Thompson 
2797a982d89SJeremy L. Thompson   if (field->vec == CEED_VECTOR_ACTIVE)
2807a982d89SJeremy L. Thompson     fprintf(stream, "%s      Active vector\n", pre);
2817a982d89SJeremy L. Thompson   else if (field->vec == CEED_VECTOR_NONE)
2827a982d89SJeremy L. Thompson     fprintf(stream, "%s      No vector\n", pre);
283e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2847a982d89SJeremy L. Thompson }
2857a982d89SJeremy L. Thompson 
2867a982d89SJeremy L. Thompson /**
2877a982d89SJeremy L. Thompson   @brief View a single CeedOperator
2887a982d89SJeremy L. Thompson 
2897a982d89SJeremy L. Thompson   @param[in] op      CeedOperator to view
2907a982d89SJeremy L. Thompson   @param[in] sub     Boolean flag for sub-operator
2917a982d89SJeremy L. Thompson   @param[in] stream  Stream to write; typically stdout/stderr or a file
2927a982d89SJeremy L. Thompson 
2937a982d89SJeremy L. Thompson   @return Error code: 0 - success, otherwise - failure
2947a982d89SJeremy L. Thompson 
2957a982d89SJeremy L. Thompson   @ref Utility
2967a982d89SJeremy L. Thompson **/
2977a982d89SJeremy L. Thompson int CeedOperatorSingleView(CeedOperator op, bool sub, FILE *stream) {
2987a982d89SJeremy L. Thompson   int ierr;
2997a982d89SJeremy L. Thompson   const char *pre = sub ? "  " : "";
3007a982d89SJeremy L. Thompson 
3017a982d89SJeremy L. Thompson   CeedInt totalfields;
3027a982d89SJeremy L. Thompson   ierr = CeedOperatorGetNumArgs(op, &totalfields); CeedChk(ierr);
3037a982d89SJeremy L. Thompson 
3047a982d89SJeremy L. Thompson   fprintf(stream, "%s  %d Field%s\n", pre, totalfields, totalfields>1 ? "s" : "");
3057a982d89SJeremy L. Thompson 
306d1d35e2fSjeremylt   fprintf(stream, "%s  %d Input Field%s:\n", pre, op->qf->num_input_fields,
307d1d35e2fSjeremylt           op->qf->num_input_fields>1 ? "s" : "");
308d1d35e2fSjeremylt   for (CeedInt i=0; i<op->qf->num_input_fields; i++) {
309d1d35e2fSjeremylt     ierr = CeedOperatorFieldView(op->input_fields[i], op->qf->input_fields[i],
3107a982d89SJeremy L. Thompson                                  i, sub, 1, stream); CeedChk(ierr);
3117a982d89SJeremy L. Thompson   }
3127a982d89SJeremy L. Thompson 
313d1d35e2fSjeremylt   fprintf(stream, "%s  %d Output Field%s:\n", pre, op->qf->num_output_fields,
314d1d35e2fSjeremylt           op->qf->num_output_fields>1 ? "s" : "");
315d1d35e2fSjeremylt   for (CeedInt i=0; i<op->qf->num_output_fields; i++) {
316d1d35e2fSjeremylt     ierr = CeedOperatorFieldView(op->output_fields[i], op->qf->output_fields[i],
3177a982d89SJeremy L. Thompson                                  i, sub, 0, stream); CeedChk(ierr);
3187a982d89SJeremy L. Thompson   }
319e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
3207a982d89SJeremy L. Thompson }
3217a982d89SJeremy L. Thompson 
322d99fa3c5SJeremy L Thompson /**
323e2f04181SAndrew T. Barker   @brief Find the active vector ElemRestriction for a CeedOperator
324e2f04181SAndrew T. Barker 
325e2f04181SAndrew T. Barker   @param[in] op            CeedOperator to find active basis for
326d1d35e2fSjeremylt   @param[out] active_rstr  ElemRestriction for active input vector
327e2f04181SAndrew T. Barker 
328e2f04181SAndrew T. Barker   @return An error code: 0 - success, otherwise - failure
329e2f04181SAndrew T. Barker 
330e2f04181SAndrew T. Barker   @ref Utility
331e2f04181SAndrew T. Barker **/
332e2f04181SAndrew T. Barker static int CeedOperatorGetActiveElemRestriction(CeedOperator op,
333d1d35e2fSjeremylt     CeedElemRestriction *active_rstr) {
334d1d35e2fSjeremylt   *active_rstr = NULL;
335d1d35e2fSjeremylt   for (int i = 0; i < op->qf->num_input_fields; i++)
336d1d35e2fSjeremylt     if (op->input_fields[i]->vec == CEED_VECTOR_ACTIVE) {
337d1d35e2fSjeremylt       *active_rstr = op->input_fields[i]->elem_restr;
338e2f04181SAndrew T. Barker       break;
339e2f04181SAndrew T. Barker     }
340e2f04181SAndrew T. Barker 
341d1d35e2fSjeremylt   if (!*active_rstr) {
342e2f04181SAndrew T. Barker     // LCOV_EXCL_START
343e2f04181SAndrew T. Barker     int ierr;
344e2f04181SAndrew T. Barker     Ceed ceed;
345e2f04181SAndrew T. Barker     ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr);
346e2f04181SAndrew T. Barker     return CeedError(ceed, CEED_ERROR_INCOMPLETE,
347e2f04181SAndrew T. Barker                      "No active ElemRestriction found!");
348e2f04181SAndrew T. Barker     // LCOV_EXCL_STOP
349e2f04181SAndrew T. Barker   }
350e2f04181SAndrew T. Barker   return CEED_ERROR_SUCCESS;
351e2f04181SAndrew T. Barker }
352e2f04181SAndrew T. Barker 
353e2f04181SAndrew T. Barker /**
354d99fa3c5SJeremy L Thompson   @brief Find the active vector basis for a CeedOperator
355d99fa3c5SJeremy L Thompson 
356d99fa3c5SJeremy L Thompson   @param[in] op             CeedOperator to find active basis for
357d1d35e2fSjeremylt   @param[out] active_basis  Basis for active input vector
358d99fa3c5SJeremy L Thompson 
359d99fa3c5SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
360d99fa3c5SJeremy L Thompson 
361d99fa3c5SJeremy L Thompson   @ ref Developer
362d99fa3c5SJeremy L Thompson **/
363d99fa3c5SJeremy L Thompson static int CeedOperatorGetActiveBasis(CeedOperator op,
364d1d35e2fSjeremylt                                       CeedBasis *active_basis) {
365d1d35e2fSjeremylt   *active_basis = NULL;
366d1d35e2fSjeremylt   for (int i = 0; i < op->qf->num_input_fields; i++)
367d1d35e2fSjeremylt     if (op->input_fields[i]->vec == CEED_VECTOR_ACTIVE) {
368d1d35e2fSjeremylt       *active_basis = op->input_fields[i]->basis;
369d99fa3c5SJeremy L Thompson       break;
370d99fa3c5SJeremy L Thompson     }
371d99fa3c5SJeremy L Thompson 
372d1d35e2fSjeremylt   if (!*active_basis) {
373d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
374d99fa3c5SJeremy L Thompson     int ierr;
375d99fa3c5SJeremy L Thompson     Ceed ceed;
376d99fa3c5SJeremy L Thompson     ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr);
377e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_MINOR,
378d99fa3c5SJeremy L Thompson                      "No active basis found for automatic multigrid setup");
379d99fa3c5SJeremy L Thompson     // LCOV_EXCL_STOP
380d99fa3c5SJeremy L Thompson   }
381e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
382d99fa3c5SJeremy L Thompson }
383d99fa3c5SJeremy L Thompson 
384d99fa3c5SJeremy L Thompson /**
385d99fa3c5SJeremy L Thompson   @brief Common code for creating a multigrid coarse operator and level
386d99fa3c5SJeremy L Thompson            transfer operators for a CeedOperator
387d99fa3c5SJeremy L Thompson 
388d1d35e2fSjeremylt   @param[in] op_fine       Fine grid operator
389d1d35e2fSjeremylt   @param[in] p_mult_fine   L-vector multiplicity in parallel gather/scatter
390d1d35e2fSjeremylt   @param[in] rstr_coarse   Coarse grid restriction
391d1d35e2fSjeremylt   @param[in] basis_coarse  Coarse grid active vector basis
392d1d35e2fSjeremylt   @param[in] basis_c_to_f  Basis for coarse to fine interpolation
393d1d35e2fSjeremylt   @param[out] op_coarse    Coarse grid operator
394d1d35e2fSjeremylt   @param[out] op_prolong   Coarse to fine operator
395d1d35e2fSjeremylt   @param[out] op_restrict  Fine to coarse operator
396d99fa3c5SJeremy L Thompson 
397d99fa3c5SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
398d99fa3c5SJeremy L Thompson 
399d99fa3c5SJeremy L Thompson   @ref Developer
400d99fa3c5SJeremy L Thompson **/
401d1d35e2fSjeremylt static int CeedOperatorMultigridLevel_Core(CeedOperator op_fine,
402d1d35e2fSjeremylt     CeedVector p_mult_fine, CeedElemRestriction rstr_coarse, CeedBasis basis_coarse,
403d1d35e2fSjeremylt     CeedBasis basis_c_to_f, CeedOperator *op_coarse, CeedOperator *op_prolong,
404d1d35e2fSjeremylt     CeedOperator *op_restrict) {
405d99fa3c5SJeremy L Thompson   int ierr;
406d99fa3c5SJeremy L Thompson   Ceed ceed;
407d1d35e2fSjeremylt   ierr = CeedOperatorGetCeed(op_fine, &ceed); CeedChk(ierr);
408d99fa3c5SJeremy L Thompson 
409d99fa3c5SJeremy L Thompson   // Check for composite operator
410d1d35e2fSjeremylt   bool is_composite;
411d1d35e2fSjeremylt   ierr = CeedOperatorIsComposite(op_fine, &is_composite); CeedChk(ierr);
412d1d35e2fSjeremylt   if (is_composite)
413d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
414e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_UNSUPPORTED,
415d99fa3c5SJeremy L Thompson                      "Automatic multigrid setup for composite operators not supported");
416d99fa3c5SJeremy L Thompson   // LCOV_EXCL_STOP
417d99fa3c5SJeremy L Thompson 
418d99fa3c5SJeremy L Thompson   // Coarse Grid
419d1d35e2fSjeremylt   ierr = CeedOperatorCreate(ceed, op_fine->qf, op_fine->dqf, op_fine->dqfT,
420d1d35e2fSjeremylt                             op_coarse); CeedChk(ierr);
421d1d35e2fSjeremylt   CeedElemRestriction rstr_fine = NULL;
422d99fa3c5SJeremy L Thompson   // -- Clone input fields
423d1d35e2fSjeremylt   for (int i = 0; i < op_fine->qf->num_input_fields; i++) {
424d1d35e2fSjeremylt     if (op_fine->input_fields[i]->vec == CEED_VECTOR_ACTIVE) {
425d1d35e2fSjeremylt       rstr_fine = op_fine->input_fields[i]->elem_restr;
426d1d35e2fSjeremylt       ierr = CeedOperatorSetField(*op_coarse, op_fine->input_fields[i]->field_name,
427d1d35e2fSjeremylt                                   rstr_coarse, basis_coarse, CEED_VECTOR_ACTIVE);
428d99fa3c5SJeremy L Thompson       CeedChk(ierr);
429d99fa3c5SJeremy L Thompson     } else {
430d1d35e2fSjeremylt       ierr = CeedOperatorSetField(*op_coarse, op_fine->input_fields[i]->field_name,
431d1d35e2fSjeremylt                                   op_fine->input_fields[i]->elem_restr,
432d1d35e2fSjeremylt                                   op_fine->input_fields[i]->basis,
433d1d35e2fSjeremylt                                   op_fine->input_fields[i]->vec); CeedChk(ierr);
434d99fa3c5SJeremy L Thompson     }
435d99fa3c5SJeremy L Thompson   }
436d99fa3c5SJeremy L Thompson   // -- Clone output fields
437d1d35e2fSjeremylt   for (int i = 0; i < op_fine->qf->num_output_fields; i++) {
438d1d35e2fSjeremylt     if (op_fine->output_fields[i]->vec == CEED_VECTOR_ACTIVE) {
439d1d35e2fSjeremylt       ierr = CeedOperatorSetField(*op_coarse, op_fine->output_fields[i]->field_name,
440d1d35e2fSjeremylt                                   rstr_coarse, basis_coarse, CEED_VECTOR_ACTIVE);
441d99fa3c5SJeremy L Thompson       CeedChk(ierr);
442d99fa3c5SJeremy L Thompson     } else {
443d1d35e2fSjeremylt       ierr = CeedOperatorSetField(*op_coarse, op_fine->output_fields[i]->field_name,
444d1d35e2fSjeremylt                                   op_fine->output_fields[i]->elem_restr,
445d1d35e2fSjeremylt                                   op_fine->output_fields[i]->basis,
446d1d35e2fSjeremylt                                   op_fine->output_fields[i]->vec); CeedChk(ierr);
447d99fa3c5SJeremy L Thompson     }
448d99fa3c5SJeremy L Thompson   }
449d99fa3c5SJeremy L Thompson 
450d99fa3c5SJeremy L Thompson   // Multiplicity vector
451d1d35e2fSjeremylt   CeedVector mult_vec, mult_e_vec;
452d1d35e2fSjeremylt   ierr = CeedElemRestrictionCreateVector(rstr_fine, &mult_vec, &mult_e_vec);
453d99fa3c5SJeremy L Thompson   CeedChk(ierr);
454d1d35e2fSjeremylt   ierr = CeedVectorSetValue(mult_e_vec, 0.0); CeedChk(ierr);
455d1d35e2fSjeremylt   ierr = CeedElemRestrictionApply(rstr_fine, CEED_NOTRANSPOSE, p_mult_fine,
456d1d35e2fSjeremylt                                   mult_e_vec, CEED_REQUEST_IMMEDIATE); CeedChk(ierr);
457d1d35e2fSjeremylt   ierr = CeedVectorSetValue(mult_vec, 0.0); CeedChk(ierr);
458d1d35e2fSjeremylt   ierr = CeedElemRestrictionApply(rstr_fine, CEED_TRANSPOSE, mult_e_vec, mult_vec,
459d99fa3c5SJeremy L Thompson                                   CEED_REQUEST_IMMEDIATE); CeedChk(ierr);
460d1d35e2fSjeremylt   ierr = CeedVectorDestroy(&mult_e_vec); CeedChk(ierr);
461d1d35e2fSjeremylt   ierr = CeedVectorReciprocal(mult_vec); CeedChk(ierr);
462d99fa3c5SJeremy L Thompson 
463d99fa3c5SJeremy L Thompson   // Restriction
464d1d35e2fSjeremylt   CeedInt num_comp;
465d1d35e2fSjeremylt   ierr = CeedBasisGetNumComponents(basis_coarse, &num_comp); CeedChk(ierr);
466d1d35e2fSjeremylt   CeedQFunction qf_restrict;
467d1d35e2fSjeremylt   ierr = CeedQFunctionCreateInteriorByName(ceed, "Scale", &qf_restrict);
468d99fa3c5SJeremy L Thompson   CeedChk(ierr);
469d1d35e2fSjeremylt   CeedInt *num_comp_r_data;
470d1d35e2fSjeremylt   ierr = CeedCalloc(1, &num_comp_r_data); CeedChk(ierr);
471d1d35e2fSjeremylt   num_comp_r_data[0] = num_comp;
472d1d35e2fSjeremylt   CeedQFunctionContext ctx_r;
473d1d35e2fSjeremylt   ierr = CeedQFunctionContextCreate(ceed, &ctx_r); CeedChk(ierr);
474d1d35e2fSjeremylt   ierr = CeedQFunctionContextSetData(ctx_r, CEED_MEM_HOST, CEED_OWN_POINTER,
475d1d35e2fSjeremylt                                      sizeof(*num_comp_r_data), num_comp_r_data);
476777ff853SJeremy L Thompson   CeedChk(ierr);
477d1d35e2fSjeremylt   ierr = CeedQFunctionSetContext(qf_restrict, ctx_r); CeedChk(ierr);
478d1d35e2fSjeremylt   ierr = CeedQFunctionContextDestroy(&ctx_r); CeedChk(ierr);
479d1d35e2fSjeremylt   ierr = CeedQFunctionAddInput(qf_restrict, "input", num_comp, CEED_EVAL_NONE);
480d99fa3c5SJeremy L Thompson   CeedChk(ierr);
481d1d35e2fSjeremylt   ierr = CeedQFunctionAddInput(qf_restrict, "scale", num_comp, CEED_EVAL_NONE);
482d99fa3c5SJeremy L Thompson   CeedChk(ierr);
483d1d35e2fSjeremylt   ierr = CeedQFunctionAddOutput(qf_restrict, "output", num_comp,
484d1d35e2fSjeremylt                                 CEED_EVAL_INTERP); CeedChk(ierr);
485d99fa3c5SJeremy L Thompson 
486d1d35e2fSjeremylt   ierr = CeedOperatorCreate(ceed, qf_restrict, CEED_QFUNCTION_NONE,
487d1d35e2fSjeremylt                             CEED_QFUNCTION_NONE, op_restrict);
488d99fa3c5SJeremy L Thompson   CeedChk(ierr);
489d1d35e2fSjeremylt   ierr = CeedOperatorSetField(*op_restrict, "input", rstr_fine,
490d99fa3c5SJeremy L Thompson                               CEED_BASIS_COLLOCATED, CEED_VECTOR_ACTIVE);
491d99fa3c5SJeremy L Thompson   CeedChk(ierr);
492d1d35e2fSjeremylt   ierr = CeedOperatorSetField(*op_restrict, "scale", rstr_fine,
493d1d35e2fSjeremylt                               CEED_BASIS_COLLOCATED, mult_vec);
494d99fa3c5SJeremy L Thompson   CeedChk(ierr);
495d1d35e2fSjeremylt   ierr = CeedOperatorSetField(*op_restrict, "output", rstr_coarse, basis_c_to_f,
496d99fa3c5SJeremy L Thompson                               CEED_VECTOR_ACTIVE); CeedChk(ierr);
497d99fa3c5SJeremy L Thompson 
498d99fa3c5SJeremy L Thompson   // Prolongation
499d1d35e2fSjeremylt   CeedQFunction qf_prolong;
500d1d35e2fSjeremylt   ierr = CeedQFunctionCreateInteriorByName(ceed, "Scale", &qf_prolong);
501d99fa3c5SJeremy L Thompson   CeedChk(ierr);
502d1d35e2fSjeremylt   CeedInt *num_comp_p_data;
503d1d35e2fSjeremylt   ierr = CeedCalloc(1, &num_comp_p_data); CeedChk(ierr);
504d1d35e2fSjeremylt   num_comp_p_data[0] = num_comp;
505d1d35e2fSjeremylt   CeedQFunctionContext ctx_p;
506d1d35e2fSjeremylt   ierr = CeedQFunctionContextCreate(ceed, &ctx_p); CeedChk(ierr);
507d1d35e2fSjeremylt   ierr = CeedQFunctionContextSetData(ctx_p, CEED_MEM_HOST, CEED_OWN_POINTER,
508d1d35e2fSjeremylt                                      sizeof(*num_comp_p_data), num_comp_p_data);
509777ff853SJeremy L Thompson   CeedChk(ierr);
510d1d35e2fSjeremylt   ierr = CeedQFunctionSetContext(qf_prolong, ctx_p); CeedChk(ierr);
511d1d35e2fSjeremylt   ierr = CeedQFunctionContextDestroy(&ctx_p); CeedChk(ierr);
512d1d35e2fSjeremylt   ierr = CeedQFunctionAddInput(qf_prolong, "input", num_comp, CEED_EVAL_INTERP);
513d99fa3c5SJeremy L Thompson   CeedChk(ierr);
514d1d35e2fSjeremylt   ierr = CeedQFunctionAddInput(qf_prolong, "scale", num_comp, CEED_EVAL_NONE);
515d99fa3c5SJeremy L Thompson   CeedChk(ierr);
516d1d35e2fSjeremylt   ierr = CeedQFunctionAddOutput(qf_prolong, "output", num_comp, CEED_EVAL_NONE);
517d99fa3c5SJeremy L Thompson   CeedChk(ierr);
518d99fa3c5SJeremy L Thompson 
519d1d35e2fSjeremylt   ierr = CeedOperatorCreate(ceed, qf_prolong, CEED_QFUNCTION_NONE,
520d1d35e2fSjeremylt                             CEED_QFUNCTION_NONE, op_prolong);
521d99fa3c5SJeremy L Thompson   CeedChk(ierr);
522d1d35e2fSjeremylt   ierr = CeedOperatorSetField(*op_prolong, "input", rstr_coarse, basis_c_to_f,
523d99fa3c5SJeremy L Thompson                               CEED_VECTOR_ACTIVE); CeedChk(ierr);
524d1d35e2fSjeremylt   ierr = CeedOperatorSetField(*op_prolong, "scale", rstr_fine,
525d1d35e2fSjeremylt                               CEED_BASIS_COLLOCATED, mult_vec);
526d99fa3c5SJeremy L Thompson   CeedChk(ierr);
527d1d35e2fSjeremylt   ierr = CeedOperatorSetField(*op_prolong, "output", rstr_fine,
528d99fa3c5SJeremy L Thompson                               CEED_BASIS_COLLOCATED, CEED_VECTOR_ACTIVE);
529d99fa3c5SJeremy L Thompson   CeedChk(ierr);
530d99fa3c5SJeremy L Thompson 
531d99fa3c5SJeremy L Thompson   // Cleanup
532d1d35e2fSjeremylt   ierr = CeedVectorDestroy(&mult_vec); CeedChk(ierr);
533d1d35e2fSjeremylt   ierr = CeedBasisDestroy(&basis_c_to_f); CeedChk(ierr);
534d1d35e2fSjeremylt   ierr = CeedQFunctionDestroy(&qf_restrict); CeedChk(ierr);
535d1d35e2fSjeremylt   ierr = CeedQFunctionDestroy(&qf_prolong); CeedChk(ierr);
536e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
537d99fa3c5SJeremy L Thompson }
538d99fa3c5SJeremy L Thompson 
5397a982d89SJeremy L. Thompson /// @}
5407a982d89SJeremy L. Thompson 
5417a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
5427a982d89SJeremy L. Thompson /// CeedOperator Backend API
5437a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
5447a982d89SJeremy L. Thompson /// @addtogroup CeedOperatorBackend
5457a982d89SJeremy L. Thompson /// @{
5467a982d89SJeremy L. Thompson 
5477a982d89SJeremy L. Thompson /**
5487a982d89SJeremy L. Thompson   @brief Get the Ceed associated with a CeedOperator
5497a982d89SJeremy L. Thompson 
5507a982d89SJeremy L. Thompson   @param op         CeedOperator
5517a982d89SJeremy L. Thompson   @param[out] ceed  Variable to store Ceed
5527a982d89SJeremy L. Thompson 
5537a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5547a982d89SJeremy L. Thompson 
5557a982d89SJeremy L. Thompson   @ref Backend
5567a982d89SJeremy L. Thompson **/
5577a982d89SJeremy L. Thompson 
5587a982d89SJeremy L. Thompson int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) {
5597a982d89SJeremy L. Thompson   *ceed = op->ceed;
560e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5617a982d89SJeremy L. Thompson }
5627a982d89SJeremy L. Thompson 
5637a982d89SJeremy L. Thompson /**
5647a982d89SJeremy L. Thompson   @brief Get the number of elements associated with a CeedOperator
5657a982d89SJeremy L. Thompson 
5667a982d89SJeremy L. Thompson   @param op             CeedOperator
567d1d35e2fSjeremylt   @param[out] num_elem  Variable to store number of elements
5687a982d89SJeremy L. Thompson 
5697a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5707a982d89SJeremy L. Thompson 
5717a982d89SJeremy L. Thompson   @ref Backend
5727a982d89SJeremy L. Thompson **/
5737a982d89SJeremy L. Thompson 
574d1d35e2fSjeremylt int CeedOperatorGetNumElements(CeedOperator op, CeedInt *num_elem) {
5757a982d89SJeremy L. Thompson   if (op->composite)
5767a982d89SJeremy L. Thompson     // LCOV_EXCL_START
577e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
578e15f9bd0SJeremy L Thompson                      "Not defined for composite operator");
5797a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
5807a982d89SJeremy L. Thompson 
581d1d35e2fSjeremylt   *num_elem = op->num_elem;
582e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5837a982d89SJeremy L. Thompson }
5847a982d89SJeremy L. Thompson 
5857a982d89SJeremy L. Thompson /**
5867a982d89SJeremy L. Thompson   @brief Get the number of quadrature points associated with a CeedOperator
5877a982d89SJeremy L. Thompson 
5887a982d89SJeremy L. Thompson   @param op             CeedOperator
589d1d35e2fSjeremylt   @param[out] num_qpts  Variable to store vector number of quadrature points
5907a982d89SJeremy L. Thompson 
5917a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5927a982d89SJeremy L. Thompson 
5937a982d89SJeremy L. Thompson   @ref Backend
5947a982d89SJeremy L. Thompson **/
5957a982d89SJeremy L. Thompson 
596d1d35e2fSjeremylt int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *num_qpts) {
5977a982d89SJeremy L. Thompson   if (op->composite)
5987a982d89SJeremy L. Thompson     // LCOV_EXCL_START
599e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
600e15f9bd0SJeremy L Thompson                      "Not defined for composite operator");
6017a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
6027a982d89SJeremy L. Thompson 
603d1d35e2fSjeremylt   *num_qpts = op->num_qpts;
604e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6057a982d89SJeremy L. Thompson }
6067a982d89SJeremy L. Thompson 
6077a982d89SJeremy L. Thompson /**
6087a982d89SJeremy L. Thompson   @brief Get the number of arguments associated with a CeedOperator
6097a982d89SJeremy L. Thompson 
6107a982d89SJeremy L. Thompson   @param op             CeedOperator
611d1d35e2fSjeremylt   @param[out] num_args  Variable to store vector number of arguments
6127a982d89SJeremy L. Thompson 
6137a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6147a982d89SJeremy L. Thompson 
6157a982d89SJeremy L. Thompson   @ref Backend
6167a982d89SJeremy L. Thompson **/
6177a982d89SJeremy L. Thompson 
618d1d35e2fSjeremylt int CeedOperatorGetNumArgs(CeedOperator op, CeedInt *num_args) {
6197a982d89SJeremy L. Thompson   if (op->composite)
6207a982d89SJeremy L. Thompson     // LCOV_EXCL_START
621e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
622e15f9bd0SJeremy L Thompson                      "Not defined for composite operators");
6237a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
6247a982d89SJeremy L. Thompson 
625d1d35e2fSjeremylt   *num_args = op->num_fields;
626e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6277a982d89SJeremy L. Thompson }
6287a982d89SJeremy L. Thompson 
6297a982d89SJeremy L. Thompson /**
6307a982d89SJeremy L. Thompson   @brief Get the setup status of a CeedOperator
6317a982d89SJeremy L. Thompson 
6327a982d89SJeremy L. Thompson   @param op                  CeedOperator
633d1d35e2fSjeremylt   @param[out] is_setup_done  Variable to store setup status
6347a982d89SJeremy L. Thompson 
6357a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6367a982d89SJeremy L. Thompson 
6377a982d89SJeremy L. Thompson   @ref Backend
6387a982d89SJeremy L. Thompson **/
6397a982d89SJeremy L. Thompson 
640d1d35e2fSjeremylt int CeedOperatorIsSetupDone(CeedOperator op, bool *is_setup_done) {
641d1d35e2fSjeremylt   *is_setup_done = op->backend_setup;
642e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6437a982d89SJeremy L. Thompson }
6447a982d89SJeremy L. Thompson 
6457a982d89SJeremy L. Thompson /**
6467a982d89SJeremy L. Thompson   @brief Get the QFunction associated with a CeedOperator
6477a982d89SJeremy L. Thompson 
6487a982d89SJeremy L. Thompson   @param op       CeedOperator
6497a982d89SJeremy L. Thompson   @param[out] qf  Variable to store QFunction
6507a982d89SJeremy L. Thompson 
6517a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6527a982d89SJeremy L. Thompson 
6537a982d89SJeremy L. Thompson   @ref Backend
6547a982d89SJeremy L. Thompson **/
6557a982d89SJeremy L. Thompson 
6567a982d89SJeremy L. Thompson int CeedOperatorGetQFunction(CeedOperator op, CeedQFunction *qf) {
6577a982d89SJeremy L. Thompson   if (op->composite)
6587a982d89SJeremy L. Thompson     // LCOV_EXCL_START
659e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
660e15f9bd0SJeremy L Thompson                      "Not defined for composite operator");
6617a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
6627a982d89SJeremy L. Thompson 
6637a982d89SJeremy L. Thompson   *qf = op->qf;
664e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6657a982d89SJeremy L. Thompson }
6667a982d89SJeremy L. Thompson 
6677a982d89SJeremy L. Thompson /**
668c04a41a7SJeremy L Thompson   @brief Get a boolean value indicating if the CeedOperator is composite
669c04a41a7SJeremy L Thompson 
670c04a41a7SJeremy L Thompson   @param op                 CeedOperator
671d1d35e2fSjeremylt   @param[out] is_composite  Variable to store composite status
672c04a41a7SJeremy L Thompson 
673c04a41a7SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
674c04a41a7SJeremy L Thompson 
675c04a41a7SJeremy L Thompson   @ref Backend
676c04a41a7SJeremy L Thompson **/
677c04a41a7SJeremy L Thompson 
678d1d35e2fSjeremylt int CeedOperatorIsComposite(CeedOperator op, bool *is_composite) {
679d1d35e2fSjeremylt   *is_composite = op->composite;
680e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
681c04a41a7SJeremy L Thompson }
682c04a41a7SJeremy L Thompson 
683c04a41a7SJeremy L Thompson /**
684d1d35e2fSjeremylt   @brief Get the number of sub_operators associated with a CeedOperator
6857a982d89SJeremy L. Thompson 
6867a982d89SJeremy L. Thompson   @param op                     CeedOperator
687d1d35e2fSjeremylt   @param[out] num_suboperators  Variable to store number of sub_operators
6887a982d89SJeremy L. Thompson 
6897a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6907a982d89SJeremy L. Thompson 
6917a982d89SJeremy L. Thompson   @ref Backend
6927a982d89SJeremy L. Thompson **/
6937a982d89SJeremy L. Thompson 
694d1d35e2fSjeremylt int CeedOperatorGetNumSub(CeedOperator op, CeedInt *num_suboperators) {
6957a982d89SJeremy L. Thompson   if (!op->composite)
6967a982d89SJeremy L. Thompson     // LCOV_EXCL_START
697e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR, "Not a composite operator");
6987a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
6997a982d89SJeremy L. Thompson 
700d1d35e2fSjeremylt   *num_suboperators = op->num_suboperators;
701e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
7027a982d89SJeremy L. Thompson }
7037a982d89SJeremy L. Thompson 
7047a982d89SJeremy L. Thompson /**
705d1d35e2fSjeremylt   @brief Get the list of sub_operators associated with a CeedOperator
7067a982d89SJeremy L. Thompson 
7077a982d89SJeremy L. Thompson   @param op                  CeedOperator
708d1d35e2fSjeremylt   @param[out] sub_operators  Variable to store list of sub_operators
7097a982d89SJeremy L. Thompson 
7107a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
7117a982d89SJeremy L. Thompson 
7127a982d89SJeremy L. Thompson   @ref Backend
7137a982d89SJeremy L. Thompson **/
7147a982d89SJeremy L. Thompson 
715d1d35e2fSjeremylt int CeedOperatorGetSubList(CeedOperator op, CeedOperator **sub_operators) {
7167a982d89SJeremy L. Thompson   if (!op->composite)
7177a982d89SJeremy L. Thompson     // LCOV_EXCL_START
718e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR, "Not a composite operator");
7197a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
7207a982d89SJeremy L. Thompson 
721d1d35e2fSjeremylt   *sub_operators = op->sub_operators;
722e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
7237a982d89SJeremy L. Thompson }
7247a982d89SJeremy L. Thompson 
7257a982d89SJeremy L. Thompson /**
7267a982d89SJeremy L. Thompson   @brief Get the backend data of a CeedOperator
7277a982d89SJeremy L. Thompson 
7287a982d89SJeremy L. Thompson   @param op         CeedOperator
7297a982d89SJeremy L. Thompson   @param[out] data  Variable to store data
7307a982d89SJeremy L. Thompson 
7317a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
7327a982d89SJeremy L. Thompson 
7337a982d89SJeremy L. Thompson   @ref Backend
7347a982d89SJeremy L. Thompson **/
7357a982d89SJeremy L. Thompson 
736777ff853SJeremy L Thompson int CeedOperatorGetData(CeedOperator op, void *data) {
737777ff853SJeremy L Thompson   *(void **)data = op->data;
738e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
7397a982d89SJeremy L. Thompson }
7407a982d89SJeremy L. Thompson 
7417a982d89SJeremy L. Thompson /**
7427a982d89SJeremy L. Thompson   @brief Set the backend data of a CeedOperator
7437a982d89SJeremy L. Thompson 
7447a982d89SJeremy L. Thompson   @param[out] op  CeedOperator
7457a982d89SJeremy L. Thompson   @param data     Data to set
7467a982d89SJeremy L. Thompson 
7477a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
7487a982d89SJeremy L. Thompson 
7497a982d89SJeremy L. Thompson   @ref Backend
7507a982d89SJeremy L. Thompson **/
7517a982d89SJeremy L. Thompson 
752777ff853SJeremy L Thompson int CeedOperatorSetData(CeedOperator op, void *data) {
753777ff853SJeremy L Thompson   op->data = data;
754e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
7557a982d89SJeremy L. Thompson }
7567a982d89SJeremy L. Thompson 
7577a982d89SJeremy L. Thompson /**
75834359f16Sjeremylt   @brief Increment the reference counter for a CeedOperator
75934359f16Sjeremylt 
76034359f16Sjeremylt   @param op  CeedOperator to increment the reference counter
76134359f16Sjeremylt 
76234359f16Sjeremylt   @return An error code: 0 - success, otherwise - failure
76334359f16Sjeremylt 
76434359f16Sjeremylt   @ref Backend
76534359f16Sjeremylt **/
766*9560d06aSjeremylt int CeedOperatorReference(CeedOperator op) {
76734359f16Sjeremylt   op->ref_count++;
76834359f16Sjeremylt   return CEED_ERROR_SUCCESS;
76934359f16Sjeremylt }
77034359f16Sjeremylt 
77134359f16Sjeremylt /**
7727a982d89SJeremy L. Thompson   @brief Set the setup flag of a CeedOperator to True
7737a982d89SJeremy L. Thompson 
7747a982d89SJeremy L. Thompson   @param op  CeedOperator
7757a982d89SJeremy L. Thompson 
7767a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
7777a982d89SJeremy L. Thompson 
7787a982d89SJeremy L. Thompson   @ref Backend
7797a982d89SJeremy L. Thompson **/
7807a982d89SJeremy L. Thompson 
7817a982d89SJeremy L. Thompson int CeedOperatorSetSetupDone(CeedOperator op) {
782d1d35e2fSjeremylt   op->backend_setup = true;
783e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
7847a982d89SJeremy L. Thompson }
7857a982d89SJeremy L. Thompson 
7867a982d89SJeremy L. Thompson /**
7877a982d89SJeremy L. Thompson   @brief Get the CeedOperatorFields of a CeedOperator
7887a982d89SJeremy L. Thompson 
7897a982d89SJeremy L. Thompson   @param op                  CeedOperator
790d1d35e2fSjeremylt   @param[out] input_fields   Variable to store input_fields
791d1d35e2fSjeremylt   @param[out] output_fields  Variable to store output_fields
7927a982d89SJeremy L. Thompson 
7937a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
7947a982d89SJeremy L. Thompson 
7957a982d89SJeremy L. Thompson   @ref Backend
7967a982d89SJeremy L. Thompson **/
7977a982d89SJeremy L. Thompson 
798d1d35e2fSjeremylt int CeedOperatorGetFields(CeedOperator op, CeedOperatorField **input_fields,
799d1d35e2fSjeremylt                           CeedOperatorField **output_fields) {
8007a982d89SJeremy L. Thompson   if (op->composite)
8017a982d89SJeremy L. Thompson     // LCOV_EXCL_START
802e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
803e15f9bd0SJeremy L Thompson                      "Not defined for composite operator");
8047a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
8057a982d89SJeremy L. Thompson 
806d1d35e2fSjeremylt   if (input_fields) *input_fields = op->input_fields;
807d1d35e2fSjeremylt   if (output_fields) *output_fields = op->output_fields;
808e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
8097a982d89SJeremy L. Thompson }
8107a982d89SJeremy L. Thompson 
8117a982d89SJeremy L. Thompson /**
8127a982d89SJeremy L. Thompson   @brief Get the CeedElemRestriction of a CeedOperatorField
8137a982d89SJeremy L. Thompson 
814d1d35e2fSjeremylt   @param op_field   CeedOperatorField
8157a982d89SJeremy L. Thompson   @param[out] rstr  Variable to store CeedElemRestriction
8167a982d89SJeremy L. Thompson 
8177a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
8187a982d89SJeremy L. Thompson 
8197a982d89SJeremy L. Thompson   @ref Backend
8207a982d89SJeremy L. Thompson **/
8217a982d89SJeremy L. Thompson 
822d1d35e2fSjeremylt int CeedOperatorFieldGetElemRestriction(CeedOperatorField op_field,
8237a982d89SJeremy L. Thompson                                         CeedElemRestriction *rstr) {
824d1d35e2fSjeremylt   *rstr = op_field->elem_restr;
825e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
8267a982d89SJeremy L. Thompson }
8277a982d89SJeremy L. Thompson 
8287a982d89SJeremy L. Thompson /**
8297a982d89SJeremy L. Thompson   @brief Get the CeedBasis of a CeedOperatorField
8307a982d89SJeremy L. Thompson 
831d1d35e2fSjeremylt   @param op_field    CeedOperatorField
8327a982d89SJeremy L. Thompson   @param[out] basis  Variable to store CeedBasis
8337a982d89SJeremy L. Thompson 
8347a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
8357a982d89SJeremy L. Thompson 
8367a982d89SJeremy L. Thompson   @ref Backend
8377a982d89SJeremy L. Thompson **/
8387a982d89SJeremy L. Thompson 
839d1d35e2fSjeremylt int CeedOperatorFieldGetBasis(CeedOperatorField op_field, CeedBasis *basis) {
840d1d35e2fSjeremylt   *basis = op_field->basis;
841e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
8427a982d89SJeremy L. Thompson }
8437a982d89SJeremy L. Thompson 
8447a982d89SJeremy L. Thompson /**
8457a982d89SJeremy L. Thompson   @brief Get the CeedVector of a CeedOperatorField
8467a982d89SJeremy L. Thompson 
847d1d35e2fSjeremylt   @param op_field  CeedOperatorField
8487a982d89SJeremy L. Thompson   @param[out] vec  Variable to store CeedVector
8497a982d89SJeremy L. Thompson 
8507a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
8517a982d89SJeremy L. Thompson 
8527a982d89SJeremy L. Thompson   @ref Backend
8537a982d89SJeremy L. Thompson **/
8547a982d89SJeremy L. Thompson 
855d1d35e2fSjeremylt int CeedOperatorFieldGetVector(CeedOperatorField op_field, CeedVector *vec) {
856d1d35e2fSjeremylt   *vec = op_field->vec;
857e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
8587a982d89SJeremy L. Thompson }
8597a982d89SJeremy L. Thompson 
8607a982d89SJeremy L. Thompson /// @}
8617a982d89SJeremy L. Thompson 
8627a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
8637a982d89SJeremy L. Thompson /// CeedOperator Public API
8647a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
8657a982d89SJeremy L. Thompson /// @addtogroup CeedOperatorUser
866dfdf5a53Sjeremylt /// @{
867d7b241e6Sjeremylt 
868d7b241e6Sjeremylt /**
8690219ea01SJeremy L Thompson   @brief Create a CeedOperator and associate a CeedQFunction. A CeedBasis and
8700219ea01SJeremy L Thompson            CeedElemRestriction can be associated with CeedQFunction fields with
8710219ea01SJeremy L Thompson            \ref CeedOperatorSetField.
872d7b241e6Sjeremylt 
873b11c1e72Sjeremylt   @param ceed     A Ceed object where the CeedOperator will be created
874d7b241e6Sjeremylt   @param qf       QFunction defining the action of the operator at quadrature points
87534138859Sjeremylt   @param dqf      QFunction defining the action of the Jacobian of @a qf (or
8764cc79fe7SJed Brown                     @ref CEED_QFUNCTION_NONE)
877d7b241e6Sjeremylt   @param dqfT     QFunction defining the action of the transpose of the Jacobian
8784cc79fe7SJed Brown                     of @a qf (or @ref CEED_QFUNCTION_NONE)
879b11c1e72Sjeremylt   @param[out] op  Address of the variable where the newly created
880b11c1e72Sjeremylt                     CeedOperator will be stored
881b11c1e72Sjeremylt 
882b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
883dfdf5a53Sjeremylt 
8847a982d89SJeremy L. Thompson   @ref User
885d7b241e6Sjeremylt  */
886d7b241e6Sjeremylt int CeedOperatorCreate(Ceed ceed, CeedQFunction qf, CeedQFunction dqf,
887d7b241e6Sjeremylt                        CeedQFunction dqfT, CeedOperator *op) {
888d7b241e6Sjeremylt   int ierr;
889d7b241e6Sjeremylt 
8905fe0d4faSjeremylt   if (!ceed->OperatorCreate) {
8915fe0d4faSjeremylt     Ceed delegate;
892aefd8378Sjeremylt     ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr);
8935fe0d4faSjeremylt 
8945fe0d4faSjeremylt     if (!delegate)
895c042f62fSJeremy L Thompson       // LCOV_EXCL_START
896e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_UNSUPPORTED,
897e15f9bd0SJeremy L Thompson                        "Backend does not support OperatorCreate");
898c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
8995fe0d4faSjeremylt 
9005fe0d4faSjeremylt     ierr = CeedOperatorCreate(delegate, qf, dqf, dqfT, op); CeedChk(ierr);
901e15f9bd0SJeremy L Thompson     return CEED_ERROR_SUCCESS;
9025fe0d4faSjeremylt   }
9035fe0d4faSjeremylt 
904b3b7035fSJeremy L Thompson   if (!qf || qf == CEED_QFUNCTION_NONE)
905b3b7035fSJeremy L Thompson     // LCOV_EXCL_START
906e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_MINOR,
907e15f9bd0SJeremy L Thompson                      "Operator must have a valid QFunction.");
908b3b7035fSJeremy L Thompson   // LCOV_EXCL_STOP
909d7b241e6Sjeremylt   ierr = CeedCalloc(1, op); CeedChk(ierr);
910d7b241e6Sjeremylt   (*op)->ceed = ceed;
911*9560d06aSjeremylt   ierr = CeedReference(ceed); CeedChk(ierr);
912d1d35e2fSjeremylt   (*op)->ref_count = 1;
913d7b241e6Sjeremylt   (*op)->qf = qf;
914*9560d06aSjeremylt   ierr = CeedQFunctionReference(qf); CeedChk(ierr);
915442e7f0bSjeremylt   if (dqf && dqf != CEED_QFUNCTION_NONE) {
916d7b241e6Sjeremylt     (*op)->dqf = dqf;
917*9560d06aSjeremylt     ierr = CeedQFunctionReference(dqf); CeedChk(ierr);
918442e7f0bSjeremylt   }
919442e7f0bSjeremylt   if (dqfT && dqfT != CEED_QFUNCTION_NONE) {
920d7b241e6Sjeremylt     (*op)->dqfT = dqfT;
921*9560d06aSjeremylt     ierr = CeedQFunctionReference(dqfT); CeedChk(ierr);
922442e7f0bSjeremylt   }
923d1d35e2fSjeremylt   ierr = CeedCalloc(16, &(*op)->input_fields); CeedChk(ierr);
924d1d35e2fSjeremylt   ierr = CeedCalloc(16, &(*op)->output_fields); CeedChk(ierr);
925d7b241e6Sjeremylt   ierr = ceed->OperatorCreate(*op); CeedChk(ierr);
926e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
927d7b241e6Sjeremylt }
928d7b241e6Sjeremylt 
929d7b241e6Sjeremylt /**
93052d6035fSJeremy L Thompson   @brief Create an operator that composes the action of several operators
93152d6035fSJeremy L Thompson 
93252d6035fSJeremy L Thompson   @param ceed     A Ceed object where the CeedOperator will be created
93352d6035fSJeremy L Thompson   @param[out] op  Address of the variable where the newly created
93452d6035fSJeremy L Thompson                     Composite CeedOperator will be stored
93552d6035fSJeremy L Thompson 
93652d6035fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
93752d6035fSJeremy L Thompson 
9387a982d89SJeremy L. Thompson   @ref User
93952d6035fSJeremy L Thompson  */
94052d6035fSJeremy L Thompson int CeedCompositeOperatorCreate(Ceed ceed, CeedOperator *op) {
94152d6035fSJeremy L Thompson   int ierr;
94252d6035fSJeremy L Thompson 
94352d6035fSJeremy L Thompson   if (!ceed->CompositeOperatorCreate) {
94452d6035fSJeremy L Thompson     Ceed delegate;
945aefd8378Sjeremylt     ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr);
94652d6035fSJeremy L Thompson 
947250756a7Sjeremylt     if (delegate) {
94852d6035fSJeremy L Thompson       ierr = CeedCompositeOperatorCreate(delegate, op); CeedChk(ierr);
949e15f9bd0SJeremy L Thompson       return CEED_ERROR_SUCCESS;
95052d6035fSJeremy L Thompson     }
951250756a7Sjeremylt   }
95252d6035fSJeremy L Thompson 
95352d6035fSJeremy L Thompson   ierr = CeedCalloc(1, op); CeedChk(ierr);
95452d6035fSJeremy L Thompson   (*op)->ceed = ceed;
955*9560d06aSjeremylt   ierr = CeedReference(ceed); CeedChk(ierr);
95652d6035fSJeremy L Thompson   (*op)->composite = true;
957d1d35e2fSjeremylt   ierr = CeedCalloc(16, &(*op)->sub_operators); CeedChk(ierr);
958250756a7Sjeremylt 
959250756a7Sjeremylt   if (ceed->CompositeOperatorCreate) {
96052d6035fSJeremy L Thompson     ierr = ceed->CompositeOperatorCreate(*op); CeedChk(ierr);
961250756a7Sjeremylt   }
962e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
96352d6035fSJeremy L Thompson }
96452d6035fSJeremy L Thompson 
96552d6035fSJeremy L Thompson /**
966*9560d06aSjeremylt   @brief Copy the pointer to a CeedOperator. Both pointers should
967*9560d06aSjeremylt            be destroyed with `CeedOperatorDestroy()`;
968*9560d06aSjeremylt            Note: If `*op_copy` is non-NULL, then it is assumed that
969*9560d06aSjeremylt            `*op_copy` is a pointer to a CeedOperator. This
970*9560d06aSjeremylt            CeedOperator will be destroyed if `*op_copy` is the only
971*9560d06aSjeremylt            reference to this CeedOperator.
972*9560d06aSjeremylt 
973*9560d06aSjeremylt   @param op            CeedOperator to copy reference to
974*9560d06aSjeremylt   @param[out] op_copy  Variable to store copied reference
975*9560d06aSjeremylt 
976*9560d06aSjeremylt   @return An error code: 0 - success, otherwise - failure
977*9560d06aSjeremylt 
978*9560d06aSjeremylt   @ref User
979*9560d06aSjeremylt **/
980*9560d06aSjeremylt int CeedOperatorReferenceCopy(CeedOperator op, CeedOperator *op_copy) {
981*9560d06aSjeremylt   int ierr;
982*9560d06aSjeremylt 
983*9560d06aSjeremylt   ierr = CeedOperatorReference(op); CeedChk(ierr);
984*9560d06aSjeremylt   ierr = CeedOperatorDestroy(op_copy); CeedChk(ierr);
985*9560d06aSjeremylt   *op_copy = op;
986*9560d06aSjeremylt   return CEED_ERROR_SUCCESS;
987*9560d06aSjeremylt }
988*9560d06aSjeremylt 
989*9560d06aSjeremylt /**
990b11c1e72Sjeremylt   @brief Provide a field to a CeedOperator for use by its CeedQFunction
991d7b241e6Sjeremylt 
992d7b241e6Sjeremylt   This function is used to specify both active and passive fields to a
993d7b241e6Sjeremylt   CeedOperator.  For passive fields, a vector @arg v must be provided.  Passive
994d7b241e6Sjeremylt   fields can inputs or outputs (updated in-place when operator is applied).
995d7b241e6Sjeremylt 
996d7b241e6Sjeremylt   Active fields must be specified using this function, but their data (in a
997d7b241e6Sjeremylt   CeedVector) is passed in CeedOperatorApply().  There can be at most one active
998d7b241e6Sjeremylt   input and at most one active output.
999d7b241e6Sjeremylt 
10008c91a0c9SJeremy L Thompson   @param op          CeedOperator on which to provide the field
1001d1d35e2fSjeremylt   @param field_name  Name of the field (to be matched with the name used by
10028795c945Sjeremylt                        CeedQFunction)
1003b11c1e72Sjeremylt   @param r           CeedElemRestriction
10044cc79fe7SJed Brown   @param b           CeedBasis in which the field resides or @ref CEED_BASIS_COLLOCATED
1005b11c1e72Sjeremylt                        if collocated with quadrature points
10064cc79fe7SJed Brown   @param v           CeedVector to be used by CeedOperator or @ref CEED_VECTOR_ACTIVE
10074cc79fe7SJed Brown                        if field is active or @ref CEED_VECTOR_NONE if using
10084cc79fe7SJed Brown                        @ref CEED_EVAL_WEIGHT in the QFunction
1009b11c1e72Sjeremylt 
1010b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
1011dfdf5a53Sjeremylt 
10127a982d89SJeremy L. Thompson   @ref User
1013b11c1e72Sjeremylt **/
1014d1d35e2fSjeremylt int CeedOperatorSetField(CeedOperator op, const char *field_name,
1015a8d32208Sjeremylt                          CeedElemRestriction r, CeedBasis b, CeedVector v) {
1016d7b241e6Sjeremylt   int ierr;
101752d6035fSJeremy L Thompson   if (op->composite)
1018c042f62fSJeremy L Thompson     // LCOV_EXCL_START
1019e1e9e29dSJed Brown     return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
1020e15f9bd0SJeremy L Thompson                      "Cannot add field to composite operator.");
1021c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
10228b067b84SJed Brown   if (!r)
1023c042f62fSJeremy L Thompson     // LCOV_EXCL_START
1024e1e9e29dSJed Brown     return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
1025c042f62fSJeremy L Thompson                      "ElemRestriction r for field \"%s\" must be non-NULL.",
1026d1d35e2fSjeremylt                      field_name);
1027c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
10288b067b84SJed Brown   if (!b)
1029c042f62fSJeremy L Thompson     // LCOV_EXCL_START
1030e1e9e29dSJed Brown     return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
1031e15f9bd0SJeremy L Thompson                      "Basis b for field \"%s\" must be non-NULL.",
1032d1d35e2fSjeremylt                      field_name);
1033c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
10348b067b84SJed Brown   if (!v)
1035c042f62fSJeremy L Thompson     // LCOV_EXCL_START
1036e1e9e29dSJed Brown     return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
1037e15f9bd0SJeremy L Thompson                      "Vector v for field \"%s\" must be non-NULL.",
1038d1d35e2fSjeremylt                      field_name);
1039c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
104052d6035fSJeremy L Thompson 
1041d1d35e2fSjeremylt   CeedInt num_elem;
1042d1d35e2fSjeremylt   ierr = CeedElemRestrictionGetNumElements(r, &num_elem); CeedChk(ierr);
1043d1d35e2fSjeremylt   if (r != CEED_ELEMRESTRICTION_NONE && op->has_restriction &&
1044d1d35e2fSjeremylt       op->num_elem != num_elem)
1045c042f62fSJeremy L Thompson     // LCOV_EXCL_START
1046e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_DIMENSION,
10471d102b48SJeremy L Thompson                      "ElemRestriction with %d elements incompatible with prior "
1048d1d35e2fSjeremylt                      "%d elements", num_elem, op->num_elem);
1049c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
1050d7b241e6Sjeremylt 
1051d1d35e2fSjeremylt   CeedInt num_qpts;
1052e15f9bd0SJeremy L Thompson   if (b != CEED_BASIS_COLLOCATED) {
1053d1d35e2fSjeremylt     ierr = CeedBasisGetNumQuadraturePoints(b, &num_qpts); CeedChk(ierr);
1054d1d35e2fSjeremylt     if (op->num_qpts && op->num_qpts != num_qpts)
1055c042f62fSJeremy L Thompson       // LCOV_EXCL_START
1056e15f9bd0SJeremy L Thompson       return CeedError(op->ceed, CEED_ERROR_DIMENSION,
1057e15f9bd0SJeremy L Thompson                        "Basis with %d quadrature points "
1058d1d35e2fSjeremylt                        "incompatible with prior %d points", num_qpts,
1059d1d35e2fSjeremylt                        op->num_qpts);
1060c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
1061d7b241e6Sjeremylt   }
1062d1d35e2fSjeremylt   CeedQFunctionField qf_field;
1063d1d35e2fSjeremylt   CeedOperatorField *op_field;
1064d1d35e2fSjeremylt   for (CeedInt i=0; i<op->qf->num_input_fields; i++) {
1065d1d35e2fSjeremylt     if (!strcmp(field_name, (*op->qf->input_fields[i]).field_name)) {
1066d1d35e2fSjeremylt       qf_field = op->qf->input_fields[i];
1067d1d35e2fSjeremylt       op_field = &op->input_fields[i];
1068d7b241e6Sjeremylt       goto found;
1069d7b241e6Sjeremylt     }
1070d7b241e6Sjeremylt   }
1071d1d35e2fSjeremylt   for (CeedInt i=0; i<op->qf->num_output_fields; i++) {
1072d1d35e2fSjeremylt     if (!strcmp(field_name, (*op->qf->output_fields[i]).field_name)) {
1073d1d35e2fSjeremylt       qf_field = op->qf->output_fields[i];
1074d1d35e2fSjeremylt       op_field = &op->output_fields[i];
1075d7b241e6Sjeremylt       goto found;
1076d7b241e6Sjeremylt     }
1077d7b241e6Sjeremylt   }
1078c042f62fSJeremy L Thompson   // LCOV_EXCL_START
1079e15f9bd0SJeremy L Thompson   return CeedError(op->ceed, CEED_ERROR_INCOMPLETE,
1080e15f9bd0SJeremy L Thompson                    "QFunction has no knowledge of field '%s'",
1081d1d35e2fSjeremylt                    field_name);
1082c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
1083d7b241e6Sjeremylt found:
1084d1d35e2fSjeremylt   ierr = CeedOperatorCheckField(op->ceed, qf_field, r, b); CeedChk(ierr);
1085d1d35e2fSjeremylt   ierr = CeedCalloc(1, op_field); CeedChk(ierr);
1086e15f9bd0SJeremy L Thompson 
1087d1d35e2fSjeremylt   (*op_field)->vec = v;
1088e15f9bd0SJeremy L Thompson   if (v != CEED_VECTOR_ACTIVE && v != CEED_VECTOR_NONE) {
1089*9560d06aSjeremylt     ierr = CeedVectorReference(v); CeedChk(ierr);
1090e15f9bd0SJeremy L Thompson   }
1091e15f9bd0SJeremy L Thompson 
1092d1d35e2fSjeremylt   (*op_field)->elem_restr = r;
1093*9560d06aSjeremylt   ierr = CeedElemRestrictionReference(r); CeedChk(ierr);
1094e15f9bd0SJeremy L Thompson   if (r != CEED_ELEMRESTRICTION_NONE) {
1095d1d35e2fSjeremylt     op->num_elem = num_elem;
1096d1d35e2fSjeremylt     op->has_restriction = true; // Restriction set, but num_elem may be 0
1097e15f9bd0SJeremy L Thompson   }
1098d99fa3c5SJeremy L Thompson 
1099d1d35e2fSjeremylt   (*op_field)->basis = b;
1100e15f9bd0SJeremy L Thompson   if (b != CEED_BASIS_COLLOCATED) {
1101d1d35e2fSjeremylt     op->num_qpts = num_qpts;
1102*9560d06aSjeremylt     ierr = CeedBasisReference(b); CeedChk(ierr);
1103e15f9bd0SJeremy L Thompson   }
1104e15f9bd0SJeremy L Thompson 
1105d1d35e2fSjeremylt   op->num_fields += 1;
1106d1d35e2fSjeremylt   size_t len = strlen(field_name);
1107d99fa3c5SJeremy L Thompson   char *tmp;
1108d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(len+1, &tmp); CeedChk(ierr);
1109d1d35e2fSjeremylt   memcpy(tmp, field_name, len+1);
1110d1d35e2fSjeremylt   (*op_field)->field_name = tmp;
1111e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1112d7b241e6Sjeremylt }
1113d7b241e6Sjeremylt 
1114d7b241e6Sjeremylt /**
111552d6035fSJeremy L Thompson   @brief Add a sub-operator to a composite CeedOperator
1116288c0443SJeremy L Thompson 
1117d1d35e2fSjeremylt   @param[out] composite_op  Composite CeedOperator
1118d1d35e2fSjeremylt   @param      sub_op        Sub-operator CeedOperator
111952d6035fSJeremy L Thompson 
112052d6035fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
112152d6035fSJeremy L Thompson 
11227a982d89SJeremy L. Thompson   @ref User
112352d6035fSJeremy L Thompson  */
1124d1d35e2fSjeremylt int CeedCompositeOperatorAddSub(CeedOperator composite_op,
1125d1d35e2fSjeremylt                                 CeedOperator sub_op) {
112634359f16Sjeremylt   int ierr;
112734359f16Sjeremylt 
1128d1d35e2fSjeremylt   if (!composite_op->composite)
1129c042f62fSJeremy L Thompson     // LCOV_EXCL_START
1130d1d35e2fSjeremylt     return CeedError(composite_op->ceed, CEED_ERROR_MINOR,
1131e2f04181SAndrew T. Barker                      "CeedOperator is not a composite operator");
1132c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
113352d6035fSJeremy L Thompson 
1134d1d35e2fSjeremylt   if (composite_op->num_suboperators == CEED_COMPOSITE_MAX)
1135c042f62fSJeremy L Thompson     // LCOV_EXCL_START
1136d1d35e2fSjeremylt     return CeedError(composite_op->ceed, CEED_ERROR_UNSUPPORTED,
1137d1d35e2fSjeremylt                      "Cannot add additional sub_operators");
1138c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
113952d6035fSJeremy L Thompson 
1140d1d35e2fSjeremylt   composite_op->sub_operators[composite_op->num_suboperators] = sub_op;
1141*9560d06aSjeremylt   ierr = CeedOperatorReference(sub_op); CeedChk(ierr);
1142d1d35e2fSjeremylt   composite_op->num_suboperators++;
1143e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
114452d6035fSJeremy L Thompson }
114552d6035fSJeremy L Thompson 
114652d6035fSJeremy L Thompson /**
11471d102b48SJeremy L Thompson   @brief Assemble a linear CeedQFunction associated with a CeedOperator
11481d102b48SJeremy L Thompson 
11491d102b48SJeremy L Thompson   This returns a CeedVector containing a matrix at each quadrature point
11501d102b48SJeremy L Thompson     providing the action of the CeedQFunction associated with the CeedOperator.
11511d102b48SJeremy L Thompson     The vector 'assembled' is of shape
11521d102b48SJeremy L Thompson       [num_elements, num_input_fields, num_output_fields, num_quad_points]
11531d102b48SJeremy L Thompson     and contains column-major matrices representing the action of the
11541d102b48SJeremy L Thompson     CeedQFunction for a corresponding quadrature point on an element. Inputs and
11551d102b48SJeremy L Thompson     outputs are in the order provided by the user when adding CeedOperator fields.
11564cc79fe7SJed Brown     For example, a CeedQFunction with inputs 'u' and 'gradu' and outputs 'gradv' and
11571d102b48SJeremy L Thompson     'v', provided in that order, would result in an assembled QFunction that
11581d102b48SJeremy L Thompson     consists of (1 + dim) x (dim + 1) matrices at each quadrature point acting
11591d102b48SJeremy L Thompson     on the input [u, du_0, du_1] and producing the output [dv_0, dv_1, v].
11601d102b48SJeremy L Thompson 
11611d102b48SJeremy L Thompson   @param op              CeedOperator to assemble CeedQFunction
11621d102b48SJeremy L Thompson   @param[out] assembled  CeedVector to store assembled CeedQFunction at
11631d102b48SJeremy L Thompson                            quadrature points
11641d102b48SJeremy L Thompson   @param[out] rstr       CeedElemRestriction for CeedVector containing assembled
11651d102b48SJeremy L Thompson                            CeedQFunction
11661d102b48SJeremy L Thompson   @param request         Address of CeedRequest for non-blocking completion, else
11674cc79fe7SJed Brown                            @ref CEED_REQUEST_IMMEDIATE
11681d102b48SJeremy L Thompson 
11691d102b48SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
11701d102b48SJeremy L Thompson 
11717a982d89SJeremy L. Thompson   @ref User
11721d102b48SJeremy L Thompson **/
117380ac2e43SJeremy L Thompson int CeedOperatorLinearAssembleQFunction(CeedOperator op, CeedVector *assembled,
11747f823360Sjeremylt                                         CeedElemRestriction *rstr,
11757f823360Sjeremylt                                         CeedRequest *request) {
11761d102b48SJeremy L Thompson   int ierr;
1177e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
11781d102b48SJeremy L Thompson 
11797172caadSjeremylt   // Backend version
118080ac2e43SJeremy L Thompson   if (op->LinearAssembleQFunction) {
1181e2f04181SAndrew T. Barker     return op->LinearAssembleQFunction(op, assembled, rstr, request);
11825107b09fSJeremy L Thompson   } else {
11835107b09fSJeremy L Thompson     // Fallback to reference Ceed
1184d1d35e2fSjeremylt     if (!op->op_fallback) {
11855107b09fSJeremy L Thompson       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
11865107b09fSJeremy L Thompson     }
11875107b09fSJeremy L Thompson     // Assemble
1188d1d35e2fSjeremylt     return CeedOperatorLinearAssembleQFunction(op->op_fallback, assembled,
1189e2f04181SAndrew T. Barker            rstr, request);
11905107b09fSJeremy L Thompson   }
11911d102b48SJeremy L Thompson }
11921d102b48SJeremy L Thompson 
11931d102b48SJeremy L Thompson /**
1194d965c7a7SJeremy L Thompson   @brief Assemble the diagonal of a square linear CeedOperator
1195b7ec98d8SJeremy L Thompson 
11969e9210b8SJeremy L Thompson   This overwrites a CeedVector with the diagonal of a linear CeedOperator.
1197b7ec98d8SJeremy L Thompson 
1198c04a41a7SJeremy L Thompson   Note: Currently only non-composite CeedOperators with a single field and
1199c04a41a7SJeremy L Thompson           composite CeedOperators with single field sub-operators are supported.
1200d965c7a7SJeremy L Thompson 
1201b7ec98d8SJeremy L Thompson   @param op              CeedOperator to assemble CeedQFunction
1202b7ec98d8SJeremy L Thompson   @param[out] assembled  CeedVector to store assembled CeedOperator diagonal
1203b7ec98d8SJeremy L Thompson   @param request         Address of CeedRequest for non-blocking completion, else
12044cc79fe7SJed Brown                            @ref CEED_REQUEST_IMMEDIATE
1205b7ec98d8SJeremy L Thompson 
1206b7ec98d8SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1207b7ec98d8SJeremy L Thompson 
12087a982d89SJeremy L. Thompson   @ref User
1209b7ec98d8SJeremy L Thompson **/
12102bba3ffaSJeremy L Thompson int CeedOperatorLinearAssembleDiagonal(CeedOperator op, CeedVector assembled,
12117f823360Sjeremylt                                        CeedRequest *request) {
1212b7ec98d8SJeremy L Thompson   int ierr;
1213e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
1214b7ec98d8SJeremy L Thompson 
1215b7ec98d8SJeremy L Thompson   // Use backend version, if available
121680ac2e43SJeremy L Thompson   if (op->LinearAssembleDiagonal) {
1217e2f04181SAndrew T. Barker     return op->LinearAssembleDiagonal(op, assembled, request);
12189e9210b8SJeremy L Thompson   } else if (op->LinearAssembleAddDiagonal) {
12199e9210b8SJeremy L Thompson     ierr = CeedVectorSetValue(assembled, 0.0); CeedChk(ierr);
12209e9210b8SJeremy L Thompson     return CeedOperatorLinearAssembleAddDiagonal(op, assembled, request);
12219e9210b8SJeremy L Thompson   } else {
12229e9210b8SJeremy L Thompson     // Fallback to reference Ceed
1223d1d35e2fSjeremylt     if (!op->op_fallback) {
12249e9210b8SJeremy L Thompson       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
12259e9210b8SJeremy L Thompson     }
12269e9210b8SJeremy L Thompson     // Assemble
1227d1d35e2fSjeremylt     return CeedOperatorLinearAssembleDiagonal(op->op_fallback, assembled,
1228e2f04181SAndrew T. Barker            request);
12299e9210b8SJeremy L Thompson   }
12309e9210b8SJeremy L Thompson }
12319e9210b8SJeremy L Thompson 
12329e9210b8SJeremy L Thompson /**
12339e9210b8SJeremy L Thompson   @brief Assemble the diagonal of a square linear CeedOperator
12349e9210b8SJeremy L Thompson 
12359e9210b8SJeremy L Thompson   This sums into a CeedVector the diagonal of a linear CeedOperator.
12369e9210b8SJeremy L Thompson 
12379e9210b8SJeremy L Thompson   Note: Currently only non-composite CeedOperators with a single field and
12389e9210b8SJeremy L Thompson           composite CeedOperators with single field sub-operators are supported.
12399e9210b8SJeremy L Thompson 
12409e9210b8SJeremy L Thompson   @param op              CeedOperator to assemble CeedQFunction
12419e9210b8SJeremy L Thompson   @param[out] assembled  CeedVector to store assembled CeedOperator diagonal
12429e9210b8SJeremy L Thompson   @param request         Address of CeedRequest for non-blocking completion, else
12439e9210b8SJeremy L Thompson                            @ref CEED_REQUEST_IMMEDIATE
12449e9210b8SJeremy L Thompson 
12459e9210b8SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
12469e9210b8SJeremy L Thompson 
12479e9210b8SJeremy L Thompson   @ref User
12489e9210b8SJeremy L Thompson **/
12499e9210b8SJeremy L Thompson int CeedOperatorLinearAssembleAddDiagonal(CeedOperator op, CeedVector assembled,
12509e9210b8SJeremy L Thompson     CeedRequest *request) {
12519e9210b8SJeremy L Thompson   int ierr;
1252e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
12539e9210b8SJeremy L Thompson 
12549e9210b8SJeremy L Thompson   // Use backend version, if available
12559e9210b8SJeremy L Thompson   if (op->LinearAssembleAddDiagonal) {
1256e2f04181SAndrew T. Barker     return op->LinearAssembleAddDiagonal(op, assembled, request);
12577172caadSjeremylt   } else {
12587172caadSjeremylt     // Fallback to reference Ceed
1259d1d35e2fSjeremylt     if (!op->op_fallback) {
12607172caadSjeremylt       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
1261b7ec98d8SJeremy L Thompson     }
12627172caadSjeremylt     // Assemble
1263d1d35e2fSjeremylt     return CeedOperatorLinearAssembleAddDiagonal(op->op_fallback, assembled,
1264e2f04181SAndrew T. Barker            request);
1265b7ec98d8SJeremy L Thompson   }
1266b7ec98d8SJeremy L Thompson }
1267b7ec98d8SJeremy L Thompson 
1268b7ec98d8SJeremy L Thompson /**
1269d965c7a7SJeremy L Thompson   @brief Assemble the point block diagonal of a square linear CeedOperator
1270d965c7a7SJeremy L Thompson 
12719e9210b8SJeremy L Thompson   This overwrites a CeedVector with the point block diagonal of a linear
1272d965c7a7SJeremy L Thompson     CeedOperator.
1273d965c7a7SJeremy L Thompson 
1274c04a41a7SJeremy L Thompson   Note: Currently only non-composite CeedOperators with a single field and
1275c04a41a7SJeremy L Thompson           composite CeedOperators with single field sub-operators are supported.
1276d965c7a7SJeremy L Thompson 
1277d965c7a7SJeremy L Thompson   @param op              CeedOperator to assemble CeedQFunction
1278d965c7a7SJeremy L Thompson   @param[out] assembled  CeedVector to store assembled CeedOperator point block
1279d965c7a7SJeremy L Thompson                            diagonal, provided in row-major form with an
1280d1d35e2fSjeremylt                            @a num_comp * @a num_comp block at each node. The dimensions
1281d965c7a7SJeremy L Thompson                            of this vector are derived from the active vector
1282d965c7a7SJeremy L Thompson                            for the CeedOperator. The array has shape
1283d965c7a7SJeremy L Thompson                            [nodes, component out, component in].
1284d965c7a7SJeremy L Thompson   @param request         Address of CeedRequest for non-blocking completion, else
1285d965c7a7SJeremy L Thompson                            CEED_REQUEST_IMMEDIATE
1286d965c7a7SJeremy L Thompson 
1287d965c7a7SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1288d965c7a7SJeremy L Thompson 
1289d965c7a7SJeremy L Thompson   @ref User
1290d965c7a7SJeremy L Thompson **/
129180ac2e43SJeremy L Thompson int CeedOperatorLinearAssemblePointBlockDiagonal(CeedOperator op,
12922bba3ffaSJeremy L Thompson     CeedVector assembled, CeedRequest *request) {
1293d965c7a7SJeremy L Thompson   int ierr;
1294e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
1295d965c7a7SJeremy L Thompson 
1296d965c7a7SJeremy L Thompson   // Use backend version, if available
129780ac2e43SJeremy L Thompson   if (op->LinearAssemblePointBlockDiagonal) {
1298e2f04181SAndrew T. Barker     return op->LinearAssemblePointBlockDiagonal(op, assembled, request);
12999e9210b8SJeremy L Thompson   } else if (op->LinearAssembleAddPointBlockDiagonal) {
13009e9210b8SJeremy L Thompson     ierr = CeedVectorSetValue(assembled, 0.0); CeedChk(ierr);
13019e9210b8SJeremy L Thompson     return CeedOperatorLinearAssembleAddPointBlockDiagonal(op, assembled,
13029e9210b8SJeremy L Thompson            request);
1303d965c7a7SJeremy L Thompson   } else {
1304d965c7a7SJeremy L Thompson     // Fallback to reference Ceed
1305d1d35e2fSjeremylt     if (!op->op_fallback) {
1306d965c7a7SJeremy L Thompson       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
1307d965c7a7SJeremy L Thompson     }
1308d965c7a7SJeremy L Thompson     // Assemble
1309d1d35e2fSjeremylt     return CeedOperatorLinearAssemblePointBlockDiagonal(op->op_fallback,
1310e2f04181SAndrew T. Barker            assembled, request);
13119e9210b8SJeremy L Thompson   }
13129e9210b8SJeremy L Thompson }
13139e9210b8SJeremy L Thompson 
13149e9210b8SJeremy L Thompson /**
13159e9210b8SJeremy L Thompson   @brief Assemble the point block diagonal of a square linear CeedOperator
13169e9210b8SJeremy L Thompson 
13179e9210b8SJeremy L Thompson   This sums into a CeedVector with the point block diagonal of a linear
13189e9210b8SJeremy L Thompson     CeedOperator.
13199e9210b8SJeremy L Thompson 
13209e9210b8SJeremy L Thompson   Note: Currently only non-composite CeedOperators with a single field and
13219e9210b8SJeremy L Thompson           composite CeedOperators with single field sub-operators are supported.
13229e9210b8SJeremy L Thompson 
13239e9210b8SJeremy L Thompson   @param op              CeedOperator to assemble CeedQFunction
13249e9210b8SJeremy L Thompson   @param[out] assembled  CeedVector to store assembled CeedOperator point block
13259e9210b8SJeremy L Thompson                            diagonal, provided in row-major form with an
1326d1d35e2fSjeremylt                            @a num_comp * @a num_comp block at each node. The dimensions
13279e9210b8SJeremy L Thompson                            of this vector are derived from the active vector
13289e9210b8SJeremy L Thompson                            for the CeedOperator. The array has shape
13299e9210b8SJeremy L Thompson                            [nodes, component out, component in].
13309e9210b8SJeremy L Thompson   @param request         Address of CeedRequest for non-blocking completion, else
13319e9210b8SJeremy L Thompson                            CEED_REQUEST_IMMEDIATE
13329e9210b8SJeremy L Thompson 
13339e9210b8SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
13349e9210b8SJeremy L Thompson 
13359e9210b8SJeremy L Thompson   @ref User
13369e9210b8SJeremy L Thompson **/
13379e9210b8SJeremy L Thompson int CeedOperatorLinearAssembleAddPointBlockDiagonal(CeedOperator op,
13389e9210b8SJeremy L Thompson     CeedVector assembled, CeedRequest *request) {
13399e9210b8SJeremy L Thompson   int ierr;
1340e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
13419e9210b8SJeremy L Thompson 
13429e9210b8SJeremy L Thompson   // Use backend version, if available
13439e9210b8SJeremy L Thompson   if (op->LinearAssembleAddPointBlockDiagonal) {
1344e2f04181SAndrew T. Barker     return op->LinearAssembleAddPointBlockDiagonal(op, assembled, request);
13459e9210b8SJeremy L Thompson   } else {
13469e9210b8SJeremy L Thompson     // Fallback to reference Ceed
1347d1d35e2fSjeremylt     if (!op->op_fallback) {
13489e9210b8SJeremy L Thompson       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
13499e9210b8SJeremy L Thompson     }
13509e9210b8SJeremy L Thompson     // Assemble
1351d1d35e2fSjeremylt     return CeedOperatorLinearAssembleAddPointBlockDiagonal(op->op_fallback,
1352e2f04181SAndrew T. Barker            assembled, request);
1353d965c7a7SJeremy L Thompson   }
1354e2f04181SAndrew T. Barker }
1355e2f04181SAndrew T. Barker 
1356e2f04181SAndrew T. Barker /**
1357e2f04181SAndrew T. Barker    @brief Build nonzero pattern for non-composite operator.
1358e2f04181SAndrew T. Barker 
1359e2f04181SAndrew T. Barker    Users should generally use CeedOperatorLinearAssembleSymbolic()
1360e2f04181SAndrew T. Barker 
1361e2f04181SAndrew T. Barker    @ref Developer
1362e2f04181SAndrew T. Barker **/
1363e2f04181SAndrew T. Barker int CeedSingleOperatorAssembleSymbolic(CeedOperator op, CeedInt offset,
1364e2f04181SAndrew T. Barker                                        CeedInt *rows, CeedInt *cols) {
1365e2f04181SAndrew T. Barker   int ierr;
1366e2f04181SAndrew T. Barker   Ceed ceed = op->ceed;
1367e2f04181SAndrew T. Barker   if (op->composite)
1368e2f04181SAndrew T. Barker     // LCOV_EXCL_START
1369e2f04181SAndrew T. Barker     return CeedError(ceed, CEED_ERROR_UNSUPPORTED,
1370e2f04181SAndrew T. Barker                      "Composite operator not supported");
1371e2f04181SAndrew T. Barker   // LCOV_EXCL_STOP
1372e2f04181SAndrew T. Barker 
1373d1d35e2fSjeremylt   CeedElemRestriction rstr_in;
1374d1d35e2fSjeremylt   ierr = CeedOperatorGetActiveElemRestriction(op, &rstr_in); CeedChk(ierr);
1375d1d35e2fSjeremylt   CeedInt num_elem, elem_size, num_nodes, num_comp;
1376d1d35e2fSjeremylt   ierr = CeedElemRestrictionGetNumElements(rstr_in, &num_elem); CeedChk(ierr);
1377d1d35e2fSjeremylt   ierr = CeedElemRestrictionGetElementSize(rstr_in, &elem_size); CeedChk(ierr);
1378d1d35e2fSjeremylt   ierr = CeedElemRestrictionGetLVectorSize(rstr_in, &num_nodes); CeedChk(ierr);
1379d1d35e2fSjeremylt   ierr = CeedElemRestrictionGetNumComponents(rstr_in, &num_comp); CeedChk(ierr);
1380e2f04181SAndrew T. Barker   CeedInt layout_er[3];
1381d1d35e2fSjeremylt   ierr = CeedElemRestrictionGetELayout(rstr_in, &layout_er); CeedChk(ierr);
1382e2f04181SAndrew T. Barker 
1383d1d35e2fSjeremylt   CeedInt local_num_entries = elem_size*num_comp * elem_size*num_comp * num_elem;
1384e2f04181SAndrew T. Barker 
1385e2f04181SAndrew T. Barker   // Determine elem_dof relation
1386e2f04181SAndrew T. Barker   CeedVector index_vec;
1387d1d35e2fSjeremylt   ierr = CeedVectorCreate(ceed, num_nodes, &index_vec); CeedChk(ierr);
1388e2f04181SAndrew T. Barker   CeedScalar *array;
1389e2f04181SAndrew T. Barker   ierr = CeedVectorGetArray(index_vec, CEED_MEM_HOST, &array); CeedChk(ierr);
1390d1d35e2fSjeremylt   for (CeedInt i = 0; i < num_nodes; ++i) {
1391e2f04181SAndrew T. Barker     array[i] = i;
1392e2f04181SAndrew T. Barker   }
1393e2f04181SAndrew T. Barker   ierr = CeedVectorRestoreArray(index_vec, &array); CeedChk(ierr);
1394e2f04181SAndrew T. Barker   CeedVector elem_dof;
1395d1d35e2fSjeremylt   ierr = CeedVectorCreate(ceed, num_elem * elem_size * num_comp, &elem_dof);
1396e2f04181SAndrew T. Barker   CeedChk(ierr);
1397e2f04181SAndrew T. Barker   ierr = CeedVectorSetValue(elem_dof, 0.0); CeedChk(ierr);
1398d1d35e2fSjeremylt   CeedElemRestrictionApply(rstr_in, CEED_NOTRANSPOSE, index_vec,
1399e2f04181SAndrew T. Barker                            elem_dof, CEED_REQUEST_IMMEDIATE); CeedChk(ierr);
1400e2f04181SAndrew T. Barker   const CeedScalar *elem_dof_a;
1401e2f04181SAndrew T. Barker   ierr = CeedVectorGetArrayRead(elem_dof, CEED_MEM_HOST, &elem_dof_a);
1402e2f04181SAndrew T. Barker   CeedChk(ierr);
1403e2f04181SAndrew T. Barker   ierr = CeedVectorDestroy(&index_vec); CeedChk(ierr);
1404e2f04181SAndrew T. Barker 
1405e2f04181SAndrew T. Barker   // Determine i, j locations for element matrices
1406e2f04181SAndrew T. Barker   CeedInt count = 0;
1407d1d35e2fSjeremylt   for (int e = 0; e < num_elem; ++e) {
1408d1d35e2fSjeremylt     for (int comp_in = 0; comp_in < num_comp; ++comp_in) {
1409d1d35e2fSjeremylt       for (int comp_out = 0; comp_out < num_comp; ++comp_out) {
1410d1d35e2fSjeremylt         for (int i = 0; i < elem_size; ++i) {
1411d1d35e2fSjeremylt           for (int j = 0; j < elem_size; ++j) {
1412d1d35e2fSjeremylt             const CeedInt elem_dof_index_row = (i)*layout_er[0] +
1413d1d35e2fSjeremylt                                                (comp_out)*layout_er[1] + e*layout_er[2];
1414d1d35e2fSjeremylt             const CeedInt elem_dof_index_col = (j)*layout_er[0] +
1415d1d35e2fSjeremylt                                                (comp_in)*layout_er[1] + e*layout_er[2];
1416e2f04181SAndrew T. Barker 
1417d1d35e2fSjeremylt             const CeedInt row = elem_dof_a[elem_dof_index_row];
1418d1d35e2fSjeremylt             const CeedInt col = elem_dof_a[elem_dof_index_col];
1419e2f04181SAndrew T. Barker 
1420e2f04181SAndrew T. Barker             rows[offset + count] = row;
1421e2f04181SAndrew T. Barker             cols[offset + count] = col;
1422e2f04181SAndrew T. Barker             count++;
1423e2f04181SAndrew T. Barker           }
1424e2f04181SAndrew T. Barker         }
1425e2f04181SAndrew T. Barker       }
1426e2f04181SAndrew T. Barker     }
1427e2f04181SAndrew T. Barker   }
1428d1d35e2fSjeremylt   if (count != local_num_entries)
1429e2f04181SAndrew T. Barker     // LCOV_EXCL_START
1430e2f04181SAndrew T. Barker     return CeedError(ceed, CEED_ERROR_MAJOR, "Error computing assembled entries");
1431e2f04181SAndrew T. Barker   // LCOV_EXCL_STOP
1432e2f04181SAndrew T. Barker   ierr = CeedVectorRestoreArrayRead(elem_dof, &elem_dof_a); CeedChk(ierr);
1433e2f04181SAndrew T. Barker   ierr = CeedVectorDestroy(&elem_dof); CeedChk(ierr);
1434e2f04181SAndrew T. Barker 
1435e2f04181SAndrew T. Barker   return CEED_ERROR_SUCCESS;
1436e2f04181SAndrew T. Barker }
1437e2f04181SAndrew T. Barker 
1438e2f04181SAndrew T. Barker /**
1439e2f04181SAndrew T. Barker    @brief Assemble nonzero entries for non-composite operator
1440e2f04181SAndrew T. Barker 
1441e2f04181SAndrew T. Barker    Users should generally use CeedOperatorLinearAssemble()
1442e2f04181SAndrew T. Barker 
1443e2f04181SAndrew T. Barker    @ref Developer
1444e2f04181SAndrew T. Barker **/
1445e2f04181SAndrew T. Barker int CeedSingleOperatorAssemble(CeedOperator op, CeedInt offset,
1446e2f04181SAndrew T. Barker                                CeedVector values) {
1447e2f04181SAndrew T. Barker   int ierr;
1448e2f04181SAndrew T. Barker   Ceed ceed = op->ceed;;
1449e2f04181SAndrew T. Barker   if (op->composite)
1450e2f04181SAndrew T. Barker     // LCOV_EXCL_START
1451e2f04181SAndrew T. Barker     return CeedError(ceed, CEED_ERROR_UNSUPPORTED,
1452e2f04181SAndrew T. Barker                      "Composite operator not supported");
1453e2f04181SAndrew T. Barker   // LCOV_EXCL_STOP
1454e2f04181SAndrew T. Barker 
1455e2f04181SAndrew T. Barker   // Assemble QFunction
1456e2f04181SAndrew T. Barker   CeedQFunction qf;
1457e2f04181SAndrew T. Barker   ierr = CeedOperatorGetQFunction(op, &qf); CeedChk(ierr);
1458d1d35e2fSjeremylt   CeedInt num_input_fields, num_output_fields;
1459d1d35e2fSjeremylt   ierr= CeedQFunctionGetNumArgs(qf, &num_input_fields, &num_output_fields);
1460e2f04181SAndrew T. Barker   CeedChk(ierr);
1461d1d35e2fSjeremylt   CeedVector assembled_qf;
1462e2f04181SAndrew T. Barker   CeedElemRestriction rstr_q;
1463e2f04181SAndrew T. Barker   ierr = CeedOperatorLinearAssembleQFunction(
1464d1d35e2fSjeremylt            op, &assembled_qf, &rstr_q, CEED_REQUEST_IMMEDIATE); CeedChk(ierr);
1465e2f04181SAndrew T. Barker 
1466d1d35e2fSjeremylt   CeedInt qf_length;
1467d1d35e2fSjeremylt   ierr = CeedVectorGetLength(assembled_qf, &qf_length); CeedChk(ierr);
1468e2f04181SAndrew T. Barker 
1469e2f04181SAndrew T. Barker   CeedOperatorField *input_fields;
1470e2f04181SAndrew T. Barker   CeedOperatorField *output_fields;
1471e2f04181SAndrew T. Barker   ierr = CeedOperatorGetFields(op, &input_fields, &output_fields); CeedChk(ierr);
1472e2f04181SAndrew T. Barker 
1473e2f04181SAndrew T. Barker   // Determine active input basis
1474d1d35e2fSjeremylt   CeedQFunctionField *qf_fields;
1475d1d35e2fSjeremylt   ierr = CeedQFunctionGetFields(qf, &qf_fields, NULL); CeedChk(ierr);
1476d1d35e2fSjeremylt   CeedInt num_eval_mode_in = 0, dim = 1;
1477d1d35e2fSjeremylt   CeedEvalMode *eval_mode_in = NULL;
1478d1d35e2fSjeremylt   CeedBasis basis_in = NULL;
1479d1d35e2fSjeremylt   CeedElemRestriction rstr_in = NULL;
1480d1d35e2fSjeremylt   for (CeedInt i=0; i<num_input_fields; i++) {
1481e2f04181SAndrew T. Barker     CeedVector vec;
1482e2f04181SAndrew T. Barker     ierr = CeedOperatorFieldGetVector(input_fields[i], &vec); CeedChk(ierr);
1483e2f04181SAndrew T. Barker     if (vec == CEED_VECTOR_ACTIVE) {
1484d1d35e2fSjeremylt       ierr = CeedOperatorFieldGetBasis(input_fields[i], &basis_in);
1485e2f04181SAndrew T. Barker       CeedChk(ierr);
1486d1d35e2fSjeremylt       ierr = CeedBasisGetDimension(basis_in, &dim); CeedChk(ierr);
1487d1d35e2fSjeremylt       ierr = CeedOperatorFieldGetElemRestriction(input_fields[i], &rstr_in);
1488e2f04181SAndrew T. Barker       CeedChk(ierr);
1489d1d35e2fSjeremylt       CeedEvalMode eval_mode;
1490d1d35e2fSjeremylt       ierr = CeedQFunctionFieldGetEvalMode(qf_fields[i], &eval_mode);
1491e2f04181SAndrew T. Barker       CeedChk(ierr);
1492d1d35e2fSjeremylt       switch (eval_mode) {
1493e2f04181SAndrew T. Barker       case CEED_EVAL_NONE:
1494e2f04181SAndrew T. Barker       case CEED_EVAL_INTERP:
1495d1d35e2fSjeremylt         ierr = CeedRealloc(num_eval_mode_in + 1, &eval_mode_in); CeedChk(ierr);
1496d1d35e2fSjeremylt         eval_mode_in[num_eval_mode_in] = eval_mode;
1497d1d35e2fSjeremylt         num_eval_mode_in += 1;
1498e2f04181SAndrew T. Barker         break;
1499e2f04181SAndrew T. Barker       case CEED_EVAL_GRAD:
1500d1d35e2fSjeremylt         ierr = CeedRealloc(num_eval_mode_in + dim, &eval_mode_in); CeedChk(ierr);
1501e2f04181SAndrew T. Barker         for (CeedInt d=0; d<dim; d++) {
1502d1d35e2fSjeremylt           eval_mode_in[num_eval_mode_in+d] = eval_mode;
1503e2f04181SAndrew T. Barker         }
1504d1d35e2fSjeremylt         num_eval_mode_in += dim;
1505e2f04181SAndrew T. Barker         break;
1506e2f04181SAndrew T. Barker       case CEED_EVAL_WEIGHT:
1507e2f04181SAndrew T. Barker       case CEED_EVAL_DIV:
1508e2f04181SAndrew T. Barker       case CEED_EVAL_CURL:
1509e2f04181SAndrew T. Barker         break; // Caught by QF Assembly
1510e2f04181SAndrew T. Barker       }
1511e2f04181SAndrew T. Barker     }
1512e2f04181SAndrew T. Barker   }
1513e2f04181SAndrew T. Barker 
1514e2f04181SAndrew T. Barker   // Determine active output basis
1515d1d35e2fSjeremylt   ierr = CeedQFunctionGetFields(qf, NULL, &qf_fields); CeedChk(ierr);
1516d1d35e2fSjeremylt   CeedInt num_eval_mode_out = 0;
1517d1d35e2fSjeremylt   CeedEvalMode *eval_mode_out = NULL;
1518d1d35e2fSjeremylt   CeedBasis basis_out = NULL;
1519d1d35e2fSjeremylt   CeedElemRestriction rstr_out = NULL;
1520d1d35e2fSjeremylt   for (CeedInt i=0; i<num_output_fields; i++) {
1521e2f04181SAndrew T. Barker     CeedVector vec;
1522e2f04181SAndrew T. Barker     ierr = CeedOperatorFieldGetVector(output_fields[i], &vec); CeedChk(ierr);
1523e2f04181SAndrew T. Barker     if (vec == CEED_VECTOR_ACTIVE) {
1524d1d35e2fSjeremylt       ierr = CeedOperatorFieldGetBasis(output_fields[i], &basis_out);
1525e2f04181SAndrew T. Barker       CeedChk(ierr);
1526d1d35e2fSjeremylt       ierr = CeedOperatorFieldGetElemRestriction(output_fields[i], &rstr_out);
1527e2f04181SAndrew T. Barker       CeedChk(ierr);
1528d1d35e2fSjeremylt       CeedEvalMode eval_mode;
1529d1d35e2fSjeremylt       ierr = CeedQFunctionFieldGetEvalMode(qf_fields[i], &eval_mode);
1530e2f04181SAndrew T. Barker       CeedChk(ierr);
1531d1d35e2fSjeremylt       switch (eval_mode) {
1532e2f04181SAndrew T. Barker       case CEED_EVAL_NONE:
1533e2f04181SAndrew T. Barker       case CEED_EVAL_INTERP:
1534d1d35e2fSjeremylt         ierr = CeedRealloc(num_eval_mode_out + 1, &eval_mode_out); CeedChk(ierr);
1535d1d35e2fSjeremylt         eval_mode_out[num_eval_mode_out] = eval_mode;
1536d1d35e2fSjeremylt         num_eval_mode_out += 1;
1537e2f04181SAndrew T. Barker         break;
1538e2f04181SAndrew T. Barker       case CEED_EVAL_GRAD:
1539d1d35e2fSjeremylt         ierr = CeedRealloc(num_eval_mode_out + dim, &eval_mode_out); CeedChk(ierr);
1540e2f04181SAndrew T. Barker         for (CeedInt d=0; d<dim; d++) {
1541d1d35e2fSjeremylt           eval_mode_out[num_eval_mode_out+d] = eval_mode;
1542e2f04181SAndrew T. Barker         }
1543d1d35e2fSjeremylt         num_eval_mode_out += dim;
1544e2f04181SAndrew T. Barker         break;
1545e2f04181SAndrew T. Barker       case CEED_EVAL_WEIGHT:
1546e2f04181SAndrew T. Barker       case CEED_EVAL_DIV:
1547e2f04181SAndrew T. Barker       case CEED_EVAL_CURL:
1548e2f04181SAndrew T. Barker         break; // Caught by QF Assembly
1549e2f04181SAndrew T. Barker       }
1550e2f04181SAndrew T. Barker     }
1551e2f04181SAndrew T. Barker   }
1552e2f04181SAndrew T. Barker 
1553d1d35e2fSjeremylt   CeedInt num_elem, elem_size, num_qpts, num_comp;
1554d1d35e2fSjeremylt   ierr = CeedElemRestrictionGetNumElements(rstr_in, &num_elem); CeedChk(ierr);
1555d1d35e2fSjeremylt   ierr = CeedElemRestrictionGetElementSize(rstr_in, &elem_size); CeedChk(ierr);
1556d1d35e2fSjeremylt   ierr = CeedElemRestrictionGetNumComponents(rstr_in, &num_comp); CeedChk(ierr);
1557d1d35e2fSjeremylt   ierr = CeedBasisGetNumQuadraturePoints(basis_in, &num_qpts); CeedChk(ierr);
1558e2f04181SAndrew T. Barker 
1559d1d35e2fSjeremylt   CeedInt local_num_entries = elem_size*num_comp * elem_size*num_comp * num_elem;
1560e2f04181SAndrew T. Barker 
1561e2f04181SAndrew T. Barker   // loop over elements and put in data structure
1562d1d35e2fSjeremylt   const CeedScalar *interp_in, *grad_in;
1563d1d35e2fSjeremylt   ierr = CeedBasisGetInterp(basis_in, &interp_in); CeedChk(ierr);
1564d1d35e2fSjeremylt   ierr = CeedBasisGetGrad(basis_in, &grad_in); CeedChk(ierr);
1565e2f04181SAndrew T. Barker 
1566d1d35e2fSjeremylt   const CeedScalar *assembled_qf_array;
1567d1d35e2fSjeremylt   ierr = CeedVectorGetArrayRead(assembled_qf, CEED_MEM_HOST, &assembled_qf_array);
1568e2f04181SAndrew T. Barker   CeedChk(ierr);
1569e2f04181SAndrew T. Barker 
1570e2f04181SAndrew T. Barker   CeedInt layout_qf[3];
1571e2f04181SAndrew T. Barker   ierr = CeedElemRestrictionGetELayout(rstr_q, &layout_qf); CeedChk(ierr);
1572e2f04181SAndrew T. Barker   ierr = CeedElemRestrictionDestroy(&rstr_q); CeedChk(ierr);
1573e2f04181SAndrew T. Barker 
1574d1d35e2fSjeremylt   // we store B_mat_in, B_mat_out, BTD, elem_mat in row-major order
1575d1d35e2fSjeremylt   CeedScalar B_mat_in[(num_qpts * num_eval_mode_in) * elem_size];
1576d1d35e2fSjeremylt   CeedScalar B_mat_out[(num_qpts * num_eval_mode_out) * elem_size];
1577d1d35e2fSjeremylt   CeedScalar D_mat[num_eval_mode_out * num_eval_mode_in *
1578d1d35e2fSjeremylt                                      num_qpts]; // logically 3-tensor
1579d1d35e2fSjeremylt   CeedScalar BTD[elem_size * num_qpts*num_eval_mode_in];
1580d1d35e2fSjeremylt   CeedScalar elem_mat[elem_size * elem_size];
1581e2f04181SAndrew T. Barker   int count = 0;
1582e2f04181SAndrew T. Barker   CeedScalar *vals;
1583e2f04181SAndrew T. Barker   ierr = CeedVectorGetArray(values, CEED_MEM_HOST, &vals); CeedChk(ierr);
1584d1d35e2fSjeremylt   for (int e = 0; e < num_elem; ++e) {
1585d1d35e2fSjeremylt     for (int comp_in = 0; comp_in < num_comp; ++comp_in) {
1586d1d35e2fSjeremylt       for (int comp_out = 0; comp_out < num_comp; ++comp_out) {
1587d1d35e2fSjeremylt         for (int ell = 0; ell < (num_qpts * num_eval_mode_in) * elem_size; ++ell) {
1588d1d35e2fSjeremylt           B_mat_in[ell] = 0.0;
1589e2f04181SAndrew T. Barker         }
1590d1d35e2fSjeremylt         for (int ell = 0; ell < (num_qpts * num_eval_mode_out) * elem_size; ++ell) {
1591d1d35e2fSjeremylt           B_mat_out[ell] = 0.0;
1592e2f04181SAndrew T. Barker         }
1593e2f04181SAndrew T. Barker         // Store block-diagonal D matrix as collection of small dense blocks
1594d1d35e2fSjeremylt         for (int ell = 0; ell < num_eval_mode_in*num_eval_mode_out*num_qpts; ++ell) {
1595d1d35e2fSjeremylt           D_mat[ell] = 0.0;
1596e2f04181SAndrew T. Barker         }
1597e2f04181SAndrew T. Barker         // form element matrix itself (for each block component)
1598d1d35e2fSjeremylt         for (int ell = 0; ell < elem_size*elem_size; ++ell) {
1599e2f04181SAndrew T. Barker           elem_mat[ell] = 0.0;
1600e2f04181SAndrew T. Barker         }
1601d1d35e2fSjeremylt         for (int q = 0; q < num_qpts; ++q) {
1602d1d35e2fSjeremylt           for (int n = 0; n < elem_size; ++n) {
1603d1d35e2fSjeremylt             CeedInt d_in = -1;
1604d1d35e2fSjeremylt             for (int e_in = 0; e_in < num_eval_mode_in; ++e_in) {
1605d1d35e2fSjeremylt               const int qq = num_eval_mode_in*q;
1606d1d35e2fSjeremylt               if (eval_mode_in[e_in] == CEED_EVAL_INTERP) {
1607d1d35e2fSjeremylt                 B_mat_in[(qq+e_in)*elem_size + n] += interp_in[q * elem_size + n];
1608d1d35e2fSjeremylt               } else if (eval_mode_in[e_in] == CEED_EVAL_GRAD) {
1609d1d35e2fSjeremylt                 d_in += 1;
1610d1d35e2fSjeremylt                 B_mat_in[(qq+e_in)*elem_size + n] +=
1611d1d35e2fSjeremylt                   grad_in[(d_in*num_qpts+q) * elem_size + n];
1612e2f04181SAndrew T. Barker               } else {
1613e2f04181SAndrew T. Barker                 // LCOV_EXCL_START
1614e2f04181SAndrew T. Barker                 return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Not implemented!");
1615e2f04181SAndrew T. Barker                 // LCOV_EXCL_STOP
1616e2f04181SAndrew T. Barker               }
1617e2f04181SAndrew T. Barker             }
1618d1d35e2fSjeremylt             CeedInt d_out = -1;
1619d1d35e2fSjeremylt             for (int e_out = 0; e_out < num_eval_mode_out; ++e_out) {
1620d1d35e2fSjeremylt               const int qq = num_eval_mode_out*q;
1621d1d35e2fSjeremylt               if (eval_mode_out[e_out] == CEED_EVAL_INTERP) {
1622d1d35e2fSjeremylt                 B_mat_out[(qq+e_out)*elem_size + n] += interp_in[q * elem_size + n];
1623d1d35e2fSjeremylt               } else if (eval_mode_out[e_out] == CEED_EVAL_GRAD) {
1624d1d35e2fSjeremylt                 d_out += 1;
1625d1d35e2fSjeremylt                 B_mat_out[(qq+e_out)*elem_size + n] +=
1626d1d35e2fSjeremylt                   grad_in[(d_out*num_qpts+q) * elem_size + n];
1627e2f04181SAndrew T. Barker               } else {
1628e2f04181SAndrew T. Barker                 // LCOV_EXCL_START
1629e2f04181SAndrew T. Barker                 return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Not implemented!");
1630e2f04181SAndrew T. Barker                 // LCOV_EXCL_STOP
1631e2f04181SAndrew T. Barker               }
1632e2f04181SAndrew T. Barker             }
1633e2f04181SAndrew T. Barker           }
1634d1d35e2fSjeremylt           for (int ei = 0; ei < num_eval_mode_out; ++ei) {
1635d1d35e2fSjeremylt             for (int ej = 0; ej < num_eval_mode_in; ++ej) {
1636d1d35e2fSjeremylt               const int eval_mode_index = ((ei*num_comp+comp_in)*num_eval_mode_in+ej)*num_comp
1637d1d35e2fSjeremylt                                           +comp_out;
1638d1d35e2fSjeremylt               const int index = q*layout_qf[0] + eval_mode_index*layout_qf[1] +
1639d1d35e2fSjeremylt                                 e*layout_qf[2];
1640d1d35e2fSjeremylt               D_mat[(ei*num_eval_mode_in+ej)*num_qpts + q] += assembled_qf_array[index];
1641e2f04181SAndrew T. Barker             }
1642e2f04181SAndrew T. Barker           }
1643e2f04181SAndrew T. Barker         }
1644e2f04181SAndrew T. Barker         // Compute B^T*D
1645d1d35e2fSjeremylt         for (int ell = 0; ell < elem_size*num_qpts*num_eval_mode_in; ++ell) {
1646e2f04181SAndrew T. Barker           BTD[ell] = 0.0;
1647e2f04181SAndrew T. Barker         }
1648d1d35e2fSjeremylt         for (int j = 0; j<elem_size; ++j) {
1649d1d35e2fSjeremylt           for (int q = 0; q<num_qpts; ++q) {
1650d1d35e2fSjeremylt             int qq = num_eval_mode_out*q;
1651d1d35e2fSjeremylt             for (int ei = 0; ei < num_eval_mode_in; ++ei) {
1652d1d35e2fSjeremylt               for (int ej = 0; ej < num_eval_mode_out; ++ej) {
1653d1d35e2fSjeremylt                 BTD[j*(num_qpts*num_eval_mode_in) + (qq+ei)] +=
1654d1d35e2fSjeremylt                   B_mat_out[(qq+ej)*elem_size + j] * D_mat[(ei*num_eval_mode_in+ej)*num_qpts + q];
1655e2f04181SAndrew T. Barker               }
1656e2f04181SAndrew T. Barker             }
1657e2f04181SAndrew T. Barker           }
1658e2f04181SAndrew T. Barker         }
1659e2f04181SAndrew T. Barker 
1660d1d35e2fSjeremylt         ierr = CeedMatrixMultiply(ceed, BTD, B_mat_in, elem_mat, elem_size,
1661d1d35e2fSjeremylt                                   elem_size, num_qpts*num_eval_mode_in); CeedChk(ierr);
1662e2f04181SAndrew T. Barker 
1663e2f04181SAndrew T. Barker         // put element matrix in coordinate data structure
1664d1d35e2fSjeremylt         for (int i = 0; i < elem_size; ++i) {
1665d1d35e2fSjeremylt           for (int j = 0; j < elem_size; ++j) {
1666d1d35e2fSjeremylt             vals[offset + count] = elem_mat[i*elem_size + j];
1667e2f04181SAndrew T. Barker             count++;
1668e2f04181SAndrew T. Barker           }
1669e2f04181SAndrew T. Barker         }
1670e2f04181SAndrew T. Barker       }
1671e2f04181SAndrew T. Barker     }
1672e2f04181SAndrew T. Barker   }
1673d1d35e2fSjeremylt   if (count != local_num_entries)
1674e2f04181SAndrew T. Barker     // LCOV_EXCL_START
1675e2f04181SAndrew T. Barker     return CeedError(ceed, CEED_ERROR_MAJOR, "Error computing entries");
1676e2f04181SAndrew T. Barker   // LCOV_EXCL_STOP
1677e2f04181SAndrew T. Barker   ierr = CeedVectorRestoreArray(values, &vals); CeedChk(ierr);
1678e2f04181SAndrew T. Barker 
1679d1d35e2fSjeremylt   ierr = CeedVectorRestoreArrayRead(assembled_qf, &assembled_qf_array);
1680e2f04181SAndrew T. Barker   CeedChk(ierr);
1681d1d35e2fSjeremylt   ierr = CeedVectorDestroy(&assembled_qf); CeedChk(ierr);
1682d1d35e2fSjeremylt   ierr = CeedFree(&eval_mode_in); CeedChk(ierr);
1683d1d35e2fSjeremylt   ierr = CeedFree(&eval_mode_out); CeedChk(ierr);
1684e2f04181SAndrew T. Barker 
1685e2f04181SAndrew T. Barker   return CEED_ERROR_SUCCESS;
1686e2f04181SAndrew T. Barker }
1687e2f04181SAndrew T. Barker 
1688e2f04181SAndrew T. Barker /**
1689e2f04181SAndrew T. Barker    @ref Utility
1690e2f04181SAndrew T. Barker **/
1691d1d35e2fSjeremylt int CeedSingleOperatorAssemblyCountEntries(CeedOperator op,
1692d1d35e2fSjeremylt     CeedInt *num_entries) {
1693e2f04181SAndrew T. Barker   int ierr;
1694e2f04181SAndrew T. Barker   CeedElemRestriction rstr;
1695d1d35e2fSjeremylt   CeedInt num_elem, elem_size, num_comp;
1696e2f04181SAndrew T. Barker 
1697e2f04181SAndrew T. Barker   if (op->composite)
1698e2f04181SAndrew T. Barker     // LCOV_EXCL_START
1699e2f04181SAndrew T. Barker     return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED,
1700e2f04181SAndrew T. Barker                      "Composite operator not supported");
1701e2f04181SAndrew T. Barker   // LCOV_EXCL_STOP
1702e2f04181SAndrew T. Barker   ierr = CeedOperatorGetActiveElemRestriction(op, &rstr); CeedChk(ierr);
1703d1d35e2fSjeremylt   ierr = CeedElemRestrictionGetNumElements(rstr, &num_elem); CeedChk(ierr);
1704d1d35e2fSjeremylt   ierr = CeedElemRestrictionGetElementSize(rstr, &elem_size); CeedChk(ierr);
1705d1d35e2fSjeremylt   ierr = CeedElemRestrictionGetNumComponents(rstr, &num_comp); CeedChk(ierr);
1706d1d35e2fSjeremylt   *num_entries = elem_size*num_comp * elem_size*num_comp * num_elem;
1707e2f04181SAndrew T. Barker 
1708e2f04181SAndrew T. Barker   return CEED_ERROR_SUCCESS;
1709e2f04181SAndrew T. Barker }
1710e2f04181SAndrew T. Barker 
1711e2f04181SAndrew T. Barker /**
1712e2f04181SAndrew T. Barker    @brief Fully assemble the nonzero pattern of a linear operator.
1713e2f04181SAndrew T. Barker 
1714e2f04181SAndrew T. Barker    Expected to be used in conjunction with CeedOperatorLinearAssemble()
1715e2f04181SAndrew T. Barker 
1716d1d35e2fSjeremylt    The assembly routines use coordinate format, with num_entries tuples of the
1717e2f04181SAndrew T. Barker    form (i, j, value) which indicate that value should be added to the matrix
1718e2f04181SAndrew T. Barker    in entry (i, j). Note that the (i, j) pairs are not unique and may repeat.
1719e2f04181SAndrew T. Barker    This function returns the number of entries and their (i, j) locations,
1720e2f04181SAndrew T. Barker    while CeedOperatorLinearAssemble() provides the values in the same
1721e2f04181SAndrew T. Barker    ordering.
1722e2f04181SAndrew T. Barker 
1723e2f04181SAndrew T. Barker    This will generally be slow unless your operator is low-order.
1724e2f04181SAndrew T. Barker 
1725e2f04181SAndrew T. Barker    @param[in]  op           CeedOperator to assemble
1726d1d35e2fSjeremylt    @param[out] num_entries  Number of entries in coordinate nonzero pattern.
1727e2f04181SAndrew T. Barker    @param[out] rows         Row number for each entry.
1728e2f04181SAndrew T. Barker    @param[out] cols         Column number for each entry.
1729e2f04181SAndrew T. Barker 
1730e2f04181SAndrew T. Barker    @ref User
1731e2f04181SAndrew T. Barker **/
1732e2f04181SAndrew T. Barker int CeedOperatorLinearAssembleSymbolic(CeedOperator op,
1733d1d35e2fSjeremylt                                        CeedInt *num_entries, CeedInt **rows, CeedInt **cols) {
1734e2f04181SAndrew T. Barker   int ierr;
1735d1d35e2fSjeremylt   CeedInt num_suboperators, single_entries;
1736d1d35e2fSjeremylt   CeedOperator *sub_operators;
1737d1d35e2fSjeremylt   bool is_composite;
1738e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
1739e2f04181SAndrew T. Barker 
1740e2f04181SAndrew T. Barker   // Use backend version, if available
1741e2f04181SAndrew T. Barker   if (op->LinearAssembleSymbolic) {
1742d1d35e2fSjeremylt     return op->LinearAssembleSymbolic(op, num_entries, rows, cols);
1743e2f04181SAndrew T. Barker   } else {
1744e2f04181SAndrew T. Barker     // Check for valid fallback resource
1745d1d35e2fSjeremylt     const char *resource, *fallback_resource;
1746e2f04181SAndrew T. Barker     ierr = CeedGetResource(op->ceed, &resource); CeedChk(ierr);
1747d1d35e2fSjeremylt     ierr = CeedGetOperatorFallbackResource(op->ceed, &fallback_resource);
1748d1d35e2fSjeremylt     if (strcmp(fallback_resource, "") && strcmp(resource, fallback_resource)) {
1749e2f04181SAndrew T. Barker       // Fallback to reference Ceed
1750d1d35e2fSjeremylt       if (!op->op_fallback) {
1751e2f04181SAndrew T. Barker         ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
1752e2f04181SAndrew T. Barker       }
1753e2f04181SAndrew T. Barker       // Assemble
1754d1d35e2fSjeremylt       return CeedOperatorLinearAssembleSymbolic(op->op_fallback, num_entries, rows,
1755d1d35e2fSjeremylt              cols);
1756e2f04181SAndrew T. Barker     }
1757e2f04181SAndrew T. Barker   }
1758e2f04181SAndrew T. Barker 
1759e2f04181SAndrew T. Barker   // if neither backend nor fallback resource provides
1760e2f04181SAndrew T. Barker   // LinearAssembleSymbolic, continue with interface-level implementation
1761e2f04181SAndrew T. Barker 
1762e2f04181SAndrew T. Barker   // count entries and allocate rows, cols arrays
1763d1d35e2fSjeremylt   ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr);
1764d1d35e2fSjeremylt   *num_entries = 0;
1765d1d35e2fSjeremylt   if (is_composite) {
1766d1d35e2fSjeremylt     ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr);
1767d1d35e2fSjeremylt     ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr);
1768d1d35e2fSjeremylt     for (int k = 0; k < num_suboperators; ++k) {
1769d1d35e2fSjeremylt       ierr = CeedSingleOperatorAssemblyCountEntries(sub_operators[k],
1770e2f04181SAndrew T. Barker              &single_entries); CeedChk(ierr);
1771d1d35e2fSjeremylt       *num_entries += single_entries;
1772e2f04181SAndrew T. Barker     }
1773e2f04181SAndrew T. Barker   } else {
1774e2f04181SAndrew T. Barker     ierr = CeedSingleOperatorAssemblyCountEntries(op,
1775e2f04181SAndrew T. Barker            &single_entries); CeedChk(ierr);
1776d1d35e2fSjeremylt     *num_entries += single_entries;
1777e2f04181SAndrew T. Barker   }
1778d1d35e2fSjeremylt   ierr = CeedCalloc(*num_entries, rows); CeedChk(ierr);
1779d1d35e2fSjeremylt   ierr = CeedCalloc(*num_entries, cols); CeedChk(ierr);
1780e2f04181SAndrew T. Barker 
1781e2f04181SAndrew T. Barker   // assemble nonzero locations
1782e2f04181SAndrew T. Barker   CeedInt offset = 0;
1783d1d35e2fSjeremylt   if (is_composite) {
1784d1d35e2fSjeremylt     ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr);
1785d1d35e2fSjeremylt     ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr);
1786d1d35e2fSjeremylt     for (int k = 0; k < num_suboperators; ++k) {
1787d1d35e2fSjeremylt       ierr = CeedSingleOperatorAssembleSymbolic(sub_operators[k], offset, *rows,
1788e2f04181SAndrew T. Barker              *cols); CeedChk(ierr);
1789d1d35e2fSjeremylt       ierr = CeedSingleOperatorAssemblyCountEntries(sub_operators[k],
1790d1d35e2fSjeremylt              &single_entries);
1791e2f04181SAndrew T. Barker       CeedChk(ierr);
1792e2f04181SAndrew T. Barker       offset += single_entries;
1793e2f04181SAndrew T. Barker     }
1794e2f04181SAndrew T. Barker   } else {
1795e2f04181SAndrew T. Barker     ierr = CeedSingleOperatorAssembleSymbolic(op, offset, *rows, *cols);
1796e2f04181SAndrew T. Barker     CeedChk(ierr);
1797e2f04181SAndrew T. Barker   }
1798e2f04181SAndrew T. Barker 
1799e2f04181SAndrew T. Barker   return CEED_ERROR_SUCCESS;
1800e2f04181SAndrew T. Barker }
1801e2f04181SAndrew T. Barker 
1802e2f04181SAndrew T. Barker /**
1803e2f04181SAndrew T. Barker    @brief Fully assemble the nonzero entries of a linear operator.
1804e2f04181SAndrew T. Barker 
1805e2f04181SAndrew T. Barker    Expected to be used in conjunction with CeedOperatorLinearAssembleSymbolic()
1806e2f04181SAndrew T. Barker 
1807d1d35e2fSjeremylt    The assembly routines use coordinate format, with num_entries tuples of the
1808e2f04181SAndrew T. Barker    form (i, j, value) which indicate that value should be added to the matrix
1809e2f04181SAndrew T. Barker    in entry (i, j). Note that the (i, j) pairs are not unique and may repeat.
1810e2f04181SAndrew T. Barker    This function returns the values of the nonzero entries to be added, their
1811e2f04181SAndrew T. Barker    (i, j) locations are provided by CeedOperatorLinearAssembleSymbolic()
1812e2f04181SAndrew T. Barker 
1813e2f04181SAndrew T. Barker    This will generally be slow unless your operator is low-order.
1814e2f04181SAndrew T. Barker 
1815e2f04181SAndrew T. Barker    @param[in]  op      CeedOperator to assemble
1816e2f04181SAndrew T. Barker    @param[out] values  Values to assemble into matrix
1817e2f04181SAndrew T. Barker 
1818e2f04181SAndrew T. Barker    @ref User
1819e2f04181SAndrew T. Barker **/
1820e2f04181SAndrew T. Barker int CeedOperatorLinearAssemble(CeedOperator op, CeedVector values) {
1821e2f04181SAndrew T. Barker   int ierr;
1822d1d35e2fSjeremylt   CeedInt num_suboperators, single_entries;
1823d1d35e2fSjeremylt   CeedOperator *sub_operators;
1824e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
1825e2f04181SAndrew T. Barker 
1826e2f04181SAndrew T. Barker   // Use backend version, if available
1827e2f04181SAndrew T. Barker   if (op->LinearAssemble) {
1828e2f04181SAndrew T. Barker     return op->LinearAssemble(op, values);
1829e2f04181SAndrew T. Barker   } else {
1830e2f04181SAndrew T. Barker     // Check for valid fallback resource
1831d1d35e2fSjeremylt     const char *resource, *fallback_resource;
1832e2f04181SAndrew T. Barker     ierr = CeedGetResource(op->ceed, &resource); CeedChk(ierr);
1833d1d35e2fSjeremylt     ierr = CeedGetOperatorFallbackResource(op->ceed, &fallback_resource);
1834d1d35e2fSjeremylt     if (strcmp(fallback_resource, "") && strcmp(resource, fallback_resource)) {
1835e2f04181SAndrew T. Barker       // Fallback to reference Ceed
1836d1d35e2fSjeremylt       if (!op->op_fallback) {
1837e2f04181SAndrew T. Barker         ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
1838e2f04181SAndrew T. Barker       }
1839e2f04181SAndrew T. Barker       // Assemble
1840d1d35e2fSjeremylt       return CeedOperatorLinearAssemble(op->op_fallback, values);
1841e2f04181SAndrew T. Barker     }
1842e2f04181SAndrew T. Barker   }
1843e2f04181SAndrew T. Barker 
1844e2f04181SAndrew T. Barker   // if neither backend nor fallback resource provides
1845e2f04181SAndrew T. Barker   // LinearAssemble, continue with interface-level implementation
1846e2f04181SAndrew T. Barker 
1847d1d35e2fSjeremylt   bool is_composite;
1848d1d35e2fSjeremylt   ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr);
1849e2f04181SAndrew T. Barker 
1850e2f04181SAndrew T. Barker   CeedInt offset = 0;
1851d1d35e2fSjeremylt   if (is_composite) {
1852d1d35e2fSjeremylt     ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr);
1853d1d35e2fSjeremylt     ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr);
1854d1d35e2fSjeremylt     for (int k = 0; k < num_suboperators; ++k) {
1855d1d35e2fSjeremylt       ierr = CeedSingleOperatorAssemble(sub_operators[k], offset, values);
1856e2f04181SAndrew T. Barker       CeedChk(ierr);
1857d1d35e2fSjeremylt       ierr = CeedSingleOperatorAssemblyCountEntries(sub_operators[k],
1858d1d35e2fSjeremylt              &single_entries);
1859e2f04181SAndrew T. Barker       CeedChk(ierr);
1860e2f04181SAndrew T. Barker       offset += single_entries;
1861e2f04181SAndrew T. Barker     }
1862e2f04181SAndrew T. Barker   } else {
1863e2f04181SAndrew T. Barker     ierr = CeedSingleOperatorAssemble(op, offset, values); CeedChk(ierr);
1864e2f04181SAndrew T. Barker   }
1865e2f04181SAndrew T. Barker 
1866e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1867d965c7a7SJeremy L Thompson }
1868d965c7a7SJeremy L Thompson 
1869d965c7a7SJeremy L Thompson /**
1870d99fa3c5SJeremy L Thompson   @brief Create a multigrid coarse operator and level transfer operators
1871d99fa3c5SJeremy L Thompson            for a CeedOperator, creating the prolongation basis from the
1872d99fa3c5SJeremy L Thompson            fine and coarse grid interpolation
1873d99fa3c5SJeremy L Thompson 
1874d1d35e2fSjeremylt   @param[in] op_fine       Fine grid operator
1875d1d35e2fSjeremylt   @param[in] p_mult_fine   L-vector multiplicity in parallel gather/scatter
1876d1d35e2fSjeremylt   @param[in] rstr_coarse   Coarse grid restriction
1877d1d35e2fSjeremylt   @param[in] basis_coarse  Coarse grid active vector basis
1878d1d35e2fSjeremylt   @param[out] op_coarse    Coarse grid operator
1879d1d35e2fSjeremylt   @param[out] op_prolong   Coarse to fine operator
1880d1d35e2fSjeremylt   @param[out] op_restrict  Fine to coarse operator
1881d99fa3c5SJeremy L Thompson 
1882d99fa3c5SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1883d99fa3c5SJeremy L Thompson 
1884d99fa3c5SJeremy L Thompson   @ref User
1885d99fa3c5SJeremy L Thompson **/
1886d1d35e2fSjeremylt int CeedOperatorMultigridLevelCreate(CeedOperator op_fine,
1887d1d35e2fSjeremylt                                      CeedVector p_mult_fine,
1888d1d35e2fSjeremylt                                      CeedElemRestriction rstr_coarse, CeedBasis basis_coarse,
1889d1d35e2fSjeremylt                                      CeedOperator *op_coarse, CeedOperator *op_prolong,
1890d1d35e2fSjeremylt                                      CeedOperator *op_restrict) {
1891d99fa3c5SJeremy L Thompson   int ierr;
1892d99fa3c5SJeremy L Thompson   Ceed ceed;
1893d1d35e2fSjeremylt   ierr = CeedOperatorGetCeed(op_fine, &ceed); CeedChk(ierr);
1894d99fa3c5SJeremy L Thompson 
1895d99fa3c5SJeremy L Thompson   // Check for compatible quadrature spaces
1896d1d35e2fSjeremylt   CeedBasis basis_fine;
1897d1d35e2fSjeremylt   ierr = CeedOperatorGetActiveBasis(op_fine, &basis_fine); CeedChk(ierr);
1898d1d35e2fSjeremylt   CeedInt Q_f, Q_c;
1899d1d35e2fSjeremylt   ierr = CeedBasisGetNumQuadraturePoints(basis_fine, &Q_f); CeedChk(ierr);
1900d1d35e2fSjeremylt   ierr = CeedBasisGetNumQuadraturePoints(basis_coarse, &Q_c); CeedChk(ierr);
1901d1d35e2fSjeremylt   if (Q_f != Q_c)
1902d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
1903e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_DIMENSION,
1904e15f9bd0SJeremy L Thompson                      "Bases must have compatible quadrature spaces");
1905d99fa3c5SJeremy L Thompson   // LCOV_EXCL_STOP
1906d99fa3c5SJeremy L Thompson 
1907d99fa3c5SJeremy L Thompson   // Coarse to fine basis
1908d1d35e2fSjeremylt   CeedInt P_f, P_c, Q = Q_f;
1909d1d35e2fSjeremylt   bool is_tensor_f, is_tensor_c;
1910d1d35e2fSjeremylt   ierr = CeedBasisIsTensor(basis_fine, &is_tensor_f); CeedChk(ierr);
1911d1d35e2fSjeremylt   ierr = CeedBasisIsTensor(basis_coarse, &is_tensor_c); CeedChk(ierr);
1912d1d35e2fSjeremylt   CeedScalar *interp_c, *interp_f, *interp_c_to_f, *tau;
1913d1d35e2fSjeremylt   if (is_tensor_f && is_tensor_c) {
1914d1d35e2fSjeremylt     ierr = CeedBasisGetNumNodes1D(basis_fine, &P_f); CeedChk(ierr);
1915d1d35e2fSjeremylt     ierr = CeedBasisGetNumNodes1D(basis_coarse, &P_c); CeedChk(ierr);
1916d1d35e2fSjeremylt     ierr = CeedBasisGetNumQuadraturePoints1D(basis_coarse, &Q); CeedChk(ierr);
1917d1d35e2fSjeremylt   } else if (!is_tensor_f && !is_tensor_c) {
1918d1d35e2fSjeremylt     ierr = CeedBasisGetNumNodes(basis_fine, &P_f); CeedChk(ierr);
1919d1d35e2fSjeremylt     ierr = CeedBasisGetNumNodes(basis_coarse, &P_c); CeedChk(ierr);
1920d99fa3c5SJeremy L Thompson   } else {
1921d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
1922e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_MINOR,
1923e15f9bd0SJeremy L Thompson                      "Bases must both be tensor or non-tensor");
1924d99fa3c5SJeremy L Thompson     // LCOV_EXCL_STOP
1925d99fa3c5SJeremy L Thompson   }
1926d99fa3c5SJeremy L Thompson 
1927d1d35e2fSjeremylt   ierr = CeedMalloc(Q*P_f, &interp_f); CeedChk(ierr);
1928d1d35e2fSjeremylt   ierr = CeedMalloc(Q*P_c, &interp_c); CeedChk(ierr);
1929d1d35e2fSjeremylt   ierr = CeedCalloc(P_c*P_f, &interp_c_to_f); CeedChk(ierr);
1930d99fa3c5SJeremy L Thompson   ierr = CeedMalloc(Q, &tau); CeedChk(ierr);
1931d1d35e2fSjeremylt   if (is_tensor_f) {
1932d1d35e2fSjeremylt     memcpy(interp_f, basis_fine->interp_1d, Q*P_f*sizeof basis_fine->interp_1d[0]);
1933d1d35e2fSjeremylt     memcpy(interp_c, basis_coarse->interp_1d,
1934d1d35e2fSjeremylt            Q*P_c*sizeof basis_coarse->interp_1d[0]);
1935d99fa3c5SJeremy L Thompson   } else {
1936d1d35e2fSjeremylt     memcpy(interp_f, basis_fine->interp, Q*P_f*sizeof basis_fine->interp[0]);
1937d1d35e2fSjeremylt     memcpy(interp_c, basis_coarse->interp, Q*P_c*sizeof basis_coarse->interp[0]);
1938d99fa3c5SJeremy L Thompson   }
1939d99fa3c5SJeremy L Thompson 
1940d1d35e2fSjeremylt   // -- QR Factorization, interp_f = Q R
1941d1d35e2fSjeremylt   ierr = CeedQRFactorization(ceed, interp_f, tau, Q, P_f); CeedChk(ierr);
1942d99fa3c5SJeremy L Thompson 
1943d1d35e2fSjeremylt   // -- Apply Qtranspose, interp_c = Qtranspose interp_c
1944d1d35e2fSjeremylt   ierr = CeedHouseholderApplyQ(interp_c, interp_f, tau, CEED_TRANSPOSE,
1945d1d35e2fSjeremylt                                Q, P_c, P_f, P_c, 1); CeedChk(ierr);
1946d99fa3c5SJeremy L Thompson 
1947d1d35e2fSjeremylt   // -- Apply Rinv, interp_c_to_f = Rinv interp_c
1948d1d35e2fSjeremylt   for (CeedInt j=0; j<P_c; j++) { // Column j
1949d1d35e2fSjeremylt     interp_c_to_f[j+P_c*(P_f-1)] = interp_c[j+P_c*(P_f-1)]/interp_f[P_f*P_f-1];
1950d1d35e2fSjeremylt     for (CeedInt i=P_f-2; i>=0; i--) { // Row i
1951d1d35e2fSjeremylt       interp_c_to_f[j+P_c*i] = interp_c[j+P_c*i];
1952d1d35e2fSjeremylt       for (CeedInt k=i+1; k<P_f; k++)
1953d1d35e2fSjeremylt         interp_c_to_f[j+P_c*i] -= interp_f[k+P_f*i]*interp_c_to_f[j+P_c*k];
1954d1d35e2fSjeremylt       interp_c_to_f[j+P_c*i] /= interp_f[i+P_f*i];
1955d99fa3c5SJeremy L Thompson     }
1956d99fa3c5SJeremy L Thompson   }
1957d99fa3c5SJeremy L Thompson   ierr = CeedFree(&tau); CeedChk(ierr);
1958d1d35e2fSjeremylt   ierr = CeedFree(&interp_c); CeedChk(ierr);
1959d1d35e2fSjeremylt   ierr = CeedFree(&interp_f); CeedChk(ierr);
1960d99fa3c5SJeremy L Thompson 
1961d1d35e2fSjeremylt   // Complete with interp_c_to_f versions of code
1962d1d35e2fSjeremylt   if (is_tensor_f) {
1963d1d35e2fSjeremylt     ierr = CeedOperatorMultigridLevelCreateTensorH1(op_fine, p_mult_fine,
1964d1d35e2fSjeremylt            rstr_coarse, basis_coarse, interp_c_to_f, op_coarse, op_prolong, op_restrict);
1965d99fa3c5SJeremy L Thompson     CeedChk(ierr);
1966d99fa3c5SJeremy L Thompson   } else {
1967d1d35e2fSjeremylt     ierr = CeedOperatorMultigridLevelCreateH1(op_fine, p_mult_fine,
1968d1d35e2fSjeremylt            rstr_coarse, basis_coarse, interp_c_to_f, op_coarse, op_prolong, op_restrict);
1969d99fa3c5SJeremy L Thompson     CeedChk(ierr);
1970d99fa3c5SJeremy L Thompson   }
1971d99fa3c5SJeremy L Thompson 
1972d99fa3c5SJeremy L Thompson   // Cleanup
1973d1d35e2fSjeremylt   ierr = CeedFree(&interp_c_to_f); CeedChk(ierr);
1974e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1975d99fa3c5SJeremy L Thompson }
1976d99fa3c5SJeremy L Thompson 
1977d99fa3c5SJeremy L Thompson /**
1978d99fa3c5SJeremy L Thompson   @brief Create a multigrid coarse operator and level transfer operators
1979d99fa3c5SJeremy L Thompson            for a CeedOperator with a tensor basis for the active basis
1980d99fa3c5SJeremy L Thompson 
1981d1d35e2fSjeremylt   @param[in] op_fine        Fine grid operator
1982d1d35e2fSjeremylt   @param[in] p_mult_fine    L-vector multiplicity in parallel gather/scatter
1983d1d35e2fSjeremylt   @param[in] rstr_coarse    Coarse grid restriction
1984d1d35e2fSjeremylt   @param[in] basis_coarse   Coarse grid active vector basis
1985d1d35e2fSjeremylt   @param[in] interp_c_to_f  Matrix for coarse to fine interpolation
1986d1d35e2fSjeremylt   @param[out] op_coarse     Coarse grid operator
1987d1d35e2fSjeremylt   @param[out] op_prolong    Coarse to fine operator
1988d1d35e2fSjeremylt   @param[out] op_restrict   Fine to coarse operator
1989d99fa3c5SJeremy L Thompson 
1990d99fa3c5SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1991d99fa3c5SJeremy L Thompson 
1992d99fa3c5SJeremy L Thompson   @ref User
1993d99fa3c5SJeremy L Thompson **/
1994d1d35e2fSjeremylt int CeedOperatorMultigridLevelCreateTensorH1(CeedOperator op_fine,
1995d1d35e2fSjeremylt     CeedVector p_mult_fine, CeedElemRestriction rstr_coarse, CeedBasis basis_coarse,
1996d1d35e2fSjeremylt     const CeedScalar *interp_c_to_f, CeedOperator *op_coarse,
1997d1d35e2fSjeremylt     CeedOperator *op_prolong, CeedOperator *op_restrict) {
1998d99fa3c5SJeremy L Thompson   int ierr;
1999d99fa3c5SJeremy L Thompson   Ceed ceed;
2000d1d35e2fSjeremylt   ierr = CeedOperatorGetCeed(op_fine, &ceed); CeedChk(ierr);
2001d99fa3c5SJeremy L Thompson 
2002d99fa3c5SJeremy L Thompson   // Check for compatible quadrature spaces
2003d1d35e2fSjeremylt   CeedBasis basis_fine;
2004d1d35e2fSjeremylt   ierr = CeedOperatorGetActiveBasis(op_fine, &basis_fine); CeedChk(ierr);
2005d1d35e2fSjeremylt   CeedInt Q_f, Q_c;
2006d1d35e2fSjeremylt   ierr = CeedBasisGetNumQuadraturePoints(basis_fine, &Q_f); CeedChk(ierr);
2007d1d35e2fSjeremylt   ierr = CeedBasisGetNumQuadraturePoints(basis_coarse, &Q_c); CeedChk(ierr);
2008d1d35e2fSjeremylt   if (Q_f != Q_c)
2009d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
2010e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_DIMENSION,
2011e15f9bd0SJeremy L Thompson                      "Bases must have compatible quadrature spaces");
2012d99fa3c5SJeremy L Thompson   // LCOV_EXCL_STOP
2013d99fa3c5SJeremy L Thompson 
2014d99fa3c5SJeremy L Thompson   // Coarse to fine basis
2015d1d35e2fSjeremylt   CeedInt dim, num_comp, num_nodes_c, P_1d_f, P_1d_c;
2016d1d35e2fSjeremylt   ierr = CeedBasisGetDimension(basis_fine, &dim); CeedChk(ierr);
2017d1d35e2fSjeremylt   ierr = CeedBasisGetNumComponents(basis_fine, &num_comp); CeedChk(ierr);
2018d1d35e2fSjeremylt   ierr = CeedBasisGetNumNodes1D(basis_fine, &P_1d_f); CeedChk(ierr);
2019d1d35e2fSjeremylt   ierr = CeedElemRestrictionGetElementSize(rstr_coarse, &num_nodes_c);
2020d99fa3c5SJeremy L Thompson   CeedChk(ierr);
2021d1d35e2fSjeremylt   P_1d_c = dim == 1 ? num_nodes_c :
2022d1d35e2fSjeremylt            dim == 2 ? sqrt(num_nodes_c) :
2023d1d35e2fSjeremylt            cbrt(num_nodes_c);
2024d1d35e2fSjeremylt   CeedScalar *q_ref, *q_weight, *grad;
2025d1d35e2fSjeremylt   ierr = CeedCalloc(P_1d_f, &q_ref); CeedChk(ierr);
2026d1d35e2fSjeremylt   ierr = CeedCalloc(P_1d_f, &q_weight); CeedChk(ierr);
2027d1d35e2fSjeremylt   ierr = CeedCalloc(P_1d_f*P_1d_c*dim, &grad); CeedChk(ierr);
2028d1d35e2fSjeremylt   CeedBasis basis_c_to_f;
2029d1d35e2fSjeremylt   ierr = CeedBasisCreateTensorH1(ceed, dim, num_comp, P_1d_c, P_1d_f,
2030d1d35e2fSjeremylt                                  interp_c_to_f, grad, q_ref, q_weight, &basis_c_to_f);
2031d99fa3c5SJeremy L Thompson   CeedChk(ierr);
2032d1d35e2fSjeremylt   ierr = CeedFree(&q_ref); CeedChk(ierr);
2033d1d35e2fSjeremylt   ierr = CeedFree(&q_weight); CeedChk(ierr);
2034d99fa3c5SJeremy L Thompson   ierr = CeedFree(&grad); CeedChk(ierr);
2035d99fa3c5SJeremy L Thompson 
2036d99fa3c5SJeremy L Thompson   // Core code
2037d1d35e2fSjeremylt   ierr = CeedOperatorMultigridLevel_Core(op_fine, p_mult_fine, rstr_coarse,
2038d1d35e2fSjeremylt                                          basis_coarse, basis_c_to_f, op_coarse,
2039d1d35e2fSjeremylt                                          op_prolong, op_restrict);
2040d99fa3c5SJeremy L Thompson   CeedChk(ierr);
2041e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2042d99fa3c5SJeremy L Thompson }
2043d99fa3c5SJeremy L Thompson 
2044d99fa3c5SJeremy L Thompson /**
2045d99fa3c5SJeremy L Thompson   @brief Create a multigrid coarse operator and level transfer operators
2046d99fa3c5SJeremy L Thompson            for a CeedOperator with a non-tensor basis for the active vector
2047d99fa3c5SJeremy L Thompson 
2048d1d35e2fSjeremylt   @param[in] op_fine        Fine grid operator
2049d1d35e2fSjeremylt   @param[in] p_mult_fine    L-vector multiplicity in parallel gather/scatter
2050d1d35e2fSjeremylt   @param[in] rstr_coarse    Coarse grid restriction
2051d1d35e2fSjeremylt   @param[in] basis_coarse   Coarse grid active vector basis
2052d1d35e2fSjeremylt   @param[in] interp_c_to_f  Matrix for coarse to fine interpolation
2053d1d35e2fSjeremylt   @param[out] op_coarse     Coarse grid operator
2054d1d35e2fSjeremylt   @param[out] op_prolong    Coarse to fine operator
2055d1d35e2fSjeremylt   @param[out] op_restrict   Fine to coarse operator
2056d99fa3c5SJeremy L Thompson 
2057d99fa3c5SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
2058d99fa3c5SJeremy L Thompson 
2059d99fa3c5SJeremy L Thompson   @ref User
2060d99fa3c5SJeremy L Thompson **/
2061d1d35e2fSjeremylt int CeedOperatorMultigridLevelCreateH1(CeedOperator op_fine,
2062d1d35e2fSjeremylt                                        CeedVector p_mult_fine,
2063d1d35e2fSjeremylt                                        CeedElemRestriction rstr_coarse,
2064d1d35e2fSjeremylt                                        CeedBasis basis_coarse,
2065d1d35e2fSjeremylt                                        const CeedScalar *interp_c_to_f,
2066d1d35e2fSjeremylt                                        CeedOperator *op_coarse,
2067d1d35e2fSjeremylt                                        CeedOperator *op_prolong,
2068d1d35e2fSjeremylt                                        CeedOperator *op_restrict) {
2069d99fa3c5SJeremy L Thompson   int ierr;
2070d99fa3c5SJeremy L Thompson   Ceed ceed;
2071d1d35e2fSjeremylt   ierr = CeedOperatorGetCeed(op_fine, &ceed); CeedChk(ierr);
2072d99fa3c5SJeremy L Thompson 
2073d99fa3c5SJeremy L Thompson   // Check for compatible quadrature spaces
2074d1d35e2fSjeremylt   CeedBasis basis_fine;
2075d1d35e2fSjeremylt   ierr = CeedOperatorGetActiveBasis(op_fine, &basis_fine); CeedChk(ierr);
2076d1d35e2fSjeremylt   CeedInt Q_f, Q_c;
2077d1d35e2fSjeremylt   ierr = CeedBasisGetNumQuadraturePoints(basis_fine, &Q_f); CeedChk(ierr);
2078d1d35e2fSjeremylt   ierr = CeedBasisGetNumQuadraturePoints(basis_coarse, &Q_c); CeedChk(ierr);
2079d1d35e2fSjeremylt   if (Q_f != Q_c)
2080d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
2081e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_DIMENSION,
2082e15f9bd0SJeremy L Thompson                      "Bases must have compatible quadrature spaces");
2083d99fa3c5SJeremy L Thompson   // LCOV_EXCL_STOP
2084d99fa3c5SJeremy L Thompson 
2085d99fa3c5SJeremy L Thompson   // Coarse to fine basis
2086d99fa3c5SJeremy L Thompson   CeedElemTopology topo;
2087d1d35e2fSjeremylt   ierr = CeedBasisGetTopology(basis_fine, &topo); CeedChk(ierr);
2088d1d35e2fSjeremylt   CeedInt dim, num_comp, num_nodes_c, num_nodes_f;
2089d1d35e2fSjeremylt   ierr = CeedBasisGetDimension(basis_fine, &dim); CeedChk(ierr);
2090d1d35e2fSjeremylt   ierr = CeedBasisGetNumComponents(basis_fine, &num_comp); CeedChk(ierr);
2091d1d35e2fSjeremylt   ierr = CeedBasisGetNumNodes(basis_fine, &num_nodes_f); CeedChk(ierr);
2092d1d35e2fSjeremylt   ierr = CeedElemRestrictionGetElementSize(rstr_coarse, &num_nodes_c);
2093d99fa3c5SJeremy L Thompson   CeedChk(ierr);
2094d1d35e2fSjeremylt   CeedScalar *q_ref, *q_weight, *grad;
2095d1d35e2fSjeremylt   ierr = CeedCalloc(num_nodes_f, &q_ref); CeedChk(ierr);
2096d1d35e2fSjeremylt   ierr = CeedCalloc(num_nodes_f, &q_weight); CeedChk(ierr);
2097d1d35e2fSjeremylt   ierr = CeedCalloc(num_nodes_f*num_nodes_c*dim, &grad); CeedChk(ierr);
2098d1d35e2fSjeremylt   CeedBasis basis_c_to_f;
2099d1d35e2fSjeremylt   ierr = CeedBasisCreateH1(ceed, topo, num_comp, num_nodes_c, num_nodes_f,
2100d1d35e2fSjeremylt                            interp_c_to_f, grad, q_ref, q_weight, &basis_c_to_f);
2101d99fa3c5SJeremy L Thompson   CeedChk(ierr);
2102d1d35e2fSjeremylt   ierr = CeedFree(&q_ref); CeedChk(ierr);
2103d1d35e2fSjeremylt   ierr = CeedFree(&q_weight); CeedChk(ierr);
2104d99fa3c5SJeremy L Thompson   ierr = CeedFree(&grad); CeedChk(ierr);
2105d99fa3c5SJeremy L Thompson 
2106d99fa3c5SJeremy L Thompson   // Core code
2107d1d35e2fSjeremylt   ierr = CeedOperatorMultigridLevel_Core(op_fine, p_mult_fine, rstr_coarse,
2108d1d35e2fSjeremylt                                          basis_coarse, basis_c_to_f, op_coarse,
2109d1d35e2fSjeremylt                                          op_prolong, op_restrict);
2110d99fa3c5SJeremy L Thompson   CeedChk(ierr);
2111e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2112d99fa3c5SJeremy L Thompson }
2113d99fa3c5SJeremy L Thompson 
2114d99fa3c5SJeremy L Thompson /**
21153bd813ffSjeremylt   @brief Build a FDM based approximate inverse for each element for a
21163bd813ffSjeremylt            CeedOperator
21173bd813ffSjeremylt 
21183bd813ffSjeremylt   This returns a CeedOperator and CeedVector to apply a Fast Diagonalization
21193bd813ffSjeremylt     Method based approximate inverse. This function obtains the simultaneous
21203bd813ffSjeremylt     diagonalization for the 1D mass and Laplacian operators,
21213bd813ffSjeremylt       M = V^T V, K = V^T S V.
21223bd813ffSjeremylt     The assembled QFunction is used to modify the eigenvalues from simultaneous
21233bd813ffSjeremylt     diagonalization and obtain an approximate inverse of the form
21243bd813ffSjeremylt       V^T S^hat V. The CeedOperator must be linear and non-composite. The
21253bd813ffSjeremylt     associated CeedQFunction must therefore also be linear.
21263bd813ffSjeremylt 
21273bd813ffSjeremylt   @param op            CeedOperator to create element inverses
2128d1d35e2fSjeremylt   @param[out] fdm_inv  CeedOperator to apply the action of a FDM based inverse
21293bd813ffSjeremylt                          for each element
21303bd813ffSjeremylt   @param request       Address of CeedRequest for non-blocking completion, else
21314cc79fe7SJed Brown                          @ref CEED_REQUEST_IMMEDIATE
21323bd813ffSjeremylt 
21333bd813ffSjeremylt   @return An error code: 0 - success, otherwise - failure
21343bd813ffSjeremylt 
21357a982d89SJeremy L. Thompson   @ref Backend
21363bd813ffSjeremylt **/
2137d1d35e2fSjeremylt int CeedOperatorCreateFDMElementInverse(CeedOperator op, CeedOperator *fdm_inv,
21383bd813ffSjeremylt                                         CeedRequest *request) {
21393bd813ffSjeremylt   int ierr;
2140e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
21413bd813ffSjeremylt 
2142713f43c3Sjeremylt   // Use backend version, if available
2143713f43c3Sjeremylt   if (op->CreateFDMElementInverse) {
2144d1d35e2fSjeremylt     ierr = op->CreateFDMElementInverse(op, fdm_inv, request); CeedChk(ierr);
2145713f43c3Sjeremylt   } else {
2146713f43c3Sjeremylt     // Fallback to reference Ceed
2147d1d35e2fSjeremylt     if (!op->op_fallback) {
2148713f43c3Sjeremylt       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
21493bd813ffSjeremylt     }
2150713f43c3Sjeremylt     // Assemble
2151d1d35e2fSjeremylt     ierr = op->op_fallback->CreateFDMElementInverse(op->op_fallback, fdm_inv,
21523bd813ffSjeremylt            request); CeedChk(ierr);
21533bd813ffSjeremylt   }
2154e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
21553bd813ffSjeremylt }
21563bd813ffSjeremylt 
21577a982d89SJeremy L. Thompson /**
21587a982d89SJeremy L. Thompson   @brief View a CeedOperator
21597a982d89SJeremy L. Thompson 
21607a982d89SJeremy L. Thompson   @param[in] op      CeedOperator to view
21617a982d89SJeremy L. Thompson   @param[in] stream  Stream to write; typically stdout/stderr or a file
21627a982d89SJeremy L. Thompson 
21637a982d89SJeremy L. Thompson   @return Error code: 0 - success, otherwise - failure
21647a982d89SJeremy L. Thompson 
21657a982d89SJeremy L. Thompson   @ref User
21667a982d89SJeremy L. Thompson **/
21677a982d89SJeremy L. Thompson int CeedOperatorView(CeedOperator op, FILE *stream) {
21687a982d89SJeremy L. Thompson   int ierr;
21697a982d89SJeremy L. Thompson 
21707a982d89SJeremy L. Thompson   if (op->composite) {
21717a982d89SJeremy L. Thompson     fprintf(stream, "Composite CeedOperator\n");
21727a982d89SJeremy L. Thompson 
2173d1d35e2fSjeremylt     for (CeedInt i=0; i<op->num_suboperators; i++) {
21747a982d89SJeremy L. Thompson       fprintf(stream, "  SubOperator [%d]:\n", i);
2175d1d35e2fSjeremylt       ierr = CeedOperatorSingleView(op->sub_operators[i], 1, stream);
21767a982d89SJeremy L. Thompson       CeedChk(ierr);
21777a982d89SJeremy L. Thompson     }
21787a982d89SJeremy L. Thompson   } else {
21797a982d89SJeremy L. Thompson     fprintf(stream, "CeedOperator\n");
21807a982d89SJeremy L. Thompson     ierr = CeedOperatorSingleView(op, 0, stream); CeedChk(ierr);
21817a982d89SJeremy L. Thompson   }
2182e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
21837a982d89SJeremy L. Thompson }
21843bd813ffSjeremylt 
21853bd813ffSjeremylt /**
21863bd813ffSjeremylt   @brief Apply CeedOperator to a vector
2187d7b241e6Sjeremylt 
2188d7b241e6Sjeremylt   This computes the action of the operator on the specified (active) input,
2189d7b241e6Sjeremylt   yielding its (active) output.  All inputs and outputs must be specified using
2190d7b241e6Sjeremylt   CeedOperatorSetField().
2191d7b241e6Sjeremylt 
2192d7b241e6Sjeremylt   @param op        CeedOperator to apply
21934cc79fe7SJed Brown   @param[in] in    CeedVector containing input state or @ref CEED_VECTOR_NONE if
219434138859Sjeremylt                      there are no active inputs
2195b11c1e72Sjeremylt   @param[out] out  CeedVector to store result of applying operator (must be
21964cc79fe7SJed Brown                      distinct from @a in) or @ref CEED_VECTOR_NONE if there are no
219734138859Sjeremylt                      active outputs
2198d7b241e6Sjeremylt   @param request   Address of CeedRequest for non-blocking completion, else
21994cc79fe7SJed Brown                      @ref CEED_REQUEST_IMMEDIATE
2200b11c1e72Sjeremylt 
2201b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
2202dfdf5a53Sjeremylt 
22037a982d89SJeremy L. Thompson   @ref User
2204b11c1e72Sjeremylt **/
2205692c2638Sjeremylt int CeedOperatorApply(CeedOperator op, CeedVector in, CeedVector out,
2206692c2638Sjeremylt                       CeedRequest *request) {
2207d7b241e6Sjeremylt   int ierr;
2208e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
2209d7b241e6Sjeremylt 
2210d1d35e2fSjeremylt   if (op->num_elem)  {
2211250756a7Sjeremylt     // Standard Operator
2212cae8b89aSjeremylt     if (op->Apply) {
2213250756a7Sjeremylt       ierr = op->Apply(op, in, out, request); CeedChk(ierr);
2214cae8b89aSjeremylt     } else {
2215cae8b89aSjeremylt       // Zero all output vectors
2216250756a7Sjeremylt       CeedQFunction qf = op->qf;
2217d1d35e2fSjeremylt       for (CeedInt i=0; i<qf->num_output_fields; i++) {
2218d1d35e2fSjeremylt         CeedVector vec = op->output_fields[i]->vec;
2219cae8b89aSjeremylt         if (vec == CEED_VECTOR_ACTIVE)
2220cae8b89aSjeremylt           vec = out;
2221cae8b89aSjeremylt         if (vec != CEED_VECTOR_NONE) {
2222cae8b89aSjeremylt           ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr);
2223cae8b89aSjeremylt         }
2224cae8b89aSjeremylt       }
2225250756a7Sjeremylt       // Apply
2226250756a7Sjeremylt       ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr);
2227250756a7Sjeremylt     }
2228250756a7Sjeremylt   } else if (op->composite) {
2229250756a7Sjeremylt     // Composite Operator
2230250756a7Sjeremylt     if (op->ApplyComposite) {
2231250756a7Sjeremylt       ierr = op->ApplyComposite(op, in, out, request); CeedChk(ierr);
2232250756a7Sjeremylt     } else {
2233d1d35e2fSjeremylt       CeedInt num_suboperators;
2234d1d35e2fSjeremylt       ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr);
2235d1d35e2fSjeremylt       CeedOperator *sub_operators;
2236d1d35e2fSjeremylt       ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr);
2237250756a7Sjeremylt 
2238250756a7Sjeremylt       // Zero all output vectors
2239250756a7Sjeremylt       if (out != CEED_VECTOR_NONE) {
2240cae8b89aSjeremylt         ierr = CeedVectorSetValue(out, 0.0); CeedChk(ierr);
2241cae8b89aSjeremylt       }
2242d1d35e2fSjeremylt       for (CeedInt i=0; i<num_suboperators; i++) {
2243d1d35e2fSjeremylt         for (CeedInt j=0; j<sub_operators[i]->qf->num_output_fields; j++) {
2244d1d35e2fSjeremylt           CeedVector vec = sub_operators[i]->output_fields[j]->vec;
2245250756a7Sjeremylt           if (vec != CEED_VECTOR_ACTIVE && vec != CEED_VECTOR_NONE) {
2246250756a7Sjeremylt             ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr);
2247250756a7Sjeremylt           }
2248250756a7Sjeremylt         }
2249250756a7Sjeremylt       }
2250250756a7Sjeremylt       // Apply
2251d1d35e2fSjeremylt       for (CeedInt i=0; i<op->num_suboperators; i++) {
2252d1d35e2fSjeremylt         ierr = CeedOperatorApplyAdd(op->sub_operators[i], in, out, request);
2253cae8b89aSjeremylt         CeedChk(ierr);
2254cae8b89aSjeremylt       }
2255cae8b89aSjeremylt     }
2256250756a7Sjeremylt   }
2257e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2258cae8b89aSjeremylt }
2259cae8b89aSjeremylt 
2260cae8b89aSjeremylt /**
2261cae8b89aSjeremylt   @brief Apply CeedOperator to a vector and add result to output vector
2262cae8b89aSjeremylt 
2263cae8b89aSjeremylt   This computes the action of the operator on the specified (active) input,
2264cae8b89aSjeremylt   yielding its (active) output.  All inputs and outputs must be specified using
2265cae8b89aSjeremylt   CeedOperatorSetField().
2266cae8b89aSjeremylt 
2267cae8b89aSjeremylt   @param op        CeedOperator to apply
2268cae8b89aSjeremylt   @param[in] in    CeedVector containing input state or NULL if there are no
2269cae8b89aSjeremylt                      active inputs
2270cae8b89aSjeremylt   @param[out] out  CeedVector to sum in result of applying operator (must be
2271cae8b89aSjeremylt                      distinct from @a in) or NULL if there are no active outputs
2272cae8b89aSjeremylt   @param request   Address of CeedRequest for non-blocking completion, else
22734cc79fe7SJed Brown                      @ref CEED_REQUEST_IMMEDIATE
2274cae8b89aSjeremylt 
2275cae8b89aSjeremylt   @return An error code: 0 - success, otherwise - failure
2276cae8b89aSjeremylt 
22777a982d89SJeremy L. Thompson   @ref User
2278cae8b89aSjeremylt **/
2279cae8b89aSjeremylt int CeedOperatorApplyAdd(CeedOperator op, CeedVector in, CeedVector out,
2280cae8b89aSjeremylt                          CeedRequest *request) {
2281cae8b89aSjeremylt   int ierr;
2282e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
2283cae8b89aSjeremylt 
2284d1d35e2fSjeremylt   if (op->num_elem)  {
2285250756a7Sjeremylt     // Standard Operator
2286250756a7Sjeremylt     ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr);
2287250756a7Sjeremylt   } else if (op->composite) {
2288250756a7Sjeremylt     // Composite Operator
2289250756a7Sjeremylt     if (op->ApplyAddComposite) {
2290250756a7Sjeremylt       ierr = op->ApplyAddComposite(op, in, out, request); CeedChk(ierr);
2291cae8b89aSjeremylt     } else {
2292d1d35e2fSjeremylt       CeedInt num_suboperators;
2293d1d35e2fSjeremylt       ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr);
2294d1d35e2fSjeremylt       CeedOperator *sub_operators;
2295d1d35e2fSjeremylt       ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr);
2296250756a7Sjeremylt 
2297d1d35e2fSjeremylt       for (CeedInt i=0; i<num_suboperators; i++) {
2298d1d35e2fSjeremylt         ierr = CeedOperatorApplyAdd(sub_operators[i], in, out, request);
2299cae8b89aSjeremylt         CeedChk(ierr);
23001d7d2407SJeremy L Thompson       }
2301250756a7Sjeremylt     }
2302250756a7Sjeremylt   }
2303e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2304d7b241e6Sjeremylt }
2305d7b241e6Sjeremylt 
2306d7b241e6Sjeremylt /**
2307b11c1e72Sjeremylt   @brief Destroy a CeedOperator
2308d7b241e6Sjeremylt 
2309d7b241e6Sjeremylt   @param op  CeedOperator to destroy
2310b11c1e72Sjeremylt 
2311b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
2312dfdf5a53Sjeremylt 
23137a982d89SJeremy L. Thompson   @ref User
2314b11c1e72Sjeremylt **/
2315d7b241e6Sjeremylt int CeedOperatorDestroy(CeedOperator *op) {
2316d7b241e6Sjeremylt   int ierr;
2317d7b241e6Sjeremylt 
2318d1d35e2fSjeremylt   if (!*op || --(*op)->ref_count > 0) return CEED_ERROR_SUCCESS;
2319d7b241e6Sjeremylt   if ((*op)->Destroy) {
2320d7b241e6Sjeremylt     ierr = (*op)->Destroy(*op); CeedChk(ierr);
2321d7b241e6Sjeremylt   }
2322fe2413ffSjeremylt   ierr = CeedDestroy(&(*op)->ceed); CeedChk(ierr);
2323fe2413ffSjeremylt   // Free fields
2324d1d35e2fSjeremylt   for (int i=0; i<(*op)->num_fields; i++)
2325d1d35e2fSjeremylt     if ((*op)->input_fields[i]) {
2326d1d35e2fSjeremylt       if ((*op)->input_fields[i]->elem_restr != CEED_ELEMRESTRICTION_NONE) {
2327d1d35e2fSjeremylt         ierr = CeedElemRestrictionDestroy(&(*op)->input_fields[i]->elem_restr);
232871352a93Sjeremylt         CeedChk(ierr);
232915910d16Sjeremylt       }
2330d1d35e2fSjeremylt       if ((*op)->input_fields[i]->basis != CEED_BASIS_COLLOCATED) {
2331d1d35e2fSjeremylt         ierr = CeedBasisDestroy(&(*op)->input_fields[i]->basis); CeedChk(ierr);
233271352a93Sjeremylt       }
2333d1d35e2fSjeremylt       if ((*op)->input_fields[i]->vec != CEED_VECTOR_ACTIVE &&
2334d1d35e2fSjeremylt           (*op)->input_fields[i]->vec != CEED_VECTOR_NONE ) {
2335d1d35e2fSjeremylt         ierr = CeedVectorDestroy(&(*op)->input_fields[i]->vec); CeedChk(ierr);
233671352a93Sjeremylt       }
2337d1d35e2fSjeremylt       ierr = CeedFree(&(*op)->input_fields[i]->field_name); CeedChk(ierr);
2338d1d35e2fSjeremylt       ierr = CeedFree(&(*op)->input_fields[i]); CeedChk(ierr);
2339fe2413ffSjeremylt     }
2340d1d35e2fSjeremylt   for (int i=0; i<(*op)->num_fields; i++)
2341d1d35e2fSjeremylt     if ((*op)->output_fields[i]) {
2342d1d35e2fSjeremylt       ierr = CeedElemRestrictionDestroy(&(*op)->output_fields[i]->elem_restr);
234371352a93Sjeremylt       CeedChk(ierr);
2344d1d35e2fSjeremylt       if ((*op)->output_fields[i]->basis != CEED_BASIS_COLLOCATED) {
2345d1d35e2fSjeremylt         ierr = CeedBasisDestroy(&(*op)->output_fields[i]->basis); CeedChk(ierr);
234671352a93Sjeremylt       }
2347d1d35e2fSjeremylt       if ((*op)->output_fields[i]->vec != CEED_VECTOR_ACTIVE &&
2348d1d35e2fSjeremylt           (*op)->output_fields[i]->vec != CEED_VECTOR_NONE ) {
2349d1d35e2fSjeremylt         ierr = CeedVectorDestroy(&(*op)->output_fields[i]->vec); CeedChk(ierr);
235071352a93Sjeremylt       }
2351d1d35e2fSjeremylt       ierr = CeedFree(&(*op)->output_fields[i]->field_name); CeedChk(ierr);
2352d1d35e2fSjeremylt       ierr = CeedFree(&(*op)->output_fields[i]); CeedChk(ierr);
2353fe2413ffSjeremylt     }
2354d1d35e2fSjeremylt   // Destroy sub_operators
2355d1d35e2fSjeremylt   for (int i=0; i<(*op)->num_suboperators; i++)
2356d1d35e2fSjeremylt     if ((*op)->sub_operators[i]) {
2357d1d35e2fSjeremylt       ierr = CeedOperatorDestroy(&(*op)->sub_operators[i]); CeedChk(ierr);
235852d6035fSJeremy L Thompson     }
2359e15f9bd0SJeremy L Thompson   if ((*op)->qf)
2360e15f9bd0SJeremy L Thompson     // LCOV_EXCL_START
2361d1d35e2fSjeremylt     (*op)->qf->operators_set--;
2362e15f9bd0SJeremy L Thompson   // LCOV_EXCL_STOP
2363d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->qf); CeedChk(ierr);
2364e15f9bd0SJeremy L Thompson   if ((*op)->dqf && (*op)->dqf != CEED_QFUNCTION_NONE)
2365e15f9bd0SJeremy L Thompson     // LCOV_EXCL_START
2366d1d35e2fSjeremylt     (*op)->dqf->operators_set--;
2367e15f9bd0SJeremy L Thompson   // LCOV_EXCL_STOP
2368d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->dqf); CeedChk(ierr);
2369e15f9bd0SJeremy L Thompson   if ((*op)->dqfT && (*op)->dqfT != CEED_QFUNCTION_NONE)
2370e15f9bd0SJeremy L Thompson     // LCOV_EXCL_START
2371d1d35e2fSjeremylt     (*op)->dqfT->operators_set--;
2372e15f9bd0SJeremy L Thompson   // LCOV_EXCL_STOP
2373d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->dqfT); CeedChk(ierr);
2374fe2413ffSjeremylt 
23755107b09fSJeremy L Thompson   // Destroy fallback
2376d1d35e2fSjeremylt   if ((*op)->op_fallback) {
2377d1d35e2fSjeremylt     ierr = (*op)->qf_fallback->Destroy((*op)->qf_fallback); CeedChk(ierr);
2378d1d35e2fSjeremylt     ierr = CeedFree(&(*op)->qf_fallback); CeedChk(ierr);
2379d1d35e2fSjeremylt     ierr = (*op)->op_fallback->Destroy((*op)->op_fallback); CeedChk(ierr);
2380d1d35e2fSjeremylt     ierr = CeedFree(&(*op)->op_fallback); CeedChk(ierr);
23815107b09fSJeremy L Thompson   }
23825107b09fSJeremy L Thompson 
2383d1d35e2fSjeremylt   ierr = CeedFree(&(*op)->input_fields); CeedChk(ierr);
2384d1d35e2fSjeremylt   ierr = CeedFree(&(*op)->output_fields); CeedChk(ierr);
2385d1d35e2fSjeremylt   ierr = CeedFree(&(*op)->sub_operators); CeedChk(ierr);
2386d7b241e6Sjeremylt   ierr = CeedFree(op); CeedChk(ierr);
2387e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2388d7b241e6Sjeremylt }
2389d7b241e6Sjeremylt 
2390d7b241e6Sjeremylt /// @}
2391