xref: /libCEED/rust/libceed-sys/c-src/interface/ceed-operator.c (revision e1e9e29d9f2ed91853512885180b2002c5f70637)
1d7b241e6Sjeremylt // Copyright (c) 2017, Lawrence Livermore National Security, LLC. Produced at
2d7b241e6Sjeremylt // the Lawrence Livermore National Laboratory. LLNL-CODE-734707. All Rights
3d7b241e6Sjeremylt // reserved. See files LICENSE and NOTICE for details.
4d7b241e6Sjeremylt //
5d7b241e6Sjeremylt // This file is part of CEED, a collection of benchmarks, miniapps, software
6d7b241e6Sjeremylt // libraries and APIs for efficient high-order finite element and spectral
7d7b241e6Sjeremylt // element discretizations for exascale applications. For more information and
8d7b241e6Sjeremylt // source code availability see http://github.com/ceed.
9d7b241e6Sjeremylt //
10d7b241e6Sjeremylt // The CEED research is supported by the Exascale Computing Project 17-SC-20-SC,
11d7b241e6Sjeremylt // a collaborative effort of two U.S. Department of Energy organizations (Office
12d7b241e6Sjeremylt // of Science and the National Nuclear Security Administration) responsible for
13d7b241e6Sjeremylt // the planning and preparation of a capable exascale ecosystem, including
14d7b241e6Sjeremylt // software, applications, hardware, advanced system engineering and early
15d7b241e6Sjeremylt // testbed platforms, in support of the nation's exascale computing imperative.
16d7b241e6Sjeremylt 
173d576824SJeremy L Thompson #include <ceed.h>
18d863ab9bSjeremylt #include <ceed-backend.h>
193d576824SJeremy L Thompson #include <ceed-impl.h>
203bd813ffSjeremylt #include <math.h>
213d576824SJeremy L Thompson #include <stdbool.h>
223d576824SJeremy L Thompson #include <stdio.h>
233d576824SJeremy L Thompson #include <string.h>
24d7b241e6Sjeremylt 
25dfdf5a53Sjeremylt /// @file
267a982d89SJeremy L. Thompson /// Implementation of CeedOperator interfaces
277a982d89SJeremy L. Thompson 
287a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
297a982d89SJeremy L. Thompson /// CeedOperator Library Internal Functions
307a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
317a982d89SJeremy L. Thompson /// @addtogroup CeedOperatorDeveloper
327a982d89SJeremy L. Thompson /// @{
337a982d89SJeremy L. Thompson 
347a982d89SJeremy L. Thompson /**
357a982d89SJeremy L. Thompson   @brief Duplicate a CeedOperator with a reference Ceed to fallback for advanced
367a982d89SJeremy L. Thompson            CeedOperator functionality
377a982d89SJeremy L. Thompson 
387a982d89SJeremy L. Thompson   @param op           CeedOperator to create fallback for
397a982d89SJeremy L. Thompson 
407a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
417a982d89SJeremy L. Thompson 
427a982d89SJeremy L. Thompson   @ref Developer
437a982d89SJeremy L. Thompson **/
447a982d89SJeremy L. Thompson int CeedOperatorCreateFallback(CeedOperator op) {
457a982d89SJeremy L. Thompson   int ierr;
467a982d89SJeremy L. Thompson 
477a982d89SJeremy L. Thompson   // Fallback Ceed
487a982d89SJeremy L. Thompson   const char *resource, *fallbackresource;
497a982d89SJeremy L. Thompson   ierr = CeedGetResource(op->ceed, &resource); CeedChk(ierr);
507a982d89SJeremy L. Thompson   ierr = CeedGetOperatorFallbackResource(op->ceed, &fallbackresource);
517a982d89SJeremy L. Thompson   CeedChk(ierr);
527a982d89SJeremy L. Thompson   if (!strcmp(resource, fallbackresource))
537a982d89SJeremy L. Thompson     // LCOV_EXCL_START
54e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED,
55e15f9bd0SJeremy L Thompson                      "Backend %s cannot create an operator"
567a982d89SJeremy L. Thompson                      "fallback to resource %s", resource, fallbackresource);
577a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
587a982d89SJeremy L. Thompson 
597a982d89SJeremy L. Thompson   // Fallback Ceed
607a982d89SJeremy L. Thompson   Ceed ceedref;
617a982d89SJeremy L. Thompson   if (!op->ceed->opfallbackceed) {
627a982d89SJeremy L. Thompson     ierr = CeedInit(fallbackresource, &ceedref); CeedChk(ierr);
637a982d89SJeremy L. Thompson     ceedref->opfallbackparent = op->ceed;
64fc164cf7SWill Pazner     ceedref->Error = op->ceed->Error;
657a982d89SJeremy L. Thompson     op->ceed->opfallbackceed = ceedref;
667a982d89SJeremy L. Thompson   }
677a982d89SJeremy L. Thompson   ceedref = op->ceed->opfallbackceed;
687a982d89SJeremy L. Thompson 
697a982d89SJeremy L. Thompson   // Clone Op
707a982d89SJeremy L. Thompson   CeedOperator opref;
717a982d89SJeremy L. Thompson   ierr = CeedCalloc(1, &opref); CeedChk(ierr);
72e15f9bd0SJeremy L Thompson   memcpy(opref, op, sizeof(*opref));
737a982d89SJeremy L. Thompson   opref->data = NULL;
74e15f9bd0SJeremy L Thompson   opref->interfacesetup = false;
75e15f9bd0SJeremy L Thompson   opref->backendsetup = false;
767a982d89SJeremy L. Thompson   opref->ceed = ceedref;
777a982d89SJeremy L. Thompson   ierr = ceedref->OperatorCreate(opref); CeedChk(ierr);
787a982d89SJeremy L. Thompson   op->opfallback = opref;
797a982d89SJeremy L. Thompson 
807a982d89SJeremy L. Thompson   // Clone QF
817a982d89SJeremy L. Thompson   CeedQFunction qfref;
827a982d89SJeremy L. Thompson   ierr = CeedCalloc(1, &qfref); CeedChk(ierr);
83e15f9bd0SJeremy L Thompson   memcpy(qfref, (op->qf), sizeof(*qfref));
847a982d89SJeremy L. Thompson   qfref->data = NULL;
857a982d89SJeremy L. Thompson   qfref->ceed = ceedref;
867a982d89SJeremy L. Thompson   ierr = ceedref->QFunctionCreate(qfref); CeedChk(ierr);
877a982d89SJeremy L. Thompson   opref->qf = qfref;
887a982d89SJeremy L. Thompson   op->qffallback = qfref;
89e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
90e15f9bd0SJeremy L Thompson }
917a982d89SJeremy L. Thompson 
92e15f9bd0SJeremy L Thompson /**
93e15f9bd0SJeremy L Thompson   @brief Check if a CeedOperator Field matches the QFunction Field
94e15f9bd0SJeremy L Thompson 
95e15f9bd0SJeremy L Thompson   @param[in] ceed   Ceed object for error handling
96e15f9bd0SJeremy L Thompson   @param[in] qfield QFunction Field matching Operator Field
97e15f9bd0SJeremy L Thompson   @param[in] r      Operator Field ElemRestriction
98e15f9bd0SJeremy L Thompson   @param[in] b      Operator Field Basis
99e15f9bd0SJeremy L Thompson 
100e15f9bd0SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
101e15f9bd0SJeremy L Thompson 
102e15f9bd0SJeremy L Thompson   @ref Developer
103e15f9bd0SJeremy L Thompson **/
104e15f9bd0SJeremy L Thompson static int CeedOperatorCheckField(Ceed ceed, CeedQFunctionField qfield,
105e15f9bd0SJeremy L Thompson                                   CeedElemRestriction r, CeedBasis b) {
106e15f9bd0SJeremy L Thompson   int ierr;
107e15f9bd0SJeremy L Thompson   CeedEvalMode emode = qfield->emode;
108e15f9bd0SJeremy L Thompson   CeedInt dim = 1, ncomp = 1, restr_ncomp = 1, size = qfield->size;
109e15f9bd0SJeremy L Thompson   // Restriction
110e15f9bd0SJeremy L Thompson   if (r != CEED_ELEMRESTRICTION_NONE) {
111*e1e9e29dSJed Brown     if (emode == CEED_EVAL_WEIGHT) {
112e15f9bd0SJeremy L Thompson       // LCOV_EXCL_START
113*e1e9e29dSJed Brown       return CeedError(ceed, CEED_ERROR_INCOMPATIBLE,
114*e1e9e29dSJed Brown                        "CEED_ELEMRESTRICTION_NONE should be used "
115e15f9bd0SJeremy L Thompson                        "for a field with eval mode CEED_EVAL_WEIGHT");
116e15f9bd0SJeremy L Thompson       // LCOV_EXCL_STOP
117e15f9bd0SJeremy L Thompson     }
118*e1e9e29dSJed Brown     ierr = CeedElemRestrictionGetNumComponents(r, &restr_ncomp);
119*e1e9e29dSJed Brown   }
120*e1e9e29dSJed Brown   if ((r == CEED_ELEMRESTRICTION_NONE) != (emode == CEED_EVAL_WEIGHT)) {
121*e1e9e29dSJed Brown     // LCOV_EXCL_START
122*e1e9e29dSJed Brown     return CeedError(ceed, CEED_ERROR_INCOMPATIBLE,
123*e1e9e29dSJed Brown                      "CEED_ELEMRESTRICTION_NONE and CEED_EVAL_WEIGHT "
124*e1e9e29dSJed Brown                      "must be used together.");
125*e1e9e29dSJed Brown     // LCOV_EXCL_STOP
126*e1e9e29dSJed Brown   }
127e15f9bd0SJeremy L Thompson   // Basis
128e15f9bd0SJeremy L Thompson   if (b != CEED_BASIS_COLLOCATED) {
129*e1e9e29dSJed Brown     if (emode == CEED_EVAL_NONE)
130*e1e9e29dSJed Brown       return CeedError(ceed, CEED_ERROR_INCOMPATIBLE,
131*e1e9e29dSJed Brown                        "Field '%s' configured with CEED_EVAL_NONE must be used with CEED_BASIS_COLLOCATED",
132*e1e9e29dSJed Brown                        qfield->fieldname);
133e15f9bd0SJeremy L Thompson     ierr = CeedBasisGetDimension(b, &dim); CeedChk(ierr);
134e15f9bd0SJeremy L Thompson     ierr = CeedBasisGetNumComponents(b, &ncomp); CeedChk(ierr);
135e15f9bd0SJeremy L Thompson     if (r != CEED_ELEMRESTRICTION_NONE && restr_ncomp != ncomp) {
136e15f9bd0SJeremy L Thompson       // LCOV_EXCL_START
137e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_DIMENSION,
138*e1e9e29dSJed Brown                        "Field '%s' of size %d and EvalMode %s: ElemRestriction has %d components, but Basis has %d components",
139*e1e9e29dSJed Brown                        qfield->fieldname, qfield->size, CeedEvalModes[qfield->emode], restr_ncomp,
140*e1e9e29dSJed Brown                        ncomp);
141e15f9bd0SJeremy L Thompson       // LCOV_EXCL_STOP
142e15f9bd0SJeremy L Thompson     }
143e15f9bd0SJeremy L Thompson   }
144e15f9bd0SJeremy L Thompson   // Field size
145e15f9bd0SJeremy L Thompson   switch(emode) {
146e15f9bd0SJeremy L Thompson   case CEED_EVAL_NONE:
147e15f9bd0SJeremy L Thompson     if (size != restr_ncomp)
148e15f9bd0SJeremy L Thompson       // LCOV_EXCL_START
149e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_DIMENSION,
150*e1e9e29dSJed Brown                        "Field '%s' of size %d and EvalMode %s: ElemRestriction has %d components",
151*e1e9e29dSJed Brown                        qfield->fieldname, qfield->size, CeedEvalModes[qfield->emode], restr_ncomp);
152e15f9bd0SJeremy L Thompson     // LCOV_EXCL_STOP
153e15f9bd0SJeremy L Thompson     break;
154e15f9bd0SJeremy L Thompson   case CEED_EVAL_INTERP:
155e15f9bd0SJeremy L Thompson     if (size != ncomp)
156e15f9bd0SJeremy L Thompson       // LCOV_EXCL_START
157e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_DIMENSION,
158*e1e9e29dSJed Brown                        "Field '%s' of size %d and EvalMode %s: ElemRestriction/Basis has %d components",
159*e1e9e29dSJed Brown                        qfield->fieldname, qfield->size, CeedEvalModes[qfield->emode], ncomp);
160e15f9bd0SJeremy L Thompson     // LCOV_EXCL_STOP
161e15f9bd0SJeremy L Thompson     break;
162e15f9bd0SJeremy L Thompson   case CEED_EVAL_GRAD:
163e15f9bd0SJeremy L Thompson     if (size != ncomp * dim)
164e15f9bd0SJeremy L Thompson       // LCOV_EXCL_START
165e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_DIMENSION,
166*e1e9e29dSJed Brown                        "Field '%s' of size %d and EvalMode %s in %d dimensions: ElemRestriction/Basis has %d components",
167*e1e9e29dSJed Brown                        qfield->fieldname, qfield->size, CeedEvalModes[qfield->emode], dim, ncomp);
168e15f9bd0SJeremy L Thompson     // LCOV_EXCL_STOP
169e15f9bd0SJeremy L Thompson     break;
170e15f9bd0SJeremy L Thompson   case CEED_EVAL_WEIGHT:
171e15f9bd0SJeremy L Thompson     // No addional checks required
172e15f9bd0SJeremy L Thompson     break;
173e15f9bd0SJeremy L Thompson   case CEED_EVAL_DIV:
174e15f9bd0SJeremy L Thompson     // Not implemented
175e15f9bd0SJeremy L Thompson     break;
176e15f9bd0SJeremy L Thompson   case CEED_EVAL_CURL:
177e15f9bd0SJeremy L Thompson     // Not implemented
178e15f9bd0SJeremy L Thompson     break;
179e15f9bd0SJeremy L Thompson   }
180e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1817a982d89SJeremy L. Thompson }
1827a982d89SJeremy L. Thompson 
1837a982d89SJeremy L. Thompson /**
1847a982d89SJeremy L. Thompson   @brief Check if a CeedOperator is ready to be used.
1857a982d89SJeremy L. Thompson 
1867a982d89SJeremy L. Thompson   @param[in] op   CeedOperator to check
1877a982d89SJeremy L. Thompson 
1887a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
1897a982d89SJeremy L. Thompson 
1907a982d89SJeremy L. Thompson   @ref Developer
1917a982d89SJeremy L. Thompson **/
192e2f04181SAndrew T. Barker static int CeedOperatorCheckReady(CeedOperator op) {
193e2f04181SAndrew T. Barker   int ierr;
194e2f04181SAndrew T. Barker   Ceed ceed;
195e2f04181SAndrew T. Barker   ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr);
196e2f04181SAndrew T. Barker 
197e15f9bd0SJeremy L Thompson   if (op->interfacesetup)
198e15f9bd0SJeremy L Thompson     return CEED_ERROR_SUCCESS;
1997a982d89SJeremy L. Thompson 
200e15f9bd0SJeremy L Thompson   CeedQFunction qf = op->qf;
2017a982d89SJeremy L. Thompson   if (op->composite) {
2027a982d89SJeremy L. Thompson     if (!op->numsub)
2037a982d89SJeremy L. Thompson       // LCOV_EXCL_START
204e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_INCOMPLETE, "No suboperators set");
2057a982d89SJeremy L. Thompson     // LCOV_EXCL_STOP
2067a982d89SJeremy L. Thompson   } else {
2077a982d89SJeremy L. Thompson     if (op->nfields == 0)
2087a982d89SJeremy L. Thompson       // LCOV_EXCL_START
209e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_INCOMPLETE, "No operator fields set");
2107a982d89SJeremy L. Thompson     // LCOV_EXCL_STOP
2117a982d89SJeremy L. Thompson     if (op->nfields < qf->numinputfields + qf->numoutputfields)
2127a982d89SJeremy L. Thompson       // LCOV_EXCL_START
213e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_INCOMPLETE, "Not all operator fields set");
2147a982d89SJeremy L. Thompson     // LCOV_EXCL_STOP
2157a982d89SJeremy L. Thompson     if (!op->hasrestriction)
2167a982d89SJeremy L. Thompson       // LCOV_EXCL_START
217e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_INCOMPLETE,
218e15f9bd0SJeremy L Thompson                        "At least one restriction required");
2197a982d89SJeremy L. Thompson     // LCOV_EXCL_STOP
2207a982d89SJeremy L. Thompson     if (op->numqpoints == 0)
2217a982d89SJeremy L. Thompson       // LCOV_EXCL_START
222e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_INCOMPLETE,
223e15f9bd0SJeremy L Thompson                        "At least one non-collocated basis required");
2247a982d89SJeremy L. Thompson     // LCOV_EXCL_STOP
2257a982d89SJeremy L. Thompson   }
2267a982d89SJeremy L. Thompson 
227e15f9bd0SJeremy L Thompson   // Flag as immutable and ready
228e15f9bd0SJeremy L Thompson   op->interfacesetup = true;
229e15f9bd0SJeremy L Thompson   if (op->qf && op->qf != CEED_QFUNCTION_NONE)
230e15f9bd0SJeremy L Thompson     // LCOV_EXCL_START
231e15f9bd0SJeremy L Thompson     op->qf->operatorsset++;
232e15f9bd0SJeremy L Thompson   // LCOV_EXCL_STOP
233e15f9bd0SJeremy L Thompson   if (op->dqf && op->dqf != CEED_QFUNCTION_NONE)
234e15f9bd0SJeremy L Thompson     // LCOV_EXCL_START
235e15f9bd0SJeremy L Thompson     op->dqf->operatorsset++;
236e15f9bd0SJeremy L Thompson   // LCOV_EXCL_STOP
237e15f9bd0SJeremy L Thompson   if (op->dqfT && op->dqfT != CEED_QFUNCTION_NONE)
238e15f9bd0SJeremy L Thompson     // LCOV_EXCL_START
239e15f9bd0SJeremy L Thompson     op->dqfT->operatorsset++;
240e15f9bd0SJeremy L Thompson   // LCOV_EXCL_STOP
241e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2427a982d89SJeremy L. Thompson }
2437a982d89SJeremy L. Thompson 
2447a982d89SJeremy L. Thompson /**
2457a982d89SJeremy L. Thompson   @brief View a field of a CeedOperator
2467a982d89SJeremy L. Thompson 
2477a982d89SJeremy L. Thompson   @param[in] field       Operator field to view
2484c4400c7SValeria Barra   @param[in] qffield     QFunction field (carries field name)
2497a982d89SJeremy L. Thompson   @param[in] fieldnumber Number of field being viewed
2504c4400c7SValeria Barra   @param[in] sub         true indicates sub-operator, which increases indentation; false for top-level operator
2514c4400c7SValeria Barra   @param[in] in          true for an input field; false for output field
2527a982d89SJeremy L. Thompson   @param[in] stream      Stream to view to, e.g., stdout
2537a982d89SJeremy L. Thompson 
2547a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
2557a982d89SJeremy L. Thompson 
2567a982d89SJeremy L. Thompson   @ref Utility
2577a982d89SJeremy L. Thompson **/
2587a982d89SJeremy L. Thompson static int CeedOperatorFieldView(CeedOperatorField field,
2597a982d89SJeremy L. Thompson                                  CeedQFunctionField qffield,
2607a982d89SJeremy L. Thompson                                  CeedInt fieldnumber, bool sub, bool in,
2617a982d89SJeremy L. Thompson                                  FILE *stream) {
2627a982d89SJeremy L. Thompson   const char *pre = sub ? "  " : "";
2637a982d89SJeremy L. Thompson   const char *inout = in ? "Input" : "Output";
2647a982d89SJeremy L. Thompson 
2657a982d89SJeremy L. Thompson   fprintf(stream, "%s    %s Field [%d]:\n"
2667a982d89SJeremy L. Thompson           "%s      Name: \"%s\"\n",
2677a982d89SJeremy L. Thompson           pre, inout, fieldnumber, pre, qffield->fieldname);
2687a982d89SJeremy L. Thompson 
2697a982d89SJeremy L. Thompson   if (field->basis == CEED_BASIS_COLLOCATED)
2707a982d89SJeremy L. Thompson     fprintf(stream, "%s      Collocated basis\n", pre);
2717a982d89SJeremy L. Thompson 
2727a982d89SJeremy L. Thompson   if (field->vec == CEED_VECTOR_ACTIVE)
2737a982d89SJeremy L. Thompson     fprintf(stream, "%s      Active vector\n", pre);
2747a982d89SJeremy L. Thompson   else if (field->vec == CEED_VECTOR_NONE)
2757a982d89SJeremy L. Thompson     fprintf(stream, "%s      No vector\n", pre);
276e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2777a982d89SJeremy L. Thompson }
2787a982d89SJeremy L. Thompson 
2797a982d89SJeremy L. Thompson /**
2807a982d89SJeremy L. Thompson   @brief View a single CeedOperator
2817a982d89SJeremy L. Thompson 
2827a982d89SJeremy L. Thompson   @param[in] op     CeedOperator to view
2837a982d89SJeremy L. Thompson   @param[in] sub    Boolean flag for sub-operator
2847a982d89SJeremy L. Thompson   @param[in] stream Stream to write; typically stdout/stderr or a file
2857a982d89SJeremy L. Thompson 
2867a982d89SJeremy L. Thompson   @return Error code: 0 - success, otherwise - failure
2877a982d89SJeremy L. Thompson 
2887a982d89SJeremy L. Thompson   @ref Utility
2897a982d89SJeremy L. Thompson **/
2907a982d89SJeremy L. Thompson int CeedOperatorSingleView(CeedOperator op, bool sub, FILE *stream) {
2917a982d89SJeremy L. Thompson   int ierr;
2927a982d89SJeremy L. Thompson   const char *pre = sub ? "  " : "";
2937a982d89SJeremy L. Thompson 
2947a982d89SJeremy L. Thompson   CeedInt totalfields;
2957a982d89SJeremy L. Thompson   ierr = CeedOperatorGetNumArgs(op, &totalfields); CeedChk(ierr);
2967a982d89SJeremy L. Thompson 
2977a982d89SJeremy L. Thompson   fprintf(stream, "%s  %d Field%s\n", pre, totalfields, totalfields>1 ? "s" : "");
2987a982d89SJeremy L. Thompson 
2997a982d89SJeremy L. Thompson   fprintf(stream, "%s  %d Input Field%s:\n", pre, op->qf->numinputfields,
3007a982d89SJeremy L. Thompson           op->qf->numinputfields>1 ? "s" : "");
3017a982d89SJeremy L. Thompson   for (CeedInt i=0; i<op->qf->numinputfields; i++) {
3027a982d89SJeremy L. Thompson     ierr = CeedOperatorFieldView(op->inputfields[i], op->qf->inputfields[i],
3037a982d89SJeremy L. Thompson                                  i, sub, 1, stream); CeedChk(ierr);
3047a982d89SJeremy L. Thompson   }
3057a982d89SJeremy L. Thompson 
3067a982d89SJeremy L. Thompson   fprintf(stream, "%s  %d Output Field%s:\n", pre, op->qf->numoutputfields,
3077a982d89SJeremy L. Thompson           op->qf->numoutputfields>1 ? "s" : "");
3087a982d89SJeremy L. Thompson   for (CeedInt i=0; i<op->qf->numoutputfields; i++) {
309829936eeSWill Pazner     ierr = CeedOperatorFieldView(op->outputfields[i], op->qf->outputfields[i],
3107a982d89SJeremy L. Thompson                                  i, sub, 0, stream); CeedChk(ierr);
3117a982d89SJeremy L. Thompson   }
312e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
3137a982d89SJeremy L. Thompson }
3147a982d89SJeremy L. Thompson 
315d99fa3c5SJeremy L Thompson /**
316e2f04181SAndrew T. Barker   @brief Find the active vector ElemRestriction for a CeedOperator
317e2f04181SAndrew T. Barker 
318e2f04181SAndrew T. Barker   @param[in] op            CeedOperator to find active basis for
319e2f04181SAndrew T. Barker   @param[out] activerstr   ElemRestriction for active input vector
320e2f04181SAndrew T. Barker 
321e2f04181SAndrew T. Barker   @return An error code: 0 - success, otherwise - failure
322e2f04181SAndrew T. Barker 
323e2f04181SAndrew T. Barker   @ref Utility
324e2f04181SAndrew T. Barker **/
325e2f04181SAndrew T. Barker static int CeedOperatorGetActiveElemRestriction(CeedOperator op,
326e2f04181SAndrew T. Barker     CeedElemRestriction *activerstr) {
327e2f04181SAndrew T. Barker   *activerstr = NULL;
328e2f04181SAndrew T. Barker   for (int i = 0; i < op->qf->numinputfields; i++)
329e2f04181SAndrew T. Barker     if (op->inputfields[i]->vec == CEED_VECTOR_ACTIVE) {
330e2f04181SAndrew T. Barker       *activerstr = op->inputfields[i]->Erestrict;
331e2f04181SAndrew T. Barker       break;
332e2f04181SAndrew T. Barker     }
333e2f04181SAndrew T. Barker 
334e2f04181SAndrew T. Barker   if (!*activerstr) {
335e2f04181SAndrew T. Barker     // LCOV_EXCL_START
336e2f04181SAndrew T. Barker     int ierr;
337e2f04181SAndrew T. Barker     Ceed ceed;
338e2f04181SAndrew T. Barker     ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr);
339e2f04181SAndrew T. Barker     return CeedError(ceed, CEED_ERROR_INCOMPLETE,
340e2f04181SAndrew T. Barker                      "No active ElemRestriction found!");
341e2f04181SAndrew T. Barker     // LCOV_EXCL_STOP
342e2f04181SAndrew T. Barker   }
343e2f04181SAndrew T. Barker   return CEED_ERROR_SUCCESS;
344e2f04181SAndrew T. Barker }
345e2f04181SAndrew T. Barker 
346e2f04181SAndrew T. Barker /**
347d99fa3c5SJeremy L Thompson   @brief Find the active vector basis for a CeedOperator
348d99fa3c5SJeremy L Thompson 
349d99fa3c5SJeremy L Thompson   @param[in] op            CeedOperator to find active basis for
350d99fa3c5SJeremy L Thompson   @param[out] activeBasis  Basis for active input vector
351d99fa3c5SJeremy L Thompson 
352d99fa3c5SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
353d99fa3c5SJeremy L Thompson 
354d99fa3c5SJeremy L Thompson   @ ref Developer
355d99fa3c5SJeremy L Thompson **/
356d99fa3c5SJeremy L Thompson static int CeedOperatorGetActiveBasis(CeedOperator op,
357d99fa3c5SJeremy L Thompson                                       CeedBasis *activeBasis) {
358d99fa3c5SJeremy L Thompson   *activeBasis = NULL;
359d99fa3c5SJeremy L Thompson   for (int i = 0; i < op->qf->numinputfields; i++)
360d99fa3c5SJeremy L Thompson     if (op->inputfields[i]->vec == CEED_VECTOR_ACTIVE) {
361d99fa3c5SJeremy L Thompson       *activeBasis = op->inputfields[i]->basis;
362d99fa3c5SJeremy L Thompson       break;
363d99fa3c5SJeremy L Thompson     }
364d99fa3c5SJeremy L Thompson 
365d99fa3c5SJeremy L Thompson   if (!*activeBasis) {
366d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
367d99fa3c5SJeremy L Thompson     int ierr;
368d99fa3c5SJeremy L Thompson     Ceed ceed;
369d99fa3c5SJeremy L Thompson     ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr);
370e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_MINOR,
371d99fa3c5SJeremy L Thompson                      "No active basis found for automatic multigrid setup");
372d99fa3c5SJeremy L Thompson     // LCOV_EXCL_STOP
373d99fa3c5SJeremy L Thompson   }
374e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
375d99fa3c5SJeremy L Thompson }
376d99fa3c5SJeremy L Thompson 
377d99fa3c5SJeremy L Thompson 
378d99fa3c5SJeremy L Thompson /**
379d99fa3c5SJeremy L Thompson   @brief Common code for creating a multigrid coarse operator and level
380d99fa3c5SJeremy L Thompson            transfer operators for a CeedOperator
381d99fa3c5SJeremy L Thompson 
382d99fa3c5SJeremy L Thompson   @param[in] opFine       Fine grid operator
383d99fa3c5SJeremy L Thompson   @param[in] PMultFine    L-vector multiplicity in parallel gather/scatter
384d99fa3c5SJeremy L Thompson   @param[in] rstrCoarse   Coarse grid restriction
385d99fa3c5SJeremy L Thompson   @param[in] basisCoarse  Coarse grid active vector basis
386d99fa3c5SJeremy L Thompson   @param[in] basisCtoF    Basis for coarse to fine interpolation
387d99fa3c5SJeremy L Thompson   @param[out] opCoarse    Coarse grid operator
388d99fa3c5SJeremy L Thompson   @param[out] opProlong   Coarse to fine operator
389d99fa3c5SJeremy L Thompson   @param[out] opRestrict  Fine to coarse operator
390d99fa3c5SJeremy L Thompson 
391d99fa3c5SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
392d99fa3c5SJeremy L Thompson 
393d99fa3c5SJeremy L Thompson   @ref Developer
394d99fa3c5SJeremy L Thompson **/
395d99fa3c5SJeremy L Thompson static int CeedOperatorMultigridLevel_Core(CeedOperator opFine,
396d99fa3c5SJeremy L Thompson     CeedVector PMultFine, CeedElemRestriction rstrCoarse, CeedBasis basisCoarse,
397d99fa3c5SJeremy L Thompson     CeedBasis basisCtoF, CeedOperator *opCoarse, CeedOperator *opProlong,
398d99fa3c5SJeremy L Thompson     CeedOperator *opRestrict) {
399d99fa3c5SJeremy L Thompson   int ierr;
400d99fa3c5SJeremy L Thompson   Ceed ceed;
401d99fa3c5SJeremy L Thompson   ierr = CeedOperatorGetCeed(opFine, &ceed); CeedChk(ierr);
402d99fa3c5SJeremy L Thompson 
403d99fa3c5SJeremy L Thompson   // Check for composite operator
404d99fa3c5SJeremy L Thompson   bool isComposite;
405d99fa3c5SJeremy L Thompson   ierr = CeedOperatorIsComposite(opFine, &isComposite); CeedChk(ierr);
406d99fa3c5SJeremy L Thompson   if (isComposite)
407d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
408e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_UNSUPPORTED,
409d99fa3c5SJeremy L Thompson                      "Automatic multigrid setup for composite operators not supported");
410d99fa3c5SJeremy L Thompson   // LCOV_EXCL_STOP
411d99fa3c5SJeremy L Thompson 
412d99fa3c5SJeremy L Thompson   // Coarse Grid
413d99fa3c5SJeremy L Thompson   ierr = CeedOperatorCreate(ceed, opFine->qf, opFine->dqf, opFine->dqfT,
414d99fa3c5SJeremy L Thompson                             opCoarse); CeedChk(ierr);
415d99fa3c5SJeremy L Thompson   CeedElemRestriction rstrFine = NULL;
416d99fa3c5SJeremy L Thompson   // -- Clone input fields
417d99fa3c5SJeremy L Thompson   for (int i = 0; i < opFine->qf->numinputfields; i++) {
418d99fa3c5SJeremy L Thompson     if (opFine->inputfields[i]->vec == CEED_VECTOR_ACTIVE) {
419d99fa3c5SJeremy L Thompson       rstrFine = opFine->inputfields[i]->Erestrict;
420d99fa3c5SJeremy L Thompson       ierr = CeedOperatorSetField(*opCoarse, opFine->inputfields[i]->fieldname,
421d99fa3c5SJeremy L Thompson                                   rstrCoarse, basisCoarse, CEED_VECTOR_ACTIVE);
422d99fa3c5SJeremy L Thompson       CeedChk(ierr);
423d99fa3c5SJeremy L Thompson     } else {
424d99fa3c5SJeremy L Thompson       ierr = CeedOperatorSetField(*opCoarse, opFine->inputfields[i]->fieldname,
425d99fa3c5SJeremy L Thompson                                   opFine->inputfields[i]->Erestrict,
426d99fa3c5SJeremy L Thompson                                   opFine->inputfields[i]->basis,
427d99fa3c5SJeremy L Thompson                                   opFine->inputfields[i]->vec); CeedChk(ierr);
428d99fa3c5SJeremy L Thompson     }
429d99fa3c5SJeremy L Thompson   }
430d99fa3c5SJeremy L Thompson   // -- Clone output fields
431d99fa3c5SJeremy L Thompson   for (int i = 0; i < opFine->qf->numoutputfields; i++) {
432d99fa3c5SJeremy L Thompson     if (opFine->outputfields[i]->vec == CEED_VECTOR_ACTIVE) {
433d99fa3c5SJeremy L Thompson       ierr = CeedOperatorSetField(*opCoarse, opFine->outputfields[i]->fieldname,
434d99fa3c5SJeremy L Thompson                                   rstrCoarse, basisCoarse, CEED_VECTOR_ACTIVE);
435d99fa3c5SJeremy L Thompson       CeedChk(ierr);
436d99fa3c5SJeremy L Thompson     } else {
437d99fa3c5SJeremy L Thompson       ierr = CeedOperatorSetField(*opCoarse, opFine->outputfields[i]->fieldname,
438d99fa3c5SJeremy L Thompson                                   opFine->outputfields[i]->Erestrict,
439d99fa3c5SJeremy L Thompson                                   opFine->outputfields[i]->basis,
440d99fa3c5SJeremy L Thompson                                   opFine->outputfields[i]->vec); CeedChk(ierr);
441d99fa3c5SJeremy L Thompson     }
442d99fa3c5SJeremy L Thompson   }
443d99fa3c5SJeremy L Thompson 
444d99fa3c5SJeremy L Thompson   // Multiplicity vector
445d99fa3c5SJeremy L Thompson   CeedVector multVec, multE;
446d99fa3c5SJeremy L Thompson   ierr = CeedElemRestrictionCreateVector(rstrFine, &multVec, &multE);
447d99fa3c5SJeremy L Thompson   CeedChk(ierr);
448d99fa3c5SJeremy L Thompson   ierr = CeedVectorSetValue(multE, 0.0); CeedChk(ierr);
449d99fa3c5SJeremy L Thompson   ierr = CeedElemRestrictionApply(rstrFine, CEED_NOTRANSPOSE, PMultFine, multE,
450d99fa3c5SJeremy L Thompson                                   CEED_REQUEST_IMMEDIATE); CeedChk(ierr);
451d99fa3c5SJeremy L Thompson   ierr = CeedVectorSetValue(multVec, 0.0); CeedChk(ierr);
452d99fa3c5SJeremy L Thompson   ierr = CeedElemRestrictionApply(rstrFine, CEED_TRANSPOSE, multE, multVec,
453d99fa3c5SJeremy L Thompson                                   CEED_REQUEST_IMMEDIATE); CeedChk(ierr);
454d99fa3c5SJeremy L Thompson   ierr = CeedVectorDestroy(&multE); CeedChk(ierr);
455d99fa3c5SJeremy L Thompson   ierr = CeedVectorReciprocal(multVec); CeedChk(ierr);
456d99fa3c5SJeremy L Thompson 
457d99fa3c5SJeremy L Thompson   // Restriction
458d99fa3c5SJeremy L Thompson   CeedInt ncomp;
459d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumComponents(basisCoarse, &ncomp); CeedChk(ierr);
460d99fa3c5SJeremy L Thompson   CeedQFunction qfRestrict;
461d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionCreateInteriorByName(ceed, "Scale", &qfRestrict);
462d99fa3c5SJeremy L Thompson   CeedChk(ierr);
463777ff853SJeremy L Thompson   CeedInt *ncompRData;
464777ff853SJeremy L Thompson   ierr = CeedCalloc(1, &ncompRData); CeedChk(ierr);
465777ff853SJeremy L Thompson   ncompRData[0] = ncomp;
466777ff853SJeremy L Thompson   CeedQFunctionContext ctxR;
467777ff853SJeremy L Thompson   ierr = CeedQFunctionContextCreate(ceed, &ctxR); CeedChk(ierr);
468777ff853SJeremy L Thompson   ierr = CeedQFunctionContextSetData(ctxR, CEED_MEM_HOST, CEED_OWN_POINTER,
469777ff853SJeremy L Thompson                                      sizeof(*ncompRData), ncompRData);
470777ff853SJeremy L Thompson   CeedChk(ierr);
471777ff853SJeremy L Thompson   ierr = CeedQFunctionSetContext(qfRestrict, ctxR); CeedChk(ierr);
472777ff853SJeremy L Thompson   ierr = CeedQFunctionContextDestroy(&ctxR); CeedChk(ierr);
473d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionAddInput(qfRestrict, "input", ncomp, CEED_EVAL_NONE);
474d99fa3c5SJeremy L Thompson   CeedChk(ierr);
475d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionAddInput(qfRestrict, "scale", ncomp, CEED_EVAL_NONE);
476d99fa3c5SJeremy L Thompson   CeedChk(ierr);
477d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionAddOutput(qfRestrict, "output", ncomp, CEED_EVAL_INTERP);
478d99fa3c5SJeremy L Thompson   CeedChk(ierr);
479d99fa3c5SJeremy L Thompson 
480d99fa3c5SJeremy L Thompson   ierr = CeedOperatorCreate(ceed, qfRestrict, CEED_QFUNCTION_NONE,
481d99fa3c5SJeremy L Thompson                             CEED_QFUNCTION_NONE, opRestrict);
482d99fa3c5SJeremy L Thompson   CeedChk(ierr);
483d99fa3c5SJeremy L Thompson   ierr = CeedOperatorSetField(*opRestrict, "input", rstrFine,
484d99fa3c5SJeremy L Thompson                               CEED_BASIS_COLLOCATED, CEED_VECTOR_ACTIVE);
485d99fa3c5SJeremy L Thompson   CeedChk(ierr);
486d99fa3c5SJeremy L Thompson   ierr = CeedOperatorSetField(*opRestrict, "scale", rstrFine,
487d99fa3c5SJeremy L Thompson                               CEED_BASIS_COLLOCATED, multVec);
488d99fa3c5SJeremy L Thompson   CeedChk(ierr);
489d99fa3c5SJeremy L Thompson   ierr = CeedOperatorSetField(*opRestrict, "output", rstrCoarse, basisCtoF,
490d99fa3c5SJeremy L Thompson                               CEED_VECTOR_ACTIVE); CeedChk(ierr);
491d99fa3c5SJeremy L Thompson 
492d99fa3c5SJeremy L Thompson   // Prolongation
493d99fa3c5SJeremy L Thompson   CeedQFunction qfProlong;
494d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionCreateInteriorByName(ceed, "Scale", &qfProlong);
495d99fa3c5SJeremy L Thompson   CeedChk(ierr);
496777ff853SJeremy L Thompson   CeedInt *ncompPData;
497777ff853SJeremy L Thompson   ierr = CeedCalloc(1, &ncompPData); CeedChk(ierr);
498777ff853SJeremy L Thompson   ncompPData[0] = ncomp;
499777ff853SJeremy L Thompson   CeedQFunctionContext ctxP;
500777ff853SJeremy L Thompson   ierr = CeedQFunctionContextCreate(ceed, &ctxP); CeedChk(ierr);
501777ff853SJeremy L Thompson   ierr = CeedQFunctionContextSetData(ctxP, CEED_MEM_HOST, CEED_OWN_POINTER,
502777ff853SJeremy L Thompson                                      sizeof(*ncompPData), ncompPData);
503777ff853SJeremy L Thompson   CeedChk(ierr);
504777ff853SJeremy L Thompson   ierr = CeedQFunctionSetContext(qfProlong, ctxP); CeedChk(ierr);
505777ff853SJeremy L Thompson   ierr = CeedQFunctionContextDestroy(&ctxP); CeedChk(ierr);
506d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionAddInput(qfProlong, "input", ncomp, CEED_EVAL_INTERP);
507d99fa3c5SJeremy L Thompson   CeedChk(ierr);
508d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionAddInput(qfProlong, "scale", ncomp, CEED_EVAL_NONE);
509d99fa3c5SJeremy L Thompson   CeedChk(ierr);
510d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionAddOutput(qfProlong, "output", ncomp, CEED_EVAL_NONE);
511d99fa3c5SJeremy L Thompson   CeedChk(ierr);
512d99fa3c5SJeremy L Thompson 
513d99fa3c5SJeremy L Thompson   ierr = CeedOperatorCreate(ceed, qfProlong, CEED_QFUNCTION_NONE,
514d99fa3c5SJeremy L Thompson                             CEED_QFUNCTION_NONE, opProlong);
515d99fa3c5SJeremy L Thompson   CeedChk(ierr);
516d99fa3c5SJeremy L Thompson   ierr = CeedOperatorSetField(*opProlong, "input", rstrCoarse, basisCtoF,
517d99fa3c5SJeremy L Thompson                               CEED_VECTOR_ACTIVE); CeedChk(ierr);
518d99fa3c5SJeremy L Thompson   ierr = CeedOperatorSetField(*opProlong, "scale", rstrFine,
519d99fa3c5SJeremy L Thompson                               CEED_BASIS_COLLOCATED, multVec);
520d99fa3c5SJeremy L Thompson   CeedChk(ierr);
521d99fa3c5SJeremy L Thompson   ierr = CeedOperatorSetField(*opProlong, "output", rstrFine,
522d99fa3c5SJeremy L Thompson                               CEED_BASIS_COLLOCATED, CEED_VECTOR_ACTIVE);
523d99fa3c5SJeremy L Thompson   CeedChk(ierr);
524d99fa3c5SJeremy L Thompson 
525d99fa3c5SJeremy L Thompson   // Cleanup
526d99fa3c5SJeremy L Thompson   ierr = CeedVectorDestroy(&multVec); CeedChk(ierr);
527d99fa3c5SJeremy L Thompson   ierr = CeedBasisDestroy(&basisCtoF); CeedChk(ierr);
528d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionDestroy(&qfRestrict); CeedChk(ierr);
529d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionDestroy(&qfProlong); CeedChk(ierr);
530e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
531d99fa3c5SJeremy L Thompson }
532d99fa3c5SJeremy L Thompson 
5337a982d89SJeremy L. Thompson /// @}
5347a982d89SJeremy L. Thompson 
5357a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
5367a982d89SJeremy L. Thompson /// CeedOperator Backend API
5377a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
5387a982d89SJeremy L. Thompson /// @addtogroup CeedOperatorBackend
5397a982d89SJeremy L. Thompson /// @{
5407a982d89SJeremy L. Thompson 
5417a982d89SJeremy L. Thompson /**
5427a982d89SJeremy L. Thompson   @brief Get the Ceed associated with a CeedOperator
5437a982d89SJeremy L. Thompson 
5447a982d89SJeremy L. Thompson   @param op              CeedOperator
5457a982d89SJeremy L. Thompson   @param[out] ceed       Variable to store Ceed
5467a982d89SJeremy L. Thompson 
5477a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5487a982d89SJeremy L. Thompson 
5497a982d89SJeremy L. Thompson   @ref Backend
5507a982d89SJeremy L. Thompson **/
5517a982d89SJeremy L. Thompson 
5527a982d89SJeremy L. Thompson int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) {
5537a982d89SJeremy L. Thompson   *ceed = op->ceed;
554e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5557a982d89SJeremy L. Thompson }
5567a982d89SJeremy L. Thompson 
5577a982d89SJeremy L. Thompson /**
5587a982d89SJeremy L. Thompson   @brief Get the number of elements associated with a CeedOperator
5597a982d89SJeremy L. Thompson 
5607a982d89SJeremy L. Thompson   @param op              CeedOperator
5617a982d89SJeremy L. Thompson   @param[out] numelem    Variable to store number of elements
5627a982d89SJeremy L. Thompson 
5637a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5647a982d89SJeremy L. Thompson 
5657a982d89SJeremy L. Thompson   @ref Backend
5667a982d89SJeremy L. Thompson **/
5677a982d89SJeremy L. Thompson 
5687a982d89SJeremy L. Thompson int CeedOperatorGetNumElements(CeedOperator op, CeedInt *numelem) {
5697a982d89SJeremy L. Thompson   if (op->composite)
5707a982d89SJeremy L. Thompson     // LCOV_EXCL_START
571e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
572e15f9bd0SJeremy L Thompson                      "Not defined for composite operator");
5737a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
5747a982d89SJeremy L. Thompson 
5757a982d89SJeremy L. Thompson   *numelem = op->numelements;
576e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5777a982d89SJeremy L. Thompson }
5787a982d89SJeremy L. Thompson 
5797a982d89SJeremy L. Thompson /**
5807a982d89SJeremy L. Thompson   @brief Get the number of quadrature points associated with a CeedOperator
5817a982d89SJeremy L. Thompson 
5827a982d89SJeremy L. Thompson   @param op              CeedOperator
5837a982d89SJeremy L. Thompson   @param[out] numqpts    Variable to store vector number of quadrature points
5847a982d89SJeremy L. Thompson 
5857a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5867a982d89SJeremy L. Thompson 
5877a982d89SJeremy L. Thompson   @ref Backend
5887a982d89SJeremy L. Thompson **/
5897a982d89SJeremy L. Thompson 
5907a982d89SJeremy L. Thompson int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *numqpts) {
5917a982d89SJeremy L. Thompson   if (op->composite)
5927a982d89SJeremy L. Thompson     // LCOV_EXCL_START
593e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
594e15f9bd0SJeremy L Thompson                      "Not defined for composite operator");
5957a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
5967a982d89SJeremy L. Thompson 
5977a982d89SJeremy L. Thompson   *numqpts = op->numqpoints;
598e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5997a982d89SJeremy L. Thompson }
6007a982d89SJeremy L. Thompson 
6017a982d89SJeremy L. Thompson /**
6027a982d89SJeremy L. Thompson   @brief Get the number of arguments associated with a CeedOperator
6037a982d89SJeremy L. Thompson 
6047a982d89SJeremy L. Thompson   @param op              CeedOperator
6057a982d89SJeremy L. Thompson   @param[out] numargs    Variable to store vector number of arguments
6067a982d89SJeremy L. Thompson 
6077a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6087a982d89SJeremy L. Thompson 
6097a982d89SJeremy L. Thompson   @ref Backend
6107a982d89SJeremy L. Thompson **/
6117a982d89SJeremy L. Thompson 
6127a982d89SJeremy L. Thompson int CeedOperatorGetNumArgs(CeedOperator op, CeedInt *numargs) {
6137a982d89SJeremy L. Thompson   if (op->composite)
6147a982d89SJeremy L. Thompson     // LCOV_EXCL_START
615e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
616e15f9bd0SJeremy L Thompson                      "Not defined for composite operators");
6177a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
6187a982d89SJeremy L. Thompson 
6197a982d89SJeremy L. Thompson   *numargs = op->nfields;
620e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6217a982d89SJeremy L. Thompson }
6227a982d89SJeremy L. Thompson 
6237a982d89SJeremy L. Thompson /**
6247a982d89SJeremy L. Thompson   @brief Get the setup status of a CeedOperator
6257a982d89SJeremy L. Thompson 
6267a982d89SJeremy L. Thompson   @param op                CeedOperator
627fd364f38SJeremy L Thompson   @param[out] issetupdone  Variable to store setup status
6287a982d89SJeremy L. Thompson 
6297a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6307a982d89SJeremy L. Thompson 
6317a982d89SJeremy L. Thompson   @ref Backend
6327a982d89SJeremy L. Thompson **/
6337a982d89SJeremy L. Thompson 
634fd364f38SJeremy L Thompson int CeedOperatorIsSetupDone(CeedOperator op, bool *issetupdone) {
635e15f9bd0SJeremy L Thompson   *issetupdone = op->backendsetup;
636e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6377a982d89SJeremy L. Thompson }
6387a982d89SJeremy L. Thompson 
6397a982d89SJeremy L. Thompson /**
6407a982d89SJeremy L. Thompson   @brief Get the QFunction associated with a CeedOperator
6417a982d89SJeremy L. Thompson 
6427a982d89SJeremy L. Thompson   @param op              CeedOperator
6437a982d89SJeremy L. Thompson   @param[out] qf         Variable to store QFunction
6447a982d89SJeremy L. Thompson 
6457a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6467a982d89SJeremy L. Thompson 
6477a982d89SJeremy L. Thompson   @ref Backend
6487a982d89SJeremy L. Thompson **/
6497a982d89SJeremy L. Thompson 
6507a982d89SJeremy L. Thompson int CeedOperatorGetQFunction(CeedOperator op, CeedQFunction *qf) {
6517a982d89SJeremy L. Thompson   if (op->composite)
6527a982d89SJeremy L. Thompson     // LCOV_EXCL_START
653e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
654e15f9bd0SJeremy L Thompson                      "Not defined for composite operator");
6557a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
6567a982d89SJeremy L. Thompson 
6577a982d89SJeremy L. Thompson   *qf = op->qf;
658e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6597a982d89SJeremy L. Thompson }
6607a982d89SJeremy L. Thompson 
6617a982d89SJeremy L. Thompson /**
662c04a41a7SJeremy L Thompson   @brief Get a boolean value indicating if the CeedOperator is composite
663c04a41a7SJeremy L Thompson 
664c04a41a7SJeremy L Thompson   @param op                CeedOperator
665fd364f38SJeremy L Thompson   @param[out] iscomposite  Variable to store composite status
666c04a41a7SJeremy L Thompson 
667c04a41a7SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
668c04a41a7SJeremy L Thompson 
669c04a41a7SJeremy L Thompson   @ref Backend
670c04a41a7SJeremy L Thompson **/
671c04a41a7SJeremy L Thompson 
672fd364f38SJeremy L Thompson int CeedOperatorIsComposite(CeedOperator op, bool *iscomposite) {
673fd364f38SJeremy L Thompson   *iscomposite = op->composite;
674e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
675c04a41a7SJeremy L Thompson }
676c04a41a7SJeremy L Thompson 
677c04a41a7SJeremy L Thompson /**
6787a982d89SJeremy L. Thompson   @brief Get the number of suboperators associated with a CeedOperator
6797a982d89SJeremy L. Thompson 
6807a982d89SJeremy L. Thompson   @param op              CeedOperator
6817a982d89SJeremy L. Thompson   @param[out] numsub     Variable to store number of suboperators
6827a982d89SJeremy L. Thompson 
6837a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6847a982d89SJeremy L. Thompson 
6857a982d89SJeremy L. Thompson   @ref Backend
6867a982d89SJeremy L. Thompson **/
6877a982d89SJeremy L. Thompson 
6887a982d89SJeremy L. Thompson int CeedOperatorGetNumSub(CeedOperator op, CeedInt *numsub) {
6897a982d89SJeremy L. Thompson   if (!op->composite)
6907a982d89SJeremy L. Thompson     // LCOV_EXCL_START
691e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR, "Not a composite operator");
6927a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
6937a982d89SJeremy L. Thompson 
6947a982d89SJeremy L. Thompson   *numsub = op->numsub;
695e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6967a982d89SJeremy L. Thompson }
6977a982d89SJeremy L. Thompson 
6987a982d89SJeremy L. Thompson /**
6997a982d89SJeremy L. Thompson   @brief Get the list of suboperators associated with a CeedOperator
7007a982d89SJeremy L. Thompson 
7017a982d89SJeremy L. Thompson   @param op                CeedOperator
7027a982d89SJeremy L. Thompson   @param[out] suboperators Variable to store list of suboperators
7037a982d89SJeremy L. Thompson 
7047a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
7057a982d89SJeremy L. Thompson 
7067a982d89SJeremy L. Thompson   @ref Backend
7077a982d89SJeremy L. Thompson **/
7087a982d89SJeremy L. Thompson 
7097a982d89SJeremy L. Thompson int CeedOperatorGetSubList(CeedOperator op, CeedOperator **suboperators) {
7107a982d89SJeremy L. Thompson   if (!op->composite)
7117a982d89SJeremy L. Thompson     // LCOV_EXCL_START
712e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR, "Not a composite operator");
7137a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
7147a982d89SJeremy L. Thompson 
7157a982d89SJeremy L. Thompson   *suboperators = op->suboperators;
716e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
7177a982d89SJeremy L. Thompson }
7187a982d89SJeremy L. Thompson 
7197a982d89SJeremy L. Thompson /**
7207a982d89SJeremy L. Thompson   @brief Get the backend data of a CeedOperator
7217a982d89SJeremy L. Thompson 
7227a982d89SJeremy L. Thompson   @param op              CeedOperator
7237a982d89SJeremy L. Thompson   @param[out] data       Variable to store data
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 
730777ff853SJeremy L Thompson int CeedOperatorGetData(CeedOperator op, void *data) {
731777ff853SJeremy L Thompson   *(void **)data = op->data;
732e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
7337a982d89SJeremy L. Thompson }
7347a982d89SJeremy L. Thompson 
7357a982d89SJeremy L. Thompson /**
7367a982d89SJeremy L. Thompson   @brief Set the backend data of a CeedOperator
7377a982d89SJeremy L. Thompson 
7387a982d89SJeremy L. Thompson   @param[out] op         CeedOperator
7397a982d89SJeremy L. Thompson   @param data            Data to set
7407a982d89SJeremy L. Thompson 
7417a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
7427a982d89SJeremy L. Thompson 
7437a982d89SJeremy L. Thompson   @ref Backend
7447a982d89SJeremy L. Thompson **/
7457a982d89SJeremy L. Thompson 
746777ff853SJeremy L Thompson int CeedOperatorSetData(CeedOperator op, void *data) {
747777ff853SJeremy L Thompson   op->data = data;
748e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
7497a982d89SJeremy L. Thompson }
7507a982d89SJeremy L. Thompson 
7517a982d89SJeremy L. Thompson /**
7527a982d89SJeremy L. Thompson   @brief Set the setup flag of a CeedOperator to True
7537a982d89SJeremy L. Thompson 
7547a982d89SJeremy L. Thompson   @param op              CeedOperator
7557a982d89SJeremy L. Thompson 
7567a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
7577a982d89SJeremy L. Thompson 
7587a982d89SJeremy L. Thompson   @ref Backend
7597a982d89SJeremy L. Thompson **/
7607a982d89SJeremy L. Thompson 
7617a982d89SJeremy L. Thompson int CeedOperatorSetSetupDone(CeedOperator op) {
762e15f9bd0SJeremy L Thompson   op->backendsetup = true;
763e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
7647a982d89SJeremy L. Thompson }
7657a982d89SJeremy L. Thompson 
7667a982d89SJeremy L. Thompson /**
7677a982d89SJeremy L. Thompson   @brief Get the CeedOperatorFields of a CeedOperator
7687a982d89SJeremy L. Thompson 
7697a982d89SJeremy L. Thompson   @param op                 CeedOperator
7707a982d89SJeremy L. Thompson   @param[out] inputfields   Variable to store inputfields
7717a982d89SJeremy L. Thompson   @param[out] outputfields  Variable to store outputfields
7727a982d89SJeremy L. Thompson 
7737a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
7747a982d89SJeremy L. Thompson 
7757a982d89SJeremy L. Thompson   @ref Backend
7767a982d89SJeremy L. Thompson **/
7777a982d89SJeremy L. Thompson 
7787a982d89SJeremy L. Thompson int CeedOperatorGetFields(CeedOperator op, CeedOperatorField **inputfields,
7797a982d89SJeremy L. Thompson                           CeedOperatorField **outputfields) {
7807a982d89SJeremy L. Thompson   if (op->composite)
7817a982d89SJeremy L. Thompson     // LCOV_EXCL_START
782e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
783e15f9bd0SJeremy L Thompson                      "Not defined for composite operator");
7847a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
7857a982d89SJeremy L. Thompson 
7867a982d89SJeremy L. Thompson   if (inputfields) *inputfields = op->inputfields;
7877a982d89SJeremy L. Thompson   if (outputfields) *outputfields = op->outputfields;
788e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
7897a982d89SJeremy L. Thompson }
7907a982d89SJeremy L. Thompson 
7917a982d89SJeremy L. Thompson /**
7927a982d89SJeremy L. Thompson   @brief Get the CeedElemRestriction of a CeedOperatorField
7937a982d89SJeremy L. Thompson 
7947a982d89SJeremy L. Thompson   @param opfield         CeedOperatorField
7957a982d89SJeremy L. Thompson   @param[out] rstr       Variable to store CeedElemRestriction
7967a982d89SJeremy L. Thompson 
7977a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
7987a982d89SJeremy L. Thompson 
7997a982d89SJeremy L. Thompson   @ref Backend
8007a982d89SJeremy L. Thompson **/
8017a982d89SJeremy L. Thompson 
8027a982d89SJeremy L. Thompson int CeedOperatorFieldGetElemRestriction(CeedOperatorField opfield,
8037a982d89SJeremy L. Thompson                                         CeedElemRestriction *rstr) {
8047a982d89SJeremy L. Thompson   *rstr = opfield->Erestrict;
805e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
8067a982d89SJeremy L. Thompson }
8077a982d89SJeremy L. Thompson 
8087a982d89SJeremy L. Thompson /**
8097a982d89SJeremy L. Thompson   @brief Get the CeedBasis of a CeedOperatorField
8107a982d89SJeremy L. Thompson 
8117a982d89SJeremy L. Thompson   @param opfield         CeedOperatorField
8127a982d89SJeremy L. Thompson   @param[out] basis      Variable to store CeedBasis
8137a982d89SJeremy L. Thompson 
8147a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
8157a982d89SJeremy L. Thompson 
8167a982d89SJeremy L. Thompson   @ref Backend
8177a982d89SJeremy L. Thompson **/
8187a982d89SJeremy L. Thompson 
8197a982d89SJeremy L. Thompson int CeedOperatorFieldGetBasis(CeedOperatorField opfield, CeedBasis *basis) {
8207a982d89SJeremy L. Thompson   *basis = opfield->basis;
821e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
8227a982d89SJeremy L. Thompson }
8237a982d89SJeremy L. Thompson 
8247a982d89SJeremy L. Thompson /**
8257a982d89SJeremy L. Thompson   @brief Get the CeedVector of a CeedOperatorField
8267a982d89SJeremy L. Thompson 
8277a982d89SJeremy L. Thompson   @param opfield         CeedOperatorField
8287a982d89SJeremy L. Thompson   @param[out] vec        Variable to store CeedVector
8297a982d89SJeremy L. Thompson 
8307a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
8317a982d89SJeremy L. Thompson 
8327a982d89SJeremy L. Thompson   @ref Backend
8337a982d89SJeremy L. Thompson **/
8347a982d89SJeremy L. Thompson 
8357a982d89SJeremy L. Thompson int CeedOperatorFieldGetVector(CeedOperatorField opfield, CeedVector *vec) {
8367a982d89SJeremy L. Thompson   *vec = opfield->vec;
837e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
8387a982d89SJeremy L. Thompson }
8397a982d89SJeremy L. Thompson 
8407a982d89SJeremy L. Thompson /// @}
8417a982d89SJeremy L. Thompson 
8427a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
8437a982d89SJeremy L. Thompson /// CeedOperator Public API
8447a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
8457a982d89SJeremy L. Thompson /// @addtogroup CeedOperatorUser
846dfdf5a53Sjeremylt /// @{
847d7b241e6Sjeremylt 
848d7b241e6Sjeremylt /**
8490219ea01SJeremy L Thompson   @brief Create a CeedOperator and associate a CeedQFunction. A CeedBasis and
8500219ea01SJeremy L Thompson            CeedElemRestriction can be associated with CeedQFunction fields with
8510219ea01SJeremy L Thompson            \ref CeedOperatorSetField.
852d7b241e6Sjeremylt 
853b11c1e72Sjeremylt   @param ceed    A Ceed object where the CeedOperator will be created
854d7b241e6Sjeremylt   @param qf      QFunction defining the action of the operator at quadrature points
85534138859Sjeremylt   @param dqf     QFunction defining the action of the Jacobian of @a qf (or
8564cc79fe7SJed Brown                    @ref CEED_QFUNCTION_NONE)
857d7b241e6Sjeremylt   @param dqfT    QFunction defining the action of the transpose of the Jacobian
8584cc79fe7SJed Brown                    of @a qf (or @ref CEED_QFUNCTION_NONE)
859b11c1e72Sjeremylt   @param[out] op Address of the variable where the newly created
860b11c1e72Sjeremylt                      CeedOperator will be stored
861b11c1e72Sjeremylt 
862b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
863dfdf5a53Sjeremylt 
8647a982d89SJeremy L. Thompson   @ref User
865d7b241e6Sjeremylt  */
866d7b241e6Sjeremylt int CeedOperatorCreate(Ceed ceed, CeedQFunction qf, CeedQFunction dqf,
867d7b241e6Sjeremylt                        CeedQFunction dqfT, CeedOperator *op) {
868d7b241e6Sjeremylt   int ierr;
869d7b241e6Sjeremylt 
8705fe0d4faSjeremylt   if (!ceed->OperatorCreate) {
8715fe0d4faSjeremylt     Ceed delegate;
872aefd8378Sjeremylt     ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr);
8735fe0d4faSjeremylt 
8745fe0d4faSjeremylt     if (!delegate)
875c042f62fSJeremy L Thompson       // LCOV_EXCL_START
876e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_UNSUPPORTED,
877e15f9bd0SJeremy L Thompson                        "Backend does not support OperatorCreate");
878c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
8795fe0d4faSjeremylt 
8805fe0d4faSjeremylt     ierr = CeedOperatorCreate(delegate, qf, dqf, dqfT, op); CeedChk(ierr);
881e15f9bd0SJeremy L Thompson     return CEED_ERROR_SUCCESS;
8825fe0d4faSjeremylt   }
8835fe0d4faSjeremylt 
884b3b7035fSJeremy L Thompson   if (!qf || qf == CEED_QFUNCTION_NONE)
885b3b7035fSJeremy L Thompson     // LCOV_EXCL_START
886e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_MINOR,
887e15f9bd0SJeremy L Thompson                      "Operator must have a valid QFunction.");
888b3b7035fSJeremy L Thompson   // LCOV_EXCL_STOP
889d7b241e6Sjeremylt   ierr = CeedCalloc(1, op); CeedChk(ierr);
890d7b241e6Sjeremylt   (*op)->ceed = ceed;
891d7b241e6Sjeremylt   ceed->refcount++;
892d7b241e6Sjeremylt   (*op)->refcount = 1;
893d7b241e6Sjeremylt   (*op)->qf = qf;
894d7b241e6Sjeremylt   qf->refcount++;
895442e7f0bSjeremylt   if (dqf && dqf != CEED_QFUNCTION_NONE) {
896d7b241e6Sjeremylt     (*op)->dqf = dqf;
897442e7f0bSjeremylt     dqf->refcount++;
898442e7f0bSjeremylt   }
899442e7f0bSjeremylt   if (dqfT && dqfT != CEED_QFUNCTION_NONE) {
900d7b241e6Sjeremylt     (*op)->dqfT = dqfT;
901442e7f0bSjeremylt     dqfT->refcount++;
902442e7f0bSjeremylt   }
903fe2413ffSjeremylt   ierr = CeedCalloc(16, &(*op)->inputfields); CeedChk(ierr);
904fe2413ffSjeremylt   ierr = CeedCalloc(16, &(*op)->outputfields); CeedChk(ierr);
905d7b241e6Sjeremylt   ierr = ceed->OperatorCreate(*op); CeedChk(ierr);
906e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
907d7b241e6Sjeremylt }
908d7b241e6Sjeremylt 
909d7b241e6Sjeremylt /**
91052d6035fSJeremy L Thompson   @brief Create an operator that composes the action of several operators
91152d6035fSJeremy L Thompson 
91252d6035fSJeremy L Thompson   @param ceed    A Ceed object where the CeedOperator will be created
91352d6035fSJeremy L Thompson   @param[out] op Address of the variable where the newly created
91452d6035fSJeremy L Thompson                      Composite CeedOperator will be stored
91552d6035fSJeremy L Thompson 
91652d6035fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
91752d6035fSJeremy L Thompson 
9187a982d89SJeremy L. Thompson   @ref User
91952d6035fSJeremy L Thompson  */
92052d6035fSJeremy L Thompson int CeedCompositeOperatorCreate(Ceed ceed, CeedOperator *op) {
92152d6035fSJeremy L Thompson   int ierr;
92252d6035fSJeremy L Thompson 
92352d6035fSJeremy L Thompson   if (!ceed->CompositeOperatorCreate) {
92452d6035fSJeremy L Thompson     Ceed delegate;
925aefd8378Sjeremylt     ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr);
92652d6035fSJeremy L Thompson 
927250756a7Sjeremylt     if (delegate) {
92852d6035fSJeremy L Thompson       ierr = CeedCompositeOperatorCreate(delegate, op); CeedChk(ierr);
929e15f9bd0SJeremy L Thompson       return CEED_ERROR_SUCCESS;
93052d6035fSJeremy L Thompson     }
931250756a7Sjeremylt   }
93252d6035fSJeremy L Thompson 
93352d6035fSJeremy L Thompson   ierr = CeedCalloc(1, op); CeedChk(ierr);
93452d6035fSJeremy L Thompson   (*op)->ceed = ceed;
93552d6035fSJeremy L Thompson   ceed->refcount++;
93652d6035fSJeremy L Thompson   (*op)->composite = true;
93752d6035fSJeremy L Thompson   ierr = CeedCalloc(16, &(*op)->suboperators); CeedChk(ierr);
938250756a7Sjeremylt 
939250756a7Sjeremylt   if (ceed->CompositeOperatorCreate) {
94052d6035fSJeremy L Thompson     ierr = ceed->CompositeOperatorCreate(*op); CeedChk(ierr);
941250756a7Sjeremylt   }
942e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
94352d6035fSJeremy L Thompson }
94452d6035fSJeremy L Thompson 
94552d6035fSJeremy L Thompson /**
946b11c1e72Sjeremylt   @brief Provide a field to a CeedOperator for use by its CeedQFunction
947d7b241e6Sjeremylt 
948d7b241e6Sjeremylt   This function is used to specify both active and passive fields to a
949d7b241e6Sjeremylt   CeedOperator.  For passive fields, a vector @arg v must be provided.  Passive
950d7b241e6Sjeremylt   fields can inputs or outputs (updated in-place when operator is applied).
951d7b241e6Sjeremylt 
952d7b241e6Sjeremylt   Active fields must be specified using this function, but their data (in a
953d7b241e6Sjeremylt   CeedVector) is passed in CeedOperatorApply().  There can be at most one active
954d7b241e6Sjeremylt   input and at most one active output.
955d7b241e6Sjeremylt 
9568c91a0c9SJeremy L Thompson   @param op         CeedOperator on which to provide the field
9578795c945Sjeremylt   @param fieldname  Name of the field (to be matched with the name used by
9588795c945Sjeremylt                       CeedQFunction)
959b11c1e72Sjeremylt   @param r          CeedElemRestriction
9604cc79fe7SJed Brown   @param b          CeedBasis in which the field resides or @ref CEED_BASIS_COLLOCATED
961b11c1e72Sjeremylt                       if collocated with quadrature points
9624cc79fe7SJed Brown   @param v          CeedVector to be used by CeedOperator or @ref CEED_VECTOR_ACTIVE
9634cc79fe7SJed Brown                       if field is active or @ref CEED_VECTOR_NONE if using
9644cc79fe7SJed Brown                       @ref CEED_EVAL_WEIGHT in the QFunction
965b11c1e72Sjeremylt 
966b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
967dfdf5a53Sjeremylt 
9687a982d89SJeremy L. Thompson   @ref User
969b11c1e72Sjeremylt **/
970d7b241e6Sjeremylt int CeedOperatorSetField(CeedOperator op, const char *fieldname,
971a8d32208Sjeremylt                          CeedElemRestriction r, CeedBasis b, CeedVector v) {
972d7b241e6Sjeremylt   int ierr;
97352d6035fSJeremy L Thompson   if (op->composite)
974c042f62fSJeremy L Thompson     // LCOV_EXCL_START
975*e1e9e29dSJed Brown     return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
976e15f9bd0SJeremy L Thompson                      "Cannot add field to composite operator.");
977c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
9788b067b84SJed Brown   if (!r)
979c042f62fSJeremy L Thompson     // LCOV_EXCL_START
980*e1e9e29dSJed Brown     return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
981c042f62fSJeremy L Thompson                      "ElemRestriction r for field \"%s\" must be non-NULL.",
982c042f62fSJeremy L Thompson                      fieldname);
983c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
9848b067b84SJed Brown   if (!b)
985c042f62fSJeremy L Thompson     // LCOV_EXCL_START
986*e1e9e29dSJed Brown     return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
987e15f9bd0SJeremy L Thompson                      "Basis b for field \"%s\" must be non-NULL.",
988c042f62fSJeremy L Thompson                      fieldname);
989c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
9908b067b84SJed Brown   if (!v)
991c042f62fSJeremy L Thompson     // LCOV_EXCL_START
992*e1e9e29dSJed Brown     return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
993e15f9bd0SJeremy L Thompson                      "Vector v for field \"%s\" must be non-NULL.",
994c042f62fSJeremy L Thompson                      fieldname);
995c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
99652d6035fSJeremy L Thompson 
997d7b241e6Sjeremylt   CeedInt numelements;
998d7b241e6Sjeremylt   ierr = CeedElemRestrictionGetNumElements(r, &numelements); CeedChk(ierr);
99915910d16Sjeremylt   if (r != CEED_ELEMRESTRICTION_NONE && op->hasrestriction &&
100015910d16Sjeremylt       op->numelements != numelements)
1001c042f62fSJeremy L Thompson     // LCOV_EXCL_START
1002e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_DIMENSION,
10031d102b48SJeremy L Thompson                      "ElemRestriction with %d elements incompatible with prior "
10041d102b48SJeremy L Thompson                      "%d elements", numelements, op->numelements);
1005c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
1006d7b241e6Sjeremylt 
1007d7b241e6Sjeremylt   CeedInt numqpoints;
1008e15f9bd0SJeremy L Thompson   if (b != CEED_BASIS_COLLOCATED) {
1009d7b241e6Sjeremylt     ierr = CeedBasisGetNumQuadraturePoints(b, &numqpoints); CeedChk(ierr);
1010d7b241e6Sjeremylt     if (op->numqpoints && op->numqpoints != numqpoints)
1011c042f62fSJeremy L Thompson       // LCOV_EXCL_START
1012e15f9bd0SJeremy L Thompson       return CeedError(op->ceed, CEED_ERROR_DIMENSION,
1013e15f9bd0SJeremy L Thompson                        "Basis with %d quadrature points "
10141d102b48SJeremy L Thompson                        "incompatible with prior %d points", numqpoints,
10151d102b48SJeremy L Thompson                        op->numqpoints);
1016c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
1017d7b241e6Sjeremylt   }
101815910d16Sjeremylt   CeedQFunctionField qfield;
1019d1bcdac9Sjeremylt   CeedOperatorField *ofield;
1020d7b241e6Sjeremylt   for (CeedInt i=0; i<op->qf->numinputfields; i++) {
1021fe2413ffSjeremylt     if (!strcmp(fieldname, (*op->qf->inputfields[i]).fieldname)) {
102215910d16Sjeremylt       qfield = op->qf->inputfields[i];
1023d7b241e6Sjeremylt       ofield = &op->inputfields[i];
1024d7b241e6Sjeremylt       goto found;
1025d7b241e6Sjeremylt     }
1026d7b241e6Sjeremylt   }
1027d7b241e6Sjeremylt   for (CeedInt i=0; i<op->qf->numoutputfields; i++) {
1028fe2413ffSjeremylt     if (!strcmp(fieldname, (*op->qf->outputfields[i]).fieldname)) {
1029e15f9bd0SJeremy L Thompson       qfield = op->qf->outputfields[i];
1030d7b241e6Sjeremylt       ofield = &op->outputfields[i];
1031d7b241e6Sjeremylt       goto found;
1032d7b241e6Sjeremylt     }
1033d7b241e6Sjeremylt   }
1034c042f62fSJeremy L Thompson   // LCOV_EXCL_START
1035e15f9bd0SJeremy L Thompson   return CeedError(op->ceed, CEED_ERROR_INCOMPLETE,
1036e15f9bd0SJeremy L Thompson                    "QFunction has no knowledge of field '%s'",
1037d7b241e6Sjeremylt                    fieldname);
1038c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
1039d7b241e6Sjeremylt found:
1040e15f9bd0SJeremy L Thompson   ierr = CeedOperatorCheckField(op->ceed, qfield, r, b); CeedChk(ierr);
1041fe2413ffSjeremylt   ierr = CeedCalloc(1, ofield); CeedChk(ierr);
1042e15f9bd0SJeremy L Thompson 
1043e15f9bd0SJeremy L Thompson   (*ofield)->vec = v;
1044e15f9bd0SJeremy L Thompson   if (v != CEED_VECTOR_ACTIVE && v != CEED_VECTOR_NONE) {
1045e15f9bd0SJeremy L Thompson     v->refcount += 1;
1046e15f9bd0SJeremy L Thompson   }
1047e15f9bd0SJeremy L Thompson 
1048fe2413ffSjeremylt   (*ofield)->Erestrict = r;
104971352a93Sjeremylt   r->refcount += 1;
1050e15f9bd0SJeremy L Thompson   if (r != CEED_ELEMRESTRICTION_NONE) {
1051e15f9bd0SJeremy L Thompson     op->numelements = numelements;
1052e15f9bd0SJeremy L Thompson     op->hasrestriction = true; // Restriction set, but numelements may be 0
1053e15f9bd0SJeremy L Thompson   }
1054d99fa3c5SJeremy L Thompson 
1055e15f9bd0SJeremy L Thompson   (*ofield)->basis = b;
1056e15f9bd0SJeremy L Thompson   if (b != CEED_BASIS_COLLOCATED) {
1057e15f9bd0SJeremy L Thompson     op->numqpoints = numqpoints;
1058e15f9bd0SJeremy L Thompson     b->refcount += 1;
1059e15f9bd0SJeremy L Thompson   }
1060e15f9bd0SJeremy L Thompson 
1061e15f9bd0SJeremy L Thompson   op->nfields += 1;
1062d99fa3c5SJeremy L Thompson   size_t len = strlen(fieldname);
1063d99fa3c5SJeremy L Thompson   char *tmp;
1064d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(len+1, &tmp); CeedChk(ierr);
1065d99fa3c5SJeremy L Thompson   memcpy(tmp, fieldname, len+1);
1066d99fa3c5SJeremy L Thompson   (*ofield)->fieldname = tmp;
1067e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1068d7b241e6Sjeremylt }
1069d7b241e6Sjeremylt 
1070d7b241e6Sjeremylt /**
107152d6035fSJeremy L Thompson   @brief Add a sub-operator to a composite CeedOperator
1072288c0443SJeremy L Thompson 
107334138859Sjeremylt   @param[out] compositeop Composite CeedOperator
107434138859Sjeremylt   @param      subop       Sub-operator CeedOperator
107552d6035fSJeremy L Thompson 
107652d6035fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
107752d6035fSJeremy L Thompson 
10787a982d89SJeremy L. Thompson   @ref User
107952d6035fSJeremy L Thompson  */
1080692c2638Sjeremylt int CeedCompositeOperatorAddSub(CeedOperator compositeop, CeedOperator subop) {
108152d6035fSJeremy L Thompson   if (!compositeop->composite)
1082c042f62fSJeremy L Thompson     // LCOV_EXCL_START
1083e15f9bd0SJeremy L Thompson     return CeedError(compositeop->ceed, CEED_ERROR_MINOR,
1084e2f04181SAndrew T. Barker                      "CeedOperator is not a composite operator");
1085c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
108652d6035fSJeremy L Thompson 
108752d6035fSJeremy L Thompson   if (compositeop->numsub == CEED_COMPOSITE_MAX)
1088c042f62fSJeremy L Thompson     // LCOV_EXCL_START
1089e15f9bd0SJeremy L Thompson     return CeedError(compositeop->ceed, CEED_ERROR_UNSUPPORTED,
1090e15f9bd0SJeremy L Thompson                      "Cannot add additional suboperators");
1091c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
109252d6035fSJeremy L Thompson 
109352d6035fSJeremy L Thompson   compositeop->suboperators[compositeop->numsub] = subop;
109452d6035fSJeremy L Thompson   subop->refcount++;
109552d6035fSJeremy L Thompson   compositeop->numsub++;
1096e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
109752d6035fSJeremy L Thompson }
109852d6035fSJeremy L Thompson 
109952d6035fSJeremy L Thompson /**
11001d102b48SJeremy L Thompson   @brief Assemble a linear CeedQFunction associated with a CeedOperator
11011d102b48SJeremy L Thompson 
11021d102b48SJeremy L Thompson   This returns a CeedVector containing a matrix at each quadrature point
11031d102b48SJeremy L Thompson     providing the action of the CeedQFunction associated with the CeedOperator.
11041d102b48SJeremy L Thompson     The vector 'assembled' is of shape
11051d102b48SJeremy L Thompson       [num_elements, num_input_fields, num_output_fields, num_quad_points]
11061d102b48SJeremy L Thompson     and contains column-major matrices representing the action of the
11071d102b48SJeremy L Thompson     CeedQFunction for a corresponding quadrature point on an element. Inputs and
11081d102b48SJeremy L Thompson     outputs are in the order provided by the user when adding CeedOperator fields.
11094cc79fe7SJed Brown     For example, a CeedQFunction with inputs 'u' and 'gradu' and outputs 'gradv' and
11101d102b48SJeremy L Thompson     'v', provided in that order, would result in an assembled QFunction that
11111d102b48SJeremy L Thompson     consists of (1 + dim) x (dim + 1) matrices at each quadrature point acting
11121d102b48SJeremy L Thompson     on the input [u, du_0, du_1] and producing the output [dv_0, dv_1, v].
11131d102b48SJeremy L Thompson 
11141d102b48SJeremy L Thompson   @param op             CeedOperator to assemble CeedQFunction
11151d102b48SJeremy L Thompson   @param[out] assembled CeedVector to store assembled CeedQFunction at
11161d102b48SJeremy L Thompson                           quadrature points
11171d102b48SJeremy L Thompson   @param[out] rstr      CeedElemRestriction for CeedVector containing assembled
11181d102b48SJeremy L Thompson                           CeedQFunction
11191d102b48SJeremy L Thompson   @param request        Address of CeedRequest for non-blocking completion, else
11204cc79fe7SJed Brown                           @ref CEED_REQUEST_IMMEDIATE
11211d102b48SJeremy L Thompson 
11221d102b48SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
11231d102b48SJeremy L Thompson 
11247a982d89SJeremy L. Thompson   @ref User
11251d102b48SJeremy L Thompson **/
112680ac2e43SJeremy L Thompson int CeedOperatorLinearAssembleQFunction(CeedOperator op, CeedVector *assembled,
11277f823360Sjeremylt                                         CeedElemRestriction *rstr,
11287f823360Sjeremylt                                         CeedRequest *request) {
11291d102b48SJeremy L Thompson   int ierr;
1130e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
11311d102b48SJeremy L Thompson 
11327172caadSjeremylt   // Backend version
113380ac2e43SJeremy L Thompson   if (op->LinearAssembleQFunction) {
1134e2f04181SAndrew T. Barker     return op->LinearAssembleQFunction(op, assembled, rstr, request);
11355107b09fSJeremy L Thompson   } else {
11365107b09fSJeremy L Thompson     // Fallback to reference Ceed
11375107b09fSJeremy L Thompson     if (!op->opfallback) {
11385107b09fSJeremy L Thompson       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
11395107b09fSJeremy L Thompson     }
11405107b09fSJeremy L Thompson     // Assemble
1141e2f04181SAndrew T. Barker     return CeedOperatorLinearAssembleQFunction(op->opfallback, assembled,
1142e2f04181SAndrew T. Barker            rstr, request);
11435107b09fSJeremy L Thompson   }
11441d102b48SJeremy L Thompson }
11451d102b48SJeremy L Thompson 
11461d102b48SJeremy L Thompson /**
1147d965c7a7SJeremy L Thompson   @brief Assemble the diagonal of a square linear CeedOperator
1148b7ec98d8SJeremy L Thompson 
11499e9210b8SJeremy L Thompson   This overwrites a CeedVector with the diagonal of a linear CeedOperator.
1150b7ec98d8SJeremy L Thompson 
1151c04a41a7SJeremy L Thompson   Note: Currently only non-composite CeedOperators with a single field and
1152c04a41a7SJeremy L Thompson           composite CeedOperators with single field sub-operators are supported.
1153d965c7a7SJeremy L Thompson 
1154b7ec98d8SJeremy L Thompson   @param op             CeedOperator to assemble CeedQFunction
1155b7ec98d8SJeremy L Thompson   @param[out] assembled CeedVector to store assembled CeedOperator diagonal
1156b7ec98d8SJeremy L Thompson   @param request        Address of CeedRequest for non-blocking completion, else
11574cc79fe7SJed Brown                           @ref CEED_REQUEST_IMMEDIATE
1158b7ec98d8SJeremy L Thompson 
1159b7ec98d8SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1160b7ec98d8SJeremy L Thompson 
11617a982d89SJeremy L. Thompson   @ref User
1162b7ec98d8SJeremy L Thompson **/
11632bba3ffaSJeremy L Thompson int CeedOperatorLinearAssembleDiagonal(CeedOperator op, CeedVector assembled,
11647f823360Sjeremylt                                        CeedRequest *request) {
1165b7ec98d8SJeremy L Thompson   int ierr;
1166e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
1167b7ec98d8SJeremy L Thompson 
1168b7ec98d8SJeremy L Thompson   // Use backend version, if available
116980ac2e43SJeremy L Thompson   if (op->LinearAssembleDiagonal) {
1170e2f04181SAndrew T. Barker     return op->LinearAssembleDiagonal(op, assembled, request);
11719e9210b8SJeremy L Thompson   } else if (op->LinearAssembleAddDiagonal) {
11729e9210b8SJeremy L Thompson     ierr = CeedVectorSetValue(assembled, 0.0); CeedChk(ierr);
11739e9210b8SJeremy L Thompson     return CeedOperatorLinearAssembleAddDiagonal(op, assembled, request);
11749e9210b8SJeremy L Thompson   } else {
11759e9210b8SJeremy L Thompson     // Fallback to reference Ceed
11769e9210b8SJeremy L Thompson     if (!op->opfallback) {
11779e9210b8SJeremy L Thompson       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
11789e9210b8SJeremy L Thompson     }
11799e9210b8SJeremy L Thompson     // Assemble
1180e2f04181SAndrew T. Barker     return CeedOperatorLinearAssembleDiagonal(op->opfallback, assembled,
1181e2f04181SAndrew T. Barker            request);
11829e9210b8SJeremy L Thompson   }
11839e9210b8SJeremy L Thompson }
11849e9210b8SJeremy L Thompson 
11859e9210b8SJeremy L Thompson /**
11869e9210b8SJeremy L Thompson   @brief Assemble the diagonal of a square linear CeedOperator
11879e9210b8SJeremy L Thompson 
11889e9210b8SJeremy L Thompson   This sums into a CeedVector the diagonal of a linear CeedOperator.
11899e9210b8SJeremy L Thompson 
11909e9210b8SJeremy L Thompson   Note: Currently only non-composite CeedOperators with a single field and
11919e9210b8SJeremy L Thompson           composite CeedOperators with single field sub-operators are supported.
11929e9210b8SJeremy L Thompson 
11939e9210b8SJeremy L Thompson   @param op             CeedOperator to assemble CeedQFunction
11949e9210b8SJeremy L Thompson   @param[out] assembled CeedVector to store assembled CeedOperator diagonal
11959e9210b8SJeremy L Thompson   @param request        Address of CeedRequest for non-blocking completion, else
11969e9210b8SJeremy L Thompson                           @ref CEED_REQUEST_IMMEDIATE
11979e9210b8SJeremy L Thompson 
11989e9210b8SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
11999e9210b8SJeremy L Thompson 
12009e9210b8SJeremy L Thompson   @ref User
12019e9210b8SJeremy L Thompson **/
12029e9210b8SJeremy L Thompson int CeedOperatorLinearAssembleAddDiagonal(CeedOperator op, CeedVector assembled,
12039e9210b8SJeremy L Thompson     CeedRequest *request) {
12049e9210b8SJeremy L Thompson   int ierr;
1205e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
12069e9210b8SJeremy L Thompson 
12079e9210b8SJeremy L Thompson   // Use backend version, if available
12089e9210b8SJeremy L Thompson   if (op->LinearAssembleAddDiagonal) {
1209e2f04181SAndrew T. Barker     return op->LinearAssembleAddDiagonal(op, assembled, request);
12107172caadSjeremylt   } else {
12117172caadSjeremylt     // Fallback to reference Ceed
12127172caadSjeremylt     if (!op->opfallback) {
12137172caadSjeremylt       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
1214b7ec98d8SJeremy L Thompson     }
12157172caadSjeremylt     // Assemble
1216e2f04181SAndrew T. Barker     return CeedOperatorLinearAssembleAddDiagonal(op->opfallback, assembled,
1217e2f04181SAndrew T. Barker            request);
1218b7ec98d8SJeremy L Thompson   }
1219b7ec98d8SJeremy L Thompson }
1220b7ec98d8SJeremy L Thompson 
1221b7ec98d8SJeremy L Thompson /**
1222d965c7a7SJeremy L Thompson   @brief Assemble the point block diagonal of a square linear CeedOperator
1223d965c7a7SJeremy L Thompson 
12249e9210b8SJeremy L Thompson   This overwrites a CeedVector with the point block diagonal of a linear
1225d965c7a7SJeremy L Thompson     CeedOperator.
1226d965c7a7SJeremy L Thompson 
1227c04a41a7SJeremy L Thompson   Note: Currently only non-composite CeedOperators with a single field and
1228c04a41a7SJeremy L Thompson           composite CeedOperators with single field sub-operators are supported.
1229d965c7a7SJeremy L Thompson 
1230d965c7a7SJeremy L Thompson   @param op             CeedOperator to assemble CeedQFunction
1231d965c7a7SJeremy L Thompson   @param[out] assembled CeedVector to store assembled CeedOperator point block
1232d965c7a7SJeremy L Thompson                           diagonal, provided in row-major form with an
1233d965c7a7SJeremy L Thompson                           @a ncomp * @a ncomp block at each node. The dimensions
1234d965c7a7SJeremy L Thompson                           of this vector are derived from the active vector
1235d965c7a7SJeremy L Thompson                           for the CeedOperator. The array has shape
1236d965c7a7SJeremy L Thompson                           [nodes, component out, component in].
1237d965c7a7SJeremy L Thompson   @param request        Address of CeedRequest for non-blocking completion, else
1238d965c7a7SJeremy L Thompson                           CEED_REQUEST_IMMEDIATE
1239d965c7a7SJeremy L Thompson 
1240d965c7a7SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1241d965c7a7SJeremy L Thompson 
1242d965c7a7SJeremy L Thompson   @ref User
1243d965c7a7SJeremy L Thompson **/
124480ac2e43SJeremy L Thompson int CeedOperatorLinearAssemblePointBlockDiagonal(CeedOperator op,
12452bba3ffaSJeremy L Thompson     CeedVector assembled, CeedRequest *request) {
1246d965c7a7SJeremy L Thompson   int ierr;
1247e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
1248d965c7a7SJeremy L Thompson 
1249d965c7a7SJeremy L Thompson   // Use backend version, if available
125080ac2e43SJeremy L Thompson   if (op->LinearAssemblePointBlockDiagonal) {
1251e2f04181SAndrew T. Barker     return op->LinearAssemblePointBlockDiagonal(op, assembled, request);
12529e9210b8SJeremy L Thompson   } else if (op->LinearAssembleAddPointBlockDiagonal) {
12539e9210b8SJeremy L Thompson     ierr = CeedVectorSetValue(assembled, 0.0); CeedChk(ierr);
12549e9210b8SJeremy L Thompson     return CeedOperatorLinearAssembleAddPointBlockDiagonal(op, assembled,
12559e9210b8SJeremy L Thompson            request);
1256d965c7a7SJeremy L Thompson   } else {
1257d965c7a7SJeremy L Thompson     // Fallback to reference Ceed
1258d965c7a7SJeremy L Thompson     if (!op->opfallback) {
1259d965c7a7SJeremy L Thompson       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
1260d965c7a7SJeremy L Thompson     }
1261d965c7a7SJeremy L Thompson     // Assemble
1262e2f04181SAndrew T. Barker     return CeedOperatorLinearAssemblePointBlockDiagonal(op->opfallback,
1263e2f04181SAndrew T. Barker            assembled, request);
12649e9210b8SJeremy L Thompson   }
12659e9210b8SJeremy L Thompson }
12669e9210b8SJeremy L Thompson 
12679e9210b8SJeremy L Thompson /**
12689e9210b8SJeremy L Thompson   @brief Assemble the point block diagonal of a square linear CeedOperator
12699e9210b8SJeremy L Thompson 
12709e9210b8SJeremy L Thompson   This sums into a CeedVector with the point block diagonal of a linear
12719e9210b8SJeremy L Thompson     CeedOperator.
12729e9210b8SJeremy L Thompson 
12739e9210b8SJeremy L Thompson   Note: Currently only non-composite CeedOperators with a single field and
12749e9210b8SJeremy L Thompson           composite CeedOperators with single field sub-operators are supported.
12759e9210b8SJeremy L Thompson 
12769e9210b8SJeremy L Thompson   @param op             CeedOperator to assemble CeedQFunction
12779e9210b8SJeremy L Thompson   @param[out] assembled CeedVector to store assembled CeedOperator point block
12789e9210b8SJeremy L Thompson                           diagonal, provided in row-major form with an
12799e9210b8SJeremy L Thompson                           @a ncomp * @a ncomp block at each node. The dimensions
12809e9210b8SJeremy L Thompson                           of this vector are derived from the active vector
12819e9210b8SJeremy L Thompson                           for the CeedOperator. The array has shape
12829e9210b8SJeremy L Thompson                           [nodes, component out, component in].
12839e9210b8SJeremy L Thompson   @param request        Address of CeedRequest for non-blocking completion, else
12849e9210b8SJeremy L Thompson                           CEED_REQUEST_IMMEDIATE
12859e9210b8SJeremy L Thompson 
12869e9210b8SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
12879e9210b8SJeremy L Thompson 
12889e9210b8SJeremy L Thompson   @ref User
12899e9210b8SJeremy L Thompson **/
12909e9210b8SJeremy L Thompson int CeedOperatorLinearAssembleAddPointBlockDiagonal(CeedOperator op,
12919e9210b8SJeremy L Thompson     CeedVector assembled, CeedRequest *request) {
12929e9210b8SJeremy L Thompson   int ierr;
1293e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
12949e9210b8SJeremy L Thompson 
12959e9210b8SJeremy L Thompson   // Use backend version, if available
12969e9210b8SJeremy L Thompson   if (op->LinearAssembleAddPointBlockDiagonal) {
1297e2f04181SAndrew T. Barker     return op->LinearAssembleAddPointBlockDiagonal(op, assembled, request);
12989e9210b8SJeremy L Thompson   } else {
12999e9210b8SJeremy L Thompson     // Fallback to reference Ceed
13009e9210b8SJeremy L Thompson     if (!op->opfallback) {
13019e9210b8SJeremy L Thompson       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
13029e9210b8SJeremy L Thompson     }
13039e9210b8SJeremy L Thompson     // Assemble
1304e2f04181SAndrew T. Barker     return CeedOperatorLinearAssembleAddPointBlockDiagonal(op->opfallback,
1305e2f04181SAndrew T. Barker            assembled, request);
1306d965c7a7SJeremy L Thompson   }
1307e2f04181SAndrew T. Barker }
1308e2f04181SAndrew T. Barker 
1309e2f04181SAndrew T. Barker /**
1310e2f04181SAndrew T. Barker    @brief Build nonzero pattern for non-composite operator.
1311e2f04181SAndrew T. Barker 
1312e2f04181SAndrew T. Barker    Users should generally use CeedOperatorLinearAssembleSymbolic()
1313e2f04181SAndrew T. Barker 
1314e2f04181SAndrew T. Barker    @ref Developer
1315e2f04181SAndrew T. Barker **/
1316e2f04181SAndrew T. Barker int CeedSingleOperatorAssembleSymbolic(CeedOperator op, CeedInt offset,
1317e2f04181SAndrew T. Barker                                        CeedInt *rows, CeedInt *cols) {
1318e2f04181SAndrew T. Barker   int ierr;
1319e2f04181SAndrew T. Barker   Ceed ceed = op->ceed;
1320e2f04181SAndrew T. Barker   if (op->composite)
1321e2f04181SAndrew T. Barker     // LCOV_EXCL_START
1322e2f04181SAndrew T. Barker     return CeedError(ceed, CEED_ERROR_UNSUPPORTED,
1323e2f04181SAndrew T. Barker                      "Composite operator not supported");
1324e2f04181SAndrew T. Barker   // LCOV_EXCL_STOP
1325e2f04181SAndrew T. Barker 
1326e2f04181SAndrew T. Barker   CeedElemRestriction rstrin;
1327e2f04181SAndrew T. Barker   ierr = CeedOperatorGetActiveElemRestriction(op, &rstrin); CeedChk(ierr);
1328e2f04181SAndrew T. Barker   CeedInt nelem, elemsize, nnodes, ncomp;
1329e2f04181SAndrew T. Barker   ierr = CeedElemRestrictionGetNumElements(rstrin, &nelem); CeedChk(ierr);
1330e2f04181SAndrew T. Barker   ierr = CeedElemRestrictionGetElementSize(rstrin, &elemsize); CeedChk(ierr);
1331e2f04181SAndrew T. Barker   ierr = CeedElemRestrictionGetLVectorSize(rstrin, &nnodes); CeedChk(ierr);
1332e2f04181SAndrew T. Barker   ierr = CeedElemRestrictionGetNumComponents(rstrin, &ncomp); CeedChk(ierr);
1333e2f04181SAndrew T. Barker   CeedInt layout_er[3];
1334e2f04181SAndrew T. Barker   ierr = CeedElemRestrictionGetELayout(rstrin, &layout_er); CeedChk(ierr);
1335e2f04181SAndrew T. Barker 
1336e2f04181SAndrew T. Barker   CeedInt local_nentries = elemsize*ncomp * elemsize*ncomp * nelem;
1337e2f04181SAndrew T. Barker 
1338e2f04181SAndrew T. Barker   // Determine elem_dof relation
1339e2f04181SAndrew T. Barker   CeedVector index_vec;
1340e2f04181SAndrew T. Barker   ierr = CeedVectorCreate(ceed, nnodes, &index_vec); CeedChk(ierr);
1341e2f04181SAndrew T. Barker   CeedScalar *array;
1342e2f04181SAndrew T. Barker   ierr = CeedVectorGetArray(index_vec, CEED_MEM_HOST, &array); CeedChk(ierr);
1343e2f04181SAndrew T. Barker   for (CeedInt i = 0; i < nnodes; ++i) {
1344e2f04181SAndrew T. Barker     array[i] = i;
1345e2f04181SAndrew T. Barker   }
1346e2f04181SAndrew T. Barker   ierr = CeedVectorRestoreArray(index_vec, &array); CeedChk(ierr);
1347e2f04181SAndrew T. Barker   CeedVector elem_dof;
1348e2f04181SAndrew T. Barker   ierr = CeedVectorCreate(ceed, nelem * elemsize * ncomp, &elem_dof);
1349e2f04181SAndrew T. Barker   CeedChk(ierr);
1350e2f04181SAndrew T. Barker   ierr = CeedVectorSetValue(elem_dof, 0.0); CeedChk(ierr);
1351e2f04181SAndrew T. Barker   CeedElemRestrictionApply(rstrin, CEED_NOTRANSPOSE, index_vec,
1352e2f04181SAndrew T. Barker                            elem_dof, CEED_REQUEST_IMMEDIATE); CeedChk(ierr);
1353e2f04181SAndrew T. Barker   const CeedScalar *elem_dof_a;
1354e2f04181SAndrew T. Barker   ierr = CeedVectorGetArrayRead(elem_dof, CEED_MEM_HOST, &elem_dof_a);
1355e2f04181SAndrew T. Barker   CeedChk(ierr);
1356e2f04181SAndrew T. Barker   ierr = CeedVectorDestroy(&index_vec); CeedChk(ierr);
1357e2f04181SAndrew T. Barker 
1358e2f04181SAndrew T. Barker   // Determine i, j locations for element matrices
1359e2f04181SAndrew T. Barker   CeedInt count = 0;
1360e2f04181SAndrew T. Barker   for (int e = 0; e < nelem; ++e) {
1361e2f04181SAndrew T. Barker     for (int compin = 0; compin < ncomp; ++compin) {
1362e2f04181SAndrew T. Barker       for (int compout = 0; compout < ncomp; ++compout) {
1363e2f04181SAndrew T. Barker         for (int i = 0; i < elemsize; ++i) {
1364e2f04181SAndrew T. Barker           for (int j = 0; j < elemsize; ++j) {
1365e2f04181SAndrew T. Barker             const CeedInt edof_index_row = (i)*layout_er[0] +
1366e2f04181SAndrew T. Barker                                            (compout)*layout_er[1] + e*layout_er[2];
1367e2f04181SAndrew T. Barker             const CeedInt edof_index_col = (j)*layout_er[0] +
1368e2f04181SAndrew T. Barker                                            (compin)*layout_er[1] + e*layout_er[2];
1369e2f04181SAndrew T. Barker 
1370e2f04181SAndrew T. Barker             const CeedInt row = elem_dof_a[edof_index_row];
1371e2f04181SAndrew T. Barker             const CeedInt col = elem_dof_a[edof_index_col];
1372e2f04181SAndrew T. Barker 
1373e2f04181SAndrew T. Barker             rows[offset + count] = row;
1374e2f04181SAndrew T. Barker             cols[offset + count] = col;
1375e2f04181SAndrew T. Barker             count++;
1376e2f04181SAndrew T. Barker           }
1377e2f04181SAndrew T. Barker         }
1378e2f04181SAndrew T. Barker       }
1379e2f04181SAndrew T. Barker     }
1380e2f04181SAndrew T. Barker   }
1381e2f04181SAndrew T. Barker   if (count != local_nentries)
1382e2f04181SAndrew T. Barker     // LCOV_EXCL_START
1383e2f04181SAndrew T. Barker     return CeedError(ceed, CEED_ERROR_MAJOR, "Error computing assembled entries");
1384e2f04181SAndrew T. Barker   // LCOV_EXCL_STOP
1385e2f04181SAndrew T. Barker   ierr = CeedVectorRestoreArrayRead(elem_dof, &elem_dof_a); CeedChk(ierr);
1386e2f04181SAndrew T. Barker   ierr = CeedVectorDestroy(&elem_dof); CeedChk(ierr);
1387e2f04181SAndrew T. Barker 
1388e2f04181SAndrew T. Barker   return CEED_ERROR_SUCCESS;
1389e2f04181SAndrew T. Barker }
1390e2f04181SAndrew T. Barker 
1391e2f04181SAndrew T. Barker /**
1392e2f04181SAndrew T. Barker    @brief Assemble nonzero entries for non-composite operator
1393e2f04181SAndrew T. Barker 
1394e2f04181SAndrew T. Barker    Users should generally use CeedOperatorLinearAssemble()
1395e2f04181SAndrew T. Barker 
1396e2f04181SAndrew T. Barker    @ref Developer
1397e2f04181SAndrew T. Barker **/
1398e2f04181SAndrew T. Barker int CeedSingleOperatorAssemble(CeedOperator op, CeedInt offset,
1399e2f04181SAndrew T. Barker                                CeedVector values) {
1400e2f04181SAndrew T. Barker   int ierr;
1401e2f04181SAndrew T. Barker   Ceed ceed = op->ceed;;
1402e2f04181SAndrew T. Barker   if (op->composite)
1403e2f04181SAndrew T. Barker     // LCOV_EXCL_START
1404e2f04181SAndrew T. Barker     return CeedError(ceed, CEED_ERROR_UNSUPPORTED,
1405e2f04181SAndrew T. Barker                      "Composite operator not supported");
1406e2f04181SAndrew T. Barker   // LCOV_EXCL_STOP
1407e2f04181SAndrew T. Barker 
1408e2f04181SAndrew T. Barker   // Assemble QFunction
1409e2f04181SAndrew T. Barker   CeedQFunction qf;
1410e2f04181SAndrew T. Barker   ierr = CeedOperatorGetQFunction(op, &qf); CeedChk(ierr);
1411e2f04181SAndrew T. Barker   CeedInt numinputfields, numoutputfields;
1412e2f04181SAndrew T. Barker   ierr= CeedQFunctionGetNumArgs(qf, &numinputfields, &numoutputfields);
1413e2f04181SAndrew T. Barker   CeedChk(ierr);
1414e2f04181SAndrew T. Barker   CeedVector assembledqf;
1415e2f04181SAndrew T. Barker   CeedElemRestriction rstr_q;
1416e2f04181SAndrew T. Barker   ierr = CeedOperatorLinearAssembleQFunction(
1417e2f04181SAndrew T. Barker            op, &assembledqf, &rstr_q, CEED_REQUEST_IMMEDIATE); CeedChk(ierr);
1418e2f04181SAndrew T. Barker 
1419e2f04181SAndrew T. Barker   CeedInt qflength;
1420e2f04181SAndrew T. Barker   ierr = CeedVectorGetLength(assembledqf, &qflength); CeedChk(ierr);
1421e2f04181SAndrew T. Barker 
1422e2f04181SAndrew T. Barker   CeedOperatorField *input_fields;
1423e2f04181SAndrew T. Barker   CeedOperatorField *output_fields;
1424e2f04181SAndrew T. Barker   ierr = CeedOperatorGetFields(op, &input_fields, &output_fields); CeedChk(ierr);
1425e2f04181SAndrew T. Barker 
1426e2f04181SAndrew T. Barker   // Determine active input basis
1427e2f04181SAndrew T. Barker   CeedQFunctionField *qffields;
1428e2f04181SAndrew T. Barker   ierr = CeedQFunctionGetFields(qf, &qffields, NULL); CeedChk(ierr);
1429e2f04181SAndrew T. Barker   CeedInt numemodein = 0, dim = 1;
1430e2f04181SAndrew T. Barker   CeedEvalMode *emodein = NULL;
1431e2f04181SAndrew T. Barker   CeedBasis basisin = NULL;
1432e2f04181SAndrew T. Barker   CeedElemRestriction rstrin = NULL;
1433e2f04181SAndrew T. Barker   for (CeedInt i=0; i<numinputfields; i++) {
1434e2f04181SAndrew T. Barker     CeedVector vec;
1435e2f04181SAndrew T. Barker     ierr = CeedOperatorFieldGetVector(input_fields[i], &vec); CeedChk(ierr);
1436e2f04181SAndrew T. Barker     if (vec == CEED_VECTOR_ACTIVE) {
1437e2f04181SAndrew T. Barker       ierr = CeedOperatorFieldGetBasis(input_fields[i], &basisin);
1438e2f04181SAndrew T. Barker       CeedChk(ierr);
1439e2f04181SAndrew T. Barker       ierr = CeedBasisGetDimension(basisin, &dim); CeedChk(ierr);
1440e2f04181SAndrew T. Barker       ierr = CeedOperatorFieldGetElemRestriction(input_fields[i], &rstrin);
1441e2f04181SAndrew T. Barker       CeedChk(ierr);
1442e2f04181SAndrew T. Barker       CeedEvalMode emode;
1443e2f04181SAndrew T. Barker       ierr = CeedQFunctionFieldGetEvalMode(qffields[i], &emode);
1444e2f04181SAndrew T. Barker       CeedChk(ierr);
1445e2f04181SAndrew T. Barker       switch (emode) {
1446e2f04181SAndrew T. Barker       case CEED_EVAL_NONE:
1447e2f04181SAndrew T. Barker       case CEED_EVAL_INTERP:
1448e2f04181SAndrew T. Barker         ierr = CeedRealloc(numemodein + 1, &emodein); CeedChk(ierr);
1449e2f04181SAndrew T. Barker         emodein[numemodein] = emode;
1450e2f04181SAndrew T. Barker         numemodein += 1;
1451e2f04181SAndrew T. Barker         break;
1452e2f04181SAndrew T. Barker       case CEED_EVAL_GRAD:
1453e2f04181SAndrew T. Barker         ierr = CeedRealloc(numemodein + dim, &emodein); CeedChk(ierr);
1454e2f04181SAndrew T. Barker         for (CeedInt d=0; d<dim; d++) {
1455e2f04181SAndrew T. Barker           emodein[numemodein+d] = emode;
1456e2f04181SAndrew T. Barker         }
1457e2f04181SAndrew T. Barker         numemodein += dim;
1458e2f04181SAndrew T. Barker         break;
1459e2f04181SAndrew T. Barker       case CEED_EVAL_WEIGHT:
1460e2f04181SAndrew T. Barker       case CEED_EVAL_DIV:
1461e2f04181SAndrew T. Barker       case CEED_EVAL_CURL:
1462e2f04181SAndrew T. Barker         break; // Caught by QF Assembly
1463e2f04181SAndrew T. Barker       }
1464e2f04181SAndrew T. Barker     }
1465e2f04181SAndrew T. Barker   }
1466e2f04181SAndrew T. Barker 
1467e2f04181SAndrew T. Barker   // Determine active output basis
1468e2f04181SAndrew T. Barker   ierr = CeedQFunctionGetFields(qf, NULL, &qffields); CeedChk(ierr);
1469e2f04181SAndrew T. Barker   CeedInt numemodeout = 0;
1470e2f04181SAndrew T. Barker   CeedEvalMode *emodeout = NULL;
1471e2f04181SAndrew T. Barker   CeedBasis basisout = NULL;
1472e2f04181SAndrew T. Barker   CeedElemRestriction rstrout = NULL;
1473e2f04181SAndrew T. Barker   for (CeedInt i=0; i<numoutputfields; i++) {
1474e2f04181SAndrew T. Barker     CeedVector vec;
1475e2f04181SAndrew T. Barker     ierr = CeedOperatorFieldGetVector(output_fields[i], &vec); CeedChk(ierr);
1476e2f04181SAndrew T. Barker     if (vec == CEED_VECTOR_ACTIVE) {
1477e2f04181SAndrew T. Barker       ierr = CeedOperatorFieldGetBasis(output_fields[i], &basisout);
1478e2f04181SAndrew T. Barker       CeedChk(ierr);
1479e2f04181SAndrew T. Barker       ierr = CeedOperatorFieldGetElemRestriction(output_fields[i], &rstrout);
1480e2f04181SAndrew T. Barker       CeedChk(ierr);
1481e2f04181SAndrew T. Barker       CeedEvalMode emode;
1482e2f04181SAndrew T. Barker       ierr = CeedQFunctionFieldGetEvalMode(qffields[i], &emode);
1483e2f04181SAndrew T. Barker       CeedChk(ierr);
1484e2f04181SAndrew T. Barker       switch (emode) {
1485e2f04181SAndrew T. Barker       case CEED_EVAL_NONE:
1486e2f04181SAndrew T. Barker       case CEED_EVAL_INTERP:
1487e2f04181SAndrew T. Barker         ierr = CeedRealloc(numemodeout + 1, &emodeout); CeedChk(ierr);
1488e2f04181SAndrew T. Barker         emodeout[numemodeout] = emode;
1489e2f04181SAndrew T. Barker         numemodeout += 1;
1490e2f04181SAndrew T. Barker         break;
1491e2f04181SAndrew T. Barker       case CEED_EVAL_GRAD:
1492e2f04181SAndrew T. Barker         ierr = CeedRealloc(numemodeout + dim, &emodeout); CeedChk(ierr);
1493e2f04181SAndrew T. Barker         for (CeedInt d=0; d<dim; d++) {
1494e2f04181SAndrew T. Barker           emodeout[numemodeout+d] = emode;
1495e2f04181SAndrew T. Barker         }
1496e2f04181SAndrew T. Barker         numemodeout += dim;
1497e2f04181SAndrew T. Barker         break;
1498e2f04181SAndrew T. Barker       case CEED_EVAL_WEIGHT:
1499e2f04181SAndrew T. Barker       case CEED_EVAL_DIV:
1500e2f04181SAndrew T. Barker       case CEED_EVAL_CURL:
1501e2f04181SAndrew T. Barker         break; // Caught by QF Assembly
1502e2f04181SAndrew T. Barker       }
1503e2f04181SAndrew T. Barker     }
1504e2f04181SAndrew T. Barker   }
1505e2f04181SAndrew T. Barker 
1506e2f04181SAndrew T. Barker   CeedInt nelem, elemsize, nqpts, ncomp;
1507e2f04181SAndrew T. Barker   ierr = CeedElemRestrictionGetNumElements(rstrin, &nelem); CeedChk(ierr);
1508e2f04181SAndrew T. Barker   ierr = CeedElemRestrictionGetElementSize(rstrin, &elemsize); CeedChk(ierr);
1509e2f04181SAndrew T. Barker   ierr = CeedElemRestrictionGetNumComponents(rstrin, &ncomp); CeedChk(ierr);
1510e2f04181SAndrew T. Barker   ierr = CeedBasisGetNumQuadraturePoints(basisin, &nqpts); CeedChk(ierr);
1511e2f04181SAndrew T. Barker 
1512e2f04181SAndrew T. Barker   CeedInt local_nentries = elemsize*ncomp * elemsize*ncomp * nelem;
1513e2f04181SAndrew T. Barker 
1514e2f04181SAndrew T. Barker   // loop over elements and put in data structure
1515e2f04181SAndrew T. Barker   const CeedScalar *interpin, *gradin;
1516e2f04181SAndrew T. Barker   ierr = CeedBasisGetInterp(basisin, &interpin); CeedChk(ierr);
1517e2f04181SAndrew T. Barker   ierr = CeedBasisGetGrad(basisin, &gradin); CeedChk(ierr);
1518e2f04181SAndrew T. Barker 
1519e2f04181SAndrew T. Barker   const CeedScalar *assembledqfarray;
1520e2f04181SAndrew T. Barker   ierr = CeedVectorGetArrayRead(assembledqf, CEED_MEM_HOST, &assembledqfarray);
1521e2f04181SAndrew T. Barker   CeedChk(ierr);
1522e2f04181SAndrew T. Barker 
1523e2f04181SAndrew T. Barker   CeedInt layout_qf[3];
1524e2f04181SAndrew T. Barker   ierr = CeedElemRestrictionGetELayout(rstr_q, &layout_qf); CeedChk(ierr);
1525e2f04181SAndrew T. Barker   ierr = CeedElemRestrictionDestroy(&rstr_q); CeedChk(ierr);
1526e2f04181SAndrew T. Barker 
1527e2f04181SAndrew T. Barker   // we store Bmat_in, Bmat_out, BTD, elem_mat in row-major order
1528e2f04181SAndrew T. Barker   CeedScalar Bmat_in[(nqpts * numemodein) * elemsize];
1529e2f04181SAndrew T. Barker   CeedScalar Bmat_out[(nqpts * numemodeout) * elemsize];
1530e2f04181SAndrew T. Barker   CeedScalar Dmat[numemodeout * numemodein * nqpts]; // logically 3-tensor
1531e2f04181SAndrew T. Barker   CeedScalar BTD[elemsize * nqpts*numemodein];
1532e2f04181SAndrew T. Barker   CeedScalar elem_mat[elemsize * elemsize];
1533e2f04181SAndrew T. Barker   int count = 0;
1534e2f04181SAndrew T. Barker   CeedScalar *vals;
1535e2f04181SAndrew T. Barker   ierr = CeedVectorGetArray(values, CEED_MEM_HOST, &vals); CeedChk(ierr);
1536e2f04181SAndrew T. Barker   for (int e = 0; e < nelem; ++e) {
1537e2f04181SAndrew T. Barker     for (int compin = 0; compin < ncomp; ++compin) {
1538e2f04181SAndrew T. Barker       for (int compout = 0; compout < ncomp; ++compout) {
1539e2f04181SAndrew T. Barker         for (int ell = 0; ell < (nqpts * numemodein) * elemsize; ++ell) {
1540e2f04181SAndrew T. Barker           Bmat_in[ell] = 0.0;
1541e2f04181SAndrew T. Barker         }
1542e2f04181SAndrew T. Barker         for (int ell = 0; ell < (nqpts * numemodeout) * elemsize; ++ell) {
1543e2f04181SAndrew T. Barker           Bmat_out[ell] = 0.0;
1544e2f04181SAndrew T. Barker         }
1545e2f04181SAndrew T. Barker         // Store block-diagonal D matrix as collection of small dense blocks
1546e2f04181SAndrew T. Barker         for (int ell = 0; ell < numemodein*numemodeout*nqpts; ++ell) {
1547e2f04181SAndrew T. Barker           Dmat[ell] = 0.0;
1548e2f04181SAndrew T. Barker         }
1549e2f04181SAndrew T. Barker         // form element matrix itself (for each block component)
1550e2f04181SAndrew T. Barker         for (int ell = 0; ell < elemsize*elemsize; ++ell) {
1551e2f04181SAndrew T. Barker           elem_mat[ell] = 0.0;
1552e2f04181SAndrew T. Barker         }
1553e2f04181SAndrew T. Barker         for (int q = 0; q < nqpts; ++q) {
1554e2f04181SAndrew T. Barker           for (int n = 0; n < elemsize; ++n) {
1555e2f04181SAndrew T. Barker             CeedInt din = -1;
1556e2f04181SAndrew T. Barker             for (int ein = 0; ein < numemodein; ++ein) {
1557e2f04181SAndrew T. Barker               const int qq = numemodein*q;
1558e2f04181SAndrew T. Barker               if (emodein[ein] == CEED_EVAL_INTERP) {
1559e2f04181SAndrew T. Barker                 Bmat_in[(qq+ein)*elemsize + n] += interpin[q * elemsize + n];
1560e2f04181SAndrew T. Barker               } else if (emodein[ein] == CEED_EVAL_GRAD) {
1561e2f04181SAndrew T. Barker                 din += 1;
1562e2f04181SAndrew T. Barker                 Bmat_in[(qq+ein)*elemsize + n] +=
1563e2f04181SAndrew T. Barker                   gradin[(din*nqpts+q) * elemsize + n];
1564e2f04181SAndrew T. Barker               } else {
1565e2f04181SAndrew T. Barker                 // LCOV_EXCL_START
1566e2f04181SAndrew T. Barker                 return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Not implemented!");
1567e2f04181SAndrew T. Barker                 // LCOV_EXCL_STOP
1568e2f04181SAndrew T. Barker               }
1569e2f04181SAndrew T. Barker             }
1570e2f04181SAndrew T. Barker             CeedInt dout = -1;
1571e2f04181SAndrew T. Barker             for (int eout = 0; eout < numemodeout; ++eout) {
1572e2f04181SAndrew T. Barker               const int qq = numemodeout*q;
1573e2f04181SAndrew T. Barker               if (emodeout[eout] == CEED_EVAL_INTERP) {
1574e2f04181SAndrew T. Barker                 Bmat_out[(qq+eout)*elemsize + n] += interpin[q * elemsize + n];
1575e2f04181SAndrew T. Barker               } else if (emodeout[eout] == CEED_EVAL_GRAD) {
1576e2f04181SAndrew T. Barker                 dout += 1;
1577e2f04181SAndrew T. Barker                 Bmat_out[(qq+eout)*elemsize + n] +=
1578e2f04181SAndrew T. Barker                   gradin[(dout*nqpts+q) * elemsize + n];
1579e2f04181SAndrew T. Barker               } else {
1580e2f04181SAndrew T. Barker                 // LCOV_EXCL_START
1581e2f04181SAndrew T. Barker                 return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Not implemented!");
1582e2f04181SAndrew T. Barker                 // LCOV_EXCL_STOP
1583e2f04181SAndrew T. Barker               }
1584e2f04181SAndrew T. Barker             }
1585e2f04181SAndrew T. Barker           }
1586e2f04181SAndrew T. Barker           for (int ei = 0; ei < numemodeout; ++ei) {
1587e2f04181SAndrew T. Barker             for (int ej = 0; ej < numemodein; ++ej) {
1588e2f04181SAndrew T. Barker               const int emode_index = ((ei*ncomp+compin)*numemodein+ej)*ncomp+compout;
1589e2f04181SAndrew T. Barker               const int index = q*layout_qf[0] + emode_index*layout_qf[1] + e*layout_qf[2];
1590e2f04181SAndrew T. Barker               Dmat[(ei*numemodein+ej)*nqpts + q] += assembledqfarray[index];
1591e2f04181SAndrew T. Barker             }
1592e2f04181SAndrew T. Barker           }
1593e2f04181SAndrew T. Barker         }
1594e2f04181SAndrew T. Barker         // Compute B^T*D
1595e2f04181SAndrew T. Barker         for (int ell = 0; ell < elemsize*nqpts*numemodein; ++ell) {
1596e2f04181SAndrew T. Barker           BTD[ell] = 0.0;
1597e2f04181SAndrew T. Barker         }
1598e2f04181SAndrew T. Barker         for (int j = 0; j<elemsize; ++j) {
1599e2f04181SAndrew T. Barker           for (int q = 0; q<nqpts; ++q) {
1600e2f04181SAndrew T. Barker             int qq = numemodeout*q;
1601e2f04181SAndrew T. Barker             for (int ei = 0; ei < numemodein; ++ei) {
1602e2f04181SAndrew T. Barker               for (int ej = 0; ej < numemodeout; ++ej) {
1603e2f04181SAndrew T. Barker                 BTD[j*(nqpts*numemodein) + (qq+ei)] +=
1604e2f04181SAndrew T. Barker                   Bmat_out[(qq+ej)*elemsize + j] * Dmat[(ei*numemodein+ej)*nqpts + q];
1605e2f04181SAndrew T. Barker               }
1606e2f04181SAndrew T. Barker             }
1607e2f04181SAndrew T. Barker           }
1608e2f04181SAndrew T. Barker         }
1609e2f04181SAndrew T. Barker 
1610e2f04181SAndrew T. Barker         ierr = CeedMatrixMultiply(ceed, BTD, Bmat_in, elem_mat, elemsize,
1611e2f04181SAndrew T. Barker                                   elemsize, nqpts*numemodein); CeedChk(ierr);
1612e2f04181SAndrew T. Barker 
1613e2f04181SAndrew T. Barker         // put element matrix in coordinate data structure
1614e2f04181SAndrew T. Barker         for (int i = 0; i < elemsize; ++i) {
1615e2f04181SAndrew T. Barker           for (int j = 0; j < elemsize; ++j) {
1616e2f04181SAndrew T. Barker             vals[offset + count] = elem_mat[i*elemsize + j];
1617e2f04181SAndrew T. Barker             count++;
1618e2f04181SAndrew T. Barker           }
1619e2f04181SAndrew T. Barker         }
1620e2f04181SAndrew T. Barker       }
1621e2f04181SAndrew T. Barker     }
1622e2f04181SAndrew T. Barker   }
1623e2f04181SAndrew T. Barker   if (count != local_nentries)
1624e2f04181SAndrew T. Barker     // LCOV_EXCL_START
1625e2f04181SAndrew T. Barker     return CeedError(ceed, CEED_ERROR_MAJOR, "Error computing entries");
1626e2f04181SAndrew T. Barker   // LCOV_EXCL_STOP
1627e2f04181SAndrew T. Barker   ierr = CeedVectorRestoreArray(values, &vals); CeedChk(ierr);
1628e2f04181SAndrew T. Barker 
1629e2f04181SAndrew T. Barker   ierr = CeedVectorRestoreArrayRead(assembledqf, &assembledqfarray);
1630e2f04181SAndrew T. Barker   CeedChk(ierr);
1631e2f04181SAndrew T. Barker   ierr = CeedVectorDestroy(&assembledqf); CeedChk(ierr);
1632e2f04181SAndrew T. Barker   ierr = CeedFree(&emodein); CeedChk(ierr);
1633e2f04181SAndrew T. Barker   ierr = CeedFree(&emodeout); CeedChk(ierr);
1634e2f04181SAndrew T. Barker 
1635e2f04181SAndrew T. Barker   return CEED_ERROR_SUCCESS;
1636e2f04181SAndrew T. Barker }
1637e2f04181SAndrew T. Barker 
1638e2f04181SAndrew T. Barker /**
1639e2f04181SAndrew T. Barker    @ref Utility
1640e2f04181SAndrew T. Barker **/
1641e2f04181SAndrew T. Barker int CeedSingleOperatorAssemblyCountEntries(CeedOperator op, CeedInt *nentries) {
1642e2f04181SAndrew T. Barker   int ierr;
1643e2f04181SAndrew T. Barker   CeedElemRestriction rstr;
1644e2f04181SAndrew T. Barker   CeedInt nelem, elemsize, ncomp;
1645e2f04181SAndrew T. Barker 
1646e2f04181SAndrew T. Barker   if (op->composite)
1647e2f04181SAndrew T. Barker     // LCOV_EXCL_START
1648e2f04181SAndrew T. Barker     return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED,
1649e2f04181SAndrew T. Barker                      "Composite operator not supported");
1650e2f04181SAndrew T. Barker   // LCOV_EXCL_STOP
1651e2f04181SAndrew T. Barker   ierr = CeedOperatorGetActiveElemRestriction(op, &rstr); CeedChk(ierr);
1652e2f04181SAndrew T. Barker   ierr = CeedElemRestrictionGetNumElements(rstr, &nelem); CeedChk(ierr);
1653e2f04181SAndrew T. Barker   ierr = CeedElemRestrictionGetElementSize(rstr, &elemsize); CeedChk(ierr);
1654e2f04181SAndrew T. Barker   ierr = CeedElemRestrictionGetNumComponents(rstr, &ncomp); CeedChk(ierr);
1655e2f04181SAndrew T. Barker   *nentries = elemsize*ncomp * elemsize*ncomp * nelem;
1656e2f04181SAndrew T. Barker 
1657e2f04181SAndrew T. Barker   return CEED_ERROR_SUCCESS;
1658e2f04181SAndrew T. Barker }
1659e2f04181SAndrew T. Barker 
1660e2f04181SAndrew T. Barker /**
1661e2f04181SAndrew T. Barker    @brief Fully assemble the nonzero pattern of a linear operator.
1662e2f04181SAndrew T. Barker 
1663e2f04181SAndrew T. Barker    Expected to be used in conjunction with CeedOperatorLinearAssemble()
1664e2f04181SAndrew T. Barker 
1665e2f04181SAndrew T. Barker    The assembly routines use coordinate format, with nentries tuples of the
1666e2f04181SAndrew T. Barker    form (i, j, value) which indicate that value should be added to the matrix
1667e2f04181SAndrew T. Barker    in entry (i, j). Note that the (i, j) pairs are not unique and may repeat.
1668e2f04181SAndrew T. Barker    This function returns the number of entries and their (i, j) locations,
1669e2f04181SAndrew T. Barker    while CeedOperatorLinearAssemble() provides the values in the same
1670e2f04181SAndrew T. Barker    ordering.
1671e2f04181SAndrew T. Barker 
1672e2f04181SAndrew T. Barker    This will generally be slow unless your operator is low-order.
1673e2f04181SAndrew T. Barker 
1674e2f04181SAndrew T. Barker    @param[in]  op       CeedOperator to assemble
1675e2f04181SAndrew T. Barker    @param[out] nentries Number of entries in coordinate nonzero pattern.
1676e2f04181SAndrew T. Barker    @param[out] rows     Row number for each entry.
1677e2f04181SAndrew T. Barker    @param[out] cols     Column number for each entry.
1678e2f04181SAndrew T. Barker 
1679e2f04181SAndrew T. Barker    @ref User
1680e2f04181SAndrew T. Barker **/
1681e2f04181SAndrew T. Barker int CeedOperatorLinearAssembleSymbolic(CeedOperator op,
1682e2f04181SAndrew T. Barker                                        CeedInt *nentries, CeedInt **rows, CeedInt **cols) {
1683e2f04181SAndrew T. Barker   int ierr;
1684e2f04181SAndrew T. Barker   CeedInt numsub, single_entries;
1685e2f04181SAndrew T. Barker   CeedOperator *suboperators;
1686e2f04181SAndrew T. Barker   bool isComposite;
1687e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
1688e2f04181SAndrew T. Barker 
1689e2f04181SAndrew T. Barker   // Use backend version, if available
1690e2f04181SAndrew T. Barker   if (op->LinearAssembleSymbolic) {
1691e2f04181SAndrew T. Barker     return op->LinearAssembleSymbolic(op, nentries, rows, cols);
1692e2f04181SAndrew T. Barker   } else {
1693e2f04181SAndrew T. Barker     // Check for valid fallback resource
1694e2f04181SAndrew T. Barker     const char *resource, *fallbackresource;
1695e2f04181SAndrew T. Barker     ierr = CeedGetResource(op->ceed, &resource); CeedChk(ierr);
1696e2f04181SAndrew T. Barker     ierr = CeedGetOperatorFallbackResource(op->ceed, &fallbackresource);
1697e2f04181SAndrew T. Barker     if (strcmp(fallbackresource, "") && strcmp(resource, fallbackresource)) {
1698e2f04181SAndrew T. Barker       // Fallback to reference Ceed
1699e2f04181SAndrew T. Barker       if (!op->opfallback) {
1700e2f04181SAndrew T. Barker         ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
1701e2f04181SAndrew T. Barker       }
1702e2f04181SAndrew T. Barker       // Assemble
1703e2f04181SAndrew T. Barker       return CeedOperatorLinearAssembleSymbolic(op->opfallback, nentries, rows, cols);
1704e2f04181SAndrew T. Barker     }
1705e2f04181SAndrew T. Barker   }
1706e2f04181SAndrew T. Barker 
1707e2f04181SAndrew T. Barker   // if neither backend nor fallback resource provides
1708e2f04181SAndrew T. Barker   // LinearAssembleSymbolic, continue with interface-level implementation
1709e2f04181SAndrew T. Barker 
1710e2f04181SAndrew T. Barker   // count entries and allocate rows, cols arrays
1711e2f04181SAndrew T. Barker   ierr = CeedOperatorIsComposite(op, &isComposite); CeedChk(ierr);
1712e2f04181SAndrew T. Barker   *nentries = 0;
1713e2f04181SAndrew T. Barker   if (isComposite) {
1714e2f04181SAndrew T. Barker     ierr = CeedOperatorGetNumSub(op, &numsub); CeedChk(ierr);
1715e2f04181SAndrew T. Barker     ierr = CeedOperatorGetSubList(op, &suboperators); CeedChk(ierr);
1716e2f04181SAndrew T. Barker     for (int k = 0; k < numsub; ++k) {
1717e2f04181SAndrew T. Barker       ierr = CeedSingleOperatorAssemblyCountEntries(suboperators[k],
1718e2f04181SAndrew T. Barker              &single_entries); CeedChk(ierr);
1719e2f04181SAndrew T. Barker       *nentries += single_entries;
1720e2f04181SAndrew T. Barker     }
1721e2f04181SAndrew T. Barker   } else {
1722e2f04181SAndrew T. Barker     ierr = CeedSingleOperatorAssemblyCountEntries(op,
1723e2f04181SAndrew T. Barker            &single_entries); CeedChk(ierr);
1724e2f04181SAndrew T. Barker     *nentries += single_entries;
1725e2f04181SAndrew T. Barker   }
1726e2f04181SAndrew T. Barker   ierr = CeedCalloc(*nentries, rows); CeedChk(ierr);
1727e2f04181SAndrew T. Barker   ierr = CeedCalloc(*nentries, cols); CeedChk(ierr);
1728e2f04181SAndrew T. Barker 
1729e2f04181SAndrew T. Barker   // assemble nonzero locations
1730e2f04181SAndrew T. Barker   CeedInt offset = 0;
1731e2f04181SAndrew T. Barker   if (isComposite) {
1732e2f04181SAndrew T. Barker     ierr = CeedOperatorGetNumSub(op, &numsub); CeedChk(ierr);
1733e2f04181SAndrew T. Barker     ierr = CeedOperatorGetSubList(op, &suboperators); CeedChk(ierr);
1734e2f04181SAndrew T. Barker     for (int k = 0; k < numsub; ++k) {
1735e2f04181SAndrew T. Barker       ierr = CeedSingleOperatorAssembleSymbolic(suboperators[k], offset, *rows,
1736e2f04181SAndrew T. Barker              *cols); CeedChk(ierr);
1737e2f04181SAndrew T. Barker       ierr = CeedSingleOperatorAssemblyCountEntries(suboperators[k], &single_entries);
1738e2f04181SAndrew T. Barker       CeedChk(ierr);
1739e2f04181SAndrew T. Barker       offset += single_entries;
1740e2f04181SAndrew T. Barker     }
1741e2f04181SAndrew T. Barker   } else {
1742e2f04181SAndrew T. Barker     ierr = CeedSingleOperatorAssembleSymbolic(op, offset, *rows, *cols);
1743e2f04181SAndrew T. Barker     CeedChk(ierr);
1744e2f04181SAndrew T. Barker   }
1745e2f04181SAndrew T. Barker 
1746e2f04181SAndrew T. Barker   return CEED_ERROR_SUCCESS;
1747e2f04181SAndrew T. Barker }
1748e2f04181SAndrew T. Barker 
1749e2f04181SAndrew T. Barker /**
1750e2f04181SAndrew T. Barker    @brief Fully assemble the nonzero entries of a linear operator.
1751e2f04181SAndrew T. Barker 
1752e2f04181SAndrew T. Barker    Expected to be used in conjunction with CeedOperatorLinearAssembleSymbolic()
1753e2f04181SAndrew T. Barker 
1754e2f04181SAndrew T. Barker    The assembly routines use coordinate format, with nentries tuples of the
1755e2f04181SAndrew T. Barker    form (i, j, value) which indicate that value should be added to the matrix
1756e2f04181SAndrew T. Barker    in entry (i, j). Note that the (i, j) pairs are not unique and may repeat.
1757e2f04181SAndrew T. Barker    This function returns the values of the nonzero entries to be added, their
1758e2f04181SAndrew T. Barker    (i, j) locations are provided by CeedOperatorLinearAssembleSymbolic()
1759e2f04181SAndrew T. Barker 
1760e2f04181SAndrew T. Barker    This will generally be slow unless your operator is low-order.
1761e2f04181SAndrew T. Barker 
1762e2f04181SAndrew T. Barker    @param[in]  op       CeedOperator to assemble
1763e2f04181SAndrew T. Barker    @param[out] values   Values to assemble into matrix
1764e2f04181SAndrew T. Barker 
1765e2f04181SAndrew T. Barker    @ref User
1766e2f04181SAndrew T. Barker **/
1767e2f04181SAndrew T. Barker int CeedOperatorLinearAssemble(CeedOperator op, CeedVector values) {
1768e2f04181SAndrew T. Barker   int ierr;
1769e2f04181SAndrew T. Barker   CeedInt numsub, single_entries;
1770e2f04181SAndrew T. Barker   CeedOperator *suboperators;
1771e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
1772e2f04181SAndrew T. Barker 
1773e2f04181SAndrew T. Barker   // Use backend version, if available
1774e2f04181SAndrew T. Barker   if (op->LinearAssemble) {
1775e2f04181SAndrew T. Barker     return op->LinearAssemble(op, values);
1776e2f04181SAndrew T. Barker   } else {
1777e2f04181SAndrew T. Barker     // Check for valid fallback resource
1778e2f04181SAndrew T. Barker     const char *resource, *fallbackresource;
1779e2f04181SAndrew T. Barker     ierr = CeedGetResource(op->ceed, &resource); CeedChk(ierr);
1780e2f04181SAndrew T. Barker     ierr = CeedGetOperatorFallbackResource(op->ceed, &fallbackresource);
1781e2f04181SAndrew T. Barker     if (strcmp(fallbackresource, "") && strcmp(resource, fallbackresource)) {
1782e2f04181SAndrew T. Barker       // Fallback to reference Ceed
1783e2f04181SAndrew T. Barker       if (!op->opfallback) {
1784e2f04181SAndrew T. Barker         ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
1785e2f04181SAndrew T. Barker       }
1786e2f04181SAndrew T. Barker       // Assemble
1787e2f04181SAndrew T. Barker       return CeedOperatorLinearAssemble(op->opfallback, values);
1788e2f04181SAndrew T. Barker     }
1789e2f04181SAndrew T. Barker   }
1790e2f04181SAndrew T. Barker 
1791e2f04181SAndrew T. Barker   // if neither backend nor fallback resource provides
1792e2f04181SAndrew T. Barker   // LinearAssemble, continue with interface-level implementation
1793e2f04181SAndrew T. Barker 
1794e2f04181SAndrew T. Barker   bool isComposite;
1795e2f04181SAndrew T. Barker   ierr = CeedOperatorIsComposite(op, &isComposite); CeedChk(ierr);
1796e2f04181SAndrew T. Barker 
1797e2f04181SAndrew T. Barker   CeedInt offset = 0;
1798e2f04181SAndrew T. Barker   if (isComposite) {
1799e2f04181SAndrew T. Barker     ierr = CeedOperatorGetNumSub(op, &numsub); CeedChk(ierr);
1800e2f04181SAndrew T. Barker     ierr = CeedOperatorGetSubList(op, &suboperators); CeedChk(ierr);
1801e2f04181SAndrew T. Barker     for (int k = 0; k < numsub; ++k) {
1802e2f04181SAndrew T. Barker       ierr = CeedSingleOperatorAssemble(suboperators[k], offset, values);
1803e2f04181SAndrew T. Barker       CeedChk(ierr);
1804e2f04181SAndrew T. Barker       ierr = CeedSingleOperatorAssemblyCountEntries(suboperators[k], &single_entries);
1805e2f04181SAndrew T. Barker       CeedChk(ierr);
1806e2f04181SAndrew T. Barker       offset += single_entries;
1807e2f04181SAndrew T. Barker     }
1808e2f04181SAndrew T. Barker   } else {
1809e2f04181SAndrew T. Barker     ierr = CeedSingleOperatorAssemble(op, offset, values); CeedChk(ierr);
1810e2f04181SAndrew T. Barker   }
1811e2f04181SAndrew T. Barker 
1812e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1813d965c7a7SJeremy L Thompson }
1814d965c7a7SJeremy L Thompson 
1815d965c7a7SJeremy L Thompson /**
1816d99fa3c5SJeremy L Thompson   @brief Create a multigrid coarse operator and level transfer operators
1817d99fa3c5SJeremy L Thompson            for a CeedOperator, creating the prolongation basis from the
1818d99fa3c5SJeremy L Thompson            fine and coarse grid interpolation
1819d99fa3c5SJeremy L Thompson 
1820d99fa3c5SJeremy L Thompson   @param[in] opFine       Fine grid operator
1821d99fa3c5SJeremy L Thompson   @param[in] PMultFine    L-vector multiplicity in parallel gather/scatter
1822d99fa3c5SJeremy L Thompson   @param[in] rstrCoarse   Coarse grid restriction
1823d99fa3c5SJeremy L Thompson   @param[in] basisCoarse  Coarse grid active vector basis
1824d99fa3c5SJeremy L Thompson   @param[out] opCoarse    Coarse grid operator
1825d99fa3c5SJeremy L Thompson   @param[out] opProlong   Coarse to fine operator
1826d99fa3c5SJeremy L Thompson   @param[out] opRestrict  Fine to coarse operator
1827d99fa3c5SJeremy L Thompson 
1828d99fa3c5SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1829d99fa3c5SJeremy L Thompson 
1830d99fa3c5SJeremy L Thompson   @ref User
1831d99fa3c5SJeremy L Thompson **/
1832d99fa3c5SJeremy L Thompson int CeedOperatorMultigridLevelCreate(CeedOperator opFine, CeedVector PMultFine,
1833d99fa3c5SJeremy L Thompson                                      CeedElemRestriction rstrCoarse, CeedBasis basisCoarse,
1834d99fa3c5SJeremy L Thompson                                      CeedOperator *opCoarse, CeedOperator *opProlong, CeedOperator *opRestrict) {
1835d99fa3c5SJeremy L Thompson   int ierr;
1836d99fa3c5SJeremy L Thompson   Ceed ceed;
1837d99fa3c5SJeremy L Thompson   ierr = CeedOperatorGetCeed(opFine, &ceed); CeedChk(ierr);
1838d99fa3c5SJeremy L Thompson 
1839d99fa3c5SJeremy L Thompson   // Check for compatible quadrature spaces
1840d99fa3c5SJeremy L Thompson   CeedBasis basisFine;
1841d99fa3c5SJeremy L Thompson   ierr = CeedOperatorGetActiveBasis(opFine, &basisFine); CeedChk(ierr);
1842d99fa3c5SJeremy L Thompson   CeedInt Qf, Qc;
1843d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumQuadraturePoints(basisFine, &Qf); CeedChk(ierr);
1844d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumQuadraturePoints(basisCoarse, &Qc); CeedChk(ierr);
1845d99fa3c5SJeremy L Thompson   if (Qf != Qc)
1846d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
1847e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_DIMENSION,
1848e15f9bd0SJeremy L Thompson                      "Bases must have compatible quadrature spaces");
1849d99fa3c5SJeremy L Thompson   // LCOV_EXCL_STOP
1850d99fa3c5SJeremy L Thompson 
1851d99fa3c5SJeremy L Thompson   // Coarse to fine basis
1852d99fa3c5SJeremy L Thompson   CeedInt Pf, Pc, Q = Qf;
1853d99fa3c5SJeremy L Thompson   bool isTensorF, isTensorC;
1854d99fa3c5SJeremy L Thompson   ierr = CeedBasisIsTensor(basisFine, &isTensorF); CeedChk(ierr);
1855d99fa3c5SJeremy L Thompson   ierr = CeedBasisIsTensor(basisCoarse, &isTensorC); CeedChk(ierr);
1856d99fa3c5SJeremy L Thompson   CeedScalar *interpC, *interpF, *interpCtoF, *tau;
1857d99fa3c5SJeremy L Thompson   if (isTensorF && isTensorC) {
1858d99fa3c5SJeremy L Thompson     ierr = CeedBasisGetNumNodes1D(basisFine, &Pf); CeedChk(ierr);
1859d99fa3c5SJeremy L Thompson     ierr = CeedBasisGetNumNodes1D(basisCoarse, &Pc); CeedChk(ierr);
1860d99fa3c5SJeremy L Thompson     ierr = CeedBasisGetNumQuadraturePoints1D(basisCoarse, &Q); CeedChk(ierr);
1861d99fa3c5SJeremy L Thompson   } else if (!isTensorF && !isTensorC) {
1862d99fa3c5SJeremy L Thompson     ierr = CeedBasisGetNumNodes(basisFine, &Pf); CeedChk(ierr);
1863d99fa3c5SJeremy L Thompson     ierr = CeedBasisGetNumNodes(basisCoarse, &Pc); CeedChk(ierr);
1864d99fa3c5SJeremy L Thompson   } else {
1865d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
1866e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_MINOR,
1867e15f9bd0SJeremy L Thompson                      "Bases must both be tensor or non-tensor");
1868d99fa3c5SJeremy L Thompson     // LCOV_EXCL_STOP
1869d99fa3c5SJeremy L Thompson   }
1870d99fa3c5SJeremy L Thompson 
1871d99fa3c5SJeremy L Thompson   ierr = CeedMalloc(Q*Pf, &interpF); CeedChk(ierr);
1872d99fa3c5SJeremy L Thompson   ierr = CeedMalloc(Q*Pc, &interpC); CeedChk(ierr);
1873d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(Pc*Pf, &interpCtoF); CeedChk(ierr);
1874d99fa3c5SJeremy L Thompson   ierr = CeedMalloc(Q, &tau); CeedChk(ierr);
1875d99fa3c5SJeremy L Thompson   if (isTensorF) {
1876d99fa3c5SJeremy L Thompson     memcpy(interpF, basisFine->interp1d, Q*Pf*sizeof basisFine->interp1d[0]);
1877d99fa3c5SJeremy L Thompson     memcpy(interpC, basisCoarse->interp1d, Q*Pc*sizeof basisCoarse->interp1d[0]);
1878d99fa3c5SJeremy L Thompson   } else {
1879d99fa3c5SJeremy L Thompson     memcpy(interpF, basisFine->interp, Q*Pf*sizeof basisFine->interp[0]);
1880d99fa3c5SJeremy L Thompson     memcpy(interpC, basisCoarse->interp, Q*Pc*sizeof basisCoarse->interp[0]);
1881d99fa3c5SJeremy L Thompson   }
1882d99fa3c5SJeremy L Thompson 
1883d99fa3c5SJeremy L Thompson   // -- QR Factorization, interpF = Q R
1884d99fa3c5SJeremy L Thompson   ierr = CeedQRFactorization(ceed, interpF, tau, Q, Pf); CeedChk(ierr);
1885d99fa3c5SJeremy L Thompson 
1886d99fa3c5SJeremy L Thompson   // -- Apply Qtranspose, interpC = Qtranspose interpC
1887d99fa3c5SJeremy L Thompson   CeedHouseholderApplyQ(interpC, interpF, tau, CEED_TRANSPOSE,
1888d99fa3c5SJeremy L Thompson                         Q, Pc, Pf, Pc, 1);
1889d99fa3c5SJeremy L Thompson 
1890d99fa3c5SJeremy L Thompson   // -- Apply Rinv, interpCtoF = Rinv interpC
1891d99fa3c5SJeremy L Thompson   for (CeedInt j=0; j<Pc; j++) { // Column j
1892d99fa3c5SJeremy L Thompson     interpCtoF[j+Pc*(Pf-1)] = interpC[j+Pc*(Pf-1)]/interpF[Pf*Pf-1];
1893d99fa3c5SJeremy L Thompson     for (CeedInt i=Pf-2; i>=0; i--) { // Row i
1894d99fa3c5SJeremy L Thompson       interpCtoF[j+Pc*i] = interpC[j+Pc*i];
1895d99fa3c5SJeremy L Thompson       for (CeedInt k=i+1; k<Pf; k++)
1896d99fa3c5SJeremy L Thompson         interpCtoF[j+Pc*i] -= interpF[k+Pf*i]*interpCtoF[j+Pc*k];
1897d99fa3c5SJeremy L Thompson       interpCtoF[j+Pc*i] /= interpF[i+Pf*i];
1898d99fa3c5SJeremy L Thompson     }
1899d99fa3c5SJeremy L Thompson   }
1900d99fa3c5SJeremy L Thompson   ierr = CeedFree(&tau); CeedChk(ierr);
1901d99fa3c5SJeremy L Thompson   ierr = CeedFree(&interpC); CeedChk(ierr);
1902d99fa3c5SJeremy L Thompson   ierr = CeedFree(&interpF); CeedChk(ierr);
1903d99fa3c5SJeremy L Thompson 
1904e15f9bd0SJeremy L Thompson   // Complete with interpCtoF versions of code
1905d99fa3c5SJeremy L Thompson   if (isTensorF) {
1906d99fa3c5SJeremy L Thompson     ierr = CeedOperatorMultigridLevelCreateTensorH1(opFine, PMultFine,
1907d99fa3c5SJeremy L Thompson            rstrCoarse, basisCoarse, interpCtoF, opCoarse, opProlong, opRestrict);
1908d99fa3c5SJeremy L Thompson     CeedChk(ierr);
1909d99fa3c5SJeremy L Thompson   } else {
1910d99fa3c5SJeremy L Thompson     ierr = CeedOperatorMultigridLevelCreateH1(opFine, PMultFine,
1911d99fa3c5SJeremy L Thompson            rstrCoarse, basisCoarse, interpCtoF, opCoarse, opProlong, opRestrict);
1912d99fa3c5SJeremy L Thompson     CeedChk(ierr);
1913d99fa3c5SJeremy L Thompson   }
1914d99fa3c5SJeremy L Thompson 
1915d99fa3c5SJeremy L Thompson   // Cleanup
1916d99fa3c5SJeremy L Thompson   ierr = CeedFree(&interpCtoF); CeedChk(ierr);
1917e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1918d99fa3c5SJeremy L Thompson }
1919d99fa3c5SJeremy L Thompson 
1920d99fa3c5SJeremy L Thompson /**
1921d99fa3c5SJeremy L Thompson   @brief Create a multigrid coarse operator and level transfer operators
1922d99fa3c5SJeremy L Thompson            for a CeedOperator with a tensor basis for the active basis
1923d99fa3c5SJeremy L Thompson 
1924d99fa3c5SJeremy L Thompson   @param[in] opFine       Fine grid operator
1925d99fa3c5SJeremy L Thompson   @param[in] PMultFine    L-vector multiplicity in parallel gather/scatter
1926d99fa3c5SJeremy L Thompson   @param[in] rstrCoarse   Coarse grid restriction
1927d99fa3c5SJeremy L Thompson   @param[in] basisCoarse  Coarse grid active vector basis
1928d99fa3c5SJeremy L Thompson   @param[in] interpCtoF   Matrix for coarse to fine interpolation
1929d99fa3c5SJeremy L Thompson   @param[out] opCoarse    Coarse grid operator
1930d99fa3c5SJeremy L Thompson   @param[out] opProlong   Coarse to fine operator
1931d99fa3c5SJeremy L Thompson   @param[out] opRestrict  Fine to coarse operator
1932d99fa3c5SJeremy L Thompson 
1933d99fa3c5SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1934d99fa3c5SJeremy L Thompson 
1935d99fa3c5SJeremy L Thompson   @ref User
1936d99fa3c5SJeremy L Thompson **/
1937d99fa3c5SJeremy L Thompson int CeedOperatorMultigridLevelCreateTensorH1(CeedOperator opFine,
1938d99fa3c5SJeremy L Thompson     CeedVector PMultFine, CeedElemRestriction rstrCoarse, CeedBasis basisCoarse,
1939d99fa3c5SJeremy L Thompson     const CeedScalar *interpCtoF, CeedOperator *opCoarse,
1940d99fa3c5SJeremy L Thompson     CeedOperator *opProlong, CeedOperator *opRestrict) {
1941d99fa3c5SJeremy L Thompson   int ierr;
1942d99fa3c5SJeremy L Thompson   Ceed ceed;
1943d99fa3c5SJeremy L Thompson   ierr = CeedOperatorGetCeed(opFine, &ceed); CeedChk(ierr);
1944d99fa3c5SJeremy L Thompson 
1945d99fa3c5SJeremy L Thompson   // Check for compatible quadrature spaces
1946d99fa3c5SJeremy L Thompson   CeedBasis basisFine;
1947d99fa3c5SJeremy L Thompson   ierr = CeedOperatorGetActiveBasis(opFine, &basisFine); CeedChk(ierr);
1948d99fa3c5SJeremy L Thompson   CeedInt Qf, Qc;
1949d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumQuadraturePoints(basisFine, &Qf); CeedChk(ierr);
1950d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumQuadraturePoints(basisCoarse, &Qc); CeedChk(ierr);
1951d99fa3c5SJeremy L Thompson   if (Qf != Qc)
1952d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
1953e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_DIMENSION,
1954e15f9bd0SJeremy L Thompson                      "Bases must have compatible quadrature spaces");
1955d99fa3c5SJeremy L Thompson   // LCOV_EXCL_STOP
1956d99fa3c5SJeremy L Thompson 
1957d99fa3c5SJeremy L Thompson   // Coarse to fine basis
1958d99fa3c5SJeremy L Thompson   CeedInt dim, ncomp, nnodesCoarse, P1dFine, P1dCoarse;
1959d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetDimension(basisFine, &dim); CeedChk(ierr);
1960d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumComponents(basisFine, &ncomp); CeedChk(ierr);
1961d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumNodes1D(basisFine, &P1dFine); CeedChk(ierr);
1962d99fa3c5SJeremy L Thompson   ierr = CeedElemRestrictionGetElementSize(rstrCoarse, &nnodesCoarse);
1963d99fa3c5SJeremy L Thompson   CeedChk(ierr);
1964d99fa3c5SJeremy L Thompson   P1dCoarse = dim == 1 ? nnodesCoarse :
1965d99fa3c5SJeremy L Thompson               dim == 2 ? sqrt(nnodesCoarse) :
1966d99fa3c5SJeremy L Thompson               cbrt(nnodesCoarse);
1967d99fa3c5SJeremy L Thompson   CeedScalar *qref, *qweight, *grad;
1968d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(P1dFine, &qref); CeedChk(ierr);
1969d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(P1dFine, &qweight); CeedChk(ierr);
1970d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(P1dFine*P1dCoarse*dim, &grad); CeedChk(ierr);
1971d99fa3c5SJeremy L Thompson   CeedBasis basisCtoF;
1972d99fa3c5SJeremy L Thompson   ierr = CeedBasisCreateTensorH1(ceed, dim, ncomp, P1dCoarse, P1dFine,
1973d99fa3c5SJeremy L Thompson                                  interpCtoF, grad, qref, qweight, &basisCtoF);
1974d99fa3c5SJeremy L Thompson   CeedChk(ierr);
1975d99fa3c5SJeremy L Thompson   ierr = CeedFree(&qref); CeedChk(ierr);
1976d99fa3c5SJeremy L Thompson   ierr = CeedFree(&qweight); CeedChk(ierr);
1977d99fa3c5SJeremy L Thompson   ierr = CeedFree(&grad); CeedChk(ierr);
1978d99fa3c5SJeremy L Thompson 
1979d99fa3c5SJeremy L Thompson   // Core code
1980d99fa3c5SJeremy L Thompson   ierr = CeedOperatorMultigridLevel_Core(opFine, PMultFine, rstrCoarse,
1981d99fa3c5SJeremy L Thompson                                          basisCoarse, basisCtoF, opCoarse,
1982d99fa3c5SJeremy L Thompson                                          opProlong, opRestrict);
1983d99fa3c5SJeremy L Thompson   CeedChk(ierr);
1984e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1985d99fa3c5SJeremy L Thompson }
1986d99fa3c5SJeremy L Thompson 
1987d99fa3c5SJeremy L Thompson /**
1988d99fa3c5SJeremy L Thompson   @brief Create a multigrid coarse operator and level transfer operators
1989d99fa3c5SJeremy L Thompson            for a CeedOperator with a non-tensor basis for the active vector
1990d99fa3c5SJeremy L Thompson 
1991d99fa3c5SJeremy L Thompson   @param[in] opFine       Fine grid operator
1992d99fa3c5SJeremy L Thompson   @param[in] PMultFine    L-vector multiplicity in parallel gather/scatter
1993d99fa3c5SJeremy L Thompson   @param[in] rstrCoarse   Coarse grid restriction
1994d99fa3c5SJeremy L Thompson   @param[in] basisCoarse  Coarse grid active vector basis
1995d99fa3c5SJeremy L Thompson   @param[in] interpCtoF   Matrix for coarse to fine interpolation
1996d99fa3c5SJeremy L Thompson   @param[out] opCoarse    Coarse grid operator
1997d99fa3c5SJeremy L Thompson   @param[out] opProlong   Coarse to fine operator
1998d99fa3c5SJeremy L Thompson   @param[out] opRestrict  Fine to coarse operator
1999d99fa3c5SJeremy L Thompson 
2000d99fa3c5SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
2001d99fa3c5SJeremy L Thompson 
2002d99fa3c5SJeremy L Thompson   @ref User
2003d99fa3c5SJeremy L Thompson **/
2004d99fa3c5SJeremy L Thompson int CeedOperatorMultigridLevelCreateH1(CeedOperator opFine,
2005d99fa3c5SJeremy L Thompson                                        CeedVector PMultFine,
2006d99fa3c5SJeremy L Thompson                                        CeedElemRestriction rstrCoarse,
2007d99fa3c5SJeremy L Thompson                                        CeedBasis basisCoarse,
2008d99fa3c5SJeremy L Thompson                                        const CeedScalar *interpCtoF,
2009d99fa3c5SJeremy L Thompson                                        CeedOperator *opCoarse,
2010d99fa3c5SJeremy L Thompson                                        CeedOperator *opProlong,
2011d99fa3c5SJeremy L Thompson                                        CeedOperator *opRestrict) {
2012d99fa3c5SJeremy L Thompson   int ierr;
2013d99fa3c5SJeremy L Thompson   Ceed ceed;
2014d99fa3c5SJeremy L Thompson   ierr = CeedOperatorGetCeed(opFine, &ceed); CeedChk(ierr);
2015d99fa3c5SJeremy L Thompson 
2016d99fa3c5SJeremy L Thompson   // Check for compatible quadrature spaces
2017d99fa3c5SJeremy L Thompson   CeedBasis basisFine;
2018d99fa3c5SJeremy L Thompson   ierr = CeedOperatorGetActiveBasis(opFine, &basisFine); CeedChk(ierr);
2019d99fa3c5SJeremy L Thompson   CeedInt Qf, Qc;
2020d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumQuadraturePoints(basisFine, &Qf); CeedChk(ierr);
2021d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumQuadraturePoints(basisCoarse, &Qc); CeedChk(ierr);
2022d99fa3c5SJeremy L Thompson   if (Qf != Qc)
2023d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
2024e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_DIMENSION,
2025e15f9bd0SJeremy L Thompson                      "Bases must have compatible quadrature spaces");
2026d99fa3c5SJeremy L Thompson   // LCOV_EXCL_STOP
2027d99fa3c5SJeremy L Thompson 
2028d99fa3c5SJeremy L Thompson   // Coarse to fine basis
2029d99fa3c5SJeremy L Thompson   CeedElemTopology topo;
2030d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetTopology(basisFine, &topo); CeedChk(ierr);
2031d99fa3c5SJeremy L Thompson   CeedInt dim, ncomp, nnodesCoarse, nnodesFine;
2032d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetDimension(basisFine, &dim); CeedChk(ierr);
2033d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumComponents(basisFine, &ncomp); CeedChk(ierr);
2034d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumNodes(basisFine, &nnodesFine); CeedChk(ierr);
2035d99fa3c5SJeremy L Thompson   ierr = CeedElemRestrictionGetElementSize(rstrCoarse, &nnodesCoarse);
2036d99fa3c5SJeremy L Thompson   CeedChk(ierr);
2037d99fa3c5SJeremy L Thompson   CeedScalar *qref, *qweight, *grad;
2038d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(nnodesFine, &qref); CeedChk(ierr);
2039d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(nnodesFine, &qweight); CeedChk(ierr);
2040d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(nnodesFine*nnodesCoarse*dim, &grad); CeedChk(ierr);
2041d99fa3c5SJeremy L Thompson   CeedBasis basisCtoF;
2042d99fa3c5SJeremy L Thompson   ierr = CeedBasisCreateH1(ceed, topo, ncomp, nnodesCoarse, nnodesFine,
2043d99fa3c5SJeremy L Thompson                            interpCtoF, grad, qref, qweight, &basisCtoF);
2044d99fa3c5SJeremy L Thompson   CeedChk(ierr);
2045d99fa3c5SJeremy L Thompson   ierr = CeedFree(&qref); CeedChk(ierr);
2046d99fa3c5SJeremy L Thompson   ierr = CeedFree(&qweight); CeedChk(ierr);
2047d99fa3c5SJeremy L Thompson   ierr = CeedFree(&grad); CeedChk(ierr);
2048d99fa3c5SJeremy L Thompson 
2049d99fa3c5SJeremy L Thompson   // Core code
2050d99fa3c5SJeremy L Thompson   ierr = CeedOperatorMultigridLevel_Core(opFine, PMultFine, rstrCoarse,
2051d99fa3c5SJeremy L Thompson                                          basisCoarse, basisCtoF, opCoarse,
2052d99fa3c5SJeremy L Thompson                                          opProlong, opRestrict);
2053d99fa3c5SJeremy L Thompson   CeedChk(ierr);
2054e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2055d99fa3c5SJeremy L Thompson }
2056d99fa3c5SJeremy L Thompson 
2057d99fa3c5SJeremy L Thompson /**
20583bd813ffSjeremylt   @brief Build a FDM based approximate inverse for each element for a
20593bd813ffSjeremylt            CeedOperator
20603bd813ffSjeremylt 
20613bd813ffSjeremylt   This returns a CeedOperator and CeedVector to apply a Fast Diagonalization
20623bd813ffSjeremylt     Method based approximate inverse. This function obtains the simultaneous
20633bd813ffSjeremylt     diagonalization for the 1D mass and Laplacian operators,
20643bd813ffSjeremylt       M = V^T V, K = V^T S V.
20653bd813ffSjeremylt     The assembled QFunction is used to modify the eigenvalues from simultaneous
20663bd813ffSjeremylt     diagonalization and obtain an approximate inverse of the form
20673bd813ffSjeremylt       V^T S^hat V. The CeedOperator must be linear and non-composite. The
20683bd813ffSjeremylt     associated CeedQFunction must therefore also be linear.
20693bd813ffSjeremylt 
20703bd813ffSjeremylt   @param op             CeedOperator to create element inverses
20713bd813ffSjeremylt   @param[out] fdminv    CeedOperator to apply the action of a FDM based inverse
20723bd813ffSjeremylt                           for each element
20733bd813ffSjeremylt   @param request        Address of CeedRequest for non-blocking completion, else
20744cc79fe7SJed Brown                           @ref CEED_REQUEST_IMMEDIATE
20753bd813ffSjeremylt 
20763bd813ffSjeremylt   @return An error code: 0 - success, otherwise - failure
20773bd813ffSjeremylt 
20787a982d89SJeremy L. Thompson   @ref Backend
20793bd813ffSjeremylt **/
20803bd813ffSjeremylt int CeedOperatorCreateFDMElementInverse(CeedOperator op, CeedOperator *fdminv,
20813bd813ffSjeremylt                                         CeedRequest *request) {
20823bd813ffSjeremylt   int ierr;
2083e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
20843bd813ffSjeremylt 
2085713f43c3Sjeremylt   // Use backend version, if available
2086713f43c3Sjeremylt   if (op->CreateFDMElementInverse) {
2087713f43c3Sjeremylt     ierr = op->CreateFDMElementInverse(op, fdminv, request); CeedChk(ierr);
2088713f43c3Sjeremylt   } else {
2089713f43c3Sjeremylt     // Fallback to reference Ceed
2090713f43c3Sjeremylt     if (!op->opfallback) {
2091713f43c3Sjeremylt       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
20923bd813ffSjeremylt     }
2093713f43c3Sjeremylt     // Assemble
2094713f43c3Sjeremylt     ierr = op->opfallback->CreateFDMElementInverse(op->opfallback, fdminv,
20953bd813ffSjeremylt            request); CeedChk(ierr);
20963bd813ffSjeremylt   }
2097e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
20983bd813ffSjeremylt }
20993bd813ffSjeremylt 
21007a982d89SJeremy L. Thompson /**
21017a982d89SJeremy L. Thompson   @brief View a CeedOperator
21027a982d89SJeremy L. Thompson 
21037a982d89SJeremy L. Thompson   @param[in] op     CeedOperator to view
21047a982d89SJeremy L. Thompson   @param[in] stream Stream to write; typically stdout/stderr or a file
21057a982d89SJeremy L. Thompson 
21067a982d89SJeremy L. Thompson   @return Error code: 0 - success, otherwise - failure
21077a982d89SJeremy L. Thompson 
21087a982d89SJeremy L. Thompson   @ref User
21097a982d89SJeremy L. Thompson **/
21107a982d89SJeremy L. Thompson int CeedOperatorView(CeedOperator op, FILE *stream) {
21117a982d89SJeremy L. Thompson   int ierr;
21127a982d89SJeremy L. Thompson 
21137a982d89SJeremy L. Thompson   if (op->composite) {
21147a982d89SJeremy L. Thompson     fprintf(stream, "Composite CeedOperator\n");
21157a982d89SJeremy L. Thompson 
21167a982d89SJeremy L. Thompson     for (CeedInt i=0; i<op->numsub; i++) {
21177a982d89SJeremy L. Thompson       fprintf(stream, "  SubOperator [%d]:\n", i);
21187a982d89SJeremy L. Thompson       ierr = CeedOperatorSingleView(op->suboperators[i], 1, stream);
21197a982d89SJeremy L. Thompson       CeedChk(ierr);
21207a982d89SJeremy L. Thompson     }
21217a982d89SJeremy L. Thompson   } else {
21227a982d89SJeremy L. Thompson     fprintf(stream, "CeedOperator\n");
21237a982d89SJeremy L. Thompson     ierr = CeedOperatorSingleView(op, 0, stream); CeedChk(ierr);
21247a982d89SJeremy L. Thompson   }
2125e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
21267a982d89SJeremy L. Thompson }
21273bd813ffSjeremylt 
21283bd813ffSjeremylt /**
21293bd813ffSjeremylt   @brief Apply CeedOperator to a vector
2130d7b241e6Sjeremylt 
2131d7b241e6Sjeremylt   This computes the action of the operator on the specified (active) input,
2132d7b241e6Sjeremylt   yielding its (active) output.  All inputs and outputs must be specified using
2133d7b241e6Sjeremylt   CeedOperatorSetField().
2134d7b241e6Sjeremylt 
2135d7b241e6Sjeremylt   @param op        CeedOperator to apply
21364cc79fe7SJed Brown   @param[in] in    CeedVector containing input state or @ref CEED_VECTOR_NONE if
213734138859Sjeremylt                   there are no active inputs
2138b11c1e72Sjeremylt   @param[out] out  CeedVector to store result of applying operator (must be
21394cc79fe7SJed Brown                      distinct from @a in) or @ref CEED_VECTOR_NONE if there are no
214034138859Sjeremylt                      active outputs
2141d7b241e6Sjeremylt   @param request   Address of CeedRequest for non-blocking completion, else
21424cc79fe7SJed Brown                      @ref CEED_REQUEST_IMMEDIATE
2143b11c1e72Sjeremylt 
2144b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
2145dfdf5a53Sjeremylt 
21467a982d89SJeremy L. Thompson   @ref User
2147b11c1e72Sjeremylt **/
2148692c2638Sjeremylt int CeedOperatorApply(CeedOperator op, CeedVector in, CeedVector out,
2149692c2638Sjeremylt                       CeedRequest *request) {
2150d7b241e6Sjeremylt   int ierr;
2151e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
2152d7b241e6Sjeremylt 
2153250756a7Sjeremylt   if (op->numelements)  {
2154250756a7Sjeremylt     // Standard Operator
2155cae8b89aSjeremylt     if (op->Apply) {
2156250756a7Sjeremylt       ierr = op->Apply(op, in, out, request); CeedChk(ierr);
2157cae8b89aSjeremylt     } else {
2158cae8b89aSjeremylt       // Zero all output vectors
2159250756a7Sjeremylt       CeedQFunction qf = op->qf;
2160cae8b89aSjeremylt       for (CeedInt i=0; i<qf->numoutputfields; i++) {
2161cae8b89aSjeremylt         CeedVector vec = op->outputfields[i]->vec;
2162cae8b89aSjeremylt         if (vec == CEED_VECTOR_ACTIVE)
2163cae8b89aSjeremylt           vec = out;
2164cae8b89aSjeremylt         if (vec != CEED_VECTOR_NONE) {
2165cae8b89aSjeremylt           ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr);
2166cae8b89aSjeremylt         }
2167cae8b89aSjeremylt       }
2168250756a7Sjeremylt       // Apply
2169250756a7Sjeremylt       ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr);
2170250756a7Sjeremylt     }
2171250756a7Sjeremylt   } else if (op->composite) {
2172250756a7Sjeremylt     // Composite Operator
2173250756a7Sjeremylt     if (op->ApplyComposite) {
2174250756a7Sjeremylt       ierr = op->ApplyComposite(op, in, out, request); CeedChk(ierr);
2175250756a7Sjeremylt     } else {
2176250756a7Sjeremylt       CeedInt numsub;
2177250756a7Sjeremylt       ierr = CeedOperatorGetNumSub(op, &numsub); CeedChk(ierr);
2178250756a7Sjeremylt       CeedOperator *suboperators;
2179250756a7Sjeremylt       ierr = CeedOperatorGetSubList(op, &suboperators); CeedChk(ierr);
2180250756a7Sjeremylt 
2181250756a7Sjeremylt       // Zero all output vectors
2182250756a7Sjeremylt       if (out != CEED_VECTOR_NONE) {
2183cae8b89aSjeremylt         ierr = CeedVectorSetValue(out, 0.0); CeedChk(ierr);
2184cae8b89aSjeremylt       }
2185250756a7Sjeremylt       for (CeedInt i=0; i<numsub; i++) {
2186250756a7Sjeremylt         for (CeedInt j=0; j<suboperators[i]->qf->numoutputfields; j++) {
2187250756a7Sjeremylt           CeedVector vec = suboperators[i]->outputfields[j]->vec;
2188250756a7Sjeremylt           if (vec != CEED_VECTOR_ACTIVE && vec != CEED_VECTOR_NONE) {
2189250756a7Sjeremylt             ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr);
2190250756a7Sjeremylt           }
2191250756a7Sjeremylt         }
2192250756a7Sjeremylt       }
2193250756a7Sjeremylt       // Apply
2194250756a7Sjeremylt       for (CeedInt i=0; i<op->numsub; i++) {
2195250756a7Sjeremylt         ierr = CeedOperatorApplyAdd(op->suboperators[i], in, out, request);
2196cae8b89aSjeremylt         CeedChk(ierr);
2197cae8b89aSjeremylt       }
2198cae8b89aSjeremylt     }
2199250756a7Sjeremylt   }
2200e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2201cae8b89aSjeremylt }
2202cae8b89aSjeremylt 
2203cae8b89aSjeremylt /**
2204cae8b89aSjeremylt   @brief Apply CeedOperator to a vector and add result to output vector
2205cae8b89aSjeremylt 
2206cae8b89aSjeremylt   This computes the action of the operator on the specified (active) input,
2207cae8b89aSjeremylt   yielding its (active) output.  All inputs and outputs must be specified using
2208cae8b89aSjeremylt   CeedOperatorSetField().
2209cae8b89aSjeremylt 
2210cae8b89aSjeremylt   @param op        CeedOperator to apply
2211cae8b89aSjeremylt   @param[in] in    CeedVector containing input state or NULL if there are no
2212cae8b89aSjeremylt                      active inputs
2213cae8b89aSjeremylt   @param[out] out  CeedVector to sum in result of applying operator (must be
2214cae8b89aSjeremylt                      distinct from @a in) or NULL if there are no active outputs
2215cae8b89aSjeremylt   @param request   Address of CeedRequest for non-blocking completion, else
22164cc79fe7SJed Brown                      @ref CEED_REQUEST_IMMEDIATE
2217cae8b89aSjeremylt 
2218cae8b89aSjeremylt   @return An error code: 0 - success, otherwise - failure
2219cae8b89aSjeremylt 
22207a982d89SJeremy L. Thompson   @ref User
2221cae8b89aSjeremylt **/
2222cae8b89aSjeremylt int CeedOperatorApplyAdd(CeedOperator op, CeedVector in, CeedVector out,
2223cae8b89aSjeremylt                          CeedRequest *request) {
2224cae8b89aSjeremylt   int ierr;
2225e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
2226cae8b89aSjeremylt 
2227250756a7Sjeremylt   if (op->numelements)  {
2228250756a7Sjeremylt     // Standard Operator
2229250756a7Sjeremylt     ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr);
2230250756a7Sjeremylt   } else if (op->composite) {
2231250756a7Sjeremylt     // Composite Operator
2232250756a7Sjeremylt     if (op->ApplyAddComposite) {
2233250756a7Sjeremylt       ierr = op->ApplyAddComposite(op, in, out, request); CeedChk(ierr);
2234cae8b89aSjeremylt     } else {
2235250756a7Sjeremylt       CeedInt numsub;
2236250756a7Sjeremylt       ierr = CeedOperatorGetNumSub(op, &numsub); CeedChk(ierr);
2237250756a7Sjeremylt       CeedOperator *suboperators;
2238250756a7Sjeremylt       ierr = CeedOperatorGetSubList(op, &suboperators); CeedChk(ierr);
2239250756a7Sjeremylt 
2240250756a7Sjeremylt       for (CeedInt i=0; i<numsub; i++) {
2241250756a7Sjeremylt         ierr = CeedOperatorApplyAdd(suboperators[i], in, out, request);
2242cae8b89aSjeremylt         CeedChk(ierr);
22431d7d2407SJeremy L Thompson       }
2244250756a7Sjeremylt     }
2245250756a7Sjeremylt   }
2246e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2247d7b241e6Sjeremylt }
2248d7b241e6Sjeremylt 
2249d7b241e6Sjeremylt /**
2250b11c1e72Sjeremylt   @brief Destroy a CeedOperator
2251d7b241e6Sjeremylt 
2252d7b241e6Sjeremylt   @param op CeedOperator to destroy
2253b11c1e72Sjeremylt 
2254b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
2255dfdf5a53Sjeremylt 
22567a982d89SJeremy L. Thompson   @ref User
2257b11c1e72Sjeremylt **/
2258d7b241e6Sjeremylt int CeedOperatorDestroy(CeedOperator *op) {
2259d7b241e6Sjeremylt   int ierr;
2260d7b241e6Sjeremylt 
2261e15f9bd0SJeremy L Thompson   if (!*op || --(*op)->refcount > 0) return CEED_ERROR_SUCCESS;
2262d7b241e6Sjeremylt   if ((*op)->Destroy) {
2263d7b241e6Sjeremylt     ierr = (*op)->Destroy(*op); CeedChk(ierr);
2264d7b241e6Sjeremylt   }
2265fe2413ffSjeremylt   ierr = CeedDestroy(&(*op)->ceed); CeedChk(ierr);
2266fe2413ffSjeremylt   // Free fields
22671d102b48SJeremy L Thompson   for (int i=0; i<(*op)->nfields; i++)
226852d6035fSJeremy L Thompson     if ((*op)->inputfields[i]) {
226915910d16Sjeremylt       if ((*op)->inputfields[i]->Erestrict != CEED_ELEMRESTRICTION_NONE) {
227071352a93Sjeremylt         ierr = CeedElemRestrictionDestroy(&(*op)->inputfields[i]->Erestrict);
227171352a93Sjeremylt         CeedChk(ierr);
227215910d16Sjeremylt       }
227371352a93Sjeremylt       if ((*op)->inputfields[i]->basis != CEED_BASIS_COLLOCATED) {
227471352a93Sjeremylt         ierr = CeedBasisDestroy(&(*op)->inputfields[i]->basis); CeedChk(ierr);
227571352a93Sjeremylt       }
227671352a93Sjeremylt       if ((*op)->inputfields[i]->vec != CEED_VECTOR_ACTIVE &&
227771352a93Sjeremylt           (*op)->inputfields[i]->vec != CEED_VECTOR_NONE ) {
227871352a93Sjeremylt         ierr = CeedVectorDestroy(&(*op)->inputfields[i]->vec); CeedChk(ierr);
227971352a93Sjeremylt       }
2280d99fa3c5SJeremy L Thompson       ierr = CeedFree(&(*op)->inputfields[i]->fieldname); CeedChk(ierr);
2281fe2413ffSjeremylt       ierr = CeedFree(&(*op)->inputfields[i]); CeedChk(ierr);
2282fe2413ffSjeremylt     }
22831d102b48SJeremy L Thompson   for (int i=0; i<(*op)->nfields; i++)
2284d0eb30a5Sjeremylt     if ((*op)->outputfields[i]) {
228571352a93Sjeremylt       ierr = CeedElemRestrictionDestroy(&(*op)->outputfields[i]->Erestrict);
228671352a93Sjeremylt       CeedChk(ierr);
228771352a93Sjeremylt       if ((*op)->outputfields[i]->basis != CEED_BASIS_COLLOCATED) {
228871352a93Sjeremylt         ierr = CeedBasisDestroy(&(*op)->outputfields[i]->basis); CeedChk(ierr);
228971352a93Sjeremylt       }
229071352a93Sjeremylt       if ((*op)->outputfields[i]->vec != CEED_VECTOR_ACTIVE &&
229171352a93Sjeremylt           (*op)->outputfields[i]->vec != CEED_VECTOR_NONE ) {
229271352a93Sjeremylt         ierr = CeedVectorDestroy(&(*op)->outputfields[i]->vec); CeedChk(ierr);
229371352a93Sjeremylt       }
2294d99fa3c5SJeremy L Thompson       ierr = CeedFree(&(*op)->outputfields[i]->fieldname); CeedChk(ierr);
2295fe2413ffSjeremylt       ierr = CeedFree(&(*op)->outputfields[i]); CeedChk(ierr);
2296fe2413ffSjeremylt     }
229752d6035fSJeremy L Thompson   // Destroy suboperators
22981d102b48SJeremy L Thompson   for (int i=0; i<(*op)->numsub; i++)
229952d6035fSJeremy L Thompson     if ((*op)->suboperators[i]) {
230052d6035fSJeremy L Thompson       ierr = CeedOperatorDestroy(&(*op)->suboperators[i]); CeedChk(ierr);
230152d6035fSJeremy L Thompson     }
2302e15f9bd0SJeremy L Thompson   if ((*op)->qf)
2303e15f9bd0SJeremy L Thompson     // LCOV_EXCL_START
2304e15f9bd0SJeremy L Thompson     (*op)->qf->operatorsset--;
2305e15f9bd0SJeremy L Thompson   // LCOV_EXCL_STOP
2306d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->qf); CeedChk(ierr);
2307e15f9bd0SJeremy L Thompson   if ((*op)->dqf && (*op)->dqf != CEED_QFUNCTION_NONE)
2308e15f9bd0SJeremy L Thompson     // LCOV_EXCL_START
2309e15f9bd0SJeremy L Thompson     (*op)->dqf->operatorsset--;
2310e15f9bd0SJeremy L Thompson   // LCOV_EXCL_STOP
2311d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->dqf); CeedChk(ierr);
2312e15f9bd0SJeremy L Thompson   if ((*op)->dqfT && (*op)->dqfT != CEED_QFUNCTION_NONE)
2313e15f9bd0SJeremy L Thompson     // LCOV_EXCL_START
2314e15f9bd0SJeremy L Thompson     (*op)->dqfT->operatorsset--;
2315e15f9bd0SJeremy L Thompson   // LCOV_EXCL_STOP
2316d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->dqfT); CeedChk(ierr);
2317fe2413ffSjeremylt 
23185107b09fSJeremy L Thompson   // Destroy fallback
23195107b09fSJeremy L Thompson   if ((*op)->opfallback) {
23205107b09fSJeremy L Thompson     ierr = (*op)->qffallback->Destroy((*op)->qffallback); CeedChk(ierr);
23215107b09fSJeremy L Thompson     ierr = CeedFree(&(*op)->qffallback); CeedChk(ierr);
23225107b09fSJeremy L Thompson     ierr = (*op)->opfallback->Destroy((*op)->opfallback); CeedChk(ierr);
23235107b09fSJeremy L Thompson     ierr = CeedFree(&(*op)->opfallback); CeedChk(ierr);
23245107b09fSJeremy L Thompson   }
23255107b09fSJeremy L Thompson 
2326fe2413ffSjeremylt   ierr = CeedFree(&(*op)->inputfields); CeedChk(ierr);
2327fe2413ffSjeremylt   ierr = CeedFree(&(*op)->outputfields); CeedChk(ierr);
232852d6035fSJeremy L Thompson   ierr = CeedFree(&(*op)->suboperators); CeedChk(ierr);
2329d7b241e6Sjeremylt   ierr = CeedFree(op); CeedChk(ierr);
2330e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2331d7b241e6Sjeremylt }
2332d7b241e6Sjeremylt 
2333d7b241e6Sjeremylt /// @}
2334