xref: /libCEED/interface/ceed-operator.c (revision e15f9bd09af0280c89b79924fa9af7dd2e3e30be)
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
54*e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED,
55*e15f9bd0SJeremy 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);
72*e15f9bd0SJeremy L Thompson   memcpy(opref, op, sizeof(*opref));
737a982d89SJeremy L. Thompson   opref->data = NULL;
74*e15f9bd0SJeremy L Thompson   opref->interfacesetup = false;
75*e15f9bd0SJeremy 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);
83*e15f9bd0SJeremy 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;
89*e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
90*e15f9bd0SJeremy L Thompson }
917a982d89SJeremy L. Thompson 
92*e15f9bd0SJeremy L Thompson /**
93*e15f9bd0SJeremy L Thompson   @brief Check if a CeedOperator Field matches the QFunction Field
94*e15f9bd0SJeremy L Thompson 
95*e15f9bd0SJeremy L Thompson   @param[in] ceed   Ceed object for error handling
96*e15f9bd0SJeremy L Thompson   @param[in] qfield QFunction Field matching Operator Field
97*e15f9bd0SJeremy L Thompson   @param[in] r      Operator Field ElemRestriction
98*e15f9bd0SJeremy L Thompson   @param[in] b      Operator Field Basis
99*e15f9bd0SJeremy L Thompson 
100*e15f9bd0SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
101*e15f9bd0SJeremy L Thompson 
102*e15f9bd0SJeremy L Thompson   @ref Developer
103*e15f9bd0SJeremy L Thompson **/
104*e15f9bd0SJeremy L Thompson static int CeedOperatorCheckField(Ceed ceed, CeedQFunctionField qfield,
105*e15f9bd0SJeremy L Thompson                                   CeedElemRestriction r, CeedBasis b) {
106*e15f9bd0SJeremy L Thompson   int ierr;
107*e15f9bd0SJeremy L Thompson   CeedEvalMode emode = qfield->emode;
108*e15f9bd0SJeremy L Thompson   CeedInt dim = 1, ncomp = 1, restr_ncomp = 1, size = qfield->size;
109*e15f9bd0SJeremy L Thompson   // Restriction
110*e15f9bd0SJeremy L Thompson   if (r != CEED_ELEMRESTRICTION_NONE) {
111*e15f9bd0SJeremy L Thompson     ierr = CeedElemRestrictionGetNumComponents(r, &restr_ncomp);
112*e15f9bd0SJeremy L Thompson   } else if (emode != CEED_EVAL_WEIGHT) {
113*e15f9bd0SJeremy L Thompson     // LCOV_EXCL_START
114*e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_MINOR,
115*e15f9bd0SJeremy L Thompson                      "CEED_ELEMRESTRICTION_NONE can only be used "
116*e15f9bd0SJeremy L Thompson                      "for a field with eval mode CEED_EVAL_WEIGHT");
117*e15f9bd0SJeremy L Thompson     // LCOV_EXCL_STOP
118*e15f9bd0SJeremy L Thompson   }
119*e15f9bd0SJeremy L Thompson   // Basis
120*e15f9bd0SJeremy L Thompson   if (b != CEED_BASIS_COLLOCATED) {
121*e15f9bd0SJeremy L Thompson     ierr = CeedBasisGetDimension(b, &dim); CeedChk(ierr);
122*e15f9bd0SJeremy L Thompson     ierr = CeedBasisGetNumComponents(b, &ncomp); CeedChk(ierr);
123*e15f9bd0SJeremy L Thompson     if (r != CEED_ELEMRESTRICTION_NONE && restr_ncomp != ncomp) {
124*e15f9bd0SJeremy L Thompson       // LCOV_EXCL_START
125*e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_DIMENSION,
126*e15f9bd0SJeremy L Thompson                        "ElemRestriction and Basis have incompatible numbers of components");
127*e15f9bd0SJeremy L Thompson       // LCOV_EXCL_STOP
128*e15f9bd0SJeremy L Thompson     }
129*e15f9bd0SJeremy L Thompson   }
130*e15f9bd0SJeremy L Thompson   // Field size
131*e15f9bd0SJeremy L Thompson   switch(emode) {
132*e15f9bd0SJeremy L Thompson   case CEED_EVAL_NONE:
133*e15f9bd0SJeremy L Thompson     if (size != restr_ncomp)
134*e15f9bd0SJeremy L Thompson       // LCOV_EXCL_START
135*e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_DIMENSION,
136*e15f9bd0SJeremy L Thompson                        "Incompatible QFunction field size and Operator field "
137*e15f9bd0SJeremy L Thompson                        "ElemRestriction number of components");
138*e15f9bd0SJeremy L Thompson     // LCOV_EXCL_STOP
139*e15f9bd0SJeremy L Thompson     break;
140*e15f9bd0SJeremy L Thompson   case CEED_EVAL_INTERP:
141*e15f9bd0SJeremy L Thompson     if (size != ncomp)
142*e15f9bd0SJeremy L Thompson       // LCOV_EXCL_START
143*e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_DIMENSION,
144*e15f9bd0SJeremy L Thompson                        "Incompatible QFunction field size and Operator field "
145*e15f9bd0SJeremy L Thompson                        "Basis number of components");
146*e15f9bd0SJeremy L Thompson     // LCOV_EXCL_STOP
147*e15f9bd0SJeremy L Thompson     break;
148*e15f9bd0SJeremy L Thompson   case CEED_EVAL_GRAD:
149*e15f9bd0SJeremy L Thompson     if (size != ncomp * dim)
150*e15f9bd0SJeremy L Thompson       // LCOV_EXCL_START
151*e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_DIMENSION,
152*e15f9bd0SJeremy L Thompson                        "Incompatible QFunction field size and Operator field "
153*e15f9bd0SJeremy L Thompson                        "Basis dimension and number of components");
154*e15f9bd0SJeremy L Thompson     // LCOV_EXCL_STOP
155*e15f9bd0SJeremy L Thompson     break;
156*e15f9bd0SJeremy L Thompson   case CEED_EVAL_WEIGHT:
157*e15f9bd0SJeremy L Thompson     // No addional checks required
158*e15f9bd0SJeremy L Thompson     break;
159*e15f9bd0SJeremy L Thompson   case CEED_EVAL_DIV:
160*e15f9bd0SJeremy L Thompson     // Not implemented
161*e15f9bd0SJeremy L Thompson     break;
162*e15f9bd0SJeremy L Thompson   case CEED_EVAL_CURL:
163*e15f9bd0SJeremy L Thompson     // Not implemented
164*e15f9bd0SJeremy L Thompson     break;
165*e15f9bd0SJeremy L Thompson   }
166*e15f9bd0SJeremy 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] ceed Ceed object for error handling
1737a982d89SJeremy L. Thompson   @param[in] op   CeedOperator to check
1747a982d89SJeremy L. Thompson 
1757a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
1767a982d89SJeremy L. Thompson 
1777a982d89SJeremy L. Thompson   @ref Developer
1787a982d89SJeremy L. Thompson **/
1797a982d89SJeremy L. Thompson static int CeedOperatorCheckReady(Ceed ceed, CeedOperator op) {
180*e15f9bd0SJeremy L Thompson   if (op->interfacesetup)
181*e15f9bd0SJeremy L Thompson     return CEED_ERROR_SUCCESS;
1827a982d89SJeremy L. Thompson 
183*e15f9bd0SJeremy L Thompson   CeedQFunction qf = op->qf;
1847a982d89SJeremy L. Thompson   if (op->composite) {
1857a982d89SJeremy L. Thompson     if (!op->numsub)
1867a982d89SJeremy L. Thompson       // LCOV_EXCL_START
187*e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_INCOMPLETE, "No suboperators set");
1887a982d89SJeremy L. Thompson     // LCOV_EXCL_STOP
1897a982d89SJeremy L. Thompson   } else {
1907a982d89SJeremy L. Thompson     if (op->nfields == 0)
1917a982d89SJeremy L. Thompson       // LCOV_EXCL_START
192*e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_INCOMPLETE, "No operator fields set");
1937a982d89SJeremy L. Thompson     // LCOV_EXCL_STOP
1947a982d89SJeremy L. Thompson     if (op->nfields < qf->numinputfields + qf->numoutputfields)
1957a982d89SJeremy L. Thompson       // LCOV_EXCL_START
196*e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_INCOMPLETE, "Not all operator fields set");
1977a982d89SJeremy L. Thompson     // LCOV_EXCL_STOP
1987a982d89SJeremy L. Thompson     if (!op->hasrestriction)
1997a982d89SJeremy L. Thompson       // LCOV_EXCL_START
200*e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_INCOMPLETE,
201*e15f9bd0SJeremy L Thompson                        "At least one restriction required");
2027a982d89SJeremy L. Thompson     // LCOV_EXCL_STOP
2037a982d89SJeremy L. Thompson     if (op->numqpoints == 0)
2047a982d89SJeremy L. Thompson       // LCOV_EXCL_START
205*e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_INCOMPLETE,
206*e15f9bd0SJeremy L Thompson                        "At least one non-collocated basis required");
2077a982d89SJeremy L. Thompson     // LCOV_EXCL_STOP
2087a982d89SJeremy L. Thompson   }
2097a982d89SJeremy L. Thompson 
210*e15f9bd0SJeremy L Thompson   // Flag as immutable and ready
211*e15f9bd0SJeremy L Thompson   op->interfacesetup = true;
212*e15f9bd0SJeremy L Thompson   if (op->qf && op->qf != CEED_QFUNCTION_NONE)
213*e15f9bd0SJeremy L Thompson     // LCOV_EXCL_START
214*e15f9bd0SJeremy L Thompson     op->qf->operatorsset++;
215*e15f9bd0SJeremy L Thompson   // LCOV_EXCL_STOP
216*e15f9bd0SJeremy L Thompson   if (op->dqf && op->dqf != CEED_QFUNCTION_NONE)
217*e15f9bd0SJeremy L Thompson     // LCOV_EXCL_START
218*e15f9bd0SJeremy L Thompson     op->dqf->operatorsset++;
219*e15f9bd0SJeremy L Thompson   // LCOV_EXCL_STOP
220*e15f9bd0SJeremy L Thompson   if (op->dqfT && op->dqfT != CEED_QFUNCTION_NONE)
221*e15f9bd0SJeremy L Thompson     // LCOV_EXCL_START
222*e15f9bd0SJeremy L Thompson     op->dqfT->operatorsset++;
223*e15f9bd0SJeremy L Thompson   // LCOV_EXCL_STOP
224*e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2257a982d89SJeremy L. Thompson }
2267a982d89SJeremy L. Thompson 
2277a982d89SJeremy L. Thompson /**
2287a982d89SJeremy L. Thompson   @brief View a field of a CeedOperator
2297a982d89SJeremy L. Thompson 
2307a982d89SJeremy L. Thompson   @param[in] field       Operator field to view
2314c4400c7SValeria Barra   @param[in] qffield     QFunction field (carries field name)
2327a982d89SJeremy L. Thompson   @param[in] fieldnumber Number of field being viewed
2334c4400c7SValeria Barra   @param[in] sub         true indicates sub-operator, which increases indentation; false for top-level operator
2344c4400c7SValeria Barra   @param[in] in          true for an input field; false for output field
2357a982d89SJeremy L. Thompson   @param[in] stream      Stream to view to, e.g., stdout
2367a982d89SJeremy L. Thompson 
2377a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
2387a982d89SJeremy L. Thompson 
2397a982d89SJeremy L. Thompson   @ref Utility
2407a982d89SJeremy L. Thompson **/
2417a982d89SJeremy L. Thompson static int CeedOperatorFieldView(CeedOperatorField field,
2427a982d89SJeremy L. Thompson                                  CeedQFunctionField qffield,
2437a982d89SJeremy L. Thompson                                  CeedInt fieldnumber, bool sub, bool in,
2447a982d89SJeremy L. Thompson                                  FILE *stream) {
2457a982d89SJeremy L. Thompson   const char *pre = sub ? "  " : "";
2467a982d89SJeremy L. Thompson   const char *inout = in ? "Input" : "Output";
2477a982d89SJeremy L. Thompson 
2487a982d89SJeremy L. Thompson   fprintf(stream, "%s    %s Field [%d]:\n"
2497a982d89SJeremy L. Thompson           "%s      Name: \"%s\"\n",
2507a982d89SJeremy L. Thompson           pre, inout, fieldnumber, pre, qffield->fieldname);
2517a982d89SJeremy L. Thompson 
2527a982d89SJeremy L. Thompson   if (field->basis == CEED_BASIS_COLLOCATED)
2537a982d89SJeremy L. Thompson     fprintf(stream, "%s      Collocated basis\n", pre);
2547a982d89SJeremy L. Thompson 
2557a982d89SJeremy L. Thompson   if (field->vec == CEED_VECTOR_ACTIVE)
2567a982d89SJeremy L. Thompson     fprintf(stream, "%s      Active vector\n", pre);
2577a982d89SJeremy L. Thompson   else if (field->vec == CEED_VECTOR_NONE)
2587a982d89SJeremy L. Thompson     fprintf(stream, "%s      No vector\n", pre);
259*e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2607a982d89SJeremy L. Thompson }
2617a982d89SJeremy L. Thompson 
2627a982d89SJeremy L. Thompson /**
2637a982d89SJeremy L. Thompson   @brief View a single CeedOperator
2647a982d89SJeremy L. Thompson 
2657a982d89SJeremy L. Thompson   @param[in] op     CeedOperator to view
2667a982d89SJeremy L. Thompson   @param[in] sub    Boolean flag for sub-operator
2677a982d89SJeremy L. Thompson   @param[in] stream Stream to write; typically stdout/stderr or a file
2687a982d89SJeremy L. Thompson 
2697a982d89SJeremy L. Thompson   @return Error code: 0 - success, otherwise - failure
2707a982d89SJeremy L. Thompson 
2717a982d89SJeremy L. Thompson   @ref Utility
2727a982d89SJeremy L. Thompson **/
2737a982d89SJeremy L. Thompson int CeedOperatorSingleView(CeedOperator op, bool sub, FILE *stream) {
2747a982d89SJeremy L. Thompson   int ierr;
2757a982d89SJeremy L. Thompson   const char *pre = sub ? "  " : "";
2767a982d89SJeremy L. Thompson 
2777a982d89SJeremy L. Thompson   CeedInt totalfields;
2787a982d89SJeremy L. Thompson   ierr = CeedOperatorGetNumArgs(op, &totalfields); CeedChk(ierr);
2797a982d89SJeremy L. Thompson 
2807a982d89SJeremy L. Thompson   fprintf(stream, "%s  %d Field%s\n", pre, totalfields, totalfields>1 ? "s" : "");
2817a982d89SJeremy L. Thompson 
2827a982d89SJeremy L. Thompson   fprintf(stream, "%s  %d Input Field%s:\n", pre, op->qf->numinputfields,
2837a982d89SJeremy L. Thompson           op->qf->numinputfields>1 ? "s" : "");
2847a982d89SJeremy L. Thompson   for (CeedInt i=0; i<op->qf->numinputfields; i++) {
2857a982d89SJeremy L. Thompson     ierr = CeedOperatorFieldView(op->inputfields[i], op->qf->inputfields[i],
2867a982d89SJeremy L. Thompson                                  i, sub, 1, stream); CeedChk(ierr);
2877a982d89SJeremy L. Thompson   }
2887a982d89SJeremy L. Thompson 
2897a982d89SJeremy L. Thompson   fprintf(stream, "%s  %d Output Field%s:\n", pre, op->qf->numoutputfields,
2907a982d89SJeremy L. Thompson           op->qf->numoutputfields>1 ? "s" : "");
2917a982d89SJeremy L. Thompson   for (CeedInt i=0; i<op->qf->numoutputfields; i++) {
292829936eeSWill Pazner     ierr = CeedOperatorFieldView(op->outputfields[i], op->qf->outputfields[i],
2937a982d89SJeremy L. Thompson                                  i, sub, 0, stream); CeedChk(ierr);
2947a982d89SJeremy L. Thompson   }
295*e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2967a982d89SJeremy L. Thompson }
2977a982d89SJeremy L. Thompson 
298d99fa3c5SJeremy L Thompson /**
299d99fa3c5SJeremy L Thompson   @brief Find the active vector basis for a CeedOperator
300d99fa3c5SJeremy L Thompson 
301d99fa3c5SJeremy L Thompson   @param[in] op            CeedOperator to find active basis for
302d99fa3c5SJeremy L Thompson   @param[out] activeBasis  Basis for active input vector
303d99fa3c5SJeremy L Thompson 
304d99fa3c5SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
305d99fa3c5SJeremy L Thompson 
306d99fa3c5SJeremy L Thompson   @ ref Developer
307d99fa3c5SJeremy L Thompson **/
308d99fa3c5SJeremy L Thompson static int CeedOperatorGetActiveBasis(CeedOperator op,
309d99fa3c5SJeremy L Thompson                                       CeedBasis *activeBasis) {
310d99fa3c5SJeremy L Thompson   *activeBasis = NULL;
311d99fa3c5SJeremy L Thompson   for (int i = 0; i < op->qf->numinputfields; i++)
312d99fa3c5SJeremy L Thompson     if (op->inputfields[i]->vec == CEED_VECTOR_ACTIVE) {
313d99fa3c5SJeremy L Thompson       *activeBasis = op->inputfields[i]->basis;
314d99fa3c5SJeremy L Thompson       break;
315d99fa3c5SJeremy L Thompson     }
316d99fa3c5SJeremy L Thompson 
317d99fa3c5SJeremy L Thompson   if (!*activeBasis) {
318d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
319d99fa3c5SJeremy L Thompson     int ierr;
320d99fa3c5SJeremy L Thompson     Ceed ceed;
321d99fa3c5SJeremy L Thompson     ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr);
322*e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_MINOR,
323d99fa3c5SJeremy L Thompson                      "No active basis found for automatic multigrid setup");
324d99fa3c5SJeremy L Thompson     // LCOV_EXCL_STOP
325d99fa3c5SJeremy L Thompson   }
326*e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
327d99fa3c5SJeremy L Thompson }
328d99fa3c5SJeremy L Thompson 
329d99fa3c5SJeremy L Thompson 
330d99fa3c5SJeremy L Thompson /**
331d99fa3c5SJeremy L Thompson   @brief Common code for creating a multigrid coarse operator and level
332d99fa3c5SJeremy L Thompson            transfer operators for a CeedOperator
333d99fa3c5SJeremy L Thompson 
334d99fa3c5SJeremy L Thompson   @param[in] opFine       Fine grid operator
335d99fa3c5SJeremy L Thompson   @param[in] PMultFine    L-vector multiplicity in parallel gather/scatter
336d99fa3c5SJeremy L Thompson   @param[in] rstrCoarse   Coarse grid restriction
337d99fa3c5SJeremy L Thompson   @param[in] basisCoarse  Coarse grid active vector basis
338d99fa3c5SJeremy L Thompson   @param[in] basisCtoF    Basis for coarse to fine interpolation
339d99fa3c5SJeremy L Thompson   @param[out] opCoarse    Coarse grid operator
340d99fa3c5SJeremy L Thompson   @param[out] opProlong   Coarse to fine operator
341d99fa3c5SJeremy L Thompson   @param[out] opRestrict  Fine to coarse operator
342d99fa3c5SJeremy L Thompson 
343d99fa3c5SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
344d99fa3c5SJeremy L Thompson 
345d99fa3c5SJeremy L Thompson   @ref Developer
346d99fa3c5SJeremy L Thompson **/
347d99fa3c5SJeremy L Thompson static int CeedOperatorMultigridLevel_Core(CeedOperator opFine,
348d99fa3c5SJeremy L Thompson     CeedVector PMultFine, CeedElemRestriction rstrCoarse, CeedBasis basisCoarse,
349d99fa3c5SJeremy L Thompson     CeedBasis basisCtoF, CeedOperator *opCoarse, CeedOperator *opProlong,
350d99fa3c5SJeremy L Thompson     CeedOperator *opRestrict) {
351d99fa3c5SJeremy L Thompson   int ierr;
352d99fa3c5SJeremy L Thompson   Ceed ceed;
353d99fa3c5SJeremy L Thompson   ierr = CeedOperatorGetCeed(opFine, &ceed); CeedChk(ierr);
354d99fa3c5SJeremy L Thompson 
355d99fa3c5SJeremy L Thompson   // Check for composite operator
356d99fa3c5SJeremy L Thompson   bool isComposite;
357d99fa3c5SJeremy L Thompson   ierr = CeedOperatorIsComposite(opFine, &isComposite); CeedChk(ierr);
358d99fa3c5SJeremy L Thompson   if (isComposite)
359d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
360*e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_UNSUPPORTED,
361d99fa3c5SJeremy L Thompson                      "Automatic multigrid setup for composite operators not supported");
362d99fa3c5SJeremy L Thompson   // LCOV_EXCL_STOP
363d99fa3c5SJeremy L Thompson 
364d99fa3c5SJeremy L Thompson   // Coarse Grid
365d99fa3c5SJeremy L Thompson   ierr = CeedOperatorCreate(ceed, opFine->qf, opFine->dqf, opFine->dqfT,
366d99fa3c5SJeremy L Thompson                             opCoarse); CeedChk(ierr);
367d99fa3c5SJeremy L Thompson   CeedElemRestriction rstrFine = NULL;
368d99fa3c5SJeremy L Thompson   // -- Clone input fields
369d99fa3c5SJeremy L Thompson   for (int i = 0; i < opFine->qf->numinputfields; i++) {
370d99fa3c5SJeremy L Thompson     if (opFine->inputfields[i]->vec == CEED_VECTOR_ACTIVE) {
371d99fa3c5SJeremy L Thompson       rstrFine = opFine->inputfields[i]->Erestrict;
372d99fa3c5SJeremy L Thompson       ierr = CeedOperatorSetField(*opCoarse, opFine->inputfields[i]->fieldname,
373d99fa3c5SJeremy L Thompson                                   rstrCoarse, basisCoarse, CEED_VECTOR_ACTIVE);
374d99fa3c5SJeremy L Thompson       CeedChk(ierr);
375d99fa3c5SJeremy L Thompson     } else {
376d99fa3c5SJeremy L Thompson       ierr = CeedOperatorSetField(*opCoarse, opFine->inputfields[i]->fieldname,
377d99fa3c5SJeremy L Thompson                                   opFine->inputfields[i]->Erestrict,
378d99fa3c5SJeremy L Thompson                                   opFine->inputfields[i]->basis,
379d99fa3c5SJeremy L Thompson                                   opFine->inputfields[i]->vec); CeedChk(ierr);
380d99fa3c5SJeremy L Thompson     }
381d99fa3c5SJeremy L Thompson   }
382d99fa3c5SJeremy L Thompson   // -- Clone output fields
383d99fa3c5SJeremy L Thompson   for (int i = 0; i < opFine->qf->numoutputfields; i++) {
384d99fa3c5SJeremy L Thompson     if (opFine->outputfields[i]->vec == CEED_VECTOR_ACTIVE) {
385d99fa3c5SJeremy L Thompson       ierr = CeedOperatorSetField(*opCoarse, opFine->outputfields[i]->fieldname,
386d99fa3c5SJeremy L Thompson                                   rstrCoarse, basisCoarse, CEED_VECTOR_ACTIVE);
387d99fa3c5SJeremy L Thompson       CeedChk(ierr);
388d99fa3c5SJeremy L Thompson     } else {
389d99fa3c5SJeremy L Thompson       ierr = CeedOperatorSetField(*opCoarse, opFine->outputfields[i]->fieldname,
390d99fa3c5SJeremy L Thompson                                   opFine->outputfields[i]->Erestrict,
391d99fa3c5SJeremy L Thompson                                   opFine->outputfields[i]->basis,
392d99fa3c5SJeremy L Thompson                                   opFine->outputfields[i]->vec); CeedChk(ierr);
393d99fa3c5SJeremy L Thompson     }
394d99fa3c5SJeremy L Thompson   }
395d99fa3c5SJeremy L Thompson 
396d99fa3c5SJeremy L Thompson   // Multiplicity vector
397d99fa3c5SJeremy L Thompson   CeedVector multVec, multE;
398d99fa3c5SJeremy L Thompson   ierr = CeedElemRestrictionCreateVector(rstrFine, &multVec, &multE);
399d99fa3c5SJeremy L Thompson   CeedChk(ierr);
400d99fa3c5SJeremy L Thompson   ierr = CeedVectorSetValue(multE, 0.0); CeedChk(ierr);
401d99fa3c5SJeremy L Thompson   ierr = CeedElemRestrictionApply(rstrFine, CEED_NOTRANSPOSE, PMultFine, multE,
402d99fa3c5SJeremy L Thompson                                   CEED_REQUEST_IMMEDIATE); CeedChk(ierr);
403d99fa3c5SJeremy L Thompson   ierr = CeedVectorSetValue(multVec, 0.0); CeedChk(ierr);
404d99fa3c5SJeremy L Thompson   ierr = CeedElemRestrictionApply(rstrFine, CEED_TRANSPOSE, multE, multVec,
405d99fa3c5SJeremy L Thompson                                   CEED_REQUEST_IMMEDIATE); CeedChk(ierr);
406d99fa3c5SJeremy L Thompson   ierr = CeedVectorDestroy(&multE); CeedChk(ierr);
407d99fa3c5SJeremy L Thompson   ierr = CeedVectorReciprocal(multVec); CeedChk(ierr);
408d99fa3c5SJeremy L Thompson 
409d99fa3c5SJeremy L Thompson   // Restriction
410d99fa3c5SJeremy L Thompson   CeedInt ncomp;
411d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumComponents(basisCoarse, &ncomp); CeedChk(ierr);
412d99fa3c5SJeremy L Thompson   CeedQFunction qfRestrict;
413d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionCreateInteriorByName(ceed, "Scale", &qfRestrict);
414d99fa3c5SJeremy L Thompson   CeedChk(ierr);
415777ff853SJeremy L Thompson   CeedInt *ncompRData;
416777ff853SJeremy L Thompson   ierr = CeedCalloc(1, &ncompRData); CeedChk(ierr);
417777ff853SJeremy L Thompson   ncompRData[0] = ncomp;
418777ff853SJeremy L Thompson   CeedQFunctionContext ctxR;
419777ff853SJeremy L Thompson   ierr = CeedQFunctionContextCreate(ceed, &ctxR); CeedChk(ierr);
420777ff853SJeremy L Thompson   ierr = CeedQFunctionContextSetData(ctxR, CEED_MEM_HOST, CEED_OWN_POINTER,
421777ff853SJeremy L Thompson                                      sizeof(*ncompRData), ncompRData);
422777ff853SJeremy L Thompson   CeedChk(ierr);
423777ff853SJeremy L Thompson   ierr = CeedQFunctionSetContext(qfRestrict, ctxR); CeedChk(ierr);
424777ff853SJeremy L Thompson   ierr = CeedQFunctionContextDestroy(&ctxR); CeedChk(ierr);
425d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionAddInput(qfRestrict, "input", ncomp, CEED_EVAL_NONE);
426d99fa3c5SJeremy L Thompson   CeedChk(ierr);
427d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionAddInput(qfRestrict, "scale", ncomp, CEED_EVAL_NONE);
428d99fa3c5SJeremy L Thompson   CeedChk(ierr);
429d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionAddOutput(qfRestrict, "output", ncomp, CEED_EVAL_INTERP);
430d99fa3c5SJeremy L Thompson   CeedChk(ierr);
431d99fa3c5SJeremy L Thompson 
432d99fa3c5SJeremy L Thompson   ierr = CeedOperatorCreate(ceed, qfRestrict, CEED_QFUNCTION_NONE,
433d99fa3c5SJeremy L Thompson                             CEED_QFUNCTION_NONE, opRestrict);
434d99fa3c5SJeremy L Thompson   CeedChk(ierr);
435d99fa3c5SJeremy L Thompson   ierr = CeedOperatorSetField(*opRestrict, "input", rstrFine,
436d99fa3c5SJeremy L Thompson                               CEED_BASIS_COLLOCATED, CEED_VECTOR_ACTIVE);
437d99fa3c5SJeremy L Thompson   CeedChk(ierr);
438d99fa3c5SJeremy L Thompson   ierr = CeedOperatorSetField(*opRestrict, "scale", rstrFine,
439d99fa3c5SJeremy L Thompson                               CEED_BASIS_COLLOCATED, multVec);
440d99fa3c5SJeremy L Thompson   CeedChk(ierr);
441d99fa3c5SJeremy L Thompson   ierr = CeedOperatorSetField(*opRestrict, "output", rstrCoarse, basisCtoF,
442d99fa3c5SJeremy L Thompson                               CEED_VECTOR_ACTIVE); CeedChk(ierr);
443d99fa3c5SJeremy L Thompson 
444d99fa3c5SJeremy L Thompson   // Prolongation
445d99fa3c5SJeremy L Thompson   CeedQFunction qfProlong;
446d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionCreateInteriorByName(ceed, "Scale", &qfProlong);
447d99fa3c5SJeremy L Thompson   CeedChk(ierr);
448777ff853SJeremy L Thompson   CeedInt *ncompPData;
449777ff853SJeremy L Thompson   ierr = CeedCalloc(1, &ncompPData); CeedChk(ierr);
450777ff853SJeremy L Thompson   ncompPData[0] = ncomp;
451777ff853SJeremy L Thompson   CeedQFunctionContext ctxP;
452777ff853SJeremy L Thompson   ierr = CeedQFunctionContextCreate(ceed, &ctxP); CeedChk(ierr);
453777ff853SJeremy L Thompson   ierr = CeedQFunctionContextSetData(ctxP, CEED_MEM_HOST, CEED_OWN_POINTER,
454777ff853SJeremy L Thompson                                      sizeof(*ncompPData), ncompPData);
455777ff853SJeremy L Thompson   CeedChk(ierr);
456777ff853SJeremy L Thompson   ierr = CeedQFunctionSetContext(qfProlong, ctxP); CeedChk(ierr);
457777ff853SJeremy L Thompson   ierr = CeedQFunctionContextDestroy(&ctxP); CeedChk(ierr);
458d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionAddInput(qfProlong, "input", ncomp, CEED_EVAL_INTERP);
459d99fa3c5SJeremy L Thompson   CeedChk(ierr);
460d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionAddInput(qfProlong, "scale", ncomp, CEED_EVAL_NONE);
461d99fa3c5SJeremy L Thompson   CeedChk(ierr);
462d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionAddOutput(qfProlong, "output", ncomp, CEED_EVAL_NONE);
463d99fa3c5SJeremy L Thompson   CeedChk(ierr);
464d99fa3c5SJeremy L Thompson 
465d99fa3c5SJeremy L Thompson   ierr = CeedOperatorCreate(ceed, qfProlong, CEED_QFUNCTION_NONE,
466d99fa3c5SJeremy L Thompson                             CEED_QFUNCTION_NONE, opProlong);
467d99fa3c5SJeremy L Thompson   CeedChk(ierr);
468d99fa3c5SJeremy L Thompson   ierr = CeedOperatorSetField(*opProlong, "input", rstrCoarse, basisCtoF,
469d99fa3c5SJeremy L Thompson                               CEED_VECTOR_ACTIVE); CeedChk(ierr);
470d99fa3c5SJeremy L Thompson   ierr = CeedOperatorSetField(*opProlong, "scale", rstrFine,
471d99fa3c5SJeremy L Thompson                               CEED_BASIS_COLLOCATED, multVec);
472d99fa3c5SJeremy L Thompson   CeedChk(ierr);
473d99fa3c5SJeremy L Thompson   ierr = CeedOperatorSetField(*opProlong, "output", rstrFine,
474d99fa3c5SJeremy L Thompson                               CEED_BASIS_COLLOCATED, CEED_VECTOR_ACTIVE);
475d99fa3c5SJeremy L Thompson   CeedChk(ierr);
476d99fa3c5SJeremy L Thompson 
477d99fa3c5SJeremy L Thompson   // Cleanup
478d99fa3c5SJeremy L Thompson   ierr = CeedVectorDestroy(&multVec); CeedChk(ierr);
479d99fa3c5SJeremy L Thompson   ierr = CeedBasisDestroy(&basisCtoF); CeedChk(ierr);
480d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionDestroy(&qfRestrict); CeedChk(ierr);
481d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionDestroy(&qfProlong); CeedChk(ierr);
482*e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
483d99fa3c5SJeremy L Thompson }
484d99fa3c5SJeremy L Thompson 
4857a982d89SJeremy L. Thompson /// @}
4867a982d89SJeremy L. Thompson 
4877a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
4887a982d89SJeremy L. Thompson /// CeedOperator Backend API
4897a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
4907a982d89SJeremy L. Thompson /// @addtogroup CeedOperatorBackend
4917a982d89SJeremy L. Thompson /// @{
4927a982d89SJeremy L. Thompson 
4937a982d89SJeremy L. Thompson /**
4947a982d89SJeremy L. Thompson   @brief Get the Ceed associated with a CeedOperator
4957a982d89SJeremy L. Thompson 
4967a982d89SJeremy L. Thompson   @param op              CeedOperator
4977a982d89SJeremy L. Thompson   @param[out] ceed       Variable to store Ceed
4987a982d89SJeremy L. Thompson 
4997a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5007a982d89SJeremy L. Thompson 
5017a982d89SJeremy L. Thompson   @ref Backend
5027a982d89SJeremy L. Thompson **/
5037a982d89SJeremy L. Thompson 
5047a982d89SJeremy L. Thompson int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) {
5057a982d89SJeremy L. Thompson   *ceed = op->ceed;
506*e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5077a982d89SJeremy L. Thompson }
5087a982d89SJeremy L. Thompson 
5097a982d89SJeremy L. Thompson /**
5107a982d89SJeremy L. Thompson   @brief Get the number of elements associated with a CeedOperator
5117a982d89SJeremy L. Thompson 
5127a982d89SJeremy L. Thompson   @param op              CeedOperator
5137a982d89SJeremy L. Thompson   @param[out] numelem    Variable to store number of elements
5147a982d89SJeremy L. Thompson 
5157a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5167a982d89SJeremy L. Thompson 
5177a982d89SJeremy L. Thompson   @ref Backend
5187a982d89SJeremy L. Thompson **/
5197a982d89SJeremy L. Thompson 
5207a982d89SJeremy L. Thompson int CeedOperatorGetNumElements(CeedOperator op, CeedInt *numelem) {
5217a982d89SJeremy L. Thompson   if (op->composite)
5227a982d89SJeremy L. Thompson     // LCOV_EXCL_START
523*e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
524*e15f9bd0SJeremy L Thompson                      "Not defined for composite operator");
5257a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
5267a982d89SJeremy L. Thompson 
5277a982d89SJeremy L. Thompson   *numelem = op->numelements;
528*e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5297a982d89SJeremy L. Thompson }
5307a982d89SJeremy L. Thompson 
5317a982d89SJeremy L. Thompson /**
5327a982d89SJeremy L. Thompson   @brief Get the number of quadrature points associated with a CeedOperator
5337a982d89SJeremy L. Thompson 
5347a982d89SJeremy L. Thompson   @param op              CeedOperator
5357a982d89SJeremy L. Thompson   @param[out] numqpts    Variable to store vector number of quadrature points
5367a982d89SJeremy L. Thompson 
5377a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5387a982d89SJeremy L. Thompson 
5397a982d89SJeremy L. Thompson   @ref Backend
5407a982d89SJeremy L. Thompson **/
5417a982d89SJeremy L. Thompson 
5427a982d89SJeremy L. Thompson int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *numqpts) {
5437a982d89SJeremy L. Thompson   if (op->composite)
5447a982d89SJeremy L. Thompson     // LCOV_EXCL_START
545*e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
546*e15f9bd0SJeremy L Thompson                      "Not defined for composite operator");
5477a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
5487a982d89SJeremy L. Thompson 
5497a982d89SJeremy L. Thompson   *numqpts = op->numqpoints;
550*e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5517a982d89SJeremy L. Thompson }
5527a982d89SJeremy L. Thompson 
5537a982d89SJeremy L. Thompson /**
5547a982d89SJeremy L. Thompson   @brief Get the number of arguments associated with a CeedOperator
5557a982d89SJeremy L. Thompson 
5567a982d89SJeremy L. Thompson   @param op              CeedOperator
5577a982d89SJeremy L. Thompson   @param[out] numargs    Variable to store vector number of arguments
5587a982d89SJeremy L. Thompson 
5597a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5607a982d89SJeremy L. Thompson 
5617a982d89SJeremy L. Thompson   @ref Backend
5627a982d89SJeremy L. Thompson **/
5637a982d89SJeremy L. Thompson 
5647a982d89SJeremy L. Thompson int CeedOperatorGetNumArgs(CeedOperator op, CeedInt *numargs) {
5657a982d89SJeremy L. Thompson   if (op->composite)
5667a982d89SJeremy L. Thompson     // LCOV_EXCL_START
567*e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
568*e15f9bd0SJeremy L Thompson                      "Not defined for composite operators");
5697a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
5707a982d89SJeremy L. Thompson 
5717a982d89SJeremy L. Thompson   *numargs = op->nfields;
572*e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5737a982d89SJeremy L. Thompson }
5747a982d89SJeremy L. Thompson 
5757a982d89SJeremy L. Thompson /**
5767a982d89SJeremy L. Thompson   @brief Get the setup status of a CeedOperator
5777a982d89SJeremy L. Thompson 
5787a982d89SJeremy L. Thompson   @param op                CeedOperator
579fd364f38SJeremy L Thompson   @param[out] issetupdone  Variable to store setup status
5807a982d89SJeremy L. Thompson 
5817a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5827a982d89SJeremy L. Thompson 
5837a982d89SJeremy L. Thompson   @ref Backend
5847a982d89SJeremy L. Thompson **/
5857a982d89SJeremy L. Thompson 
586fd364f38SJeremy L Thompson int CeedOperatorIsSetupDone(CeedOperator op, bool *issetupdone) {
587*e15f9bd0SJeremy L Thompson   *issetupdone = op->backendsetup;
588*e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5897a982d89SJeremy L. Thompson }
5907a982d89SJeremy L. Thompson 
5917a982d89SJeremy L. Thompson /**
5927a982d89SJeremy L. Thompson   @brief Get the QFunction associated with a CeedOperator
5937a982d89SJeremy L. Thompson 
5947a982d89SJeremy L. Thompson   @param op              CeedOperator
5957a982d89SJeremy L. Thompson   @param[out] qf         Variable to store QFunction
5967a982d89SJeremy L. Thompson 
5977a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5987a982d89SJeremy L. Thompson 
5997a982d89SJeremy L. Thompson   @ref Backend
6007a982d89SJeremy L. Thompson **/
6017a982d89SJeremy L. Thompson 
6027a982d89SJeremy L. Thompson int CeedOperatorGetQFunction(CeedOperator op, CeedQFunction *qf) {
6037a982d89SJeremy L. Thompson   if (op->composite)
6047a982d89SJeremy L. Thompson     // LCOV_EXCL_START
605*e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
606*e15f9bd0SJeremy L Thompson                      "Not defined for composite operator");
6077a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
6087a982d89SJeremy L. Thompson 
6097a982d89SJeremy L. Thompson   *qf = op->qf;
610*e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6117a982d89SJeremy L. Thompson }
6127a982d89SJeremy L. Thompson 
6137a982d89SJeremy L. Thompson /**
614c04a41a7SJeremy L Thompson   @brief Get a boolean value indicating if the CeedOperator is composite
615c04a41a7SJeremy L Thompson 
616c04a41a7SJeremy L Thompson   @param op                CeedOperator
617fd364f38SJeremy L Thompson   @param[out] iscomposite  Variable to store composite status
618c04a41a7SJeremy L Thompson 
619c04a41a7SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
620c04a41a7SJeremy L Thompson 
621c04a41a7SJeremy L Thompson   @ref Backend
622c04a41a7SJeremy L Thompson **/
623c04a41a7SJeremy L Thompson 
624fd364f38SJeremy L Thompson int CeedOperatorIsComposite(CeedOperator op, bool *iscomposite) {
625fd364f38SJeremy L Thompson   *iscomposite = op->composite;
626*e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
627c04a41a7SJeremy L Thompson }
628c04a41a7SJeremy L Thompson 
629c04a41a7SJeremy L Thompson /**
6307a982d89SJeremy L. Thompson   @brief Get the number of suboperators associated with a CeedOperator
6317a982d89SJeremy L. Thompson 
6327a982d89SJeremy L. Thompson   @param op              CeedOperator
6337a982d89SJeremy L. Thompson   @param[out] numsub     Variable to store number of suboperators
6347a982d89SJeremy L. Thompson 
6357a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6367a982d89SJeremy L. Thompson 
6377a982d89SJeremy L. Thompson   @ref Backend
6387a982d89SJeremy L. Thompson **/
6397a982d89SJeremy L. Thompson 
6407a982d89SJeremy L. Thompson int CeedOperatorGetNumSub(CeedOperator op, CeedInt *numsub) {
6417a982d89SJeremy L. Thompson   if (!op->composite)
6427a982d89SJeremy L. Thompson     // LCOV_EXCL_START
643*e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR, "Not a composite operator");
6447a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
6457a982d89SJeremy L. Thompson 
6467a982d89SJeremy L. Thompson   *numsub = op->numsub;
647*e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6487a982d89SJeremy L. Thompson }
6497a982d89SJeremy L. Thompson 
6507a982d89SJeremy L. Thompson /**
6517a982d89SJeremy L. Thompson   @brief Get the list of suboperators associated with a CeedOperator
6527a982d89SJeremy L. Thompson 
6537a982d89SJeremy L. Thompson   @param op                CeedOperator
6547a982d89SJeremy L. Thompson   @param[out] suboperators Variable to store list of suboperators
6557a982d89SJeremy L. Thompson 
6567a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6577a982d89SJeremy L. Thompson 
6587a982d89SJeremy L. Thompson   @ref Backend
6597a982d89SJeremy L. Thompson **/
6607a982d89SJeremy L. Thompson 
6617a982d89SJeremy L. Thompson int CeedOperatorGetSubList(CeedOperator op, CeedOperator **suboperators) {
6627a982d89SJeremy L. Thompson   if (!op->composite)
6637a982d89SJeremy L. Thompson     // LCOV_EXCL_START
664*e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR, "Not a composite operator");
6657a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
6667a982d89SJeremy L. Thompson 
6677a982d89SJeremy L. Thompson   *suboperators = op->suboperators;
668*e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6697a982d89SJeremy L. Thompson }
6707a982d89SJeremy L. Thompson 
6717a982d89SJeremy L. Thompson /**
6727a982d89SJeremy L. Thompson   @brief Get the backend data of a CeedOperator
6737a982d89SJeremy L. Thompson 
6747a982d89SJeremy L. Thompson   @param op              CeedOperator
6757a982d89SJeremy L. Thompson   @param[out] data       Variable to store data
6767a982d89SJeremy L. Thompson 
6777a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6787a982d89SJeremy L. Thompson 
6797a982d89SJeremy L. Thompson   @ref Backend
6807a982d89SJeremy L. Thompson **/
6817a982d89SJeremy L. Thompson 
682777ff853SJeremy L Thompson int CeedOperatorGetData(CeedOperator op, void *data) {
683777ff853SJeremy L Thompson   *(void **)data = op->data;
684*e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6857a982d89SJeremy L. Thompson }
6867a982d89SJeremy L. Thompson 
6877a982d89SJeremy L. Thompson /**
6887a982d89SJeremy L. Thompson   @brief Set the backend data of a CeedOperator
6897a982d89SJeremy L. Thompson 
6907a982d89SJeremy L. Thompson   @param[out] op         CeedOperator
6917a982d89SJeremy L. Thompson   @param data            Data to set
6927a982d89SJeremy L. Thompson 
6937a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6947a982d89SJeremy L. Thompson 
6957a982d89SJeremy L. Thompson   @ref Backend
6967a982d89SJeremy L. Thompson **/
6977a982d89SJeremy L. Thompson 
698777ff853SJeremy L Thompson int CeedOperatorSetData(CeedOperator op, void *data) {
699777ff853SJeremy L Thompson   op->data = data;
700*e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
7017a982d89SJeremy L. Thompson }
7027a982d89SJeremy L. Thompson 
7037a982d89SJeremy L. Thompson /**
7047a982d89SJeremy L. Thompson   @brief Set the setup flag of a CeedOperator to True
7057a982d89SJeremy L. Thompson 
7067a982d89SJeremy L. Thompson   @param op              CeedOperator
7077a982d89SJeremy L. Thompson 
7087a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
7097a982d89SJeremy L. Thompson 
7107a982d89SJeremy L. Thompson   @ref Backend
7117a982d89SJeremy L. Thompson **/
7127a982d89SJeremy L. Thompson 
7137a982d89SJeremy L. Thompson int CeedOperatorSetSetupDone(CeedOperator op) {
714*e15f9bd0SJeremy L Thompson   op->backendsetup = true;
715*e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
7167a982d89SJeremy L. Thompson }
7177a982d89SJeremy L. Thompson 
7187a982d89SJeremy L. Thompson /**
7197a982d89SJeremy L. Thompson   @brief Get the CeedOperatorFields of a CeedOperator
7207a982d89SJeremy L. Thompson 
7217a982d89SJeremy L. Thompson   @param op                 CeedOperator
7227a982d89SJeremy L. Thompson   @param[out] inputfields   Variable to store inputfields
7237a982d89SJeremy L. Thompson   @param[out] outputfields  Variable to store outputfields
7247a982d89SJeremy L. Thompson 
7257a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
7267a982d89SJeremy L. Thompson 
7277a982d89SJeremy L. Thompson   @ref Backend
7287a982d89SJeremy L. Thompson **/
7297a982d89SJeremy L. Thompson 
7307a982d89SJeremy L. Thompson int CeedOperatorGetFields(CeedOperator op, CeedOperatorField **inputfields,
7317a982d89SJeremy L. Thompson                           CeedOperatorField **outputfields) {
7327a982d89SJeremy L. Thompson   if (op->composite)
7337a982d89SJeremy L. Thompson     // LCOV_EXCL_START
734*e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
735*e15f9bd0SJeremy L Thompson                      "Not defined for composite operator");
7367a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
7377a982d89SJeremy L. Thompson 
7387a982d89SJeremy L. Thompson   if (inputfields) *inputfields = op->inputfields;
7397a982d89SJeremy L. Thompson   if (outputfields) *outputfields = op->outputfields;
740*e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
7417a982d89SJeremy L. Thompson }
7427a982d89SJeremy L. Thompson 
7437a982d89SJeremy L. Thompson /**
7447a982d89SJeremy L. Thompson   @brief Get the CeedElemRestriction of a CeedOperatorField
7457a982d89SJeremy L. Thompson 
7467a982d89SJeremy L. Thompson   @param opfield         CeedOperatorField
7477a982d89SJeremy L. Thompson   @param[out] rstr       Variable to store CeedElemRestriction
7487a982d89SJeremy L. Thompson 
7497a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
7507a982d89SJeremy L. Thompson 
7517a982d89SJeremy L. Thompson   @ref Backend
7527a982d89SJeremy L. Thompson **/
7537a982d89SJeremy L. Thompson 
7547a982d89SJeremy L. Thompson int CeedOperatorFieldGetElemRestriction(CeedOperatorField opfield,
7557a982d89SJeremy L. Thompson                                         CeedElemRestriction *rstr) {
7567a982d89SJeremy L. Thompson   *rstr = opfield->Erestrict;
757*e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
7587a982d89SJeremy L. Thompson }
7597a982d89SJeremy L. Thompson 
7607a982d89SJeremy L. Thompson /**
7617a982d89SJeremy L. Thompson   @brief Get the CeedBasis of a CeedOperatorField
7627a982d89SJeremy L. Thompson 
7637a982d89SJeremy L. Thompson   @param opfield         CeedOperatorField
7647a982d89SJeremy L. Thompson   @param[out] basis      Variable to store CeedBasis
7657a982d89SJeremy L. Thompson 
7667a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
7677a982d89SJeremy L. Thompson 
7687a982d89SJeremy L. Thompson   @ref Backend
7697a982d89SJeremy L. Thompson **/
7707a982d89SJeremy L. Thompson 
7717a982d89SJeremy L. Thompson int CeedOperatorFieldGetBasis(CeedOperatorField opfield, CeedBasis *basis) {
7727a982d89SJeremy L. Thompson   *basis = opfield->basis;
773*e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
7747a982d89SJeremy L. Thompson }
7757a982d89SJeremy L. Thompson 
7767a982d89SJeremy L. Thompson /**
7777a982d89SJeremy L. Thompson   @brief Get the CeedVector of a CeedOperatorField
7787a982d89SJeremy L. Thompson 
7797a982d89SJeremy L. Thompson   @param opfield         CeedOperatorField
7807a982d89SJeremy L. Thompson   @param[out] vec        Variable to store CeedVector
7817a982d89SJeremy L. Thompson 
7827a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
7837a982d89SJeremy L. Thompson 
7847a982d89SJeremy L. Thompson   @ref Backend
7857a982d89SJeremy L. Thompson **/
7867a982d89SJeremy L. Thompson 
7877a982d89SJeremy L. Thompson int CeedOperatorFieldGetVector(CeedOperatorField opfield, CeedVector *vec) {
7887a982d89SJeremy L. Thompson   *vec = opfield->vec;
789*e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
7907a982d89SJeremy L. Thompson }
7917a982d89SJeremy L. Thompson 
7927a982d89SJeremy L. Thompson /// @}
7937a982d89SJeremy L. Thompson 
7947a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
7957a982d89SJeremy L. Thompson /// CeedOperator Public API
7967a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
7977a982d89SJeremy L. Thompson /// @addtogroup CeedOperatorUser
798dfdf5a53Sjeremylt /// @{
799d7b241e6Sjeremylt 
800d7b241e6Sjeremylt /**
8010219ea01SJeremy L Thompson   @brief Create a CeedOperator and associate a CeedQFunction. A CeedBasis and
8020219ea01SJeremy L Thompson            CeedElemRestriction can be associated with CeedQFunction fields with
8030219ea01SJeremy L Thompson            \ref CeedOperatorSetField.
804d7b241e6Sjeremylt 
805b11c1e72Sjeremylt   @param ceed    A Ceed object where the CeedOperator will be created
806d7b241e6Sjeremylt   @param qf      QFunction defining the action of the operator at quadrature points
80734138859Sjeremylt   @param dqf     QFunction defining the action of the Jacobian of @a qf (or
8084cc79fe7SJed Brown                    @ref CEED_QFUNCTION_NONE)
809d7b241e6Sjeremylt   @param dqfT    QFunction defining the action of the transpose of the Jacobian
8104cc79fe7SJed Brown                    of @a qf (or @ref CEED_QFUNCTION_NONE)
811b11c1e72Sjeremylt   @param[out] op Address of the variable where the newly created
812b11c1e72Sjeremylt                      CeedOperator will be stored
813b11c1e72Sjeremylt 
814b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
815dfdf5a53Sjeremylt 
8167a982d89SJeremy L. Thompson   @ref User
817d7b241e6Sjeremylt  */
818d7b241e6Sjeremylt int CeedOperatorCreate(Ceed ceed, CeedQFunction qf, CeedQFunction dqf,
819d7b241e6Sjeremylt                        CeedQFunction dqfT, CeedOperator *op) {
820d7b241e6Sjeremylt   int ierr;
821d7b241e6Sjeremylt 
8225fe0d4faSjeremylt   if (!ceed->OperatorCreate) {
8235fe0d4faSjeremylt     Ceed delegate;
824aefd8378Sjeremylt     ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr);
8255fe0d4faSjeremylt 
8265fe0d4faSjeremylt     if (!delegate)
827c042f62fSJeremy L Thompson       // LCOV_EXCL_START
828*e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_UNSUPPORTED,
829*e15f9bd0SJeremy L Thompson                        "Backend does not support OperatorCreate");
830c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
8315fe0d4faSjeremylt 
8325fe0d4faSjeremylt     ierr = CeedOperatorCreate(delegate, qf, dqf, dqfT, op); CeedChk(ierr);
833*e15f9bd0SJeremy L Thompson     return CEED_ERROR_SUCCESS;
8345fe0d4faSjeremylt   }
8355fe0d4faSjeremylt 
836b3b7035fSJeremy L Thompson   if (!qf || qf == CEED_QFUNCTION_NONE)
837b3b7035fSJeremy L Thompson     // LCOV_EXCL_START
838*e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_MINOR,
839*e15f9bd0SJeremy L Thompson                      "Operator must have a valid QFunction.");
840b3b7035fSJeremy L Thompson   // LCOV_EXCL_STOP
841d7b241e6Sjeremylt   ierr = CeedCalloc(1, op); CeedChk(ierr);
842d7b241e6Sjeremylt   (*op)->ceed = ceed;
843d7b241e6Sjeremylt   ceed->refcount++;
844d7b241e6Sjeremylt   (*op)->refcount = 1;
845d7b241e6Sjeremylt   (*op)->qf = qf;
846d7b241e6Sjeremylt   qf->refcount++;
847442e7f0bSjeremylt   if (dqf && dqf != CEED_QFUNCTION_NONE) {
848d7b241e6Sjeremylt     (*op)->dqf = dqf;
849442e7f0bSjeremylt     dqf->refcount++;
850442e7f0bSjeremylt   }
851442e7f0bSjeremylt   if (dqfT && dqfT != CEED_QFUNCTION_NONE) {
852d7b241e6Sjeremylt     (*op)->dqfT = dqfT;
853442e7f0bSjeremylt     dqfT->refcount++;
854442e7f0bSjeremylt   }
855fe2413ffSjeremylt   ierr = CeedCalloc(16, &(*op)->inputfields); CeedChk(ierr);
856fe2413ffSjeremylt   ierr = CeedCalloc(16, &(*op)->outputfields); CeedChk(ierr);
857d7b241e6Sjeremylt   ierr = ceed->OperatorCreate(*op); CeedChk(ierr);
858*e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
859d7b241e6Sjeremylt }
860d7b241e6Sjeremylt 
861d7b241e6Sjeremylt /**
86252d6035fSJeremy L Thompson   @brief Create an operator that composes the action of several operators
86352d6035fSJeremy L Thompson 
86452d6035fSJeremy L Thompson   @param ceed    A Ceed object where the CeedOperator will be created
86552d6035fSJeremy L Thompson   @param[out] op Address of the variable where the newly created
86652d6035fSJeremy L Thompson                      Composite CeedOperator will be stored
86752d6035fSJeremy L Thompson 
86852d6035fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
86952d6035fSJeremy L Thompson 
8707a982d89SJeremy L. Thompson   @ref User
87152d6035fSJeremy L Thompson  */
87252d6035fSJeremy L Thompson int CeedCompositeOperatorCreate(Ceed ceed, CeedOperator *op) {
87352d6035fSJeremy L Thompson   int ierr;
87452d6035fSJeremy L Thompson 
87552d6035fSJeremy L Thompson   if (!ceed->CompositeOperatorCreate) {
87652d6035fSJeremy L Thompson     Ceed delegate;
877aefd8378Sjeremylt     ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr);
87852d6035fSJeremy L Thompson 
879250756a7Sjeremylt     if (delegate) {
88052d6035fSJeremy L Thompson       ierr = CeedCompositeOperatorCreate(delegate, op); CeedChk(ierr);
881*e15f9bd0SJeremy L Thompson       return CEED_ERROR_SUCCESS;
88252d6035fSJeremy L Thompson     }
883250756a7Sjeremylt   }
88452d6035fSJeremy L Thompson 
88552d6035fSJeremy L Thompson   ierr = CeedCalloc(1, op); CeedChk(ierr);
88652d6035fSJeremy L Thompson   (*op)->ceed = ceed;
88752d6035fSJeremy L Thompson   ceed->refcount++;
88852d6035fSJeremy L Thompson   (*op)->composite = true;
88952d6035fSJeremy L Thompson   ierr = CeedCalloc(16, &(*op)->suboperators); CeedChk(ierr);
890250756a7Sjeremylt 
891250756a7Sjeremylt   if (ceed->CompositeOperatorCreate) {
89252d6035fSJeremy L Thompson     ierr = ceed->CompositeOperatorCreate(*op); CeedChk(ierr);
893250756a7Sjeremylt   }
894*e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
89552d6035fSJeremy L Thompson }
89652d6035fSJeremy L Thompson 
89752d6035fSJeremy L Thompson /**
898b11c1e72Sjeremylt   @brief Provide a field to a CeedOperator for use by its CeedQFunction
899d7b241e6Sjeremylt 
900d7b241e6Sjeremylt   This function is used to specify both active and passive fields to a
901d7b241e6Sjeremylt   CeedOperator.  For passive fields, a vector @arg v must be provided.  Passive
902d7b241e6Sjeremylt   fields can inputs or outputs (updated in-place when operator is applied).
903d7b241e6Sjeremylt 
904d7b241e6Sjeremylt   Active fields must be specified using this function, but their data (in a
905d7b241e6Sjeremylt   CeedVector) is passed in CeedOperatorApply().  There can be at most one active
906d7b241e6Sjeremylt   input and at most one active output.
907d7b241e6Sjeremylt 
9088c91a0c9SJeremy L Thompson   @param op         CeedOperator on which to provide the field
9098795c945Sjeremylt   @param fieldname  Name of the field (to be matched with the name used by
9108795c945Sjeremylt                       CeedQFunction)
911b11c1e72Sjeremylt   @param r          CeedElemRestriction
9124cc79fe7SJed Brown   @param b          CeedBasis in which the field resides or @ref CEED_BASIS_COLLOCATED
913b11c1e72Sjeremylt                       if collocated with quadrature points
9144cc79fe7SJed Brown   @param v          CeedVector to be used by CeedOperator or @ref CEED_VECTOR_ACTIVE
9154cc79fe7SJed Brown                       if field is active or @ref CEED_VECTOR_NONE if using
9164cc79fe7SJed Brown                       @ref CEED_EVAL_WEIGHT in the QFunction
917b11c1e72Sjeremylt 
918b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
919dfdf5a53Sjeremylt 
9207a982d89SJeremy L. Thompson   @ref User
921b11c1e72Sjeremylt **/
922d7b241e6Sjeremylt int CeedOperatorSetField(CeedOperator op, const char *fieldname,
923a8d32208Sjeremylt                          CeedElemRestriction r, CeedBasis b, CeedVector v) {
924d7b241e6Sjeremylt   int ierr;
92552d6035fSJeremy L Thompson   if (op->composite)
926c042f62fSJeremy L Thompson     // LCOV_EXCL_START
927*e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
928*e15f9bd0SJeremy L Thompson                      "Cannot add field to composite operator.");
929c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
9308b067b84SJed Brown   if (!r)
931c042f62fSJeremy L Thompson     // LCOV_EXCL_START
932*e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
933c042f62fSJeremy L Thompson                      "ElemRestriction r for field \"%s\" must be non-NULL.",
934c042f62fSJeremy L Thompson                      fieldname);
935c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
9368b067b84SJed Brown   if (!b)
937c042f62fSJeremy L Thompson     // LCOV_EXCL_START
938*e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
939*e15f9bd0SJeremy L Thompson                      "Basis b for field \"%s\" must be non-NULL.",
940c042f62fSJeremy L Thompson                      fieldname);
941c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
9428b067b84SJed Brown   if (!v)
943c042f62fSJeremy L Thompson     // LCOV_EXCL_START
944*e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
945*e15f9bd0SJeremy L Thompson                      "Vector v for field \"%s\" must be non-NULL.",
946c042f62fSJeremy L Thompson                      fieldname);
947c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
94852d6035fSJeremy L Thompson 
949d7b241e6Sjeremylt   CeedInt numelements;
950d7b241e6Sjeremylt   ierr = CeedElemRestrictionGetNumElements(r, &numelements); CeedChk(ierr);
95115910d16Sjeremylt   if (r != CEED_ELEMRESTRICTION_NONE && op->hasrestriction &&
95215910d16Sjeremylt       op->numelements != numelements)
953c042f62fSJeremy L Thompson     // LCOV_EXCL_START
954*e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_DIMENSION,
9551d102b48SJeremy L Thompson                      "ElemRestriction with %d elements incompatible with prior "
9561d102b48SJeremy L Thompson                      "%d elements", numelements, op->numelements);
957c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
958d7b241e6Sjeremylt 
959d7b241e6Sjeremylt   CeedInt numqpoints;
960*e15f9bd0SJeremy L Thompson   if (b != CEED_BASIS_COLLOCATED) {
961d7b241e6Sjeremylt     ierr = CeedBasisGetNumQuadraturePoints(b, &numqpoints); CeedChk(ierr);
962d7b241e6Sjeremylt     if (op->numqpoints && op->numqpoints != numqpoints)
963c042f62fSJeremy L Thompson       // LCOV_EXCL_START
964*e15f9bd0SJeremy L Thompson       return CeedError(op->ceed, CEED_ERROR_DIMENSION,
965*e15f9bd0SJeremy L Thompson                        "Basis with %d quadrature points "
9661d102b48SJeremy L Thompson                        "incompatible with prior %d points", numqpoints,
9671d102b48SJeremy L Thompson                        op->numqpoints);
968c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
969d7b241e6Sjeremylt   }
97015910d16Sjeremylt   CeedQFunctionField qfield;
971d1bcdac9Sjeremylt   CeedOperatorField *ofield;
972d7b241e6Sjeremylt   for (CeedInt i=0; i<op->qf->numinputfields; i++) {
973fe2413ffSjeremylt     if (!strcmp(fieldname, (*op->qf->inputfields[i]).fieldname)) {
97415910d16Sjeremylt       qfield = op->qf->inputfields[i];
975d7b241e6Sjeremylt       ofield = &op->inputfields[i];
976d7b241e6Sjeremylt       goto found;
977d7b241e6Sjeremylt     }
978d7b241e6Sjeremylt   }
979d7b241e6Sjeremylt   for (CeedInt i=0; i<op->qf->numoutputfields; i++) {
980fe2413ffSjeremylt     if (!strcmp(fieldname, (*op->qf->outputfields[i]).fieldname)) {
981*e15f9bd0SJeremy L Thompson       qfield = op->qf->outputfields[i];
982d7b241e6Sjeremylt       ofield = &op->outputfields[i];
983d7b241e6Sjeremylt       goto found;
984d7b241e6Sjeremylt     }
985d7b241e6Sjeremylt   }
986c042f62fSJeremy L Thompson   // LCOV_EXCL_START
987*e15f9bd0SJeremy L Thompson   return CeedError(op->ceed, CEED_ERROR_INCOMPLETE,
988*e15f9bd0SJeremy L Thompson                    "QFunction has no knowledge of field '%s'",
989d7b241e6Sjeremylt                    fieldname);
990c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
991d7b241e6Sjeremylt found:
992*e15f9bd0SJeremy L Thompson   ierr = CeedOperatorCheckField(op->ceed, qfield, r, b); CeedChk(ierr);
993fe2413ffSjeremylt   ierr = CeedCalloc(1, ofield); CeedChk(ierr);
994*e15f9bd0SJeremy L Thompson 
995*e15f9bd0SJeremy L Thompson   (*ofield)->vec = v;
996*e15f9bd0SJeremy L Thompson   if (v != CEED_VECTOR_ACTIVE && v != CEED_VECTOR_NONE) {
997*e15f9bd0SJeremy L Thompson     v->refcount += 1;
998*e15f9bd0SJeremy L Thompson   }
999*e15f9bd0SJeremy L Thompson 
1000fe2413ffSjeremylt   (*ofield)->Erestrict = r;
100171352a93Sjeremylt   r->refcount += 1;
1002*e15f9bd0SJeremy L Thompson   if (r != CEED_ELEMRESTRICTION_NONE) {
1003*e15f9bd0SJeremy L Thompson     op->numelements = numelements;
1004*e15f9bd0SJeremy L Thompson     op->hasrestriction = true; // Restriction set, but numelements may be 0
1005*e15f9bd0SJeremy L Thompson   }
1006d99fa3c5SJeremy L Thompson 
1007*e15f9bd0SJeremy L Thompson   (*ofield)->basis = b;
1008*e15f9bd0SJeremy L Thompson   if (b != CEED_BASIS_COLLOCATED) {
1009*e15f9bd0SJeremy L Thompson     op->numqpoints = numqpoints;
1010*e15f9bd0SJeremy L Thompson     b->refcount += 1;
1011*e15f9bd0SJeremy L Thompson   }
1012*e15f9bd0SJeremy L Thompson 
1013*e15f9bd0SJeremy L Thompson   op->nfields += 1;
1014d99fa3c5SJeremy L Thompson   size_t len = strlen(fieldname);
1015d99fa3c5SJeremy L Thompson   char *tmp;
1016d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(len+1, &tmp); CeedChk(ierr);
1017d99fa3c5SJeremy L Thompson   memcpy(tmp, fieldname, len+1);
1018d99fa3c5SJeremy L Thompson   (*ofield)->fieldname = tmp;
1019*e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1020d7b241e6Sjeremylt }
1021d7b241e6Sjeremylt 
1022d7b241e6Sjeremylt /**
102352d6035fSJeremy L Thompson   @brief Add a sub-operator to a composite CeedOperator
1024288c0443SJeremy L Thompson 
102534138859Sjeremylt   @param[out] compositeop Composite CeedOperator
102634138859Sjeremylt   @param      subop       Sub-operator CeedOperator
102752d6035fSJeremy L Thompson 
102852d6035fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
102952d6035fSJeremy L Thompson 
10307a982d89SJeremy L. Thompson   @ref User
103152d6035fSJeremy L Thompson  */
1032692c2638Sjeremylt int CeedCompositeOperatorAddSub(CeedOperator compositeop, CeedOperator subop) {
103352d6035fSJeremy L Thompson   if (!compositeop->composite)
1034c042f62fSJeremy L Thompson     // LCOV_EXCL_START
1035*e15f9bd0SJeremy L Thompson     return CeedError(compositeop->ceed, CEED_ERROR_MINOR,
1036*e15f9bd0SJeremy L Thompson                      "CeedOperator is not a composite "
10371d102b48SJeremy L Thompson                      "operator");
1038c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
103952d6035fSJeremy L Thompson 
104052d6035fSJeremy L Thompson   if (compositeop->numsub == CEED_COMPOSITE_MAX)
1041c042f62fSJeremy L Thompson     // LCOV_EXCL_START
1042*e15f9bd0SJeremy L Thompson     return CeedError(compositeop->ceed, CEED_ERROR_UNSUPPORTED,
1043*e15f9bd0SJeremy L Thompson                      "Cannot add additional suboperators");
1044c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
104552d6035fSJeremy L Thompson 
104652d6035fSJeremy L Thompson   compositeop->suboperators[compositeop->numsub] = subop;
104752d6035fSJeremy L Thompson   subop->refcount++;
104852d6035fSJeremy L Thompson   compositeop->numsub++;
1049*e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
105052d6035fSJeremy L Thompson }
105152d6035fSJeremy L Thompson 
105252d6035fSJeremy L Thompson /**
10531d102b48SJeremy L Thompson   @brief Assemble a linear CeedQFunction associated with a CeedOperator
10541d102b48SJeremy L Thompson 
10551d102b48SJeremy L Thompson   This returns a CeedVector containing a matrix at each quadrature point
10561d102b48SJeremy L Thompson     providing the action of the CeedQFunction associated with the CeedOperator.
10571d102b48SJeremy L Thompson     The vector 'assembled' is of shape
10581d102b48SJeremy L Thompson       [num_elements, num_input_fields, num_output_fields, num_quad_points]
10591d102b48SJeremy L Thompson     and contains column-major matrices representing the action of the
10601d102b48SJeremy L Thompson     CeedQFunction for a corresponding quadrature point on an element. Inputs and
10611d102b48SJeremy L Thompson     outputs are in the order provided by the user when adding CeedOperator fields.
10624cc79fe7SJed Brown     For example, a CeedQFunction with inputs 'u' and 'gradu' and outputs 'gradv' and
10631d102b48SJeremy L Thompson     'v', provided in that order, would result in an assembled QFunction that
10641d102b48SJeremy L Thompson     consists of (1 + dim) x (dim + 1) matrices at each quadrature point acting
10651d102b48SJeremy L Thompson     on the input [u, du_0, du_1] and producing the output [dv_0, dv_1, v].
10661d102b48SJeremy L Thompson 
10671d102b48SJeremy L Thompson   @param op             CeedOperator to assemble CeedQFunction
10681d102b48SJeremy L Thompson   @param[out] assembled CeedVector to store assembled CeedQFunction at
10691d102b48SJeremy L Thompson                           quadrature points
10701d102b48SJeremy L Thompson   @param[out] rstr      CeedElemRestriction for CeedVector containing assembled
10711d102b48SJeremy L Thompson                           CeedQFunction
10721d102b48SJeremy L Thompson   @param request        Address of CeedRequest for non-blocking completion, else
10734cc79fe7SJed Brown                           @ref CEED_REQUEST_IMMEDIATE
10741d102b48SJeremy L Thompson 
10751d102b48SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
10761d102b48SJeremy L Thompson 
10777a982d89SJeremy L. Thompson   @ref User
10781d102b48SJeremy L Thompson **/
107980ac2e43SJeremy L Thompson int CeedOperatorLinearAssembleQFunction(CeedOperator op, CeedVector *assembled,
10807f823360Sjeremylt                                         CeedElemRestriction *rstr,
10817f823360Sjeremylt                                         CeedRequest *request) {
10821d102b48SJeremy L Thompson   int ierr;
10831d102b48SJeremy L Thompson   Ceed ceed = op->ceed;
1084250756a7Sjeremylt   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
10851d102b48SJeremy L Thompson 
10867172caadSjeremylt   // Backend version
108780ac2e43SJeremy L Thompson   if (op->LinearAssembleQFunction) {
108880ac2e43SJeremy L Thompson     ierr = op->LinearAssembleQFunction(op, assembled, rstr, request);
10891d102b48SJeremy L Thompson     CeedChk(ierr);
10905107b09fSJeremy L Thompson   } else {
10915107b09fSJeremy L Thompson     // Fallback to reference Ceed
10925107b09fSJeremy L Thompson     if (!op->opfallback) {
10935107b09fSJeremy L Thompson       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
10945107b09fSJeremy L Thompson     }
10955107b09fSJeremy L Thompson     // Assemble
109680ac2e43SJeremy L Thompson     ierr = op->opfallback->LinearAssembleQFunction(op->opfallback, assembled,
10975107b09fSJeremy L Thompson            rstr, request); CeedChk(ierr);
10985107b09fSJeremy L Thompson   }
1099*e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
11001d102b48SJeremy L Thompson }
11011d102b48SJeremy L Thompson 
11021d102b48SJeremy L Thompson /**
1103d965c7a7SJeremy L Thompson   @brief Assemble the diagonal of a square linear CeedOperator
1104b7ec98d8SJeremy L Thompson 
11059e9210b8SJeremy L Thompson   This overwrites a CeedVector with the diagonal of a linear CeedOperator.
1106b7ec98d8SJeremy L Thompson 
1107c04a41a7SJeremy L Thompson   Note: Currently only non-composite CeedOperators with a single field and
1108c04a41a7SJeremy L Thompson           composite CeedOperators with single field sub-operators are supported.
1109d965c7a7SJeremy L Thompson 
1110b7ec98d8SJeremy L Thompson   @param op             CeedOperator to assemble CeedQFunction
1111b7ec98d8SJeremy L Thompson   @param[out] assembled CeedVector to store assembled CeedOperator diagonal
1112b7ec98d8SJeremy L Thompson   @param request        Address of CeedRequest for non-blocking completion, else
11134cc79fe7SJed Brown                           @ref CEED_REQUEST_IMMEDIATE
1114b7ec98d8SJeremy L Thompson 
1115b7ec98d8SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1116b7ec98d8SJeremy L Thompson 
11177a982d89SJeremy L. Thompson   @ref User
1118b7ec98d8SJeremy L Thompson **/
11192bba3ffaSJeremy L Thompson int CeedOperatorLinearAssembleDiagonal(CeedOperator op, CeedVector assembled,
11207f823360Sjeremylt                                        CeedRequest *request) {
1121b7ec98d8SJeremy L Thompson   int ierr;
1122b7ec98d8SJeremy L Thompson   Ceed ceed = op->ceed;
1123250756a7Sjeremylt   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
1124b7ec98d8SJeremy L Thompson 
1125b7ec98d8SJeremy L Thompson   // Use backend version, if available
112680ac2e43SJeremy L Thompson   if (op->LinearAssembleDiagonal) {
112780ac2e43SJeremy L Thompson     ierr = op->LinearAssembleDiagonal(op, assembled, request); CeedChk(ierr);
11289e9210b8SJeremy L Thompson   } else if (op->LinearAssembleAddDiagonal) {
11299e9210b8SJeremy L Thompson     ierr = CeedVectorSetValue(assembled, 0.0); CeedChk(ierr);
11309e9210b8SJeremy L Thompson     return CeedOperatorLinearAssembleAddDiagonal(op, assembled, request);
11319e9210b8SJeremy L Thompson   } else {
11329e9210b8SJeremy L Thompson     // Fallback to reference Ceed
11339e9210b8SJeremy L Thompson     if (!op->opfallback) {
11349e9210b8SJeremy L Thompson       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
11359e9210b8SJeremy L Thompson     }
11369e9210b8SJeremy L Thompson     // Assemble
11379e9210b8SJeremy L Thompson     if (op->opfallback->LinearAssembleDiagonal) {
11389e9210b8SJeremy L Thompson       ierr = op->opfallback->LinearAssembleDiagonal(op->opfallback, assembled,
11399e9210b8SJeremy L Thompson              request); CeedChk(ierr);
11409e9210b8SJeremy L Thompson     } else {
11419e9210b8SJeremy L Thompson       ierr = CeedVectorSetValue(assembled, 0.0); CeedChk(ierr);
11429e9210b8SJeremy L Thompson       return CeedOperatorLinearAssembleAddDiagonal(op, assembled, request);
11439e9210b8SJeremy L Thompson     }
11449e9210b8SJeremy L Thompson   }
1145*e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
11469e9210b8SJeremy L Thompson }
11479e9210b8SJeremy L Thompson 
11489e9210b8SJeremy L Thompson /**
11499e9210b8SJeremy L Thompson   @brief Assemble the diagonal of a square linear CeedOperator
11509e9210b8SJeremy L Thompson 
11519e9210b8SJeremy L Thompson   This sums into a CeedVector the diagonal of a linear CeedOperator.
11529e9210b8SJeremy L Thompson 
11539e9210b8SJeremy L Thompson   Note: Currently only non-composite CeedOperators with a single field and
11549e9210b8SJeremy L Thompson           composite CeedOperators with single field sub-operators are supported.
11559e9210b8SJeremy L Thompson 
11569e9210b8SJeremy L Thompson   @param op             CeedOperator to assemble CeedQFunction
11579e9210b8SJeremy L Thompson   @param[out] assembled CeedVector to store assembled CeedOperator diagonal
11589e9210b8SJeremy L Thompson   @param request        Address of CeedRequest for non-blocking completion, else
11599e9210b8SJeremy L Thompson                           @ref CEED_REQUEST_IMMEDIATE
11609e9210b8SJeremy L Thompson 
11619e9210b8SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
11629e9210b8SJeremy L Thompson 
11639e9210b8SJeremy L Thompson   @ref User
11649e9210b8SJeremy L Thompson **/
11659e9210b8SJeremy L Thompson int CeedOperatorLinearAssembleAddDiagonal(CeedOperator op, CeedVector assembled,
11669e9210b8SJeremy L Thompson     CeedRequest *request) {
11679e9210b8SJeremy L Thompson   int ierr;
11689e9210b8SJeremy L Thompson   Ceed ceed = op->ceed;
11699e9210b8SJeremy L Thompson   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
11709e9210b8SJeremy L Thompson 
11719e9210b8SJeremy L Thompson   // Use backend version, if available
11729e9210b8SJeremy L Thompson   if (op->LinearAssembleAddDiagonal) {
11739e9210b8SJeremy L Thompson     ierr = op->LinearAssembleAddDiagonal(op, assembled, request); CeedChk(ierr);
11747172caadSjeremylt   } else {
11757172caadSjeremylt     // Fallback to reference Ceed
11767172caadSjeremylt     if (!op->opfallback) {
11777172caadSjeremylt       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
1178b7ec98d8SJeremy L Thompson     }
11797172caadSjeremylt     // Assemble
11809e9210b8SJeremy L Thompson     ierr = op->opfallback->LinearAssembleAddDiagonal(op->opfallback, assembled,
11817172caadSjeremylt            request); CeedChk(ierr);
1182b7ec98d8SJeremy L Thompson   }
1183*e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1184b7ec98d8SJeremy L Thompson }
1185b7ec98d8SJeremy L Thompson 
1186b7ec98d8SJeremy L Thompson /**
1187d965c7a7SJeremy L Thompson   @brief Assemble the point block diagonal of a square linear CeedOperator
1188d965c7a7SJeremy L Thompson 
11899e9210b8SJeremy L Thompson   This overwrites a CeedVector with the point block diagonal of a linear
1190d965c7a7SJeremy L Thompson     CeedOperator.
1191d965c7a7SJeremy L Thompson 
1192c04a41a7SJeremy L Thompson   Note: Currently only non-composite CeedOperators with a single field and
1193c04a41a7SJeremy L Thompson           composite CeedOperators with single field sub-operators are supported.
1194d965c7a7SJeremy L Thompson 
1195d965c7a7SJeremy L Thompson   @param op             CeedOperator to assemble CeedQFunction
1196d965c7a7SJeremy L Thompson   @param[out] assembled CeedVector to store assembled CeedOperator point block
1197d965c7a7SJeremy L Thompson                           diagonal, provided in row-major form with an
1198d965c7a7SJeremy L Thompson                           @a ncomp * @a ncomp block at each node. The dimensions
1199d965c7a7SJeremy L Thompson                           of this vector are derived from the active vector
1200d965c7a7SJeremy L Thompson                           for the CeedOperator. The array has shape
1201d965c7a7SJeremy L Thompson                           [nodes, component out, component in].
1202d965c7a7SJeremy L Thompson   @param request        Address of CeedRequest for non-blocking completion, else
1203d965c7a7SJeremy L Thompson                           CEED_REQUEST_IMMEDIATE
1204d965c7a7SJeremy L Thompson 
1205d965c7a7SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1206d965c7a7SJeremy L Thompson 
1207d965c7a7SJeremy L Thompson   @ref User
1208d965c7a7SJeremy L Thompson **/
120980ac2e43SJeremy L Thompson int CeedOperatorLinearAssemblePointBlockDiagonal(CeedOperator op,
12102bba3ffaSJeremy L Thompson     CeedVector assembled, CeedRequest *request) {
1211d965c7a7SJeremy L Thompson   int ierr;
1212d965c7a7SJeremy L Thompson   Ceed ceed = op->ceed;
1213d965c7a7SJeremy L Thompson   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
1214d965c7a7SJeremy L Thompson 
1215d965c7a7SJeremy L Thompson   // Use backend version, if available
121680ac2e43SJeremy L Thompson   if (op->LinearAssemblePointBlockDiagonal) {
121780ac2e43SJeremy L Thompson     ierr = op->LinearAssemblePointBlockDiagonal(op, assembled, request);
1218d965c7a7SJeremy L Thompson     CeedChk(ierr);
12199e9210b8SJeremy L Thompson   } else if (op->LinearAssembleAddPointBlockDiagonal) {
12209e9210b8SJeremy L Thompson     ierr = CeedVectorSetValue(assembled, 0.0); CeedChk(ierr);
12219e9210b8SJeremy L Thompson     return CeedOperatorLinearAssembleAddPointBlockDiagonal(op, assembled,
12229e9210b8SJeremy L Thompson            request);
1223d965c7a7SJeremy L Thompson   } else {
1224d965c7a7SJeremy L Thompson     // Fallback to reference Ceed
1225d965c7a7SJeremy L Thompson     if (!op->opfallback) {
1226d965c7a7SJeremy L Thompson       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
1227d965c7a7SJeremy L Thompson     }
1228d965c7a7SJeremy L Thompson     // Assemble
12299e9210b8SJeremy L Thompson     if (op->opfallback->LinearAssemblePointBlockDiagonal) {
123080ac2e43SJeremy L Thompson       ierr = op->opfallback->LinearAssemblePointBlockDiagonal(op->opfallback,
1231d965c7a7SJeremy L Thompson              assembled, request); CeedChk(ierr);
12329e9210b8SJeremy L Thompson     } else {
12339e9210b8SJeremy L Thompson       ierr = CeedVectorSetValue(assembled, 0.0); CeedChk(ierr);
12349e9210b8SJeremy L Thompson       return CeedOperatorLinearAssembleAddPointBlockDiagonal(op, assembled,
12359e9210b8SJeremy L Thompson              request);
12369e9210b8SJeremy L Thompson     }
12379e9210b8SJeremy L Thompson   }
1238*e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
12399e9210b8SJeremy L Thompson }
12409e9210b8SJeremy L Thompson 
12419e9210b8SJeremy L Thompson /**
12429e9210b8SJeremy L Thompson   @brief Assemble the point block diagonal of a square linear CeedOperator
12439e9210b8SJeremy L Thompson 
12449e9210b8SJeremy L Thompson   This sums into a CeedVector with the point block diagonal of a linear
12459e9210b8SJeremy L Thompson     CeedOperator.
12469e9210b8SJeremy L Thompson 
12479e9210b8SJeremy L Thompson   Note: Currently only non-composite CeedOperators with a single field and
12489e9210b8SJeremy L Thompson           composite CeedOperators with single field sub-operators are supported.
12499e9210b8SJeremy L Thompson 
12509e9210b8SJeremy L Thompson   @param op             CeedOperator to assemble CeedQFunction
12519e9210b8SJeremy L Thompson   @param[out] assembled CeedVector to store assembled CeedOperator point block
12529e9210b8SJeremy L Thompson                           diagonal, provided in row-major form with an
12539e9210b8SJeremy L Thompson                           @a ncomp * @a ncomp block at each node. The dimensions
12549e9210b8SJeremy L Thompson                           of this vector are derived from the active vector
12559e9210b8SJeremy L Thompson                           for the CeedOperator. The array has shape
12569e9210b8SJeremy L Thompson                           [nodes, component out, component in].
12579e9210b8SJeremy L Thompson   @param request        Address of CeedRequest for non-blocking completion, else
12589e9210b8SJeremy L Thompson                           CEED_REQUEST_IMMEDIATE
12599e9210b8SJeremy L Thompson 
12609e9210b8SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
12619e9210b8SJeremy L Thompson 
12629e9210b8SJeremy L Thompson   @ref User
12639e9210b8SJeremy L Thompson **/
12649e9210b8SJeremy L Thompson int CeedOperatorLinearAssembleAddPointBlockDiagonal(CeedOperator op,
12659e9210b8SJeremy L Thompson     CeedVector assembled, CeedRequest *request) {
12669e9210b8SJeremy L Thompson   int ierr;
12679e9210b8SJeremy L Thompson   Ceed ceed = op->ceed;
12689e9210b8SJeremy L Thompson   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
12699e9210b8SJeremy L Thompson 
12709e9210b8SJeremy L Thompson   // Use backend version, if available
12719e9210b8SJeremy L Thompson   if (op->LinearAssembleAddPointBlockDiagonal) {
12729e9210b8SJeremy L Thompson     ierr = op->LinearAssembleAddPointBlockDiagonal(op, assembled, request);
12739e9210b8SJeremy L Thompson     CeedChk(ierr);
12749e9210b8SJeremy L Thompson   } else {
12759e9210b8SJeremy L Thompson     // Fallback to reference Ceed
12769e9210b8SJeremy L Thompson     if (!op->opfallback) {
12779e9210b8SJeremy L Thompson       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
12789e9210b8SJeremy L Thompson     }
12799e9210b8SJeremy L Thompson     // Assemble
12809e9210b8SJeremy L Thompson     ierr = op->opfallback->LinearAssembleAddPointBlockDiagonal(op->opfallback,
12819e9210b8SJeremy L Thompson            assembled, request); CeedChk(ierr);
1282d965c7a7SJeremy L Thompson   }
1283*e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1284d965c7a7SJeremy L Thompson }
1285d965c7a7SJeremy L Thompson 
1286d965c7a7SJeremy L Thompson /**
1287d99fa3c5SJeremy L Thompson   @brief Create a multigrid coarse operator and level transfer operators
1288d99fa3c5SJeremy L Thompson            for a CeedOperator, creating the prolongation basis from the
1289d99fa3c5SJeremy L Thompson            fine and coarse grid interpolation
1290d99fa3c5SJeremy L Thompson 
1291d99fa3c5SJeremy L Thompson   @param[in] opFine       Fine grid operator
1292d99fa3c5SJeremy L Thompson   @param[in] PMultFine    L-vector multiplicity in parallel gather/scatter
1293d99fa3c5SJeremy L Thompson   @param[in] rstrCoarse   Coarse grid restriction
1294d99fa3c5SJeremy L Thompson   @param[in] basisCoarse  Coarse grid active vector basis
1295d99fa3c5SJeremy L Thompson   @param[out] opCoarse    Coarse grid operator
1296d99fa3c5SJeremy L Thompson   @param[out] opProlong   Coarse to fine operator
1297d99fa3c5SJeremy L Thompson   @param[out] opRestrict  Fine to coarse operator
1298d99fa3c5SJeremy L Thompson 
1299d99fa3c5SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1300d99fa3c5SJeremy L Thompson 
1301d99fa3c5SJeremy L Thompson   @ref User
1302d99fa3c5SJeremy L Thompson **/
1303d99fa3c5SJeremy L Thompson int CeedOperatorMultigridLevelCreate(CeedOperator opFine, CeedVector PMultFine,
1304d99fa3c5SJeremy L Thompson                                      CeedElemRestriction rstrCoarse, CeedBasis basisCoarse,
1305d99fa3c5SJeremy L Thompson                                      CeedOperator *opCoarse, CeedOperator *opProlong, CeedOperator *opRestrict) {
1306d99fa3c5SJeremy L Thompson   int ierr;
1307d99fa3c5SJeremy L Thompson   Ceed ceed;
1308d99fa3c5SJeremy L Thompson   ierr = CeedOperatorGetCeed(opFine, &ceed); CeedChk(ierr);
1309d99fa3c5SJeremy L Thompson 
1310d99fa3c5SJeremy L Thompson   // Check for compatible quadrature spaces
1311d99fa3c5SJeremy L Thompson   CeedBasis basisFine;
1312d99fa3c5SJeremy L Thompson   ierr = CeedOperatorGetActiveBasis(opFine, &basisFine); CeedChk(ierr);
1313d99fa3c5SJeremy L Thompson   CeedInt Qf, Qc;
1314d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumQuadraturePoints(basisFine, &Qf); CeedChk(ierr);
1315d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumQuadraturePoints(basisCoarse, &Qc); CeedChk(ierr);
1316d99fa3c5SJeremy L Thompson   if (Qf != Qc)
1317d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
1318*e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_DIMENSION,
1319*e15f9bd0SJeremy L Thompson                      "Bases must have compatible quadrature spaces");
1320d99fa3c5SJeremy L Thompson   // LCOV_EXCL_STOP
1321d99fa3c5SJeremy L Thompson 
1322d99fa3c5SJeremy L Thompson   // Coarse to fine basis
1323d99fa3c5SJeremy L Thompson   CeedInt Pf, Pc, Q = Qf;
1324d99fa3c5SJeremy L Thompson   bool isTensorF, isTensorC;
1325d99fa3c5SJeremy L Thompson   ierr = CeedBasisIsTensor(basisFine, &isTensorF); CeedChk(ierr);
1326d99fa3c5SJeremy L Thompson   ierr = CeedBasisIsTensor(basisCoarse, &isTensorC); CeedChk(ierr);
1327d99fa3c5SJeremy L Thompson   CeedScalar *interpC, *interpF, *interpCtoF, *tau;
1328d99fa3c5SJeremy L Thompson   if (isTensorF && isTensorC) {
1329d99fa3c5SJeremy L Thompson     ierr = CeedBasisGetNumNodes1D(basisFine, &Pf); CeedChk(ierr);
1330d99fa3c5SJeremy L Thompson     ierr = CeedBasisGetNumNodes1D(basisCoarse, &Pc); CeedChk(ierr);
1331d99fa3c5SJeremy L Thompson     ierr = CeedBasisGetNumQuadraturePoints1D(basisCoarse, &Q); CeedChk(ierr);
1332d99fa3c5SJeremy L Thompson   } else if (!isTensorF && !isTensorC) {
1333d99fa3c5SJeremy L Thompson     ierr = CeedBasisGetNumNodes(basisFine, &Pf); CeedChk(ierr);
1334d99fa3c5SJeremy L Thompson     ierr = CeedBasisGetNumNodes(basisCoarse, &Pc); CeedChk(ierr);
1335d99fa3c5SJeremy L Thompson   } else {
1336d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
1337*e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_MINOR,
1338*e15f9bd0SJeremy L Thompson                      "Bases must both be tensor or non-tensor");
1339d99fa3c5SJeremy L Thompson     // LCOV_EXCL_STOP
1340d99fa3c5SJeremy L Thompson   }
1341d99fa3c5SJeremy L Thompson 
1342d99fa3c5SJeremy L Thompson   ierr = CeedMalloc(Q*Pf, &interpF); CeedChk(ierr);
1343d99fa3c5SJeremy L Thompson   ierr = CeedMalloc(Q*Pc, &interpC); CeedChk(ierr);
1344d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(Pc*Pf, &interpCtoF); CeedChk(ierr);
1345d99fa3c5SJeremy L Thompson   ierr = CeedMalloc(Q, &tau); CeedChk(ierr);
1346d99fa3c5SJeremy L Thompson   if (isTensorF) {
1347d99fa3c5SJeremy L Thompson     memcpy(interpF, basisFine->interp1d, Q*Pf*sizeof basisFine->interp1d[0]);
1348d99fa3c5SJeremy L Thompson     memcpy(interpC, basisCoarse->interp1d, Q*Pc*sizeof basisCoarse->interp1d[0]);
1349d99fa3c5SJeremy L Thompson   } else {
1350d99fa3c5SJeremy L Thompson     memcpy(interpF, basisFine->interp, Q*Pf*sizeof basisFine->interp[0]);
1351d99fa3c5SJeremy L Thompson     memcpy(interpC, basisCoarse->interp, Q*Pc*sizeof basisCoarse->interp[0]);
1352d99fa3c5SJeremy L Thompson   }
1353d99fa3c5SJeremy L Thompson 
1354d99fa3c5SJeremy L Thompson   // -- QR Factorization, interpF = Q R
1355d99fa3c5SJeremy L Thompson   ierr = CeedQRFactorization(ceed, interpF, tau, Q, Pf); CeedChk(ierr);
1356d99fa3c5SJeremy L Thompson 
1357d99fa3c5SJeremy L Thompson   // -- Apply Qtranspose, interpC = Qtranspose interpC
1358d99fa3c5SJeremy L Thompson   CeedHouseholderApplyQ(interpC, interpF, tau, CEED_TRANSPOSE,
1359d99fa3c5SJeremy L Thompson                         Q, Pc, Pf, Pc, 1);
1360d99fa3c5SJeremy L Thompson 
1361d99fa3c5SJeremy L Thompson   // -- Apply Rinv, interpCtoF = Rinv interpC
1362d99fa3c5SJeremy L Thompson   for (CeedInt j=0; j<Pc; j++) { // Column j
1363d99fa3c5SJeremy L Thompson     interpCtoF[j+Pc*(Pf-1)] = interpC[j+Pc*(Pf-1)]/interpF[Pf*Pf-1];
1364d99fa3c5SJeremy L Thompson     for (CeedInt i=Pf-2; i>=0; i--) { // Row i
1365d99fa3c5SJeremy L Thompson       interpCtoF[j+Pc*i] = interpC[j+Pc*i];
1366d99fa3c5SJeremy L Thompson       for (CeedInt k=i+1; k<Pf; k++)
1367d99fa3c5SJeremy L Thompson         interpCtoF[j+Pc*i] -= interpF[k+Pf*i]*interpCtoF[j+Pc*k];
1368d99fa3c5SJeremy L Thompson       interpCtoF[j+Pc*i] /= interpF[i+Pf*i];
1369d99fa3c5SJeremy L Thompson     }
1370d99fa3c5SJeremy L Thompson   }
1371d99fa3c5SJeremy L Thompson   ierr = CeedFree(&tau); CeedChk(ierr);
1372d99fa3c5SJeremy L Thompson   ierr = CeedFree(&interpC); CeedChk(ierr);
1373d99fa3c5SJeremy L Thompson   ierr = CeedFree(&interpF); CeedChk(ierr);
1374d99fa3c5SJeremy L Thompson 
1375*e15f9bd0SJeremy L Thompson   // Complete with interpCtoF versions of code
1376d99fa3c5SJeremy L Thompson   if (isTensorF) {
1377d99fa3c5SJeremy L Thompson     ierr = CeedOperatorMultigridLevelCreateTensorH1(opFine, PMultFine,
1378d99fa3c5SJeremy L Thompson            rstrCoarse, basisCoarse, interpCtoF, opCoarse, opProlong, opRestrict);
1379d99fa3c5SJeremy L Thompson     CeedChk(ierr);
1380d99fa3c5SJeremy L Thompson   } else {
1381d99fa3c5SJeremy L Thompson     ierr = CeedOperatorMultigridLevelCreateH1(opFine, PMultFine,
1382d99fa3c5SJeremy L Thompson            rstrCoarse, basisCoarse, interpCtoF, opCoarse, opProlong, opRestrict);
1383d99fa3c5SJeremy L Thompson     CeedChk(ierr);
1384d99fa3c5SJeremy L Thompson   }
1385d99fa3c5SJeremy L Thompson 
1386d99fa3c5SJeremy L Thompson   // Cleanup
1387d99fa3c5SJeremy L Thompson   ierr = CeedFree(&interpCtoF); CeedChk(ierr);
1388*e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1389d99fa3c5SJeremy L Thompson }
1390d99fa3c5SJeremy L Thompson 
1391d99fa3c5SJeremy L Thompson /**
1392d99fa3c5SJeremy L Thompson   @brief Create a multigrid coarse operator and level transfer operators
1393d99fa3c5SJeremy L Thompson            for a CeedOperator with a tensor basis for the active basis
1394d99fa3c5SJeremy L Thompson 
1395d99fa3c5SJeremy L Thompson   @param[in] opFine       Fine grid operator
1396d99fa3c5SJeremy L Thompson   @param[in] PMultFine    L-vector multiplicity in parallel gather/scatter
1397d99fa3c5SJeremy L Thompson   @param[in] rstrCoarse   Coarse grid restriction
1398d99fa3c5SJeremy L Thompson   @param[in] basisCoarse  Coarse grid active vector basis
1399d99fa3c5SJeremy L Thompson   @param[in] interpCtoF   Matrix for coarse to fine interpolation
1400d99fa3c5SJeremy L Thompson   @param[out] opCoarse    Coarse grid operator
1401d99fa3c5SJeremy L Thompson   @param[out] opProlong   Coarse to fine operator
1402d99fa3c5SJeremy L Thompson   @param[out] opRestrict  Fine to coarse operator
1403d99fa3c5SJeremy L Thompson 
1404d99fa3c5SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1405d99fa3c5SJeremy L Thompson 
1406d99fa3c5SJeremy L Thompson   @ref User
1407d99fa3c5SJeremy L Thompson **/
1408d99fa3c5SJeremy L Thompson int CeedOperatorMultigridLevelCreateTensorH1(CeedOperator opFine,
1409d99fa3c5SJeremy L Thompson     CeedVector PMultFine, CeedElemRestriction rstrCoarse, CeedBasis basisCoarse,
1410d99fa3c5SJeremy L Thompson     const CeedScalar *interpCtoF, CeedOperator *opCoarse,
1411d99fa3c5SJeremy L Thompson     CeedOperator *opProlong, CeedOperator *opRestrict) {
1412d99fa3c5SJeremy L Thompson   int ierr;
1413d99fa3c5SJeremy L Thompson   Ceed ceed;
1414d99fa3c5SJeremy L Thompson   ierr = CeedOperatorGetCeed(opFine, &ceed); CeedChk(ierr);
1415d99fa3c5SJeremy L Thompson 
1416d99fa3c5SJeremy L Thompson   // Check for compatible quadrature spaces
1417d99fa3c5SJeremy L Thompson   CeedBasis basisFine;
1418d99fa3c5SJeremy L Thompson   ierr = CeedOperatorGetActiveBasis(opFine, &basisFine); CeedChk(ierr);
1419d99fa3c5SJeremy L Thompson   CeedInt Qf, Qc;
1420d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumQuadraturePoints(basisFine, &Qf); CeedChk(ierr);
1421d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumQuadraturePoints(basisCoarse, &Qc); CeedChk(ierr);
1422d99fa3c5SJeremy L Thompson   if (Qf != Qc)
1423d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
1424*e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_DIMENSION,
1425*e15f9bd0SJeremy L Thompson                      "Bases must have compatible quadrature spaces");
1426d99fa3c5SJeremy L Thompson   // LCOV_EXCL_STOP
1427d99fa3c5SJeremy L Thompson 
1428d99fa3c5SJeremy L Thompson   // Coarse to fine basis
1429d99fa3c5SJeremy L Thompson   CeedInt dim, ncomp, nnodesCoarse, P1dFine, P1dCoarse;
1430d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetDimension(basisFine, &dim); CeedChk(ierr);
1431d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumComponents(basisFine, &ncomp); CeedChk(ierr);
1432d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumNodes1D(basisFine, &P1dFine); CeedChk(ierr);
1433d99fa3c5SJeremy L Thompson   ierr = CeedElemRestrictionGetElementSize(rstrCoarse, &nnodesCoarse);
1434d99fa3c5SJeremy L Thompson   CeedChk(ierr);
1435d99fa3c5SJeremy L Thompson   P1dCoarse = dim == 1 ? nnodesCoarse :
1436d99fa3c5SJeremy L Thompson               dim == 2 ? sqrt(nnodesCoarse) :
1437d99fa3c5SJeremy L Thompson               cbrt(nnodesCoarse);
1438d99fa3c5SJeremy L Thompson   CeedScalar *qref, *qweight, *grad;
1439d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(P1dFine, &qref); CeedChk(ierr);
1440d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(P1dFine, &qweight); CeedChk(ierr);
1441d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(P1dFine*P1dCoarse*dim, &grad); CeedChk(ierr);
1442d99fa3c5SJeremy L Thompson   CeedBasis basisCtoF;
1443d99fa3c5SJeremy L Thompson   ierr = CeedBasisCreateTensorH1(ceed, dim, ncomp, P1dCoarse, P1dFine,
1444d99fa3c5SJeremy L Thompson                                  interpCtoF, grad, qref, qweight, &basisCtoF);
1445d99fa3c5SJeremy L Thompson   CeedChk(ierr);
1446d99fa3c5SJeremy L Thompson   ierr = CeedFree(&qref); CeedChk(ierr);
1447d99fa3c5SJeremy L Thompson   ierr = CeedFree(&qweight); CeedChk(ierr);
1448d99fa3c5SJeremy L Thompson   ierr = CeedFree(&grad); CeedChk(ierr);
1449d99fa3c5SJeremy L Thompson 
1450d99fa3c5SJeremy L Thompson   // Core code
1451d99fa3c5SJeremy L Thompson   ierr = CeedOperatorMultigridLevel_Core(opFine, PMultFine, rstrCoarse,
1452d99fa3c5SJeremy L Thompson                                          basisCoarse, basisCtoF, opCoarse,
1453d99fa3c5SJeremy L Thompson                                          opProlong, opRestrict);
1454d99fa3c5SJeremy L Thompson   CeedChk(ierr);
1455*e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1456d99fa3c5SJeremy L Thompson }
1457d99fa3c5SJeremy L Thompson 
1458d99fa3c5SJeremy L Thompson /**
1459d99fa3c5SJeremy L Thompson   @brief Create a multigrid coarse operator and level transfer operators
1460d99fa3c5SJeremy L Thompson            for a CeedOperator with a non-tensor basis for the active vector
1461d99fa3c5SJeremy L Thompson 
1462d99fa3c5SJeremy L Thompson   @param[in] opFine       Fine grid operator
1463d99fa3c5SJeremy L Thompson   @param[in] PMultFine    L-vector multiplicity in parallel gather/scatter
1464d99fa3c5SJeremy L Thompson   @param[in] rstrCoarse   Coarse grid restriction
1465d99fa3c5SJeremy L Thompson   @param[in] basisCoarse  Coarse grid active vector basis
1466d99fa3c5SJeremy L Thompson   @param[in] interpCtoF   Matrix for coarse to fine interpolation
1467d99fa3c5SJeremy L Thompson   @param[out] opCoarse    Coarse grid operator
1468d99fa3c5SJeremy L Thompson   @param[out] opProlong   Coarse to fine operator
1469d99fa3c5SJeremy L Thompson   @param[out] opRestrict  Fine to coarse operator
1470d99fa3c5SJeremy L Thompson 
1471d99fa3c5SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1472d99fa3c5SJeremy L Thompson 
1473d99fa3c5SJeremy L Thompson   @ref User
1474d99fa3c5SJeremy L Thompson **/
1475d99fa3c5SJeremy L Thompson int CeedOperatorMultigridLevelCreateH1(CeedOperator opFine,
1476d99fa3c5SJeremy L Thompson                                        CeedVector PMultFine,
1477d99fa3c5SJeremy L Thompson                                        CeedElemRestriction rstrCoarse,
1478d99fa3c5SJeremy L Thompson                                        CeedBasis basisCoarse,
1479d99fa3c5SJeremy L Thompson                                        const CeedScalar *interpCtoF,
1480d99fa3c5SJeremy L Thompson                                        CeedOperator *opCoarse,
1481d99fa3c5SJeremy L Thompson                                        CeedOperator *opProlong,
1482d99fa3c5SJeremy L Thompson                                        CeedOperator *opRestrict) {
1483d99fa3c5SJeremy L Thompson   int ierr;
1484d99fa3c5SJeremy L Thompson   Ceed ceed;
1485d99fa3c5SJeremy L Thompson   ierr = CeedOperatorGetCeed(opFine, &ceed); CeedChk(ierr);
1486d99fa3c5SJeremy L Thompson 
1487d99fa3c5SJeremy L Thompson   // Check for compatible quadrature spaces
1488d99fa3c5SJeremy L Thompson   CeedBasis basisFine;
1489d99fa3c5SJeremy L Thompson   ierr = CeedOperatorGetActiveBasis(opFine, &basisFine); CeedChk(ierr);
1490d99fa3c5SJeremy L Thompson   CeedInt Qf, Qc;
1491d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumQuadraturePoints(basisFine, &Qf); CeedChk(ierr);
1492d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumQuadraturePoints(basisCoarse, &Qc); CeedChk(ierr);
1493d99fa3c5SJeremy L Thompson   if (Qf != Qc)
1494d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
1495*e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_DIMENSION,
1496*e15f9bd0SJeremy L Thompson                      "Bases must have compatible quadrature spaces");
1497d99fa3c5SJeremy L Thompson   // LCOV_EXCL_STOP
1498d99fa3c5SJeremy L Thompson 
1499d99fa3c5SJeremy L Thompson   // Coarse to fine basis
1500d99fa3c5SJeremy L Thompson   CeedElemTopology topo;
1501d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetTopology(basisFine, &topo); CeedChk(ierr);
1502d99fa3c5SJeremy L Thompson   CeedInt dim, ncomp, nnodesCoarse, nnodesFine;
1503d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetDimension(basisFine, &dim); CeedChk(ierr);
1504d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumComponents(basisFine, &ncomp); CeedChk(ierr);
1505d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumNodes(basisFine, &nnodesFine); CeedChk(ierr);
1506d99fa3c5SJeremy L Thompson   ierr = CeedElemRestrictionGetElementSize(rstrCoarse, &nnodesCoarse);
1507d99fa3c5SJeremy L Thompson   CeedChk(ierr);
1508d99fa3c5SJeremy L Thompson   CeedScalar *qref, *qweight, *grad;
1509d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(nnodesFine, &qref); CeedChk(ierr);
1510d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(nnodesFine, &qweight); CeedChk(ierr);
1511d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(nnodesFine*nnodesCoarse*dim, &grad); CeedChk(ierr);
1512d99fa3c5SJeremy L Thompson   CeedBasis basisCtoF;
1513d99fa3c5SJeremy L Thompson   ierr = CeedBasisCreateH1(ceed, topo, ncomp, nnodesCoarse, nnodesFine,
1514d99fa3c5SJeremy L Thompson                            interpCtoF, grad, qref, qweight, &basisCtoF);
1515d99fa3c5SJeremy L Thompson   CeedChk(ierr);
1516d99fa3c5SJeremy L Thompson   ierr = CeedFree(&qref); CeedChk(ierr);
1517d99fa3c5SJeremy L Thompson   ierr = CeedFree(&qweight); CeedChk(ierr);
1518d99fa3c5SJeremy L Thompson   ierr = CeedFree(&grad); CeedChk(ierr);
1519d99fa3c5SJeremy L Thompson 
1520d99fa3c5SJeremy L Thompson   // Core code
1521d99fa3c5SJeremy L Thompson   ierr = CeedOperatorMultigridLevel_Core(opFine, PMultFine, rstrCoarse,
1522d99fa3c5SJeremy L Thompson                                          basisCoarse, basisCtoF, opCoarse,
1523d99fa3c5SJeremy L Thompson                                          opProlong, opRestrict);
1524d99fa3c5SJeremy L Thompson   CeedChk(ierr);
1525*e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1526d99fa3c5SJeremy L Thompson }
1527d99fa3c5SJeremy L Thompson 
1528d99fa3c5SJeremy L Thompson /**
15293bd813ffSjeremylt   @brief Build a FDM based approximate inverse for each element for a
15303bd813ffSjeremylt            CeedOperator
15313bd813ffSjeremylt 
15323bd813ffSjeremylt   This returns a CeedOperator and CeedVector to apply a Fast Diagonalization
15333bd813ffSjeremylt     Method based approximate inverse. This function obtains the simultaneous
15343bd813ffSjeremylt     diagonalization for the 1D mass and Laplacian operators,
15353bd813ffSjeremylt       M = V^T V, K = V^T S V.
15363bd813ffSjeremylt     The assembled QFunction is used to modify the eigenvalues from simultaneous
15373bd813ffSjeremylt     diagonalization and obtain an approximate inverse of the form
15383bd813ffSjeremylt       V^T S^hat V. The CeedOperator must be linear and non-composite. The
15393bd813ffSjeremylt     associated CeedQFunction must therefore also be linear.
15403bd813ffSjeremylt 
15413bd813ffSjeremylt   @param op             CeedOperator to create element inverses
15423bd813ffSjeremylt   @param[out] fdminv    CeedOperator to apply the action of a FDM based inverse
15433bd813ffSjeremylt                           for each element
15443bd813ffSjeremylt   @param request        Address of CeedRequest for non-blocking completion, else
15454cc79fe7SJed Brown                           @ref CEED_REQUEST_IMMEDIATE
15463bd813ffSjeremylt 
15473bd813ffSjeremylt   @return An error code: 0 - success, otherwise - failure
15483bd813ffSjeremylt 
15497a982d89SJeremy L. Thompson   @ref Backend
15503bd813ffSjeremylt **/
15513bd813ffSjeremylt int CeedOperatorCreateFDMElementInverse(CeedOperator op, CeedOperator *fdminv,
15523bd813ffSjeremylt                                         CeedRequest *request) {
15533bd813ffSjeremylt   int ierr;
15543bd813ffSjeremylt   Ceed ceed = op->ceed;
1555713f43c3Sjeremylt   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
15563bd813ffSjeremylt 
1557713f43c3Sjeremylt   // Use backend version, if available
1558713f43c3Sjeremylt   if (op->CreateFDMElementInverse) {
1559713f43c3Sjeremylt     ierr = op->CreateFDMElementInverse(op, fdminv, request); CeedChk(ierr);
1560713f43c3Sjeremylt   } else {
1561713f43c3Sjeremylt     // Fallback to reference Ceed
1562713f43c3Sjeremylt     if (!op->opfallback) {
1563713f43c3Sjeremylt       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
15643bd813ffSjeremylt     }
1565713f43c3Sjeremylt     // Assemble
1566713f43c3Sjeremylt     ierr = op->opfallback->CreateFDMElementInverse(op->opfallback, fdminv,
15673bd813ffSjeremylt            request); CeedChk(ierr);
15683bd813ffSjeremylt   }
1569*e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
15703bd813ffSjeremylt }
15713bd813ffSjeremylt 
15727a982d89SJeremy L. Thompson /**
15737a982d89SJeremy L. Thompson   @brief View a CeedOperator
15747a982d89SJeremy L. Thompson 
15757a982d89SJeremy L. Thompson   @param[in] op     CeedOperator to view
15767a982d89SJeremy L. Thompson   @param[in] stream Stream to write; typically stdout/stderr or a file
15777a982d89SJeremy L. Thompson 
15787a982d89SJeremy L. Thompson   @return Error code: 0 - success, otherwise - failure
15797a982d89SJeremy L. Thompson 
15807a982d89SJeremy L. Thompson   @ref User
15817a982d89SJeremy L. Thompson **/
15827a982d89SJeremy L. Thompson int CeedOperatorView(CeedOperator op, FILE *stream) {
15837a982d89SJeremy L. Thompson   int ierr;
15847a982d89SJeremy L. Thompson 
15857a982d89SJeremy L. Thompson   if (op->composite) {
15867a982d89SJeremy L. Thompson     fprintf(stream, "Composite CeedOperator\n");
15877a982d89SJeremy L. Thompson 
15887a982d89SJeremy L. Thompson     for (CeedInt i=0; i<op->numsub; i++) {
15897a982d89SJeremy L. Thompson       fprintf(stream, "  SubOperator [%d]:\n", i);
15907a982d89SJeremy L. Thompson       ierr = CeedOperatorSingleView(op->suboperators[i], 1, stream);
15917a982d89SJeremy L. Thompson       CeedChk(ierr);
15927a982d89SJeremy L. Thompson     }
15937a982d89SJeremy L. Thompson   } else {
15947a982d89SJeremy L. Thompson     fprintf(stream, "CeedOperator\n");
15957a982d89SJeremy L. Thompson     ierr = CeedOperatorSingleView(op, 0, stream); CeedChk(ierr);
15967a982d89SJeremy L. Thompson   }
1597*e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
15987a982d89SJeremy L. Thompson }
15993bd813ffSjeremylt 
16003bd813ffSjeremylt /**
16013bd813ffSjeremylt   @brief Apply CeedOperator to a vector
1602d7b241e6Sjeremylt 
1603d7b241e6Sjeremylt   This computes the action of the operator on the specified (active) input,
1604d7b241e6Sjeremylt   yielding its (active) output.  All inputs and outputs must be specified using
1605d7b241e6Sjeremylt   CeedOperatorSetField().
1606d7b241e6Sjeremylt 
1607d7b241e6Sjeremylt   @param op        CeedOperator to apply
16084cc79fe7SJed Brown   @param[in] in    CeedVector containing input state or @ref CEED_VECTOR_NONE if
160934138859Sjeremylt                   there are no active inputs
1610b11c1e72Sjeremylt   @param[out] out  CeedVector to store result of applying operator (must be
16114cc79fe7SJed Brown                      distinct from @a in) or @ref CEED_VECTOR_NONE if there are no
161234138859Sjeremylt                      active outputs
1613d7b241e6Sjeremylt   @param request   Address of CeedRequest for non-blocking completion, else
16144cc79fe7SJed Brown                      @ref CEED_REQUEST_IMMEDIATE
1615b11c1e72Sjeremylt 
1616b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
1617dfdf5a53Sjeremylt 
16187a982d89SJeremy L. Thompson   @ref User
1619b11c1e72Sjeremylt **/
1620692c2638Sjeremylt int CeedOperatorApply(CeedOperator op, CeedVector in, CeedVector out,
1621692c2638Sjeremylt                       CeedRequest *request) {
1622d7b241e6Sjeremylt   int ierr;
1623d7b241e6Sjeremylt   Ceed ceed = op->ceed;
1624250756a7Sjeremylt   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
1625d7b241e6Sjeremylt 
1626250756a7Sjeremylt   if (op->numelements)  {
1627250756a7Sjeremylt     // Standard Operator
1628cae8b89aSjeremylt     if (op->Apply) {
1629250756a7Sjeremylt       ierr = op->Apply(op, in, out, request); CeedChk(ierr);
1630cae8b89aSjeremylt     } else {
1631cae8b89aSjeremylt       // Zero all output vectors
1632250756a7Sjeremylt       CeedQFunction qf = op->qf;
1633cae8b89aSjeremylt       for (CeedInt i=0; i<qf->numoutputfields; i++) {
1634cae8b89aSjeremylt         CeedVector vec = op->outputfields[i]->vec;
1635cae8b89aSjeremylt         if (vec == CEED_VECTOR_ACTIVE)
1636cae8b89aSjeremylt           vec = out;
1637cae8b89aSjeremylt         if (vec != CEED_VECTOR_NONE) {
1638cae8b89aSjeremylt           ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr);
1639cae8b89aSjeremylt         }
1640cae8b89aSjeremylt       }
1641250756a7Sjeremylt       // Apply
1642250756a7Sjeremylt       ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr);
1643250756a7Sjeremylt     }
1644250756a7Sjeremylt   } else if (op->composite) {
1645250756a7Sjeremylt     // Composite Operator
1646250756a7Sjeremylt     if (op->ApplyComposite) {
1647250756a7Sjeremylt       ierr = op->ApplyComposite(op, in, out, request); CeedChk(ierr);
1648250756a7Sjeremylt     } else {
1649250756a7Sjeremylt       CeedInt numsub;
1650250756a7Sjeremylt       ierr = CeedOperatorGetNumSub(op, &numsub); CeedChk(ierr);
1651250756a7Sjeremylt       CeedOperator *suboperators;
1652250756a7Sjeremylt       ierr = CeedOperatorGetSubList(op, &suboperators); CeedChk(ierr);
1653250756a7Sjeremylt 
1654250756a7Sjeremylt       // Zero all output vectors
1655250756a7Sjeremylt       if (out != CEED_VECTOR_NONE) {
1656cae8b89aSjeremylt         ierr = CeedVectorSetValue(out, 0.0); CeedChk(ierr);
1657cae8b89aSjeremylt       }
1658250756a7Sjeremylt       for (CeedInt i=0; i<numsub; i++) {
1659250756a7Sjeremylt         for (CeedInt j=0; j<suboperators[i]->qf->numoutputfields; j++) {
1660250756a7Sjeremylt           CeedVector vec = suboperators[i]->outputfields[j]->vec;
1661250756a7Sjeremylt           if (vec != CEED_VECTOR_ACTIVE && vec != CEED_VECTOR_NONE) {
1662250756a7Sjeremylt             ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr);
1663250756a7Sjeremylt           }
1664250756a7Sjeremylt         }
1665250756a7Sjeremylt       }
1666250756a7Sjeremylt       // Apply
1667250756a7Sjeremylt       for (CeedInt i=0; i<op->numsub; i++) {
1668250756a7Sjeremylt         ierr = CeedOperatorApplyAdd(op->suboperators[i], in, out, request);
1669cae8b89aSjeremylt         CeedChk(ierr);
1670cae8b89aSjeremylt       }
1671cae8b89aSjeremylt     }
1672250756a7Sjeremylt   }
1673*e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1674cae8b89aSjeremylt }
1675cae8b89aSjeremylt 
1676cae8b89aSjeremylt /**
1677cae8b89aSjeremylt   @brief Apply CeedOperator to a vector and add result to output vector
1678cae8b89aSjeremylt 
1679cae8b89aSjeremylt   This computes the action of the operator on the specified (active) input,
1680cae8b89aSjeremylt   yielding its (active) output.  All inputs and outputs must be specified using
1681cae8b89aSjeremylt   CeedOperatorSetField().
1682cae8b89aSjeremylt 
1683cae8b89aSjeremylt   @param op        CeedOperator to apply
1684cae8b89aSjeremylt   @param[in] in    CeedVector containing input state or NULL if there are no
1685cae8b89aSjeremylt                      active inputs
1686cae8b89aSjeremylt   @param[out] out  CeedVector to sum in result of applying operator (must be
1687cae8b89aSjeremylt                      distinct from @a in) or NULL if there are no active outputs
1688cae8b89aSjeremylt   @param request   Address of CeedRequest for non-blocking completion, else
16894cc79fe7SJed Brown                      @ref CEED_REQUEST_IMMEDIATE
1690cae8b89aSjeremylt 
1691cae8b89aSjeremylt   @return An error code: 0 - success, otherwise - failure
1692cae8b89aSjeremylt 
16937a982d89SJeremy L. Thompson   @ref User
1694cae8b89aSjeremylt **/
1695cae8b89aSjeremylt int CeedOperatorApplyAdd(CeedOperator op, CeedVector in, CeedVector out,
1696cae8b89aSjeremylt                          CeedRequest *request) {
1697cae8b89aSjeremylt   int ierr;
1698cae8b89aSjeremylt   Ceed ceed = op->ceed;
1699250756a7Sjeremylt   ierr = CeedOperatorCheckReady(ceed, op); CeedChk(ierr);
1700cae8b89aSjeremylt 
1701250756a7Sjeremylt   if (op->numelements)  {
1702250756a7Sjeremylt     // Standard Operator
1703250756a7Sjeremylt     ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr);
1704250756a7Sjeremylt   } else if (op->composite) {
1705250756a7Sjeremylt     // Composite Operator
1706250756a7Sjeremylt     if (op->ApplyAddComposite) {
1707250756a7Sjeremylt       ierr = op->ApplyAddComposite(op, in, out, request); CeedChk(ierr);
1708cae8b89aSjeremylt     } else {
1709250756a7Sjeremylt       CeedInt numsub;
1710250756a7Sjeremylt       ierr = CeedOperatorGetNumSub(op, &numsub); CeedChk(ierr);
1711250756a7Sjeremylt       CeedOperator *suboperators;
1712250756a7Sjeremylt       ierr = CeedOperatorGetSubList(op, &suboperators); CeedChk(ierr);
1713250756a7Sjeremylt 
1714250756a7Sjeremylt       for (CeedInt i=0; i<numsub; i++) {
1715250756a7Sjeremylt         ierr = CeedOperatorApplyAdd(suboperators[i], in, out, request);
1716cae8b89aSjeremylt         CeedChk(ierr);
17171d7d2407SJeremy L Thompson       }
1718250756a7Sjeremylt     }
1719250756a7Sjeremylt   }
1720*e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1721d7b241e6Sjeremylt }
1722d7b241e6Sjeremylt 
1723d7b241e6Sjeremylt /**
1724b11c1e72Sjeremylt   @brief Destroy a CeedOperator
1725d7b241e6Sjeremylt 
1726d7b241e6Sjeremylt   @param op CeedOperator to destroy
1727b11c1e72Sjeremylt 
1728b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
1729dfdf5a53Sjeremylt 
17307a982d89SJeremy L. Thompson   @ref User
1731b11c1e72Sjeremylt **/
1732d7b241e6Sjeremylt int CeedOperatorDestroy(CeedOperator *op) {
1733d7b241e6Sjeremylt   int ierr;
1734d7b241e6Sjeremylt 
1735*e15f9bd0SJeremy L Thompson   if (!*op || --(*op)->refcount > 0) return CEED_ERROR_SUCCESS;
1736d7b241e6Sjeremylt   if ((*op)->Destroy) {
1737d7b241e6Sjeremylt     ierr = (*op)->Destroy(*op); CeedChk(ierr);
1738d7b241e6Sjeremylt   }
1739fe2413ffSjeremylt   ierr = CeedDestroy(&(*op)->ceed); CeedChk(ierr);
1740fe2413ffSjeremylt   // Free fields
17411d102b48SJeremy L Thompson   for (int i=0; i<(*op)->nfields; i++)
174252d6035fSJeremy L Thompson     if ((*op)->inputfields[i]) {
174315910d16Sjeremylt       if ((*op)->inputfields[i]->Erestrict != CEED_ELEMRESTRICTION_NONE) {
174471352a93Sjeremylt         ierr = CeedElemRestrictionDestroy(&(*op)->inputfields[i]->Erestrict);
174571352a93Sjeremylt         CeedChk(ierr);
174615910d16Sjeremylt       }
174771352a93Sjeremylt       if ((*op)->inputfields[i]->basis != CEED_BASIS_COLLOCATED) {
174871352a93Sjeremylt         ierr = CeedBasisDestroy(&(*op)->inputfields[i]->basis); CeedChk(ierr);
174971352a93Sjeremylt       }
175071352a93Sjeremylt       if ((*op)->inputfields[i]->vec != CEED_VECTOR_ACTIVE &&
175171352a93Sjeremylt           (*op)->inputfields[i]->vec != CEED_VECTOR_NONE ) {
175271352a93Sjeremylt         ierr = CeedVectorDestroy(&(*op)->inputfields[i]->vec); CeedChk(ierr);
175371352a93Sjeremylt       }
1754d99fa3c5SJeremy L Thompson       ierr = CeedFree(&(*op)->inputfields[i]->fieldname); CeedChk(ierr);
1755fe2413ffSjeremylt       ierr = CeedFree(&(*op)->inputfields[i]); CeedChk(ierr);
1756fe2413ffSjeremylt     }
17571d102b48SJeremy L Thompson   for (int i=0; i<(*op)->nfields; i++)
1758d0eb30a5Sjeremylt     if ((*op)->outputfields[i]) {
175971352a93Sjeremylt       ierr = CeedElemRestrictionDestroy(&(*op)->outputfields[i]->Erestrict);
176071352a93Sjeremylt       CeedChk(ierr);
176171352a93Sjeremylt       if ((*op)->outputfields[i]->basis != CEED_BASIS_COLLOCATED) {
176271352a93Sjeremylt         ierr = CeedBasisDestroy(&(*op)->outputfields[i]->basis); CeedChk(ierr);
176371352a93Sjeremylt       }
176471352a93Sjeremylt       if ((*op)->outputfields[i]->vec != CEED_VECTOR_ACTIVE &&
176571352a93Sjeremylt           (*op)->outputfields[i]->vec != CEED_VECTOR_NONE ) {
176671352a93Sjeremylt         ierr = CeedVectorDestroy(&(*op)->outputfields[i]->vec); CeedChk(ierr);
176771352a93Sjeremylt       }
1768d99fa3c5SJeremy L Thompson       ierr = CeedFree(&(*op)->outputfields[i]->fieldname); CeedChk(ierr);
1769fe2413ffSjeremylt       ierr = CeedFree(&(*op)->outputfields[i]); CeedChk(ierr);
1770fe2413ffSjeremylt     }
177152d6035fSJeremy L Thompson   // Destroy suboperators
17721d102b48SJeremy L Thompson   for (int i=0; i<(*op)->numsub; i++)
177352d6035fSJeremy L Thompson     if ((*op)->suboperators[i]) {
177452d6035fSJeremy L Thompson       ierr = CeedOperatorDestroy(&(*op)->suboperators[i]); CeedChk(ierr);
177552d6035fSJeremy L Thompson     }
1776*e15f9bd0SJeremy L Thompson   if ((*op)->qf)
1777*e15f9bd0SJeremy L Thompson     // LCOV_EXCL_START
1778*e15f9bd0SJeremy L Thompson     (*op)->qf->operatorsset--;
1779*e15f9bd0SJeremy L Thompson   // LCOV_EXCL_STOP
1780d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->qf); CeedChk(ierr);
1781*e15f9bd0SJeremy L Thompson   if ((*op)->dqf && (*op)->dqf != CEED_QFUNCTION_NONE)
1782*e15f9bd0SJeremy L Thompson     // LCOV_EXCL_START
1783*e15f9bd0SJeremy L Thompson     (*op)->dqf->operatorsset--;
1784*e15f9bd0SJeremy L Thompson   // LCOV_EXCL_STOP
1785d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->dqf); CeedChk(ierr);
1786*e15f9bd0SJeremy L Thompson   if ((*op)->dqfT && (*op)->dqfT != CEED_QFUNCTION_NONE)
1787*e15f9bd0SJeremy L Thompson     // LCOV_EXCL_START
1788*e15f9bd0SJeremy L Thompson     (*op)->dqfT->operatorsset--;
1789*e15f9bd0SJeremy L Thompson   // LCOV_EXCL_STOP
1790d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->dqfT); CeedChk(ierr);
1791fe2413ffSjeremylt 
17925107b09fSJeremy L Thompson   // Destroy fallback
17935107b09fSJeremy L Thompson   if ((*op)->opfallback) {
17945107b09fSJeremy L Thompson     ierr = (*op)->qffallback->Destroy((*op)->qffallback); CeedChk(ierr);
17955107b09fSJeremy L Thompson     ierr = CeedFree(&(*op)->qffallback); CeedChk(ierr);
17965107b09fSJeremy L Thompson     ierr = (*op)->opfallback->Destroy((*op)->opfallback); CeedChk(ierr);
17975107b09fSJeremy L Thompson     ierr = CeedFree(&(*op)->opfallback); CeedChk(ierr);
17985107b09fSJeremy L Thompson   }
17995107b09fSJeremy L Thompson 
1800fe2413ffSjeremylt   ierr = CeedFree(&(*op)->inputfields); CeedChk(ierr);
1801fe2413ffSjeremylt   ierr = CeedFree(&(*op)->outputfields); CeedChk(ierr);
180252d6035fSJeremy L Thompson   ierr = CeedFree(&(*op)->suboperators); CeedChk(ierr);
1803d7b241e6Sjeremylt   ierr = CeedFree(op); CeedChk(ierr);
1804*e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1805d7b241e6Sjeremylt }
1806d7b241e6Sjeremylt 
1807d7b241e6Sjeremylt /// @}
1808