xref: /libCEED/interface/ceed-operator.c (revision 784646086dc2cd22411d95107c6b787565214f18)
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);
119*78464608Sjeremylt     CeedChk(ierr);
120e1e9e29dSJed Brown   }
121d1d35e2fSjeremylt   if ((r == CEED_ELEMRESTRICTION_NONE) != (eval_mode == CEED_EVAL_WEIGHT)) {
122e1e9e29dSJed Brown     // LCOV_EXCL_START
123e1e9e29dSJed Brown     return CeedError(ceed, CEED_ERROR_INCOMPATIBLE,
124e1e9e29dSJed Brown                      "CEED_ELEMRESTRICTION_NONE and CEED_EVAL_WEIGHT "
125e1e9e29dSJed Brown                      "must be used together.");
126e1e9e29dSJed Brown     // LCOV_EXCL_STOP
127e1e9e29dSJed Brown   }
128e15f9bd0SJeremy L Thompson   // Basis
129e15f9bd0SJeremy L Thompson   if (b != CEED_BASIS_COLLOCATED) {
130d1d35e2fSjeremylt     if (eval_mode == CEED_EVAL_NONE)
131e1e9e29dSJed Brown       return CeedError(ceed, CEED_ERROR_INCOMPATIBLE,
132d1d35e2fSjeremylt                        "Field '%s' configured with CEED_EVAL_NONE must "
133d1d35e2fSjeremylt                        "be used with CEED_BASIS_COLLOCATED",
134d1d35e2fSjeremylt                        qf_field->field_name);
135e15f9bd0SJeremy L Thompson     ierr = CeedBasisGetDimension(b, &dim); CeedChk(ierr);
136d1d35e2fSjeremylt     ierr = CeedBasisGetNumComponents(b, &num_comp); CeedChk(ierr);
137d1d35e2fSjeremylt     if (r != CEED_ELEMRESTRICTION_NONE && restr_num_comp != num_comp) {
138e15f9bd0SJeremy L Thompson       // LCOV_EXCL_START
139e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_DIMENSION,
140d1d35e2fSjeremylt                        "Field '%s' of size %d and EvalMode %s: ElemRestriction "
141d1d35e2fSjeremylt                        "has %d components, but Basis has %d components",
142d1d35e2fSjeremylt                        qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode],
143d1d35e2fSjeremylt                        restr_num_comp,
144d1d35e2fSjeremylt                        num_comp);
145e15f9bd0SJeremy L Thompson       // LCOV_EXCL_STOP
146e15f9bd0SJeremy L Thompson     }
147e15f9bd0SJeremy L Thompson   }
148e15f9bd0SJeremy L Thompson   // Field size
149d1d35e2fSjeremylt   switch(eval_mode) {
150e15f9bd0SJeremy L Thompson   case CEED_EVAL_NONE:
151d1d35e2fSjeremylt     if (size != restr_num_comp)
152e15f9bd0SJeremy L Thompson       // LCOV_EXCL_START
153e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_DIMENSION,
154e1e9e29dSJed Brown                        "Field '%s' of size %d and EvalMode %s: ElemRestriction has %d components",
155d1d35e2fSjeremylt                        qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode],
156d1d35e2fSjeremylt                        restr_num_comp);
157e15f9bd0SJeremy L Thompson     // LCOV_EXCL_STOP
158e15f9bd0SJeremy L Thompson     break;
159e15f9bd0SJeremy L Thompson   case CEED_EVAL_INTERP:
160d1d35e2fSjeremylt     if (size != num_comp)
161e15f9bd0SJeremy L Thompson       // LCOV_EXCL_START
162e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_DIMENSION,
163e1e9e29dSJed Brown                        "Field '%s' of size %d and EvalMode %s: ElemRestriction/Basis has %d components",
164d1d35e2fSjeremylt                        qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode],
165d1d35e2fSjeremylt                        num_comp);
166e15f9bd0SJeremy L Thompson     // LCOV_EXCL_STOP
167e15f9bd0SJeremy L Thompson     break;
168e15f9bd0SJeremy L Thompson   case CEED_EVAL_GRAD:
169d1d35e2fSjeremylt     if (size != num_comp * dim)
170e15f9bd0SJeremy L Thompson       // LCOV_EXCL_START
171e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_DIMENSION,
172d1d35e2fSjeremylt                        "Field '%s' of size %d and EvalMode %s in %d dimensions: "
173d1d35e2fSjeremylt                        "ElemRestriction/Basis has %d components",
174d1d35e2fSjeremylt                        qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode], dim,
175d1d35e2fSjeremylt                        num_comp);
176e15f9bd0SJeremy L Thompson     // LCOV_EXCL_STOP
177e15f9bd0SJeremy L Thompson     break;
178e15f9bd0SJeremy L Thompson   case CEED_EVAL_WEIGHT:
179d1d35e2fSjeremylt     // No additional checks required
180e15f9bd0SJeremy L Thompson     break;
181e15f9bd0SJeremy L Thompson   case CEED_EVAL_DIV:
182e15f9bd0SJeremy L Thompson     // Not implemented
183e15f9bd0SJeremy L Thompson     break;
184e15f9bd0SJeremy L Thompson   case CEED_EVAL_CURL:
185e15f9bd0SJeremy L Thompson     // Not implemented
186e15f9bd0SJeremy L Thompson     break;
187e15f9bd0SJeremy L Thompson   }
188e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1897a982d89SJeremy L. Thompson }
1907a982d89SJeremy L. Thompson 
1917a982d89SJeremy L. Thompson /**
1927a982d89SJeremy L. Thompson   @brief Check if a CeedOperator is ready to be used.
1937a982d89SJeremy L. Thompson 
1947a982d89SJeremy L. Thompson   @param[in] op  CeedOperator to check
1957a982d89SJeremy L. Thompson 
1967a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
1977a982d89SJeremy L. Thompson 
1987a982d89SJeremy L. Thompson   @ref Developer
1997a982d89SJeremy L. Thompson **/
200e2f04181SAndrew T. Barker static int CeedOperatorCheckReady(CeedOperator op) {
201e2f04181SAndrew T. Barker   int ierr;
202e2f04181SAndrew T. Barker   Ceed ceed;
203e2f04181SAndrew T. Barker   ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr);
204e2f04181SAndrew T. Barker 
205d1d35e2fSjeremylt   if (op->interface_setup)
206e15f9bd0SJeremy L Thompson     return CEED_ERROR_SUCCESS;
2077a982d89SJeremy L. Thompson 
208e15f9bd0SJeremy L Thompson   CeedQFunction qf = op->qf;
2097a982d89SJeremy L. Thompson   if (op->composite) {
210d1d35e2fSjeremylt     if (!op->num_suboperators)
2117a982d89SJeremy L. Thompson       // LCOV_EXCL_START
212d1d35e2fSjeremylt       return CeedError(ceed, CEED_ERROR_INCOMPLETE, "No sub_operators set");
2137a982d89SJeremy L. Thompson     // LCOV_EXCL_STOP
2147a982d89SJeremy L. Thompson   } else {
215d1d35e2fSjeremylt     if (op->num_fields == 0)
2167a982d89SJeremy L. Thompson       // LCOV_EXCL_START
217e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_INCOMPLETE, "No operator fields set");
2187a982d89SJeremy L. Thompson     // LCOV_EXCL_STOP
219d1d35e2fSjeremylt     if (op->num_fields < qf->num_input_fields + qf->num_output_fields)
2207a982d89SJeremy L. Thompson       // LCOV_EXCL_START
221e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_INCOMPLETE, "Not all operator fields set");
2227a982d89SJeremy L. Thompson     // LCOV_EXCL_STOP
223d1d35e2fSjeremylt     if (!op->has_restriction)
2247a982d89SJeremy L. Thompson       // LCOV_EXCL_START
225e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_INCOMPLETE,
226e15f9bd0SJeremy L Thompson                        "At least one restriction required");
2277a982d89SJeremy L. Thompson     // LCOV_EXCL_STOP
228d1d35e2fSjeremylt     if (op->num_qpts == 0)
2297a982d89SJeremy L. Thompson       // LCOV_EXCL_START
230e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_INCOMPLETE,
231e15f9bd0SJeremy L Thompson                        "At least one non-collocated basis required");
2327a982d89SJeremy L. Thompson     // LCOV_EXCL_STOP
2337a982d89SJeremy L. Thompson   }
2347a982d89SJeremy L. Thompson 
235e15f9bd0SJeremy L Thompson   // Flag as immutable and ready
236d1d35e2fSjeremylt   op->interface_setup = true;
237e15f9bd0SJeremy L Thompson   if (op->qf && op->qf != CEED_QFUNCTION_NONE)
238e15f9bd0SJeremy L Thompson     // LCOV_EXCL_START
239d1d35e2fSjeremylt     op->qf->operators_set++;
240e15f9bd0SJeremy L Thompson   // LCOV_EXCL_STOP
241e15f9bd0SJeremy L Thompson   if (op->dqf && op->dqf != CEED_QFUNCTION_NONE)
242e15f9bd0SJeremy L Thompson     // LCOV_EXCL_START
243d1d35e2fSjeremylt     op->dqf->operators_set++;
244e15f9bd0SJeremy L Thompson   // LCOV_EXCL_STOP
245e15f9bd0SJeremy L Thompson   if (op->dqfT && op->dqfT != CEED_QFUNCTION_NONE)
246e15f9bd0SJeremy L Thompson     // LCOV_EXCL_START
247d1d35e2fSjeremylt     op->dqfT->operators_set++;
248e15f9bd0SJeremy L Thompson   // LCOV_EXCL_STOP
249e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2507a982d89SJeremy L. Thompson }
2517a982d89SJeremy L. Thompson 
2527a982d89SJeremy L. Thompson /**
2537a982d89SJeremy L. Thompson   @brief View a field of a CeedOperator
2547a982d89SJeremy L. Thompson 
2557a982d89SJeremy L. Thompson   @param[in] field         Operator field to view
256d1d35e2fSjeremylt   @param[in] qf_field      QFunction field (carries field name)
257d1d35e2fSjeremylt   @param[in] field_number  Number of field being viewed
2584c4400c7SValeria Barra   @param[in] sub           true indicates sub-operator, which increases indentation; false for top-level operator
259d1d35e2fSjeremylt   @param[in] input         true for an input field; false for output field
2607a982d89SJeremy L. Thompson   @param[in] stream        Stream to view to, e.g., stdout
2617a982d89SJeremy L. Thompson 
2627a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
2637a982d89SJeremy L. Thompson 
2647a982d89SJeremy L. Thompson   @ref Utility
2657a982d89SJeremy L. Thompson **/
2667a982d89SJeremy L. Thompson static int CeedOperatorFieldView(CeedOperatorField field,
267d1d35e2fSjeremylt                                  CeedQFunctionField qf_field,
268d1d35e2fSjeremylt                                  CeedInt field_number, bool sub, bool input,
2697a982d89SJeremy L. Thompson                                  FILE *stream) {
2707a982d89SJeremy L. Thompson   const char *pre = sub ? "  " : "";
271d1d35e2fSjeremylt   const char *in_out = input ? "Input" : "Output";
2727a982d89SJeremy L. Thompson 
2737a982d89SJeremy L. Thompson   fprintf(stream, "%s    %s Field [%d]:\n"
2747a982d89SJeremy L. Thompson           "%s      Name: \"%s\"\n",
275d1d35e2fSjeremylt           pre, in_out, field_number, pre, qf_field->field_name);
2767a982d89SJeremy L. Thompson 
2777a982d89SJeremy L. Thompson   if (field->basis == CEED_BASIS_COLLOCATED)
2787a982d89SJeremy L. Thompson     fprintf(stream, "%s      Collocated basis\n", pre);
2797a982d89SJeremy L. Thompson 
2807a982d89SJeremy L. Thompson   if (field->vec == CEED_VECTOR_ACTIVE)
2817a982d89SJeremy L. Thompson     fprintf(stream, "%s      Active vector\n", pre);
2827a982d89SJeremy L. Thompson   else if (field->vec == CEED_VECTOR_NONE)
2837a982d89SJeremy L. Thompson     fprintf(stream, "%s      No vector\n", pre);
284e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2857a982d89SJeremy L. Thompson }
2867a982d89SJeremy L. Thompson 
2877a982d89SJeremy L. Thompson /**
2887a982d89SJeremy L. Thompson   @brief View a single CeedOperator
2897a982d89SJeremy L. Thompson 
2907a982d89SJeremy L. Thompson   @param[in] op      CeedOperator to view
2917a982d89SJeremy L. Thompson   @param[in] sub     Boolean flag for sub-operator
2927a982d89SJeremy L. Thompson   @param[in] stream  Stream to write; typically stdout/stderr or a file
2937a982d89SJeremy L. Thompson 
2947a982d89SJeremy L. Thompson   @return Error code: 0 - success, otherwise - failure
2957a982d89SJeremy L. Thompson 
2967a982d89SJeremy L. Thompson   @ref Utility
2977a982d89SJeremy L. Thompson **/
2987a982d89SJeremy L. Thompson int CeedOperatorSingleView(CeedOperator op, bool sub, FILE *stream) {
2997a982d89SJeremy L. Thompson   int ierr;
3007a982d89SJeremy L. Thompson   const char *pre = sub ? "  " : "";
3017a982d89SJeremy L. Thompson 
302*78464608Sjeremylt   CeedInt total_fields = 0;
303*78464608Sjeremylt   ierr = CeedOperatorGetNumArgs(op, &total_fields); CeedChk(ierr);
3047a982d89SJeremy L. Thompson 
305*78464608Sjeremylt   fprintf(stream, "%s  %d Field%s\n", pre, total_fields,
306*78464608Sjeremylt           total_fields>1 ? "s" : "");
3077a982d89SJeremy L. Thompson 
308d1d35e2fSjeremylt   fprintf(stream, "%s  %d Input Field%s:\n", pre, op->qf->num_input_fields,
309d1d35e2fSjeremylt           op->qf->num_input_fields>1 ? "s" : "");
310d1d35e2fSjeremylt   for (CeedInt i=0; i<op->qf->num_input_fields; i++) {
311d1d35e2fSjeremylt     ierr = CeedOperatorFieldView(op->input_fields[i], op->qf->input_fields[i],
3127a982d89SJeremy L. Thompson                                  i, sub, 1, stream); CeedChk(ierr);
3137a982d89SJeremy L. Thompson   }
3147a982d89SJeremy L. Thompson 
315d1d35e2fSjeremylt   fprintf(stream, "%s  %d Output Field%s:\n", pre, op->qf->num_output_fields,
316d1d35e2fSjeremylt           op->qf->num_output_fields>1 ? "s" : "");
317d1d35e2fSjeremylt   for (CeedInt i=0; i<op->qf->num_output_fields; i++) {
318d1d35e2fSjeremylt     ierr = CeedOperatorFieldView(op->output_fields[i], op->qf->output_fields[i],
3197a982d89SJeremy L. Thompson                                  i, sub, 0, stream); CeedChk(ierr);
3207a982d89SJeremy L. Thompson   }
321e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
3227a982d89SJeremy L. Thompson }
3237a982d89SJeremy L. Thompson 
324d99fa3c5SJeremy L Thompson /**
325e2f04181SAndrew T. Barker   @brief Find the active vector ElemRestriction for a CeedOperator
326e2f04181SAndrew T. Barker 
327e2f04181SAndrew T. Barker   @param[in] op            CeedOperator to find active basis for
328d1d35e2fSjeremylt   @param[out] active_rstr  ElemRestriction for active input vector
329e2f04181SAndrew T. Barker 
330e2f04181SAndrew T. Barker   @return An error code: 0 - success, otherwise - failure
331e2f04181SAndrew T. Barker 
332e2f04181SAndrew T. Barker   @ref Utility
333e2f04181SAndrew T. Barker **/
334e2f04181SAndrew T. Barker static int CeedOperatorGetActiveElemRestriction(CeedOperator op,
335d1d35e2fSjeremylt     CeedElemRestriction *active_rstr) {
336d1d35e2fSjeremylt   *active_rstr = NULL;
337d1d35e2fSjeremylt   for (int i = 0; i < op->qf->num_input_fields; i++)
338d1d35e2fSjeremylt     if (op->input_fields[i]->vec == CEED_VECTOR_ACTIVE) {
339d1d35e2fSjeremylt       *active_rstr = op->input_fields[i]->elem_restr;
340e2f04181SAndrew T. Barker       break;
341e2f04181SAndrew T. Barker     }
342e2f04181SAndrew T. Barker 
343d1d35e2fSjeremylt   if (!*active_rstr) {
344e2f04181SAndrew T. Barker     // LCOV_EXCL_START
345e2f04181SAndrew T. Barker     int ierr;
346e2f04181SAndrew T. Barker     Ceed ceed;
347e2f04181SAndrew T. Barker     ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr);
348e2f04181SAndrew T. Barker     return CeedError(ceed, CEED_ERROR_INCOMPLETE,
349e2f04181SAndrew T. Barker                      "No active ElemRestriction found!");
350e2f04181SAndrew T. Barker     // LCOV_EXCL_STOP
351e2f04181SAndrew T. Barker   }
352e2f04181SAndrew T. Barker   return CEED_ERROR_SUCCESS;
353e2f04181SAndrew T. Barker }
354e2f04181SAndrew T. Barker 
355e2f04181SAndrew T. Barker /**
356d99fa3c5SJeremy L Thompson   @brief Find the active vector basis for a CeedOperator
357d99fa3c5SJeremy L Thompson 
358d99fa3c5SJeremy L Thompson   @param[in] op             CeedOperator to find active basis for
359d1d35e2fSjeremylt   @param[out] active_basis  Basis for active input vector
360d99fa3c5SJeremy L Thompson 
361d99fa3c5SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
362d99fa3c5SJeremy L Thompson 
363d99fa3c5SJeremy L Thompson   @ ref Developer
364d99fa3c5SJeremy L Thompson **/
365d99fa3c5SJeremy L Thompson static int CeedOperatorGetActiveBasis(CeedOperator op,
366d1d35e2fSjeremylt                                       CeedBasis *active_basis) {
367d1d35e2fSjeremylt   *active_basis = NULL;
368d1d35e2fSjeremylt   for (int i = 0; i < op->qf->num_input_fields; i++)
369d1d35e2fSjeremylt     if (op->input_fields[i]->vec == CEED_VECTOR_ACTIVE) {
370d1d35e2fSjeremylt       *active_basis = op->input_fields[i]->basis;
371d99fa3c5SJeremy L Thompson       break;
372d99fa3c5SJeremy L Thompson     }
373d99fa3c5SJeremy L Thompson 
374d1d35e2fSjeremylt   if (!*active_basis) {
375d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
376d99fa3c5SJeremy L Thompson     int ierr;
377d99fa3c5SJeremy L Thompson     Ceed ceed;
378d99fa3c5SJeremy L Thompson     ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr);
379e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_MINOR,
380d99fa3c5SJeremy L Thompson                      "No active basis found for automatic multigrid setup");
381d99fa3c5SJeremy L Thompson     // LCOV_EXCL_STOP
382d99fa3c5SJeremy L Thompson   }
383e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
384d99fa3c5SJeremy L Thompson }
385d99fa3c5SJeremy L Thompson 
386d99fa3c5SJeremy L Thompson /**
387d99fa3c5SJeremy L Thompson   @brief Common code for creating a multigrid coarse operator and level
388d99fa3c5SJeremy L Thompson            transfer operators for a CeedOperator
389d99fa3c5SJeremy L Thompson 
390d1d35e2fSjeremylt   @param[in] op_fine       Fine grid operator
391d1d35e2fSjeremylt   @param[in] p_mult_fine   L-vector multiplicity in parallel gather/scatter
392d1d35e2fSjeremylt   @param[in] rstr_coarse   Coarse grid restriction
393d1d35e2fSjeremylt   @param[in] basis_coarse  Coarse grid active vector basis
394d1d35e2fSjeremylt   @param[in] basis_c_to_f  Basis for coarse to fine interpolation
395d1d35e2fSjeremylt   @param[out] op_coarse    Coarse grid operator
396d1d35e2fSjeremylt   @param[out] op_prolong   Coarse to fine operator
397d1d35e2fSjeremylt   @param[out] op_restrict  Fine to coarse operator
398d99fa3c5SJeremy L Thompson 
399d99fa3c5SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
400d99fa3c5SJeremy L Thompson 
401d99fa3c5SJeremy L Thompson   @ref Developer
402d99fa3c5SJeremy L Thompson **/
403d1d35e2fSjeremylt static int CeedOperatorMultigridLevel_Core(CeedOperator op_fine,
404d1d35e2fSjeremylt     CeedVector p_mult_fine, CeedElemRestriction rstr_coarse, CeedBasis basis_coarse,
405d1d35e2fSjeremylt     CeedBasis basis_c_to_f, CeedOperator *op_coarse, CeedOperator *op_prolong,
406d1d35e2fSjeremylt     CeedOperator *op_restrict) {
407d99fa3c5SJeremy L Thompson   int ierr;
408d99fa3c5SJeremy L Thompson   Ceed ceed;
409d1d35e2fSjeremylt   ierr = CeedOperatorGetCeed(op_fine, &ceed); CeedChk(ierr);
410d99fa3c5SJeremy L Thompson 
411d99fa3c5SJeremy L Thompson   // Check for composite operator
412d1d35e2fSjeremylt   bool is_composite;
413d1d35e2fSjeremylt   ierr = CeedOperatorIsComposite(op_fine, &is_composite); CeedChk(ierr);
414d1d35e2fSjeremylt   if (is_composite)
415d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
416e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_UNSUPPORTED,
417d99fa3c5SJeremy L Thompson                      "Automatic multigrid setup for composite operators not supported");
418d99fa3c5SJeremy L Thompson   // LCOV_EXCL_STOP
419d99fa3c5SJeremy L Thompson 
420d99fa3c5SJeremy L Thompson   // Coarse Grid
421d1d35e2fSjeremylt   ierr = CeedOperatorCreate(ceed, op_fine->qf, op_fine->dqf, op_fine->dqfT,
422d1d35e2fSjeremylt                             op_coarse); CeedChk(ierr);
423d1d35e2fSjeremylt   CeedElemRestriction rstr_fine = NULL;
424d99fa3c5SJeremy L Thompson   // -- Clone input fields
425d1d35e2fSjeremylt   for (int i = 0; i < op_fine->qf->num_input_fields; i++) {
426d1d35e2fSjeremylt     if (op_fine->input_fields[i]->vec == CEED_VECTOR_ACTIVE) {
427d1d35e2fSjeremylt       rstr_fine = op_fine->input_fields[i]->elem_restr;
428d1d35e2fSjeremylt       ierr = CeedOperatorSetField(*op_coarse, op_fine->input_fields[i]->field_name,
429d1d35e2fSjeremylt                                   rstr_coarse, basis_coarse, CEED_VECTOR_ACTIVE);
430d99fa3c5SJeremy L Thompson       CeedChk(ierr);
431d99fa3c5SJeremy L Thompson     } else {
432d1d35e2fSjeremylt       ierr = CeedOperatorSetField(*op_coarse, op_fine->input_fields[i]->field_name,
433d1d35e2fSjeremylt                                   op_fine->input_fields[i]->elem_restr,
434d1d35e2fSjeremylt                                   op_fine->input_fields[i]->basis,
435d1d35e2fSjeremylt                                   op_fine->input_fields[i]->vec); CeedChk(ierr);
436d99fa3c5SJeremy L Thompson     }
437d99fa3c5SJeremy L Thompson   }
438d99fa3c5SJeremy L Thompson   // -- Clone output fields
439d1d35e2fSjeremylt   for (int i = 0; i < op_fine->qf->num_output_fields; i++) {
440d1d35e2fSjeremylt     if (op_fine->output_fields[i]->vec == CEED_VECTOR_ACTIVE) {
441d1d35e2fSjeremylt       ierr = CeedOperatorSetField(*op_coarse, op_fine->output_fields[i]->field_name,
442d1d35e2fSjeremylt                                   rstr_coarse, basis_coarse, CEED_VECTOR_ACTIVE);
443d99fa3c5SJeremy L Thompson       CeedChk(ierr);
444d99fa3c5SJeremy L Thompson     } else {
445d1d35e2fSjeremylt       ierr = CeedOperatorSetField(*op_coarse, op_fine->output_fields[i]->field_name,
446d1d35e2fSjeremylt                                   op_fine->output_fields[i]->elem_restr,
447d1d35e2fSjeremylt                                   op_fine->output_fields[i]->basis,
448d1d35e2fSjeremylt                                   op_fine->output_fields[i]->vec); CeedChk(ierr);
449d99fa3c5SJeremy L Thompson     }
450d99fa3c5SJeremy L Thompson   }
451d99fa3c5SJeremy L Thompson 
452d99fa3c5SJeremy L Thompson   // Multiplicity vector
453d1d35e2fSjeremylt   CeedVector mult_vec, mult_e_vec;
454d1d35e2fSjeremylt   ierr = CeedElemRestrictionCreateVector(rstr_fine, &mult_vec, &mult_e_vec);
455d99fa3c5SJeremy L Thompson   CeedChk(ierr);
456d1d35e2fSjeremylt   ierr = CeedVectorSetValue(mult_e_vec, 0.0); CeedChk(ierr);
457d1d35e2fSjeremylt   ierr = CeedElemRestrictionApply(rstr_fine, CEED_NOTRANSPOSE, p_mult_fine,
458d1d35e2fSjeremylt                                   mult_e_vec, CEED_REQUEST_IMMEDIATE); CeedChk(ierr);
459d1d35e2fSjeremylt   ierr = CeedVectorSetValue(mult_vec, 0.0); CeedChk(ierr);
460d1d35e2fSjeremylt   ierr = CeedElemRestrictionApply(rstr_fine, CEED_TRANSPOSE, mult_e_vec, mult_vec,
461d99fa3c5SJeremy L Thompson                                   CEED_REQUEST_IMMEDIATE); CeedChk(ierr);
462d1d35e2fSjeremylt   ierr = CeedVectorDestroy(&mult_e_vec); CeedChk(ierr);
463d1d35e2fSjeremylt   ierr = CeedVectorReciprocal(mult_vec); CeedChk(ierr);
464d99fa3c5SJeremy L Thompson 
465d99fa3c5SJeremy L Thompson   // Restriction
466d1d35e2fSjeremylt   CeedInt num_comp;
467d1d35e2fSjeremylt   ierr = CeedBasisGetNumComponents(basis_coarse, &num_comp); CeedChk(ierr);
468d1d35e2fSjeremylt   CeedQFunction qf_restrict;
469d1d35e2fSjeremylt   ierr = CeedQFunctionCreateInteriorByName(ceed, "Scale", &qf_restrict);
470d99fa3c5SJeremy L Thompson   CeedChk(ierr);
471d1d35e2fSjeremylt   CeedInt *num_comp_r_data;
472d1d35e2fSjeremylt   ierr = CeedCalloc(1, &num_comp_r_data); CeedChk(ierr);
473d1d35e2fSjeremylt   num_comp_r_data[0] = num_comp;
474d1d35e2fSjeremylt   CeedQFunctionContext ctx_r;
475d1d35e2fSjeremylt   ierr = CeedQFunctionContextCreate(ceed, &ctx_r); CeedChk(ierr);
476d1d35e2fSjeremylt   ierr = CeedQFunctionContextSetData(ctx_r, CEED_MEM_HOST, CEED_OWN_POINTER,
477d1d35e2fSjeremylt                                      sizeof(*num_comp_r_data), num_comp_r_data);
478777ff853SJeremy L Thompson   CeedChk(ierr);
479d1d35e2fSjeremylt   ierr = CeedQFunctionSetContext(qf_restrict, ctx_r); CeedChk(ierr);
480d1d35e2fSjeremylt   ierr = CeedQFunctionContextDestroy(&ctx_r); CeedChk(ierr);
481d1d35e2fSjeremylt   ierr = CeedQFunctionAddInput(qf_restrict, "input", num_comp, CEED_EVAL_NONE);
482d99fa3c5SJeremy L Thompson   CeedChk(ierr);
483d1d35e2fSjeremylt   ierr = CeedQFunctionAddInput(qf_restrict, "scale", num_comp, CEED_EVAL_NONE);
484d99fa3c5SJeremy L Thompson   CeedChk(ierr);
485d1d35e2fSjeremylt   ierr = CeedQFunctionAddOutput(qf_restrict, "output", num_comp,
486d1d35e2fSjeremylt                                 CEED_EVAL_INTERP); CeedChk(ierr);
487d99fa3c5SJeremy L Thompson 
488d1d35e2fSjeremylt   ierr = CeedOperatorCreate(ceed, qf_restrict, CEED_QFUNCTION_NONE,
489d1d35e2fSjeremylt                             CEED_QFUNCTION_NONE, op_restrict);
490d99fa3c5SJeremy L Thompson   CeedChk(ierr);
491d1d35e2fSjeremylt   ierr = CeedOperatorSetField(*op_restrict, "input", rstr_fine,
492d99fa3c5SJeremy L Thompson                               CEED_BASIS_COLLOCATED, CEED_VECTOR_ACTIVE);
493d99fa3c5SJeremy L Thompson   CeedChk(ierr);
494d1d35e2fSjeremylt   ierr = CeedOperatorSetField(*op_restrict, "scale", rstr_fine,
495d1d35e2fSjeremylt                               CEED_BASIS_COLLOCATED, mult_vec);
496d99fa3c5SJeremy L Thompson   CeedChk(ierr);
497d1d35e2fSjeremylt   ierr = CeedOperatorSetField(*op_restrict, "output", rstr_coarse, basis_c_to_f,
498d99fa3c5SJeremy L Thompson                               CEED_VECTOR_ACTIVE); CeedChk(ierr);
499d99fa3c5SJeremy L Thompson 
500d99fa3c5SJeremy L Thompson   // Prolongation
501d1d35e2fSjeremylt   CeedQFunction qf_prolong;
502d1d35e2fSjeremylt   ierr = CeedQFunctionCreateInteriorByName(ceed, "Scale", &qf_prolong);
503d99fa3c5SJeremy L Thompson   CeedChk(ierr);
504d1d35e2fSjeremylt   CeedInt *num_comp_p_data;
505d1d35e2fSjeremylt   ierr = CeedCalloc(1, &num_comp_p_data); CeedChk(ierr);
506d1d35e2fSjeremylt   num_comp_p_data[0] = num_comp;
507d1d35e2fSjeremylt   CeedQFunctionContext ctx_p;
508d1d35e2fSjeremylt   ierr = CeedQFunctionContextCreate(ceed, &ctx_p); CeedChk(ierr);
509d1d35e2fSjeremylt   ierr = CeedQFunctionContextSetData(ctx_p, CEED_MEM_HOST, CEED_OWN_POINTER,
510d1d35e2fSjeremylt                                      sizeof(*num_comp_p_data), num_comp_p_data);
511777ff853SJeremy L Thompson   CeedChk(ierr);
512d1d35e2fSjeremylt   ierr = CeedQFunctionSetContext(qf_prolong, ctx_p); CeedChk(ierr);
513d1d35e2fSjeremylt   ierr = CeedQFunctionContextDestroy(&ctx_p); CeedChk(ierr);
514d1d35e2fSjeremylt   ierr = CeedQFunctionAddInput(qf_prolong, "input", num_comp, CEED_EVAL_INTERP);
515d99fa3c5SJeremy L Thompson   CeedChk(ierr);
516d1d35e2fSjeremylt   ierr = CeedQFunctionAddInput(qf_prolong, "scale", num_comp, CEED_EVAL_NONE);
517d99fa3c5SJeremy L Thompson   CeedChk(ierr);
518d1d35e2fSjeremylt   ierr = CeedQFunctionAddOutput(qf_prolong, "output", num_comp, CEED_EVAL_NONE);
519d99fa3c5SJeremy L Thompson   CeedChk(ierr);
520d99fa3c5SJeremy L Thompson 
521d1d35e2fSjeremylt   ierr = CeedOperatorCreate(ceed, qf_prolong, CEED_QFUNCTION_NONE,
522d1d35e2fSjeremylt                             CEED_QFUNCTION_NONE, op_prolong);
523d99fa3c5SJeremy L Thompson   CeedChk(ierr);
524d1d35e2fSjeremylt   ierr = CeedOperatorSetField(*op_prolong, "input", rstr_coarse, basis_c_to_f,
525d99fa3c5SJeremy L Thompson                               CEED_VECTOR_ACTIVE); CeedChk(ierr);
526d1d35e2fSjeremylt   ierr = CeedOperatorSetField(*op_prolong, "scale", rstr_fine,
527d1d35e2fSjeremylt                               CEED_BASIS_COLLOCATED, mult_vec);
528d99fa3c5SJeremy L Thompson   CeedChk(ierr);
529d1d35e2fSjeremylt   ierr = CeedOperatorSetField(*op_prolong, "output", rstr_fine,
530d99fa3c5SJeremy L Thompson                               CEED_BASIS_COLLOCATED, CEED_VECTOR_ACTIVE);
531d99fa3c5SJeremy L Thompson   CeedChk(ierr);
532d99fa3c5SJeremy L Thompson 
533d99fa3c5SJeremy L Thompson   // Cleanup
534d1d35e2fSjeremylt   ierr = CeedVectorDestroy(&mult_vec); CeedChk(ierr);
535d1d35e2fSjeremylt   ierr = CeedBasisDestroy(&basis_c_to_f); CeedChk(ierr);
536d1d35e2fSjeremylt   ierr = CeedQFunctionDestroy(&qf_restrict); CeedChk(ierr);
537d1d35e2fSjeremylt   ierr = CeedQFunctionDestroy(&qf_prolong); CeedChk(ierr);
538e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
539d99fa3c5SJeremy L Thompson }
540d99fa3c5SJeremy L Thompson 
5417a982d89SJeremy L. Thompson /// @}
5427a982d89SJeremy L. Thompson 
5437a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
5447a982d89SJeremy L. Thompson /// CeedOperator Backend API
5457a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
5467a982d89SJeremy L. Thompson /// @addtogroup CeedOperatorBackend
5477a982d89SJeremy L. Thompson /// @{
5487a982d89SJeremy L. Thompson 
5497a982d89SJeremy L. Thompson /**
5507a982d89SJeremy L. Thompson   @brief Get the Ceed associated with a CeedOperator
5517a982d89SJeremy L. Thompson 
5527a982d89SJeremy L. Thompson   @param op         CeedOperator
5537a982d89SJeremy L. Thompson   @param[out] ceed  Variable to store Ceed
5547a982d89SJeremy L. Thompson 
5557a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5567a982d89SJeremy L. Thompson 
5577a982d89SJeremy L. Thompson   @ref Backend
5587a982d89SJeremy L. Thompson **/
5597a982d89SJeremy L. Thompson 
5607a982d89SJeremy L. Thompson int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) {
5617a982d89SJeremy L. Thompson   *ceed = op->ceed;
562e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5637a982d89SJeremy L. Thompson }
5647a982d89SJeremy L. Thompson 
5657a982d89SJeremy L. Thompson /**
5667a982d89SJeremy L. Thompson   @brief Get the number of elements associated with a CeedOperator
5677a982d89SJeremy L. Thompson 
5687a982d89SJeremy L. Thompson   @param op             CeedOperator
569d1d35e2fSjeremylt   @param[out] num_elem  Variable to store number of elements
5707a982d89SJeremy L. Thompson 
5717a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5727a982d89SJeremy L. Thompson 
5737a982d89SJeremy L. Thompson   @ref Backend
5747a982d89SJeremy L. Thompson **/
5757a982d89SJeremy L. Thompson 
576d1d35e2fSjeremylt int CeedOperatorGetNumElements(CeedOperator op, CeedInt *num_elem) {
5777a982d89SJeremy L. Thompson   if (op->composite)
5787a982d89SJeremy L. Thompson     // LCOV_EXCL_START
579e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
580e15f9bd0SJeremy L Thompson                      "Not defined for composite operator");
5817a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
5827a982d89SJeremy L. Thompson 
583d1d35e2fSjeremylt   *num_elem = op->num_elem;
584e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5857a982d89SJeremy L. Thompson }
5867a982d89SJeremy L. Thompson 
5877a982d89SJeremy L. Thompson /**
5887a982d89SJeremy L. Thompson   @brief Get the number of quadrature points associated with a CeedOperator
5897a982d89SJeremy L. Thompson 
5907a982d89SJeremy L. Thompson   @param op             CeedOperator
591d1d35e2fSjeremylt   @param[out] num_qpts  Variable to store vector number of quadrature points
5927a982d89SJeremy L. Thompson 
5937a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5947a982d89SJeremy L. Thompson 
5957a982d89SJeremy L. Thompson   @ref Backend
5967a982d89SJeremy L. Thompson **/
5977a982d89SJeremy L. Thompson 
598d1d35e2fSjeremylt int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *num_qpts) {
5997a982d89SJeremy L. Thompson   if (op->composite)
6007a982d89SJeremy L. Thompson     // LCOV_EXCL_START
601e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
602e15f9bd0SJeremy L Thompson                      "Not defined for composite operator");
6037a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
6047a982d89SJeremy L. Thompson 
605d1d35e2fSjeremylt   *num_qpts = op->num_qpts;
606e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6077a982d89SJeremy L. Thompson }
6087a982d89SJeremy L. Thompson 
6097a982d89SJeremy L. Thompson /**
6107a982d89SJeremy L. Thompson   @brief Get the number of arguments associated with a CeedOperator
6117a982d89SJeremy L. Thompson 
6127a982d89SJeremy L. Thompson   @param op             CeedOperator
613d1d35e2fSjeremylt   @param[out] num_args  Variable to store vector number of arguments
6147a982d89SJeremy L. Thompson 
6157a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6167a982d89SJeremy L. Thompson 
6177a982d89SJeremy L. Thompson   @ref Backend
6187a982d89SJeremy L. Thompson **/
6197a982d89SJeremy L. Thompson 
620d1d35e2fSjeremylt int CeedOperatorGetNumArgs(CeedOperator op, CeedInt *num_args) {
6217a982d89SJeremy L. Thompson   if (op->composite)
6227a982d89SJeremy L. Thompson     // LCOV_EXCL_START
623e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
624e15f9bd0SJeremy L Thompson                      "Not defined for composite operators");
6257a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
6267a982d89SJeremy L. Thompson 
627d1d35e2fSjeremylt   *num_args = op->num_fields;
628e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6297a982d89SJeremy L. Thompson }
6307a982d89SJeremy L. Thompson 
6317a982d89SJeremy L. Thompson /**
6327a982d89SJeremy L. Thompson   @brief Get the setup status of a CeedOperator
6337a982d89SJeremy L. Thompson 
6347a982d89SJeremy L. Thompson   @param op                  CeedOperator
635d1d35e2fSjeremylt   @param[out] is_setup_done  Variable to store setup status
6367a982d89SJeremy L. Thompson 
6377a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6387a982d89SJeremy L. Thompson 
6397a982d89SJeremy L. Thompson   @ref Backend
6407a982d89SJeremy L. Thompson **/
6417a982d89SJeremy L. Thompson 
642d1d35e2fSjeremylt int CeedOperatorIsSetupDone(CeedOperator op, bool *is_setup_done) {
643d1d35e2fSjeremylt   *is_setup_done = op->backend_setup;
644e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6457a982d89SJeremy L. Thompson }
6467a982d89SJeremy L. Thompson 
6477a982d89SJeremy L. Thompson /**
6487a982d89SJeremy L. Thompson   @brief Get the QFunction associated with a CeedOperator
6497a982d89SJeremy L. Thompson 
6507a982d89SJeremy L. Thompson   @param op       CeedOperator
6517a982d89SJeremy L. Thompson   @param[out] qf  Variable to store QFunction
6527a982d89SJeremy L. Thompson 
6537a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6547a982d89SJeremy L. Thompson 
6557a982d89SJeremy L. Thompson   @ref Backend
6567a982d89SJeremy L. Thompson **/
6577a982d89SJeremy L. Thompson 
6587a982d89SJeremy L. Thompson int CeedOperatorGetQFunction(CeedOperator op, CeedQFunction *qf) {
6597a982d89SJeremy L. Thompson   if (op->composite)
6607a982d89SJeremy L. Thompson     // LCOV_EXCL_START
661e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
662e15f9bd0SJeremy L Thompson                      "Not defined for composite operator");
6637a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
6647a982d89SJeremy L. Thompson 
6657a982d89SJeremy L. Thompson   *qf = op->qf;
666e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6677a982d89SJeremy L. Thompson }
6687a982d89SJeremy L. Thompson 
6697a982d89SJeremy L. Thompson /**
670c04a41a7SJeremy L Thompson   @brief Get a boolean value indicating if the CeedOperator is composite
671c04a41a7SJeremy L Thompson 
672c04a41a7SJeremy L Thompson   @param op                 CeedOperator
673d1d35e2fSjeremylt   @param[out] is_composite  Variable to store composite status
674c04a41a7SJeremy L Thompson 
675c04a41a7SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
676c04a41a7SJeremy L Thompson 
677c04a41a7SJeremy L Thompson   @ref Backend
678c04a41a7SJeremy L Thompson **/
679c04a41a7SJeremy L Thompson 
680d1d35e2fSjeremylt int CeedOperatorIsComposite(CeedOperator op, bool *is_composite) {
681d1d35e2fSjeremylt   *is_composite = op->composite;
682e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
683c04a41a7SJeremy L Thompson }
684c04a41a7SJeremy L Thompson 
685c04a41a7SJeremy L Thompson /**
686d1d35e2fSjeremylt   @brief Get the number of sub_operators associated with a CeedOperator
6877a982d89SJeremy L. Thompson 
6887a982d89SJeremy L. Thompson   @param op                     CeedOperator
689d1d35e2fSjeremylt   @param[out] num_suboperators  Variable to store number of sub_operators
6907a982d89SJeremy L. Thompson 
6917a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6927a982d89SJeremy L. Thompson 
6937a982d89SJeremy L. Thompson   @ref Backend
6947a982d89SJeremy L. Thompson **/
6957a982d89SJeremy L. Thompson 
696d1d35e2fSjeremylt int CeedOperatorGetNumSub(CeedOperator op, CeedInt *num_suboperators) {
6977a982d89SJeremy L. Thompson   if (!op->composite)
6987a982d89SJeremy L. Thompson     // LCOV_EXCL_START
699e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR, "Not a composite operator");
7007a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
7017a982d89SJeremy L. Thompson 
702d1d35e2fSjeremylt   *num_suboperators = op->num_suboperators;
703e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
7047a982d89SJeremy L. Thompson }
7057a982d89SJeremy L. Thompson 
7067a982d89SJeremy L. Thompson /**
707d1d35e2fSjeremylt   @brief Get the list of sub_operators associated with a CeedOperator
7087a982d89SJeremy L. Thompson 
7097a982d89SJeremy L. Thompson   @param op                  CeedOperator
710d1d35e2fSjeremylt   @param[out] sub_operators  Variable to store list of sub_operators
7117a982d89SJeremy L. Thompson 
7127a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
7137a982d89SJeremy L. Thompson 
7147a982d89SJeremy L. Thompson   @ref Backend
7157a982d89SJeremy L. Thompson **/
7167a982d89SJeremy L. Thompson 
717d1d35e2fSjeremylt int CeedOperatorGetSubList(CeedOperator op, CeedOperator **sub_operators) {
7187a982d89SJeremy L. Thompson   if (!op->composite)
7197a982d89SJeremy L. Thompson     // LCOV_EXCL_START
720e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR, "Not a composite operator");
7217a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
7227a982d89SJeremy L. Thompson 
723d1d35e2fSjeremylt   *sub_operators = op->sub_operators;
724e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
7257a982d89SJeremy L. Thompson }
7267a982d89SJeremy L. Thompson 
7277a982d89SJeremy L. Thompson /**
7287a982d89SJeremy L. Thompson   @brief Get the backend data of a CeedOperator
7297a982d89SJeremy L. Thompson 
7307a982d89SJeremy L. Thompson   @param op         CeedOperator
7317a982d89SJeremy L. Thompson   @param[out] data  Variable to store data
7327a982d89SJeremy L. Thompson 
7337a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
7347a982d89SJeremy L. Thompson 
7357a982d89SJeremy L. Thompson   @ref Backend
7367a982d89SJeremy L. Thompson **/
7377a982d89SJeremy L. Thompson 
738777ff853SJeremy L Thompson int CeedOperatorGetData(CeedOperator op, void *data) {
739777ff853SJeremy L Thompson   *(void **)data = op->data;
740e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
7417a982d89SJeremy L. Thompson }
7427a982d89SJeremy L. Thompson 
7437a982d89SJeremy L. Thompson /**
7447a982d89SJeremy L. Thompson   @brief Set the backend data of a CeedOperator
7457a982d89SJeremy L. Thompson 
7467a982d89SJeremy L. Thompson   @param[out] op  CeedOperator
7477a982d89SJeremy L. Thompson   @param data     Data to set
7487a982d89SJeremy L. Thompson 
7497a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
7507a982d89SJeremy L. Thompson 
7517a982d89SJeremy L. Thompson   @ref Backend
7527a982d89SJeremy L. Thompson **/
7537a982d89SJeremy L. Thompson 
754777ff853SJeremy L Thompson int CeedOperatorSetData(CeedOperator op, void *data) {
755777ff853SJeremy L Thompson   op->data = data;
756e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
7577a982d89SJeremy L. Thompson }
7587a982d89SJeremy L. Thompson 
7597a982d89SJeremy L. Thompson /**
7607a982d89SJeremy L. Thompson   @brief Set the setup flag of a CeedOperator to True
7617a982d89SJeremy L. Thompson 
7627a982d89SJeremy L. Thompson   @param op  CeedOperator
7637a982d89SJeremy L. Thompson 
7647a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
7657a982d89SJeremy L. Thompson 
7667a982d89SJeremy L. Thompson   @ref Backend
7677a982d89SJeremy L. Thompson **/
7687a982d89SJeremy L. Thompson 
7697a982d89SJeremy L. Thompson int CeedOperatorSetSetupDone(CeedOperator op) {
770d1d35e2fSjeremylt   op->backend_setup = true;
771e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
7727a982d89SJeremy L. Thompson }
7737a982d89SJeremy L. Thompson 
7747a982d89SJeremy L. Thompson /**
7757a982d89SJeremy L. Thompson   @brief Get the CeedOperatorFields of a CeedOperator
7767a982d89SJeremy L. Thompson 
7777a982d89SJeremy L. Thompson   @param op                  CeedOperator
778d1d35e2fSjeremylt   @param[out] input_fields   Variable to store input_fields
779d1d35e2fSjeremylt   @param[out] output_fields  Variable to store output_fields
7807a982d89SJeremy L. Thompson 
7817a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
7827a982d89SJeremy L. Thompson 
7837a982d89SJeremy L. Thompson   @ref Backend
7847a982d89SJeremy L. Thompson **/
7857a982d89SJeremy L. Thompson 
786d1d35e2fSjeremylt int CeedOperatorGetFields(CeedOperator op, CeedOperatorField **input_fields,
787d1d35e2fSjeremylt                           CeedOperatorField **output_fields) {
7887a982d89SJeremy L. Thompson   if (op->composite)
7897a982d89SJeremy L. Thompson     // LCOV_EXCL_START
790e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
791e15f9bd0SJeremy L Thompson                      "Not defined for composite operator");
7927a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
7937a982d89SJeremy L. Thompson 
794d1d35e2fSjeremylt   if (input_fields) *input_fields = op->input_fields;
795d1d35e2fSjeremylt   if (output_fields) *output_fields = op->output_fields;
796e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
7977a982d89SJeremy L. Thompson }
7987a982d89SJeremy L. Thompson 
7997a982d89SJeremy L. Thompson /**
8007a982d89SJeremy L. Thompson   @brief Get the CeedElemRestriction of a CeedOperatorField
8017a982d89SJeremy L. Thompson 
802d1d35e2fSjeremylt   @param op_field   CeedOperatorField
8037a982d89SJeremy L. Thompson   @param[out] rstr  Variable to store CeedElemRestriction
8047a982d89SJeremy L. Thompson 
8057a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
8067a982d89SJeremy L. Thompson 
8077a982d89SJeremy L. Thompson   @ref Backend
8087a982d89SJeremy L. Thompson **/
8097a982d89SJeremy L. Thompson 
810d1d35e2fSjeremylt int CeedOperatorFieldGetElemRestriction(CeedOperatorField op_field,
8117a982d89SJeremy L. Thompson                                         CeedElemRestriction *rstr) {
812d1d35e2fSjeremylt   *rstr = op_field->elem_restr;
813e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
8147a982d89SJeremy L. Thompson }
8157a982d89SJeremy L. Thompson 
8167a982d89SJeremy L. Thompson /**
8177a982d89SJeremy L. Thompson   @brief Get the CeedBasis of a CeedOperatorField
8187a982d89SJeremy L. Thompson 
819d1d35e2fSjeremylt   @param op_field    CeedOperatorField
8207a982d89SJeremy L. Thompson   @param[out] basis  Variable to store CeedBasis
8217a982d89SJeremy L. Thompson 
8227a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
8237a982d89SJeremy L. Thompson 
8247a982d89SJeremy L. Thompson   @ref Backend
8257a982d89SJeremy L. Thompson **/
8267a982d89SJeremy L. Thompson 
827d1d35e2fSjeremylt int CeedOperatorFieldGetBasis(CeedOperatorField op_field, CeedBasis *basis) {
828d1d35e2fSjeremylt   *basis = op_field->basis;
829e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
8307a982d89SJeremy L. Thompson }
8317a982d89SJeremy L. Thompson 
8327a982d89SJeremy L. Thompson /**
8337a982d89SJeremy L. Thompson   @brief Get the CeedVector of a CeedOperatorField
8347a982d89SJeremy L. Thompson 
835d1d35e2fSjeremylt   @param op_field  CeedOperatorField
8367a982d89SJeremy L. Thompson   @param[out] vec  Variable to store CeedVector
8377a982d89SJeremy L. Thompson 
8387a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
8397a982d89SJeremy L. Thompson 
8407a982d89SJeremy L. Thompson   @ref Backend
8417a982d89SJeremy L. Thompson **/
8427a982d89SJeremy L. Thompson 
843d1d35e2fSjeremylt int CeedOperatorFieldGetVector(CeedOperatorField op_field, CeedVector *vec) {
844d1d35e2fSjeremylt   *vec = op_field->vec;
845e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
8467a982d89SJeremy L. Thompson }
8477a982d89SJeremy L. Thompson 
8487a982d89SJeremy L. Thompson /// @}
8497a982d89SJeremy L. Thompson 
8507a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
8517a982d89SJeremy L. Thompson /// CeedOperator Public API
8527a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
8537a982d89SJeremy L. Thompson /// @addtogroup CeedOperatorUser
854dfdf5a53Sjeremylt /// @{
855d7b241e6Sjeremylt 
856d7b241e6Sjeremylt /**
8570219ea01SJeremy L Thompson   @brief Create a CeedOperator and associate a CeedQFunction. A CeedBasis and
8580219ea01SJeremy L Thompson            CeedElemRestriction can be associated with CeedQFunction fields with
8590219ea01SJeremy L Thompson            \ref CeedOperatorSetField.
860d7b241e6Sjeremylt 
861b11c1e72Sjeremylt   @param ceed     A Ceed object where the CeedOperator will be created
862d7b241e6Sjeremylt   @param qf       QFunction defining the action of the operator at quadrature points
86334138859Sjeremylt   @param dqf      QFunction defining the action of the Jacobian of @a qf (or
8644cc79fe7SJed Brown                     @ref CEED_QFUNCTION_NONE)
865d7b241e6Sjeremylt   @param dqfT     QFunction defining the action of the transpose of the Jacobian
8664cc79fe7SJed Brown                     of @a qf (or @ref CEED_QFUNCTION_NONE)
867b11c1e72Sjeremylt   @param[out] op  Address of the variable where the newly created
868b11c1e72Sjeremylt                     CeedOperator will be stored
869b11c1e72Sjeremylt 
870b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
871dfdf5a53Sjeremylt 
8727a982d89SJeremy L. Thompson   @ref User
873d7b241e6Sjeremylt  */
874d7b241e6Sjeremylt int CeedOperatorCreate(Ceed ceed, CeedQFunction qf, CeedQFunction dqf,
875d7b241e6Sjeremylt                        CeedQFunction dqfT, CeedOperator *op) {
876d7b241e6Sjeremylt   int ierr;
877d7b241e6Sjeremylt 
8785fe0d4faSjeremylt   if (!ceed->OperatorCreate) {
8795fe0d4faSjeremylt     Ceed delegate;
880aefd8378Sjeremylt     ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr);
8815fe0d4faSjeremylt 
8825fe0d4faSjeremylt     if (!delegate)
883c042f62fSJeremy L Thompson       // LCOV_EXCL_START
884e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_UNSUPPORTED,
885e15f9bd0SJeremy L Thompson                        "Backend does not support OperatorCreate");
886c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
8875fe0d4faSjeremylt 
8885fe0d4faSjeremylt     ierr = CeedOperatorCreate(delegate, qf, dqf, dqfT, op); CeedChk(ierr);
889e15f9bd0SJeremy L Thompson     return CEED_ERROR_SUCCESS;
8905fe0d4faSjeremylt   }
8915fe0d4faSjeremylt 
892b3b7035fSJeremy L Thompson   if (!qf || qf == CEED_QFUNCTION_NONE)
893b3b7035fSJeremy L Thompson     // LCOV_EXCL_START
894e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_MINOR,
895e15f9bd0SJeremy L Thompson                      "Operator must have a valid QFunction.");
896b3b7035fSJeremy L Thompson   // LCOV_EXCL_STOP
897d7b241e6Sjeremylt   ierr = CeedCalloc(1, op); CeedChk(ierr);
898d7b241e6Sjeremylt   (*op)->ceed = ceed;
899d1d35e2fSjeremylt   ceed->ref_count++;
900d1d35e2fSjeremylt   (*op)->ref_count = 1;
901d7b241e6Sjeremylt   (*op)->qf = qf;
902d1d35e2fSjeremylt   qf->ref_count++;
903442e7f0bSjeremylt   if (dqf && dqf != CEED_QFUNCTION_NONE) {
904d7b241e6Sjeremylt     (*op)->dqf = dqf;
905d1d35e2fSjeremylt     dqf->ref_count++;
906442e7f0bSjeremylt   }
907442e7f0bSjeremylt   if (dqfT && dqfT != CEED_QFUNCTION_NONE) {
908d7b241e6Sjeremylt     (*op)->dqfT = dqfT;
909d1d35e2fSjeremylt     dqfT->ref_count++;
910442e7f0bSjeremylt   }
911d1d35e2fSjeremylt   ierr = CeedCalloc(16, &(*op)->input_fields); CeedChk(ierr);
912d1d35e2fSjeremylt   ierr = CeedCalloc(16, &(*op)->output_fields); CeedChk(ierr);
913d7b241e6Sjeremylt   ierr = ceed->OperatorCreate(*op); CeedChk(ierr);
914e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
915d7b241e6Sjeremylt }
916d7b241e6Sjeremylt 
917d7b241e6Sjeremylt /**
91852d6035fSJeremy L Thompson   @brief Create an operator that composes the action of several operators
91952d6035fSJeremy L Thompson 
92052d6035fSJeremy L Thompson   @param ceed     A Ceed object where the CeedOperator will be created
92152d6035fSJeremy L Thompson   @param[out] op  Address of the variable where the newly created
92252d6035fSJeremy L Thompson                     Composite CeedOperator will be stored
92352d6035fSJeremy L Thompson 
92452d6035fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
92552d6035fSJeremy L Thompson 
9267a982d89SJeremy L. Thompson   @ref User
92752d6035fSJeremy L Thompson  */
92852d6035fSJeremy L Thompson int CeedCompositeOperatorCreate(Ceed ceed, CeedOperator *op) {
92952d6035fSJeremy L Thompson   int ierr;
93052d6035fSJeremy L Thompson 
93152d6035fSJeremy L Thompson   if (!ceed->CompositeOperatorCreate) {
93252d6035fSJeremy L Thompson     Ceed delegate;
933aefd8378Sjeremylt     ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr);
93452d6035fSJeremy L Thompson 
935250756a7Sjeremylt     if (delegate) {
93652d6035fSJeremy L Thompson       ierr = CeedCompositeOperatorCreate(delegate, op); CeedChk(ierr);
937e15f9bd0SJeremy L Thompson       return CEED_ERROR_SUCCESS;
93852d6035fSJeremy L Thompson     }
939250756a7Sjeremylt   }
94052d6035fSJeremy L Thompson 
94152d6035fSJeremy L Thompson   ierr = CeedCalloc(1, op); CeedChk(ierr);
94252d6035fSJeremy L Thompson   (*op)->ceed = ceed;
943d1d35e2fSjeremylt   ceed->ref_count++;
94452d6035fSJeremy L Thompson   (*op)->composite = true;
945d1d35e2fSjeremylt   ierr = CeedCalloc(16, &(*op)->sub_operators); CeedChk(ierr);
946250756a7Sjeremylt 
947250756a7Sjeremylt   if (ceed->CompositeOperatorCreate) {
94852d6035fSJeremy L Thompson     ierr = ceed->CompositeOperatorCreate(*op); CeedChk(ierr);
949250756a7Sjeremylt   }
950e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
95152d6035fSJeremy L Thompson }
95252d6035fSJeremy L Thompson 
95352d6035fSJeremy L Thompson /**
954b11c1e72Sjeremylt   @brief Provide a field to a CeedOperator for use by its CeedQFunction
955d7b241e6Sjeremylt 
956d7b241e6Sjeremylt   This function is used to specify both active and passive fields to a
957d7b241e6Sjeremylt   CeedOperator.  For passive fields, a vector @arg v must be provided.  Passive
958d7b241e6Sjeremylt   fields can inputs or outputs (updated in-place when operator is applied).
959d7b241e6Sjeremylt 
960d7b241e6Sjeremylt   Active fields must be specified using this function, but their data (in a
961d7b241e6Sjeremylt   CeedVector) is passed in CeedOperatorApply().  There can be at most one active
962d7b241e6Sjeremylt   input and at most one active output.
963d7b241e6Sjeremylt 
9648c91a0c9SJeremy L Thompson   @param op          CeedOperator on which to provide the field
965d1d35e2fSjeremylt   @param field_name  Name of the field (to be matched with the name used by
9668795c945Sjeremylt                        CeedQFunction)
967b11c1e72Sjeremylt   @param r           CeedElemRestriction
9684cc79fe7SJed Brown   @param b           CeedBasis in which the field resides or @ref CEED_BASIS_COLLOCATED
969b11c1e72Sjeremylt                        if collocated with quadrature points
9704cc79fe7SJed Brown   @param v           CeedVector to be used by CeedOperator or @ref CEED_VECTOR_ACTIVE
9714cc79fe7SJed Brown                        if field is active or @ref CEED_VECTOR_NONE if using
9724cc79fe7SJed Brown                        @ref CEED_EVAL_WEIGHT in the QFunction
973b11c1e72Sjeremylt 
974b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
975dfdf5a53Sjeremylt 
9767a982d89SJeremy L. Thompson   @ref User
977b11c1e72Sjeremylt **/
978d1d35e2fSjeremylt int CeedOperatorSetField(CeedOperator op, const char *field_name,
979a8d32208Sjeremylt                          CeedElemRestriction r, CeedBasis b, CeedVector v) {
980d7b241e6Sjeremylt   int ierr;
98152d6035fSJeremy L Thompson   if (op->composite)
982c042f62fSJeremy L Thompson     // LCOV_EXCL_START
983e1e9e29dSJed Brown     return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
984e15f9bd0SJeremy L Thompson                      "Cannot add field to composite operator.");
985c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
9868b067b84SJed Brown   if (!r)
987c042f62fSJeremy L Thompson     // LCOV_EXCL_START
988e1e9e29dSJed Brown     return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
989c042f62fSJeremy L Thompson                      "ElemRestriction r for field \"%s\" must be non-NULL.",
990d1d35e2fSjeremylt                      field_name);
991c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
9928b067b84SJed Brown   if (!b)
993c042f62fSJeremy L Thompson     // LCOV_EXCL_START
994e1e9e29dSJed Brown     return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
995e15f9bd0SJeremy L Thompson                      "Basis b for field \"%s\" must be non-NULL.",
996d1d35e2fSjeremylt                      field_name);
997c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
9988b067b84SJed Brown   if (!v)
999c042f62fSJeremy L Thompson     // LCOV_EXCL_START
1000e1e9e29dSJed Brown     return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
1001e15f9bd0SJeremy L Thompson                      "Vector v for field \"%s\" must be non-NULL.",
1002d1d35e2fSjeremylt                      field_name);
1003c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
100452d6035fSJeremy L Thompson 
1005d1d35e2fSjeremylt   CeedInt num_elem;
1006d1d35e2fSjeremylt   ierr = CeedElemRestrictionGetNumElements(r, &num_elem); CeedChk(ierr);
1007d1d35e2fSjeremylt   if (r != CEED_ELEMRESTRICTION_NONE && op->has_restriction &&
1008d1d35e2fSjeremylt       op->num_elem != num_elem)
1009c042f62fSJeremy L Thompson     // LCOV_EXCL_START
1010e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_DIMENSION,
10111d102b48SJeremy L Thompson                      "ElemRestriction with %d elements incompatible with prior "
1012d1d35e2fSjeremylt                      "%d elements", num_elem, op->num_elem);
1013c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
1014d7b241e6Sjeremylt 
1015*78464608Sjeremylt   CeedInt num_qpts = 0;
1016e15f9bd0SJeremy L Thompson   if (b != CEED_BASIS_COLLOCATED) {
1017d1d35e2fSjeremylt     ierr = CeedBasisGetNumQuadraturePoints(b, &num_qpts); CeedChk(ierr);
1018d1d35e2fSjeremylt     if (op->num_qpts && op->num_qpts != num_qpts)
1019c042f62fSJeremy L Thompson       // LCOV_EXCL_START
1020e15f9bd0SJeremy L Thompson       return CeedError(op->ceed, CEED_ERROR_DIMENSION,
1021e15f9bd0SJeremy L Thompson                        "Basis with %d quadrature points "
1022d1d35e2fSjeremylt                        "incompatible with prior %d points", num_qpts,
1023d1d35e2fSjeremylt                        op->num_qpts);
1024c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
1025d7b241e6Sjeremylt   }
1026d1d35e2fSjeremylt   CeedQFunctionField qf_field;
1027d1d35e2fSjeremylt   CeedOperatorField *op_field;
1028d1d35e2fSjeremylt   for (CeedInt i=0; i<op->qf->num_input_fields; i++) {
1029d1d35e2fSjeremylt     if (!strcmp(field_name, (*op->qf->input_fields[i]).field_name)) {
1030d1d35e2fSjeremylt       qf_field = op->qf->input_fields[i];
1031d1d35e2fSjeremylt       op_field = &op->input_fields[i];
1032d7b241e6Sjeremylt       goto found;
1033d7b241e6Sjeremylt     }
1034d7b241e6Sjeremylt   }
1035d1d35e2fSjeremylt   for (CeedInt i=0; i<op->qf->num_output_fields; i++) {
1036d1d35e2fSjeremylt     if (!strcmp(field_name, (*op->qf->output_fields[i]).field_name)) {
1037d1d35e2fSjeremylt       qf_field = op->qf->output_fields[i];
1038d1d35e2fSjeremylt       op_field = &op->output_fields[i];
1039d7b241e6Sjeremylt       goto found;
1040d7b241e6Sjeremylt     }
1041d7b241e6Sjeremylt   }
1042c042f62fSJeremy L Thompson   // LCOV_EXCL_START
1043e15f9bd0SJeremy L Thompson   return CeedError(op->ceed, CEED_ERROR_INCOMPLETE,
1044e15f9bd0SJeremy L Thompson                    "QFunction has no knowledge of field '%s'",
1045d1d35e2fSjeremylt                    field_name);
1046c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
1047d7b241e6Sjeremylt found:
1048d1d35e2fSjeremylt   ierr = CeedOperatorCheckField(op->ceed, qf_field, r, b); CeedChk(ierr);
1049d1d35e2fSjeremylt   ierr = CeedCalloc(1, op_field); CeedChk(ierr);
1050e15f9bd0SJeremy L Thompson 
1051d1d35e2fSjeremylt   (*op_field)->vec = v;
1052e15f9bd0SJeremy L Thompson   if (v != CEED_VECTOR_ACTIVE && v != CEED_VECTOR_NONE) {
1053d1d35e2fSjeremylt     v->ref_count += 1;
1054e15f9bd0SJeremy L Thompson   }
1055e15f9bd0SJeremy L Thompson 
1056d1d35e2fSjeremylt   (*op_field)->elem_restr = r;
1057d1d35e2fSjeremylt   r->ref_count += 1;
1058e15f9bd0SJeremy L Thompson   if (r != CEED_ELEMRESTRICTION_NONE) {
1059d1d35e2fSjeremylt     op->num_elem = num_elem;
1060d1d35e2fSjeremylt     op->has_restriction = true; // Restriction set, but num_elem may be 0
1061e15f9bd0SJeremy L Thompson   }
1062d99fa3c5SJeremy L Thompson 
1063d1d35e2fSjeremylt   (*op_field)->basis = b;
1064e15f9bd0SJeremy L Thompson   if (b != CEED_BASIS_COLLOCATED) {
1065d1d35e2fSjeremylt     op->num_qpts = num_qpts;
1066d1d35e2fSjeremylt     b->ref_count += 1;
1067e15f9bd0SJeremy L Thompson   }
1068e15f9bd0SJeremy L Thompson 
1069d1d35e2fSjeremylt   op->num_fields += 1;
1070d1d35e2fSjeremylt   size_t len = strlen(field_name);
1071d99fa3c5SJeremy L Thompson   char *tmp;
1072d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(len+1, &tmp); CeedChk(ierr);
1073d1d35e2fSjeremylt   memcpy(tmp, field_name, len+1);
1074d1d35e2fSjeremylt   (*op_field)->field_name = tmp;
1075e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1076d7b241e6Sjeremylt }
1077d7b241e6Sjeremylt 
1078d7b241e6Sjeremylt /**
107952d6035fSJeremy L Thompson   @brief Add a sub-operator to a composite CeedOperator
1080288c0443SJeremy L Thompson 
1081d1d35e2fSjeremylt   @param[out] composite_op  Composite CeedOperator
1082d1d35e2fSjeremylt   @param      sub_op        Sub-operator CeedOperator
108352d6035fSJeremy L Thompson 
108452d6035fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
108552d6035fSJeremy L Thompson 
10867a982d89SJeremy L. Thompson   @ref User
108752d6035fSJeremy L Thompson  */
1088d1d35e2fSjeremylt int CeedCompositeOperatorAddSub(CeedOperator composite_op,
1089d1d35e2fSjeremylt                                 CeedOperator sub_op) {
1090d1d35e2fSjeremylt   if (!composite_op->composite)
1091c042f62fSJeremy L Thompson     // LCOV_EXCL_START
1092d1d35e2fSjeremylt     return CeedError(composite_op->ceed, CEED_ERROR_MINOR,
1093e2f04181SAndrew T. Barker                      "CeedOperator is not a composite operator");
1094c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
109552d6035fSJeremy L Thompson 
1096d1d35e2fSjeremylt   if (composite_op->num_suboperators == CEED_COMPOSITE_MAX)
1097c042f62fSJeremy L Thompson     // LCOV_EXCL_START
1098d1d35e2fSjeremylt     return CeedError(composite_op->ceed, CEED_ERROR_UNSUPPORTED,
1099d1d35e2fSjeremylt                      "Cannot add additional sub_operators");
1100c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
110152d6035fSJeremy L Thompson 
1102d1d35e2fSjeremylt   composite_op->sub_operators[composite_op->num_suboperators] = sub_op;
1103d1d35e2fSjeremylt   sub_op->ref_count++;
1104d1d35e2fSjeremylt   composite_op->num_suboperators++;
1105e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
110652d6035fSJeremy L Thompson }
110752d6035fSJeremy L Thompson 
110852d6035fSJeremy L Thompson /**
11091d102b48SJeremy L Thompson   @brief Assemble a linear CeedQFunction associated with a CeedOperator
11101d102b48SJeremy L Thompson 
11111d102b48SJeremy L Thompson   This returns a CeedVector containing a matrix at each quadrature point
11121d102b48SJeremy L Thompson     providing the action of the CeedQFunction associated with the CeedOperator.
11131d102b48SJeremy L Thompson     The vector 'assembled' is of shape
11141d102b48SJeremy L Thompson       [num_elements, num_input_fields, num_output_fields, num_quad_points]
11151d102b48SJeremy L Thompson     and contains column-major matrices representing the action of the
11161d102b48SJeremy L Thompson     CeedQFunction for a corresponding quadrature point on an element. Inputs and
11171d102b48SJeremy L Thompson     outputs are in the order provided by the user when adding CeedOperator fields.
11184cc79fe7SJed Brown     For example, a CeedQFunction with inputs 'u' and 'gradu' and outputs 'gradv' and
11191d102b48SJeremy L Thompson     'v', provided in that order, would result in an assembled QFunction that
11201d102b48SJeremy L Thompson     consists of (1 + dim) x (dim + 1) matrices at each quadrature point acting
11211d102b48SJeremy L Thompson     on the input [u, du_0, du_1] and producing the output [dv_0, dv_1, v].
11221d102b48SJeremy L Thompson 
11231d102b48SJeremy L Thompson   @param op              CeedOperator to assemble CeedQFunction
11241d102b48SJeremy L Thompson   @param[out] assembled  CeedVector to store assembled CeedQFunction at
11251d102b48SJeremy L Thompson                            quadrature points
11261d102b48SJeremy L Thompson   @param[out] rstr       CeedElemRestriction for CeedVector containing assembled
11271d102b48SJeremy L Thompson                            CeedQFunction
11281d102b48SJeremy L Thompson   @param request         Address of CeedRequest for non-blocking completion, else
11294cc79fe7SJed Brown                            @ref CEED_REQUEST_IMMEDIATE
11301d102b48SJeremy L Thompson 
11311d102b48SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
11321d102b48SJeremy L Thompson 
11337a982d89SJeremy L. Thompson   @ref User
11341d102b48SJeremy L Thompson **/
113580ac2e43SJeremy L Thompson int CeedOperatorLinearAssembleQFunction(CeedOperator op, CeedVector *assembled,
11367f823360Sjeremylt                                         CeedElemRestriction *rstr,
11377f823360Sjeremylt                                         CeedRequest *request) {
11381d102b48SJeremy L Thompson   int ierr;
1139e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
11401d102b48SJeremy L Thompson 
11417172caadSjeremylt   // Backend version
114280ac2e43SJeremy L Thompson   if (op->LinearAssembleQFunction) {
1143e2f04181SAndrew T. Barker     return op->LinearAssembleQFunction(op, assembled, rstr, request);
11445107b09fSJeremy L Thompson   } else {
11455107b09fSJeremy L Thompson     // Fallback to reference Ceed
1146d1d35e2fSjeremylt     if (!op->op_fallback) {
11475107b09fSJeremy L Thompson       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
11485107b09fSJeremy L Thompson     }
11495107b09fSJeremy L Thompson     // Assemble
1150d1d35e2fSjeremylt     return CeedOperatorLinearAssembleQFunction(op->op_fallback, assembled,
1151e2f04181SAndrew T. Barker            rstr, request);
11525107b09fSJeremy L Thompson   }
11531d102b48SJeremy L Thompson }
11541d102b48SJeremy L Thompson 
11551d102b48SJeremy L Thompson /**
1156d965c7a7SJeremy L Thompson   @brief Assemble the diagonal of a square linear CeedOperator
1157b7ec98d8SJeremy L Thompson 
11589e9210b8SJeremy L Thompson   This overwrites a CeedVector with the diagonal of a linear CeedOperator.
1159b7ec98d8SJeremy L Thompson 
1160c04a41a7SJeremy L Thompson   Note: Currently only non-composite CeedOperators with a single field and
1161c04a41a7SJeremy L Thompson           composite CeedOperators with single field sub-operators are supported.
1162d965c7a7SJeremy L Thompson 
1163b7ec98d8SJeremy L Thompson   @param op              CeedOperator to assemble CeedQFunction
1164b7ec98d8SJeremy L Thompson   @param[out] assembled  CeedVector to store assembled CeedOperator diagonal
1165b7ec98d8SJeremy L Thompson   @param request         Address of CeedRequest for non-blocking completion, else
11664cc79fe7SJed Brown                            @ref CEED_REQUEST_IMMEDIATE
1167b7ec98d8SJeremy L Thompson 
1168b7ec98d8SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1169b7ec98d8SJeremy L Thompson 
11707a982d89SJeremy L. Thompson   @ref User
1171b7ec98d8SJeremy L Thompson **/
11722bba3ffaSJeremy L Thompson int CeedOperatorLinearAssembleDiagonal(CeedOperator op, CeedVector assembled,
11737f823360Sjeremylt                                        CeedRequest *request) {
1174b7ec98d8SJeremy L Thompson   int ierr;
1175e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
1176b7ec98d8SJeremy L Thompson 
1177b7ec98d8SJeremy L Thompson   // Use backend version, if available
117880ac2e43SJeremy L Thompson   if (op->LinearAssembleDiagonal) {
1179e2f04181SAndrew T. Barker     return op->LinearAssembleDiagonal(op, assembled, request);
11809e9210b8SJeremy L Thompson   } else if (op->LinearAssembleAddDiagonal) {
11819e9210b8SJeremy L Thompson     ierr = CeedVectorSetValue(assembled, 0.0); CeedChk(ierr);
11829e9210b8SJeremy L Thompson     return CeedOperatorLinearAssembleAddDiagonal(op, assembled, request);
11839e9210b8SJeremy L Thompson   } else {
11849e9210b8SJeremy L Thompson     // Fallback to reference Ceed
1185d1d35e2fSjeremylt     if (!op->op_fallback) {
11869e9210b8SJeremy L Thompson       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
11879e9210b8SJeremy L Thompson     }
11889e9210b8SJeremy L Thompson     // Assemble
1189d1d35e2fSjeremylt     return CeedOperatorLinearAssembleDiagonal(op->op_fallback, assembled,
1190e2f04181SAndrew T. Barker            request);
11919e9210b8SJeremy L Thompson   }
11929e9210b8SJeremy L Thompson }
11939e9210b8SJeremy L Thompson 
11949e9210b8SJeremy L Thompson /**
11959e9210b8SJeremy L Thompson   @brief Assemble the diagonal of a square linear CeedOperator
11969e9210b8SJeremy L Thompson 
11979e9210b8SJeremy L Thompson   This sums into a CeedVector the diagonal of a linear CeedOperator.
11989e9210b8SJeremy L Thompson 
11999e9210b8SJeremy L Thompson   Note: Currently only non-composite CeedOperators with a single field and
12009e9210b8SJeremy L Thompson           composite CeedOperators with single field sub-operators are supported.
12019e9210b8SJeremy L Thompson 
12029e9210b8SJeremy L Thompson   @param op              CeedOperator to assemble CeedQFunction
12039e9210b8SJeremy L Thompson   @param[out] assembled  CeedVector to store assembled CeedOperator diagonal
12049e9210b8SJeremy L Thompson   @param request         Address of CeedRequest for non-blocking completion, else
12059e9210b8SJeremy L Thompson                            @ref CEED_REQUEST_IMMEDIATE
12069e9210b8SJeremy L Thompson 
12079e9210b8SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
12089e9210b8SJeremy L Thompson 
12099e9210b8SJeremy L Thompson   @ref User
12109e9210b8SJeremy L Thompson **/
12119e9210b8SJeremy L Thompson int CeedOperatorLinearAssembleAddDiagonal(CeedOperator op, CeedVector assembled,
12129e9210b8SJeremy L Thompson     CeedRequest *request) {
12139e9210b8SJeremy L Thompson   int ierr;
1214e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
12159e9210b8SJeremy L Thompson 
12169e9210b8SJeremy L Thompson   // Use backend version, if available
12179e9210b8SJeremy L Thompson   if (op->LinearAssembleAddDiagonal) {
1218e2f04181SAndrew T. Barker     return op->LinearAssembleAddDiagonal(op, assembled, request);
12197172caadSjeremylt   } else {
12207172caadSjeremylt     // Fallback to reference Ceed
1221d1d35e2fSjeremylt     if (!op->op_fallback) {
12227172caadSjeremylt       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
1223b7ec98d8SJeremy L Thompson     }
12247172caadSjeremylt     // Assemble
1225d1d35e2fSjeremylt     return CeedOperatorLinearAssembleAddDiagonal(op->op_fallback, assembled,
1226e2f04181SAndrew T. Barker            request);
1227b7ec98d8SJeremy L Thompson   }
1228b7ec98d8SJeremy L Thompson }
1229b7ec98d8SJeremy L Thompson 
1230b7ec98d8SJeremy L Thompson /**
1231d965c7a7SJeremy L Thompson   @brief Assemble the point block diagonal of a square linear CeedOperator
1232d965c7a7SJeremy L Thompson 
12339e9210b8SJeremy L Thompson   This overwrites a CeedVector with the point block diagonal of a linear
1234d965c7a7SJeremy L Thompson     CeedOperator.
1235d965c7a7SJeremy L Thompson 
1236c04a41a7SJeremy L Thompson   Note: Currently only non-composite CeedOperators with a single field and
1237c04a41a7SJeremy L Thompson           composite CeedOperators with single field sub-operators are supported.
1238d965c7a7SJeremy L Thompson 
1239d965c7a7SJeremy L Thompson   @param op              CeedOperator to assemble CeedQFunction
1240d965c7a7SJeremy L Thompson   @param[out] assembled  CeedVector to store assembled CeedOperator point block
1241d965c7a7SJeremy L Thompson                            diagonal, provided in row-major form with an
1242d1d35e2fSjeremylt                            @a num_comp * @a num_comp block at each node. The dimensions
1243d965c7a7SJeremy L Thompson                            of this vector are derived from the active vector
1244d965c7a7SJeremy L Thompson                            for the CeedOperator. The array has shape
1245d965c7a7SJeremy L Thompson                            [nodes, component out, component in].
1246d965c7a7SJeremy L Thompson   @param request         Address of CeedRequest for non-blocking completion, else
1247d965c7a7SJeremy L Thompson                            CEED_REQUEST_IMMEDIATE
1248d965c7a7SJeremy L Thompson 
1249d965c7a7SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1250d965c7a7SJeremy L Thompson 
1251d965c7a7SJeremy L Thompson   @ref User
1252d965c7a7SJeremy L Thompson **/
125380ac2e43SJeremy L Thompson int CeedOperatorLinearAssemblePointBlockDiagonal(CeedOperator op,
12542bba3ffaSJeremy L Thompson     CeedVector assembled, CeedRequest *request) {
1255d965c7a7SJeremy L Thompson   int ierr;
1256e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
1257d965c7a7SJeremy L Thompson 
1258d965c7a7SJeremy L Thompson   // Use backend version, if available
125980ac2e43SJeremy L Thompson   if (op->LinearAssemblePointBlockDiagonal) {
1260e2f04181SAndrew T. Barker     return op->LinearAssemblePointBlockDiagonal(op, assembled, request);
12619e9210b8SJeremy L Thompson   } else if (op->LinearAssembleAddPointBlockDiagonal) {
12629e9210b8SJeremy L Thompson     ierr = CeedVectorSetValue(assembled, 0.0); CeedChk(ierr);
12639e9210b8SJeremy L Thompson     return CeedOperatorLinearAssembleAddPointBlockDiagonal(op, assembled,
12649e9210b8SJeremy L Thompson            request);
1265d965c7a7SJeremy L Thompson   } else {
1266d965c7a7SJeremy L Thompson     // Fallback to reference Ceed
1267d1d35e2fSjeremylt     if (!op->op_fallback) {
1268d965c7a7SJeremy L Thompson       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
1269d965c7a7SJeremy L Thompson     }
1270d965c7a7SJeremy L Thompson     // Assemble
1271d1d35e2fSjeremylt     return CeedOperatorLinearAssemblePointBlockDiagonal(op->op_fallback,
1272e2f04181SAndrew T. Barker            assembled, request);
12739e9210b8SJeremy L Thompson   }
12749e9210b8SJeremy L Thompson }
12759e9210b8SJeremy L Thompson 
12769e9210b8SJeremy L Thompson /**
12779e9210b8SJeremy L Thompson   @brief Assemble the point block diagonal of a square linear CeedOperator
12789e9210b8SJeremy L Thompson 
12799e9210b8SJeremy L Thompson   This sums into a CeedVector with the point block diagonal of a linear
12809e9210b8SJeremy L Thompson     CeedOperator.
12819e9210b8SJeremy L Thompson 
12829e9210b8SJeremy L Thompson   Note: Currently only non-composite CeedOperators with a single field and
12839e9210b8SJeremy L Thompson           composite CeedOperators with single field sub-operators are supported.
12849e9210b8SJeremy L Thompson 
12859e9210b8SJeremy L Thompson   @param op              CeedOperator to assemble CeedQFunction
12869e9210b8SJeremy L Thompson   @param[out] assembled  CeedVector to store assembled CeedOperator point block
12879e9210b8SJeremy L Thompson                            diagonal, provided in row-major form with an
1288d1d35e2fSjeremylt                            @a num_comp * @a num_comp block at each node. The dimensions
12899e9210b8SJeremy L Thompson                            of this vector are derived from the active vector
12909e9210b8SJeremy L Thompson                            for the CeedOperator. The array has shape
12919e9210b8SJeremy L Thompson                            [nodes, component out, component in].
12929e9210b8SJeremy L Thompson   @param request         Address of CeedRequest for non-blocking completion, else
12939e9210b8SJeremy L Thompson                            CEED_REQUEST_IMMEDIATE
12949e9210b8SJeremy L Thompson 
12959e9210b8SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
12969e9210b8SJeremy L Thompson 
12979e9210b8SJeremy L Thompson   @ref User
12989e9210b8SJeremy L Thompson **/
12999e9210b8SJeremy L Thompson int CeedOperatorLinearAssembleAddPointBlockDiagonal(CeedOperator op,
13009e9210b8SJeremy L Thompson     CeedVector assembled, CeedRequest *request) {
13019e9210b8SJeremy L Thompson   int ierr;
1302e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
13039e9210b8SJeremy L Thompson 
13049e9210b8SJeremy L Thompson   // Use backend version, if available
13059e9210b8SJeremy L Thompson   if (op->LinearAssembleAddPointBlockDiagonal) {
1306e2f04181SAndrew T. Barker     return op->LinearAssembleAddPointBlockDiagonal(op, assembled, request);
13079e9210b8SJeremy L Thompson   } else {
13089e9210b8SJeremy L Thompson     // Fallback to reference Ceed
1309d1d35e2fSjeremylt     if (!op->op_fallback) {
13109e9210b8SJeremy L Thompson       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
13119e9210b8SJeremy L Thompson     }
13129e9210b8SJeremy L Thompson     // Assemble
1313d1d35e2fSjeremylt     return CeedOperatorLinearAssembleAddPointBlockDiagonal(op->op_fallback,
1314e2f04181SAndrew T. Barker            assembled, request);
1315d965c7a7SJeremy L Thompson   }
1316e2f04181SAndrew T. Barker }
1317e2f04181SAndrew T. Barker 
1318e2f04181SAndrew T. Barker /**
1319e2f04181SAndrew T. Barker    @brief Build nonzero pattern for non-composite operator.
1320e2f04181SAndrew T. Barker 
1321e2f04181SAndrew T. Barker    Users should generally use CeedOperatorLinearAssembleSymbolic()
1322e2f04181SAndrew T. Barker 
1323e2f04181SAndrew T. Barker    @ref Developer
1324e2f04181SAndrew T. Barker **/
1325e2f04181SAndrew T. Barker int CeedSingleOperatorAssembleSymbolic(CeedOperator op, CeedInt offset,
1326e2f04181SAndrew T. Barker                                        CeedInt *rows, CeedInt *cols) {
1327e2f04181SAndrew T. Barker   int ierr;
1328e2f04181SAndrew T. Barker   Ceed ceed = op->ceed;
1329e2f04181SAndrew T. Barker   if (op->composite)
1330e2f04181SAndrew T. Barker     // LCOV_EXCL_START
1331e2f04181SAndrew T. Barker     return CeedError(ceed, CEED_ERROR_UNSUPPORTED,
1332e2f04181SAndrew T. Barker                      "Composite operator not supported");
1333e2f04181SAndrew T. Barker   // LCOV_EXCL_STOP
1334e2f04181SAndrew T. Barker 
1335d1d35e2fSjeremylt   CeedElemRestriction rstr_in;
1336d1d35e2fSjeremylt   ierr = CeedOperatorGetActiveElemRestriction(op, &rstr_in); CeedChk(ierr);
1337d1d35e2fSjeremylt   CeedInt num_elem, elem_size, num_nodes, num_comp;
1338d1d35e2fSjeremylt   ierr = CeedElemRestrictionGetNumElements(rstr_in, &num_elem); CeedChk(ierr);
1339d1d35e2fSjeremylt   ierr = CeedElemRestrictionGetElementSize(rstr_in, &elem_size); CeedChk(ierr);
1340d1d35e2fSjeremylt   ierr = CeedElemRestrictionGetLVectorSize(rstr_in, &num_nodes); CeedChk(ierr);
1341d1d35e2fSjeremylt   ierr = CeedElemRestrictionGetNumComponents(rstr_in, &num_comp); CeedChk(ierr);
1342e2f04181SAndrew T. Barker   CeedInt layout_er[3];
1343d1d35e2fSjeremylt   ierr = CeedElemRestrictionGetELayout(rstr_in, &layout_er); CeedChk(ierr);
1344e2f04181SAndrew T. Barker 
1345d1d35e2fSjeremylt   CeedInt local_num_entries = elem_size*num_comp * elem_size*num_comp * num_elem;
1346e2f04181SAndrew T. Barker 
1347e2f04181SAndrew T. Barker   // Determine elem_dof relation
1348e2f04181SAndrew T. Barker   CeedVector index_vec;
1349d1d35e2fSjeremylt   ierr = CeedVectorCreate(ceed, num_nodes, &index_vec); CeedChk(ierr);
1350e2f04181SAndrew T. Barker   CeedScalar *array;
1351e2f04181SAndrew T. Barker   ierr = CeedVectorGetArray(index_vec, CEED_MEM_HOST, &array); CeedChk(ierr);
1352d1d35e2fSjeremylt   for (CeedInt i = 0; i < num_nodes; ++i) {
1353e2f04181SAndrew T. Barker     array[i] = i;
1354e2f04181SAndrew T. Barker   }
1355e2f04181SAndrew T. Barker   ierr = CeedVectorRestoreArray(index_vec, &array); CeedChk(ierr);
1356e2f04181SAndrew T. Barker   CeedVector elem_dof;
1357d1d35e2fSjeremylt   ierr = CeedVectorCreate(ceed, num_elem * elem_size * num_comp, &elem_dof);
1358e2f04181SAndrew T. Barker   CeedChk(ierr);
1359e2f04181SAndrew T. Barker   ierr = CeedVectorSetValue(elem_dof, 0.0); CeedChk(ierr);
1360d1d35e2fSjeremylt   CeedElemRestrictionApply(rstr_in, CEED_NOTRANSPOSE, index_vec,
1361e2f04181SAndrew T. Barker                            elem_dof, CEED_REQUEST_IMMEDIATE); CeedChk(ierr);
1362e2f04181SAndrew T. Barker   const CeedScalar *elem_dof_a;
1363e2f04181SAndrew T. Barker   ierr = CeedVectorGetArrayRead(elem_dof, CEED_MEM_HOST, &elem_dof_a);
1364e2f04181SAndrew T. Barker   CeedChk(ierr);
1365e2f04181SAndrew T. Barker   ierr = CeedVectorDestroy(&index_vec); CeedChk(ierr);
1366e2f04181SAndrew T. Barker 
1367e2f04181SAndrew T. Barker   // Determine i, j locations for element matrices
1368e2f04181SAndrew T. Barker   CeedInt count = 0;
1369d1d35e2fSjeremylt   for (int e = 0; e < num_elem; ++e) {
1370d1d35e2fSjeremylt     for (int comp_in = 0; comp_in < num_comp; ++comp_in) {
1371d1d35e2fSjeremylt       for (int comp_out = 0; comp_out < num_comp; ++comp_out) {
1372d1d35e2fSjeremylt         for (int i = 0; i < elem_size; ++i) {
1373d1d35e2fSjeremylt           for (int j = 0; j < elem_size; ++j) {
1374d1d35e2fSjeremylt             const CeedInt elem_dof_index_row = (i)*layout_er[0] +
1375d1d35e2fSjeremylt                                                (comp_out)*layout_er[1] + e*layout_er[2];
1376d1d35e2fSjeremylt             const CeedInt elem_dof_index_col = (j)*layout_er[0] +
1377d1d35e2fSjeremylt                                                (comp_in)*layout_er[1] + e*layout_er[2];
1378e2f04181SAndrew T. Barker 
1379d1d35e2fSjeremylt             const CeedInt row = elem_dof_a[elem_dof_index_row];
1380d1d35e2fSjeremylt             const CeedInt col = elem_dof_a[elem_dof_index_col];
1381e2f04181SAndrew T. Barker 
1382e2f04181SAndrew T. Barker             rows[offset + count] = row;
1383e2f04181SAndrew T. Barker             cols[offset + count] = col;
1384e2f04181SAndrew T. Barker             count++;
1385e2f04181SAndrew T. Barker           }
1386e2f04181SAndrew T. Barker         }
1387e2f04181SAndrew T. Barker       }
1388e2f04181SAndrew T. Barker     }
1389e2f04181SAndrew T. Barker   }
1390d1d35e2fSjeremylt   if (count != local_num_entries)
1391e2f04181SAndrew T. Barker     // LCOV_EXCL_START
1392e2f04181SAndrew T. Barker     return CeedError(ceed, CEED_ERROR_MAJOR, "Error computing assembled entries");
1393e2f04181SAndrew T. Barker   // LCOV_EXCL_STOP
1394e2f04181SAndrew T. Barker   ierr = CeedVectorRestoreArrayRead(elem_dof, &elem_dof_a); CeedChk(ierr);
1395e2f04181SAndrew T. Barker   ierr = CeedVectorDestroy(&elem_dof); CeedChk(ierr);
1396e2f04181SAndrew T. Barker 
1397e2f04181SAndrew T. Barker   return CEED_ERROR_SUCCESS;
1398e2f04181SAndrew T. Barker }
1399e2f04181SAndrew T. Barker 
1400e2f04181SAndrew T. Barker /**
1401e2f04181SAndrew T. Barker    @brief Assemble nonzero entries for non-composite operator
1402e2f04181SAndrew T. Barker 
1403e2f04181SAndrew T. Barker    Users should generally use CeedOperatorLinearAssemble()
1404e2f04181SAndrew T. Barker 
1405e2f04181SAndrew T. Barker    @ref Developer
1406e2f04181SAndrew T. Barker **/
1407e2f04181SAndrew T. Barker int CeedSingleOperatorAssemble(CeedOperator op, CeedInt offset,
1408e2f04181SAndrew T. Barker                                CeedVector values) {
1409e2f04181SAndrew T. Barker   int ierr;
1410e2f04181SAndrew T. Barker   Ceed ceed = op->ceed;;
1411e2f04181SAndrew T. Barker   if (op->composite)
1412e2f04181SAndrew T. Barker     // LCOV_EXCL_START
1413e2f04181SAndrew T. Barker     return CeedError(ceed, CEED_ERROR_UNSUPPORTED,
1414e2f04181SAndrew T. Barker                      "Composite operator not supported");
1415e2f04181SAndrew T. Barker   // LCOV_EXCL_STOP
1416e2f04181SAndrew T. Barker 
1417e2f04181SAndrew T. Barker   // Assemble QFunction
1418e2f04181SAndrew T. Barker   CeedQFunction qf;
1419e2f04181SAndrew T. Barker   ierr = CeedOperatorGetQFunction(op, &qf); CeedChk(ierr);
1420d1d35e2fSjeremylt   CeedInt num_input_fields, num_output_fields;
1421d1d35e2fSjeremylt   ierr= CeedQFunctionGetNumArgs(qf, &num_input_fields, &num_output_fields);
1422e2f04181SAndrew T. Barker   CeedChk(ierr);
1423d1d35e2fSjeremylt   CeedVector assembled_qf;
1424e2f04181SAndrew T. Barker   CeedElemRestriction rstr_q;
1425e2f04181SAndrew T. Barker   ierr = CeedOperatorLinearAssembleQFunction(
1426d1d35e2fSjeremylt            op, &assembled_qf, &rstr_q, CEED_REQUEST_IMMEDIATE); CeedChk(ierr);
1427e2f04181SAndrew T. Barker 
1428d1d35e2fSjeremylt   CeedInt qf_length;
1429d1d35e2fSjeremylt   ierr = CeedVectorGetLength(assembled_qf, &qf_length); CeedChk(ierr);
1430e2f04181SAndrew T. Barker 
1431e2f04181SAndrew T. Barker   CeedOperatorField *input_fields;
1432e2f04181SAndrew T. Barker   CeedOperatorField *output_fields;
1433e2f04181SAndrew T. Barker   ierr = CeedOperatorGetFields(op, &input_fields, &output_fields); CeedChk(ierr);
1434e2f04181SAndrew T. Barker 
1435e2f04181SAndrew T. Barker   // Determine active input basis
1436d1d35e2fSjeremylt   CeedQFunctionField *qf_fields;
1437d1d35e2fSjeremylt   ierr = CeedQFunctionGetFields(qf, &qf_fields, NULL); CeedChk(ierr);
1438d1d35e2fSjeremylt   CeedInt num_eval_mode_in = 0, dim = 1;
1439d1d35e2fSjeremylt   CeedEvalMode *eval_mode_in = NULL;
1440d1d35e2fSjeremylt   CeedBasis basis_in = NULL;
1441d1d35e2fSjeremylt   CeedElemRestriction rstr_in = NULL;
1442d1d35e2fSjeremylt   for (CeedInt i=0; i<num_input_fields; i++) {
1443e2f04181SAndrew T. Barker     CeedVector vec;
1444e2f04181SAndrew T. Barker     ierr = CeedOperatorFieldGetVector(input_fields[i], &vec); CeedChk(ierr);
1445e2f04181SAndrew T. Barker     if (vec == CEED_VECTOR_ACTIVE) {
1446d1d35e2fSjeremylt       ierr = CeedOperatorFieldGetBasis(input_fields[i], &basis_in);
1447e2f04181SAndrew T. Barker       CeedChk(ierr);
1448d1d35e2fSjeremylt       ierr = CeedBasisGetDimension(basis_in, &dim); CeedChk(ierr);
1449d1d35e2fSjeremylt       ierr = CeedOperatorFieldGetElemRestriction(input_fields[i], &rstr_in);
1450e2f04181SAndrew T. Barker       CeedChk(ierr);
1451d1d35e2fSjeremylt       CeedEvalMode eval_mode;
1452d1d35e2fSjeremylt       ierr = CeedQFunctionFieldGetEvalMode(qf_fields[i], &eval_mode);
1453e2f04181SAndrew T. Barker       CeedChk(ierr);
1454d1d35e2fSjeremylt       switch (eval_mode) {
1455e2f04181SAndrew T. Barker       case CEED_EVAL_NONE:
1456e2f04181SAndrew T. Barker       case CEED_EVAL_INTERP:
1457d1d35e2fSjeremylt         ierr = CeedRealloc(num_eval_mode_in + 1, &eval_mode_in); CeedChk(ierr);
1458d1d35e2fSjeremylt         eval_mode_in[num_eval_mode_in] = eval_mode;
1459d1d35e2fSjeremylt         num_eval_mode_in += 1;
1460e2f04181SAndrew T. Barker         break;
1461e2f04181SAndrew T. Barker       case CEED_EVAL_GRAD:
1462d1d35e2fSjeremylt         ierr = CeedRealloc(num_eval_mode_in + dim, &eval_mode_in); CeedChk(ierr);
1463e2f04181SAndrew T. Barker         for (CeedInt d=0; d<dim; d++) {
1464d1d35e2fSjeremylt           eval_mode_in[num_eval_mode_in+d] = eval_mode;
1465e2f04181SAndrew T. Barker         }
1466d1d35e2fSjeremylt         num_eval_mode_in += dim;
1467e2f04181SAndrew T. Barker         break;
1468e2f04181SAndrew T. Barker       case CEED_EVAL_WEIGHT:
1469e2f04181SAndrew T. Barker       case CEED_EVAL_DIV:
1470e2f04181SAndrew T. Barker       case CEED_EVAL_CURL:
1471e2f04181SAndrew T. Barker         break; // Caught by QF Assembly
1472e2f04181SAndrew T. Barker       }
1473e2f04181SAndrew T. Barker     }
1474e2f04181SAndrew T. Barker   }
1475e2f04181SAndrew T. Barker 
1476e2f04181SAndrew T. Barker   // Determine active output basis
1477d1d35e2fSjeremylt   ierr = CeedQFunctionGetFields(qf, NULL, &qf_fields); CeedChk(ierr);
1478d1d35e2fSjeremylt   CeedInt num_eval_mode_out = 0;
1479d1d35e2fSjeremylt   CeedEvalMode *eval_mode_out = NULL;
1480d1d35e2fSjeremylt   CeedBasis basis_out = NULL;
1481d1d35e2fSjeremylt   CeedElemRestriction rstr_out = NULL;
1482d1d35e2fSjeremylt   for (CeedInt i=0; i<num_output_fields; i++) {
1483e2f04181SAndrew T. Barker     CeedVector vec;
1484e2f04181SAndrew T. Barker     ierr = CeedOperatorFieldGetVector(output_fields[i], &vec); CeedChk(ierr);
1485e2f04181SAndrew T. Barker     if (vec == CEED_VECTOR_ACTIVE) {
1486d1d35e2fSjeremylt       ierr = CeedOperatorFieldGetBasis(output_fields[i], &basis_out);
1487e2f04181SAndrew T. Barker       CeedChk(ierr);
1488d1d35e2fSjeremylt       ierr = CeedOperatorFieldGetElemRestriction(output_fields[i], &rstr_out);
1489e2f04181SAndrew T. Barker       CeedChk(ierr);
1490d1d35e2fSjeremylt       CeedEvalMode eval_mode;
1491d1d35e2fSjeremylt       ierr = CeedQFunctionFieldGetEvalMode(qf_fields[i], &eval_mode);
1492e2f04181SAndrew T. Barker       CeedChk(ierr);
1493d1d35e2fSjeremylt       switch (eval_mode) {
1494e2f04181SAndrew T. Barker       case CEED_EVAL_NONE:
1495e2f04181SAndrew T. Barker       case CEED_EVAL_INTERP:
1496d1d35e2fSjeremylt         ierr = CeedRealloc(num_eval_mode_out + 1, &eval_mode_out); CeedChk(ierr);
1497d1d35e2fSjeremylt         eval_mode_out[num_eval_mode_out] = eval_mode;
1498d1d35e2fSjeremylt         num_eval_mode_out += 1;
1499e2f04181SAndrew T. Barker         break;
1500e2f04181SAndrew T. Barker       case CEED_EVAL_GRAD:
1501d1d35e2fSjeremylt         ierr = CeedRealloc(num_eval_mode_out + dim, &eval_mode_out); CeedChk(ierr);
1502e2f04181SAndrew T. Barker         for (CeedInt d=0; d<dim; d++) {
1503d1d35e2fSjeremylt           eval_mode_out[num_eval_mode_out+d] = eval_mode;
1504e2f04181SAndrew T. Barker         }
1505d1d35e2fSjeremylt         num_eval_mode_out += dim;
1506e2f04181SAndrew T. Barker         break;
1507e2f04181SAndrew T. Barker       case CEED_EVAL_WEIGHT:
1508e2f04181SAndrew T. Barker       case CEED_EVAL_DIV:
1509e2f04181SAndrew T. Barker       case CEED_EVAL_CURL:
1510e2f04181SAndrew T. Barker         break; // Caught by QF Assembly
1511e2f04181SAndrew T. Barker       }
1512e2f04181SAndrew T. Barker     }
1513e2f04181SAndrew T. Barker   }
1514e2f04181SAndrew T. Barker 
1515*78464608Sjeremylt   if (num_eval_mode_in == 0 || num_eval_mode_out == 0)
1516*78464608Sjeremylt     // LCOV_EXCL_START
1517*78464608Sjeremylt     return CeedError(ceed, CEED_ERROR_UNSUPPORTED,
1518*78464608Sjeremylt                      "Cannot assemble operator with out inputs/outputs");
1519*78464608Sjeremylt   // LCOV_EXCL_STOP
1520*78464608Sjeremylt 
1521d1d35e2fSjeremylt   CeedInt num_elem, elem_size, num_qpts, num_comp;
1522d1d35e2fSjeremylt   ierr = CeedElemRestrictionGetNumElements(rstr_in, &num_elem); CeedChk(ierr);
1523d1d35e2fSjeremylt   ierr = CeedElemRestrictionGetElementSize(rstr_in, &elem_size); CeedChk(ierr);
1524d1d35e2fSjeremylt   ierr = CeedElemRestrictionGetNumComponents(rstr_in, &num_comp); CeedChk(ierr);
1525d1d35e2fSjeremylt   ierr = CeedBasisGetNumQuadraturePoints(basis_in, &num_qpts); CeedChk(ierr);
1526e2f04181SAndrew T. Barker 
1527d1d35e2fSjeremylt   CeedInt local_num_entries = elem_size*num_comp * elem_size*num_comp * num_elem;
1528e2f04181SAndrew T. Barker 
1529e2f04181SAndrew T. Barker   // loop over elements and put in data structure
1530d1d35e2fSjeremylt   const CeedScalar *interp_in, *grad_in;
1531d1d35e2fSjeremylt   ierr = CeedBasisGetInterp(basis_in, &interp_in); CeedChk(ierr);
1532d1d35e2fSjeremylt   ierr = CeedBasisGetGrad(basis_in, &grad_in); CeedChk(ierr);
1533e2f04181SAndrew T. Barker 
1534d1d35e2fSjeremylt   const CeedScalar *assembled_qf_array;
1535d1d35e2fSjeremylt   ierr = CeedVectorGetArrayRead(assembled_qf, CEED_MEM_HOST, &assembled_qf_array);
1536e2f04181SAndrew T. Barker   CeedChk(ierr);
1537e2f04181SAndrew T. Barker 
1538e2f04181SAndrew T. Barker   CeedInt layout_qf[3];
1539e2f04181SAndrew T. Barker   ierr = CeedElemRestrictionGetELayout(rstr_q, &layout_qf); CeedChk(ierr);
1540e2f04181SAndrew T. Barker   ierr = CeedElemRestrictionDestroy(&rstr_q); CeedChk(ierr);
1541e2f04181SAndrew T. Barker 
1542d1d35e2fSjeremylt   // we store B_mat_in, B_mat_out, BTD, elem_mat in row-major order
1543d1d35e2fSjeremylt   CeedScalar B_mat_in[(num_qpts * num_eval_mode_in) * elem_size];
1544d1d35e2fSjeremylt   CeedScalar B_mat_out[(num_qpts * num_eval_mode_out) * elem_size];
1545d1d35e2fSjeremylt   CeedScalar D_mat[num_eval_mode_out * num_eval_mode_in *
1546d1d35e2fSjeremylt                                      num_qpts]; // logically 3-tensor
1547d1d35e2fSjeremylt   CeedScalar BTD[elem_size * num_qpts*num_eval_mode_in];
1548d1d35e2fSjeremylt   CeedScalar elem_mat[elem_size * elem_size];
1549e2f04181SAndrew T. Barker   int count = 0;
1550e2f04181SAndrew T. Barker   CeedScalar *vals;
1551e2f04181SAndrew T. Barker   ierr = CeedVectorGetArray(values, CEED_MEM_HOST, &vals); CeedChk(ierr);
1552d1d35e2fSjeremylt   for (int e = 0; e < num_elem; ++e) {
1553d1d35e2fSjeremylt     for (int comp_in = 0; comp_in < num_comp; ++comp_in) {
1554d1d35e2fSjeremylt       for (int comp_out = 0; comp_out < num_comp; ++comp_out) {
1555d1d35e2fSjeremylt         for (int ell = 0; ell < (num_qpts * num_eval_mode_in) * elem_size; ++ell) {
1556d1d35e2fSjeremylt           B_mat_in[ell] = 0.0;
1557e2f04181SAndrew T. Barker         }
1558d1d35e2fSjeremylt         for (int ell = 0; ell < (num_qpts * num_eval_mode_out) * elem_size; ++ell) {
1559d1d35e2fSjeremylt           B_mat_out[ell] = 0.0;
1560e2f04181SAndrew T. Barker         }
1561e2f04181SAndrew T. Barker         // Store block-diagonal D matrix as collection of small dense blocks
1562d1d35e2fSjeremylt         for (int ell = 0; ell < num_eval_mode_in*num_eval_mode_out*num_qpts; ++ell) {
1563d1d35e2fSjeremylt           D_mat[ell] = 0.0;
1564e2f04181SAndrew T. Barker         }
1565e2f04181SAndrew T. Barker         // form element matrix itself (for each block component)
1566d1d35e2fSjeremylt         for (int ell = 0; ell < elem_size*elem_size; ++ell) {
1567e2f04181SAndrew T. Barker           elem_mat[ell] = 0.0;
1568e2f04181SAndrew T. Barker         }
1569d1d35e2fSjeremylt         for (int q = 0; q < num_qpts; ++q) {
1570d1d35e2fSjeremylt           for (int n = 0; n < elem_size; ++n) {
1571d1d35e2fSjeremylt             CeedInt d_in = -1;
1572d1d35e2fSjeremylt             for (int e_in = 0; e_in < num_eval_mode_in; ++e_in) {
1573d1d35e2fSjeremylt               const int qq = num_eval_mode_in*q;
1574d1d35e2fSjeremylt               if (eval_mode_in[e_in] == CEED_EVAL_INTERP) {
1575d1d35e2fSjeremylt                 B_mat_in[(qq+e_in)*elem_size + n] += interp_in[q * elem_size + n];
1576d1d35e2fSjeremylt               } else if (eval_mode_in[e_in] == CEED_EVAL_GRAD) {
1577d1d35e2fSjeremylt                 d_in += 1;
1578d1d35e2fSjeremylt                 B_mat_in[(qq+e_in)*elem_size + n] +=
1579d1d35e2fSjeremylt                   grad_in[(d_in*num_qpts+q) * elem_size + n];
1580e2f04181SAndrew T. Barker               } else {
1581e2f04181SAndrew T. Barker                 // LCOV_EXCL_START
1582e2f04181SAndrew T. Barker                 return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Not implemented!");
1583e2f04181SAndrew T. Barker                 // LCOV_EXCL_STOP
1584e2f04181SAndrew T. Barker               }
1585e2f04181SAndrew T. Barker             }
1586d1d35e2fSjeremylt             CeedInt d_out = -1;
1587d1d35e2fSjeremylt             for (int e_out = 0; e_out < num_eval_mode_out; ++e_out) {
1588d1d35e2fSjeremylt               const int qq = num_eval_mode_out*q;
1589d1d35e2fSjeremylt               if (eval_mode_out[e_out] == CEED_EVAL_INTERP) {
1590d1d35e2fSjeremylt                 B_mat_out[(qq+e_out)*elem_size + n] += interp_in[q * elem_size + n];
1591d1d35e2fSjeremylt               } else if (eval_mode_out[e_out] == CEED_EVAL_GRAD) {
1592d1d35e2fSjeremylt                 d_out += 1;
1593d1d35e2fSjeremylt                 B_mat_out[(qq+e_out)*elem_size + n] +=
1594d1d35e2fSjeremylt                   grad_in[(d_out*num_qpts+q) * elem_size + n];
1595e2f04181SAndrew T. Barker               } else {
1596e2f04181SAndrew T. Barker                 // LCOV_EXCL_START
1597e2f04181SAndrew T. Barker                 return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Not implemented!");
1598e2f04181SAndrew T. Barker                 // LCOV_EXCL_STOP
1599e2f04181SAndrew T. Barker               }
1600e2f04181SAndrew T. Barker             }
1601e2f04181SAndrew T. Barker           }
1602d1d35e2fSjeremylt           for (int ei = 0; ei < num_eval_mode_out; ++ei) {
1603d1d35e2fSjeremylt             for (int ej = 0; ej < num_eval_mode_in; ++ej) {
1604d1d35e2fSjeremylt               const int eval_mode_index = ((ei*num_comp+comp_in)*num_eval_mode_in+ej)*num_comp
1605d1d35e2fSjeremylt                                           +comp_out;
1606d1d35e2fSjeremylt               const int index = q*layout_qf[0] + eval_mode_index*layout_qf[1] +
1607d1d35e2fSjeremylt                                 e*layout_qf[2];
1608d1d35e2fSjeremylt               D_mat[(ei*num_eval_mode_in+ej)*num_qpts + q] += assembled_qf_array[index];
1609e2f04181SAndrew T. Barker             }
1610e2f04181SAndrew T. Barker           }
1611e2f04181SAndrew T. Barker         }
1612e2f04181SAndrew T. Barker         // Compute B^T*D
1613d1d35e2fSjeremylt         for (int ell = 0; ell < elem_size*num_qpts*num_eval_mode_in; ++ell) {
1614e2f04181SAndrew T. Barker           BTD[ell] = 0.0;
1615e2f04181SAndrew T. Barker         }
1616d1d35e2fSjeremylt         for (int j = 0; j<elem_size; ++j) {
1617d1d35e2fSjeremylt           for (int q = 0; q<num_qpts; ++q) {
1618d1d35e2fSjeremylt             int qq = num_eval_mode_out*q;
1619d1d35e2fSjeremylt             for (int ei = 0; ei < num_eval_mode_in; ++ei) {
1620d1d35e2fSjeremylt               for (int ej = 0; ej < num_eval_mode_out; ++ej) {
1621d1d35e2fSjeremylt                 BTD[j*(num_qpts*num_eval_mode_in) + (qq+ei)] +=
1622d1d35e2fSjeremylt                   B_mat_out[(qq+ej)*elem_size + j] * D_mat[(ei*num_eval_mode_in+ej)*num_qpts + q];
1623e2f04181SAndrew T. Barker               }
1624e2f04181SAndrew T. Barker             }
1625e2f04181SAndrew T. Barker           }
1626e2f04181SAndrew T. Barker         }
1627e2f04181SAndrew T. Barker 
1628d1d35e2fSjeremylt         ierr = CeedMatrixMultiply(ceed, BTD, B_mat_in, elem_mat, elem_size,
1629d1d35e2fSjeremylt                                   elem_size, num_qpts*num_eval_mode_in); CeedChk(ierr);
1630e2f04181SAndrew T. Barker 
1631e2f04181SAndrew T. Barker         // put element matrix in coordinate data structure
1632d1d35e2fSjeremylt         for (int i = 0; i < elem_size; ++i) {
1633d1d35e2fSjeremylt           for (int j = 0; j < elem_size; ++j) {
1634d1d35e2fSjeremylt             vals[offset + count] = elem_mat[i*elem_size + j];
1635e2f04181SAndrew T. Barker             count++;
1636e2f04181SAndrew T. Barker           }
1637e2f04181SAndrew T. Barker         }
1638e2f04181SAndrew T. Barker       }
1639e2f04181SAndrew T. Barker     }
1640e2f04181SAndrew T. Barker   }
1641d1d35e2fSjeremylt   if (count != local_num_entries)
1642e2f04181SAndrew T. Barker     // LCOV_EXCL_START
1643e2f04181SAndrew T. Barker     return CeedError(ceed, CEED_ERROR_MAJOR, "Error computing entries");
1644e2f04181SAndrew T. Barker   // LCOV_EXCL_STOP
1645e2f04181SAndrew T. Barker   ierr = CeedVectorRestoreArray(values, &vals); CeedChk(ierr);
1646e2f04181SAndrew T. Barker 
1647d1d35e2fSjeremylt   ierr = CeedVectorRestoreArrayRead(assembled_qf, &assembled_qf_array);
1648e2f04181SAndrew T. Barker   CeedChk(ierr);
1649d1d35e2fSjeremylt   ierr = CeedVectorDestroy(&assembled_qf); CeedChk(ierr);
1650d1d35e2fSjeremylt   ierr = CeedFree(&eval_mode_in); CeedChk(ierr);
1651d1d35e2fSjeremylt   ierr = CeedFree(&eval_mode_out); CeedChk(ierr);
1652e2f04181SAndrew T. Barker 
1653e2f04181SAndrew T. Barker   return CEED_ERROR_SUCCESS;
1654e2f04181SAndrew T. Barker }
1655e2f04181SAndrew T. Barker 
1656e2f04181SAndrew T. Barker /**
1657e2f04181SAndrew T. Barker    @ref Utility
1658e2f04181SAndrew T. Barker **/
1659d1d35e2fSjeremylt int CeedSingleOperatorAssemblyCountEntries(CeedOperator op,
1660d1d35e2fSjeremylt     CeedInt *num_entries) {
1661e2f04181SAndrew T. Barker   int ierr;
1662e2f04181SAndrew T. Barker   CeedElemRestriction rstr;
1663d1d35e2fSjeremylt   CeedInt num_elem, elem_size, num_comp;
1664e2f04181SAndrew T. Barker 
1665e2f04181SAndrew T. Barker   if (op->composite)
1666e2f04181SAndrew T. Barker     // LCOV_EXCL_START
1667e2f04181SAndrew T. Barker     return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED,
1668e2f04181SAndrew T. Barker                      "Composite operator not supported");
1669e2f04181SAndrew T. Barker   // LCOV_EXCL_STOP
1670e2f04181SAndrew T. Barker   ierr = CeedOperatorGetActiveElemRestriction(op, &rstr); CeedChk(ierr);
1671d1d35e2fSjeremylt   ierr = CeedElemRestrictionGetNumElements(rstr, &num_elem); CeedChk(ierr);
1672d1d35e2fSjeremylt   ierr = CeedElemRestrictionGetElementSize(rstr, &elem_size); CeedChk(ierr);
1673d1d35e2fSjeremylt   ierr = CeedElemRestrictionGetNumComponents(rstr, &num_comp); CeedChk(ierr);
1674d1d35e2fSjeremylt   *num_entries = elem_size*num_comp * elem_size*num_comp * num_elem;
1675e2f04181SAndrew T. Barker 
1676e2f04181SAndrew T. Barker   return CEED_ERROR_SUCCESS;
1677e2f04181SAndrew T. Barker }
1678e2f04181SAndrew T. Barker 
1679e2f04181SAndrew T. Barker /**
1680e2f04181SAndrew T. Barker    @brief Fully assemble the nonzero pattern of a linear operator.
1681e2f04181SAndrew T. Barker 
1682e2f04181SAndrew T. Barker    Expected to be used in conjunction with CeedOperatorLinearAssemble()
1683e2f04181SAndrew T. Barker 
1684d1d35e2fSjeremylt    The assembly routines use coordinate format, with num_entries tuples of the
1685e2f04181SAndrew T. Barker    form (i, j, value) which indicate that value should be added to the matrix
1686e2f04181SAndrew T. Barker    in entry (i, j). Note that the (i, j) pairs are not unique and may repeat.
1687e2f04181SAndrew T. Barker    This function returns the number of entries and their (i, j) locations,
1688e2f04181SAndrew T. Barker    while CeedOperatorLinearAssemble() provides the values in the same
1689e2f04181SAndrew T. Barker    ordering.
1690e2f04181SAndrew T. Barker 
1691e2f04181SAndrew T. Barker    This will generally be slow unless your operator is low-order.
1692e2f04181SAndrew T. Barker 
1693e2f04181SAndrew T. Barker    @param[in]  op           CeedOperator to assemble
1694d1d35e2fSjeremylt    @param[out] num_entries  Number of entries in coordinate nonzero pattern.
1695e2f04181SAndrew T. Barker    @param[out] rows         Row number for each entry.
1696e2f04181SAndrew T. Barker    @param[out] cols         Column number for each entry.
1697e2f04181SAndrew T. Barker 
1698e2f04181SAndrew T. Barker    @ref User
1699e2f04181SAndrew T. Barker **/
1700e2f04181SAndrew T. Barker int CeedOperatorLinearAssembleSymbolic(CeedOperator op,
1701d1d35e2fSjeremylt                                        CeedInt *num_entries, CeedInt **rows, CeedInt **cols) {
1702e2f04181SAndrew T. Barker   int ierr;
1703d1d35e2fSjeremylt   CeedInt num_suboperators, single_entries;
1704d1d35e2fSjeremylt   CeedOperator *sub_operators;
1705d1d35e2fSjeremylt   bool is_composite;
1706e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
1707e2f04181SAndrew T. Barker 
1708e2f04181SAndrew T. Barker   // Use backend version, if available
1709e2f04181SAndrew T. Barker   if (op->LinearAssembleSymbolic) {
1710d1d35e2fSjeremylt     return op->LinearAssembleSymbolic(op, num_entries, rows, cols);
1711e2f04181SAndrew T. Barker   } else {
1712e2f04181SAndrew T. Barker     // Check for valid fallback resource
1713d1d35e2fSjeremylt     const char *resource, *fallback_resource;
1714e2f04181SAndrew T. Barker     ierr = CeedGetResource(op->ceed, &resource); CeedChk(ierr);
1715d1d35e2fSjeremylt     ierr = CeedGetOperatorFallbackResource(op->ceed, &fallback_resource);
1716*78464608Sjeremylt     CeedChk(ierr);
1717d1d35e2fSjeremylt     if (strcmp(fallback_resource, "") && strcmp(resource, fallback_resource)) {
1718e2f04181SAndrew T. Barker       // Fallback to reference Ceed
1719d1d35e2fSjeremylt       if (!op->op_fallback) {
1720e2f04181SAndrew T. Barker         ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
1721e2f04181SAndrew T. Barker       }
1722e2f04181SAndrew T. Barker       // Assemble
1723d1d35e2fSjeremylt       return CeedOperatorLinearAssembleSymbolic(op->op_fallback, num_entries, rows,
1724d1d35e2fSjeremylt              cols);
1725e2f04181SAndrew T. Barker     }
1726e2f04181SAndrew T. Barker   }
1727e2f04181SAndrew T. Barker 
1728e2f04181SAndrew T. Barker   // if neither backend nor fallback resource provides
1729e2f04181SAndrew T. Barker   // LinearAssembleSymbolic, continue with interface-level implementation
1730e2f04181SAndrew T. Barker 
1731e2f04181SAndrew T. Barker   // count entries and allocate rows, cols arrays
1732d1d35e2fSjeremylt   ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr);
1733d1d35e2fSjeremylt   *num_entries = 0;
1734d1d35e2fSjeremylt   if (is_composite) {
1735d1d35e2fSjeremylt     ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr);
1736d1d35e2fSjeremylt     ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr);
1737d1d35e2fSjeremylt     for (int k = 0; k < num_suboperators; ++k) {
1738d1d35e2fSjeremylt       ierr = CeedSingleOperatorAssemblyCountEntries(sub_operators[k],
1739e2f04181SAndrew T. Barker              &single_entries); CeedChk(ierr);
1740d1d35e2fSjeremylt       *num_entries += single_entries;
1741e2f04181SAndrew T. Barker     }
1742e2f04181SAndrew T. Barker   } else {
1743e2f04181SAndrew T. Barker     ierr = CeedSingleOperatorAssemblyCountEntries(op,
1744e2f04181SAndrew T. Barker            &single_entries); CeedChk(ierr);
1745d1d35e2fSjeremylt     *num_entries += single_entries;
1746e2f04181SAndrew T. Barker   }
1747d1d35e2fSjeremylt   ierr = CeedCalloc(*num_entries, rows); CeedChk(ierr);
1748d1d35e2fSjeremylt   ierr = CeedCalloc(*num_entries, cols); CeedChk(ierr);
1749e2f04181SAndrew T. Barker 
1750e2f04181SAndrew T. Barker   // assemble nonzero locations
1751e2f04181SAndrew T. Barker   CeedInt offset = 0;
1752d1d35e2fSjeremylt   if (is_composite) {
1753d1d35e2fSjeremylt     ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr);
1754d1d35e2fSjeremylt     ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr);
1755d1d35e2fSjeremylt     for (int k = 0; k < num_suboperators; ++k) {
1756d1d35e2fSjeremylt       ierr = CeedSingleOperatorAssembleSymbolic(sub_operators[k], offset, *rows,
1757e2f04181SAndrew T. Barker              *cols); CeedChk(ierr);
1758d1d35e2fSjeremylt       ierr = CeedSingleOperatorAssemblyCountEntries(sub_operators[k],
1759d1d35e2fSjeremylt              &single_entries);
1760e2f04181SAndrew T. Barker       CeedChk(ierr);
1761e2f04181SAndrew T. Barker       offset += single_entries;
1762e2f04181SAndrew T. Barker     }
1763e2f04181SAndrew T. Barker   } else {
1764e2f04181SAndrew T. Barker     ierr = CeedSingleOperatorAssembleSymbolic(op, offset, *rows, *cols);
1765e2f04181SAndrew T. Barker     CeedChk(ierr);
1766e2f04181SAndrew T. Barker   }
1767e2f04181SAndrew T. Barker 
1768e2f04181SAndrew T. Barker   return CEED_ERROR_SUCCESS;
1769e2f04181SAndrew T. Barker }
1770e2f04181SAndrew T. Barker 
1771e2f04181SAndrew T. Barker /**
1772e2f04181SAndrew T. Barker    @brief Fully assemble the nonzero entries of a linear operator.
1773e2f04181SAndrew T. Barker 
1774e2f04181SAndrew T. Barker    Expected to be used in conjunction with CeedOperatorLinearAssembleSymbolic()
1775e2f04181SAndrew T. Barker 
1776d1d35e2fSjeremylt    The assembly routines use coordinate format, with num_entries tuples of the
1777e2f04181SAndrew T. Barker    form (i, j, value) which indicate that value should be added to the matrix
1778e2f04181SAndrew T. Barker    in entry (i, j). Note that the (i, j) pairs are not unique and may repeat.
1779e2f04181SAndrew T. Barker    This function returns the values of the nonzero entries to be added, their
1780e2f04181SAndrew T. Barker    (i, j) locations are provided by CeedOperatorLinearAssembleSymbolic()
1781e2f04181SAndrew T. Barker 
1782e2f04181SAndrew T. Barker    This will generally be slow unless your operator is low-order.
1783e2f04181SAndrew T. Barker 
1784e2f04181SAndrew T. Barker    @param[in]  op      CeedOperator to assemble
1785e2f04181SAndrew T. Barker    @param[out] values  Values to assemble into matrix
1786e2f04181SAndrew T. Barker 
1787e2f04181SAndrew T. Barker    @ref User
1788e2f04181SAndrew T. Barker **/
1789e2f04181SAndrew T. Barker int CeedOperatorLinearAssemble(CeedOperator op, CeedVector values) {
1790e2f04181SAndrew T. Barker   int ierr;
1791*78464608Sjeremylt   CeedInt num_suboperators, single_entries = 0;
1792d1d35e2fSjeremylt   CeedOperator *sub_operators;
1793e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
1794e2f04181SAndrew T. Barker 
1795e2f04181SAndrew T. Barker   // Use backend version, if available
1796e2f04181SAndrew T. Barker   if (op->LinearAssemble) {
1797e2f04181SAndrew T. Barker     return op->LinearAssemble(op, values);
1798e2f04181SAndrew T. Barker   } else {
1799e2f04181SAndrew T. Barker     // Check for valid fallback resource
1800d1d35e2fSjeremylt     const char *resource, *fallback_resource;
1801e2f04181SAndrew T. Barker     ierr = CeedGetResource(op->ceed, &resource); CeedChk(ierr);
1802d1d35e2fSjeremylt     ierr = CeedGetOperatorFallbackResource(op->ceed, &fallback_resource);
1803*78464608Sjeremylt     CeedChk(ierr);
1804d1d35e2fSjeremylt     if (strcmp(fallback_resource, "") && strcmp(resource, fallback_resource)) {
1805e2f04181SAndrew T. Barker       // Fallback to reference Ceed
1806d1d35e2fSjeremylt       if (!op->op_fallback) {
1807e2f04181SAndrew T. Barker         ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
1808e2f04181SAndrew T. Barker       }
1809e2f04181SAndrew T. Barker       // Assemble
1810d1d35e2fSjeremylt       return CeedOperatorLinearAssemble(op->op_fallback, values);
1811e2f04181SAndrew T. Barker     }
1812e2f04181SAndrew T. Barker   }
1813e2f04181SAndrew T. Barker 
1814e2f04181SAndrew T. Barker   // if neither backend nor fallback resource provides
1815e2f04181SAndrew T. Barker   // LinearAssemble, continue with interface-level implementation
1816e2f04181SAndrew T. Barker 
1817d1d35e2fSjeremylt   bool is_composite;
1818d1d35e2fSjeremylt   ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr);
1819e2f04181SAndrew T. Barker 
1820e2f04181SAndrew T. Barker   CeedInt offset = 0;
1821d1d35e2fSjeremylt   if (is_composite) {
1822d1d35e2fSjeremylt     ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr);
1823d1d35e2fSjeremylt     ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr);
1824d1d35e2fSjeremylt     for (int k = 0; k < num_suboperators; ++k) {
1825d1d35e2fSjeremylt       ierr = CeedSingleOperatorAssemble(sub_operators[k], offset, values);
1826e2f04181SAndrew T. Barker       CeedChk(ierr);
1827d1d35e2fSjeremylt       ierr = CeedSingleOperatorAssemblyCountEntries(sub_operators[k],
1828d1d35e2fSjeremylt              &single_entries);
1829e2f04181SAndrew T. Barker       CeedChk(ierr);
1830e2f04181SAndrew T. Barker       offset += single_entries;
1831e2f04181SAndrew T. Barker     }
1832e2f04181SAndrew T. Barker   } else {
1833e2f04181SAndrew T. Barker     ierr = CeedSingleOperatorAssemble(op, offset, values); CeedChk(ierr);
1834e2f04181SAndrew T. Barker   }
1835e2f04181SAndrew T. Barker 
1836e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1837d965c7a7SJeremy L Thompson }
1838d965c7a7SJeremy L Thompson 
1839d965c7a7SJeremy L Thompson /**
1840d99fa3c5SJeremy L Thompson   @brief Create a multigrid coarse operator and level transfer operators
1841d99fa3c5SJeremy L Thompson            for a CeedOperator, creating the prolongation basis from the
1842d99fa3c5SJeremy L Thompson            fine and coarse grid interpolation
1843d99fa3c5SJeremy L Thompson 
1844d1d35e2fSjeremylt   @param[in] op_fine       Fine grid operator
1845d1d35e2fSjeremylt   @param[in] p_mult_fine   L-vector multiplicity in parallel gather/scatter
1846d1d35e2fSjeremylt   @param[in] rstr_coarse   Coarse grid restriction
1847d1d35e2fSjeremylt   @param[in] basis_coarse  Coarse grid active vector basis
1848d1d35e2fSjeremylt   @param[out] op_coarse    Coarse grid operator
1849d1d35e2fSjeremylt   @param[out] op_prolong   Coarse to fine operator
1850d1d35e2fSjeremylt   @param[out] op_restrict  Fine to coarse operator
1851d99fa3c5SJeremy L Thompson 
1852d99fa3c5SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1853d99fa3c5SJeremy L Thompson 
1854d99fa3c5SJeremy L Thompson   @ref User
1855d99fa3c5SJeremy L Thompson **/
1856d1d35e2fSjeremylt int CeedOperatorMultigridLevelCreate(CeedOperator op_fine,
1857d1d35e2fSjeremylt                                      CeedVector p_mult_fine,
1858d1d35e2fSjeremylt                                      CeedElemRestriction rstr_coarse, CeedBasis basis_coarse,
1859d1d35e2fSjeremylt                                      CeedOperator *op_coarse, CeedOperator *op_prolong,
1860d1d35e2fSjeremylt                                      CeedOperator *op_restrict) {
1861d99fa3c5SJeremy L Thompson   int ierr;
1862d99fa3c5SJeremy L Thompson   Ceed ceed;
1863d1d35e2fSjeremylt   ierr = CeedOperatorGetCeed(op_fine, &ceed); CeedChk(ierr);
1864d99fa3c5SJeremy L Thompson 
1865d99fa3c5SJeremy L Thompson   // Check for compatible quadrature spaces
1866d1d35e2fSjeremylt   CeedBasis basis_fine;
1867d1d35e2fSjeremylt   ierr = CeedOperatorGetActiveBasis(op_fine, &basis_fine); CeedChk(ierr);
1868d1d35e2fSjeremylt   CeedInt Q_f, Q_c;
1869d1d35e2fSjeremylt   ierr = CeedBasisGetNumQuadraturePoints(basis_fine, &Q_f); CeedChk(ierr);
1870d1d35e2fSjeremylt   ierr = CeedBasisGetNumQuadraturePoints(basis_coarse, &Q_c); CeedChk(ierr);
1871d1d35e2fSjeremylt   if (Q_f != Q_c)
1872d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
1873e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_DIMENSION,
1874e15f9bd0SJeremy L Thompson                      "Bases must have compatible quadrature spaces");
1875d99fa3c5SJeremy L Thompson   // LCOV_EXCL_STOP
1876d99fa3c5SJeremy L Thompson 
1877d99fa3c5SJeremy L Thompson   // Coarse to fine basis
1878d1d35e2fSjeremylt   CeedInt P_f, P_c, Q = Q_f;
1879d1d35e2fSjeremylt   bool is_tensor_f, is_tensor_c;
1880d1d35e2fSjeremylt   ierr = CeedBasisIsTensor(basis_fine, &is_tensor_f); CeedChk(ierr);
1881d1d35e2fSjeremylt   ierr = CeedBasisIsTensor(basis_coarse, &is_tensor_c); CeedChk(ierr);
1882d1d35e2fSjeremylt   CeedScalar *interp_c, *interp_f, *interp_c_to_f, *tau;
1883d1d35e2fSjeremylt   if (is_tensor_f && is_tensor_c) {
1884d1d35e2fSjeremylt     ierr = CeedBasisGetNumNodes1D(basis_fine, &P_f); CeedChk(ierr);
1885d1d35e2fSjeremylt     ierr = CeedBasisGetNumNodes1D(basis_coarse, &P_c); CeedChk(ierr);
1886d1d35e2fSjeremylt     ierr = CeedBasisGetNumQuadraturePoints1D(basis_coarse, &Q); CeedChk(ierr);
1887d1d35e2fSjeremylt   } else if (!is_tensor_f && !is_tensor_c) {
1888d1d35e2fSjeremylt     ierr = CeedBasisGetNumNodes(basis_fine, &P_f); CeedChk(ierr);
1889d1d35e2fSjeremylt     ierr = CeedBasisGetNumNodes(basis_coarse, &P_c); CeedChk(ierr);
1890d99fa3c5SJeremy L Thompson   } else {
1891d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
1892e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_MINOR,
1893e15f9bd0SJeremy L Thompson                      "Bases must both be tensor or non-tensor");
1894d99fa3c5SJeremy L Thompson     // LCOV_EXCL_STOP
1895d99fa3c5SJeremy L Thompson   }
1896d99fa3c5SJeremy L Thompson 
1897d1d35e2fSjeremylt   ierr = CeedMalloc(Q*P_f, &interp_f); CeedChk(ierr);
1898d1d35e2fSjeremylt   ierr = CeedMalloc(Q*P_c, &interp_c); CeedChk(ierr);
1899d1d35e2fSjeremylt   ierr = CeedCalloc(P_c*P_f, &interp_c_to_f); CeedChk(ierr);
1900d99fa3c5SJeremy L Thompson   ierr = CeedMalloc(Q, &tau); CeedChk(ierr);
1901d1d35e2fSjeremylt   if (is_tensor_f) {
1902d1d35e2fSjeremylt     memcpy(interp_f, basis_fine->interp_1d, Q*P_f*sizeof basis_fine->interp_1d[0]);
1903d1d35e2fSjeremylt     memcpy(interp_c, basis_coarse->interp_1d,
1904d1d35e2fSjeremylt            Q*P_c*sizeof basis_coarse->interp_1d[0]);
1905d99fa3c5SJeremy L Thompson   } else {
1906d1d35e2fSjeremylt     memcpy(interp_f, basis_fine->interp, Q*P_f*sizeof basis_fine->interp[0]);
1907d1d35e2fSjeremylt     memcpy(interp_c, basis_coarse->interp, Q*P_c*sizeof basis_coarse->interp[0]);
1908d99fa3c5SJeremy L Thompson   }
1909d99fa3c5SJeremy L Thompson 
1910d1d35e2fSjeremylt   // -- QR Factorization, interp_f = Q R
1911d1d35e2fSjeremylt   ierr = CeedQRFactorization(ceed, interp_f, tau, Q, P_f); CeedChk(ierr);
1912d99fa3c5SJeremy L Thompson 
1913d1d35e2fSjeremylt   // -- Apply Qtranspose, interp_c = Qtranspose interp_c
1914d1d35e2fSjeremylt   ierr = CeedHouseholderApplyQ(interp_c, interp_f, tau, CEED_TRANSPOSE,
1915d1d35e2fSjeremylt                                Q, P_c, P_f, P_c, 1); CeedChk(ierr);
1916d99fa3c5SJeremy L Thompson 
1917d1d35e2fSjeremylt   // -- Apply Rinv, interp_c_to_f = Rinv interp_c
1918d1d35e2fSjeremylt   for (CeedInt j=0; j<P_c; j++) { // Column j
1919d1d35e2fSjeremylt     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];
1920d1d35e2fSjeremylt     for (CeedInt i=P_f-2; i>=0; i--) { // Row i
1921d1d35e2fSjeremylt       interp_c_to_f[j+P_c*i] = interp_c[j+P_c*i];
1922d1d35e2fSjeremylt       for (CeedInt k=i+1; k<P_f; k++)
1923d1d35e2fSjeremylt         interp_c_to_f[j+P_c*i] -= interp_f[k+P_f*i]*interp_c_to_f[j+P_c*k];
1924d1d35e2fSjeremylt       interp_c_to_f[j+P_c*i] /= interp_f[i+P_f*i];
1925d99fa3c5SJeremy L Thompson     }
1926d99fa3c5SJeremy L Thompson   }
1927d99fa3c5SJeremy L Thompson   ierr = CeedFree(&tau); CeedChk(ierr);
1928d1d35e2fSjeremylt   ierr = CeedFree(&interp_c); CeedChk(ierr);
1929d1d35e2fSjeremylt   ierr = CeedFree(&interp_f); CeedChk(ierr);
1930d99fa3c5SJeremy L Thompson 
1931d1d35e2fSjeremylt   // Complete with interp_c_to_f versions of code
1932d1d35e2fSjeremylt   if (is_tensor_f) {
1933d1d35e2fSjeremylt     ierr = CeedOperatorMultigridLevelCreateTensorH1(op_fine, p_mult_fine,
1934d1d35e2fSjeremylt            rstr_coarse, basis_coarse, interp_c_to_f, op_coarse, op_prolong, op_restrict);
1935d99fa3c5SJeremy L Thompson     CeedChk(ierr);
1936d99fa3c5SJeremy L Thompson   } else {
1937d1d35e2fSjeremylt     ierr = CeedOperatorMultigridLevelCreateH1(op_fine, p_mult_fine,
1938d1d35e2fSjeremylt            rstr_coarse, basis_coarse, interp_c_to_f, op_coarse, op_prolong, op_restrict);
1939d99fa3c5SJeremy L Thompson     CeedChk(ierr);
1940d99fa3c5SJeremy L Thompson   }
1941d99fa3c5SJeremy L Thompson 
1942d99fa3c5SJeremy L Thompson   // Cleanup
1943d1d35e2fSjeremylt   ierr = CeedFree(&interp_c_to_f); CeedChk(ierr);
1944e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1945d99fa3c5SJeremy L Thompson }
1946d99fa3c5SJeremy L Thompson 
1947d99fa3c5SJeremy L Thompson /**
1948d99fa3c5SJeremy L Thompson   @brief Create a multigrid coarse operator and level transfer operators
1949d99fa3c5SJeremy L Thompson            for a CeedOperator with a tensor basis for the active basis
1950d99fa3c5SJeremy L Thompson 
1951d1d35e2fSjeremylt   @param[in] op_fine        Fine grid operator
1952d1d35e2fSjeremylt   @param[in] p_mult_fine    L-vector multiplicity in parallel gather/scatter
1953d1d35e2fSjeremylt   @param[in] rstr_coarse    Coarse grid restriction
1954d1d35e2fSjeremylt   @param[in] basis_coarse   Coarse grid active vector basis
1955d1d35e2fSjeremylt   @param[in] interp_c_to_f  Matrix for coarse to fine interpolation
1956d1d35e2fSjeremylt   @param[out] op_coarse     Coarse grid operator
1957d1d35e2fSjeremylt   @param[out] op_prolong    Coarse to fine operator
1958d1d35e2fSjeremylt   @param[out] op_restrict   Fine to coarse operator
1959d99fa3c5SJeremy L Thompson 
1960d99fa3c5SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1961d99fa3c5SJeremy L Thompson 
1962d99fa3c5SJeremy L Thompson   @ref User
1963d99fa3c5SJeremy L Thompson **/
1964d1d35e2fSjeremylt int CeedOperatorMultigridLevelCreateTensorH1(CeedOperator op_fine,
1965d1d35e2fSjeremylt     CeedVector p_mult_fine, CeedElemRestriction rstr_coarse, CeedBasis basis_coarse,
1966d1d35e2fSjeremylt     const CeedScalar *interp_c_to_f, CeedOperator *op_coarse,
1967d1d35e2fSjeremylt     CeedOperator *op_prolong, CeedOperator *op_restrict) {
1968d99fa3c5SJeremy L Thompson   int ierr;
1969d99fa3c5SJeremy L Thompson   Ceed ceed;
1970d1d35e2fSjeremylt   ierr = CeedOperatorGetCeed(op_fine, &ceed); CeedChk(ierr);
1971d99fa3c5SJeremy L Thompson 
1972d99fa3c5SJeremy L Thompson   // Check for compatible quadrature spaces
1973d1d35e2fSjeremylt   CeedBasis basis_fine;
1974d1d35e2fSjeremylt   ierr = CeedOperatorGetActiveBasis(op_fine, &basis_fine); CeedChk(ierr);
1975d1d35e2fSjeremylt   CeedInt Q_f, Q_c;
1976d1d35e2fSjeremylt   ierr = CeedBasisGetNumQuadraturePoints(basis_fine, &Q_f); CeedChk(ierr);
1977d1d35e2fSjeremylt   ierr = CeedBasisGetNumQuadraturePoints(basis_coarse, &Q_c); CeedChk(ierr);
1978d1d35e2fSjeremylt   if (Q_f != Q_c)
1979d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
1980e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_DIMENSION,
1981e15f9bd0SJeremy L Thompson                      "Bases must have compatible quadrature spaces");
1982d99fa3c5SJeremy L Thompson   // LCOV_EXCL_STOP
1983d99fa3c5SJeremy L Thompson 
1984d99fa3c5SJeremy L Thompson   // Coarse to fine basis
1985d1d35e2fSjeremylt   CeedInt dim, num_comp, num_nodes_c, P_1d_f, P_1d_c;
1986d1d35e2fSjeremylt   ierr = CeedBasisGetDimension(basis_fine, &dim); CeedChk(ierr);
1987d1d35e2fSjeremylt   ierr = CeedBasisGetNumComponents(basis_fine, &num_comp); CeedChk(ierr);
1988d1d35e2fSjeremylt   ierr = CeedBasisGetNumNodes1D(basis_fine, &P_1d_f); CeedChk(ierr);
1989d1d35e2fSjeremylt   ierr = CeedElemRestrictionGetElementSize(rstr_coarse, &num_nodes_c);
1990d99fa3c5SJeremy L Thompson   CeedChk(ierr);
1991d1d35e2fSjeremylt   P_1d_c = dim == 1 ? num_nodes_c :
1992d1d35e2fSjeremylt            dim == 2 ? sqrt(num_nodes_c) :
1993d1d35e2fSjeremylt            cbrt(num_nodes_c);
1994d1d35e2fSjeremylt   CeedScalar *q_ref, *q_weight, *grad;
1995d1d35e2fSjeremylt   ierr = CeedCalloc(P_1d_f, &q_ref); CeedChk(ierr);
1996d1d35e2fSjeremylt   ierr = CeedCalloc(P_1d_f, &q_weight); CeedChk(ierr);
1997d1d35e2fSjeremylt   ierr = CeedCalloc(P_1d_f*P_1d_c*dim, &grad); CeedChk(ierr);
1998d1d35e2fSjeremylt   CeedBasis basis_c_to_f;
1999d1d35e2fSjeremylt   ierr = CeedBasisCreateTensorH1(ceed, dim, num_comp, P_1d_c, P_1d_f,
2000d1d35e2fSjeremylt                                  interp_c_to_f, grad, q_ref, q_weight, &basis_c_to_f);
2001d99fa3c5SJeremy L Thompson   CeedChk(ierr);
2002d1d35e2fSjeremylt   ierr = CeedFree(&q_ref); CeedChk(ierr);
2003d1d35e2fSjeremylt   ierr = CeedFree(&q_weight); CeedChk(ierr);
2004d99fa3c5SJeremy L Thompson   ierr = CeedFree(&grad); CeedChk(ierr);
2005d99fa3c5SJeremy L Thompson 
2006d99fa3c5SJeremy L Thompson   // Core code
2007d1d35e2fSjeremylt   ierr = CeedOperatorMultigridLevel_Core(op_fine, p_mult_fine, rstr_coarse,
2008d1d35e2fSjeremylt                                          basis_coarse, basis_c_to_f, op_coarse,
2009d1d35e2fSjeremylt                                          op_prolong, op_restrict);
2010d99fa3c5SJeremy L Thompson   CeedChk(ierr);
2011e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2012d99fa3c5SJeremy L Thompson }
2013d99fa3c5SJeremy L Thompson 
2014d99fa3c5SJeremy L Thompson /**
2015d99fa3c5SJeremy L Thompson   @brief Create a multigrid coarse operator and level transfer operators
2016d99fa3c5SJeremy L Thompson            for a CeedOperator with a non-tensor basis for the active vector
2017d99fa3c5SJeremy L Thompson 
2018d1d35e2fSjeremylt   @param[in] op_fine        Fine grid operator
2019d1d35e2fSjeremylt   @param[in] p_mult_fine    L-vector multiplicity in parallel gather/scatter
2020d1d35e2fSjeremylt   @param[in] rstr_coarse    Coarse grid restriction
2021d1d35e2fSjeremylt   @param[in] basis_coarse   Coarse grid active vector basis
2022d1d35e2fSjeremylt   @param[in] interp_c_to_f  Matrix for coarse to fine interpolation
2023d1d35e2fSjeremylt   @param[out] op_coarse     Coarse grid operator
2024d1d35e2fSjeremylt   @param[out] op_prolong    Coarse to fine operator
2025d1d35e2fSjeremylt   @param[out] op_restrict   Fine to coarse operator
2026d99fa3c5SJeremy L Thompson 
2027d99fa3c5SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
2028d99fa3c5SJeremy L Thompson 
2029d99fa3c5SJeremy L Thompson   @ref User
2030d99fa3c5SJeremy L Thompson **/
2031d1d35e2fSjeremylt int CeedOperatorMultigridLevelCreateH1(CeedOperator op_fine,
2032d1d35e2fSjeremylt                                        CeedVector p_mult_fine,
2033d1d35e2fSjeremylt                                        CeedElemRestriction rstr_coarse,
2034d1d35e2fSjeremylt                                        CeedBasis basis_coarse,
2035d1d35e2fSjeremylt                                        const CeedScalar *interp_c_to_f,
2036d1d35e2fSjeremylt                                        CeedOperator *op_coarse,
2037d1d35e2fSjeremylt                                        CeedOperator *op_prolong,
2038d1d35e2fSjeremylt                                        CeedOperator *op_restrict) {
2039d99fa3c5SJeremy L Thompson   int ierr;
2040d99fa3c5SJeremy L Thompson   Ceed ceed;
2041d1d35e2fSjeremylt   ierr = CeedOperatorGetCeed(op_fine, &ceed); CeedChk(ierr);
2042d99fa3c5SJeremy L Thompson 
2043d99fa3c5SJeremy L Thompson   // Check for compatible quadrature spaces
2044d1d35e2fSjeremylt   CeedBasis basis_fine;
2045d1d35e2fSjeremylt   ierr = CeedOperatorGetActiveBasis(op_fine, &basis_fine); CeedChk(ierr);
2046d1d35e2fSjeremylt   CeedInt Q_f, Q_c;
2047d1d35e2fSjeremylt   ierr = CeedBasisGetNumQuadraturePoints(basis_fine, &Q_f); CeedChk(ierr);
2048d1d35e2fSjeremylt   ierr = CeedBasisGetNumQuadraturePoints(basis_coarse, &Q_c); CeedChk(ierr);
2049d1d35e2fSjeremylt   if (Q_f != Q_c)
2050d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
2051e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_DIMENSION,
2052e15f9bd0SJeremy L Thompson                      "Bases must have compatible quadrature spaces");
2053d99fa3c5SJeremy L Thompson   // LCOV_EXCL_STOP
2054d99fa3c5SJeremy L Thompson 
2055d99fa3c5SJeremy L Thompson   // Coarse to fine basis
2056d99fa3c5SJeremy L Thompson   CeedElemTopology topo;
2057d1d35e2fSjeremylt   ierr = CeedBasisGetTopology(basis_fine, &topo); CeedChk(ierr);
2058d1d35e2fSjeremylt   CeedInt dim, num_comp, num_nodes_c, num_nodes_f;
2059d1d35e2fSjeremylt   ierr = CeedBasisGetDimension(basis_fine, &dim); CeedChk(ierr);
2060d1d35e2fSjeremylt   ierr = CeedBasisGetNumComponents(basis_fine, &num_comp); CeedChk(ierr);
2061d1d35e2fSjeremylt   ierr = CeedBasisGetNumNodes(basis_fine, &num_nodes_f); CeedChk(ierr);
2062d1d35e2fSjeremylt   ierr = CeedElemRestrictionGetElementSize(rstr_coarse, &num_nodes_c);
2063d99fa3c5SJeremy L Thompson   CeedChk(ierr);
2064d1d35e2fSjeremylt   CeedScalar *q_ref, *q_weight, *grad;
2065d1d35e2fSjeremylt   ierr = CeedCalloc(num_nodes_f, &q_ref); CeedChk(ierr);
2066d1d35e2fSjeremylt   ierr = CeedCalloc(num_nodes_f, &q_weight); CeedChk(ierr);
2067d1d35e2fSjeremylt   ierr = CeedCalloc(num_nodes_f*num_nodes_c*dim, &grad); CeedChk(ierr);
2068d1d35e2fSjeremylt   CeedBasis basis_c_to_f;
2069d1d35e2fSjeremylt   ierr = CeedBasisCreateH1(ceed, topo, num_comp, num_nodes_c, num_nodes_f,
2070d1d35e2fSjeremylt                            interp_c_to_f, grad, q_ref, q_weight, &basis_c_to_f);
2071d99fa3c5SJeremy L Thompson   CeedChk(ierr);
2072d1d35e2fSjeremylt   ierr = CeedFree(&q_ref); CeedChk(ierr);
2073d1d35e2fSjeremylt   ierr = CeedFree(&q_weight); CeedChk(ierr);
2074d99fa3c5SJeremy L Thompson   ierr = CeedFree(&grad); CeedChk(ierr);
2075d99fa3c5SJeremy L Thompson 
2076d99fa3c5SJeremy L Thompson   // Core code
2077d1d35e2fSjeremylt   ierr = CeedOperatorMultigridLevel_Core(op_fine, p_mult_fine, rstr_coarse,
2078d1d35e2fSjeremylt                                          basis_coarse, basis_c_to_f, op_coarse,
2079d1d35e2fSjeremylt                                          op_prolong, op_restrict);
2080d99fa3c5SJeremy L Thompson   CeedChk(ierr);
2081e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2082d99fa3c5SJeremy L Thompson }
2083d99fa3c5SJeremy L Thompson 
2084d99fa3c5SJeremy L Thompson /**
20853bd813ffSjeremylt   @brief Build a FDM based approximate inverse for each element for a
20863bd813ffSjeremylt            CeedOperator
20873bd813ffSjeremylt 
20883bd813ffSjeremylt   This returns a CeedOperator and CeedVector to apply a Fast Diagonalization
20893bd813ffSjeremylt     Method based approximate inverse. This function obtains the simultaneous
20903bd813ffSjeremylt     diagonalization for the 1D mass and Laplacian operators,
20913bd813ffSjeremylt       M = V^T V, K = V^T S V.
20923bd813ffSjeremylt     The assembled QFunction is used to modify the eigenvalues from simultaneous
20933bd813ffSjeremylt     diagonalization and obtain an approximate inverse of the form
20943bd813ffSjeremylt       V^T S^hat V. The CeedOperator must be linear and non-composite. The
20953bd813ffSjeremylt     associated CeedQFunction must therefore also be linear.
20963bd813ffSjeremylt 
20973bd813ffSjeremylt   @param op            CeedOperator to create element inverses
2098d1d35e2fSjeremylt   @param[out] fdm_inv  CeedOperator to apply the action of a FDM based inverse
20993bd813ffSjeremylt                          for each element
21003bd813ffSjeremylt   @param request       Address of CeedRequest for non-blocking completion, else
21014cc79fe7SJed Brown                          @ref CEED_REQUEST_IMMEDIATE
21023bd813ffSjeremylt 
21033bd813ffSjeremylt   @return An error code: 0 - success, otherwise - failure
21043bd813ffSjeremylt 
21057a982d89SJeremy L. Thompson   @ref Backend
21063bd813ffSjeremylt **/
2107d1d35e2fSjeremylt int CeedOperatorCreateFDMElementInverse(CeedOperator op, CeedOperator *fdm_inv,
21083bd813ffSjeremylt                                         CeedRequest *request) {
21093bd813ffSjeremylt   int ierr;
2110e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
21113bd813ffSjeremylt 
2112713f43c3Sjeremylt   // Use backend version, if available
2113713f43c3Sjeremylt   if (op->CreateFDMElementInverse) {
2114d1d35e2fSjeremylt     ierr = op->CreateFDMElementInverse(op, fdm_inv, request); CeedChk(ierr);
2115713f43c3Sjeremylt   } else {
2116713f43c3Sjeremylt     // Fallback to reference Ceed
2117d1d35e2fSjeremylt     if (!op->op_fallback) {
2118713f43c3Sjeremylt       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
21193bd813ffSjeremylt     }
2120713f43c3Sjeremylt     // Assemble
2121d1d35e2fSjeremylt     ierr = op->op_fallback->CreateFDMElementInverse(op->op_fallback, fdm_inv,
21223bd813ffSjeremylt            request); CeedChk(ierr);
21233bd813ffSjeremylt   }
2124e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
21253bd813ffSjeremylt }
21263bd813ffSjeremylt 
21277a982d89SJeremy L. Thompson /**
21287a982d89SJeremy L. Thompson   @brief View a CeedOperator
21297a982d89SJeremy L. Thompson 
21307a982d89SJeremy L. Thompson   @param[in] op      CeedOperator to view
21317a982d89SJeremy L. Thompson   @param[in] stream  Stream to write; typically stdout/stderr or a file
21327a982d89SJeremy L. Thompson 
21337a982d89SJeremy L. Thompson   @return Error code: 0 - success, otherwise - failure
21347a982d89SJeremy L. Thompson 
21357a982d89SJeremy L. Thompson   @ref User
21367a982d89SJeremy L. Thompson **/
21377a982d89SJeremy L. Thompson int CeedOperatorView(CeedOperator op, FILE *stream) {
21387a982d89SJeremy L. Thompson   int ierr;
21397a982d89SJeremy L. Thompson 
21407a982d89SJeremy L. Thompson   if (op->composite) {
21417a982d89SJeremy L. Thompson     fprintf(stream, "Composite CeedOperator\n");
21427a982d89SJeremy L. Thompson 
2143d1d35e2fSjeremylt     for (CeedInt i=0; i<op->num_suboperators; i++) {
21447a982d89SJeremy L. Thompson       fprintf(stream, "  SubOperator [%d]:\n", i);
2145d1d35e2fSjeremylt       ierr = CeedOperatorSingleView(op->sub_operators[i], 1, stream);
21467a982d89SJeremy L. Thompson       CeedChk(ierr);
21477a982d89SJeremy L. Thompson     }
21487a982d89SJeremy L. Thompson   } else {
21497a982d89SJeremy L. Thompson     fprintf(stream, "CeedOperator\n");
21507a982d89SJeremy L. Thompson     ierr = CeedOperatorSingleView(op, 0, stream); CeedChk(ierr);
21517a982d89SJeremy L. Thompson   }
2152e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
21537a982d89SJeremy L. Thompson }
21543bd813ffSjeremylt 
21553bd813ffSjeremylt /**
21563bd813ffSjeremylt   @brief Apply CeedOperator to a vector
2157d7b241e6Sjeremylt 
2158d7b241e6Sjeremylt   This computes the action of the operator on the specified (active) input,
2159d7b241e6Sjeremylt   yielding its (active) output.  All inputs and outputs must be specified using
2160d7b241e6Sjeremylt   CeedOperatorSetField().
2161d7b241e6Sjeremylt 
2162d7b241e6Sjeremylt   @param op        CeedOperator to apply
21634cc79fe7SJed Brown   @param[in] in    CeedVector containing input state or @ref CEED_VECTOR_NONE if
216434138859Sjeremylt                      there are no active inputs
2165b11c1e72Sjeremylt   @param[out] out  CeedVector to store result of applying operator (must be
21664cc79fe7SJed Brown                      distinct from @a in) or @ref CEED_VECTOR_NONE if there are no
216734138859Sjeremylt                      active outputs
2168d7b241e6Sjeremylt   @param request   Address of CeedRequest for non-blocking completion, else
21694cc79fe7SJed Brown                      @ref CEED_REQUEST_IMMEDIATE
2170b11c1e72Sjeremylt 
2171b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
2172dfdf5a53Sjeremylt 
21737a982d89SJeremy L. Thompson   @ref User
2174b11c1e72Sjeremylt **/
2175692c2638Sjeremylt int CeedOperatorApply(CeedOperator op, CeedVector in, CeedVector out,
2176692c2638Sjeremylt                       CeedRequest *request) {
2177d7b241e6Sjeremylt   int ierr;
2178e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
2179d7b241e6Sjeremylt 
2180d1d35e2fSjeremylt   if (op->num_elem)  {
2181250756a7Sjeremylt     // Standard Operator
2182cae8b89aSjeremylt     if (op->Apply) {
2183250756a7Sjeremylt       ierr = op->Apply(op, in, out, request); CeedChk(ierr);
2184cae8b89aSjeremylt     } else {
2185cae8b89aSjeremylt       // Zero all output vectors
2186250756a7Sjeremylt       CeedQFunction qf = op->qf;
2187d1d35e2fSjeremylt       for (CeedInt i=0; i<qf->num_output_fields; i++) {
2188d1d35e2fSjeremylt         CeedVector vec = op->output_fields[i]->vec;
2189cae8b89aSjeremylt         if (vec == CEED_VECTOR_ACTIVE)
2190cae8b89aSjeremylt           vec = out;
2191cae8b89aSjeremylt         if (vec != CEED_VECTOR_NONE) {
2192cae8b89aSjeremylt           ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr);
2193cae8b89aSjeremylt         }
2194cae8b89aSjeremylt       }
2195250756a7Sjeremylt       // Apply
2196250756a7Sjeremylt       ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr);
2197250756a7Sjeremylt     }
2198250756a7Sjeremylt   } else if (op->composite) {
2199250756a7Sjeremylt     // Composite Operator
2200250756a7Sjeremylt     if (op->ApplyComposite) {
2201250756a7Sjeremylt       ierr = op->ApplyComposite(op, in, out, request); CeedChk(ierr);
2202250756a7Sjeremylt     } else {
2203d1d35e2fSjeremylt       CeedInt num_suboperators;
2204d1d35e2fSjeremylt       ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr);
2205d1d35e2fSjeremylt       CeedOperator *sub_operators;
2206d1d35e2fSjeremylt       ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr);
2207250756a7Sjeremylt 
2208250756a7Sjeremylt       // Zero all output vectors
2209250756a7Sjeremylt       if (out != CEED_VECTOR_NONE) {
2210cae8b89aSjeremylt         ierr = CeedVectorSetValue(out, 0.0); CeedChk(ierr);
2211cae8b89aSjeremylt       }
2212d1d35e2fSjeremylt       for (CeedInt i=0; i<num_suboperators; i++) {
2213d1d35e2fSjeremylt         for (CeedInt j=0; j<sub_operators[i]->qf->num_output_fields; j++) {
2214d1d35e2fSjeremylt           CeedVector vec = sub_operators[i]->output_fields[j]->vec;
2215250756a7Sjeremylt           if (vec != CEED_VECTOR_ACTIVE && vec != CEED_VECTOR_NONE) {
2216250756a7Sjeremylt             ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr);
2217250756a7Sjeremylt           }
2218250756a7Sjeremylt         }
2219250756a7Sjeremylt       }
2220250756a7Sjeremylt       // Apply
2221d1d35e2fSjeremylt       for (CeedInt i=0; i<op->num_suboperators; i++) {
2222d1d35e2fSjeremylt         ierr = CeedOperatorApplyAdd(op->sub_operators[i], in, out, request);
2223cae8b89aSjeremylt         CeedChk(ierr);
2224cae8b89aSjeremylt       }
2225cae8b89aSjeremylt     }
2226250756a7Sjeremylt   }
2227e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2228cae8b89aSjeremylt }
2229cae8b89aSjeremylt 
2230cae8b89aSjeremylt /**
2231cae8b89aSjeremylt   @brief Apply CeedOperator to a vector and add result to output vector
2232cae8b89aSjeremylt 
2233cae8b89aSjeremylt   This computes the action of the operator on the specified (active) input,
2234cae8b89aSjeremylt   yielding its (active) output.  All inputs and outputs must be specified using
2235cae8b89aSjeremylt   CeedOperatorSetField().
2236cae8b89aSjeremylt 
2237cae8b89aSjeremylt   @param op        CeedOperator to apply
2238cae8b89aSjeremylt   @param[in] in    CeedVector containing input state or NULL if there are no
2239cae8b89aSjeremylt                      active inputs
2240cae8b89aSjeremylt   @param[out] out  CeedVector to sum in result of applying operator (must be
2241cae8b89aSjeremylt                      distinct from @a in) or NULL if there are no active outputs
2242cae8b89aSjeremylt   @param request   Address of CeedRequest for non-blocking completion, else
22434cc79fe7SJed Brown                      @ref CEED_REQUEST_IMMEDIATE
2244cae8b89aSjeremylt 
2245cae8b89aSjeremylt   @return An error code: 0 - success, otherwise - failure
2246cae8b89aSjeremylt 
22477a982d89SJeremy L. Thompson   @ref User
2248cae8b89aSjeremylt **/
2249cae8b89aSjeremylt int CeedOperatorApplyAdd(CeedOperator op, CeedVector in, CeedVector out,
2250cae8b89aSjeremylt                          CeedRequest *request) {
2251cae8b89aSjeremylt   int ierr;
2252e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
2253cae8b89aSjeremylt 
2254d1d35e2fSjeremylt   if (op->num_elem)  {
2255250756a7Sjeremylt     // Standard Operator
2256250756a7Sjeremylt     ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr);
2257250756a7Sjeremylt   } else if (op->composite) {
2258250756a7Sjeremylt     // Composite Operator
2259250756a7Sjeremylt     if (op->ApplyAddComposite) {
2260250756a7Sjeremylt       ierr = op->ApplyAddComposite(op, in, out, request); CeedChk(ierr);
2261cae8b89aSjeremylt     } else {
2262d1d35e2fSjeremylt       CeedInt num_suboperators;
2263d1d35e2fSjeremylt       ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr);
2264d1d35e2fSjeremylt       CeedOperator *sub_operators;
2265d1d35e2fSjeremylt       ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr);
2266250756a7Sjeremylt 
2267d1d35e2fSjeremylt       for (CeedInt i=0; i<num_suboperators; i++) {
2268d1d35e2fSjeremylt         ierr = CeedOperatorApplyAdd(sub_operators[i], in, out, request);
2269cae8b89aSjeremylt         CeedChk(ierr);
22701d7d2407SJeremy L Thompson       }
2271250756a7Sjeremylt     }
2272250756a7Sjeremylt   }
2273e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2274d7b241e6Sjeremylt }
2275d7b241e6Sjeremylt 
2276d7b241e6Sjeremylt /**
2277b11c1e72Sjeremylt   @brief Destroy a CeedOperator
2278d7b241e6Sjeremylt 
2279d7b241e6Sjeremylt   @param op  CeedOperator to destroy
2280b11c1e72Sjeremylt 
2281b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
2282dfdf5a53Sjeremylt 
22837a982d89SJeremy L. Thompson   @ref User
2284b11c1e72Sjeremylt **/
2285d7b241e6Sjeremylt int CeedOperatorDestroy(CeedOperator *op) {
2286d7b241e6Sjeremylt   int ierr;
2287d7b241e6Sjeremylt 
2288d1d35e2fSjeremylt   if (!*op || --(*op)->ref_count > 0) return CEED_ERROR_SUCCESS;
2289d7b241e6Sjeremylt   if ((*op)->Destroy) {
2290d7b241e6Sjeremylt     ierr = (*op)->Destroy(*op); CeedChk(ierr);
2291d7b241e6Sjeremylt   }
2292fe2413ffSjeremylt   ierr = CeedDestroy(&(*op)->ceed); CeedChk(ierr);
2293fe2413ffSjeremylt   // Free fields
2294d1d35e2fSjeremylt   for (int i=0; i<(*op)->num_fields; i++)
2295d1d35e2fSjeremylt     if ((*op)->input_fields[i]) {
2296d1d35e2fSjeremylt       if ((*op)->input_fields[i]->elem_restr != CEED_ELEMRESTRICTION_NONE) {
2297d1d35e2fSjeremylt         ierr = CeedElemRestrictionDestroy(&(*op)->input_fields[i]->elem_restr);
229871352a93Sjeremylt         CeedChk(ierr);
229915910d16Sjeremylt       }
2300d1d35e2fSjeremylt       if ((*op)->input_fields[i]->basis != CEED_BASIS_COLLOCATED) {
2301d1d35e2fSjeremylt         ierr = CeedBasisDestroy(&(*op)->input_fields[i]->basis); CeedChk(ierr);
230271352a93Sjeremylt       }
2303d1d35e2fSjeremylt       if ((*op)->input_fields[i]->vec != CEED_VECTOR_ACTIVE &&
2304d1d35e2fSjeremylt           (*op)->input_fields[i]->vec != CEED_VECTOR_NONE ) {
2305d1d35e2fSjeremylt         ierr = CeedVectorDestroy(&(*op)->input_fields[i]->vec); CeedChk(ierr);
230671352a93Sjeremylt       }
2307d1d35e2fSjeremylt       ierr = CeedFree(&(*op)->input_fields[i]->field_name); CeedChk(ierr);
2308d1d35e2fSjeremylt       ierr = CeedFree(&(*op)->input_fields[i]); CeedChk(ierr);
2309fe2413ffSjeremylt     }
2310d1d35e2fSjeremylt   for (int i=0; i<(*op)->num_fields; i++)
2311d1d35e2fSjeremylt     if ((*op)->output_fields[i]) {
2312d1d35e2fSjeremylt       ierr = CeedElemRestrictionDestroy(&(*op)->output_fields[i]->elem_restr);
231371352a93Sjeremylt       CeedChk(ierr);
2314d1d35e2fSjeremylt       if ((*op)->output_fields[i]->basis != CEED_BASIS_COLLOCATED) {
2315d1d35e2fSjeremylt         ierr = CeedBasisDestroy(&(*op)->output_fields[i]->basis); CeedChk(ierr);
231671352a93Sjeremylt       }
2317d1d35e2fSjeremylt       if ((*op)->output_fields[i]->vec != CEED_VECTOR_ACTIVE &&
2318d1d35e2fSjeremylt           (*op)->output_fields[i]->vec != CEED_VECTOR_NONE ) {
2319d1d35e2fSjeremylt         ierr = CeedVectorDestroy(&(*op)->output_fields[i]->vec); CeedChk(ierr);
232071352a93Sjeremylt       }
2321d1d35e2fSjeremylt       ierr = CeedFree(&(*op)->output_fields[i]->field_name); CeedChk(ierr);
2322d1d35e2fSjeremylt       ierr = CeedFree(&(*op)->output_fields[i]); CeedChk(ierr);
2323fe2413ffSjeremylt     }
2324d1d35e2fSjeremylt   // Destroy sub_operators
2325d1d35e2fSjeremylt   for (int i=0; i<(*op)->num_suboperators; i++)
2326d1d35e2fSjeremylt     if ((*op)->sub_operators[i]) {
2327d1d35e2fSjeremylt       ierr = CeedOperatorDestroy(&(*op)->sub_operators[i]); CeedChk(ierr);
232852d6035fSJeremy L Thompson     }
2329e15f9bd0SJeremy L Thompson   if ((*op)->qf)
2330e15f9bd0SJeremy L Thompson     // LCOV_EXCL_START
2331d1d35e2fSjeremylt     (*op)->qf->operators_set--;
2332e15f9bd0SJeremy L Thompson   // LCOV_EXCL_STOP
2333d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->qf); CeedChk(ierr);
2334e15f9bd0SJeremy L Thompson   if ((*op)->dqf && (*op)->dqf != CEED_QFUNCTION_NONE)
2335e15f9bd0SJeremy L Thompson     // LCOV_EXCL_START
2336d1d35e2fSjeremylt     (*op)->dqf->operators_set--;
2337e15f9bd0SJeremy L Thompson   // LCOV_EXCL_STOP
2338d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->dqf); CeedChk(ierr);
2339e15f9bd0SJeremy L Thompson   if ((*op)->dqfT && (*op)->dqfT != CEED_QFUNCTION_NONE)
2340e15f9bd0SJeremy L Thompson     // LCOV_EXCL_START
2341d1d35e2fSjeremylt     (*op)->dqfT->operators_set--;
2342e15f9bd0SJeremy L Thompson   // LCOV_EXCL_STOP
2343d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->dqfT); CeedChk(ierr);
2344fe2413ffSjeremylt 
23455107b09fSJeremy L Thompson   // Destroy fallback
2346d1d35e2fSjeremylt   if ((*op)->op_fallback) {
2347d1d35e2fSjeremylt     ierr = (*op)->qf_fallback->Destroy((*op)->qf_fallback); CeedChk(ierr);
2348d1d35e2fSjeremylt     ierr = CeedFree(&(*op)->qf_fallback); CeedChk(ierr);
2349d1d35e2fSjeremylt     ierr = (*op)->op_fallback->Destroy((*op)->op_fallback); CeedChk(ierr);
2350d1d35e2fSjeremylt     ierr = CeedFree(&(*op)->op_fallback); CeedChk(ierr);
23515107b09fSJeremy L Thompson   }
23525107b09fSJeremy L Thompson 
2353d1d35e2fSjeremylt   ierr = CeedFree(&(*op)->input_fields); CeedChk(ierr);
2354d1d35e2fSjeremylt   ierr = CeedFree(&(*op)->output_fields); CeedChk(ierr);
2355d1d35e2fSjeremylt   ierr = CeedFree(&(*op)->sub_operators); CeedChk(ierr);
2356d7b241e6Sjeremylt   ierr = CeedFree(op); CeedChk(ierr);
2357e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2358d7b241e6Sjeremylt }
2359d7b241e6Sjeremylt 
2360d7b241e6Sjeremylt /// @}
2361