xref: /libCEED/interface/ceed-operator.c (revision e2f04181a00c6a5b9d49ef9d074211a68e322886)
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 
173d576824SJeremy L Thompson #include <ceed.h>
18d863ab9bSjeremylt #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
487a982d89SJeremy L. Thompson   const char *resource, *fallbackresource;
497a982d89SJeremy L. Thompson   ierr = CeedGetResource(op->ceed, &resource); CeedChk(ierr);
507a982d89SJeremy L. Thompson   ierr = CeedGetOperatorFallbackResource(op->ceed, &fallbackresource);
517a982d89SJeremy L. Thompson   CeedChk(ierr);
527a982d89SJeremy L. Thompson   if (!strcmp(resource, fallbackresource))
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"
567a982d89SJeremy L. Thompson                      "fallback to resource %s", resource, fallbackresource);
577a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
587a982d89SJeremy L. Thompson 
597a982d89SJeremy L. Thompson   // Fallback Ceed
607a982d89SJeremy L. Thompson   Ceed ceedref;
617a982d89SJeremy L. Thompson   if (!op->ceed->opfallbackceed) {
627a982d89SJeremy L. Thompson     ierr = CeedInit(fallbackresource, &ceedref); CeedChk(ierr);
637a982d89SJeremy L. Thompson     ceedref->opfallbackparent = op->ceed;
64fc164cf7SWill Pazner     ceedref->Error = op->ceed->Error;
657a982d89SJeremy L. Thompson     op->ceed->opfallbackceed = ceedref;
667a982d89SJeremy L. Thompson   }
677a982d89SJeremy L. Thompson   ceedref = op->ceed->opfallbackceed;
687a982d89SJeremy L. Thompson 
697a982d89SJeremy L. Thompson   // Clone Op
707a982d89SJeremy L. Thompson   CeedOperator opref;
717a982d89SJeremy L. Thompson   ierr = CeedCalloc(1, &opref); CeedChk(ierr);
72e15f9bd0SJeremy L Thompson   memcpy(opref, op, sizeof(*opref));
737a982d89SJeremy L. Thompson   opref->data = NULL;
74e15f9bd0SJeremy L Thompson   opref->interfacesetup = false;
75e15f9bd0SJeremy L Thompson   opref->backendsetup = false;
767a982d89SJeremy L. Thompson   opref->ceed = ceedref;
777a982d89SJeremy L. Thompson   ierr = ceedref->OperatorCreate(opref); CeedChk(ierr);
787a982d89SJeremy L. Thompson   op->opfallback = opref;
797a982d89SJeremy L. Thompson 
807a982d89SJeremy L. Thompson   // Clone QF
817a982d89SJeremy L. Thompson   CeedQFunction qfref;
827a982d89SJeremy L. Thompson   ierr = CeedCalloc(1, &qfref); CeedChk(ierr);
83e15f9bd0SJeremy L Thompson   memcpy(qfref, (op->qf), sizeof(*qfref));
847a982d89SJeremy L. Thompson   qfref->data = NULL;
857a982d89SJeremy L. Thompson   qfref->ceed = ceedref;
867a982d89SJeremy L. Thompson   ierr = ceedref->QFunctionCreate(qfref); CeedChk(ierr);
877a982d89SJeremy L. Thompson   opref->qf = qfref;
887a982d89SJeremy L. Thompson   op->qffallback = qfref;
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
96e15f9bd0SJeremy L Thompson   @param[in] qfield 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 **/
104e15f9bd0SJeremy L Thompson static int CeedOperatorCheckField(Ceed ceed, CeedQFunctionField qfield,
105e15f9bd0SJeremy L Thompson                                   CeedElemRestriction r, CeedBasis b) {
106e15f9bd0SJeremy L Thompson   int ierr;
107e15f9bd0SJeremy L Thompson   CeedEvalMode emode = qfield->emode;
108e15f9bd0SJeremy L Thompson   CeedInt dim = 1, ncomp = 1, restr_ncomp = 1, size = qfield->size;
109e15f9bd0SJeremy L Thompson   // Restriction
110e15f9bd0SJeremy L Thompson   if (r != CEED_ELEMRESTRICTION_NONE) {
111e15f9bd0SJeremy L Thompson     ierr = CeedElemRestrictionGetNumComponents(r, &restr_ncomp);
112e15f9bd0SJeremy L Thompson   } else if (emode != CEED_EVAL_WEIGHT) {
113e15f9bd0SJeremy L Thompson     // LCOV_EXCL_START
114e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_MINOR,
115e15f9bd0SJeremy L Thompson                      "CEED_ELEMRESTRICTION_NONE can only be used "
116e15f9bd0SJeremy L Thompson                      "for a field with eval mode CEED_EVAL_WEIGHT");
117e15f9bd0SJeremy L Thompson     // LCOV_EXCL_STOP
118e15f9bd0SJeremy L Thompson   }
119e15f9bd0SJeremy L Thompson   // Basis
120e15f9bd0SJeremy L Thompson   if (b != CEED_BASIS_COLLOCATED) {
121e15f9bd0SJeremy L Thompson     ierr = CeedBasisGetDimension(b, &dim); CeedChk(ierr);
122e15f9bd0SJeremy L Thompson     ierr = CeedBasisGetNumComponents(b, &ncomp); CeedChk(ierr);
123e15f9bd0SJeremy L Thompson     if (r != CEED_ELEMRESTRICTION_NONE && restr_ncomp != ncomp) {
124e15f9bd0SJeremy L Thompson       // LCOV_EXCL_START
125e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_DIMENSION,
126e15f9bd0SJeremy L Thompson                        "ElemRestriction and Basis have incompatible numbers of components");
127e15f9bd0SJeremy L Thompson       // LCOV_EXCL_STOP
128e15f9bd0SJeremy L Thompson     }
129e15f9bd0SJeremy L Thompson   }
130e15f9bd0SJeremy L Thompson   // Field size
131e15f9bd0SJeremy L Thompson   switch(emode) {
132e15f9bd0SJeremy L Thompson   case CEED_EVAL_NONE:
133e15f9bd0SJeremy L Thompson     if (size != restr_ncomp)
134e15f9bd0SJeremy L Thompson       // LCOV_EXCL_START
135e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_DIMENSION,
136e15f9bd0SJeremy L Thompson                        "Incompatible QFunction field size and Operator field "
137e15f9bd0SJeremy L Thompson                        "ElemRestriction number of components");
138e15f9bd0SJeremy L Thompson     // LCOV_EXCL_STOP
139e15f9bd0SJeremy L Thompson     break;
140e15f9bd0SJeremy L Thompson   case CEED_EVAL_INTERP:
141e15f9bd0SJeremy L Thompson     if (size != ncomp)
142e15f9bd0SJeremy L Thompson       // LCOV_EXCL_START
143e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_DIMENSION,
144e15f9bd0SJeremy L Thompson                        "Incompatible QFunction field size and Operator field "
145e15f9bd0SJeremy L Thompson                        "Basis number of components");
146e15f9bd0SJeremy L Thompson     // LCOV_EXCL_STOP
147e15f9bd0SJeremy L Thompson     break;
148e15f9bd0SJeremy L Thompson   case CEED_EVAL_GRAD:
149e15f9bd0SJeremy L Thompson     if (size != ncomp * dim)
150e15f9bd0SJeremy L Thompson       // LCOV_EXCL_START
151e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_DIMENSION,
152e15f9bd0SJeremy L Thompson                        "Incompatible QFunction field size and Operator field "
153e15f9bd0SJeremy L Thompson                        "Basis dimension and number of components");
154e15f9bd0SJeremy L Thompson     // LCOV_EXCL_STOP
155e15f9bd0SJeremy L Thompson     break;
156e15f9bd0SJeremy L Thompson   case CEED_EVAL_WEIGHT:
157e15f9bd0SJeremy L Thompson     // No addional checks required
158e15f9bd0SJeremy L Thompson     break;
159e15f9bd0SJeremy L Thompson   case CEED_EVAL_DIV:
160e15f9bd0SJeremy L Thompson     // Not implemented
161e15f9bd0SJeremy L Thompson     break;
162e15f9bd0SJeremy L Thompson   case CEED_EVAL_CURL:
163e15f9bd0SJeremy L Thompson     // Not implemented
164e15f9bd0SJeremy L Thompson     break;
165e15f9bd0SJeremy L Thompson   }
166e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1677a982d89SJeremy L. Thompson }
1687a982d89SJeremy L. Thompson 
1697a982d89SJeremy L. Thompson /**
1707a982d89SJeremy L. Thompson   @brief Check if a CeedOperator is ready to be used.
1717a982d89SJeremy L. Thompson 
1727a982d89SJeremy L. Thompson   @param[in] op   CeedOperator to check
1737a982d89SJeremy L. Thompson 
1747a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
1757a982d89SJeremy L. Thompson 
1767a982d89SJeremy L. Thompson   @ref Developer
1777a982d89SJeremy L. Thompson **/
178*e2f04181SAndrew T. Barker static int CeedOperatorCheckReady(CeedOperator op) {
179*e2f04181SAndrew T. Barker   int ierr;
180*e2f04181SAndrew T. Barker   Ceed ceed;
181*e2f04181SAndrew T. Barker   ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr);
182*e2f04181SAndrew T. Barker 
183e15f9bd0SJeremy L Thompson   if (op->interfacesetup)
184e15f9bd0SJeremy L Thompson     return CEED_ERROR_SUCCESS;
1857a982d89SJeremy L. Thompson 
186e15f9bd0SJeremy L Thompson   CeedQFunction qf = op->qf;
1877a982d89SJeremy L. Thompson   if (op->composite) {
1887a982d89SJeremy L. Thompson     if (!op->numsub)
1897a982d89SJeremy L. Thompson       // LCOV_EXCL_START
190e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_INCOMPLETE, "No suboperators set");
1917a982d89SJeremy L. Thompson     // LCOV_EXCL_STOP
1927a982d89SJeremy L. Thompson   } else {
1937a982d89SJeremy L. Thompson     if (op->nfields == 0)
1947a982d89SJeremy L. Thompson       // LCOV_EXCL_START
195e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_INCOMPLETE, "No operator fields set");
1967a982d89SJeremy L. Thompson     // LCOV_EXCL_STOP
1977a982d89SJeremy L. Thompson     if (op->nfields < qf->numinputfields + qf->numoutputfields)
1987a982d89SJeremy L. Thompson       // LCOV_EXCL_START
199e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_INCOMPLETE, "Not all operator fields set");
2007a982d89SJeremy L. Thompson     // LCOV_EXCL_STOP
2017a982d89SJeremy L. Thompson     if (!op->hasrestriction)
2027a982d89SJeremy L. Thompson       // LCOV_EXCL_START
203e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_INCOMPLETE,
204e15f9bd0SJeremy L Thompson                        "At least one restriction required");
2057a982d89SJeremy L. Thompson     // LCOV_EXCL_STOP
2067a982d89SJeremy L. Thompson     if (op->numqpoints == 0)
2077a982d89SJeremy L. Thompson       // LCOV_EXCL_START
208e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_INCOMPLETE,
209e15f9bd0SJeremy L Thompson                        "At least one non-collocated basis required");
2107a982d89SJeremy L. Thompson     // LCOV_EXCL_STOP
2117a982d89SJeremy L. Thompson   }
2127a982d89SJeremy L. Thompson 
213e15f9bd0SJeremy L Thompson   // Flag as immutable and ready
214e15f9bd0SJeremy L Thompson   op->interfacesetup = true;
215e15f9bd0SJeremy L Thompson   if (op->qf && op->qf != CEED_QFUNCTION_NONE)
216e15f9bd0SJeremy L Thompson     // LCOV_EXCL_START
217e15f9bd0SJeremy L Thompson     op->qf->operatorsset++;
218e15f9bd0SJeremy L Thompson   // LCOV_EXCL_STOP
219e15f9bd0SJeremy L Thompson   if (op->dqf && op->dqf != CEED_QFUNCTION_NONE)
220e15f9bd0SJeremy L Thompson     // LCOV_EXCL_START
221e15f9bd0SJeremy L Thompson     op->dqf->operatorsset++;
222e15f9bd0SJeremy L Thompson   // LCOV_EXCL_STOP
223e15f9bd0SJeremy L Thompson   if (op->dqfT && op->dqfT != CEED_QFUNCTION_NONE)
224e15f9bd0SJeremy L Thompson     // LCOV_EXCL_START
225e15f9bd0SJeremy L Thompson     op->dqfT->operatorsset++;
226e15f9bd0SJeremy L Thompson   // LCOV_EXCL_STOP
227e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2287a982d89SJeremy L. Thompson }
2297a982d89SJeremy L. Thompson 
2307a982d89SJeremy L. Thompson /**
2317a982d89SJeremy L. Thompson   @brief View a field of a CeedOperator
2327a982d89SJeremy L. Thompson 
2337a982d89SJeremy L. Thompson   @param[in] field       Operator field to view
2344c4400c7SValeria Barra   @param[in] qffield     QFunction field (carries field name)
2357a982d89SJeremy L. Thompson   @param[in] fieldnumber Number of field being viewed
2364c4400c7SValeria Barra   @param[in] sub         true indicates sub-operator, which increases indentation; false for top-level operator
2374c4400c7SValeria Barra   @param[in] in          true for an input field; false for output field
2387a982d89SJeremy L. Thompson   @param[in] stream      Stream to view to, e.g., stdout
2397a982d89SJeremy L. Thompson 
2407a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
2417a982d89SJeremy L. Thompson 
2427a982d89SJeremy L. Thompson   @ref Utility
2437a982d89SJeremy L. Thompson **/
2447a982d89SJeremy L. Thompson static int CeedOperatorFieldView(CeedOperatorField field,
2457a982d89SJeremy L. Thompson                                  CeedQFunctionField qffield,
2467a982d89SJeremy L. Thompson                                  CeedInt fieldnumber, bool sub, bool in,
2477a982d89SJeremy L. Thompson                                  FILE *stream) {
2487a982d89SJeremy L. Thompson   const char *pre = sub ? "  " : "";
2497a982d89SJeremy L. Thompson   const char *inout = in ? "Input" : "Output";
2507a982d89SJeremy L. Thompson 
2517a982d89SJeremy L. Thompson   fprintf(stream, "%s    %s Field [%d]:\n"
2527a982d89SJeremy L. Thompson           "%s      Name: \"%s\"\n",
2537a982d89SJeremy L. Thompson           pre, inout, fieldnumber, pre, qffield->fieldname);
2547a982d89SJeremy L. Thompson 
2557a982d89SJeremy L. Thompson   if (field->basis == CEED_BASIS_COLLOCATED)
2567a982d89SJeremy L. Thompson     fprintf(stream, "%s      Collocated basis\n", pre);
2577a982d89SJeremy L. Thompson 
2587a982d89SJeremy L. Thompson   if (field->vec == CEED_VECTOR_ACTIVE)
2597a982d89SJeremy L. Thompson     fprintf(stream, "%s      Active vector\n", pre);
2607a982d89SJeremy L. Thompson   else if (field->vec == CEED_VECTOR_NONE)
2617a982d89SJeremy L. Thompson     fprintf(stream, "%s      No vector\n", pre);
262e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2637a982d89SJeremy L. Thompson }
2647a982d89SJeremy L. Thompson 
2657a982d89SJeremy L. Thompson /**
2667a982d89SJeremy L. Thompson   @brief View a single CeedOperator
2677a982d89SJeremy L. Thompson 
2687a982d89SJeremy L. Thompson   @param[in] op     CeedOperator to view
2697a982d89SJeremy L. Thompson   @param[in] sub    Boolean flag for sub-operator
2707a982d89SJeremy L. Thompson   @param[in] stream Stream to write; typically stdout/stderr or a file
2717a982d89SJeremy L. Thompson 
2727a982d89SJeremy L. Thompson   @return Error code: 0 - success, otherwise - failure
2737a982d89SJeremy L. Thompson 
2747a982d89SJeremy L. Thompson   @ref Utility
2757a982d89SJeremy L. Thompson **/
2767a982d89SJeremy L. Thompson int CeedOperatorSingleView(CeedOperator op, bool sub, FILE *stream) {
2777a982d89SJeremy L. Thompson   int ierr;
2787a982d89SJeremy L. Thompson   const char *pre = sub ? "  " : "";
2797a982d89SJeremy L. Thompson 
2807a982d89SJeremy L. Thompson   CeedInt totalfields;
2817a982d89SJeremy L. Thompson   ierr = CeedOperatorGetNumArgs(op, &totalfields); CeedChk(ierr);
2827a982d89SJeremy L. Thompson 
2837a982d89SJeremy L. Thompson   fprintf(stream, "%s  %d Field%s\n", pre, totalfields, totalfields>1 ? "s" : "");
2847a982d89SJeremy L. Thompson 
2857a982d89SJeremy L. Thompson   fprintf(stream, "%s  %d Input Field%s:\n", pre, op->qf->numinputfields,
2867a982d89SJeremy L. Thompson           op->qf->numinputfields>1 ? "s" : "");
2877a982d89SJeremy L. Thompson   for (CeedInt i=0; i<op->qf->numinputfields; i++) {
2887a982d89SJeremy L. Thompson     ierr = CeedOperatorFieldView(op->inputfields[i], op->qf->inputfields[i],
2897a982d89SJeremy L. Thompson                                  i, sub, 1, stream); CeedChk(ierr);
2907a982d89SJeremy L. Thompson   }
2917a982d89SJeremy L. Thompson 
2927a982d89SJeremy L. Thompson   fprintf(stream, "%s  %d Output Field%s:\n", pre, op->qf->numoutputfields,
2937a982d89SJeremy L. Thompson           op->qf->numoutputfields>1 ? "s" : "");
2947a982d89SJeremy L. Thompson   for (CeedInt i=0; i<op->qf->numoutputfields; i++) {
295829936eeSWill Pazner     ierr = CeedOperatorFieldView(op->outputfields[i], op->qf->outputfields[i],
2967a982d89SJeremy L. Thompson                                  i, sub, 0, stream); CeedChk(ierr);
2977a982d89SJeremy L. Thompson   }
298e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2997a982d89SJeremy L. Thompson }
3007a982d89SJeremy L. Thompson 
301d99fa3c5SJeremy L Thompson /**
302*e2f04181SAndrew T. Barker   @brief Find the active vector ElemRestriction for a CeedOperator
303*e2f04181SAndrew T. Barker 
304*e2f04181SAndrew T. Barker   @param[in] op            CeedOperator to find active basis for
305*e2f04181SAndrew T. Barker   @param[out] activerstr   ElemRestriction for active input vector
306*e2f04181SAndrew T. Barker 
307*e2f04181SAndrew T. Barker   @return An error code: 0 - success, otherwise - failure
308*e2f04181SAndrew T. Barker 
309*e2f04181SAndrew T. Barker   @ref Utility
310*e2f04181SAndrew T. Barker **/
311*e2f04181SAndrew T. Barker static int CeedOperatorGetActiveElemRestriction(CeedOperator op,
312*e2f04181SAndrew T. Barker     CeedElemRestriction *activerstr) {
313*e2f04181SAndrew T. Barker   *activerstr = NULL;
314*e2f04181SAndrew T. Barker   for (int i = 0; i < op->qf->numinputfields; i++)
315*e2f04181SAndrew T. Barker     if (op->inputfields[i]->vec == CEED_VECTOR_ACTIVE) {
316*e2f04181SAndrew T. Barker       *activerstr = op->inputfields[i]->Erestrict;
317*e2f04181SAndrew T. Barker       break;
318*e2f04181SAndrew T. Barker     }
319*e2f04181SAndrew T. Barker 
320*e2f04181SAndrew T. Barker   if (!*activerstr) {
321*e2f04181SAndrew T. Barker     // LCOV_EXCL_START
322*e2f04181SAndrew T. Barker     int ierr;
323*e2f04181SAndrew T. Barker     Ceed ceed;
324*e2f04181SAndrew T. Barker     ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr);
325*e2f04181SAndrew T. Barker     return CeedError(ceed, CEED_ERROR_INCOMPLETE,
326*e2f04181SAndrew T. Barker                      "No active ElemRestriction found!");
327*e2f04181SAndrew T. Barker     // LCOV_EXCL_STOP
328*e2f04181SAndrew T. Barker   }
329*e2f04181SAndrew T. Barker   return CEED_ERROR_SUCCESS;
330*e2f04181SAndrew T. Barker }
331*e2f04181SAndrew T. Barker 
332*e2f04181SAndrew T. Barker /**
333d99fa3c5SJeremy L Thompson   @brief Find the active vector basis for a CeedOperator
334d99fa3c5SJeremy L Thompson 
335d99fa3c5SJeremy L Thompson   @param[in] op            CeedOperator to find active basis for
336d99fa3c5SJeremy L Thompson   @param[out] activeBasis  Basis for active input vector
337d99fa3c5SJeremy L Thompson 
338d99fa3c5SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
339d99fa3c5SJeremy L Thompson 
340d99fa3c5SJeremy L Thompson   @ ref Developer
341d99fa3c5SJeremy L Thompson **/
342d99fa3c5SJeremy L Thompson static int CeedOperatorGetActiveBasis(CeedOperator op,
343d99fa3c5SJeremy L Thompson                                       CeedBasis *activeBasis) {
344d99fa3c5SJeremy L Thompson   *activeBasis = NULL;
345d99fa3c5SJeremy L Thompson   for (int i = 0; i < op->qf->numinputfields; i++)
346d99fa3c5SJeremy L Thompson     if (op->inputfields[i]->vec == CEED_VECTOR_ACTIVE) {
347d99fa3c5SJeremy L Thompson       *activeBasis = op->inputfields[i]->basis;
348d99fa3c5SJeremy L Thompson       break;
349d99fa3c5SJeremy L Thompson     }
350d99fa3c5SJeremy L Thompson 
351d99fa3c5SJeremy L Thompson   if (!*activeBasis) {
352d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
353d99fa3c5SJeremy L Thompson     int ierr;
354d99fa3c5SJeremy L Thompson     Ceed ceed;
355d99fa3c5SJeremy L Thompson     ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr);
356e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_MINOR,
357d99fa3c5SJeremy L Thompson                      "No active basis found for automatic multigrid setup");
358d99fa3c5SJeremy L Thompson     // LCOV_EXCL_STOP
359d99fa3c5SJeremy L Thompson   }
360e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
361d99fa3c5SJeremy L Thompson }
362d99fa3c5SJeremy L Thompson 
363d99fa3c5SJeremy L Thompson 
364d99fa3c5SJeremy L Thompson /**
365d99fa3c5SJeremy L Thompson   @brief Common code for creating a multigrid coarse operator and level
366d99fa3c5SJeremy L Thompson            transfer operators for a CeedOperator
367d99fa3c5SJeremy L Thompson 
368d99fa3c5SJeremy L Thompson   @param[in] opFine       Fine grid operator
369d99fa3c5SJeremy L Thompson   @param[in] PMultFine    L-vector multiplicity in parallel gather/scatter
370d99fa3c5SJeremy L Thompson   @param[in] rstrCoarse   Coarse grid restriction
371d99fa3c5SJeremy L Thompson   @param[in] basisCoarse  Coarse grid active vector basis
372d99fa3c5SJeremy L Thompson   @param[in] basisCtoF    Basis for coarse to fine interpolation
373d99fa3c5SJeremy L Thompson   @param[out] opCoarse    Coarse grid operator
374d99fa3c5SJeremy L Thompson   @param[out] opProlong   Coarse to fine operator
375d99fa3c5SJeremy L Thompson   @param[out] opRestrict  Fine to coarse operator
376d99fa3c5SJeremy L Thompson 
377d99fa3c5SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
378d99fa3c5SJeremy L Thompson 
379d99fa3c5SJeremy L Thompson   @ref Developer
380d99fa3c5SJeremy L Thompson **/
381d99fa3c5SJeremy L Thompson static int CeedOperatorMultigridLevel_Core(CeedOperator opFine,
382d99fa3c5SJeremy L Thompson     CeedVector PMultFine, CeedElemRestriction rstrCoarse, CeedBasis basisCoarse,
383d99fa3c5SJeremy L Thompson     CeedBasis basisCtoF, CeedOperator *opCoarse, CeedOperator *opProlong,
384d99fa3c5SJeremy L Thompson     CeedOperator *opRestrict) {
385d99fa3c5SJeremy L Thompson   int ierr;
386d99fa3c5SJeremy L Thompson   Ceed ceed;
387d99fa3c5SJeremy L Thompson   ierr = CeedOperatorGetCeed(opFine, &ceed); CeedChk(ierr);
388d99fa3c5SJeremy L Thompson 
389d99fa3c5SJeremy L Thompson   // Check for composite operator
390d99fa3c5SJeremy L Thompson   bool isComposite;
391d99fa3c5SJeremy L Thompson   ierr = CeedOperatorIsComposite(opFine, &isComposite); CeedChk(ierr);
392d99fa3c5SJeremy L Thompson   if (isComposite)
393d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
394e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_UNSUPPORTED,
395d99fa3c5SJeremy L Thompson                      "Automatic multigrid setup for composite operators not supported");
396d99fa3c5SJeremy L Thompson   // LCOV_EXCL_STOP
397d99fa3c5SJeremy L Thompson 
398d99fa3c5SJeremy L Thompson   // Coarse Grid
399d99fa3c5SJeremy L Thompson   ierr = CeedOperatorCreate(ceed, opFine->qf, opFine->dqf, opFine->dqfT,
400d99fa3c5SJeremy L Thompson                             opCoarse); CeedChk(ierr);
401d99fa3c5SJeremy L Thompson   CeedElemRestriction rstrFine = NULL;
402d99fa3c5SJeremy L Thompson   // -- Clone input fields
403d99fa3c5SJeremy L Thompson   for (int i = 0; i < opFine->qf->numinputfields; i++) {
404d99fa3c5SJeremy L Thompson     if (opFine->inputfields[i]->vec == CEED_VECTOR_ACTIVE) {
405d99fa3c5SJeremy L Thompson       rstrFine = opFine->inputfields[i]->Erestrict;
406d99fa3c5SJeremy L Thompson       ierr = CeedOperatorSetField(*opCoarse, opFine->inputfields[i]->fieldname,
407d99fa3c5SJeremy L Thompson                                   rstrCoarse, basisCoarse, CEED_VECTOR_ACTIVE);
408d99fa3c5SJeremy L Thompson       CeedChk(ierr);
409d99fa3c5SJeremy L Thompson     } else {
410d99fa3c5SJeremy L Thompson       ierr = CeedOperatorSetField(*opCoarse, opFine->inputfields[i]->fieldname,
411d99fa3c5SJeremy L Thompson                                   opFine->inputfields[i]->Erestrict,
412d99fa3c5SJeremy L Thompson                                   opFine->inputfields[i]->basis,
413d99fa3c5SJeremy L Thompson                                   opFine->inputfields[i]->vec); CeedChk(ierr);
414d99fa3c5SJeremy L Thompson     }
415d99fa3c5SJeremy L Thompson   }
416d99fa3c5SJeremy L Thompson   // -- Clone output fields
417d99fa3c5SJeremy L Thompson   for (int i = 0; i < opFine->qf->numoutputfields; i++) {
418d99fa3c5SJeremy L Thompson     if (opFine->outputfields[i]->vec == CEED_VECTOR_ACTIVE) {
419d99fa3c5SJeremy L Thompson       ierr = CeedOperatorSetField(*opCoarse, opFine->outputfields[i]->fieldname,
420d99fa3c5SJeremy L Thompson                                   rstrCoarse, basisCoarse, CEED_VECTOR_ACTIVE);
421d99fa3c5SJeremy L Thompson       CeedChk(ierr);
422d99fa3c5SJeremy L Thompson     } else {
423d99fa3c5SJeremy L Thompson       ierr = CeedOperatorSetField(*opCoarse, opFine->outputfields[i]->fieldname,
424d99fa3c5SJeremy L Thompson                                   opFine->outputfields[i]->Erestrict,
425d99fa3c5SJeremy L Thompson                                   opFine->outputfields[i]->basis,
426d99fa3c5SJeremy L Thompson                                   opFine->outputfields[i]->vec); CeedChk(ierr);
427d99fa3c5SJeremy L Thompson     }
428d99fa3c5SJeremy L Thompson   }
429d99fa3c5SJeremy L Thompson 
430d99fa3c5SJeremy L Thompson   // Multiplicity vector
431d99fa3c5SJeremy L Thompson   CeedVector multVec, multE;
432d99fa3c5SJeremy L Thompson   ierr = CeedElemRestrictionCreateVector(rstrFine, &multVec, &multE);
433d99fa3c5SJeremy L Thompson   CeedChk(ierr);
434d99fa3c5SJeremy L Thompson   ierr = CeedVectorSetValue(multE, 0.0); CeedChk(ierr);
435d99fa3c5SJeremy L Thompson   ierr = CeedElemRestrictionApply(rstrFine, CEED_NOTRANSPOSE, PMultFine, multE,
436d99fa3c5SJeremy L Thompson                                   CEED_REQUEST_IMMEDIATE); CeedChk(ierr);
437d99fa3c5SJeremy L Thompson   ierr = CeedVectorSetValue(multVec, 0.0); CeedChk(ierr);
438d99fa3c5SJeremy L Thompson   ierr = CeedElemRestrictionApply(rstrFine, CEED_TRANSPOSE, multE, multVec,
439d99fa3c5SJeremy L Thompson                                   CEED_REQUEST_IMMEDIATE); CeedChk(ierr);
440d99fa3c5SJeremy L Thompson   ierr = CeedVectorDestroy(&multE); CeedChk(ierr);
441d99fa3c5SJeremy L Thompson   ierr = CeedVectorReciprocal(multVec); CeedChk(ierr);
442d99fa3c5SJeremy L Thompson 
443d99fa3c5SJeremy L Thompson   // Restriction
444d99fa3c5SJeremy L Thompson   CeedInt ncomp;
445d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumComponents(basisCoarse, &ncomp); CeedChk(ierr);
446d99fa3c5SJeremy L Thompson   CeedQFunction qfRestrict;
447d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionCreateInteriorByName(ceed, "Scale", &qfRestrict);
448d99fa3c5SJeremy L Thompson   CeedChk(ierr);
449777ff853SJeremy L Thompson   CeedInt *ncompRData;
450777ff853SJeremy L Thompson   ierr = CeedCalloc(1, &ncompRData); CeedChk(ierr);
451777ff853SJeremy L Thompson   ncompRData[0] = ncomp;
452777ff853SJeremy L Thompson   CeedQFunctionContext ctxR;
453777ff853SJeremy L Thompson   ierr = CeedQFunctionContextCreate(ceed, &ctxR); CeedChk(ierr);
454777ff853SJeremy L Thompson   ierr = CeedQFunctionContextSetData(ctxR, CEED_MEM_HOST, CEED_OWN_POINTER,
455777ff853SJeremy L Thompson                                      sizeof(*ncompRData), ncompRData);
456777ff853SJeremy L Thompson   CeedChk(ierr);
457777ff853SJeremy L Thompson   ierr = CeedQFunctionSetContext(qfRestrict, ctxR); CeedChk(ierr);
458777ff853SJeremy L Thompson   ierr = CeedQFunctionContextDestroy(&ctxR); CeedChk(ierr);
459d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionAddInput(qfRestrict, "input", ncomp, CEED_EVAL_NONE);
460d99fa3c5SJeremy L Thompson   CeedChk(ierr);
461d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionAddInput(qfRestrict, "scale", ncomp, CEED_EVAL_NONE);
462d99fa3c5SJeremy L Thompson   CeedChk(ierr);
463d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionAddOutput(qfRestrict, "output", ncomp, CEED_EVAL_INTERP);
464d99fa3c5SJeremy L Thompson   CeedChk(ierr);
465d99fa3c5SJeremy L Thompson 
466d99fa3c5SJeremy L Thompson   ierr = CeedOperatorCreate(ceed, qfRestrict, CEED_QFUNCTION_NONE,
467d99fa3c5SJeremy L Thompson                             CEED_QFUNCTION_NONE, opRestrict);
468d99fa3c5SJeremy L Thompson   CeedChk(ierr);
469d99fa3c5SJeremy L Thompson   ierr = CeedOperatorSetField(*opRestrict, "input", rstrFine,
470d99fa3c5SJeremy L Thompson                               CEED_BASIS_COLLOCATED, CEED_VECTOR_ACTIVE);
471d99fa3c5SJeremy L Thompson   CeedChk(ierr);
472d99fa3c5SJeremy L Thompson   ierr = CeedOperatorSetField(*opRestrict, "scale", rstrFine,
473d99fa3c5SJeremy L Thompson                               CEED_BASIS_COLLOCATED, multVec);
474d99fa3c5SJeremy L Thompson   CeedChk(ierr);
475d99fa3c5SJeremy L Thompson   ierr = CeedOperatorSetField(*opRestrict, "output", rstrCoarse, basisCtoF,
476d99fa3c5SJeremy L Thompson                               CEED_VECTOR_ACTIVE); CeedChk(ierr);
477d99fa3c5SJeremy L Thompson 
478d99fa3c5SJeremy L Thompson   // Prolongation
479d99fa3c5SJeremy L Thompson   CeedQFunction qfProlong;
480d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionCreateInteriorByName(ceed, "Scale", &qfProlong);
481d99fa3c5SJeremy L Thompson   CeedChk(ierr);
482777ff853SJeremy L Thompson   CeedInt *ncompPData;
483777ff853SJeremy L Thompson   ierr = CeedCalloc(1, &ncompPData); CeedChk(ierr);
484777ff853SJeremy L Thompson   ncompPData[0] = ncomp;
485777ff853SJeremy L Thompson   CeedQFunctionContext ctxP;
486777ff853SJeremy L Thompson   ierr = CeedQFunctionContextCreate(ceed, &ctxP); CeedChk(ierr);
487777ff853SJeremy L Thompson   ierr = CeedQFunctionContextSetData(ctxP, CEED_MEM_HOST, CEED_OWN_POINTER,
488777ff853SJeremy L Thompson                                      sizeof(*ncompPData), ncompPData);
489777ff853SJeremy L Thompson   CeedChk(ierr);
490777ff853SJeremy L Thompson   ierr = CeedQFunctionSetContext(qfProlong, ctxP); CeedChk(ierr);
491777ff853SJeremy L Thompson   ierr = CeedQFunctionContextDestroy(&ctxP); CeedChk(ierr);
492d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionAddInput(qfProlong, "input", ncomp, CEED_EVAL_INTERP);
493d99fa3c5SJeremy L Thompson   CeedChk(ierr);
494d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionAddInput(qfProlong, "scale", ncomp, CEED_EVAL_NONE);
495d99fa3c5SJeremy L Thompson   CeedChk(ierr);
496d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionAddOutput(qfProlong, "output", ncomp, CEED_EVAL_NONE);
497d99fa3c5SJeremy L Thompson   CeedChk(ierr);
498d99fa3c5SJeremy L Thompson 
499d99fa3c5SJeremy L Thompson   ierr = CeedOperatorCreate(ceed, qfProlong, CEED_QFUNCTION_NONE,
500d99fa3c5SJeremy L Thompson                             CEED_QFUNCTION_NONE, opProlong);
501d99fa3c5SJeremy L Thompson   CeedChk(ierr);
502d99fa3c5SJeremy L Thompson   ierr = CeedOperatorSetField(*opProlong, "input", rstrCoarse, basisCtoF,
503d99fa3c5SJeremy L Thompson                               CEED_VECTOR_ACTIVE); CeedChk(ierr);
504d99fa3c5SJeremy L Thompson   ierr = CeedOperatorSetField(*opProlong, "scale", rstrFine,
505d99fa3c5SJeremy L Thompson                               CEED_BASIS_COLLOCATED, multVec);
506d99fa3c5SJeremy L Thompson   CeedChk(ierr);
507d99fa3c5SJeremy L Thompson   ierr = CeedOperatorSetField(*opProlong, "output", rstrFine,
508d99fa3c5SJeremy L Thompson                               CEED_BASIS_COLLOCATED, CEED_VECTOR_ACTIVE);
509d99fa3c5SJeremy L Thompson   CeedChk(ierr);
510d99fa3c5SJeremy L Thompson 
511d99fa3c5SJeremy L Thompson   // Cleanup
512d99fa3c5SJeremy L Thompson   ierr = CeedVectorDestroy(&multVec); CeedChk(ierr);
513d99fa3c5SJeremy L Thompson   ierr = CeedBasisDestroy(&basisCtoF); CeedChk(ierr);
514d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionDestroy(&qfRestrict); CeedChk(ierr);
515d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionDestroy(&qfProlong); CeedChk(ierr);
516e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
517d99fa3c5SJeremy L Thompson }
518d99fa3c5SJeremy L Thompson 
5197a982d89SJeremy L. Thompson /// @}
5207a982d89SJeremy L. Thompson 
5217a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
5227a982d89SJeremy L. Thompson /// CeedOperator Backend API
5237a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
5247a982d89SJeremy L. Thompson /// @addtogroup CeedOperatorBackend
5257a982d89SJeremy L. Thompson /// @{
5267a982d89SJeremy L. Thompson 
5277a982d89SJeremy L. Thompson /**
5287a982d89SJeremy L. Thompson   @brief Get the Ceed associated with a CeedOperator
5297a982d89SJeremy L. Thompson 
5307a982d89SJeremy L. Thompson   @param op              CeedOperator
5317a982d89SJeremy L. Thompson   @param[out] ceed       Variable to store Ceed
5327a982d89SJeremy L. Thompson 
5337a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5347a982d89SJeremy L. Thompson 
5357a982d89SJeremy L. Thompson   @ref Backend
5367a982d89SJeremy L. Thompson **/
5377a982d89SJeremy L. Thompson 
5387a982d89SJeremy L. Thompson int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) {
5397a982d89SJeremy L. Thompson   *ceed = op->ceed;
540e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5417a982d89SJeremy L. Thompson }
5427a982d89SJeremy L. Thompson 
5437a982d89SJeremy L. Thompson /**
5447a982d89SJeremy L. Thompson   @brief Get the number of elements associated with a CeedOperator
5457a982d89SJeremy L. Thompson 
5467a982d89SJeremy L. Thompson   @param op              CeedOperator
5477a982d89SJeremy L. Thompson   @param[out] numelem    Variable to store number of elements
5487a982d89SJeremy L. Thompson 
5497a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5507a982d89SJeremy L. Thompson 
5517a982d89SJeremy L. Thompson   @ref Backend
5527a982d89SJeremy L. Thompson **/
5537a982d89SJeremy L. Thompson 
5547a982d89SJeremy L. Thompson int CeedOperatorGetNumElements(CeedOperator op, CeedInt *numelem) {
5557a982d89SJeremy L. Thompson   if (op->composite)
5567a982d89SJeremy L. Thompson     // LCOV_EXCL_START
557e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
558e15f9bd0SJeremy L Thompson                      "Not defined for composite operator");
5597a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
5607a982d89SJeremy L. Thompson 
5617a982d89SJeremy L. Thompson   *numelem = op->numelements;
562e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5637a982d89SJeremy L. Thompson }
5647a982d89SJeremy L. Thompson 
5657a982d89SJeremy L. Thompson /**
5667a982d89SJeremy L. Thompson   @brief Get the number of quadrature points associated with a CeedOperator
5677a982d89SJeremy L. Thompson 
5687a982d89SJeremy L. Thompson   @param op              CeedOperator
5697a982d89SJeremy L. Thompson   @param[out] numqpts    Variable to store vector number of quadrature points
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 
5767a982d89SJeremy L. Thompson int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *numqpts) {
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 
5837a982d89SJeremy L. Thompson   *numqpts = op->numqpoints;
584e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5857a982d89SJeremy L. Thompson }
5867a982d89SJeremy L. Thompson 
5877a982d89SJeremy L. Thompson /**
5887a982d89SJeremy L. Thompson   @brief Get the number of arguments associated with a CeedOperator
5897a982d89SJeremy L. Thompson 
5907a982d89SJeremy L. Thompson   @param op              CeedOperator
5917a982d89SJeremy L. Thompson   @param[out] numargs    Variable to store vector number of arguments
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 
5987a982d89SJeremy L. Thompson int CeedOperatorGetNumArgs(CeedOperator op, CeedInt *numargs) {
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 operators");
6037a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
6047a982d89SJeremy L. Thompson 
6057a982d89SJeremy L. Thompson   *numargs = op->nfields;
606e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6077a982d89SJeremy L. Thompson }
6087a982d89SJeremy L. Thompson 
6097a982d89SJeremy L. Thompson /**
6107a982d89SJeremy L. Thompson   @brief Get the setup status of a CeedOperator
6117a982d89SJeremy L. Thompson 
6127a982d89SJeremy L. Thompson   @param op                CeedOperator
613fd364f38SJeremy L Thompson   @param[out] issetupdone  Variable to store setup status
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 
620fd364f38SJeremy L Thompson int CeedOperatorIsSetupDone(CeedOperator op, bool *issetupdone) {
621e15f9bd0SJeremy L Thompson   *issetupdone = op->backendsetup;
622e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6237a982d89SJeremy L. Thompson }
6247a982d89SJeremy L. Thompson 
6257a982d89SJeremy L. Thompson /**
6267a982d89SJeremy L. Thompson   @brief Get the QFunction associated with a CeedOperator
6277a982d89SJeremy L. Thompson 
6287a982d89SJeremy L. Thompson   @param op              CeedOperator
6297a982d89SJeremy L. Thompson   @param[out] qf         Variable to store QFunction
6307a982d89SJeremy L. Thompson 
6317a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6327a982d89SJeremy L. Thompson 
6337a982d89SJeremy L. Thompson   @ref Backend
6347a982d89SJeremy L. Thompson **/
6357a982d89SJeremy L. Thompson 
6367a982d89SJeremy L. Thompson int CeedOperatorGetQFunction(CeedOperator op, CeedQFunction *qf) {
6377a982d89SJeremy L. Thompson   if (op->composite)
6387a982d89SJeremy L. Thompson     // LCOV_EXCL_START
639e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
640e15f9bd0SJeremy L Thompson                      "Not defined for composite operator");
6417a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
6427a982d89SJeremy L. Thompson 
6437a982d89SJeremy L. Thompson   *qf = op->qf;
644e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6457a982d89SJeremy L. Thompson }
6467a982d89SJeremy L. Thompson 
6477a982d89SJeremy L. Thompson /**
648c04a41a7SJeremy L Thompson   @brief Get a boolean value indicating if the CeedOperator is composite
649c04a41a7SJeremy L Thompson 
650c04a41a7SJeremy L Thompson   @param op                CeedOperator
651fd364f38SJeremy L Thompson   @param[out] iscomposite  Variable to store composite status
652c04a41a7SJeremy L Thompson 
653c04a41a7SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
654c04a41a7SJeremy L Thompson 
655c04a41a7SJeremy L Thompson   @ref Backend
656c04a41a7SJeremy L Thompson **/
657c04a41a7SJeremy L Thompson 
658fd364f38SJeremy L Thompson int CeedOperatorIsComposite(CeedOperator op, bool *iscomposite) {
659fd364f38SJeremy L Thompson   *iscomposite = op->composite;
660e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
661c04a41a7SJeremy L Thompson }
662c04a41a7SJeremy L Thompson 
663c04a41a7SJeremy L Thompson /**
6647a982d89SJeremy L. Thompson   @brief Get the number of suboperators associated with a CeedOperator
6657a982d89SJeremy L. Thompson 
6667a982d89SJeremy L. Thompson   @param op              CeedOperator
6677a982d89SJeremy L. Thompson   @param[out] numsub     Variable to store number of suboperators
6687a982d89SJeremy L. Thompson 
6697a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6707a982d89SJeremy L. Thompson 
6717a982d89SJeremy L. Thompson   @ref Backend
6727a982d89SJeremy L. Thompson **/
6737a982d89SJeremy L. Thompson 
6747a982d89SJeremy L. Thompson int CeedOperatorGetNumSub(CeedOperator op, CeedInt *numsub) {
6757a982d89SJeremy L. Thompson   if (!op->composite)
6767a982d89SJeremy L. Thompson     // LCOV_EXCL_START
677e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR, "Not a composite operator");
6787a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
6797a982d89SJeremy L. Thompson 
6807a982d89SJeremy L. Thompson   *numsub = op->numsub;
681e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6827a982d89SJeremy L. Thompson }
6837a982d89SJeremy L. Thompson 
6847a982d89SJeremy L. Thompson /**
6857a982d89SJeremy L. Thompson   @brief Get the list of suboperators associated with a CeedOperator
6867a982d89SJeremy L. Thompson 
6877a982d89SJeremy L. Thompson   @param op                CeedOperator
6887a982d89SJeremy L. Thompson   @param[out] suboperators Variable to store list of suboperators
6897a982d89SJeremy L. Thompson 
6907a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6917a982d89SJeremy L. Thompson 
6927a982d89SJeremy L. Thompson   @ref Backend
6937a982d89SJeremy L. Thompson **/
6947a982d89SJeremy L. Thompson 
6957a982d89SJeremy L. Thompson int CeedOperatorGetSubList(CeedOperator op, CeedOperator **suboperators) {
6967a982d89SJeremy L. Thompson   if (!op->composite)
6977a982d89SJeremy L. Thompson     // LCOV_EXCL_START
698e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR, "Not a composite operator");
6997a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
7007a982d89SJeremy L. Thompson 
7017a982d89SJeremy L. Thompson   *suboperators = op->suboperators;
702e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
7037a982d89SJeremy L. Thompson }
7047a982d89SJeremy L. Thompson 
7057a982d89SJeremy L. Thompson /**
7067a982d89SJeremy L. Thompson   @brief Get the backend data of a CeedOperator
7077a982d89SJeremy L. Thompson 
7087a982d89SJeremy L. Thompson   @param op              CeedOperator
7097a982d89SJeremy L. Thompson   @param[out] data       Variable to store data
7107a982d89SJeremy L. Thompson 
7117a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
7127a982d89SJeremy L. Thompson 
7137a982d89SJeremy L. Thompson   @ref Backend
7147a982d89SJeremy L. Thompson **/
7157a982d89SJeremy L. Thompson 
716777ff853SJeremy L Thompson int CeedOperatorGetData(CeedOperator op, void *data) {
717777ff853SJeremy L Thompson   *(void **)data = op->data;
718e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
7197a982d89SJeremy L. Thompson }
7207a982d89SJeremy L. Thompson 
7217a982d89SJeremy L. Thompson /**
7227a982d89SJeremy L. Thompson   @brief Set the backend data of a CeedOperator
7237a982d89SJeremy L. Thompson 
7247a982d89SJeremy L. Thompson   @param[out] op         CeedOperator
7257a982d89SJeremy L. Thompson   @param data            Data to set
7267a982d89SJeremy L. Thompson 
7277a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
7287a982d89SJeremy L. Thompson 
7297a982d89SJeremy L. Thompson   @ref Backend
7307a982d89SJeremy L. Thompson **/
7317a982d89SJeremy L. Thompson 
732777ff853SJeremy L Thompson int CeedOperatorSetData(CeedOperator op, void *data) {
733777ff853SJeremy L Thompson   op->data = data;
734e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
7357a982d89SJeremy L. Thompson }
7367a982d89SJeremy L. Thompson 
7377a982d89SJeremy L. Thompson /**
7387a982d89SJeremy L. Thompson   @brief Set the setup flag of a CeedOperator to True
7397a982d89SJeremy L. Thompson 
7407a982d89SJeremy L. Thompson   @param op              CeedOperator
7417a982d89SJeremy L. Thompson 
7427a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
7437a982d89SJeremy L. Thompson 
7447a982d89SJeremy L. Thompson   @ref Backend
7457a982d89SJeremy L. Thompson **/
7467a982d89SJeremy L. Thompson 
7477a982d89SJeremy L. Thompson int CeedOperatorSetSetupDone(CeedOperator op) {
748e15f9bd0SJeremy L Thompson   op->backendsetup = true;
749e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
7507a982d89SJeremy L. Thompson }
7517a982d89SJeremy L. Thompson 
7527a982d89SJeremy L. Thompson /**
7537a982d89SJeremy L. Thompson   @brief Get the CeedOperatorFields of a CeedOperator
7547a982d89SJeremy L. Thompson 
7557a982d89SJeremy L. Thompson   @param op                 CeedOperator
7567a982d89SJeremy L. Thompson   @param[out] inputfields   Variable to store inputfields
7577a982d89SJeremy L. Thompson   @param[out] outputfields  Variable to store outputfields
7587a982d89SJeremy L. Thompson 
7597a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
7607a982d89SJeremy L. Thompson 
7617a982d89SJeremy L. Thompson   @ref Backend
7627a982d89SJeremy L. Thompson **/
7637a982d89SJeremy L. Thompson 
7647a982d89SJeremy L. Thompson int CeedOperatorGetFields(CeedOperator op, CeedOperatorField **inputfields,
7657a982d89SJeremy L. Thompson                           CeedOperatorField **outputfields) {
7667a982d89SJeremy L. Thompson   if (op->composite)
7677a982d89SJeremy L. Thompson     // LCOV_EXCL_START
768e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
769e15f9bd0SJeremy L Thompson                      "Not defined for composite operator");
7707a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
7717a982d89SJeremy L. Thompson 
7727a982d89SJeremy L. Thompson   if (inputfields) *inputfields = op->inputfields;
7737a982d89SJeremy L. Thompson   if (outputfields) *outputfields = op->outputfields;
774e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
7757a982d89SJeremy L. Thompson }
7767a982d89SJeremy L. Thompson 
7777a982d89SJeremy L. Thompson /**
7787a982d89SJeremy L. Thompson   @brief Get the CeedElemRestriction of a CeedOperatorField
7797a982d89SJeremy L. Thompson 
7807a982d89SJeremy L. Thompson   @param opfield         CeedOperatorField
7817a982d89SJeremy L. Thompson   @param[out] rstr       Variable to store CeedElemRestriction
7827a982d89SJeremy L. Thompson 
7837a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
7847a982d89SJeremy L. Thompson 
7857a982d89SJeremy L. Thompson   @ref Backend
7867a982d89SJeremy L. Thompson **/
7877a982d89SJeremy L. Thompson 
7887a982d89SJeremy L. Thompson int CeedOperatorFieldGetElemRestriction(CeedOperatorField opfield,
7897a982d89SJeremy L. Thompson                                         CeedElemRestriction *rstr) {
7907a982d89SJeremy L. Thompson   *rstr = opfield->Erestrict;
791e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
7927a982d89SJeremy L. Thompson }
7937a982d89SJeremy L. Thompson 
7947a982d89SJeremy L. Thompson /**
7957a982d89SJeremy L. Thompson   @brief Get the CeedBasis of a CeedOperatorField
7967a982d89SJeremy L. Thompson 
7977a982d89SJeremy L. Thompson   @param opfield         CeedOperatorField
7987a982d89SJeremy L. Thompson   @param[out] basis      Variable to store CeedBasis
7997a982d89SJeremy L. Thompson 
8007a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
8017a982d89SJeremy L. Thompson 
8027a982d89SJeremy L. Thompson   @ref Backend
8037a982d89SJeremy L. Thompson **/
8047a982d89SJeremy L. Thompson 
8057a982d89SJeremy L. Thompson int CeedOperatorFieldGetBasis(CeedOperatorField opfield, CeedBasis *basis) {
8067a982d89SJeremy L. Thompson   *basis = opfield->basis;
807e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
8087a982d89SJeremy L. Thompson }
8097a982d89SJeremy L. Thompson 
8107a982d89SJeremy L. Thompson /**
8117a982d89SJeremy L. Thompson   @brief Get the CeedVector of a CeedOperatorField
8127a982d89SJeremy L. Thompson 
8137a982d89SJeremy L. Thompson   @param opfield         CeedOperatorField
8147a982d89SJeremy L. Thompson   @param[out] vec        Variable to store CeedVector
8157a982d89SJeremy L. Thompson 
8167a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
8177a982d89SJeremy L. Thompson 
8187a982d89SJeremy L. Thompson   @ref Backend
8197a982d89SJeremy L. Thompson **/
8207a982d89SJeremy L. Thompson 
8217a982d89SJeremy L. Thompson int CeedOperatorFieldGetVector(CeedOperatorField opfield, CeedVector *vec) {
8227a982d89SJeremy L. Thompson   *vec = opfield->vec;
823e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
8247a982d89SJeremy L. Thompson }
8257a982d89SJeremy L. Thompson 
8267a982d89SJeremy L. Thompson /// @}
8277a982d89SJeremy L. Thompson 
8287a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
8297a982d89SJeremy L. Thompson /// CeedOperator Public API
8307a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
8317a982d89SJeremy L. Thompson /// @addtogroup CeedOperatorUser
832dfdf5a53Sjeremylt /// @{
833d7b241e6Sjeremylt 
834d7b241e6Sjeremylt /**
8350219ea01SJeremy L Thompson   @brief Create a CeedOperator and associate a CeedQFunction. A CeedBasis and
8360219ea01SJeremy L Thompson            CeedElemRestriction can be associated with CeedQFunction fields with
8370219ea01SJeremy L Thompson            \ref CeedOperatorSetField.
838d7b241e6Sjeremylt 
839b11c1e72Sjeremylt   @param ceed    A Ceed object where the CeedOperator will be created
840d7b241e6Sjeremylt   @param qf      QFunction defining the action of the operator at quadrature points
84134138859Sjeremylt   @param dqf     QFunction defining the action of the Jacobian of @a qf (or
8424cc79fe7SJed Brown                    @ref CEED_QFUNCTION_NONE)
843d7b241e6Sjeremylt   @param dqfT    QFunction defining the action of the transpose of the Jacobian
8444cc79fe7SJed Brown                    of @a qf (or @ref CEED_QFUNCTION_NONE)
845b11c1e72Sjeremylt   @param[out] op Address of the variable where the newly created
846b11c1e72Sjeremylt                      CeedOperator will be stored
847b11c1e72Sjeremylt 
848b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
849dfdf5a53Sjeremylt 
8507a982d89SJeremy L. Thompson   @ref User
851d7b241e6Sjeremylt  */
852d7b241e6Sjeremylt int CeedOperatorCreate(Ceed ceed, CeedQFunction qf, CeedQFunction dqf,
853d7b241e6Sjeremylt                        CeedQFunction dqfT, CeedOperator *op) {
854d7b241e6Sjeremylt   int ierr;
855d7b241e6Sjeremylt 
8565fe0d4faSjeremylt   if (!ceed->OperatorCreate) {
8575fe0d4faSjeremylt     Ceed delegate;
858aefd8378Sjeremylt     ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr);
8595fe0d4faSjeremylt 
8605fe0d4faSjeremylt     if (!delegate)
861c042f62fSJeremy L Thompson       // LCOV_EXCL_START
862e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_UNSUPPORTED,
863e15f9bd0SJeremy L Thompson                        "Backend does not support OperatorCreate");
864c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
8655fe0d4faSjeremylt 
8665fe0d4faSjeremylt     ierr = CeedOperatorCreate(delegate, qf, dqf, dqfT, op); CeedChk(ierr);
867e15f9bd0SJeremy L Thompson     return CEED_ERROR_SUCCESS;
8685fe0d4faSjeremylt   }
8695fe0d4faSjeremylt 
870b3b7035fSJeremy L Thompson   if (!qf || qf == CEED_QFUNCTION_NONE)
871b3b7035fSJeremy L Thompson     // LCOV_EXCL_START
872e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_MINOR,
873e15f9bd0SJeremy L Thompson                      "Operator must have a valid QFunction.");
874b3b7035fSJeremy L Thompson   // LCOV_EXCL_STOP
875d7b241e6Sjeremylt   ierr = CeedCalloc(1, op); CeedChk(ierr);
876d7b241e6Sjeremylt   (*op)->ceed = ceed;
877d7b241e6Sjeremylt   ceed->refcount++;
878d7b241e6Sjeremylt   (*op)->refcount = 1;
879d7b241e6Sjeremylt   (*op)->qf = qf;
880d7b241e6Sjeremylt   qf->refcount++;
881442e7f0bSjeremylt   if (dqf && dqf != CEED_QFUNCTION_NONE) {
882d7b241e6Sjeremylt     (*op)->dqf = dqf;
883442e7f0bSjeremylt     dqf->refcount++;
884442e7f0bSjeremylt   }
885442e7f0bSjeremylt   if (dqfT && dqfT != CEED_QFUNCTION_NONE) {
886d7b241e6Sjeremylt     (*op)->dqfT = dqfT;
887442e7f0bSjeremylt     dqfT->refcount++;
888442e7f0bSjeremylt   }
889fe2413ffSjeremylt   ierr = CeedCalloc(16, &(*op)->inputfields); CeedChk(ierr);
890fe2413ffSjeremylt   ierr = CeedCalloc(16, &(*op)->outputfields); CeedChk(ierr);
891d7b241e6Sjeremylt   ierr = ceed->OperatorCreate(*op); CeedChk(ierr);
892e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
893d7b241e6Sjeremylt }
894d7b241e6Sjeremylt 
895d7b241e6Sjeremylt /**
89652d6035fSJeremy L Thompson   @brief Create an operator that composes the action of several operators
89752d6035fSJeremy L Thompson 
89852d6035fSJeremy L Thompson   @param ceed    A Ceed object where the CeedOperator will be created
89952d6035fSJeremy L Thompson   @param[out] op Address of the variable where the newly created
90052d6035fSJeremy L Thompson                      Composite CeedOperator will be stored
90152d6035fSJeremy L Thompson 
90252d6035fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
90352d6035fSJeremy L Thompson 
9047a982d89SJeremy L. Thompson   @ref User
90552d6035fSJeremy L Thompson  */
90652d6035fSJeremy L Thompson int CeedCompositeOperatorCreate(Ceed ceed, CeedOperator *op) {
90752d6035fSJeremy L Thompson   int ierr;
90852d6035fSJeremy L Thompson 
90952d6035fSJeremy L Thompson   if (!ceed->CompositeOperatorCreate) {
91052d6035fSJeremy L Thompson     Ceed delegate;
911aefd8378Sjeremylt     ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr);
91252d6035fSJeremy L Thompson 
913250756a7Sjeremylt     if (delegate) {
91452d6035fSJeremy L Thompson       ierr = CeedCompositeOperatorCreate(delegate, op); CeedChk(ierr);
915e15f9bd0SJeremy L Thompson       return CEED_ERROR_SUCCESS;
91652d6035fSJeremy L Thompson     }
917250756a7Sjeremylt   }
91852d6035fSJeremy L Thompson 
91952d6035fSJeremy L Thompson   ierr = CeedCalloc(1, op); CeedChk(ierr);
92052d6035fSJeremy L Thompson   (*op)->ceed = ceed;
92152d6035fSJeremy L Thompson   ceed->refcount++;
92252d6035fSJeremy L Thompson   (*op)->composite = true;
92352d6035fSJeremy L Thompson   ierr = CeedCalloc(16, &(*op)->suboperators); CeedChk(ierr);
924250756a7Sjeremylt 
925250756a7Sjeremylt   if (ceed->CompositeOperatorCreate) {
92652d6035fSJeremy L Thompson     ierr = ceed->CompositeOperatorCreate(*op); CeedChk(ierr);
927250756a7Sjeremylt   }
928e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
92952d6035fSJeremy L Thompson }
93052d6035fSJeremy L Thompson 
93152d6035fSJeremy L Thompson /**
932b11c1e72Sjeremylt   @brief Provide a field to a CeedOperator for use by its CeedQFunction
933d7b241e6Sjeremylt 
934d7b241e6Sjeremylt   This function is used to specify both active and passive fields to a
935d7b241e6Sjeremylt   CeedOperator.  For passive fields, a vector @arg v must be provided.  Passive
936d7b241e6Sjeremylt   fields can inputs or outputs (updated in-place when operator is applied).
937d7b241e6Sjeremylt 
938d7b241e6Sjeremylt   Active fields must be specified using this function, but their data (in a
939d7b241e6Sjeremylt   CeedVector) is passed in CeedOperatorApply().  There can be at most one active
940d7b241e6Sjeremylt   input and at most one active output.
941d7b241e6Sjeremylt 
9428c91a0c9SJeremy L Thompson   @param op         CeedOperator on which to provide the field
9438795c945Sjeremylt   @param fieldname  Name of the field (to be matched with the name used by
9448795c945Sjeremylt                       CeedQFunction)
945b11c1e72Sjeremylt   @param r          CeedElemRestriction
9464cc79fe7SJed Brown   @param b          CeedBasis in which the field resides or @ref CEED_BASIS_COLLOCATED
947b11c1e72Sjeremylt                       if collocated with quadrature points
9484cc79fe7SJed Brown   @param v          CeedVector to be used by CeedOperator or @ref CEED_VECTOR_ACTIVE
9494cc79fe7SJed Brown                       if field is active or @ref CEED_VECTOR_NONE if using
9504cc79fe7SJed Brown                       @ref CEED_EVAL_WEIGHT in the QFunction
951b11c1e72Sjeremylt 
952b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
953dfdf5a53Sjeremylt 
9547a982d89SJeremy L. Thompson   @ref User
955b11c1e72Sjeremylt **/
956d7b241e6Sjeremylt int CeedOperatorSetField(CeedOperator op, const char *fieldname,
957a8d32208Sjeremylt                          CeedElemRestriction r, CeedBasis b, CeedVector v) {
958d7b241e6Sjeremylt   int ierr;
95952d6035fSJeremy L Thompson   if (op->composite)
960c042f62fSJeremy L Thompson     // LCOV_EXCL_START
961e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
962e15f9bd0SJeremy L Thompson                      "Cannot add field to composite operator.");
963c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
9648b067b84SJed Brown   if (!r)
965c042f62fSJeremy L Thompson     // LCOV_EXCL_START
966e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
967c042f62fSJeremy L Thompson                      "ElemRestriction r for field \"%s\" must be non-NULL.",
968c042f62fSJeremy L Thompson                      fieldname);
969c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
9708b067b84SJed Brown   if (!b)
971c042f62fSJeremy L Thompson     // LCOV_EXCL_START
972e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
973e15f9bd0SJeremy L Thompson                      "Basis b for field \"%s\" must be non-NULL.",
974c042f62fSJeremy L Thompson                      fieldname);
975c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
9768b067b84SJed Brown   if (!v)
977c042f62fSJeremy L Thompson     // LCOV_EXCL_START
978e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
979e15f9bd0SJeremy L Thompson                      "Vector v for field \"%s\" must be non-NULL.",
980c042f62fSJeremy L Thompson                      fieldname);
981c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
98252d6035fSJeremy L Thompson 
983d7b241e6Sjeremylt   CeedInt numelements;
984d7b241e6Sjeremylt   ierr = CeedElemRestrictionGetNumElements(r, &numelements); CeedChk(ierr);
98515910d16Sjeremylt   if (r != CEED_ELEMRESTRICTION_NONE && op->hasrestriction &&
98615910d16Sjeremylt       op->numelements != numelements)
987c042f62fSJeremy L Thompson     // LCOV_EXCL_START
988e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_DIMENSION,
9891d102b48SJeremy L Thompson                      "ElemRestriction with %d elements incompatible with prior "
9901d102b48SJeremy L Thompson                      "%d elements", numelements, op->numelements);
991c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
992d7b241e6Sjeremylt 
993d7b241e6Sjeremylt   CeedInt numqpoints;
994e15f9bd0SJeremy L Thompson   if (b != CEED_BASIS_COLLOCATED) {
995d7b241e6Sjeremylt     ierr = CeedBasisGetNumQuadraturePoints(b, &numqpoints); CeedChk(ierr);
996d7b241e6Sjeremylt     if (op->numqpoints && op->numqpoints != numqpoints)
997c042f62fSJeremy L Thompson       // LCOV_EXCL_START
998e15f9bd0SJeremy L Thompson       return CeedError(op->ceed, CEED_ERROR_DIMENSION,
999e15f9bd0SJeremy L Thompson                        "Basis with %d quadrature points "
10001d102b48SJeremy L Thompson                        "incompatible with prior %d points", numqpoints,
10011d102b48SJeremy L Thompson                        op->numqpoints);
1002c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
1003d7b241e6Sjeremylt   }
100415910d16Sjeremylt   CeedQFunctionField qfield;
1005d1bcdac9Sjeremylt   CeedOperatorField *ofield;
1006d7b241e6Sjeremylt   for (CeedInt i=0; i<op->qf->numinputfields; i++) {
1007fe2413ffSjeremylt     if (!strcmp(fieldname, (*op->qf->inputfields[i]).fieldname)) {
100815910d16Sjeremylt       qfield = op->qf->inputfields[i];
1009d7b241e6Sjeremylt       ofield = &op->inputfields[i];
1010d7b241e6Sjeremylt       goto found;
1011d7b241e6Sjeremylt     }
1012d7b241e6Sjeremylt   }
1013d7b241e6Sjeremylt   for (CeedInt i=0; i<op->qf->numoutputfields; i++) {
1014fe2413ffSjeremylt     if (!strcmp(fieldname, (*op->qf->outputfields[i]).fieldname)) {
1015e15f9bd0SJeremy L Thompson       qfield = op->qf->outputfields[i];
1016d7b241e6Sjeremylt       ofield = &op->outputfields[i];
1017d7b241e6Sjeremylt       goto found;
1018d7b241e6Sjeremylt     }
1019d7b241e6Sjeremylt   }
1020c042f62fSJeremy L Thompson   // LCOV_EXCL_START
1021e15f9bd0SJeremy L Thompson   return CeedError(op->ceed, CEED_ERROR_INCOMPLETE,
1022e15f9bd0SJeremy L Thompson                    "QFunction has no knowledge of field '%s'",
1023d7b241e6Sjeremylt                    fieldname);
1024c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
1025d7b241e6Sjeremylt found:
1026e15f9bd0SJeremy L Thompson   ierr = CeedOperatorCheckField(op->ceed, qfield, r, b); CeedChk(ierr);
1027fe2413ffSjeremylt   ierr = CeedCalloc(1, ofield); CeedChk(ierr);
1028e15f9bd0SJeremy L Thompson 
1029e15f9bd0SJeremy L Thompson   (*ofield)->vec = v;
1030e15f9bd0SJeremy L Thompson   if (v != CEED_VECTOR_ACTIVE && v != CEED_VECTOR_NONE) {
1031e15f9bd0SJeremy L Thompson     v->refcount += 1;
1032e15f9bd0SJeremy L Thompson   }
1033e15f9bd0SJeremy L Thompson 
1034fe2413ffSjeremylt   (*ofield)->Erestrict = r;
103571352a93Sjeremylt   r->refcount += 1;
1036e15f9bd0SJeremy L Thompson   if (r != CEED_ELEMRESTRICTION_NONE) {
1037e15f9bd0SJeremy L Thompson     op->numelements = numelements;
1038e15f9bd0SJeremy L Thompson     op->hasrestriction = true; // Restriction set, but numelements may be 0
1039e15f9bd0SJeremy L Thompson   }
1040d99fa3c5SJeremy L Thompson 
1041e15f9bd0SJeremy L Thompson   (*ofield)->basis = b;
1042e15f9bd0SJeremy L Thompson   if (b != CEED_BASIS_COLLOCATED) {
1043e15f9bd0SJeremy L Thompson     op->numqpoints = numqpoints;
1044e15f9bd0SJeremy L Thompson     b->refcount += 1;
1045e15f9bd0SJeremy L Thompson   }
1046e15f9bd0SJeremy L Thompson 
1047e15f9bd0SJeremy L Thompson   op->nfields += 1;
1048d99fa3c5SJeremy L Thompson   size_t len = strlen(fieldname);
1049d99fa3c5SJeremy L Thompson   char *tmp;
1050d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(len+1, &tmp); CeedChk(ierr);
1051d99fa3c5SJeremy L Thompson   memcpy(tmp, fieldname, len+1);
1052d99fa3c5SJeremy L Thompson   (*ofield)->fieldname = tmp;
1053e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1054d7b241e6Sjeremylt }
1055d7b241e6Sjeremylt 
1056d7b241e6Sjeremylt /**
105752d6035fSJeremy L Thompson   @brief Add a sub-operator to a composite CeedOperator
1058288c0443SJeremy L Thompson 
105934138859Sjeremylt   @param[out] compositeop Composite CeedOperator
106034138859Sjeremylt   @param      subop       Sub-operator CeedOperator
106152d6035fSJeremy L Thompson 
106252d6035fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
106352d6035fSJeremy L Thompson 
10647a982d89SJeremy L. Thompson   @ref User
106552d6035fSJeremy L Thompson  */
1066692c2638Sjeremylt int CeedCompositeOperatorAddSub(CeedOperator compositeop, CeedOperator subop) {
106752d6035fSJeremy L Thompson   if (!compositeop->composite)
1068c042f62fSJeremy L Thompson     // LCOV_EXCL_START
1069e15f9bd0SJeremy L Thompson     return CeedError(compositeop->ceed, CEED_ERROR_MINOR,
1070*e2f04181SAndrew T. Barker                      "CeedOperator is not a composite operator");
1071c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
107252d6035fSJeremy L Thompson 
107352d6035fSJeremy L Thompson   if (compositeop->numsub == CEED_COMPOSITE_MAX)
1074c042f62fSJeremy L Thompson     // LCOV_EXCL_START
1075e15f9bd0SJeremy L Thompson     return CeedError(compositeop->ceed, CEED_ERROR_UNSUPPORTED,
1076e15f9bd0SJeremy L Thompson                      "Cannot add additional suboperators");
1077c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
107852d6035fSJeremy L Thompson 
107952d6035fSJeremy L Thompson   compositeop->suboperators[compositeop->numsub] = subop;
108052d6035fSJeremy L Thompson   subop->refcount++;
108152d6035fSJeremy L Thompson   compositeop->numsub++;
1082e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
108352d6035fSJeremy L Thompson }
108452d6035fSJeremy L Thompson 
108552d6035fSJeremy L Thompson /**
10861d102b48SJeremy L Thompson   @brief Assemble a linear CeedQFunction associated with a CeedOperator
10871d102b48SJeremy L Thompson 
10881d102b48SJeremy L Thompson   This returns a CeedVector containing a matrix at each quadrature point
10891d102b48SJeremy L Thompson     providing the action of the CeedQFunction associated with the CeedOperator.
10901d102b48SJeremy L Thompson     The vector 'assembled' is of shape
10911d102b48SJeremy L Thompson       [num_elements, num_input_fields, num_output_fields, num_quad_points]
10921d102b48SJeremy L Thompson     and contains column-major matrices representing the action of the
10931d102b48SJeremy L Thompson     CeedQFunction for a corresponding quadrature point on an element. Inputs and
10941d102b48SJeremy L Thompson     outputs are in the order provided by the user when adding CeedOperator fields.
10954cc79fe7SJed Brown     For example, a CeedQFunction with inputs 'u' and 'gradu' and outputs 'gradv' and
10961d102b48SJeremy L Thompson     'v', provided in that order, would result in an assembled QFunction that
10971d102b48SJeremy L Thompson     consists of (1 + dim) x (dim + 1) matrices at each quadrature point acting
10981d102b48SJeremy L Thompson     on the input [u, du_0, du_1] and producing the output [dv_0, dv_1, v].
10991d102b48SJeremy L Thompson 
11001d102b48SJeremy L Thompson   @param op             CeedOperator to assemble CeedQFunction
11011d102b48SJeremy L Thompson   @param[out] assembled CeedVector to store assembled CeedQFunction at
11021d102b48SJeremy L Thompson                           quadrature points
11031d102b48SJeremy L Thompson   @param[out] rstr      CeedElemRestriction for CeedVector containing assembled
11041d102b48SJeremy L Thompson                           CeedQFunction
11051d102b48SJeremy L Thompson   @param request        Address of CeedRequest for non-blocking completion, else
11064cc79fe7SJed Brown                           @ref CEED_REQUEST_IMMEDIATE
11071d102b48SJeremy L Thompson 
11081d102b48SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
11091d102b48SJeremy L Thompson 
11107a982d89SJeremy L. Thompson   @ref User
11111d102b48SJeremy L Thompson **/
111280ac2e43SJeremy L Thompson int CeedOperatorLinearAssembleQFunction(CeedOperator op, CeedVector *assembled,
11137f823360Sjeremylt                                         CeedElemRestriction *rstr,
11147f823360Sjeremylt                                         CeedRequest *request) {
11151d102b48SJeremy L Thompson   int ierr;
1116*e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
11171d102b48SJeremy L Thompson 
11187172caadSjeremylt   // Backend version
111980ac2e43SJeremy L Thompson   if (op->LinearAssembleQFunction) {
1120*e2f04181SAndrew T. Barker     return op->LinearAssembleQFunction(op, assembled, rstr, request);
11215107b09fSJeremy L Thompson   } else {
11225107b09fSJeremy L Thompson     // Fallback to reference Ceed
11235107b09fSJeremy L Thompson     if (!op->opfallback) {
11245107b09fSJeremy L Thompson       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
11255107b09fSJeremy L Thompson     }
11265107b09fSJeremy L Thompson     // Assemble
1127*e2f04181SAndrew T. Barker     return CeedOperatorLinearAssembleQFunction(op->opfallback, assembled,
1128*e2f04181SAndrew T. Barker            rstr, request);
11295107b09fSJeremy L Thompson   }
11301d102b48SJeremy L Thompson }
11311d102b48SJeremy L Thompson 
11321d102b48SJeremy L Thompson /**
1133d965c7a7SJeremy L Thompson   @brief Assemble the diagonal of a square linear CeedOperator
1134b7ec98d8SJeremy L Thompson 
11359e9210b8SJeremy L Thompson   This overwrites a CeedVector with the diagonal of a linear CeedOperator.
1136b7ec98d8SJeremy L Thompson 
1137c04a41a7SJeremy L Thompson   Note: Currently only non-composite CeedOperators with a single field and
1138c04a41a7SJeremy L Thompson           composite CeedOperators with single field sub-operators are supported.
1139d965c7a7SJeremy L Thompson 
1140b7ec98d8SJeremy L Thompson   @param op             CeedOperator to assemble CeedQFunction
1141b7ec98d8SJeremy L Thompson   @param[out] assembled CeedVector to store assembled CeedOperator diagonal
1142b7ec98d8SJeremy L Thompson   @param request        Address of CeedRequest for non-blocking completion, else
11434cc79fe7SJed Brown                           @ref CEED_REQUEST_IMMEDIATE
1144b7ec98d8SJeremy L Thompson 
1145b7ec98d8SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1146b7ec98d8SJeremy L Thompson 
11477a982d89SJeremy L. Thompson   @ref User
1148b7ec98d8SJeremy L Thompson **/
11492bba3ffaSJeremy L Thompson int CeedOperatorLinearAssembleDiagonal(CeedOperator op, CeedVector assembled,
11507f823360Sjeremylt                                        CeedRequest *request) {
1151b7ec98d8SJeremy L Thompson   int ierr;
1152*e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
1153b7ec98d8SJeremy L Thompson 
1154b7ec98d8SJeremy L Thompson   // Use backend version, if available
115580ac2e43SJeremy L Thompson   if (op->LinearAssembleDiagonal) {
1156*e2f04181SAndrew T. Barker     return op->LinearAssembleDiagonal(op, assembled, request);
11579e9210b8SJeremy L Thompson   } else if (op->LinearAssembleAddDiagonal) {
11589e9210b8SJeremy L Thompson     ierr = CeedVectorSetValue(assembled, 0.0); CeedChk(ierr);
11599e9210b8SJeremy L Thompson     return CeedOperatorLinearAssembleAddDiagonal(op, assembled, request);
11609e9210b8SJeremy L Thompson   } else {
11619e9210b8SJeremy L Thompson     // Fallback to reference Ceed
11629e9210b8SJeremy L Thompson     if (!op->opfallback) {
11639e9210b8SJeremy L Thompson       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
11649e9210b8SJeremy L Thompson     }
11659e9210b8SJeremy L Thompson     // Assemble
1166*e2f04181SAndrew T. Barker     return CeedOperatorLinearAssembleDiagonal(op->opfallback, assembled,
1167*e2f04181SAndrew T. Barker            request);
11689e9210b8SJeremy L Thompson   }
11699e9210b8SJeremy L Thompson }
11709e9210b8SJeremy L Thompson 
11719e9210b8SJeremy L Thompson /**
11729e9210b8SJeremy L Thompson   @brief Assemble the diagonal of a square linear CeedOperator
11739e9210b8SJeremy L Thompson 
11749e9210b8SJeremy L Thompson   This sums into a CeedVector the diagonal of a linear CeedOperator.
11759e9210b8SJeremy L Thompson 
11769e9210b8SJeremy L Thompson   Note: Currently only non-composite CeedOperators with a single field and
11779e9210b8SJeremy L Thompson           composite CeedOperators with single field sub-operators are supported.
11789e9210b8SJeremy L Thompson 
11799e9210b8SJeremy L Thompson   @param op             CeedOperator to assemble CeedQFunction
11809e9210b8SJeremy L Thompson   @param[out] assembled CeedVector to store assembled CeedOperator diagonal
11819e9210b8SJeremy L Thompson   @param request        Address of CeedRequest for non-blocking completion, else
11829e9210b8SJeremy L Thompson                           @ref CEED_REQUEST_IMMEDIATE
11839e9210b8SJeremy L Thompson 
11849e9210b8SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
11859e9210b8SJeremy L Thompson 
11869e9210b8SJeremy L Thompson   @ref User
11879e9210b8SJeremy L Thompson **/
11889e9210b8SJeremy L Thompson int CeedOperatorLinearAssembleAddDiagonal(CeedOperator op, CeedVector assembled,
11899e9210b8SJeremy L Thompson     CeedRequest *request) {
11909e9210b8SJeremy L Thompson   int ierr;
1191*e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
11929e9210b8SJeremy L Thompson 
11939e9210b8SJeremy L Thompson   // Use backend version, if available
11949e9210b8SJeremy L Thompson   if (op->LinearAssembleAddDiagonal) {
1195*e2f04181SAndrew T. Barker     return op->LinearAssembleAddDiagonal(op, assembled, request);
11967172caadSjeremylt   } else {
11977172caadSjeremylt     // Fallback to reference Ceed
11987172caadSjeremylt     if (!op->opfallback) {
11997172caadSjeremylt       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
1200b7ec98d8SJeremy L Thompson     }
12017172caadSjeremylt     // Assemble
1202*e2f04181SAndrew T. Barker     return CeedOperatorLinearAssembleAddDiagonal(op->opfallback, assembled,
1203*e2f04181SAndrew T. Barker            request);
1204b7ec98d8SJeremy L Thompson   }
1205b7ec98d8SJeremy L Thompson }
1206b7ec98d8SJeremy L Thompson 
1207b7ec98d8SJeremy L Thompson /**
1208d965c7a7SJeremy L Thompson   @brief Assemble the point block diagonal of a square linear CeedOperator
1209d965c7a7SJeremy L Thompson 
12109e9210b8SJeremy L Thompson   This overwrites a CeedVector with the point block diagonal of a linear
1211d965c7a7SJeremy L Thompson     CeedOperator.
1212d965c7a7SJeremy L Thompson 
1213c04a41a7SJeremy L Thompson   Note: Currently only non-composite CeedOperators with a single field and
1214c04a41a7SJeremy L Thompson           composite CeedOperators with single field sub-operators are supported.
1215d965c7a7SJeremy L Thompson 
1216d965c7a7SJeremy L Thompson   @param op             CeedOperator to assemble CeedQFunction
1217d965c7a7SJeremy L Thompson   @param[out] assembled CeedVector to store assembled CeedOperator point block
1218d965c7a7SJeremy L Thompson                           diagonal, provided in row-major form with an
1219d965c7a7SJeremy L Thompson                           @a ncomp * @a ncomp block at each node. The dimensions
1220d965c7a7SJeremy L Thompson                           of this vector are derived from the active vector
1221d965c7a7SJeremy L Thompson                           for the CeedOperator. The array has shape
1222d965c7a7SJeremy L Thompson                           [nodes, component out, component in].
1223d965c7a7SJeremy L Thompson   @param request        Address of CeedRequest for non-blocking completion, else
1224d965c7a7SJeremy L Thompson                           CEED_REQUEST_IMMEDIATE
1225d965c7a7SJeremy L Thompson 
1226d965c7a7SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1227d965c7a7SJeremy L Thompson 
1228d965c7a7SJeremy L Thompson   @ref User
1229d965c7a7SJeremy L Thompson **/
123080ac2e43SJeremy L Thompson int CeedOperatorLinearAssemblePointBlockDiagonal(CeedOperator op,
12312bba3ffaSJeremy L Thompson     CeedVector assembled, CeedRequest *request) {
1232d965c7a7SJeremy L Thompson   int ierr;
1233*e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
1234d965c7a7SJeremy L Thompson 
1235d965c7a7SJeremy L Thompson   // Use backend version, if available
123680ac2e43SJeremy L Thompson   if (op->LinearAssemblePointBlockDiagonal) {
1237*e2f04181SAndrew T. Barker     return op->LinearAssemblePointBlockDiagonal(op, assembled, request);
12389e9210b8SJeremy L Thompson   } else if (op->LinearAssembleAddPointBlockDiagonal) {
12399e9210b8SJeremy L Thompson     ierr = CeedVectorSetValue(assembled, 0.0); CeedChk(ierr);
12409e9210b8SJeremy L Thompson     return CeedOperatorLinearAssembleAddPointBlockDiagonal(op, assembled,
12419e9210b8SJeremy L Thompson            request);
1242d965c7a7SJeremy L Thompson   } else {
1243d965c7a7SJeremy L Thompson     // Fallback to reference Ceed
1244d965c7a7SJeremy L Thompson     if (!op->opfallback) {
1245d965c7a7SJeremy L Thompson       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
1246d965c7a7SJeremy L Thompson     }
1247d965c7a7SJeremy L Thompson     // Assemble
1248*e2f04181SAndrew T. Barker     return CeedOperatorLinearAssemblePointBlockDiagonal(op->opfallback,
1249*e2f04181SAndrew T. Barker            assembled, request);
12509e9210b8SJeremy L Thompson   }
12519e9210b8SJeremy L Thompson }
12529e9210b8SJeremy L Thompson 
12539e9210b8SJeremy L Thompson /**
12549e9210b8SJeremy L Thompson   @brief Assemble the point block diagonal of a square linear CeedOperator
12559e9210b8SJeremy L Thompson 
12569e9210b8SJeremy L Thompson   This sums into a CeedVector with the point block diagonal of a linear
12579e9210b8SJeremy L Thompson     CeedOperator.
12589e9210b8SJeremy L Thompson 
12599e9210b8SJeremy L Thompson   Note: Currently only non-composite CeedOperators with a single field and
12609e9210b8SJeremy L Thompson           composite CeedOperators with single field sub-operators are supported.
12619e9210b8SJeremy L Thompson 
12629e9210b8SJeremy L Thompson   @param op             CeedOperator to assemble CeedQFunction
12639e9210b8SJeremy L Thompson   @param[out] assembled CeedVector to store assembled CeedOperator point block
12649e9210b8SJeremy L Thompson                           diagonal, provided in row-major form with an
12659e9210b8SJeremy L Thompson                           @a ncomp * @a ncomp block at each node. The dimensions
12669e9210b8SJeremy L Thompson                           of this vector are derived from the active vector
12679e9210b8SJeremy L Thompson                           for the CeedOperator. The array has shape
12689e9210b8SJeremy L Thompson                           [nodes, component out, component in].
12699e9210b8SJeremy L Thompson   @param request        Address of CeedRequest for non-blocking completion, else
12709e9210b8SJeremy L Thompson                           CEED_REQUEST_IMMEDIATE
12719e9210b8SJeremy L Thompson 
12729e9210b8SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
12739e9210b8SJeremy L Thompson 
12749e9210b8SJeremy L Thompson   @ref User
12759e9210b8SJeremy L Thompson **/
12769e9210b8SJeremy L Thompson int CeedOperatorLinearAssembleAddPointBlockDiagonal(CeedOperator op,
12779e9210b8SJeremy L Thompson     CeedVector assembled, CeedRequest *request) {
12789e9210b8SJeremy L Thompson   int ierr;
1279*e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
12809e9210b8SJeremy L Thompson 
12819e9210b8SJeremy L Thompson   // Use backend version, if available
12829e9210b8SJeremy L Thompson   if (op->LinearAssembleAddPointBlockDiagonal) {
1283*e2f04181SAndrew T. Barker     return op->LinearAssembleAddPointBlockDiagonal(op, assembled, request);
12849e9210b8SJeremy L Thompson   } else {
12859e9210b8SJeremy L Thompson     // Fallback to reference Ceed
12869e9210b8SJeremy L Thompson     if (!op->opfallback) {
12879e9210b8SJeremy L Thompson       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
12889e9210b8SJeremy L Thompson     }
12899e9210b8SJeremy L Thompson     // Assemble
1290*e2f04181SAndrew T. Barker     return CeedOperatorLinearAssembleAddPointBlockDiagonal(op->opfallback,
1291*e2f04181SAndrew T. Barker            assembled, request);
1292d965c7a7SJeremy L Thompson   }
1293*e2f04181SAndrew T. Barker }
1294*e2f04181SAndrew T. Barker 
1295*e2f04181SAndrew T. Barker /**
1296*e2f04181SAndrew T. Barker    @brief Build nonzero pattern for non-composite operator.
1297*e2f04181SAndrew T. Barker 
1298*e2f04181SAndrew T. Barker    Users should generally use CeedOperatorLinearAssembleSymbolic()
1299*e2f04181SAndrew T. Barker 
1300*e2f04181SAndrew T. Barker    @ref Developer
1301*e2f04181SAndrew T. Barker **/
1302*e2f04181SAndrew T. Barker int CeedSingleOperatorAssembleSymbolic(CeedOperator op, CeedInt offset,
1303*e2f04181SAndrew T. Barker                                        CeedInt *rows, CeedInt *cols) {
1304*e2f04181SAndrew T. Barker   int ierr;
1305*e2f04181SAndrew T. Barker   Ceed ceed = op->ceed;
1306*e2f04181SAndrew T. Barker   if (op->composite)
1307*e2f04181SAndrew T. Barker     // LCOV_EXCL_START
1308*e2f04181SAndrew T. Barker     return CeedError(ceed, CEED_ERROR_UNSUPPORTED,
1309*e2f04181SAndrew T. Barker                      "Composite operator not supported");
1310*e2f04181SAndrew T. Barker   // LCOV_EXCL_STOP
1311*e2f04181SAndrew T. Barker 
1312*e2f04181SAndrew T. Barker   CeedElemRestriction rstrin;
1313*e2f04181SAndrew T. Barker   ierr = CeedOperatorGetActiveElemRestriction(op, &rstrin); CeedChk(ierr);
1314*e2f04181SAndrew T. Barker   CeedInt nelem, elemsize, nnodes, ncomp;
1315*e2f04181SAndrew T. Barker   ierr = CeedElemRestrictionGetNumElements(rstrin, &nelem); CeedChk(ierr);
1316*e2f04181SAndrew T. Barker   ierr = CeedElemRestrictionGetElementSize(rstrin, &elemsize); CeedChk(ierr);
1317*e2f04181SAndrew T. Barker   ierr = CeedElemRestrictionGetLVectorSize(rstrin, &nnodes); CeedChk(ierr);
1318*e2f04181SAndrew T. Barker   ierr = CeedElemRestrictionGetNumComponents(rstrin, &ncomp); CeedChk(ierr);
1319*e2f04181SAndrew T. Barker   CeedInt layout_er[3];
1320*e2f04181SAndrew T. Barker   ierr = CeedElemRestrictionGetELayout(rstrin, &layout_er); CeedChk(ierr);
1321*e2f04181SAndrew T. Barker 
1322*e2f04181SAndrew T. Barker   CeedInt local_nentries = elemsize*ncomp * elemsize*ncomp * nelem;
1323*e2f04181SAndrew T. Barker 
1324*e2f04181SAndrew T. Barker   // Determine elem_dof relation
1325*e2f04181SAndrew T. Barker   CeedVector index_vec;
1326*e2f04181SAndrew T. Barker   ierr = CeedVectorCreate(ceed, nnodes, &index_vec); CeedChk(ierr);
1327*e2f04181SAndrew T. Barker   CeedScalar *array;
1328*e2f04181SAndrew T. Barker   ierr = CeedVectorGetArray(index_vec, CEED_MEM_HOST, &array); CeedChk(ierr);
1329*e2f04181SAndrew T. Barker   for (CeedInt i = 0; i < nnodes; ++i) {
1330*e2f04181SAndrew T. Barker     array[i] = i;
1331*e2f04181SAndrew T. Barker   }
1332*e2f04181SAndrew T. Barker   ierr = CeedVectorRestoreArray(index_vec, &array); CeedChk(ierr);
1333*e2f04181SAndrew T. Barker   CeedVector elem_dof;
1334*e2f04181SAndrew T. Barker   ierr = CeedVectorCreate(ceed, nelem * elemsize * ncomp, &elem_dof);
1335*e2f04181SAndrew T. Barker   CeedChk(ierr);
1336*e2f04181SAndrew T. Barker   ierr = CeedVectorSetValue(elem_dof, 0.0); CeedChk(ierr);
1337*e2f04181SAndrew T. Barker   CeedElemRestrictionApply(rstrin, CEED_NOTRANSPOSE, index_vec,
1338*e2f04181SAndrew T. Barker                            elem_dof, CEED_REQUEST_IMMEDIATE); CeedChk(ierr);
1339*e2f04181SAndrew T. Barker   const CeedScalar *elem_dof_a;
1340*e2f04181SAndrew T. Barker   ierr = CeedVectorGetArrayRead(elem_dof, CEED_MEM_HOST, &elem_dof_a);
1341*e2f04181SAndrew T. Barker   CeedChk(ierr);
1342*e2f04181SAndrew T. Barker   ierr = CeedVectorDestroy(&index_vec); CeedChk(ierr);
1343*e2f04181SAndrew T. Barker 
1344*e2f04181SAndrew T. Barker   // Determine i, j locations for element matrices
1345*e2f04181SAndrew T. Barker   CeedInt count = 0;
1346*e2f04181SAndrew T. Barker   for (int e = 0; e < nelem; ++e) {
1347*e2f04181SAndrew T. Barker     for (int compin = 0; compin < ncomp; ++compin) {
1348*e2f04181SAndrew T. Barker       for (int compout = 0; compout < ncomp; ++compout) {
1349*e2f04181SAndrew T. Barker         for (int i = 0; i < elemsize; ++i) {
1350*e2f04181SAndrew T. Barker           for (int j = 0; j < elemsize; ++j) {
1351*e2f04181SAndrew T. Barker             const CeedInt edof_index_row = (i)*layout_er[0] +
1352*e2f04181SAndrew T. Barker                                            (compout)*layout_er[1] + e*layout_er[2];
1353*e2f04181SAndrew T. Barker             const CeedInt edof_index_col = (j)*layout_er[0] +
1354*e2f04181SAndrew T. Barker                                            (compin)*layout_er[1] + e*layout_er[2];
1355*e2f04181SAndrew T. Barker 
1356*e2f04181SAndrew T. Barker             const CeedInt row = elem_dof_a[edof_index_row];
1357*e2f04181SAndrew T. Barker             const CeedInt col = elem_dof_a[edof_index_col];
1358*e2f04181SAndrew T. Barker 
1359*e2f04181SAndrew T. Barker             rows[offset + count] = row;
1360*e2f04181SAndrew T. Barker             cols[offset + count] = col;
1361*e2f04181SAndrew T. Barker             count++;
1362*e2f04181SAndrew T. Barker           }
1363*e2f04181SAndrew T. Barker         }
1364*e2f04181SAndrew T. Barker       }
1365*e2f04181SAndrew T. Barker     }
1366*e2f04181SAndrew T. Barker   }
1367*e2f04181SAndrew T. Barker   if (count != local_nentries)
1368*e2f04181SAndrew T. Barker     // LCOV_EXCL_START
1369*e2f04181SAndrew T. Barker     return CeedError(ceed, CEED_ERROR_MAJOR, "Error computing assembled entries");
1370*e2f04181SAndrew T. Barker   // LCOV_EXCL_STOP
1371*e2f04181SAndrew T. Barker   ierr = CeedVectorRestoreArrayRead(elem_dof, &elem_dof_a); CeedChk(ierr);
1372*e2f04181SAndrew T. Barker   ierr = CeedVectorDestroy(&elem_dof); CeedChk(ierr);
1373*e2f04181SAndrew T. Barker 
1374*e2f04181SAndrew T. Barker   return CEED_ERROR_SUCCESS;
1375*e2f04181SAndrew T. Barker }
1376*e2f04181SAndrew T. Barker 
1377*e2f04181SAndrew T. Barker /**
1378*e2f04181SAndrew T. Barker    @brief Assemble nonzero entries for non-composite operator
1379*e2f04181SAndrew T. Barker 
1380*e2f04181SAndrew T. Barker    Users should generally use CeedOperatorLinearAssemble()
1381*e2f04181SAndrew T. Barker 
1382*e2f04181SAndrew T. Barker    @ref Developer
1383*e2f04181SAndrew T. Barker **/
1384*e2f04181SAndrew T. Barker int CeedSingleOperatorAssemble(CeedOperator op, CeedInt offset,
1385*e2f04181SAndrew T. Barker                                CeedVector values) {
1386*e2f04181SAndrew T. Barker   int ierr;
1387*e2f04181SAndrew T. Barker   Ceed ceed = op->ceed;;
1388*e2f04181SAndrew T. Barker   if (op->composite)
1389*e2f04181SAndrew T. Barker     // LCOV_EXCL_START
1390*e2f04181SAndrew T. Barker     return CeedError(ceed, CEED_ERROR_UNSUPPORTED,
1391*e2f04181SAndrew T. Barker                      "Composite operator not supported");
1392*e2f04181SAndrew T. Barker   // LCOV_EXCL_STOP
1393*e2f04181SAndrew T. Barker 
1394*e2f04181SAndrew T. Barker   // Assemble QFunction
1395*e2f04181SAndrew T. Barker   CeedQFunction qf;
1396*e2f04181SAndrew T. Barker   ierr = CeedOperatorGetQFunction(op, &qf); CeedChk(ierr);
1397*e2f04181SAndrew T. Barker   CeedInt numinputfields, numoutputfields;
1398*e2f04181SAndrew T. Barker   ierr= CeedQFunctionGetNumArgs(qf, &numinputfields, &numoutputfields);
1399*e2f04181SAndrew T. Barker   CeedChk(ierr);
1400*e2f04181SAndrew T. Barker   CeedVector assembledqf;
1401*e2f04181SAndrew T. Barker   CeedElemRestriction rstr_q;
1402*e2f04181SAndrew T. Barker   ierr = CeedOperatorLinearAssembleQFunction(
1403*e2f04181SAndrew T. Barker            op, &assembledqf, &rstr_q, CEED_REQUEST_IMMEDIATE); CeedChk(ierr);
1404*e2f04181SAndrew T. Barker 
1405*e2f04181SAndrew T. Barker   CeedInt qflength;
1406*e2f04181SAndrew T. Barker   ierr = CeedVectorGetLength(assembledqf, &qflength); CeedChk(ierr);
1407*e2f04181SAndrew T. Barker 
1408*e2f04181SAndrew T. Barker   CeedOperatorField *input_fields;
1409*e2f04181SAndrew T. Barker   CeedOperatorField *output_fields;
1410*e2f04181SAndrew T. Barker   ierr = CeedOperatorGetFields(op, &input_fields, &output_fields); CeedChk(ierr);
1411*e2f04181SAndrew T. Barker 
1412*e2f04181SAndrew T. Barker   // Determine active input basis
1413*e2f04181SAndrew T. Barker   CeedQFunctionField *qffields;
1414*e2f04181SAndrew T. Barker   ierr = CeedQFunctionGetFields(qf, &qffields, NULL); CeedChk(ierr);
1415*e2f04181SAndrew T. Barker   CeedInt numemodein = 0, dim = 1;
1416*e2f04181SAndrew T. Barker   CeedEvalMode *emodein = NULL;
1417*e2f04181SAndrew T. Barker   CeedBasis basisin = NULL;
1418*e2f04181SAndrew T. Barker   CeedElemRestriction rstrin = NULL;
1419*e2f04181SAndrew T. Barker   for (CeedInt i=0; i<numinputfields; i++) {
1420*e2f04181SAndrew T. Barker     CeedVector vec;
1421*e2f04181SAndrew T. Barker     ierr = CeedOperatorFieldGetVector(input_fields[i], &vec); CeedChk(ierr);
1422*e2f04181SAndrew T. Barker     if (vec == CEED_VECTOR_ACTIVE) {
1423*e2f04181SAndrew T. Barker       ierr = CeedOperatorFieldGetBasis(input_fields[i], &basisin);
1424*e2f04181SAndrew T. Barker       CeedChk(ierr);
1425*e2f04181SAndrew T. Barker       ierr = CeedBasisGetDimension(basisin, &dim); CeedChk(ierr);
1426*e2f04181SAndrew T. Barker       ierr = CeedOperatorFieldGetElemRestriction(input_fields[i], &rstrin);
1427*e2f04181SAndrew T. Barker       CeedChk(ierr);
1428*e2f04181SAndrew T. Barker       CeedEvalMode emode;
1429*e2f04181SAndrew T. Barker       ierr = CeedQFunctionFieldGetEvalMode(qffields[i], &emode);
1430*e2f04181SAndrew T. Barker       CeedChk(ierr);
1431*e2f04181SAndrew T. Barker       switch (emode) {
1432*e2f04181SAndrew T. Barker       case CEED_EVAL_NONE:
1433*e2f04181SAndrew T. Barker       case CEED_EVAL_INTERP:
1434*e2f04181SAndrew T. Barker         ierr = CeedRealloc(numemodein + 1, &emodein); CeedChk(ierr);
1435*e2f04181SAndrew T. Barker         emodein[numemodein] = emode;
1436*e2f04181SAndrew T. Barker         numemodein += 1;
1437*e2f04181SAndrew T. Barker         break;
1438*e2f04181SAndrew T. Barker       case CEED_EVAL_GRAD:
1439*e2f04181SAndrew T. Barker         ierr = CeedRealloc(numemodein + dim, &emodein); CeedChk(ierr);
1440*e2f04181SAndrew T. Barker         for (CeedInt d=0; d<dim; d++) {
1441*e2f04181SAndrew T. Barker           emodein[numemodein+d] = emode;
1442*e2f04181SAndrew T. Barker         }
1443*e2f04181SAndrew T. Barker         numemodein += dim;
1444*e2f04181SAndrew T. Barker         break;
1445*e2f04181SAndrew T. Barker       case CEED_EVAL_WEIGHT:
1446*e2f04181SAndrew T. Barker       case CEED_EVAL_DIV:
1447*e2f04181SAndrew T. Barker       case CEED_EVAL_CURL:
1448*e2f04181SAndrew T. Barker         break; // Caught by QF Assembly
1449*e2f04181SAndrew T. Barker       }
1450*e2f04181SAndrew T. Barker     }
1451*e2f04181SAndrew T. Barker   }
1452*e2f04181SAndrew T. Barker 
1453*e2f04181SAndrew T. Barker   // Determine active output basis
1454*e2f04181SAndrew T. Barker   ierr = CeedQFunctionGetFields(qf, NULL, &qffields); CeedChk(ierr);
1455*e2f04181SAndrew T. Barker   CeedInt numemodeout = 0;
1456*e2f04181SAndrew T. Barker   CeedEvalMode *emodeout = NULL;
1457*e2f04181SAndrew T. Barker   CeedBasis basisout = NULL;
1458*e2f04181SAndrew T. Barker   CeedElemRestriction rstrout = NULL;
1459*e2f04181SAndrew T. Barker   for (CeedInt i=0; i<numoutputfields; i++) {
1460*e2f04181SAndrew T. Barker     CeedVector vec;
1461*e2f04181SAndrew T. Barker     ierr = CeedOperatorFieldGetVector(output_fields[i], &vec); CeedChk(ierr);
1462*e2f04181SAndrew T. Barker     if (vec == CEED_VECTOR_ACTIVE) {
1463*e2f04181SAndrew T. Barker       ierr = CeedOperatorFieldGetBasis(output_fields[i], &basisout);
1464*e2f04181SAndrew T. Barker       CeedChk(ierr);
1465*e2f04181SAndrew T. Barker       ierr = CeedOperatorFieldGetElemRestriction(output_fields[i], &rstrout);
1466*e2f04181SAndrew T. Barker       CeedChk(ierr);
1467*e2f04181SAndrew T. Barker       CeedEvalMode emode;
1468*e2f04181SAndrew T. Barker       ierr = CeedQFunctionFieldGetEvalMode(qffields[i], &emode);
1469*e2f04181SAndrew T. Barker       CeedChk(ierr);
1470*e2f04181SAndrew T. Barker       switch (emode) {
1471*e2f04181SAndrew T. Barker       case CEED_EVAL_NONE:
1472*e2f04181SAndrew T. Barker       case CEED_EVAL_INTERP:
1473*e2f04181SAndrew T. Barker         ierr = CeedRealloc(numemodeout + 1, &emodeout); CeedChk(ierr);
1474*e2f04181SAndrew T. Barker         emodeout[numemodeout] = emode;
1475*e2f04181SAndrew T. Barker         numemodeout += 1;
1476*e2f04181SAndrew T. Barker         break;
1477*e2f04181SAndrew T. Barker       case CEED_EVAL_GRAD:
1478*e2f04181SAndrew T. Barker         ierr = CeedRealloc(numemodeout + dim, &emodeout); CeedChk(ierr);
1479*e2f04181SAndrew T. Barker         for (CeedInt d=0; d<dim; d++) {
1480*e2f04181SAndrew T. Barker           emodeout[numemodeout+d] = emode;
1481*e2f04181SAndrew T. Barker         }
1482*e2f04181SAndrew T. Barker         numemodeout += dim;
1483*e2f04181SAndrew T. Barker         break;
1484*e2f04181SAndrew T. Barker       case CEED_EVAL_WEIGHT:
1485*e2f04181SAndrew T. Barker       case CEED_EVAL_DIV:
1486*e2f04181SAndrew T. Barker       case CEED_EVAL_CURL:
1487*e2f04181SAndrew T. Barker         break; // Caught by QF Assembly
1488*e2f04181SAndrew T. Barker       }
1489*e2f04181SAndrew T. Barker     }
1490*e2f04181SAndrew T. Barker   }
1491*e2f04181SAndrew T. Barker 
1492*e2f04181SAndrew T. Barker   CeedInt nelem, elemsize, nqpts, ncomp;
1493*e2f04181SAndrew T. Barker   ierr = CeedElemRestrictionGetNumElements(rstrin, &nelem); CeedChk(ierr);
1494*e2f04181SAndrew T. Barker   ierr = CeedElemRestrictionGetElementSize(rstrin, &elemsize); CeedChk(ierr);
1495*e2f04181SAndrew T. Barker   ierr = CeedElemRestrictionGetNumComponents(rstrin, &ncomp); CeedChk(ierr);
1496*e2f04181SAndrew T. Barker   ierr = CeedBasisGetNumQuadraturePoints(basisin, &nqpts); CeedChk(ierr);
1497*e2f04181SAndrew T. Barker 
1498*e2f04181SAndrew T. Barker   CeedInt local_nentries = elemsize*ncomp * elemsize*ncomp * nelem;
1499*e2f04181SAndrew T. Barker 
1500*e2f04181SAndrew T. Barker   // loop over elements and put in data structure
1501*e2f04181SAndrew T. Barker   const CeedScalar *interpin, *gradin;
1502*e2f04181SAndrew T. Barker   ierr = CeedBasisGetInterp(basisin, &interpin); CeedChk(ierr);
1503*e2f04181SAndrew T. Barker   ierr = CeedBasisGetGrad(basisin, &gradin); CeedChk(ierr);
1504*e2f04181SAndrew T. Barker 
1505*e2f04181SAndrew T. Barker   const CeedScalar *assembledqfarray;
1506*e2f04181SAndrew T. Barker   ierr = CeedVectorGetArrayRead(assembledqf, CEED_MEM_HOST, &assembledqfarray);
1507*e2f04181SAndrew T. Barker   CeedChk(ierr);
1508*e2f04181SAndrew T. Barker 
1509*e2f04181SAndrew T. Barker   CeedInt layout_qf[3];
1510*e2f04181SAndrew T. Barker   ierr = CeedElemRestrictionGetELayout(rstr_q, &layout_qf); CeedChk(ierr);
1511*e2f04181SAndrew T. Barker   ierr = CeedElemRestrictionDestroy(&rstr_q); CeedChk(ierr);
1512*e2f04181SAndrew T. Barker 
1513*e2f04181SAndrew T. Barker   // we store Bmat_in, Bmat_out, BTD, elem_mat in row-major order
1514*e2f04181SAndrew T. Barker   CeedScalar Bmat_in[(nqpts * numemodein) * elemsize];
1515*e2f04181SAndrew T. Barker   CeedScalar Bmat_out[(nqpts * numemodeout) * elemsize];
1516*e2f04181SAndrew T. Barker   CeedScalar Dmat[numemodeout * numemodein * nqpts]; // logically 3-tensor
1517*e2f04181SAndrew T. Barker   CeedScalar BTD[elemsize * nqpts*numemodein];
1518*e2f04181SAndrew T. Barker   CeedScalar elem_mat[elemsize * elemsize];
1519*e2f04181SAndrew T. Barker   int count = 0;
1520*e2f04181SAndrew T. Barker   CeedScalar *vals;
1521*e2f04181SAndrew T. Barker   ierr = CeedVectorGetArray(values, CEED_MEM_HOST, &vals); CeedChk(ierr);
1522*e2f04181SAndrew T. Barker   for (int e = 0; e < nelem; ++e) {
1523*e2f04181SAndrew T. Barker     for (int compin = 0; compin < ncomp; ++compin) {
1524*e2f04181SAndrew T. Barker       for (int compout = 0; compout < ncomp; ++compout) {
1525*e2f04181SAndrew T. Barker         for (int ell = 0; ell < (nqpts * numemodein) * elemsize; ++ell) {
1526*e2f04181SAndrew T. Barker           Bmat_in[ell] = 0.0;
1527*e2f04181SAndrew T. Barker         }
1528*e2f04181SAndrew T. Barker         for (int ell = 0; ell < (nqpts * numemodeout) * elemsize; ++ell) {
1529*e2f04181SAndrew T. Barker           Bmat_out[ell] = 0.0;
1530*e2f04181SAndrew T. Barker         }
1531*e2f04181SAndrew T. Barker         // Store block-diagonal D matrix as collection of small dense blocks
1532*e2f04181SAndrew T. Barker         for (int ell = 0; ell < numemodein*numemodeout*nqpts; ++ell) {
1533*e2f04181SAndrew T. Barker           Dmat[ell] = 0.0;
1534*e2f04181SAndrew T. Barker         }
1535*e2f04181SAndrew T. Barker         // form element matrix itself (for each block component)
1536*e2f04181SAndrew T. Barker         for (int ell = 0; ell < elemsize*elemsize; ++ell) {
1537*e2f04181SAndrew T. Barker           elem_mat[ell] = 0.0;
1538*e2f04181SAndrew T. Barker         }
1539*e2f04181SAndrew T. Barker         for (int q = 0; q < nqpts; ++q) {
1540*e2f04181SAndrew T. Barker           for (int n = 0; n < elemsize; ++n) {
1541*e2f04181SAndrew T. Barker             CeedInt din = -1;
1542*e2f04181SAndrew T. Barker             for (int ein = 0; ein < numemodein; ++ein) {
1543*e2f04181SAndrew T. Barker               const int qq = numemodein*q;
1544*e2f04181SAndrew T. Barker               if (emodein[ein] == CEED_EVAL_INTERP) {
1545*e2f04181SAndrew T. Barker                 Bmat_in[(qq+ein)*elemsize + n] += interpin[q * elemsize + n];
1546*e2f04181SAndrew T. Barker               } else if (emodein[ein] == CEED_EVAL_GRAD) {
1547*e2f04181SAndrew T. Barker                 din += 1;
1548*e2f04181SAndrew T. Barker                 Bmat_in[(qq+ein)*elemsize + n] +=
1549*e2f04181SAndrew T. Barker                   gradin[(din*nqpts+q) * elemsize + n];
1550*e2f04181SAndrew T. Barker               } else {
1551*e2f04181SAndrew T. Barker                 // LCOV_EXCL_START
1552*e2f04181SAndrew T. Barker                 return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Not implemented!");
1553*e2f04181SAndrew T. Barker                 // LCOV_EXCL_STOP
1554*e2f04181SAndrew T. Barker               }
1555*e2f04181SAndrew T. Barker             }
1556*e2f04181SAndrew T. Barker             CeedInt dout = -1;
1557*e2f04181SAndrew T. Barker             for (int eout = 0; eout < numemodeout; ++eout) {
1558*e2f04181SAndrew T. Barker               const int qq = numemodeout*q;
1559*e2f04181SAndrew T. Barker               if (emodeout[eout] == CEED_EVAL_INTERP) {
1560*e2f04181SAndrew T. Barker                 Bmat_out[(qq+eout)*elemsize + n] += interpin[q * elemsize + n];
1561*e2f04181SAndrew T. Barker               } else if (emodeout[eout] == CEED_EVAL_GRAD) {
1562*e2f04181SAndrew T. Barker                 dout += 1;
1563*e2f04181SAndrew T. Barker                 Bmat_out[(qq+eout)*elemsize + n] +=
1564*e2f04181SAndrew T. Barker                   gradin[(dout*nqpts+q) * elemsize + n];
1565*e2f04181SAndrew T. Barker               } else {
1566*e2f04181SAndrew T. Barker                 // LCOV_EXCL_START
1567*e2f04181SAndrew T. Barker                 return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Not implemented!");
1568*e2f04181SAndrew T. Barker                 // LCOV_EXCL_STOP
1569*e2f04181SAndrew T. Barker               }
1570*e2f04181SAndrew T. Barker             }
1571*e2f04181SAndrew T. Barker           }
1572*e2f04181SAndrew T. Barker           for (int ei = 0; ei < numemodeout; ++ei) {
1573*e2f04181SAndrew T. Barker             for (int ej = 0; ej < numemodein; ++ej) {
1574*e2f04181SAndrew T. Barker               const int emode_index = ((ei*ncomp+compin)*numemodein+ej)*ncomp+compout;
1575*e2f04181SAndrew T. Barker               const int index = q*layout_qf[0] + emode_index*layout_qf[1] + e*layout_qf[2];
1576*e2f04181SAndrew T. Barker               Dmat[(ei*numemodein+ej)*nqpts + q] += assembledqfarray[index];
1577*e2f04181SAndrew T. Barker             }
1578*e2f04181SAndrew T. Barker           }
1579*e2f04181SAndrew T. Barker         }
1580*e2f04181SAndrew T. Barker         // Compute B^T*D
1581*e2f04181SAndrew T. Barker         for (int ell = 0; ell < elemsize*nqpts*numemodein; ++ell) {
1582*e2f04181SAndrew T. Barker           BTD[ell] = 0.0;
1583*e2f04181SAndrew T. Barker         }
1584*e2f04181SAndrew T. Barker         for (int j = 0; j<elemsize; ++j) {
1585*e2f04181SAndrew T. Barker           for (int q = 0; q<nqpts; ++q) {
1586*e2f04181SAndrew T. Barker             int qq = numemodeout*q;
1587*e2f04181SAndrew T. Barker             for (int ei = 0; ei < numemodein; ++ei) {
1588*e2f04181SAndrew T. Barker               for (int ej = 0; ej < numemodeout; ++ej) {
1589*e2f04181SAndrew T. Barker                 BTD[j*(nqpts*numemodein) + (qq+ei)] +=
1590*e2f04181SAndrew T. Barker                   Bmat_out[(qq+ej)*elemsize + j] * Dmat[(ei*numemodein+ej)*nqpts + q];
1591*e2f04181SAndrew T. Barker               }
1592*e2f04181SAndrew T. Barker             }
1593*e2f04181SAndrew T. Barker           }
1594*e2f04181SAndrew T. Barker         }
1595*e2f04181SAndrew T. Barker 
1596*e2f04181SAndrew T. Barker         ierr = CeedMatrixMultiply(ceed, BTD, Bmat_in, elem_mat, elemsize,
1597*e2f04181SAndrew T. Barker                                   elemsize, nqpts*numemodein); CeedChk(ierr);
1598*e2f04181SAndrew T. Barker 
1599*e2f04181SAndrew T. Barker         // put element matrix in coordinate data structure
1600*e2f04181SAndrew T. Barker         for (int i = 0; i < elemsize; ++i) {
1601*e2f04181SAndrew T. Barker           for (int j = 0; j < elemsize; ++j) {
1602*e2f04181SAndrew T. Barker             vals[offset + count] = elem_mat[i*elemsize + j];
1603*e2f04181SAndrew T. Barker             count++;
1604*e2f04181SAndrew T. Barker           }
1605*e2f04181SAndrew T. Barker         }
1606*e2f04181SAndrew T. Barker       }
1607*e2f04181SAndrew T. Barker     }
1608*e2f04181SAndrew T. Barker   }
1609*e2f04181SAndrew T. Barker   if (count != local_nentries)
1610*e2f04181SAndrew T. Barker     // LCOV_EXCL_START
1611*e2f04181SAndrew T. Barker     return CeedError(ceed, CEED_ERROR_MAJOR, "Error computing entries");
1612*e2f04181SAndrew T. Barker   // LCOV_EXCL_STOP
1613*e2f04181SAndrew T. Barker   ierr = CeedVectorRestoreArray(values, &vals); CeedChk(ierr);
1614*e2f04181SAndrew T. Barker 
1615*e2f04181SAndrew T. Barker   ierr = CeedVectorRestoreArrayRead(assembledqf, &assembledqfarray);
1616*e2f04181SAndrew T. Barker   CeedChk(ierr);
1617*e2f04181SAndrew T. Barker   ierr = CeedVectorDestroy(&assembledqf); CeedChk(ierr);
1618*e2f04181SAndrew T. Barker   ierr = CeedFree(&emodein); CeedChk(ierr);
1619*e2f04181SAndrew T. Barker   ierr = CeedFree(&emodeout); CeedChk(ierr);
1620*e2f04181SAndrew T. Barker 
1621*e2f04181SAndrew T. Barker   return CEED_ERROR_SUCCESS;
1622*e2f04181SAndrew T. Barker }
1623*e2f04181SAndrew T. Barker 
1624*e2f04181SAndrew T. Barker /**
1625*e2f04181SAndrew T. Barker    @ref Utility
1626*e2f04181SAndrew T. Barker **/
1627*e2f04181SAndrew T. Barker int CeedSingleOperatorAssemblyCountEntries(CeedOperator op, CeedInt *nentries) {
1628*e2f04181SAndrew T. Barker   int ierr;
1629*e2f04181SAndrew T. Barker   CeedElemRestriction rstr;
1630*e2f04181SAndrew T. Barker   CeedInt nelem, elemsize, ncomp;
1631*e2f04181SAndrew T. Barker 
1632*e2f04181SAndrew T. Barker   if (op->composite)
1633*e2f04181SAndrew T. Barker     // LCOV_EXCL_START
1634*e2f04181SAndrew T. Barker     return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED,
1635*e2f04181SAndrew T. Barker                      "Composite operator not supported");
1636*e2f04181SAndrew T. Barker   // LCOV_EXCL_STOP
1637*e2f04181SAndrew T. Barker   ierr = CeedOperatorGetActiveElemRestriction(op, &rstr); CeedChk(ierr);
1638*e2f04181SAndrew T. Barker   ierr = CeedElemRestrictionGetNumElements(rstr, &nelem); CeedChk(ierr);
1639*e2f04181SAndrew T. Barker   ierr = CeedElemRestrictionGetElementSize(rstr, &elemsize); CeedChk(ierr);
1640*e2f04181SAndrew T. Barker   ierr = CeedElemRestrictionGetNumComponents(rstr, &ncomp); CeedChk(ierr);
1641*e2f04181SAndrew T. Barker   *nentries = elemsize*ncomp * elemsize*ncomp * nelem;
1642*e2f04181SAndrew T. Barker 
1643*e2f04181SAndrew T. Barker   return CEED_ERROR_SUCCESS;
1644*e2f04181SAndrew T. Barker }
1645*e2f04181SAndrew T. Barker 
1646*e2f04181SAndrew T. Barker /**
1647*e2f04181SAndrew T. Barker    @brief Fully assemble the nonzero pattern of a linear operator.
1648*e2f04181SAndrew T. Barker 
1649*e2f04181SAndrew T. Barker    Expected to be used in conjunction with CeedOperatorLinearAssemble()
1650*e2f04181SAndrew T. Barker 
1651*e2f04181SAndrew T. Barker    The assembly routines use coordinate format, with nentries tuples of the
1652*e2f04181SAndrew T. Barker    form (i, j, value) which indicate that value should be added to the matrix
1653*e2f04181SAndrew T. Barker    in entry (i, j). Note that the (i, j) pairs are not unique and may repeat.
1654*e2f04181SAndrew T. Barker    This function returns the number of entries and their (i, j) locations,
1655*e2f04181SAndrew T. Barker    while CeedOperatorLinearAssemble() provides the values in the same
1656*e2f04181SAndrew T. Barker    ordering.
1657*e2f04181SAndrew T. Barker 
1658*e2f04181SAndrew T. Barker    This will generally be slow unless your operator is low-order.
1659*e2f04181SAndrew T. Barker 
1660*e2f04181SAndrew T. Barker    @param[in]  op       CeedOperator to assemble
1661*e2f04181SAndrew T. Barker    @param[out] nentries Number of entries in coordinate nonzero pattern.
1662*e2f04181SAndrew T. Barker    @param[out] rows     Row number for each entry.
1663*e2f04181SAndrew T. Barker    @param[out] cols     Column number for each entry.
1664*e2f04181SAndrew T. Barker 
1665*e2f04181SAndrew T. Barker    @ref User
1666*e2f04181SAndrew T. Barker **/
1667*e2f04181SAndrew T. Barker int CeedOperatorLinearAssembleSymbolic(CeedOperator op,
1668*e2f04181SAndrew T. Barker                                        CeedInt *nentries, CeedInt **rows, CeedInt **cols) {
1669*e2f04181SAndrew T. Barker   int ierr;
1670*e2f04181SAndrew T. Barker   CeedInt numsub, single_entries;
1671*e2f04181SAndrew T. Barker   CeedOperator *suboperators;
1672*e2f04181SAndrew T. Barker   bool isComposite;
1673*e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
1674*e2f04181SAndrew T. Barker 
1675*e2f04181SAndrew T. Barker   // Use backend version, if available
1676*e2f04181SAndrew T. Barker   if (op->LinearAssembleSymbolic) {
1677*e2f04181SAndrew T. Barker     return op->LinearAssembleSymbolic(op, nentries, rows, cols);
1678*e2f04181SAndrew T. Barker   } else {
1679*e2f04181SAndrew T. Barker     // Check for valid fallback resource
1680*e2f04181SAndrew T. Barker     const char *resource, *fallbackresource;
1681*e2f04181SAndrew T. Barker     ierr = CeedGetResource(op->ceed, &resource); CeedChk(ierr);
1682*e2f04181SAndrew T. Barker     ierr = CeedGetOperatorFallbackResource(op->ceed, &fallbackresource);
1683*e2f04181SAndrew T. Barker     if (strcmp(fallbackresource, "") && strcmp(resource, fallbackresource)) {
1684*e2f04181SAndrew T. Barker       // Fallback to reference Ceed
1685*e2f04181SAndrew T. Barker       if (!op->opfallback) {
1686*e2f04181SAndrew T. Barker         ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
1687*e2f04181SAndrew T. Barker       }
1688*e2f04181SAndrew T. Barker       // Assemble
1689*e2f04181SAndrew T. Barker       return CeedOperatorLinearAssembleSymbolic(op->opfallback, nentries, rows, cols);
1690*e2f04181SAndrew T. Barker     }
1691*e2f04181SAndrew T. Barker   }
1692*e2f04181SAndrew T. Barker 
1693*e2f04181SAndrew T. Barker   // if neither backend nor fallback resource provides
1694*e2f04181SAndrew T. Barker   // LinearAssembleSymbolic, continue with interface-level implementation
1695*e2f04181SAndrew T. Barker 
1696*e2f04181SAndrew T. Barker   // count entries and allocate rows, cols arrays
1697*e2f04181SAndrew T. Barker   ierr = CeedOperatorIsComposite(op, &isComposite); CeedChk(ierr);
1698*e2f04181SAndrew T. Barker   *nentries = 0;
1699*e2f04181SAndrew T. Barker   if (isComposite) {
1700*e2f04181SAndrew T. Barker     ierr = CeedOperatorGetNumSub(op, &numsub); CeedChk(ierr);
1701*e2f04181SAndrew T. Barker     ierr = CeedOperatorGetSubList(op, &suboperators); CeedChk(ierr);
1702*e2f04181SAndrew T. Barker     for (int k = 0; k < numsub; ++k) {
1703*e2f04181SAndrew T. Barker       ierr = CeedSingleOperatorAssemblyCountEntries(suboperators[k],
1704*e2f04181SAndrew T. Barker              &single_entries); CeedChk(ierr);
1705*e2f04181SAndrew T. Barker       *nentries += single_entries;
1706*e2f04181SAndrew T. Barker     }
1707*e2f04181SAndrew T. Barker   } else {
1708*e2f04181SAndrew T. Barker     ierr = CeedSingleOperatorAssemblyCountEntries(op,
1709*e2f04181SAndrew T. Barker            &single_entries); CeedChk(ierr);
1710*e2f04181SAndrew T. Barker     *nentries += single_entries;
1711*e2f04181SAndrew T. Barker   }
1712*e2f04181SAndrew T. Barker   ierr = CeedCalloc(*nentries, rows); CeedChk(ierr);
1713*e2f04181SAndrew T. Barker   ierr = CeedCalloc(*nentries, cols); CeedChk(ierr);
1714*e2f04181SAndrew T. Barker 
1715*e2f04181SAndrew T. Barker   // assemble nonzero locations
1716*e2f04181SAndrew T. Barker   CeedInt offset = 0;
1717*e2f04181SAndrew T. Barker   if (isComposite) {
1718*e2f04181SAndrew T. Barker     ierr = CeedOperatorGetNumSub(op, &numsub); CeedChk(ierr);
1719*e2f04181SAndrew T. Barker     ierr = CeedOperatorGetSubList(op, &suboperators); CeedChk(ierr);
1720*e2f04181SAndrew T. Barker     for (int k = 0; k < numsub; ++k) {
1721*e2f04181SAndrew T. Barker       ierr = CeedSingleOperatorAssembleSymbolic(suboperators[k], offset, *rows,
1722*e2f04181SAndrew T. Barker              *cols); CeedChk(ierr);
1723*e2f04181SAndrew T. Barker       ierr = CeedSingleOperatorAssemblyCountEntries(suboperators[k], &single_entries);
1724*e2f04181SAndrew T. Barker       CeedChk(ierr);
1725*e2f04181SAndrew T. Barker       offset += single_entries;
1726*e2f04181SAndrew T. Barker     }
1727*e2f04181SAndrew T. Barker   } else {
1728*e2f04181SAndrew T. Barker     ierr = CeedSingleOperatorAssembleSymbolic(op, offset, *rows, *cols);
1729*e2f04181SAndrew T. Barker     CeedChk(ierr);
1730*e2f04181SAndrew T. Barker   }
1731*e2f04181SAndrew T. Barker 
1732*e2f04181SAndrew T. Barker   return CEED_ERROR_SUCCESS;
1733*e2f04181SAndrew T. Barker }
1734*e2f04181SAndrew T. Barker 
1735*e2f04181SAndrew T. Barker /**
1736*e2f04181SAndrew T. Barker    @brief Fully assemble the nonzero entries of a linear operator.
1737*e2f04181SAndrew T. Barker 
1738*e2f04181SAndrew T. Barker    Expected to be used in conjunction with CeedOperatorLinearAssembleSymbolic()
1739*e2f04181SAndrew T. Barker 
1740*e2f04181SAndrew T. Barker    The assembly routines use coordinate format, with nentries tuples of the
1741*e2f04181SAndrew T. Barker    form (i, j, value) which indicate that value should be added to the matrix
1742*e2f04181SAndrew T. Barker    in entry (i, j). Note that the (i, j) pairs are not unique and may repeat.
1743*e2f04181SAndrew T. Barker    This function returns the values of the nonzero entries to be added, their
1744*e2f04181SAndrew T. Barker    (i, j) locations are provided by CeedOperatorLinearAssembleSymbolic()
1745*e2f04181SAndrew T. Barker 
1746*e2f04181SAndrew T. Barker    This will generally be slow unless your operator is low-order.
1747*e2f04181SAndrew T. Barker 
1748*e2f04181SAndrew T. Barker    @param[in]  op       CeedOperator to assemble
1749*e2f04181SAndrew T. Barker    @param[out] values   Values to assemble into matrix
1750*e2f04181SAndrew T. Barker 
1751*e2f04181SAndrew T. Barker    @ref User
1752*e2f04181SAndrew T. Barker **/
1753*e2f04181SAndrew T. Barker int CeedOperatorLinearAssemble(CeedOperator op, CeedVector values) {
1754*e2f04181SAndrew T. Barker   int ierr;
1755*e2f04181SAndrew T. Barker   CeedInt numsub, single_entries;
1756*e2f04181SAndrew T. Barker   CeedOperator *suboperators;
1757*e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
1758*e2f04181SAndrew T. Barker 
1759*e2f04181SAndrew T. Barker   // Use backend version, if available
1760*e2f04181SAndrew T. Barker   if (op->LinearAssemble) {
1761*e2f04181SAndrew T. Barker     return op->LinearAssemble(op, values);
1762*e2f04181SAndrew T. Barker   } else {
1763*e2f04181SAndrew T. Barker     // Check for valid fallback resource
1764*e2f04181SAndrew T. Barker     const char *resource, *fallbackresource;
1765*e2f04181SAndrew T. Barker     ierr = CeedGetResource(op->ceed, &resource); CeedChk(ierr);
1766*e2f04181SAndrew T. Barker     ierr = CeedGetOperatorFallbackResource(op->ceed, &fallbackresource);
1767*e2f04181SAndrew T. Barker     if (strcmp(fallbackresource, "") && strcmp(resource, fallbackresource)) {
1768*e2f04181SAndrew T. Barker       // Fallback to reference Ceed
1769*e2f04181SAndrew T. Barker       if (!op->opfallback) {
1770*e2f04181SAndrew T. Barker         ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
1771*e2f04181SAndrew T. Barker       }
1772*e2f04181SAndrew T. Barker       // Assemble
1773*e2f04181SAndrew T. Barker       return CeedOperatorLinearAssemble(op->opfallback, values);
1774*e2f04181SAndrew T. Barker     }
1775*e2f04181SAndrew T. Barker   }
1776*e2f04181SAndrew T. Barker 
1777*e2f04181SAndrew T. Barker   // if neither backend nor fallback resource provides
1778*e2f04181SAndrew T. Barker   // LinearAssemble, continue with interface-level implementation
1779*e2f04181SAndrew T. Barker 
1780*e2f04181SAndrew T. Barker   bool isComposite;
1781*e2f04181SAndrew T. Barker   ierr = CeedOperatorIsComposite(op, &isComposite); CeedChk(ierr);
1782*e2f04181SAndrew T. Barker 
1783*e2f04181SAndrew T. Barker   CeedInt offset = 0;
1784*e2f04181SAndrew T. Barker   if (isComposite) {
1785*e2f04181SAndrew T. Barker     ierr = CeedOperatorGetNumSub(op, &numsub); CeedChk(ierr);
1786*e2f04181SAndrew T. Barker     ierr = CeedOperatorGetSubList(op, &suboperators); CeedChk(ierr);
1787*e2f04181SAndrew T. Barker     for (int k = 0; k < numsub; ++k) {
1788*e2f04181SAndrew T. Barker       ierr = CeedSingleOperatorAssemble(suboperators[k], offset, values);
1789*e2f04181SAndrew T. Barker       CeedChk(ierr);
1790*e2f04181SAndrew T. Barker       ierr = CeedSingleOperatorAssemblyCountEntries(suboperators[k], &single_entries);
1791*e2f04181SAndrew T. Barker       CeedChk(ierr);
1792*e2f04181SAndrew T. Barker       offset += single_entries;
1793*e2f04181SAndrew T. Barker     }
1794*e2f04181SAndrew T. Barker   } else {
1795*e2f04181SAndrew T. Barker     ierr = CeedSingleOperatorAssemble(op, offset, values); CeedChk(ierr);
1796*e2f04181SAndrew T. Barker   }
1797*e2f04181SAndrew T. Barker 
1798e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1799d965c7a7SJeremy L Thompson }
1800d965c7a7SJeremy L Thompson 
1801d965c7a7SJeremy L Thompson /**
1802d99fa3c5SJeremy L Thompson   @brief Create a multigrid coarse operator and level transfer operators
1803d99fa3c5SJeremy L Thompson            for a CeedOperator, creating the prolongation basis from the
1804d99fa3c5SJeremy L Thompson            fine and coarse grid interpolation
1805d99fa3c5SJeremy L Thompson 
1806d99fa3c5SJeremy L Thompson   @param[in] opFine       Fine grid operator
1807d99fa3c5SJeremy L Thompson   @param[in] PMultFine    L-vector multiplicity in parallel gather/scatter
1808d99fa3c5SJeremy L Thompson   @param[in] rstrCoarse   Coarse grid restriction
1809d99fa3c5SJeremy L Thompson   @param[in] basisCoarse  Coarse grid active vector basis
1810d99fa3c5SJeremy L Thompson   @param[out] opCoarse    Coarse grid operator
1811d99fa3c5SJeremy L Thompson   @param[out] opProlong   Coarse to fine operator
1812d99fa3c5SJeremy L Thompson   @param[out] opRestrict  Fine to coarse operator
1813d99fa3c5SJeremy L Thompson 
1814d99fa3c5SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1815d99fa3c5SJeremy L Thompson 
1816d99fa3c5SJeremy L Thompson   @ref User
1817d99fa3c5SJeremy L Thompson **/
1818d99fa3c5SJeremy L Thompson int CeedOperatorMultigridLevelCreate(CeedOperator opFine, CeedVector PMultFine,
1819d99fa3c5SJeremy L Thompson                                      CeedElemRestriction rstrCoarse, CeedBasis basisCoarse,
1820d99fa3c5SJeremy L Thompson                                      CeedOperator *opCoarse, CeedOperator *opProlong, CeedOperator *opRestrict) {
1821d99fa3c5SJeremy L Thompson   int ierr;
1822d99fa3c5SJeremy L Thompson   Ceed ceed;
1823d99fa3c5SJeremy L Thompson   ierr = CeedOperatorGetCeed(opFine, &ceed); CeedChk(ierr);
1824d99fa3c5SJeremy L Thompson 
1825d99fa3c5SJeremy L Thompson   // Check for compatible quadrature spaces
1826d99fa3c5SJeremy L Thompson   CeedBasis basisFine;
1827d99fa3c5SJeremy L Thompson   ierr = CeedOperatorGetActiveBasis(opFine, &basisFine); CeedChk(ierr);
1828d99fa3c5SJeremy L Thompson   CeedInt Qf, Qc;
1829d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumQuadraturePoints(basisFine, &Qf); CeedChk(ierr);
1830d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumQuadraturePoints(basisCoarse, &Qc); CeedChk(ierr);
1831d99fa3c5SJeremy L Thompson   if (Qf != Qc)
1832d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
1833e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_DIMENSION,
1834e15f9bd0SJeremy L Thompson                      "Bases must have compatible quadrature spaces");
1835d99fa3c5SJeremy L Thompson   // LCOV_EXCL_STOP
1836d99fa3c5SJeremy L Thompson 
1837d99fa3c5SJeremy L Thompson   // Coarse to fine basis
1838d99fa3c5SJeremy L Thompson   CeedInt Pf, Pc, Q = Qf;
1839d99fa3c5SJeremy L Thompson   bool isTensorF, isTensorC;
1840d99fa3c5SJeremy L Thompson   ierr = CeedBasisIsTensor(basisFine, &isTensorF); CeedChk(ierr);
1841d99fa3c5SJeremy L Thompson   ierr = CeedBasisIsTensor(basisCoarse, &isTensorC); CeedChk(ierr);
1842d99fa3c5SJeremy L Thompson   CeedScalar *interpC, *interpF, *interpCtoF, *tau;
1843d99fa3c5SJeremy L Thompson   if (isTensorF && isTensorC) {
1844d99fa3c5SJeremy L Thompson     ierr = CeedBasisGetNumNodes1D(basisFine, &Pf); CeedChk(ierr);
1845d99fa3c5SJeremy L Thompson     ierr = CeedBasisGetNumNodes1D(basisCoarse, &Pc); CeedChk(ierr);
1846d99fa3c5SJeremy L Thompson     ierr = CeedBasisGetNumQuadraturePoints1D(basisCoarse, &Q); CeedChk(ierr);
1847d99fa3c5SJeremy L Thompson   } else if (!isTensorF && !isTensorC) {
1848d99fa3c5SJeremy L Thompson     ierr = CeedBasisGetNumNodes(basisFine, &Pf); CeedChk(ierr);
1849d99fa3c5SJeremy L Thompson     ierr = CeedBasisGetNumNodes(basisCoarse, &Pc); CeedChk(ierr);
1850d99fa3c5SJeremy L Thompson   } else {
1851d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
1852e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_MINOR,
1853e15f9bd0SJeremy L Thompson                      "Bases must both be tensor or non-tensor");
1854d99fa3c5SJeremy L Thompson     // LCOV_EXCL_STOP
1855d99fa3c5SJeremy L Thompson   }
1856d99fa3c5SJeremy L Thompson 
1857d99fa3c5SJeremy L Thompson   ierr = CeedMalloc(Q*Pf, &interpF); CeedChk(ierr);
1858d99fa3c5SJeremy L Thompson   ierr = CeedMalloc(Q*Pc, &interpC); CeedChk(ierr);
1859d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(Pc*Pf, &interpCtoF); CeedChk(ierr);
1860d99fa3c5SJeremy L Thompson   ierr = CeedMalloc(Q, &tau); CeedChk(ierr);
1861d99fa3c5SJeremy L Thompson   if (isTensorF) {
1862d99fa3c5SJeremy L Thompson     memcpy(interpF, basisFine->interp1d, Q*Pf*sizeof basisFine->interp1d[0]);
1863d99fa3c5SJeremy L Thompson     memcpy(interpC, basisCoarse->interp1d, Q*Pc*sizeof basisCoarse->interp1d[0]);
1864d99fa3c5SJeremy L Thompson   } else {
1865d99fa3c5SJeremy L Thompson     memcpy(interpF, basisFine->interp, Q*Pf*sizeof basisFine->interp[0]);
1866d99fa3c5SJeremy L Thompson     memcpy(interpC, basisCoarse->interp, Q*Pc*sizeof basisCoarse->interp[0]);
1867d99fa3c5SJeremy L Thompson   }
1868d99fa3c5SJeremy L Thompson 
1869d99fa3c5SJeremy L Thompson   // -- QR Factorization, interpF = Q R
1870d99fa3c5SJeremy L Thompson   ierr = CeedQRFactorization(ceed, interpF, tau, Q, Pf); CeedChk(ierr);
1871d99fa3c5SJeremy L Thompson 
1872d99fa3c5SJeremy L Thompson   // -- Apply Qtranspose, interpC = Qtranspose interpC
1873d99fa3c5SJeremy L Thompson   CeedHouseholderApplyQ(interpC, interpF, tau, CEED_TRANSPOSE,
1874d99fa3c5SJeremy L Thompson                         Q, Pc, Pf, Pc, 1);
1875d99fa3c5SJeremy L Thompson 
1876d99fa3c5SJeremy L Thompson   // -- Apply Rinv, interpCtoF = Rinv interpC
1877d99fa3c5SJeremy L Thompson   for (CeedInt j=0; j<Pc; j++) { // Column j
1878d99fa3c5SJeremy L Thompson     interpCtoF[j+Pc*(Pf-1)] = interpC[j+Pc*(Pf-1)]/interpF[Pf*Pf-1];
1879d99fa3c5SJeremy L Thompson     for (CeedInt i=Pf-2; i>=0; i--) { // Row i
1880d99fa3c5SJeremy L Thompson       interpCtoF[j+Pc*i] = interpC[j+Pc*i];
1881d99fa3c5SJeremy L Thompson       for (CeedInt k=i+1; k<Pf; k++)
1882d99fa3c5SJeremy L Thompson         interpCtoF[j+Pc*i] -= interpF[k+Pf*i]*interpCtoF[j+Pc*k];
1883d99fa3c5SJeremy L Thompson       interpCtoF[j+Pc*i] /= interpF[i+Pf*i];
1884d99fa3c5SJeremy L Thompson     }
1885d99fa3c5SJeremy L Thompson   }
1886d99fa3c5SJeremy L Thompson   ierr = CeedFree(&tau); CeedChk(ierr);
1887d99fa3c5SJeremy L Thompson   ierr = CeedFree(&interpC); CeedChk(ierr);
1888d99fa3c5SJeremy L Thompson   ierr = CeedFree(&interpF); CeedChk(ierr);
1889d99fa3c5SJeremy L Thompson 
1890e15f9bd0SJeremy L Thompson   // Complete with interpCtoF versions of code
1891d99fa3c5SJeremy L Thompson   if (isTensorF) {
1892d99fa3c5SJeremy L Thompson     ierr = CeedOperatorMultigridLevelCreateTensorH1(opFine, PMultFine,
1893d99fa3c5SJeremy L Thompson            rstrCoarse, basisCoarse, interpCtoF, opCoarse, opProlong, opRestrict);
1894d99fa3c5SJeremy L Thompson     CeedChk(ierr);
1895d99fa3c5SJeremy L Thompson   } else {
1896d99fa3c5SJeremy L Thompson     ierr = CeedOperatorMultigridLevelCreateH1(opFine, PMultFine,
1897d99fa3c5SJeremy L Thompson            rstrCoarse, basisCoarse, interpCtoF, opCoarse, opProlong, opRestrict);
1898d99fa3c5SJeremy L Thompson     CeedChk(ierr);
1899d99fa3c5SJeremy L Thompson   }
1900d99fa3c5SJeremy L Thompson 
1901d99fa3c5SJeremy L Thompson   // Cleanup
1902d99fa3c5SJeremy L Thompson   ierr = CeedFree(&interpCtoF); CeedChk(ierr);
1903e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1904d99fa3c5SJeremy L Thompson }
1905d99fa3c5SJeremy L Thompson 
1906d99fa3c5SJeremy L Thompson /**
1907d99fa3c5SJeremy L Thompson   @brief Create a multigrid coarse operator and level transfer operators
1908d99fa3c5SJeremy L Thompson            for a CeedOperator with a tensor basis for the active basis
1909d99fa3c5SJeremy L Thompson 
1910d99fa3c5SJeremy L Thompson   @param[in] opFine       Fine grid operator
1911d99fa3c5SJeremy L Thompson   @param[in] PMultFine    L-vector multiplicity in parallel gather/scatter
1912d99fa3c5SJeremy L Thompson   @param[in] rstrCoarse   Coarse grid restriction
1913d99fa3c5SJeremy L Thompson   @param[in] basisCoarse  Coarse grid active vector basis
1914d99fa3c5SJeremy L Thompson   @param[in] interpCtoF   Matrix for coarse to fine interpolation
1915d99fa3c5SJeremy L Thompson   @param[out] opCoarse    Coarse grid operator
1916d99fa3c5SJeremy L Thompson   @param[out] opProlong   Coarse to fine operator
1917d99fa3c5SJeremy L Thompson   @param[out] opRestrict  Fine to coarse operator
1918d99fa3c5SJeremy L Thompson 
1919d99fa3c5SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1920d99fa3c5SJeremy L Thompson 
1921d99fa3c5SJeremy L Thompson   @ref User
1922d99fa3c5SJeremy L Thompson **/
1923d99fa3c5SJeremy L Thompson int CeedOperatorMultigridLevelCreateTensorH1(CeedOperator opFine,
1924d99fa3c5SJeremy L Thompson     CeedVector PMultFine, CeedElemRestriction rstrCoarse, CeedBasis basisCoarse,
1925d99fa3c5SJeremy L Thompson     const CeedScalar *interpCtoF, CeedOperator *opCoarse,
1926d99fa3c5SJeremy L Thompson     CeedOperator *opProlong, CeedOperator *opRestrict) {
1927d99fa3c5SJeremy L Thompson   int ierr;
1928d99fa3c5SJeremy L Thompson   Ceed ceed;
1929d99fa3c5SJeremy L Thompson   ierr = CeedOperatorGetCeed(opFine, &ceed); CeedChk(ierr);
1930d99fa3c5SJeremy L Thompson 
1931d99fa3c5SJeremy L Thompson   // Check for compatible quadrature spaces
1932d99fa3c5SJeremy L Thompson   CeedBasis basisFine;
1933d99fa3c5SJeremy L Thompson   ierr = CeedOperatorGetActiveBasis(opFine, &basisFine); CeedChk(ierr);
1934d99fa3c5SJeremy L Thompson   CeedInt Qf, Qc;
1935d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumQuadraturePoints(basisFine, &Qf); CeedChk(ierr);
1936d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumQuadraturePoints(basisCoarse, &Qc); CeedChk(ierr);
1937d99fa3c5SJeremy L Thompson   if (Qf != Qc)
1938d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
1939e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_DIMENSION,
1940e15f9bd0SJeremy L Thompson                      "Bases must have compatible quadrature spaces");
1941d99fa3c5SJeremy L Thompson   // LCOV_EXCL_STOP
1942d99fa3c5SJeremy L Thompson 
1943d99fa3c5SJeremy L Thompson   // Coarse to fine basis
1944d99fa3c5SJeremy L Thompson   CeedInt dim, ncomp, nnodesCoarse, P1dFine, P1dCoarse;
1945d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetDimension(basisFine, &dim); CeedChk(ierr);
1946d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumComponents(basisFine, &ncomp); CeedChk(ierr);
1947d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumNodes1D(basisFine, &P1dFine); CeedChk(ierr);
1948d99fa3c5SJeremy L Thompson   ierr = CeedElemRestrictionGetElementSize(rstrCoarse, &nnodesCoarse);
1949d99fa3c5SJeremy L Thompson   CeedChk(ierr);
1950d99fa3c5SJeremy L Thompson   P1dCoarse = dim == 1 ? nnodesCoarse :
1951d99fa3c5SJeremy L Thompson               dim == 2 ? sqrt(nnodesCoarse) :
1952d99fa3c5SJeremy L Thompson               cbrt(nnodesCoarse);
1953d99fa3c5SJeremy L Thompson   CeedScalar *qref, *qweight, *grad;
1954d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(P1dFine, &qref); CeedChk(ierr);
1955d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(P1dFine, &qweight); CeedChk(ierr);
1956d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(P1dFine*P1dCoarse*dim, &grad); CeedChk(ierr);
1957d99fa3c5SJeremy L Thompson   CeedBasis basisCtoF;
1958d99fa3c5SJeremy L Thompson   ierr = CeedBasisCreateTensorH1(ceed, dim, ncomp, P1dCoarse, P1dFine,
1959d99fa3c5SJeremy L Thompson                                  interpCtoF, grad, qref, qweight, &basisCtoF);
1960d99fa3c5SJeremy L Thompson   CeedChk(ierr);
1961d99fa3c5SJeremy L Thompson   ierr = CeedFree(&qref); CeedChk(ierr);
1962d99fa3c5SJeremy L Thompson   ierr = CeedFree(&qweight); CeedChk(ierr);
1963d99fa3c5SJeremy L Thompson   ierr = CeedFree(&grad); CeedChk(ierr);
1964d99fa3c5SJeremy L Thompson 
1965d99fa3c5SJeremy L Thompson   // Core code
1966d99fa3c5SJeremy L Thompson   ierr = CeedOperatorMultigridLevel_Core(opFine, PMultFine, rstrCoarse,
1967d99fa3c5SJeremy L Thompson                                          basisCoarse, basisCtoF, opCoarse,
1968d99fa3c5SJeremy L Thompson                                          opProlong, opRestrict);
1969d99fa3c5SJeremy L Thompson   CeedChk(ierr);
1970e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1971d99fa3c5SJeremy L Thompson }
1972d99fa3c5SJeremy L Thompson 
1973d99fa3c5SJeremy L Thompson /**
1974d99fa3c5SJeremy L Thompson   @brief Create a multigrid coarse operator and level transfer operators
1975d99fa3c5SJeremy L Thompson            for a CeedOperator with a non-tensor basis for the active vector
1976d99fa3c5SJeremy L Thompson 
1977d99fa3c5SJeremy L Thompson   @param[in] opFine       Fine grid operator
1978d99fa3c5SJeremy L Thompson   @param[in] PMultFine    L-vector multiplicity in parallel gather/scatter
1979d99fa3c5SJeremy L Thompson   @param[in] rstrCoarse   Coarse grid restriction
1980d99fa3c5SJeremy L Thompson   @param[in] basisCoarse  Coarse grid active vector basis
1981d99fa3c5SJeremy L Thompson   @param[in] interpCtoF   Matrix for coarse to fine interpolation
1982d99fa3c5SJeremy L Thompson   @param[out] opCoarse    Coarse grid operator
1983d99fa3c5SJeremy L Thompson   @param[out] opProlong   Coarse to fine operator
1984d99fa3c5SJeremy L Thompson   @param[out] opRestrict  Fine to coarse operator
1985d99fa3c5SJeremy L Thompson 
1986d99fa3c5SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1987d99fa3c5SJeremy L Thompson 
1988d99fa3c5SJeremy L Thompson   @ref User
1989d99fa3c5SJeremy L Thompson **/
1990d99fa3c5SJeremy L Thompson int CeedOperatorMultigridLevelCreateH1(CeedOperator opFine,
1991d99fa3c5SJeremy L Thompson                                        CeedVector PMultFine,
1992d99fa3c5SJeremy L Thompson                                        CeedElemRestriction rstrCoarse,
1993d99fa3c5SJeremy L Thompson                                        CeedBasis basisCoarse,
1994d99fa3c5SJeremy L Thompson                                        const CeedScalar *interpCtoF,
1995d99fa3c5SJeremy L Thompson                                        CeedOperator *opCoarse,
1996d99fa3c5SJeremy L Thompson                                        CeedOperator *opProlong,
1997d99fa3c5SJeremy L Thompson                                        CeedOperator *opRestrict) {
1998d99fa3c5SJeremy L Thompson   int ierr;
1999d99fa3c5SJeremy L Thompson   Ceed ceed;
2000d99fa3c5SJeremy L Thompson   ierr = CeedOperatorGetCeed(opFine, &ceed); CeedChk(ierr);
2001d99fa3c5SJeremy L Thompson 
2002d99fa3c5SJeremy L Thompson   // Check for compatible quadrature spaces
2003d99fa3c5SJeremy L Thompson   CeedBasis basisFine;
2004d99fa3c5SJeremy L Thompson   ierr = CeedOperatorGetActiveBasis(opFine, &basisFine); CeedChk(ierr);
2005d99fa3c5SJeremy L Thompson   CeedInt Qf, Qc;
2006d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumQuadraturePoints(basisFine, &Qf); CeedChk(ierr);
2007d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumQuadraturePoints(basisCoarse, &Qc); CeedChk(ierr);
2008d99fa3c5SJeremy L Thompson   if (Qf != Qc)
2009d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
2010e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_DIMENSION,
2011e15f9bd0SJeremy L Thompson                      "Bases must have compatible quadrature spaces");
2012d99fa3c5SJeremy L Thompson   // LCOV_EXCL_STOP
2013d99fa3c5SJeremy L Thompson 
2014d99fa3c5SJeremy L Thompson   // Coarse to fine basis
2015d99fa3c5SJeremy L Thompson   CeedElemTopology topo;
2016d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetTopology(basisFine, &topo); CeedChk(ierr);
2017d99fa3c5SJeremy L Thompson   CeedInt dim, ncomp, nnodesCoarse, nnodesFine;
2018d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetDimension(basisFine, &dim); CeedChk(ierr);
2019d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumComponents(basisFine, &ncomp); CeedChk(ierr);
2020d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumNodes(basisFine, &nnodesFine); CeedChk(ierr);
2021d99fa3c5SJeremy L Thompson   ierr = CeedElemRestrictionGetElementSize(rstrCoarse, &nnodesCoarse);
2022d99fa3c5SJeremy L Thompson   CeedChk(ierr);
2023d99fa3c5SJeremy L Thompson   CeedScalar *qref, *qweight, *grad;
2024d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(nnodesFine, &qref); CeedChk(ierr);
2025d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(nnodesFine, &qweight); CeedChk(ierr);
2026d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(nnodesFine*nnodesCoarse*dim, &grad); CeedChk(ierr);
2027d99fa3c5SJeremy L Thompson   CeedBasis basisCtoF;
2028d99fa3c5SJeremy L Thompson   ierr = CeedBasisCreateH1(ceed, topo, ncomp, nnodesCoarse, nnodesFine,
2029d99fa3c5SJeremy L Thompson                            interpCtoF, grad, qref, qweight, &basisCtoF);
2030d99fa3c5SJeremy L Thompson   CeedChk(ierr);
2031d99fa3c5SJeremy L Thompson   ierr = CeedFree(&qref); CeedChk(ierr);
2032d99fa3c5SJeremy L Thompson   ierr = CeedFree(&qweight); CeedChk(ierr);
2033d99fa3c5SJeremy L Thompson   ierr = CeedFree(&grad); CeedChk(ierr);
2034d99fa3c5SJeremy L Thompson 
2035d99fa3c5SJeremy L Thompson   // Core code
2036d99fa3c5SJeremy L Thompson   ierr = CeedOperatorMultigridLevel_Core(opFine, PMultFine, rstrCoarse,
2037d99fa3c5SJeremy L Thompson                                          basisCoarse, basisCtoF, opCoarse,
2038d99fa3c5SJeremy L Thompson                                          opProlong, opRestrict);
2039d99fa3c5SJeremy L Thompson   CeedChk(ierr);
2040e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2041d99fa3c5SJeremy L Thompson }
2042d99fa3c5SJeremy L Thompson 
2043d99fa3c5SJeremy L Thompson /**
20443bd813ffSjeremylt   @brief Build a FDM based approximate inverse for each element for a
20453bd813ffSjeremylt            CeedOperator
20463bd813ffSjeremylt 
20473bd813ffSjeremylt   This returns a CeedOperator and CeedVector to apply a Fast Diagonalization
20483bd813ffSjeremylt     Method based approximate inverse. This function obtains the simultaneous
20493bd813ffSjeremylt     diagonalization for the 1D mass and Laplacian operators,
20503bd813ffSjeremylt       M = V^T V, K = V^T S V.
20513bd813ffSjeremylt     The assembled QFunction is used to modify the eigenvalues from simultaneous
20523bd813ffSjeremylt     diagonalization and obtain an approximate inverse of the form
20533bd813ffSjeremylt       V^T S^hat V. The CeedOperator must be linear and non-composite. The
20543bd813ffSjeremylt     associated CeedQFunction must therefore also be linear.
20553bd813ffSjeremylt 
20563bd813ffSjeremylt   @param op             CeedOperator to create element inverses
20573bd813ffSjeremylt   @param[out] fdminv    CeedOperator to apply the action of a FDM based inverse
20583bd813ffSjeremylt                           for each element
20593bd813ffSjeremylt   @param request        Address of CeedRequest for non-blocking completion, else
20604cc79fe7SJed Brown                           @ref CEED_REQUEST_IMMEDIATE
20613bd813ffSjeremylt 
20623bd813ffSjeremylt   @return An error code: 0 - success, otherwise - failure
20633bd813ffSjeremylt 
20647a982d89SJeremy L. Thompson   @ref Backend
20653bd813ffSjeremylt **/
20663bd813ffSjeremylt int CeedOperatorCreateFDMElementInverse(CeedOperator op, CeedOperator *fdminv,
20673bd813ffSjeremylt                                         CeedRequest *request) {
20683bd813ffSjeremylt   int ierr;
2069*e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
20703bd813ffSjeremylt 
2071713f43c3Sjeremylt   // Use backend version, if available
2072713f43c3Sjeremylt   if (op->CreateFDMElementInverse) {
2073713f43c3Sjeremylt     ierr = op->CreateFDMElementInverse(op, fdminv, request); CeedChk(ierr);
2074713f43c3Sjeremylt   } else {
2075713f43c3Sjeremylt     // Fallback to reference Ceed
2076713f43c3Sjeremylt     if (!op->opfallback) {
2077713f43c3Sjeremylt       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
20783bd813ffSjeremylt     }
2079713f43c3Sjeremylt     // Assemble
2080713f43c3Sjeremylt     ierr = op->opfallback->CreateFDMElementInverse(op->opfallback, fdminv,
20813bd813ffSjeremylt            request); CeedChk(ierr);
20823bd813ffSjeremylt   }
2083e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
20843bd813ffSjeremylt }
20853bd813ffSjeremylt 
20867a982d89SJeremy L. Thompson /**
20877a982d89SJeremy L. Thompson   @brief View a CeedOperator
20887a982d89SJeremy L. Thompson 
20897a982d89SJeremy L. Thompson   @param[in] op     CeedOperator to view
20907a982d89SJeremy L. Thompson   @param[in] stream Stream to write; typically stdout/stderr or a file
20917a982d89SJeremy L. Thompson 
20927a982d89SJeremy L. Thompson   @return Error code: 0 - success, otherwise - failure
20937a982d89SJeremy L. Thompson 
20947a982d89SJeremy L. Thompson   @ref User
20957a982d89SJeremy L. Thompson **/
20967a982d89SJeremy L. Thompson int CeedOperatorView(CeedOperator op, FILE *stream) {
20977a982d89SJeremy L. Thompson   int ierr;
20987a982d89SJeremy L. Thompson 
20997a982d89SJeremy L. Thompson   if (op->composite) {
21007a982d89SJeremy L. Thompson     fprintf(stream, "Composite CeedOperator\n");
21017a982d89SJeremy L. Thompson 
21027a982d89SJeremy L. Thompson     for (CeedInt i=0; i<op->numsub; i++) {
21037a982d89SJeremy L. Thompson       fprintf(stream, "  SubOperator [%d]:\n", i);
21047a982d89SJeremy L. Thompson       ierr = CeedOperatorSingleView(op->suboperators[i], 1, stream);
21057a982d89SJeremy L. Thompson       CeedChk(ierr);
21067a982d89SJeremy L. Thompson     }
21077a982d89SJeremy L. Thompson   } else {
21087a982d89SJeremy L. Thompson     fprintf(stream, "CeedOperator\n");
21097a982d89SJeremy L. Thompson     ierr = CeedOperatorSingleView(op, 0, stream); CeedChk(ierr);
21107a982d89SJeremy L. Thompson   }
2111e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
21127a982d89SJeremy L. Thompson }
21133bd813ffSjeremylt 
21143bd813ffSjeremylt /**
21153bd813ffSjeremylt   @brief Apply CeedOperator to a vector
2116d7b241e6Sjeremylt 
2117d7b241e6Sjeremylt   This computes the action of the operator on the specified (active) input,
2118d7b241e6Sjeremylt   yielding its (active) output.  All inputs and outputs must be specified using
2119d7b241e6Sjeremylt   CeedOperatorSetField().
2120d7b241e6Sjeremylt 
2121d7b241e6Sjeremylt   @param op        CeedOperator to apply
21224cc79fe7SJed Brown   @param[in] in    CeedVector containing input state or @ref CEED_VECTOR_NONE if
212334138859Sjeremylt                   there are no active inputs
2124b11c1e72Sjeremylt   @param[out] out  CeedVector to store result of applying operator (must be
21254cc79fe7SJed Brown                      distinct from @a in) or @ref CEED_VECTOR_NONE if there are no
212634138859Sjeremylt                      active outputs
2127d7b241e6Sjeremylt   @param request   Address of CeedRequest for non-blocking completion, else
21284cc79fe7SJed Brown                      @ref CEED_REQUEST_IMMEDIATE
2129b11c1e72Sjeremylt 
2130b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
2131dfdf5a53Sjeremylt 
21327a982d89SJeremy L. Thompson   @ref User
2133b11c1e72Sjeremylt **/
2134692c2638Sjeremylt int CeedOperatorApply(CeedOperator op, CeedVector in, CeedVector out,
2135692c2638Sjeremylt                       CeedRequest *request) {
2136d7b241e6Sjeremylt   int ierr;
2137*e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
2138d7b241e6Sjeremylt 
2139250756a7Sjeremylt   if (op->numelements)  {
2140250756a7Sjeremylt     // Standard Operator
2141cae8b89aSjeremylt     if (op->Apply) {
2142250756a7Sjeremylt       ierr = op->Apply(op, in, out, request); CeedChk(ierr);
2143cae8b89aSjeremylt     } else {
2144cae8b89aSjeremylt       // Zero all output vectors
2145250756a7Sjeremylt       CeedQFunction qf = op->qf;
2146cae8b89aSjeremylt       for (CeedInt i=0; i<qf->numoutputfields; i++) {
2147cae8b89aSjeremylt         CeedVector vec = op->outputfields[i]->vec;
2148cae8b89aSjeremylt         if (vec == CEED_VECTOR_ACTIVE)
2149cae8b89aSjeremylt           vec = out;
2150cae8b89aSjeremylt         if (vec != CEED_VECTOR_NONE) {
2151cae8b89aSjeremylt           ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr);
2152cae8b89aSjeremylt         }
2153cae8b89aSjeremylt       }
2154250756a7Sjeremylt       // Apply
2155250756a7Sjeremylt       ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr);
2156250756a7Sjeremylt     }
2157250756a7Sjeremylt   } else if (op->composite) {
2158250756a7Sjeremylt     // Composite Operator
2159250756a7Sjeremylt     if (op->ApplyComposite) {
2160250756a7Sjeremylt       ierr = op->ApplyComposite(op, in, out, request); CeedChk(ierr);
2161250756a7Sjeremylt     } else {
2162250756a7Sjeremylt       CeedInt numsub;
2163250756a7Sjeremylt       ierr = CeedOperatorGetNumSub(op, &numsub); CeedChk(ierr);
2164250756a7Sjeremylt       CeedOperator *suboperators;
2165250756a7Sjeremylt       ierr = CeedOperatorGetSubList(op, &suboperators); CeedChk(ierr);
2166250756a7Sjeremylt 
2167250756a7Sjeremylt       // Zero all output vectors
2168250756a7Sjeremylt       if (out != CEED_VECTOR_NONE) {
2169cae8b89aSjeremylt         ierr = CeedVectorSetValue(out, 0.0); CeedChk(ierr);
2170cae8b89aSjeremylt       }
2171250756a7Sjeremylt       for (CeedInt i=0; i<numsub; i++) {
2172250756a7Sjeremylt         for (CeedInt j=0; j<suboperators[i]->qf->numoutputfields; j++) {
2173250756a7Sjeremylt           CeedVector vec = suboperators[i]->outputfields[j]->vec;
2174250756a7Sjeremylt           if (vec != CEED_VECTOR_ACTIVE && vec != CEED_VECTOR_NONE) {
2175250756a7Sjeremylt             ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr);
2176250756a7Sjeremylt           }
2177250756a7Sjeremylt         }
2178250756a7Sjeremylt       }
2179250756a7Sjeremylt       // Apply
2180250756a7Sjeremylt       for (CeedInt i=0; i<op->numsub; i++) {
2181250756a7Sjeremylt         ierr = CeedOperatorApplyAdd(op->suboperators[i], in, out, request);
2182cae8b89aSjeremylt         CeedChk(ierr);
2183cae8b89aSjeremylt       }
2184cae8b89aSjeremylt     }
2185250756a7Sjeremylt   }
2186e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2187cae8b89aSjeremylt }
2188cae8b89aSjeremylt 
2189cae8b89aSjeremylt /**
2190cae8b89aSjeremylt   @brief Apply CeedOperator to a vector and add result to output vector
2191cae8b89aSjeremylt 
2192cae8b89aSjeremylt   This computes the action of the operator on the specified (active) input,
2193cae8b89aSjeremylt   yielding its (active) output.  All inputs and outputs must be specified using
2194cae8b89aSjeremylt   CeedOperatorSetField().
2195cae8b89aSjeremylt 
2196cae8b89aSjeremylt   @param op        CeedOperator to apply
2197cae8b89aSjeremylt   @param[in] in    CeedVector containing input state or NULL if there are no
2198cae8b89aSjeremylt                      active inputs
2199cae8b89aSjeremylt   @param[out] out  CeedVector to sum in result of applying operator (must be
2200cae8b89aSjeremylt                      distinct from @a in) or NULL if there are no active outputs
2201cae8b89aSjeremylt   @param request   Address of CeedRequest for non-blocking completion, else
22024cc79fe7SJed Brown                      @ref CEED_REQUEST_IMMEDIATE
2203cae8b89aSjeremylt 
2204cae8b89aSjeremylt   @return An error code: 0 - success, otherwise - failure
2205cae8b89aSjeremylt 
22067a982d89SJeremy L. Thompson   @ref User
2207cae8b89aSjeremylt **/
2208cae8b89aSjeremylt int CeedOperatorApplyAdd(CeedOperator op, CeedVector in, CeedVector out,
2209cae8b89aSjeremylt                          CeedRequest *request) {
2210cae8b89aSjeremylt   int ierr;
2211*e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
2212cae8b89aSjeremylt 
2213250756a7Sjeremylt   if (op->numelements)  {
2214250756a7Sjeremylt     // Standard Operator
2215250756a7Sjeremylt     ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr);
2216250756a7Sjeremylt   } else if (op->composite) {
2217250756a7Sjeremylt     // Composite Operator
2218250756a7Sjeremylt     if (op->ApplyAddComposite) {
2219250756a7Sjeremylt       ierr = op->ApplyAddComposite(op, in, out, request); CeedChk(ierr);
2220cae8b89aSjeremylt     } else {
2221250756a7Sjeremylt       CeedInt numsub;
2222250756a7Sjeremylt       ierr = CeedOperatorGetNumSub(op, &numsub); CeedChk(ierr);
2223250756a7Sjeremylt       CeedOperator *suboperators;
2224250756a7Sjeremylt       ierr = CeedOperatorGetSubList(op, &suboperators); CeedChk(ierr);
2225250756a7Sjeremylt 
2226250756a7Sjeremylt       for (CeedInt i=0; i<numsub; i++) {
2227250756a7Sjeremylt         ierr = CeedOperatorApplyAdd(suboperators[i], in, out, request);
2228cae8b89aSjeremylt         CeedChk(ierr);
22291d7d2407SJeremy L Thompson       }
2230250756a7Sjeremylt     }
2231250756a7Sjeremylt   }
2232e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2233d7b241e6Sjeremylt }
2234d7b241e6Sjeremylt 
2235d7b241e6Sjeremylt /**
2236b11c1e72Sjeremylt   @brief Destroy a CeedOperator
2237d7b241e6Sjeremylt 
2238d7b241e6Sjeremylt   @param op CeedOperator to destroy
2239b11c1e72Sjeremylt 
2240b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
2241dfdf5a53Sjeremylt 
22427a982d89SJeremy L. Thompson   @ref User
2243b11c1e72Sjeremylt **/
2244d7b241e6Sjeremylt int CeedOperatorDestroy(CeedOperator *op) {
2245d7b241e6Sjeremylt   int ierr;
2246d7b241e6Sjeremylt 
2247e15f9bd0SJeremy L Thompson   if (!*op || --(*op)->refcount > 0) return CEED_ERROR_SUCCESS;
2248d7b241e6Sjeremylt   if ((*op)->Destroy) {
2249d7b241e6Sjeremylt     ierr = (*op)->Destroy(*op); CeedChk(ierr);
2250d7b241e6Sjeremylt   }
2251fe2413ffSjeremylt   ierr = CeedDestroy(&(*op)->ceed); CeedChk(ierr);
2252fe2413ffSjeremylt   // Free fields
22531d102b48SJeremy L Thompson   for (int i=0; i<(*op)->nfields; i++)
225452d6035fSJeremy L Thompson     if ((*op)->inputfields[i]) {
225515910d16Sjeremylt       if ((*op)->inputfields[i]->Erestrict != CEED_ELEMRESTRICTION_NONE) {
225671352a93Sjeremylt         ierr = CeedElemRestrictionDestroy(&(*op)->inputfields[i]->Erestrict);
225771352a93Sjeremylt         CeedChk(ierr);
225815910d16Sjeremylt       }
225971352a93Sjeremylt       if ((*op)->inputfields[i]->basis != CEED_BASIS_COLLOCATED) {
226071352a93Sjeremylt         ierr = CeedBasisDestroy(&(*op)->inputfields[i]->basis); CeedChk(ierr);
226171352a93Sjeremylt       }
226271352a93Sjeremylt       if ((*op)->inputfields[i]->vec != CEED_VECTOR_ACTIVE &&
226371352a93Sjeremylt           (*op)->inputfields[i]->vec != CEED_VECTOR_NONE ) {
226471352a93Sjeremylt         ierr = CeedVectorDestroy(&(*op)->inputfields[i]->vec); CeedChk(ierr);
226571352a93Sjeremylt       }
2266d99fa3c5SJeremy L Thompson       ierr = CeedFree(&(*op)->inputfields[i]->fieldname); CeedChk(ierr);
2267fe2413ffSjeremylt       ierr = CeedFree(&(*op)->inputfields[i]); CeedChk(ierr);
2268fe2413ffSjeremylt     }
22691d102b48SJeremy L Thompson   for (int i=0; i<(*op)->nfields; i++)
2270d0eb30a5Sjeremylt     if ((*op)->outputfields[i]) {
227171352a93Sjeremylt       ierr = CeedElemRestrictionDestroy(&(*op)->outputfields[i]->Erestrict);
227271352a93Sjeremylt       CeedChk(ierr);
227371352a93Sjeremylt       if ((*op)->outputfields[i]->basis != CEED_BASIS_COLLOCATED) {
227471352a93Sjeremylt         ierr = CeedBasisDestroy(&(*op)->outputfields[i]->basis); CeedChk(ierr);
227571352a93Sjeremylt       }
227671352a93Sjeremylt       if ((*op)->outputfields[i]->vec != CEED_VECTOR_ACTIVE &&
227771352a93Sjeremylt           (*op)->outputfields[i]->vec != CEED_VECTOR_NONE ) {
227871352a93Sjeremylt         ierr = CeedVectorDestroy(&(*op)->outputfields[i]->vec); CeedChk(ierr);
227971352a93Sjeremylt       }
2280d99fa3c5SJeremy L Thompson       ierr = CeedFree(&(*op)->outputfields[i]->fieldname); CeedChk(ierr);
2281fe2413ffSjeremylt       ierr = CeedFree(&(*op)->outputfields[i]); CeedChk(ierr);
2282fe2413ffSjeremylt     }
228352d6035fSJeremy L Thompson   // Destroy suboperators
22841d102b48SJeremy L Thompson   for (int i=0; i<(*op)->numsub; i++)
228552d6035fSJeremy L Thompson     if ((*op)->suboperators[i]) {
228652d6035fSJeremy L Thompson       ierr = CeedOperatorDestroy(&(*op)->suboperators[i]); CeedChk(ierr);
228752d6035fSJeremy L Thompson     }
2288e15f9bd0SJeremy L Thompson   if ((*op)->qf)
2289e15f9bd0SJeremy L Thompson     // LCOV_EXCL_START
2290e15f9bd0SJeremy L Thompson     (*op)->qf->operatorsset--;
2291e15f9bd0SJeremy L Thompson   // LCOV_EXCL_STOP
2292d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->qf); CeedChk(ierr);
2293e15f9bd0SJeremy L Thompson   if ((*op)->dqf && (*op)->dqf != CEED_QFUNCTION_NONE)
2294e15f9bd0SJeremy L Thompson     // LCOV_EXCL_START
2295e15f9bd0SJeremy L Thompson     (*op)->dqf->operatorsset--;
2296e15f9bd0SJeremy L Thompson   // LCOV_EXCL_STOP
2297d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->dqf); CeedChk(ierr);
2298e15f9bd0SJeremy L Thompson   if ((*op)->dqfT && (*op)->dqfT != CEED_QFUNCTION_NONE)
2299e15f9bd0SJeremy L Thompson     // LCOV_EXCL_START
2300e15f9bd0SJeremy L Thompson     (*op)->dqfT->operatorsset--;
2301e15f9bd0SJeremy L Thompson   // LCOV_EXCL_STOP
2302d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->dqfT); CeedChk(ierr);
2303fe2413ffSjeremylt 
23045107b09fSJeremy L Thompson   // Destroy fallback
23055107b09fSJeremy L Thompson   if ((*op)->opfallback) {
23065107b09fSJeremy L Thompson     ierr = (*op)->qffallback->Destroy((*op)->qffallback); CeedChk(ierr);
23075107b09fSJeremy L Thompson     ierr = CeedFree(&(*op)->qffallback); CeedChk(ierr);
23085107b09fSJeremy L Thompson     ierr = (*op)->opfallback->Destroy((*op)->opfallback); CeedChk(ierr);
23095107b09fSJeremy L Thompson     ierr = CeedFree(&(*op)->opfallback); CeedChk(ierr);
23105107b09fSJeremy L Thompson   }
23115107b09fSJeremy L Thompson 
2312fe2413ffSjeremylt   ierr = CeedFree(&(*op)->inputfields); CeedChk(ierr);
2313fe2413ffSjeremylt   ierr = CeedFree(&(*op)->outputfields); CeedChk(ierr);
231452d6035fSJeremy L Thompson   ierr = CeedFree(&(*op)->suboperators); CeedChk(ierr);
2315d7b241e6Sjeremylt   ierr = CeedFree(op); CeedChk(ierr);
2316e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2317d7b241e6Sjeremylt }
2318d7b241e6Sjeremylt 
2319d7b241e6Sjeremylt /// @}
2320