xref: /libCEED/interface/ceed-operator.c (revision ec3da8bcb94d9f0073544b37b5081a06981a86f7)
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 
17*ec3da8bcSJed Brown #include <ceed/ceed.h>
18*ec3da8bcSJed Brown #include <ceed/backend.h>
193d576824SJeremy L Thompson #include <ceed-impl.h>
203bd813ffSjeremylt #include <math.h>
213d576824SJeremy L Thompson #include <stdbool.h>
223d576824SJeremy L Thompson #include <stdio.h>
233d576824SJeremy L Thompson #include <string.h>
24d7b241e6Sjeremylt 
25dfdf5a53Sjeremylt /// @file
267a982d89SJeremy L. Thompson /// Implementation of CeedOperator interfaces
277a982d89SJeremy L. Thompson 
287a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
297a982d89SJeremy L. Thompson /// CeedOperator Library Internal Functions
307a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
317a982d89SJeremy L. Thompson /// @addtogroup CeedOperatorDeveloper
327a982d89SJeremy L. Thompson /// @{
337a982d89SJeremy L. Thompson 
347a982d89SJeremy L. Thompson /**
357a982d89SJeremy L. Thompson   @brief Duplicate a CeedOperator with a reference Ceed to fallback for advanced
367a982d89SJeremy L. Thompson            CeedOperator functionality
377a982d89SJeremy L. Thompson 
387a982d89SJeremy L. Thompson   @param op           CeedOperator to create fallback for
397a982d89SJeremy L. Thompson 
407a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
417a982d89SJeremy L. Thompson 
427a982d89SJeremy L. Thompson   @ref Developer
437a982d89SJeremy L. Thompson **/
447a982d89SJeremy L. Thompson int CeedOperatorCreateFallback(CeedOperator op) {
457a982d89SJeremy L. Thompson   int ierr;
467a982d89SJeremy L. Thompson 
477a982d89SJeremy L. Thompson   // Fallback Ceed
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) {
111e1e9e29dSJed Brown     if (emode == CEED_EVAL_WEIGHT) {
112e15f9bd0SJeremy L Thompson       // LCOV_EXCL_START
113e1e9e29dSJed Brown       return CeedError(ceed, CEED_ERROR_INCOMPATIBLE,
114e1e9e29dSJed Brown                        "CEED_ELEMRESTRICTION_NONE should be used "
115e15f9bd0SJeremy L Thompson                        "for a field with eval mode CEED_EVAL_WEIGHT");
116e15f9bd0SJeremy L Thompson       // LCOV_EXCL_STOP
117e15f9bd0SJeremy L Thompson     }
118e1e9e29dSJed Brown     ierr = CeedElemRestrictionGetNumComponents(r, &restr_ncomp);
119e1e9e29dSJed Brown   }
120e1e9e29dSJed Brown   if ((r == CEED_ELEMRESTRICTION_NONE) != (emode == CEED_EVAL_WEIGHT)) {
121e1e9e29dSJed Brown     // LCOV_EXCL_START
122e1e9e29dSJed Brown     return CeedError(ceed, CEED_ERROR_INCOMPATIBLE,
123e1e9e29dSJed Brown                      "CEED_ELEMRESTRICTION_NONE and CEED_EVAL_WEIGHT "
124e1e9e29dSJed Brown                      "must be used together.");
125e1e9e29dSJed Brown     // LCOV_EXCL_STOP
126e1e9e29dSJed Brown   }
127e15f9bd0SJeremy L Thompson   // Basis
128e15f9bd0SJeremy L Thompson   if (b != CEED_BASIS_COLLOCATED) {
129e1e9e29dSJed Brown     if (emode == CEED_EVAL_NONE)
130e1e9e29dSJed Brown       return CeedError(ceed, CEED_ERROR_INCOMPATIBLE,
131e1e9e29dSJed Brown                        "Field '%s' configured with CEED_EVAL_NONE must be used with CEED_BASIS_COLLOCATED",
132e1e9e29dSJed 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,
138e1e9e29dSJed Brown                        "Field '%s' of size %d and EvalMode %s: ElemRestriction has %d components, but Basis has %d components",
139e1e9e29dSJed Brown                        qfield->fieldname, qfield->size, CeedEvalModes[qfield->emode], restr_ncomp,
140e1e9e29dSJed 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,
150e1e9e29dSJed Brown                        "Field '%s' of size %d and EvalMode %s: ElemRestriction has %d components",
151e1e9e29dSJed 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,
158e1e9e29dSJed Brown                        "Field '%s' of size %d and EvalMode %s: ElemRestriction/Basis has %d components",
159e1e9e29dSJed 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,
166e1e9e29dSJed Brown                        "Field '%s' of size %d and EvalMode %s in %d dimensions: ElemRestriction/Basis has %d components",
167e1e9e29dSJed 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   @brief Common code for creating a multigrid coarse operator and level
379d99fa3c5SJeremy L Thompson            transfer operators for a CeedOperator
380d99fa3c5SJeremy L Thompson 
381d99fa3c5SJeremy L Thompson   @param[in] opFine       Fine grid operator
382d99fa3c5SJeremy L Thompson   @param[in] PMultFine    L-vector multiplicity in parallel gather/scatter
383d99fa3c5SJeremy L Thompson   @param[in] rstrCoarse   Coarse grid restriction
384d99fa3c5SJeremy L Thompson   @param[in] basisCoarse  Coarse grid active vector basis
385d99fa3c5SJeremy L Thompson   @param[in] basisCtoF    Basis for coarse to fine interpolation
386d99fa3c5SJeremy L Thompson   @param[out] opCoarse    Coarse grid operator
387d99fa3c5SJeremy L Thompson   @param[out] opProlong   Coarse to fine operator
388d99fa3c5SJeremy L Thompson   @param[out] opRestrict  Fine to coarse operator
389d99fa3c5SJeremy L Thompson 
390d99fa3c5SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
391d99fa3c5SJeremy L Thompson 
392d99fa3c5SJeremy L Thompson   @ref Developer
393d99fa3c5SJeremy L Thompson **/
394d99fa3c5SJeremy L Thompson static int CeedOperatorMultigridLevel_Core(CeedOperator opFine,
395d99fa3c5SJeremy L Thompson     CeedVector PMultFine, CeedElemRestriction rstrCoarse, CeedBasis basisCoarse,
396d99fa3c5SJeremy L Thompson     CeedBasis basisCtoF, CeedOperator *opCoarse, CeedOperator *opProlong,
397d99fa3c5SJeremy L Thompson     CeedOperator *opRestrict) {
398d99fa3c5SJeremy L Thompson   int ierr;
399d99fa3c5SJeremy L Thompson   Ceed ceed;
400d99fa3c5SJeremy L Thompson   ierr = CeedOperatorGetCeed(opFine, &ceed); CeedChk(ierr);
401d99fa3c5SJeremy L Thompson 
402d99fa3c5SJeremy L Thompson   // Check for composite operator
403d99fa3c5SJeremy L Thompson   bool isComposite;
404d99fa3c5SJeremy L Thompson   ierr = CeedOperatorIsComposite(opFine, &isComposite); CeedChk(ierr);
405d99fa3c5SJeremy L Thompson   if (isComposite)
406d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
407e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_UNSUPPORTED,
408d99fa3c5SJeremy L Thompson                      "Automatic multigrid setup for composite operators not supported");
409d99fa3c5SJeremy L Thompson   // LCOV_EXCL_STOP
410d99fa3c5SJeremy L Thompson 
411d99fa3c5SJeremy L Thompson   // Coarse Grid
412d99fa3c5SJeremy L Thompson   ierr = CeedOperatorCreate(ceed, opFine->qf, opFine->dqf, opFine->dqfT,
413d99fa3c5SJeremy L Thompson                             opCoarse); CeedChk(ierr);
414d99fa3c5SJeremy L Thompson   CeedElemRestriction rstrFine = NULL;
415d99fa3c5SJeremy L Thompson   // -- Clone input fields
416d99fa3c5SJeremy L Thompson   for (int i = 0; i < opFine->qf->numinputfields; i++) {
417d99fa3c5SJeremy L Thompson     if (opFine->inputfields[i]->vec == CEED_VECTOR_ACTIVE) {
418d99fa3c5SJeremy L Thompson       rstrFine = opFine->inputfields[i]->Erestrict;
419d99fa3c5SJeremy L Thompson       ierr = CeedOperatorSetField(*opCoarse, opFine->inputfields[i]->fieldname,
420d99fa3c5SJeremy L Thompson                                   rstrCoarse, basisCoarse, CEED_VECTOR_ACTIVE);
421d99fa3c5SJeremy L Thompson       CeedChk(ierr);
422d99fa3c5SJeremy L Thompson     } else {
423d99fa3c5SJeremy L Thompson       ierr = CeedOperatorSetField(*opCoarse, opFine->inputfields[i]->fieldname,
424d99fa3c5SJeremy L Thompson                                   opFine->inputfields[i]->Erestrict,
425d99fa3c5SJeremy L Thompson                                   opFine->inputfields[i]->basis,
426d99fa3c5SJeremy L Thompson                                   opFine->inputfields[i]->vec); CeedChk(ierr);
427d99fa3c5SJeremy L Thompson     }
428d99fa3c5SJeremy L Thompson   }
429d99fa3c5SJeremy L Thompson   // -- Clone output fields
430d99fa3c5SJeremy L Thompson   for (int i = 0; i < opFine->qf->numoutputfields; i++) {
431d99fa3c5SJeremy L Thompson     if (opFine->outputfields[i]->vec == CEED_VECTOR_ACTIVE) {
432d99fa3c5SJeremy L Thompson       ierr = CeedOperatorSetField(*opCoarse, opFine->outputfields[i]->fieldname,
433d99fa3c5SJeremy L Thompson                                   rstrCoarse, basisCoarse, CEED_VECTOR_ACTIVE);
434d99fa3c5SJeremy L Thompson       CeedChk(ierr);
435d99fa3c5SJeremy L Thompson     } else {
436d99fa3c5SJeremy L Thompson       ierr = CeedOperatorSetField(*opCoarse, opFine->outputfields[i]->fieldname,
437d99fa3c5SJeremy L Thompson                                   opFine->outputfields[i]->Erestrict,
438d99fa3c5SJeremy L Thompson                                   opFine->outputfields[i]->basis,
439d99fa3c5SJeremy L Thompson                                   opFine->outputfields[i]->vec); CeedChk(ierr);
440d99fa3c5SJeremy L Thompson     }
441d99fa3c5SJeremy L Thompson   }
442d99fa3c5SJeremy L Thompson 
443d99fa3c5SJeremy L Thompson   // Multiplicity vector
444d99fa3c5SJeremy L Thompson   CeedVector multVec, multE;
445d99fa3c5SJeremy L Thompson   ierr = CeedElemRestrictionCreateVector(rstrFine, &multVec, &multE);
446d99fa3c5SJeremy L Thompson   CeedChk(ierr);
447d99fa3c5SJeremy L Thompson   ierr = CeedVectorSetValue(multE, 0.0); CeedChk(ierr);
448d99fa3c5SJeremy L Thompson   ierr = CeedElemRestrictionApply(rstrFine, CEED_NOTRANSPOSE, PMultFine, multE,
449d99fa3c5SJeremy L Thompson                                   CEED_REQUEST_IMMEDIATE); CeedChk(ierr);
450d99fa3c5SJeremy L Thompson   ierr = CeedVectorSetValue(multVec, 0.0); CeedChk(ierr);
451d99fa3c5SJeremy L Thompson   ierr = CeedElemRestrictionApply(rstrFine, CEED_TRANSPOSE, multE, multVec,
452d99fa3c5SJeremy L Thompson                                   CEED_REQUEST_IMMEDIATE); CeedChk(ierr);
453d99fa3c5SJeremy L Thompson   ierr = CeedVectorDestroy(&multE); CeedChk(ierr);
454d99fa3c5SJeremy L Thompson   ierr = CeedVectorReciprocal(multVec); CeedChk(ierr);
455d99fa3c5SJeremy L Thompson 
456d99fa3c5SJeremy L Thompson   // Restriction
457d99fa3c5SJeremy L Thompson   CeedInt ncomp;
458d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumComponents(basisCoarse, &ncomp); CeedChk(ierr);
459d99fa3c5SJeremy L Thompson   CeedQFunction qfRestrict;
460d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionCreateInteriorByName(ceed, "Scale", &qfRestrict);
461d99fa3c5SJeremy L Thompson   CeedChk(ierr);
462777ff853SJeremy L Thompson   CeedInt *ncompRData;
463777ff853SJeremy L Thompson   ierr = CeedCalloc(1, &ncompRData); CeedChk(ierr);
464777ff853SJeremy L Thompson   ncompRData[0] = ncomp;
465777ff853SJeremy L Thompson   CeedQFunctionContext ctxR;
466777ff853SJeremy L Thompson   ierr = CeedQFunctionContextCreate(ceed, &ctxR); CeedChk(ierr);
467777ff853SJeremy L Thompson   ierr = CeedQFunctionContextSetData(ctxR, CEED_MEM_HOST, CEED_OWN_POINTER,
468777ff853SJeremy L Thompson                                      sizeof(*ncompRData), ncompRData);
469777ff853SJeremy L Thompson   CeedChk(ierr);
470777ff853SJeremy L Thompson   ierr = CeedQFunctionSetContext(qfRestrict, ctxR); CeedChk(ierr);
471777ff853SJeremy L Thompson   ierr = CeedQFunctionContextDestroy(&ctxR); CeedChk(ierr);
472d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionAddInput(qfRestrict, "input", ncomp, CEED_EVAL_NONE);
473d99fa3c5SJeremy L Thompson   CeedChk(ierr);
474d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionAddInput(qfRestrict, "scale", ncomp, CEED_EVAL_NONE);
475d99fa3c5SJeremy L Thompson   CeedChk(ierr);
476d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionAddOutput(qfRestrict, "output", ncomp, CEED_EVAL_INTERP);
477d99fa3c5SJeremy L Thompson   CeedChk(ierr);
478d99fa3c5SJeremy L Thompson 
479d99fa3c5SJeremy L Thompson   ierr = CeedOperatorCreate(ceed, qfRestrict, CEED_QFUNCTION_NONE,
480d99fa3c5SJeremy L Thompson                             CEED_QFUNCTION_NONE, opRestrict);
481d99fa3c5SJeremy L Thompson   CeedChk(ierr);
482d99fa3c5SJeremy L Thompson   ierr = CeedOperatorSetField(*opRestrict, "input", rstrFine,
483d99fa3c5SJeremy L Thompson                               CEED_BASIS_COLLOCATED, CEED_VECTOR_ACTIVE);
484d99fa3c5SJeremy L Thompson   CeedChk(ierr);
485d99fa3c5SJeremy L Thompson   ierr = CeedOperatorSetField(*opRestrict, "scale", rstrFine,
486d99fa3c5SJeremy L Thompson                               CEED_BASIS_COLLOCATED, multVec);
487d99fa3c5SJeremy L Thompson   CeedChk(ierr);
488d99fa3c5SJeremy L Thompson   ierr = CeedOperatorSetField(*opRestrict, "output", rstrCoarse, basisCtoF,
489d99fa3c5SJeremy L Thompson                               CEED_VECTOR_ACTIVE); CeedChk(ierr);
490d99fa3c5SJeremy L Thompson 
491d99fa3c5SJeremy L Thompson   // Prolongation
492d99fa3c5SJeremy L Thompson   CeedQFunction qfProlong;
493d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionCreateInteriorByName(ceed, "Scale", &qfProlong);
494d99fa3c5SJeremy L Thompson   CeedChk(ierr);
495777ff853SJeremy L Thompson   CeedInt *ncompPData;
496777ff853SJeremy L Thompson   ierr = CeedCalloc(1, &ncompPData); CeedChk(ierr);
497777ff853SJeremy L Thompson   ncompPData[0] = ncomp;
498777ff853SJeremy L Thompson   CeedQFunctionContext ctxP;
499777ff853SJeremy L Thompson   ierr = CeedQFunctionContextCreate(ceed, &ctxP); CeedChk(ierr);
500777ff853SJeremy L Thompson   ierr = CeedQFunctionContextSetData(ctxP, CEED_MEM_HOST, CEED_OWN_POINTER,
501777ff853SJeremy L Thompson                                      sizeof(*ncompPData), ncompPData);
502777ff853SJeremy L Thompson   CeedChk(ierr);
503777ff853SJeremy L Thompson   ierr = CeedQFunctionSetContext(qfProlong, ctxP); CeedChk(ierr);
504777ff853SJeremy L Thompson   ierr = CeedQFunctionContextDestroy(&ctxP); CeedChk(ierr);
505d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionAddInput(qfProlong, "input", ncomp, CEED_EVAL_INTERP);
506d99fa3c5SJeremy L Thompson   CeedChk(ierr);
507d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionAddInput(qfProlong, "scale", ncomp, CEED_EVAL_NONE);
508d99fa3c5SJeremy L Thompson   CeedChk(ierr);
509d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionAddOutput(qfProlong, "output", ncomp, CEED_EVAL_NONE);
510d99fa3c5SJeremy L Thompson   CeedChk(ierr);
511d99fa3c5SJeremy L Thompson 
512d99fa3c5SJeremy L Thompson   ierr = CeedOperatorCreate(ceed, qfProlong, CEED_QFUNCTION_NONE,
513d99fa3c5SJeremy L Thompson                             CEED_QFUNCTION_NONE, opProlong);
514d99fa3c5SJeremy L Thompson   CeedChk(ierr);
515d99fa3c5SJeremy L Thompson   ierr = CeedOperatorSetField(*opProlong, "input", rstrCoarse, basisCtoF,
516d99fa3c5SJeremy L Thompson                               CEED_VECTOR_ACTIVE); CeedChk(ierr);
517d99fa3c5SJeremy L Thompson   ierr = CeedOperatorSetField(*opProlong, "scale", rstrFine,
518d99fa3c5SJeremy L Thompson                               CEED_BASIS_COLLOCATED, multVec);
519d99fa3c5SJeremy L Thompson   CeedChk(ierr);
520d99fa3c5SJeremy L Thompson   ierr = CeedOperatorSetField(*opProlong, "output", rstrFine,
521d99fa3c5SJeremy L Thompson                               CEED_BASIS_COLLOCATED, CEED_VECTOR_ACTIVE);
522d99fa3c5SJeremy L Thompson   CeedChk(ierr);
523d99fa3c5SJeremy L Thompson 
524d99fa3c5SJeremy L Thompson   // Cleanup
525d99fa3c5SJeremy L Thompson   ierr = CeedVectorDestroy(&multVec); CeedChk(ierr);
526d99fa3c5SJeremy L Thompson   ierr = CeedBasisDestroy(&basisCtoF); CeedChk(ierr);
527d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionDestroy(&qfRestrict); CeedChk(ierr);
528d99fa3c5SJeremy L Thompson   ierr = CeedQFunctionDestroy(&qfProlong); CeedChk(ierr);
529e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
530d99fa3c5SJeremy L Thompson }
531d99fa3c5SJeremy L Thompson 
5327a982d89SJeremy L. Thompson /// @}
5337a982d89SJeremy L. Thompson 
5347a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
5357a982d89SJeremy L. Thompson /// CeedOperator Backend API
5367a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
5377a982d89SJeremy L. Thompson /// @addtogroup CeedOperatorBackend
5387a982d89SJeremy L. Thompson /// @{
5397a982d89SJeremy L. Thompson 
5407a982d89SJeremy L. Thompson /**
5417a982d89SJeremy L. Thompson   @brief Get the Ceed associated with a CeedOperator
5427a982d89SJeremy L. Thompson 
5437a982d89SJeremy L. Thompson   @param op              CeedOperator
5447a982d89SJeremy L. Thompson   @param[out] ceed       Variable to store Ceed
5457a982d89SJeremy L. Thompson 
5467a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5477a982d89SJeremy L. Thompson 
5487a982d89SJeremy L. Thompson   @ref Backend
5497a982d89SJeremy L. Thompson **/
5507a982d89SJeremy L. Thompson 
5517a982d89SJeremy L. Thompson int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) {
5527a982d89SJeremy L. Thompson   *ceed = op->ceed;
553e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5547a982d89SJeremy L. Thompson }
5557a982d89SJeremy L. Thompson 
5567a982d89SJeremy L. Thompson /**
5577a982d89SJeremy L. Thompson   @brief Get the number of elements associated with a CeedOperator
5587a982d89SJeremy L. Thompson 
5597a982d89SJeremy L. Thompson   @param op              CeedOperator
5607a982d89SJeremy L. Thompson   @param[out] numelem    Variable to store number of elements
5617a982d89SJeremy L. Thompson 
5627a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5637a982d89SJeremy L. Thompson 
5647a982d89SJeremy L. Thompson   @ref Backend
5657a982d89SJeremy L. Thompson **/
5667a982d89SJeremy L. Thompson 
5677a982d89SJeremy L. Thompson int CeedOperatorGetNumElements(CeedOperator op, CeedInt *numelem) {
5687a982d89SJeremy L. Thompson   if (op->composite)
5697a982d89SJeremy L. Thompson     // LCOV_EXCL_START
570e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
571e15f9bd0SJeremy L Thompson                      "Not defined for composite operator");
5727a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
5737a982d89SJeremy L. Thompson 
5747a982d89SJeremy L. Thompson   *numelem = op->numelements;
575e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5767a982d89SJeremy L. Thompson }
5777a982d89SJeremy L. Thompson 
5787a982d89SJeremy L. Thompson /**
5797a982d89SJeremy L. Thompson   @brief Get the number of quadrature points associated with a CeedOperator
5807a982d89SJeremy L. Thompson 
5817a982d89SJeremy L. Thompson   @param op              CeedOperator
5827a982d89SJeremy L. Thompson   @param[out] numqpts    Variable to store vector number of quadrature points
5837a982d89SJeremy L. Thompson 
5847a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5857a982d89SJeremy L. Thompson 
5867a982d89SJeremy L. Thompson   @ref Backend
5877a982d89SJeremy L. Thompson **/
5887a982d89SJeremy L. Thompson 
5897a982d89SJeremy L. Thompson int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *numqpts) {
5907a982d89SJeremy L. Thompson   if (op->composite)
5917a982d89SJeremy L. Thompson     // LCOV_EXCL_START
592e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
593e15f9bd0SJeremy L Thompson                      "Not defined for composite operator");
5947a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
5957a982d89SJeremy L. Thompson 
5967a982d89SJeremy L. Thompson   *numqpts = op->numqpoints;
597e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5987a982d89SJeremy L. Thompson }
5997a982d89SJeremy L. Thompson 
6007a982d89SJeremy L. Thompson /**
6017a982d89SJeremy L. Thompson   @brief Get the number of arguments associated with a CeedOperator
6027a982d89SJeremy L. Thompson 
6037a982d89SJeremy L. Thompson   @param op              CeedOperator
6047a982d89SJeremy L. Thompson   @param[out] numargs    Variable to store vector number of arguments
6057a982d89SJeremy L. Thompson 
6067a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6077a982d89SJeremy L. Thompson 
6087a982d89SJeremy L. Thompson   @ref Backend
6097a982d89SJeremy L. Thompson **/
6107a982d89SJeremy L. Thompson 
6117a982d89SJeremy L. Thompson int CeedOperatorGetNumArgs(CeedOperator op, CeedInt *numargs) {
6127a982d89SJeremy L. Thompson   if (op->composite)
6137a982d89SJeremy L. Thompson     // LCOV_EXCL_START
614e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
615e15f9bd0SJeremy L Thompson                      "Not defined for composite operators");
6167a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
6177a982d89SJeremy L. Thompson 
6187a982d89SJeremy L. Thompson   *numargs = op->nfields;
619e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6207a982d89SJeremy L. Thompson }
6217a982d89SJeremy L. Thompson 
6227a982d89SJeremy L. Thompson /**
6237a982d89SJeremy L. Thompson   @brief Get the setup status of a CeedOperator
6247a982d89SJeremy L. Thompson 
6257a982d89SJeremy L. Thompson   @param op                CeedOperator
626fd364f38SJeremy L Thompson   @param[out] issetupdone  Variable to store setup status
6277a982d89SJeremy L. Thompson 
6287a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6297a982d89SJeremy L. Thompson 
6307a982d89SJeremy L. Thompson   @ref Backend
6317a982d89SJeremy L. Thompson **/
6327a982d89SJeremy L. Thompson 
633fd364f38SJeremy L Thompson int CeedOperatorIsSetupDone(CeedOperator op, bool *issetupdone) {
634e15f9bd0SJeremy L Thompson   *issetupdone = op->backendsetup;
635e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6367a982d89SJeremy L. Thompson }
6377a982d89SJeremy L. Thompson 
6387a982d89SJeremy L. Thompson /**
6397a982d89SJeremy L. Thompson   @brief Get the QFunction associated with a CeedOperator
6407a982d89SJeremy L. Thompson 
6417a982d89SJeremy L. Thompson   @param op              CeedOperator
6427a982d89SJeremy L. Thompson   @param[out] qf         Variable to store QFunction
6437a982d89SJeremy L. Thompson 
6447a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6457a982d89SJeremy L. Thompson 
6467a982d89SJeremy L. Thompson   @ref Backend
6477a982d89SJeremy L. Thompson **/
6487a982d89SJeremy L. Thompson 
6497a982d89SJeremy L. Thompson int CeedOperatorGetQFunction(CeedOperator op, CeedQFunction *qf) {
6507a982d89SJeremy L. Thompson   if (op->composite)
6517a982d89SJeremy L. Thompson     // LCOV_EXCL_START
652e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
653e15f9bd0SJeremy L Thompson                      "Not defined for composite operator");
6547a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
6557a982d89SJeremy L. Thompson 
6567a982d89SJeremy L. Thompson   *qf = op->qf;
657e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6587a982d89SJeremy L. Thompson }
6597a982d89SJeremy L. Thompson 
6607a982d89SJeremy L. Thompson /**
661c04a41a7SJeremy L Thompson   @brief Get a boolean value indicating if the CeedOperator is composite
662c04a41a7SJeremy L Thompson 
663c04a41a7SJeremy L Thompson   @param op                CeedOperator
664fd364f38SJeremy L Thompson   @param[out] iscomposite  Variable to store composite status
665c04a41a7SJeremy L Thompson 
666c04a41a7SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
667c04a41a7SJeremy L Thompson 
668c04a41a7SJeremy L Thompson   @ref Backend
669c04a41a7SJeremy L Thompson **/
670c04a41a7SJeremy L Thompson 
671fd364f38SJeremy L Thompson int CeedOperatorIsComposite(CeedOperator op, bool *iscomposite) {
672fd364f38SJeremy L Thompson   *iscomposite = op->composite;
673e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
674c04a41a7SJeremy L Thompson }
675c04a41a7SJeremy L Thompson 
676c04a41a7SJeremy L Thompson /**
6777a982d89SJeremy L. Thompson   @brief Get the number of suboperators associated with a CeedOperator
6787a982d89SJeremy L. Thompson 
6797a982d89SJeremy L. Thompson   @param op              CeedOperator
6807a982d89SJeremy L. Thompson   @param[out] numsub     Variable to store number of suboperators
6817a982d89SJeremy L. Thompson 
6827a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6837a982d89SJeremy L. Thompson 
6847a982d89SJeremy L. Thompson   @ref Backend
6857a982d89SJeremy L. Thompson **/
6867a982d89SJeremy L. Thompson 
6877a982d89SJeremy L. Thompson int CeedOperatorGetNumSub(CeedOperator op, CeedInt *numsub) {
6887a982d89SJeremy L. Thompson   if (!op->composite)
6897a982d89SJeremy L. Thompson     // LCOV_EXCL_START
690e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR, "Not a composite operator");
6917a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
6927a982d89SJeremy L. Thompson 
6937a982d89SJeremy L. Thompson   *numsub = op->numsub;
694e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6957a982d89SJeremy L. Thompson }
6967a982d89SJeremy L. Thompson 
6977a982d89SJeremy L. Thompson /**
6987a982d89SJeremy L. Thompson   @brief Get the list of suboperators associated with a CeedOperator
6997a982d89SJeremy L. Thompson 
7007a982d89SJeremy L. Thompson   @param op                CeedOperator
7017a982d89SJeremy L. Thompson   @param[out] suboperators Variable to store list of suboperators
7027a982d89SJeremy L. Thompson 
7037a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
7047a982d89SJeremy L. Thompson 
7057a982d89SJeremy L. Thompson   @ref Backend
7067a982d89SJeremy L. Thompson **/
7077a982d89SJeremy L. Thompson 
7087a982d89SJeremy L. Thompson int CeedOperatorGetSubList(CeedOperator op, CeedOperator **suboperators) {
7097a982d89SJeremy L. Thompson   if (!op->composite)
7107a982d89SJeremy L. Thompson     // LCOV_EXCL_START
711e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR, "Not a composite operator");
7127a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
7137a982d89SJeremy L. Thompson 
7147a982d89SJeremy L. Thompson   *suboperators = op->suboperators;
715e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
7167a982d89SJeremy L. Thompson }
7177a982d89SJeremy L. Thompson 
7187a982d89SJeremy L. Thompson /**
7197a982d89SJeremy L. Thompson   @brief Get the backend data of a CeedOperator
7207a982d89SJeremy L. Thompson 
7217a982d89SJeremy L. Thompson   @param op              CeedOperator
7227a982d89SJeremy L. Thompson   @param[out] data       Variable to store data
7237a982d89SJeremy L. Thompson 
7247a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
7257a982d89SJeremy L. Thompson 
7267a982d89SJeremy L. Thompson   @ref Backend
7277a982d89SJeremy L. Thompson **/
7287a982d89SJeremy L. Thompson 
729777ff853SJeremy L Thompson int CeedOperatorGetData(CeedOperator op, void *data) {
730777ff853SJeremy L Thompson   *(void **)data = op->data;
731e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
7327a982d89SJeremy L. Thompson }
7337a982d89SJeremy L. Thompson 
7347a982d89SJeremy L. Thompson /**
7357a982d89SJeremy L. Thompson   @brief Set the backend data of a CeedOperator
7367a982d89SJeremy L. Thompson 
7377a982d89SJeremy L. Thompson   @param[out] op         CeedOperator
7387a982d89SJeremy L. Thompson   @param data            Data to set
7397a982d89SJeremy L. Thompson 
7407a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
7417a982d89SJeremy L. Thompson 
7427a982d89SJeremy L. Thompson   @ref Backend
7437a982d89SJeremy L. Thompson **/
7447a982d89SJeremy L. Thompson 
745777ff853SJeremy L Thompson int CeedOperatorSetData(CeedOperator op, void *data) {
746777ff853SJeremy L Thompson   op->data = data;
747e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
7487a982d89SJeremy L. Thompson }
7497a982d89SJeremy L. Thompson 
7507a982d89SJeremy L. Thompson /**
7517a982d89SJeremy L. Thompson   @brief Set the setup flag of a CeedOperator to True
7527a982d89SJeremy L. Thompson 
7537a982d89SJeremy L. Thompson   @param op              CeedOperator
7547a982d89SJeremy L. Thompson 
7557a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
7567a982d89SJeremy L. Thompson 
7577a982d89SJeremy L. Thompson   @ref Backend
7587a982d89SJeremy L. Thompson **/
7597a982d89SJeremy L. Thompson 
7607a982d89SJeremy L. Thompson int CeedOperatorSetSetupDone(CeedOperator op) {
761e15f9bd0SJeremy L Thompson   op->backendsetup = true;
762e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
7637a982d89SJeremy L. Thompson }
7647a982d89SJeremy L. Thompson 
7657a982d89SJeremy L. Thompson /**
7667a982d89SJeremy L. Thompson   @brief Get the CeedOperatorFields of a CeedOperator
7677a982d89SJeremy L. Thompson 
7687a982d89SJeremy L. Thompson   @param op                 CeedOperator
7697a982d89SJeremy L. Thompson   @param[out] inputfields   Variable to store inputfields
7707a982d89SJeremy L. Thompson   @param[out] outputfields  Variable to store outputfields
7717a982d89SJeremy L. Thompson 
7727a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
7737a982d89SJeremy L. Thompson 
7747a982d89SJeremy L. Thompson   @ref Backend
7757a982d89SJeremy L. Thompson **/
7767a982d89SJeremy L. Thompson 
7777a982d89SJeremy L. Thompson int CeedOperatorGetFields(CeedOperator op, CeedOperatorField **inputfields,
7787a982d89SJeremy L. Thompson                           CeedOperatorField **outputfields) {
7797a982d89SJeremy L. Thompson   if (op->composite)
7807a982d89SJeremy L. Thompson     // LCOV_EXCL_START
781e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
782e15f9bd0SJeremy L Thompson                      "Not defined for composite operator");
7837a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
7847a982d89SJeremy L. Thompson 
7857a982d89SJeremy L. Thompson   if (inputfields) *inputfields = op->inputfields;
7867a982d89SJeremy L. Thompson   if (outputfields) *outputfields = op->outputfields;
787e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
7887a982d89SJeremy L. Thompson }
7897a982d89SJeremy L. Thompson 
7907a982d89SJeremy L. Thompson /**
7917a982d89SJeremy L. Thompson   @brief Get the CeedElemRestriction of a CeedOperatorField
7927a982d89SJeremy L. Thompson 
7937a982d89SJeremy L. Thompson   @param opfield         CeedOperatorField
7947a982d89SJeremy L. Thompson   @param[out] rstr       Variable to store CeedElemRestriction
7957a982d89SJeremy L. Thompson 
7967a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
7977a982d89SJeremy L. Thompson 
7987a982d89SJeremy L. Thompson   @ref Backend
7997a982d89SJeremy L. Thompson **/
8007a982d89SJeremy L. Thompson 
8017a982d89SJeremy L. Thompson int CeedOperatorFieldGetElemRestriction(CeedOperatorField opfield,
8027a982d89SJeremy L. Thompson                                         CeedElemRestriction *rstr) {
8037a982d89SJeremy L. Thompson   *rstr = opfield->Erestrict;
804e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
8057a982d89SJeremy L. Thompson }
8067a982d89SJeremy L. Thompson 
8077a982d89SJeremy L. Thompson /**
8087a982d89SJeremy L. Thompson   @brief Get the CeedBasis of a CeedOperatorField
8097a982d89SJeremy L. Thompson 
8107a982d89SJeremy L. Thompson   @param opfield         CeedOperatorField
8117a982d89SJeremy L. Thompson   @param[out] basis      Variable to store CeedBasis
8127a982d89SJeremy L. Thompson 
8137a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
8147a982d89SJeremy L. Thompson 
8157a982d89SJeremy L. Thompson   @ref Backend
8167a982d89SJeremy L. Thompson **/
8177a982d89SJeremy L. Thompson 
8187a982d89SJeremy L. Thompson int CeedOperatorFieldGetBasis(CeedOperatorField opfield, CeedBasis *basis) {
8197a982d89SJeremy L. Thompson   *basis = opfield->basis;
820e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
8217a982d89SJeremy L. Thompson }
8227a982d89SJeremy L. Thompson 
8237a982d89SJeremy L. Thompson /**
8247a982d89SJeremy L. Thompson   @brief Get the CeedVector of a CeedOperatorField
8257a982d89SJeremy L. Thompson 
8267a982d89SJeremy L. Thompson   @param opfield         CeedOperatorField
8277a982d89SJeremy L. Thompson   @param[out] vec        Variable to store CeedVector
8287a982d89SJeremy L. Thompson 
8297a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
8307a982d89SJeremy L. Thompson 
8317a982d89SJeremy L. Thompson   @ref Backend
8327a982d89SJeremy L. Thompson **/
8337a982d89SJeremy L. Thompson 
8347a982d89SJeremy L. Thompson int CeedOperatorFieldGetVector(CeedOperatorField opfield, CeedVector *vec) {
8357a982d89SJeremy L. Thompson   *vec = opfield->vec;
836e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
8377a982d89SJeremy L. Thompson }
8387a982d89SJeremy L. Thompson 
8397a982d89SJeremy L. Thompson /// @}
8407a982d89SJeremy L. Thompson 
8417a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
8427a982d89SJeremy L. Thompson /// CeedOperator Public API
8437a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
8447a982d89SJeremy L. Thompson /// @addtogroup CeedOperatorUser
845dfdf5a53Sjeremylt /// @{
846d7b241e6Sjeremylt 
847d7b241e6Sjeremylt /**
8480219ea01SJeremy L Thompson   @brief Create a CeedOperator and associate a CeedQFunction. A CeedBasis and
8490219ea01SJeremy L Thompson            CeedElemRestriction can be associated with CeedQFunction fields with
8500219ea01SJeremy L Thompson            \ref CeedOperatorSetField.
851d7b241e6Sjeremylt 
852b11c1e72Sjeremylt   @param ceed    A Ceed object where the CeedOperator will be created
853d7b241e6Sjeremylt   @param qf      QFunction defining the action of the operator at quadrature points
85434138859Sjeremylt   @param dqf     QFunction defining the action of the Jacobian of @a qf (or
8554cc79fe7SJed Brown                    @ref CEED_QFUNCTION_NONE)
856d7b241e6Sjeremylt   @param dqfT    QFunction defining the action of the transpose of the Jacobian
8574cc79fe7SJed Brown                    of @a qf (or @ref CEED_QFUNCTION_NONE)
858b11c1e72Sjeremylt   @param[out] op Address of the variable where the newly created
859b11c1e72Sjeremylt                      CeedOperator will be stored
860b11c1e72Sjeremylt 
861b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
862dfdf5a53Sjeremylt 
8637a982d89SJeremy L. Thompson   @ref User
864d7b241e6Sjeremylt  */
865d7b241e6Sjeremylt int CeedOperatorCreate(Ceed ceed, CeedQFunction qf, CeedQFunction dqf,
866d7b241e6Sjeremylt                        CeedQFunction dqfT, CeedOperator *op) {
867d7b241e6Sjeremylt   int ierr;
868d7b241e6Sjeremylt 
8695fe0d4faSjeremylt   if (!ceed->OperatorCreate) {
8705fe0d4faSjeremylt     Ceed delegate;
871aefd8378Sjeremylt     ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr);
8725fe0d4faSjeremylt 
8735fe0d4faSjeremylt     if (!delegate)
874c042f62fSJeremy L Thompson       // LCOV_EXCL_START
875e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_UNSUPPORTED,
876e15f9bd0SJeremy L Thompson                        "Backend does not support OperatorCreate");
877c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
8785fe0d4faSjeremylt 
8795fe0d4faSjeremylt     ierr = CeedOperatorCreate(delegate, qf, dqf, dqfT, op); CeedChk(ierr);
880e15f9bd0SJeremy L Thompson     return CEED_ERROR_SUCCESS;
8815fe0d4faSjeremylt   }
8825fe0d4faSjeremylt 
883b3b7035fSJeremy L Thompson   if (!qf || qf == CEED_QFUNCTION_NONE)
884b3b7035fSJeremy L Thompson     // LCOV_EXCL_START
885e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_MINOR,
886e15f9bd0SJeremy L Thompson                      "Operator must have a valid QFunction.");
887b3b7035fSJeremy L Thompson   // LCOV_EXCL_STOP
888d7b241e6Sjeremylt   ierr = CeedCalloc(1, op); CeedChk(ierr);
889d7b241e6Sjeremylt   (*op)->ceed = ceed;
890d7b241e6Sjeremylt   ceed->refcount++;
891d7b241e6Sjeremylt   (*op)->refcount = 1;
892d7b241e6Sjeremylt   (*op)->qf = qf;
893d7b241e6Sjeremylt   qf->refcount++;
894442e7f0bSjeremylt   if (dqf && dqf != CEED_QFUNCTION_NONE) {
895d7b241e6Sjeremylt     (*op)->dqf = dqf;
896442e7f0bSjeremylt     dqf->refcount++;
897442e7f0bSjeremylt   }
898442e7f0bSjeremylt   if (dqfT && dqfT != CEED_QFUNCTION_NONE) {
899d7b241e6Sjeremylt     (*op)->dqfT = dqfT;
900442e7f0bSjeremylt     dqfT->refcount++;
901442e7f0bSjeremylt   }
902fe2413ffSjeremylt   ierr = CeedCalloc(16, &(*op)->inputfields); CeedChk(ierr);
903fe2413ffSjeremylt   ierr = CeedCalloc(16, &(*op)->outputfields); CeedChk(ierr);
904d7b241e6Sjeremylt   ierr = ceed->OperatorCreate(*op); CeedChk(ierr);
905e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
906d7b241e6Sjeremylt }
907d7b241e6Sjeremylt 
908d7b241e6Sjeremylt /**
90952d6035fSJeremy L Thompson   @brief Create an operator that composes the action of several operators
91052d6035fSJeremy L Thompson 
91152d6035fSJeremy L Thompson   @param ceed    A Ceed object where the CeedOperator will be created
91252d6035fSJeremy L Thompson   @param[out] op Address of the variable where the newly created
91352d6035fSJeremy L Thompson                      Composite CeedOperator will be stored
91452d6035fSJeremy L Thompson 
91552d6035fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
91652d6035fSJeremy L Thompson 
9177a982d89SJeremy L. Thompson   @ref User
91852d6035fSJeremy L Thompson  */
91952d6035fSJeremy L Thompson int CeedCompositeOperatorCreate(Ceed ceed, CeedOperator *op) {
92052d6035fSJeremy L Thompson   int ierr;
92152d6035fSJeremy L Thompson 
92252d6035fSJeremy L Thompson   if (!ceed->CompositeOperatorCreate) {
92352d6035fSJeremy L Thompson     Ceed delegate;
924aefd8378Sjeremylt     ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr);
92552d6035fSJeremy L Thompson 
926250756a7Sjeremylt     if (delegate) {
92752d6035fSJeremy L Thompson       ierr = CeedCompositeOperatorCreate(delegate, op); CeedChk(ierr);
928e15f9bd0SJeremy L Thompson       return CEED_ERROR_SUCCESS;
92952d6035fSJeremy L Thompson     }
930250756a7Sjeremylt   }
93152d6035fSJeremy L Thompson 
93252d6035fSJeremy L Thompson   ierr = CeedCalloc(1, op); CeedChk(ierr);
93352d6035fSJeremy L Thompson   (*op)->ceed = ceed;
93452d6035fSJeremy L Thompson   ceed->refcount++;
93552d6035fSJeremy L Thompson   (*op)->composite = true;
93652d6035fSJeremy L Thompson   ierr = CeedCalloc(16, &(*op)->suboperators); CeedChk(ierr);
937250756a7Sjeremylt 
938250756a7Sjeremylt   if (ceed->CompositeOperatorCreate) {
93952d6035fSJeremy L Thompson     ierr = ceed->CompositeOperatorCreate(*op); CeedChk(ierr);
940250756a7Sjeremylt   }
941e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
94252d6035fSJeremy L Thompson }
94352d6035fSJeremy L Thompson 
94452d6035fSJeremy L Thompson /**
945b11c1e72Sjeremylt   @brief Provide a field to a CeedOperator for use by its CeedQFunction
946d7b241e6Sjeremylt 
947d7b241e6Sjeremylt   This function is used to specify both active and passive fields to a
948d7b241e6Sjeremylt   CeedOperator.  For passive fields, a vector @arg v must be provided.  Passive
949d7b241e6Sjeremylt   fields can inputs or outputs (updated in-place when operator is applied).
950d7b241e6Sjeremylt 
951d7b241e6Sjeremylt   Active fields must be specified using this function, but their data (in a
952d7b241e6Sjeremylt   CeedVector) is passed in CeedOperatorApply().  There can be at most one active
953d7b241e6Sjeremylt   input and at most one active output.
954d7b241e6Sjeremylt 
9558c91a0c9SJeremy L Thompson   @param op         CeedOperator on which to provide the field
9568795c945Sjeremylt   @param fieldname  Name of the field (to be matched with the name used by
9578795c945Sjeremylt                       CeedQFunction)
958b11c1e72Sjeremylt   @param r          CeedElemRestriction
9594cc79fe7SJed Brown   @param b          CeedBasis in which the field resides or @ref CEED_BASIS_COLLOCATED
960b11c1e72Sjeremylt                       if collocated with quadrature points
9614cc79fe7SJed Brown   @param v          CeedVector to be used by CeedOperator or @ref CEED_VECTOR_ACTIVE
9624cc79fe7SJed Brown                       if field is active or @ref CEED_VECTOR_NONE if using
9634cc79fe7SJed Brown                       @ref CEED_EVAL_WEIGHT in the QFunction
964b11c1e72Sjeremylt 
965b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
966dfdf5a53Sjeremylt 
9677a982d89SJeremy L. Thompson   @ref User
968b11c1e72Sjeremylt **/
969d7b241e6Sjeremylt int CeedOperatorSetField(CeedOperator op, const char *fieldname,
970a8d32208Sjeremylt                          CeedElemRestriction r, CeedBasis b, CeedVector v) {
971d7b241e6Sjeremylt   int ierr;
97252d6035fSJeremy L Thompson   if (op->composite)
973c042f62fSJeremy L Thompson     // LCOV_EXCL_START
974e1e9e29dSJed Brown     return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
975e15f9bd0SJeremy L Thompson                      "Cannot add field to composite operator.");
976c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
9778b067b84SJed Brown   if (!r)
978c042f62fSJeremy L Thompson     // LCOV_EXCL_START
979e1e9e29dSJed Brown     return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
980c042f62fSJeremy L Thompson                      "ElemRestriction r for field \"%s\" must be non-NULL.",
981c042f62fSJeremy L Thompson                      fieldname);
982c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
9838b067b84SJed Brown   if (!b)
984c042f62fSJeremy L Thompson     // LCOV_EXCL_START
985e1e9e29dSJed Brown     return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
986e15f9bd0SJeremy L Thompson                      "Basis b for field \"%s\" must be non-NULL.",
987c042f62fSJeremy L Thompson                      fieldname);
988c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
9898b067b84SJed Brown   if (!v)
990c042f62fSJeremy L Thompson     // LCOV_EXCL_START
991e1e9e29dSJed Brown     return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
992e15f9bd0SJeremy L Thompson                      "Vector v for field \"%s\" must be non-NULL.",
993c042f62fSJeremy L Thompson                      fieldname);
994c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
99552d6035fSJeremy L Thompson 
996d7b241e6Sjeremylt   CeedInt numelements;
997d7b241e6Sjeremylt   ierr = CeedElemRestrictionGetNumElements(r, &numelements); CeedChk(ierr);
99815910d16Sjeremylt   if (r != CEED_ELEMRESTRICTION_NONE && op->hasrestriction &&
99915910d16Sjeremylt       op->numelements != numelements)
1000c042f62fSJeremy L Thompson     // LCOV_EXCL_START
1001e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_DIMENSION,
10021d102b48SJeremy L Thompson                      "ElemRestriction with %d elements incompatible with prior "
10031d102b48SJeremy L Thompson                      "%d elements", numelements, op->numelements);
1004c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
1005d7b241e6Sjeremylt 
1006d7b241e6Sjeremylt   CeedInt numqpoints;
1007e15f9bd0SJeremy L Thompson   if (b != CEED_BASIS_COLLOCATED) {
1008d7b241e6Sjeremylt     ierr = CeedBasisGetNumQuadraturePoints(b, &numqpoints); CeedChk(ierr);
1009d7b241e6Sjeremylt     if (op->numqpoints && op->numqpoints != numqpoints)
1010c042f62fSJeremy L Thompson       // LCOV_EXCL_START
1011e15f9bd0SJeremy L Thompson       return CeedError(op->ceed, CEED_ERROR_DIMENSION,
1012e15f9bd0SJeremy L Thompson                        "Basis with %d quadrature points "
10131d102b48SJeremy L Thompson                        "incompatible with prior %d points", numqpoints,
10141d102b48SJeremy L Thompson                        op->numqpoints);
1015c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
1016d7b241e6Sjeremylt   }
101715910d16Sjeremylt   CeedQFunctionField qfield;
1018d1bcdac9Sjeremylt   CeedOperatorField *ofield;
1019d7b241e6Sjeremylt   for (CeedInt i=0; i<op->qf->numinputfields; i++) {
1020fe2413ffSjeremylt     if (!strcmp(fieldname, (*op->qf->inputfields[i]).fieldname)) {
102115910d16Sjeremylt       qfield = op->qf->inputfields[i];
1022d7b241e6Sjeremylt       ofield = &op->inputfields[i];
1023d7b241e6Sjeremylt       goto found;
1024d7b241e6Sjeremylt     }
1025d7b241e6Sjeremylt   }
1026d7b241e6Sjeremylt   for (CeedInt i=0; i<op->qf->numoutputfields; i++) {
1027fe2413ffSjeremylt     if (!strcmp(fieldname, (*op->qf->outputfields[i]).fieldname)) {
1028e15f9bd0SJeremy L Thompson       qfield = op->qf->outputfields[i];
1029d7b241e6Sjeremylt       ofield = &op->outputfields[i];
1030d7b241e6Sjeremylt       goto found;
1031d7b241e6Sjeremylt     }
1032d7b241e6Sjeremylt   }
1033c042f62fSJeremy L Thompson   // LCOV_EXCL_START
1034e15f9bd0SJeremy L Thompson   return CeedError(op->ceed, CEED_ERROR_INCOMPLETE,
1035e15f9bd0SJeremy L Thompson                    "QFunction has no knowledge of field '%s'",
1036d7b241e6Sjeremylt                    fieldname);
1037c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
1038d7b241e6Sjeremylt found:
1039e15f9bd0SJeremy L Thompson   ierr = CeedOperatorCheckField(op->ceed, qfield, r, b); CeedChk(ierr);
1040fe2413ffSjeremylt   ierr = CeedCalloc(1, ofield); CeedChk(ierr);
1041e15f9bd0SJeremy L Thompson 
1042e15f9bd0SJeremy L Thompson   (*ofield)->vec = v;
1043e15f9bd0SJeremy L Thompson   if (v != CEED_VECTOR_ACTIVE && v != CEED_VECTOR_NONE) {
1044e15f9bd0SJeremy L Thompson     v->refcount += 1;
1045e15f9bd0SJeremy L Thompson   }
1046e15f9bd0SJeremy L Thompson 
1047fe2413ffSjeremylt   (*ofield)->Erestrict = r;
104871352a93Sjeremylt   r->refcount += 1;
1049e15f9bd0SJeremy L Thompson   if (r != CEED_ELEMRESTRICTION_NONE) {
1050e15f9bd0SJeremy L Thompson     op->numelements = numelements;
1051e15f9bd0SJeremy L Thompson     op->hasrestriction = true; // Restriction set, but numelements may be 0
1052e15f9bd0SJeremy L Thompson   }
1053d99fa3c5SJeremy L Thompson 
1054e15f9bd0SJeremy L Thompson   (*ofield)->basis = b;
1055e15f9bd0SJeremy L Thompson   if (b != CEED_BASIS_COLLOCATED) {
1056e15f9bd0SJeremy L Thompson     op->numqpoints = numqpoints;
1057e15f9bd0SJeremy L Thompson     b->refcount += 1;
1058e15f9bd0SJeremy L Thompson   }
1059e15f9bd0SJeremy L Thompson 
1060e15f9bd0SJeremy L Thompson   op->nfields += 1;
1061d99fa3c5SJeremy L Thompson   size_t len = strlen(fieldname);
1062d99fa3c5SJeremy L Thompson   char *tmp;
1063d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(len+1, &tmp); CeedChk(ierr);
1064d99fa3c5SJeremy L Thompson   memcpy(tmp, fieldname, len+1);
1065d99fa3c5SJeremy L Thompson   (*ofield)->fieldname = tmp;
1066e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1067d7b241e6Sjeremylt }
1068d7b241e6Sjeremylt 
1069d7b241e6Sjeremylt /**
107052d6035fSJeremy L Thompson   @brief Add a sub-operator to a composite CeedOperator
1071288c0443SJeremy L Thompson 
107234138859Sjeremylt   @param[out] compositeop Composite CeedOperator
107334138859Sjeremylt   @param      subop       Sub-operator CeedOperator
107452d6035fSJeremy L Thompson 
107552d6035fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
107652d6035fSJeremy L Thompson 
10777a982d89SJeremy L. Thompson   @ref User
107852d6035fSJeremy L Thompson  */
1079692c2638Sjeremylt int CeedCompositeOperatorAddSub(CeedOperator compositeop, CeedOperator subop) {
108052d6035fSJeremy L Thompson   if (!compositeop->composite)
1081c042f62fSJeremy L Thompson     // LCOV_EXCL_START
1082e15f9bd0SJeremy L Thompson     return CeedError(compositeop->ceed, CEED_ERROR_MINOR,
1083e2f04181SAndrew T. Barker                      "CeedOperator is not a composite operator");
1084c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
108552d6035fSJeremy L Thompson 
108652d6035fSJeremy L Thompson   if (compositeop->numsub == CEED_COMPOSITE_MAX)
1087c042f62fSJeremy L Thompson     // LCOV_EXCL_START
1088e15f9bd0SJeremy L Thompson     return CeedError(compositeop->ceed, CEED_ERROR_UNSUPPORTED,
1089e15f9bd0SJeremy L Thompson                      "Cannot add additional suboperators");
1090c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
109152d6035fSJeremy L Thompson 
109252d6035fSJeremy L Thompson   compositeop->suboperators[compositeop->numsub] = subop;
109352d6035fSJeremy L Thompson   subop->refcount++;
109452d6035fSJeremy L Thompson   compositeop->numsub++;
1095e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
109652d6035fSJeremy L Thompson }
109752d6035fSJeremy L Thompson 
109852d6035fSJeremy L Thompson /**
10991d102b48SJeremy L Thompson   @brief Assemble a linear CeedQFunction associated with a CeedOperator
11001d102b48SJeremy L Thompson 
11011d102b48SJeremy L Thompson   This returns a CeedVector containing a matrix at each quadrature point
11021d102b48SJeremy L Thompson     providing the action of the CeedQFunction associated with the CeedOperator.
11031d102b48SJeremy L Thompson     The vector 'assembled' is of shape
11041d102b48SJeremy L Thompson       [num_elements, num_input_fields, num_output_fields, num_quad_points]
11051d102b48SJeremy L Thompson     and contains column-major matrices representing the action of the
11061d102b48SJeremy L Thompson     CeedQFunction for a corresponding quadrature point on an element. Inputs and
11071d102b48SJeremy L Thompson     outputs are in the order provided by the user when adding CeedOperator fields.
11084cc79fe7SJed Brown     For example, a CeedQFunction with inputs 'u' and 'gradu' and outputs 'gradv' and
11091d102b48SJeremy L Thompson     'v', provided in that order, would result in an assembled QFunction that
11101d102b48SJeremy L Thompson     consists of (1 + dim) x (dim + 1) matrices at each quadrature point acting
11111d102b48SJeremy L Thompson     on the input [u, du_0, du_1] and producing the output [dv_0, dv_1, v].
11121d102b48SJeremy L Thompson 
11131d102b48SJeremy L Thompson   @param op             CeedOperator to assemble CeedQFunction
11141d102b48SJeremy L Thompson   @param[out] assembled CeedVector to store assembled CeedQFunction at
11151d102b48SJeremy L Thompson                           quadrature points
11161d102b48SJeremy L Thompson   @param[out] rstr      CeedElemRestriction for CeedVector containing assembled
11171d102b48SJeremy L Thompson                           CeedQFunction
11181d102b48SJeremy L Thompson   @param request        Address of CeedRequest for non-blocking completion, else
11194cc79fe7SJed Brown                           @ref CEED_REQUEST_IMMEDIATE
11201d102b48SJeremy L Thompson 
11211d102b48SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
11221d102b48SJeremy L Thompson 
11237a982d89SJeremy L. Thompson   @ref User
11241d102b48SJeremy L Thompson **/
112580ac2e43SJeremy L Thompson int CeedOperatorLinearAssembleQFunction(CeedOperator op, CeedVector *assembled,
11267f823360Sjeremylt                                         CeedElemRestriction *rstr,
11277f823360Sjeremylt                                         CeedRequest *request) {
11281d102b48SJeremy L Thompson   int ierr;
1129e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
11301d102b48SJeremy L Thompson 
11317172caadSjeremylt   // Backend version
113280ac2e43SJeremy L Thompson   if (op->LinearAssembleQFunction) {
1133e2f04181SAndrew T. Barker     return op->LinearAssembleQFunction(op, assembled, rstr, request);
11345107b09fSJeremy L Thompson   } else {
11355107b09fSJeremy L Thompson     // Fallback to reference Ceed
11365107b09fSJeremy L Thompson     if (!op->opfallback) {
11375107b09fSJeremy L Thompson       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
11385107b09fSJeremy L Thompson     }
11395107b09fSJeremy L Thompson     // Assemble
1140e2f04181SAndrew T. Barker     return CeedOperatorLinearAssembleQFunction(op->opfallback, assembled,
1141e2f04181SAndrew T. Barker            rstr, request);
11425107b09fSJeremy L Thompson   }
11431d102b48SJeremy L Thompson }
11441d102b48SJeremy L Thompson 
11451d102b48SJeremy L Thompson /**
1146d965c7a7SJeremy L Thompson   @brief Assemble the diagonal of a square linear CeedOperator
1147b7ec98d8SJeremy L Thompson 
11489e9210b8SJeremy L Thompson   This overwrites a CeedVector with the diagonal of a linear CeedOperator.
1149b7ec98d8SJeremy L Thompson 
1150c04a41a7SJeremy L Thompson   Note: Currently only non-composite CeedOperators with a single field and
1151c04a41a7SJeremy L Thompson           composite CeedOperators with single field sub-operators are supported.
1152d965c7a7SJeremy L Thompson 
1153b7ec98d8SJeremy L Thompson   @param op             CeedOperator to assemble CeedQFunction
1154b7ec98d8SJeremy L Thompson   @param[out] assembled CeedVector to store assembled CeedOperator diagonal
1155b7ec98d8SJeremy L Thompson   @param request        Address of CeedRequest for non-blocking completion, else
11564cc79fe7SJed Brown                           @ref CEED_REQUEST_IMMEDIATE
1157b7ec98d8SJeremy L Thompson 
1158b7ec98d8SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1159b7ec98d8SJeremy L Thompson 
11607a982d89SJeremy L. Thompson   @ref User
1161b7ec98d8SJeremy L Thompson **/
11622bba3ffaSJeremy L Thompson int CeedOperatorLinearAssembleDiagonal(CeedOperator op, CeedVector assembled,
11637f823360Sjeremylt                                        CeedRequest *request) {
1164b7ec98d8SJeremy L Thompson   int ierr;
1165e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
1166b7ec98d8SJeremy L Thompson 
1167b7ec98d8SJeremy L Thompson   // Use backend version, if available
116880ac2e43SJeremy L Thompson   if (op->LinearAssembleDiagonal) {
1169e2f04181SAndrew T. Barker     return op->LinearAssembleDiagonal(op, assembled, request);
11709e9210b8SJeremy L Thompson   } else if (op->LinearAssembleAddDiagonal) {
11719e9210b8SJeremy L Thompson     ierr = CeedVectorSetValue(assembled, 0.0); CeedChk(ierr);
11729e9210b8SJeremy L Thompson     return CeedOperatorLinearAssembleAddDiagonal(op, assembled, request);
11739e9210b8SJeremy L Thompson   } else {
11749e9210b8SJeremy L Thompson     // Fallback to reference Ceed
11759e9210b8SJeremy L Thompson     if (!op->opfallback) {
11769e9210b8SJeremy L Thompson       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
11779e9210b8SJeremy L Thompson     }
11789e9210b8SJeremy L Thompson     // Assemble
1179e2f04181SAndrew T. Barker     return CeedOperatorLinearAssembleDiagonal(op->opfallback, assembled,
1180e2f04181SAndrew T. Barker            request);
11819e9210b8SJeremy L Thompson   }
11829e9210b8SJeremy L Thompson }
11839e9210b8SJeremy L Thompson 
11849e9210b8SJeremy L Thompson /**
11859e9210b8SJeremy L Thompson   @brief Assemble the diagonal of a square linear CeedOperator
11869e9210b8SJeremy L Thompson 
11879e9210b8SJeremy L Thompson   This sums into a CeedVector the diagonal of a linear CeedOperator.
11889e9210b8SJeremy L Thompson 
11899e9210b8SJeremy L Thompson   Note: Currently only non-composite CeedOperators with a single field and
11909e9210b8SJeremy L Thompson           composite CeedOperators with single field sub-operators are supported.
11919e9210b8SJeremy L Thompson 
11929e9210b8SJeremy L Thompson   @param op             CeedOperator to assemble CeedQFunction
11939e9210b8SJeremy L Thompson   @param[out] assembled CeedVector to store assembled CeedOperator diagonal
11949e9210b8SJeremy L Thompson   @param request        Address of CeedRequest for non-blocking completion, else
11959e9210b8SJeremy L Thompson                           @ref CEED_REQUEST_IMMEDIATE
11969e9210b8SJeremy L Thompson 
11979e9210b8SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
11989e9210b8SJeremy L Thompson 
11999e9210b8SJeremy L Thompson   @ref User
12009e9210b8SJeremy L Thompson **/
12019e9210b8SJeremy L Thompson int CeedOperatorLinearAssembleAddDiagonal(CeedOperator op, CeedVector assembled,
12029e9210b8SJeremy L Thompson     CeedRequest *request) {
12039e9210b8SJeremy L Thompson   int ierr;
1204e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
12059e9210b8SJeremy L Thompson 
12069e9210b8SJeremy L Thompson   // Use backend version, if available
12079e9210b8SJeremy L Thompson   if (op->LinearAssembleAddDiagonal) {
1208e2f04181SAndrew T. Barker     return op->LinearAssembleAddDiagonal(op, assembled, request);
12097172caadSjeremylt   } else {
12107172caadSjeremylt     // Fallback to reference Ceed
12117172caadSjeremylt     if (!op->opfallback) {
12127172caadSjeremylt       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
1213b7ec98d8SJeremy L Thompson     }
12147172caadSjeremylt     // Assemble
1215e2f04181SAndrew T. Barker     return CeedOperatorLinearAssembleAddDiagonal(op->opfallback, assembled,
1216e2f04181SAndrew T. Barker            request);
1217b7ec98d8SJeremy L Thompson   }
1218b7ec98d8SJeremy L Thompson }
1219b7ec98d8SJeremy L Thompson 
1220b7ec98d8SJeremy L Thompson /**
1221d965c7a7SJeremy L Thompson   @brief Assemble the point block diagonal of a square linear CeedOperator
1222d965c7a7SJeremy L Thompson 
12239e9210b8SJeremy L Thompson   This overwrites a CeedVector with the point block diagonal of a linear
1224d965c7a7SJeremy L Thompson     CeedOperator.
1225d965c7a7SJeremy L Thompson 
1226c04a41a7SJeremy L Thompson   Note: Currently only non-composite CeedOperators with a single field and
1227c04a41a7SJeremy L Thompson           composite CeedOperators with single field sub-operators are supported.
1228d965c7a7SJeremy L Thompson 
1229d965c7a7SJeremy L Thompson   @param op             CeedOperator to assemble CeedQFunction
1230d965c7a7SJeremy L Thompson   @param[out] assembled CeedVector to store assembled CeedOperator point block
1231d965c7a7SJeremy L Thompson                           diagonal, provided in row-major form with an
1232d965c7a7SJeremy L Thompson                           @a ncomp * @a ncomp block at each node. The dimensions
1233d965c7a7SJeremy L Thompson                           of this vector are derived from the active vector
1234d965c7a7SJeremy L Thompson                           for the CeedOperator. The array has shape
1235d965c7a7SJeremy L Thompson                           [nodes, component out, component in].
1236d965c7a7SJeremy L Thompson   @param request        Address of CeedRequest for non-blocking completion, else
1237d965c7a7SJeremy L Thompson                           CEED_REQUEST_IMMEDIATE
1238d965c7a7SJeremy L Thompson 
1239d965c7a7SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1240d965c7a7SJeremy L Thompson 
1241d965c7a7SJeremy L Thompson   @ref User
1242d965c7a7SJeremy L Thompson **/
124380ac2e43SJeremy L Thompson int CeedOperatorLinearAssemblePointBlockDiagonal(CeedOperator op,
12442bba3ffaSJeremy L Thompson     CeedVector assembled, CeedRequest *request) {
1245d965c7a7SJeremy L Thompson   int ierr;
1246e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
1247d965c7a7SJeremy L Thompson 
1248d965c7a7SJeremy L Thompson   // Use backend version, if available
124980ac2e43SJeremy L Thompson   if (op->LinearAssemblePointBlockDiagonal) {
1250e2f04181SAndrew T. Barker     return op->LinearAssemblePointBlockDiagonal(op, assembled, request);
12519e9210b8SJeremy L Thompson   } else if (op->LinearAssembleAddPointBlockDiagonal) {
12529e9210b8SJeremy L Thompson     ierr = CeedVectorSetValue(assembled, 0.0); CeedChk(ierr);
12539e9210b8SJeremy L Thompson     return CeedOperatorLinearAssembleAddPointBlockDiagonal(op, assembled,
12549e9210b8SJeremy L Thompson            request);
1255d965c7a7SJeremy L Thompson   } else {
1256d965c7a7SJeremy L Thompson     // Fallback to reference Ceed
1257d965c7a7SJeremy L Thompson     if (!op->opfallback) {
1258d965c7a7SJeremy L Thompson       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
1259d965c7a7SJeremy L Thompson     }
1260d965c7a7SJeremy L Thompson     // Assemble
1261e2f04181SAndrew T. Barker     return CeedOperatorLinearAssemblePointBlockDiagonal(op->opfallback,
1262e2f04181SAndrew T. Barker            assembled, request);
12639e9210b8SJeremy L Thompson   }
12649e9210b8SJeremy L Thompson }
12659e9210b8SJeremy L Thompson 
12669e9210b8SJeremy L Thompson /**
12679e9210b8SJeremy L Thompson   @brief Assemble the point block diagonal of a square linear CeedOperator
12689e9210b8SJeremy L Thompson 
12699e9210b8SJeremy L Thompson   This sums into a CeedVector with the point block diagonal of a linear
12709e9210b8SJeremy L Thompson     CeedOperator.
12719e9210b8SJeremy L Thompson 
12729e9210b8SJeremy L Thompson   Note: Currently only non-composite CeedOperators with a single field and
12739e9210b8SJeremy L Thompson           composite CeedOperators with single field sub-operators are supported.
12749e9210b8SJeremy L Thompson 
12759e9210b8SJeremy L Thompson   @param op             CeedOperator to assemble CeedQFunction
12769e9210b8SJeremy L Thompson   @param[out] assembled CeedVector to store assembled CeedOperator point block
12779e9210b8SJeremy L Thompson                           diagonal, provided in row-major form with an
12789e9210b8SJeremy L Thompson                           @a ncomp * @a ncomp block at each node. The dimensions
12799e9210b8SJeremy L Thompson                           of this vector are derived from the active vector
12809e9210b8SJeremy L Thompson                           for the CeedOperator. The array has shape
12819e9210b8SJeremy L Thompson                           [nodes, component out, component in].
12829e9210b8SJeremy L Thompson   @param request        Address of CeedRequest for non-blocking completion, else
12839e9210b8SJeremy L Thompson                           CEED_REQUEST_IMMEDIATE
12849e9210b8SJeremy L Thompson 
12859e9210b8SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
12869e9210b8SJeremy L Thompson 
12879e9210b8SJeremy L Thompson   @ref User
12889e9210b8SJeremy L Thompson **/
12899e9210b8SJeremy L Thompson int CeedOperatorLinearAssembleAddPointBlockDiagonal(CeedOperator op,
12909e9210b8SJeremy L Thompson     CeedVector assembled, CeedRequest *request) {
12919e9210b8SJeremy L Thompson   int ierr;
1292e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
12939e9210b8SJeremy L Thompson 
12949e9210b8SJeremy L Thompson   // Use backend version, if available
12959e9210b8SJeremy L Thompson   if (op->LinearAssembleAddPointBlockDiagonal) {
1296e2f04181SAndrew T. Barker     return op->LinearAssembleAddPointBlockDiagonal(op, assembled, request);
12979e9210b8SJeremy L Thompson   } else {
12989e9210b8SJeremy L Thompson     // Fallback to reference Ceed
12999e9210b8SJeremy L Thompson     if (!op->opfallback) {
13009e9210b8SJeremy L Thompson       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
13019e9210b8SJeremy L Thompson     }
13029e9210b8SJeremy L Thompson     // Assemble
1303e2f04181SAndrew T. Barker     return CeedOperatorLinearAssembleAddPointBlockDiagonal(op->opfallback,
1304e2f04181SAndrew T. Barker            assembled, request);
1305d965c7a7SJeremy L Thompson   }
1306e2f04181SAndrew T. Barker }
1307e2f04181SAndrew T. Barker 
1308e2f04181SAndrew T. Barker /**
1309e2f04181SAndrew T. Barker    @brief Build nonzero pattern for non-composite operator.
1310e2f04181SAndrew T. Barker 
1311e2f04181SAndrew T. Barker    Users should generally use CeedOperatorLinearAssembleSymbolic()
1312e2f04181SAndrew T. Barker 
1313e2f04181SAndrew T. Barker    @ref Developer
1314e2f04181SAndrew T. Barker **/
1315e2f04181SAndrew T. Barker int CeedSingleOperatorAssembleSymbolic(CeedOperator op, CeedInt offset,
1316e2f04181SAndrew T. Barker                                        CeedInt *rows, CeedInt *cols) {
1317e2f04181SAndrew T. Barker   int ierr;
1318e2f04181SAndrew T. Barker   Ceed ceed = op->ceed;
1319e2f04181SAndrew T. Barker   if (op->composite)
1320e2f04181SAndrew T. Barker     // LCOV_EXCL_START
1321e2f04181SAndrew T. Barker     return CeedError(ceed, CEED_ERROR_UNSUPPORTED,
1322e2f04181SAndrew T. Barker                      "Composite operator not supported");
1323e2f04181SAndrew T. Barker   // LCOV_EXCL_STOP
1324e2f04181SAndrew T. Barker 
1325e2f04181SAndrew T. Barker   CeedElemRestriction rstrin;
1326e2f04181SAndrew T. Barker   ierr = CeedOperatorGetActiveElemRestriction(op, &rstrin); CeedChk(ierr);
1327e2f04181SAndrew T. Barker   CeedInt nelem, elemsize, nnodes, ncomp;
1328e2f04181SAndrew T. Barker   ierr = CeedElemRestrictionGetNumElements(rstrin, &nelem); CeedChk(ierr);
1329e2f04181SAndrew T. Barker   ierr = CeedElemRestrictionGetElementSize(rstrin, &elemsize); CeedChk(ierr);
1330e2f04181SAndrew T. Barker   ierr = CeedElemRestrictionGetLVectorSize(rstrin, &nnodes); CeedChk(ierr);
1331e2f04181SAndrew T. Barker   ierr = CeedElemRestrictionGetNumComponents(rstrin, &ncomp); CeedChk(ierr);
1332e2f04181SAndrew T. Barker   CeedInt layout_er[3];
1333e2f04181SAndrew T. Barker   ierr = CeedElemRestrictionGetELayout(rstrin, &layout_er); CeedChk(ierr);
1334e2f04181SAndrew T. Barker 
1335e2f04181SAndrew T. Barker   CeedInt local_nentries = elemsize*ncomp * elemsize*ncomp * nelem;
1336e2f04181SAndrew T. Barker 
1337e2f04181SAndrew T. Barker   // Determine elem_dof relation
1338e2f04181SAndrew T. Barker   CeedVector index_vec;
1339e2f04181SAndrew T. Barker   ierr = CeedVectorCreate(ceed, nnodes, &index_vec); CeedChk(ierr);
1340e2f04181SAndrew T. Barker   CeedScalar *array;
1341e2f04181SAndrew T. Barker   ierr = CeedVectorGetArray(index_vec, CEED_MEM_HOST, &array); CeedChk(ierr);
1342e2f04181SAndrew T. Barker   for (CeedInt i = 0; i < nnodes; ++i) {
1343e2f04181SAndrew T. Barker     array[i] = i;
1344e2f04181SAndrew T. Barker   }
1345e2f04181SAndrew T. Barker   ierr = CeedVectorRestoreArray(index_vec, &array); CeedChk(ierr);
1346e2f04181SAndrew T. Barker   CeedVector elem_dof;
1347e2f04181SAndrew T. Barker   ierr = CeedVectorCreate(ceed, nelem * elemsize * ncomp, &elem_dof);
1348e2f04181SAndrew T. Barker   CeedChk(ierr);
1349e2f04181SAndrew T. Barker   ierr = CeedVectorSetValue(elem_dof, 0.0); CeedChk(ierr);
1350e2f04181SAndrew T. Barker   CeedElemRestrictionApply(rstrin, CEED_NOTRANSPOSE, index_vec,
1351e2f04181SAndrew T. Barker                            elem_dof, CEED_REQUEST_IMMEDIATE); CeedChk(ierr);
1352e2f04181SAndrew T. Barker   const CeedScalar *elem_dof_a;
1353e2f04181SAndrew T. Barker   ierr = CeedVectorGetArrayRead(elem_dof, CEED_MEM_HOST, &elem_dof_a);
1354e2f04181SAndrew T. Barker   CeedChk(ierr);
1355e2f04181SAndrew T. Barker   ierr = CeedVectorDestroy(&index_vec); CeedChk(ierr);
1356e2f04181SAndrew T. Barker 
1357e2f04181SAndrew T. Barker   // Determine i, j locations for element matrices
1358e2f04181SAndrew T. Barker   CeedInt count = 0;
1359e2f04181SAndrew T. Barker   for (int e = 0; e < nelem; ++e) {
1360e2f04181SAndrew T. Barker     for (int compin = 0; compin < ncomp; ++compin) {
1361e2f04181SAndrew T. Barker       for (int compout = 0; compout < ncomp; ++compout) {
1362e2f04181SAndrew T. Barker         for (int i = 0; i < elemsize; ++i) {
1363e2f04181SAndrew T. Barker           for (int j = 0; j < elemsize; ++j) {
1364e2f04181SAndrew T. Barker             const CeedInt edof_index_row = (i)*layout_er[0] +
1365e2f04181SAndrew T. Barker                                            (compout)*layout_er[1] + e*layout_er[2];
1366e2f04181SAndrew T. Barker             const CeedInt edof_index_col = (j)*layout_er[0] +
1367e2f04181SAndrew T. Barker                                            (compin)*layout_er[1] + e*layout_er[2];
1368e2f04181SAndrew T. Barker 
1369e2f04181SAndrew T. Barker             const CeedInt row = elem_dof_a[edof_index_row];
1370e2f04181SAndrew T. Barker             const CeedInt col = elem_dof_a[edof_index_col];
1371e2f04181SAndrew T. Barker 
1372e2f04181SAndrew T. Barker             rows[offset + count] = row;
1373e2f04181SAndrew T. Barker             cols[offset + count] = col;
1374e2f04181SAndrew T. Barker             count++;
1375e2f04181SAndrew T. Barker           }
1376e2f04181SAndrew T. Barker         }
1377e2f04181SAndrew T. Barker       }
1378e2f04181SAndrew T. Barker     }
1379e2f04181SAndrew T. Barker   }
1380e2f04181SAndrew T. Barker   if (count != local_nentries)
1381e2f04181SAndrew T. Barker     // LCOV_EXCL_START
1382e2f04181SAndrew T. Barker     return CeedError(ceed, CEED_ERROR_MAJOR, "Error computing assembled entries");
1383e2f04181SAndrew T. Barker   // LCOV_EXCL_STOP
1384e2f04181SAndrew T. Barker   ierr = CeedVectorRestoreArrayRead(elem_dof, &elem_dof_a); CeedChk(ierr);
1385e2f04181SAndrew T. Barker   ierr = CeedVectorDestroy(&elem_dof); CeedChk(ierr);
1386e2f04181SAndrew T. Barker 
1387e2f04181SAndrew T. Barker   return CEED_ERROR_SUCCESS;
1388e2f04181SAndrew T. Barker }
1389e2f04181SAndrew T. Barker 
1390e2f04181SAndrew T. Barker /**
1391e2f04181SAndrew T. Barker    @brief Assemble nonzero entries for non-composite operator
1392e2f04181SAndrew T. Barker 
1393e2f04181SAndrew T. Barker    Users should generally use CeedOperatorLinearAssemble()
1394e2f04181SAndrew T. Barker 
1395e2f04181SAndrew T. Barker    @ref Developer
1396e2f04181SAndrew T. Barker **/
1397e2f04181SAndrew T. Barker int CeedSingleOperatorAssemble(CeedOperator op, CeedInt offset,
1398e2f04181SAndrew T. Barker                                CeedVector values) {
1399e2f04181SAndrew T. Barker   int ierr;
1400e2f04181SAndrew T. Barker   Ceed ceed = op->ceed;;
1401e2f04181SAndrew T. Barker   if (op->composite)
1402e2f04181SAndrew T. Barker     // LCOV_EXCL_START
1403e2f04181SAndrew T. Barker     return CeedError(ceed, CEED_ERROR_UNSUPPORTED,
1404e2f04181SAndrew T. Barker                      "Composite operator not supported");
1405e2f04181SAndrew T. Barker   // LCOV_EXCL_STOP
1406e2f04181SAndrew T. Barker 
1407e2f04181SAndrew T. Barker   // Assemble QFunction
1408e2f04181SAndrew T. Barker   CeedQFunction qf;
1409e2f04181SAndrew T. Barker   ierr = CeedOperatorGetQFunction(op, &qf); CeedChk(ierr);
1410e2f04181SAndrew T. Barker   CeedInt numinputfields, numoutputfields;
1411e2f04181SAndrew T. Barker   ierr= CeedQFunctionGetNumArgs(qf, &numinputfields, &numoutputfields);
1412e2f04181SAndrew T. Barker   CeedChk(ierr);
1413e2f04181SAndrew T. Barker   CeedVector assembledqf;
1414e2f04181SAndrew T. Barker   CeedElemRestriction rstr_q;
1415e2f04181SAndrew T. Barker   ierr = CeedOperatorLinearAssembleQFunction(
1416e2f04181SAndrew T. Barker            op, &assembledqf, &rstr_q, CEED_REQUEST_IMMEDIATE); CeedChk(ierr);
1417e2f04181SAndrew T. Barker 
1418e2f04181SAndrew T. Barker   CeedInt qflength;
1419e2f04181SAndrew T. Barker   ierr = CeedVectorGetLength(assembledqf, &qflength); CeedChk(ierr);
1420e2f04181SAndrew T. Barker 
1421e2f04181SAndrew T. Barker   CeedOperatorField *input_fields;
1422e2f04181SAndrew T. Barker   CeedOperatorField *output_fields;
1423e2f04181SAndrew T. Barker   ierr = CeedOperatorGetFields(op, &input_fields, &output_fields); CeedChk(ierr);
1424e2f04181SAndrew T. Barker 
1425e2f04181SAndrew T. Barker   // Determine active input basis
1426e2f04181SAndrew T. Barker   CeedQFunctionField *qffields;
1427e2f04181SAndrew T. Barker   ierr = CeedQFunctionGetFields(qf, &qffields, NULL); CeedChk(ierr);
1428e2f04181SAndrew T. Barker   CeedInt numemodein = 0, dim = 1;
1429e2f04181SAndrew T. Barker   CeedEvalMode *emodein = NULL;
1430e2f04181SAndrew T. Barker   CeedBasis basisin = NULL;
1431e2f04181SAndrew T. Barker   CeedElemRestriction rstrin = NULL;
1432e2f04181SAndrew T. Barker   for (CeedInt i=0; i<numinputfields; i++) {
1433e2f04181SAndrew T. Barker     CeedVector vec;
1434e2f04181SAndrew T. Barker     ierr = CeedOperatorFieldGetVector(input_fields[i], &vec); CeedChk(ierr);
1435e2f04181SAndrew T. Barker     if (vec == CEED_VECTOR_ACTIVE) {
1436e2f04181SAndrew T. Barker       ierr = CeedOperatorFieldGetBasis(input_fields[i], &basisin);
1437e2f04181SAndrew T. Barker       CeedChk(ierr);
1438e2f04181SAndrew T. Barker       ierr = CeedBasisGetDimension(basisin, &dim); CeedChk(ierr);
1439e2f04181SAndrew T. Barker       ierr = CeedOperatorFieldGetElemRestriction(input_fields[i], &rstrin);
1440e2f04181SAndrew T. Barker       CeedChk(ierr);
1441e2f04181SAndrew T. Barker       CeedEvalMode emode;
1442e2f04181SAndrew T. Barker       ierr = CeedQFunctionFieldGetEvalMode(qffields[i], &emode);
1443e2f04181SAndrew T. Barker       CeedChk(ierr);
1444e2f04181SAndrew T. Barker       switch (emode) {
1445e2f04181SAndrew T. Barker       case CEED_EVAL_NONE:
1446e2f04181SAndrew T. Barker       case CEED_EVAL_INTERP:
1447e2f04181SAndrew T. Barker         ierr = CeedRealloc(numemodein + 1, &emodein); CeedChk(ierr);
1448e2f04181SAndrew T. Barker         emodein[numemodein] = emode;
1449e2f04181SAndrew T. Barker         numemodein += 1;
1450e2f04181SAndrew T. Barker         break;
1451e2f04181SAndrew T. Barker       case CEED_EVAL_GRAD:
1452e2f04181SAndrew T. Barker         ierr = CeedRealloc(numemodein + dim, &emodein); CeedChk(ierr);
1453e2f04181SAndrew T. Barker         for (CeedInt d=0; d<dim; d++) {
1454e2f04181SAndrew T. Barker           emodein[numemodein+d] = emode;
1455e2f04181SAndrew T. Barker         }
1456e2f04181SAndrew T. Barker         numemodein += dim;
1457e2f04181SAndrew T. Barker         break;
1458e2f04181SAndrew T. Barker       case CEED_EVAL_WEIGHT:
1459e2f04181SAndrew T. Barker       case CEED_EVAL_DIV:
1460e2f04181SAndrew T. Barker       case CEED_EVAL_CURL:
1461e2f04181SAndrew T. Barker         break; // Caught by QF Assembly
1462e2f04181SAndrew T. Barker       }
1463e2f04181SAndrew T. Barker     }
1464e2f04181SAndrew T. Barker   }
1465e2f04181SAndrew T. Barker 
1466e2f04181SAndrew T. Barker   // Determine active output basis
1467e2f04181SAndrew T. Barker   ierr = CeedQFunctionGetFields(qf, NULL, &qffields); CeedChk(ierr);
1468e2f04181SAndrew T. Barker   CeedInt numemodeout = 0;
1469e2f04181SAndrew T. Barker   CeedEvalMode *emodeout = NULL;
1470e2f04181SAndrew T. Barker   CeedBasis basisout = NULL;
1471e2f04181SAndrew T. Barker   CeedElemRestriction rstrout = NULL;
1472e2f04181SAndrew T. Barker   for (CeedInt i=0; i<numoutputfields; i++) {
1473e2f04181SAndrew T. Barker     CeedVector vec;
1474e2f04181SAndrew T. Barker     ierr = CeedOperatorFieldGetVector(output_fields[i], &vec); CeedChk(ierr);
1475e2f04181SAndrew T. Barker     if (vec == CEED_VECTOR_ACTIVE) {
1476e2f04181SAndrew T. Barker       ierr = CeedOperatorFieldGetBasis(output_fields[i], &basisout);
1477e2f04181SAndrew T. Barker       CeedChk(ierr);
1478e2f04181SAndrew T. Barker       ierr = CeedOperatorFieldGetElemRestriction(output_fields[i], &rstrout);
1479e2f04181SAndrew T. Barker       CeedChk(ierr);
1480e2f04181SAndrew T. Barker       CeedEvalMode emode;
1481e2f04181SAndrew T. Barker       ierr = CeedQFunctionFieldGetEvalMode(qffields[i], &emode);
1482e2f04181SAndrew T. Barker       CeedChk(ierr);
1483e2f04181SAndrew T. Barker       switch (emode) {
1484e2f04181SAndrew T. Barker       case CEED_EVAL_NONE:
1485e2f04181SAndrew T. Barker       case CEED_EVAL_INTERP:
1486e2f04181SAndrew T. Barker         ierr = CeedRealloc(numemodeout + 1, &emodeout); CeedChk(ierr);
1487e2f04181SAndrew T. Barker         emodeout[numemodeout] = emode;
1488e2f04181SAndrew T. Barker         numemodeout += 1;
1489e2f04181SAndrew T. Barker         break;
1490e2f04181SAndrew T. Barker       case CEED_EVAL_GRAD:
1491e2f04181SAndrew T. Barker         ierr = CeedRealloc(numemodeout + dim, &emodeout); CeedChk(ierr);
1492e2f04181SAndrew T. Barker         for (CeedInt d=0; d<dim; d++) {
1493e2f04181SAndrew T. Barker           emodeout[numemodeout+d] = emode;
1494e2f04181SAndrew T. Barker         }
1495e2f04181SAndrew T. Barker         numemodeout += dim;
1496e2f04181SAndrew T. Barker         break;
1497e2f04181SAndrew T. Barker       case CEED_EVAL_WEIGHT:
1498e2f04181SAndrew T. Barker       case CEED_EVAL_DIV:
1499e2f04181SAndrew T. Barker       case CEED_EVAL_CURL:
1500e2f04181SAndrew T. Barker         break; // Caught by QF Assembly
1501e2f04181SAndrew T. Barker       }
1502e2f04181SAndrew T. Barker     }
1503e2f04181SAndrew T. Barker   }
1504e2f04181SAndrew T. Barker 
1505e2f04181SAndrew T. Barker   CeedInt nelem, elemsize, nqpts, ncomp;
1506e2f04181SAndrew T. Barker   ierr = CeedElemRestrictionGetNumElements(rstrin, &nelem); CeedChk(ierr);
1507e2f04181SAndrew T. Barker   ierr = CeedElemRestrictionGetElementSize(rstrin, &elemsize); CeedChk(ierr);
1508e2f04181SAndrew T. Barker   ierr = CeedElemRestrictionGetNumComponents(rstrin, &ncomp); CeedChk(ierr);
1509e2f04181SAndrew T. Barker   ierr = CeedBasisGetNumQuadraturePoints(basisin, &nqpts); CeedChk(ierr);
1510e2f04181SAndrew T. Barker 
1511e2f04181SAndrew T. Barker   CeedInt local_nentries = elemsize*ncomp * elemsize*ncomp * nelem;
1512e2f04181SAndrew T. Barker 
1513e2f04181SAndrew T. Barker   // loop over elements and put in data structure
1514e2f04181SAndrew T. Barker   const CeedScalar *interpin, *gradin;
1515e2f04181SAndrew T. Barker   ierr = CeedBasisGetInterp(basisin, &interpin); CeedChk(ierr);
1516e2f04181SAndrew T. Barker   ierr = CeedBasisGetGrad(basisin, &gradin); CeedChk(ierr);
1517e2f04181SAndrew T. Barker 
1518e2f04181SAndrew T. Barker   const CeedScalar *assembledqfarray;
1519e2f04181SAndrew T. Barker   ierr = CeedVectorGetArrayRead(assembledqf, CEED_MEM_HOST, &assembledqfarray);
1520e2f04181SAndrew T. Barker   CeedChk(ierr);
1521e2f04181SAndrew T. Barker 
1522e2f04181SAndrew T. Barker   CeedInt layout_qf[3];
1523e2f04181SAndrew T. Barker   ierr = CeedElemRestrictionGetELayout(rstr_q, &layout_qf); CeedChk(ierr);
1524e2f04181SAndrew T. Barker   ierr = CeedElemRestrictionDestroy(&rstr_q); CeedChk(ierr);
1525e2f04181SAndrew T. Barker 
1526e2f04181SAndrew T. Barker   // we store Bmat_in, Bmat_out, BTD, elem_mat in row-major order
1527e2f04181SAndrew T. Barker   CeedScalar Bmat_in[(nqpts * numemodein) * elemsize];
1528e2f04181SAndrew T. Barker   CeedScalar Bmat_out[(nqpts * numemodeout) * elemsize];
1529e2f04181SAndrew T. Barker   CeedScalar Dmat[numemodeout * numemodein * nqpts]; // logically 3-tensor
1530e2f04181SAndrew T. Barker   CeedScalar BTD[elemsize * nqpts*numemodein];
1531e2f04181SAndrew T. Barker   CeedScalar elem_mat[elemsize * elemsize];
1532e2f04181SAndrew T. Barker   int count = 0;
1533e2f04181SAndrew T. Barker   CeedScalar *vals;
1534e2f04181SAndrew T. Barker   ierr = CeedVectorGetArray(values, CEED_MEM_HOST, &vals); CeedChk(ierr);
1535e2f04181SAndrew T. Barker   for (int e = 0; e < nelem; ++e) {
1536e2f04181SAndrew T. Barker     for (int compin = 0; compin < ncomp; ++compin) {
1537e2f04181SAndrew T. Barker       for (int compout = 0; compout < ncomp; ++compout) {
1538e2f04181SAndrew T. Barker         for (int ell = 0; ell < (nqpts * numemodein) * elemsize; ++ell) {
1539e2f04181SAndrew T. Barker           Bmat_in[ell] = 0.0;
1540e2f04181SAndrew T. Barker         }
1541e2f04181SAndrew T. Barker         for (int ell = 0; ell < (nqpts * numemodeout) * elemsize; ++ell) {
1542e2f04181SAndrew T. Barker           Bmat_out[ell] = 0.0;
1543e2f04181SAndrew T. Barker         }
1544e2f04181SAndrew T. Barker         // Store block-diagonal D matrix as collection of small dense blocks
1545e2f04181SAndrew T. Barker         for (int ell = 0; ell < numemodein*numemodeout*nqpts; ++ell) {
1546e2f04181SAndrew T. Barker           Dmat[ell] = 0.0;
1547e2f04181SAndrew T. Barker         }
1548e2f04181SAndrew T. Barker         // form element matrix itself (for each block component)
1549e2f04181SAndrew T. Barker         for (int ell = 0; ell < elemsize*elemsize; ++ell) {
1550e2f04181SAndrew T. Barker           elem_mat[ell] = 0.0;
1551e2f04181SAndrew T. Barker         }
1552e2f04181SAndrew T. Barker         for (int q = 0; q < nqpts; ++q) {
1553e2f04181SAndrew T. Barker           for (int n = 0; n < elemsize; ++n) {
1554e2f04181SAndrew T. Barker             CeedInt din = -1;
1555e2f04181SAndrew T. Barker             for (int ein = 0; ein < numemodein; ++ein) {
1556e2f04181SAndrew T. Barker               const int qq = numemodein*q;
1557e2f04181SAndrew T. Barker               if (emodein[ein] == CEED_EVAL_INTERP) {
1558e2f04181SAndrew T. Barker                 Bmat_in[(qq+ein)*elemsize + n] += interpin[q * elemsize + n];
1559e2f04181SAndrew T. Barker               } else if (emodein[ein] == CEED_EVAL_GRAD) {
1560e2f04181SAndrew T. Barker                 din += 1;
1561e2f04181SAndrew T. Barker                 Bmat_in[(qq+ein)*elemsize + n] +=
1562e2f04181SAndrew T. Barker                   gradin[(din*nqpts+q) * elemsize + n];
1563e2f04181SAndrew T. Barker               } else {
1564e2f04181SAndrew T. Barker                 // LCOV_EXCL_START
1565e2f04181SAndrew T. Barker                 return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Not implemented!");
1566e2f04181SAndrew T. Barker                 // LCOV_EXCL_STOP
1567e2f04181SAndrew T. Barker               }
1568e2f04181SAndrew T. Barker             }
1569e2f04181SAndrew T. Barker             CeedInt dout = -1;
1570e2f04181SAndrew T. Barker             for (int eout = 0; eout < numemodeout; ++eout) {
1571e2f04181SAndrew T. Barker               const int qq = numemodeout*q;
1572e2f04181SAndrew T. Barker               if (emodeout[eout] == CEED_EVAL_INTERP) {
1573e2f04181SAndrew T. Barker                 Bmat_out[(qq+eout)*elemsize + n] += interpin[q * elemsize + n];
1574e2f04181SAndrew T. Barker               } else if (emodeout[eout] == CEED_EVAL_GRAD) {
1575e2f04181SAndrew T. Barker                 dout += 1;
1576e2f04181SAndrew T. Barker                 Bmat_out[(qq+eout)*elemsize + n] +=
1577e2f04181SAndrew T. Barker                   gradin[(dout*nqpts+q) * elemsize + n];
1578e2f04181SAndrew T. Barker               } else {
1579e2f04181SAndrew T. Barker                 // LCOV_EXCL_START
1580e2f04181SAndrew T. Barker                 return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Not implemented!");
1581e2f04181SAndrew T. Barker                 // LCOV_EXCL_STOP
1582e2f04181SAndrew T. Barker               }
1583e2f04181SAndrew T. Barker             }
1584e2f04181SAndrew T. Barker           }
1585e2f04181SAndrew T. Barker           for (int ei = 0; ei < numemodeout; ++ei) {
1586e2f04181SAndrew T. Barker             for (int ej = 0; ej < numemodein; ++ej) {
1587e2f04181SAndrew T. Barker               const int emode_index = ((ei*ncomp+compin)*numemodein+ej)*ncomp+compout;
1588e2f04181SAndrew T. Barker               const int index = q*layout_qf[0] + emode_index*layout_qf[1] + e*layout_qf[2];
1589e2f04181SAndrew T. Barker               Dmat[(ei*numemodein+ej)*nqpts + q] += assembledqfarray[index];
1590e2f04181SAndrew T. Barker             }
1591e2f04181SAndrew T. Barker           }
1592e2f04181SAndrew T. Barker         }
1593e2f04181SAndrew T. Barker         // Compute B^T*D
1594e2f04181SAndrew T. Barker         for (int ell = 0; ell < elemsize*nqpts*numemodein; ++ell) {
1595e2f04181SAndrew T. Barker           BTD[ell] = 0.0;
1596e2f04181SAndrew T. Barker         }
1597e2f04181SAndrew T. Barker         for (int j = 0; j<elemsize; ++j) {
1598e2f04181SAndrew T. Barker           for (int q = 0; q<nqpts; ++q) {
1599e2f04181SAndrew T. Barker             int qq = numemodeout*q;
1600e2f04181SAndrew T. Barker             for (int ei = 0; ei < numemodein; ++ei) {
1601e2f04181SAndrew T. Barker               for (int ej = 0; ej < numemodeout; ++ej) {
1602e2f04181SAndrew T. Barker                 BTD[j*(nqpts*numemodein) + (qq+ei)] +=
1603e2f04181SAndrew T. Barker                   Bmat_out[(qq+ej)*elemsize + j] * Dmat[(ei*numemodein+ej)*nqpts + q];
1604e2f04181SAndrew T. Barker               }
1605e2f04181SAndrew T. Barker             }
1606e2f04181SAndrew T. Barker           }
1607e2f04181SAndrew T. Barker         }
1608e2f04181SAndrew T. Barker 
1609e2f04181SAndrew T. Barker         ierr = CeedMatrixMultiply(ceed, BTD, Bmat_in, elem_mat, elemsize,
1610e2f04181SAndrew T. Barker                                   elemsize, nqpts*numemodein); CeedChk(ierr);
1611e2f04181SAndrew T. Barker 
1612e2f04181SAndrew T. Barker         // put element matrix in coordinate data structure
1613e2f04181SAndrew T. Barker         for (int i = 0; i < elemsize; ++i) {
1614e2f04181SAndrew T. Barker           for (int j = 0; j < elemsize; ++j) {
1615e2f04181SAndrew T. Barker             vals[offset + count] = elem_mat[i*elemsize + j];
1616e2f04181SAndrew T. Barker             count++;
1617e2f04181SAndrew T. Barker           }
1618e2f04181SAndrew T. Barker         }
1619e2f04181SAndrew T. Barker       }
1620e2f04181SAndrew T. Barker     }
1621e2f04181SAndrew T. Barker   }
1622e2f04181SAndrew T. Barker   if (count != local_nentries)
1623e2f04181SAndrew T. Barker     // LCOV_EXCL_START
1624e2f04181SAndrew T. Barker     return CeedError(ceed, CEED_ERROR_MAJOR, "Error computing entries");
1625e2f04181SAndrew T. Barker   // LCOV_EXCL_STOP
1626e2f04181SAndrew T. Barker   ierr = CeedVectorRestoreArray(values, &vals); CeedChk(ierr);
1627e2f04181SAndrew T. Barker 
1628e2f04181SAndrew T. Barker   ierr = CeedVectorRestoreArrayRead(assembledqf, &assembledqfarray);
1629e2f04181SAndrew T. Barker   CeedChk(ierr);
1630e2f04181SAndrew T. Barker   ierr = CeedVectorDestroy(&assembledqf); CeedChk(ierr);
1631e2f04181SAndrew T. Barker   ierr = CeedFree(&emodein); CeedChk(ierr);
1632e2f04181SAndrew T. Barker   ierr = CeedFree(&emodeout); CeedChk(ierr);
1633e2f04181SAndrew T. Barker 
1634e2f04181SAndrew T. Barker   return CEED_ERROR_SUCCESS;
1635e2f04181SAndrew T. Barker }
1636e2f04181SAndrew T. Barker 
1637e2f04181SAndrew T. Barker /**
1638e2f04181SAndrew T. Barker    @ref Utility
1639e2f04181SAndrew T. Barker **/
1640e2f04181SAndrew T. Barker int CeedSingleOperatorAssemblyCountEntries(CeedOperator op, CeedInt *nentries) {
1641e2f04181SAndrew T. Barker   int ierr;
1642e2f04181SAndrew T. Barker   CeedElemRestriction rstr;
1643e2f04181SAndrew T. Barker   CeedInt nelem, elemsize, ncomp;
1644e2f04181SAndrew T. Barker 
1645e2f04181SAndrew T. Barker   if (op->composite)
1646e2f04181SAndrew T. Barker     // LCOV_EXCL_START
1647e2f04181SAndrew T. Barker     return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED,
1648e2f04181SAndrew T. Barker                      "Composite operator not supported");
1649e2f04181SAndrew T. Barker   // LCOV_EXCL_STOP
1650e2f04181SAndrew T. Barker   ierr = CeedOperatorGetActiveElemRestriction(op, &rstr); CeedChk(ierr);
1651e2f04181SAndrew T. Barker   ierr = CeedElemRestrictionGetNumElements(rstr, &nelem); CeedChk(ierr);
1652e2f04181SAndrew T. Barker   ierr = CeedElemRestrictionGetElementSize(rstr, &elemsize); CeedChk(ierr);
1653e2f04181SAndrew T. Barker   ierr = CeedElemRestrictionGetNumComponents(rstr, &ncomp); CeedChk(ierr);
1654e2f04181SAndrew T. Barker   *nentries = elemsize*ncomp * elemsize*ncomp * nelem;
1655e2f04181SAndrew T. Barker 
1656e2f04181SAndrew T. Barker   return CEED_ERROR_SUCCESS;
1657e2f04181SAndrew T. Barker }
1658e2f04181SAndrew T. Barker 
1659e2f04181SAndrew T. Barker /**
1660e2f04181SAndrew T. Barker    @brief Fully assemble the nonzero pattern of a linear operator.
1661e2f04181SAndrew T. Barker 
1662e2f04181SAndrew T. Barker    Expected to be used in conjunction with CeedOperatorLinearAssemble()
1663e2f04181SAndrew T. Barker 
1664e2f04181SAndrew T. Barker    The assembly routines use coordinate format, with nentries tuples of the
1665e2f04181SAndrew T. Barker    form (i, j, value) which indicate that value should be added to the matrix
1666e2f04181SAndrew T. Barker    in entry (i, j). Note that the (i, j) pairs are not unique and may repeat.
1667e2f04181SAndrew T. Barker    This function returns the number of entries and their (i, j) locations,
1668e2f04181SAndrew T. Barker    while CeedOperatorLinearAssemble() provides the values in the same
1669e2f04181SAndrew T. Barker    ordering.
1670e2f04181SAndrew T. Barker 
1671e2f04181SAndrew T. Barker    This will generally be slow unless your operator is low-order.
1672e2f04181SAndrew T. Barker 
1673e2f04181SAndrew T. Barker    @param[in]  op       CeedOperator to assemble
1674e2f04181SAndrew T. Barker    @param[out] nentries Number of entries in coordinate nonzero pattern.
1675e2f04181SAndrew T. Barker    @param[out] rows     Row number for each entry.
1676e2f04181SAndrew T. Barker    @param[out] cols     Column number for each entry.
1677e2f04181SAndrew T. Barker 
1678e2f04181SAndrew T. Barker    @ref User
1679e2f04181SAndrew T. Barker **/
1680e2f04181SAndrew T. Barker int CeedOperatorLinearAssembleSymbolic(CeedOperator op,
1681e2f04181SAndrew T. Barker                                        CeedInt *nentries, CeedInt **rows, CeedInt **cols) {
1682e2f04181SAndrew T. Barker   int ierr;
1683e2f04181SAndrew T. Barker   CeedInt numsub, single_entries;
1684e2f04181SAndrew T. Barker   CeedOperator *suboperators;
1685e2f04181SAndrew T. Barker   bool isComposite;
1686e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
1687e2f04181SAndrew T. Barker 
1688e2f04181SAndrew T. Barker   // Use backend version, if available
1689e2f04181SAndrew T. Barker   if (op->LinearAssembleSymbolic) {
1690e2f04181SAndrew T. Barker     return op->LinearAssembleSymbolic(op, nentries, rows, cols);
1691e2f04181SAndrew T. Barker   } else {
1692e2f04181SAndrew T. Barker     // Check for valid fallback resource
1693e2f04181SAndrew T. Barker     const char *resource, *fallbackresource;
1694e2f04181SAndrew T. Barker     ierr = CeedGetResource(op->ceed, &resource); CeedChk(ierr);
1695e2f04181SAndrew T. Barker     ierr = CeedGetOperatorFallbackResource(op->ceed, &fallbackresource);
1696e2f04181SAndrew T. Barker     if (strcmp(fallbackresource, "") && strcmp(resource, fallbackresource)) {
1697e2f04181SAndrew T. Barker       // Fallback to reference Ceed
1698e2f04181SAndrew T. Barker       if (!op->opfallback) {
1699e2f04181SAndrew T. Barker         ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
1700e2f04181SAndrew T. Barker       }
1701e2f04181SAndrew T. Barker       // Assemble
1702e2f04181SAndrew T. Barker       return CeedOperatorLinearAssembleSymbolic(op->opfallback, nentries, rows, cols);
1703e2f04181SAndrew T. Barker     }
1704e2f04181SAndrew T. Barker   }
1705e2f04181SAndrew T. Barker 
1706e2f04181SAndrew T. Barker   // if neither backend nor fallback resource provides
1707e2f04181SAndrew T. Barker   // LinearAssembleSymbolic, continue with interface-level implementation
1708e2f04181SAndrew T. Barker 
1709e2f04181SAndrew T. Barker   // count entries and allocate rows, cols arrays
1710e2f04181SAndrew T. Barker   ierr = CeedOperatorIsComposite(op, &isComposite); CeedChk(ierr);
1711e2f04181SAndrew T. Barker   *nentries = 0;
1712e2f04181SAndrew T. Barker   if (isComposite) {
1713e2f04181SAndrew T. Barker     ierr = CeedOperatorGetNumSub(op, &numsub); CeedChk(ierr);
1714e2f04181SAndrew T. Barker     ierr = CeedOperatorGetSubList(op, &suboperators); CeedChk(ierr);
1715e2f04181SAndrew T. Barker     for (int k = 0; k < numsub; ++k) {
1716e2f04181SAndrew T. Barker       ierr = CeedSingleOperatorAssemblyCountEntries(suboperators[k],
1717e2f04181SAndrew T. Barker              &single_entries); CeedChk(ierr);
1718e2f04181SAndrew T. Barker       *nentries += single_entries;
1719e2f04181SAndrew T. Barker     }
1720e2f04181SAndrew T. Barker   } else {
1721e2f04181SAndrew T. Barker     ierr = CeedSingleOperatorAssemblyCountEntries(op,
1722e2f04181SAndrew T. Barker            &single_entries); CeedChk(ierr);
1723e2f04181SAndrew T. Barker     *nentries += single_entries;
1724e2f04181SAndrew T. Barker   }
1725e2f04181SAndrew T. Barker   ierr = CeedCalloc(*nentries, rows); CeedChk(ierr);
1726e2f04181SAndrew T. Barker   ierr = CeedCalloc(*nentries, cols); CeedChk(ierr);
1727e2f04181SAndrew T. Barker 
1728e2f04181SAndrew T. Barker   // assemble nonzero locations
1729e2f04181SAndrew T. Barker   CeedInt offset = 0;
1730e2f04181SAndrew T. Barker   if (isComposite) {
1731e2f04181SAndrew T. Barker     ierr = CeedOperatorGetNumSub(op, &numsub); CeedChk(ierr);
1732e2f04181SAndrew T. Barker     ierr = CeedOperatorGetSubList(op, &suboperators); CeedChk(ierr);
1733e2f04181SAndrew T. Barker     for (int k = 0; k < numsub; ++k) {
1734e2f04181SAndrew T. Barker       ierr = CeedSingleOperatorAssembleSymbolic(suboperators[k], offset, *rows,
1735e2f04181SAndrew T. Barker              *cols); CeedChk(ierr);
1736e2f04181SAndrew T. Barker       ierr = CeedSingleOperatorAssemblyCountEntries(suboperators[k], &single_entries);
1737e2f04181SAndrew T. Barker       CeedChk(ierr);
1738e2f04181SAndrew T. Barker       offset += single_entries;
1739e2f04181SAndrew T. Barker     }
1740e2f04181SAndrew T. Barker   } else {
1741e2f04181SAndrew T. Barker     ierr = CeedSingleOperatorAssembleSymbolic(op, offset, *rows, *cols);
1742e2f04181SAndrew T. Barker     CeedChk(ierr);
1743e2f04181SAndrew T. Barker   }
1744e2f04181SAndrew T. Barker 
1745e2f04181SAndrew T. Barker   return CEED_ERROR_SUCCESS;
1746e2f04181SAndrew T. Barker }
1747e2f04181SAndrew T. Barker 
1748e2f04181SAndrew T. Barker /**
1749e2f04181SAndrew T. Barker    @brief Fully assemble the nonzero entries of a linear operator.
1750e2f04181SAndrew T. Barker 
1751e2f04181SAndrew T. Barker    Expected to be used in conjunction with CeedOperatorLinearAssembleSymbolic()
1752e2f04181SAndrew T. Barker 
1753e2f04181SAndrew T. Barker    The assembly routines use coordinate format, with nentries tuples of the
1754e2f04181SAndrew T. Barker    form (i, j, value) which indicate that value should be added to the matrix
1755e2f04181SAndrew T. Barker    in entry (i, j). Note that the (i, j) pairs are not unique and may repeat.
1756e2f04181SAndrew T. Barker    This function returns the values of the nonzero entries to be added, their
1757e2f04181SAndrew T. Barker    (i, j) locations are provided by CeedOperatorLinearAssembleSymbolic()
1758e2f04181SAndrew T. Barker 
1759e2f04181SAndrew T. Barker    This will generally be slow unless your operator is low-order.
1760e2f04181SAndrew T. Barker 
1761e2f04181SAndrew T. Barker    @param[in]  op       CeedOperator to assemble
1762e2f04181SAndrew T. Barker    @param[out] values   Values to assemble into matrix
1763e2f04181SAndrew T. Barker 
1764e2f04181SAndrew T. Barker    @ref User
1765e2f04181SAndrew T. Barker **/
1766e2f04181SAndrew T. Barker int CeedOperatorLinearAssemble(CeedOperator op, CeedVector values) {
1767e2f04181SAndrew T. Barker   int ierr;
1768e2f04181SAndrew T. Barker   CeedInt numsub, single_entries;
1769e2f04181SAndrew T. Barker   CeedOperator *suboperators;
1770e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
1771e2f04181SAndrew T. Barker 
1772e2f04181SAndrew T. Barker   // Use backend version, if available
1773e2f04181SAndrew T. Barker   if (op->LinearAssemble) {
1774e2f04181SAndrew T. Barker     return op->LinearAssemble(op, values);
1775e2f04181SAndrew T. Barker   } else {
1776e2f04181SAndrew T. Barker     // Check for valid fallback resource
1777e2f04181SAndrew T. Barker     const char *resource, *fallbackresource;
1778e2f04181SAndrew T. Barker     ierr = CeedGetResource(op->ceed, &resource); CeedChk(ierr);
1779e2f04181SAndrew T. Barker     ierr = CeedGetOperatorFallbackResource(op->ceed, &fallbackresource);
1780e2f04181SAndrew T. Barker     if (strcmp(fallbackresource, "") && strcmp(resource, fallbackresource)) {
1781e2f04181SAndrew T. Barker       // Fallback to reference Ceed
1782e2f04181SAndrew T. Barker       if (!op->opfallback) {
1783e2f04181SAndrew T. Barker         ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
1784e2f04181SAndrew T. Barker       }
1785e2f04181SAndrew T. Barker       // Assemble
1786e2f04181SAndrew T. Barker       return CeedOperatorLinearAssemble(op->opfallback, values);
1787e2f04181SAndrew T. Barker     }
1788e2f04181SAndrew T. Barker   }
1789e2f04181SAndrew T. Barker 
1790e2f04181SAndrew T. Barker   // if neither backend nor fallback resource provides
1791e2f04181SAndrew T. Barker   // LinearAssemble, continue with interface-level implementation
1792e2f04181SAndrew T. Barker 
1793e2f04181SAndrew T. Barker   bool isComposite;
1794e2f04181SAndrew T. Barker   ierr = CeedOperatorIsComposite(op, &isComposite); CeedChk(ierr);
1795e2f04181SAndrew T. Barker 
1796e2f04181SAndrew T. Barker   CeedInt offset = 0;
1797e2f04181SAndrew T. Barker   if (isComposite) {
1798e2f04181SAndrew T. Barker     ierr = CeedOperatorGetNumSub(op, &numsub); CeedChk(ierr);
1799e2f04181SAndrew T. Barker     ierr = CeedOperatorGetSubList(op, &suboperators); CeedChk(ierr);
1800e2f04181SAndrew T. Barker     for (int k = 0; k < numsub; ++k) {
1801e2f04181SAndrew T. Barker       ierr = CeedSingleOperatorAssemble(suboperators[k], offset, values);
1802e2f04181SAndrew T. Barker       CeedChk(ierr);
1803e2f04181SAndrew T. Barker       ierr = CeedSingleOperatorAssemblyCountEntries(suboperators[k], &single_entries);
1804e2f04181SAndrew T. Barker       CeedChk(ierr);
1805e2f04181SAndrew T. Barker       offset += single_entries;
1806e2f04181SAndrew T. Barker     }
1807e2f04181SAndrew T. Barker   } else {
1808e2f04181SAndrew T. Barker     ierr = CeedSingleOperatorAssemble(op, offset, values); CeedChk(ierr);
1809e2f04181SAndrew T. Barker   }
1810e2f04181SAndrew T. Barker 
1811e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1812d965c7a7SJeremy L Thompson }
1813d965c7a7SJeremy L Thompson 
1814d965c7a7SJeremy L Thompson /**
1815d99fa3c5SJeremy L Thompson   @brief Create a multigrid coarse operator and level transfer operators
1816d99fa3c5SJeremy L Thompson            for a CeedOperator, creating the prolongation basis from the
1817d99fa3c5SJeremy L Thompson            fine and coarse grid interpolation
1818d99fa3c5SJeremy L Thompson 
1819d99fa3c5SJeremy L Thompson   @param[in] opFine       Fine grid operator
1820d99fa3c5SJeremy L Thompson   @param[in] PMultFine    L-vector multiplicity in parallel gather/scatter
1821d99fa3c5SJeremy L Thompson   @param[in] rstrCoarse   Coarse grid restriction
1822d99fa3c5SJeremy L Thompson   @param[in] basisCoarse  Coarse grid active vector basis
1823d99fa3c5SJeremy L Thompson   @param[out] opCoarse    Coarse grid operator
1824d99fa3c5SJeremy L Thompson   @param[out] opProlong   Coarse to fine operator
1825d99fa3c5SJeremy L Thompson   @param[out] opRestrict  Fine to coarse operator
1826d99fa3c5SJeremy L Thompson 
1827d99fa3c5SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1828d99fa3c5SJeremy L Thompson 
1829d99fa3c5SJeremy L Thompson   @ref User
1830d99fa3c5SJeremy L Thompson **/
1831d99fa3c5SJeremy L Thompson int CeedOperatorMultigridLevelCreate(CeedOperator opFine, CeedVector PMultFine,
1832d99fa3c5SJeremy L Thompson                                      CeedElemRestriction rstrCoarse, CeedBasis basisCoarse,
1833d99fa3c5SJeremy L Thompson                                      CeedOperator *opCoarse, CeedOperator *opProlong, CeedOperator *opRestrict) {
1834d99fa3c5SJeremy L Thompson   int ierr;
1835d99fa3c5SJeremy L Thompson   Ceed ceed;
1836d99fa3c5SJeremy L Thompson   ierr = CeedOperatorGetCeed(opFine, &ceed); CeedChk(ierr);
1837d99fa3c5SJeremy L Thompson 
1838d99fa3c5SJeremy L Thompson   // Check for compatible quadrature spaces
1839d99fa3c5SJeremy L Thompson   CeedBasis basisFine;
1840d99fa3c5SJeremy L Thompson   ierr = CeedOperatorGetActiveBasis(opFine, &basisFine); CeedChk(ierr);
1841d99fa3c5SJeremy L Thompson   CeedInt Qf, Qc;
1842d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumQuadraturePoints(basisFine, &Qf); CeedChk(ierr);
1843d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumQuadraturePoints(basisCoarse, &Qc); CeedChk(ierr);
1844d99fa3c5SJeremy L Thompson   if (Qf != Qc)
1845d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
1846e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_DIMENSION,
1847e15f9bd0SJeremy L Thompson                      "Bases must have compatible quadrature spaces");
1848d99fa3c5SJeremy L Thompson   // LCOV_EXCL_STOP
1849d99fa3c5SJeremy L Thompson 
1850d99fa3c5SJeremy L Thompson   // Coarse to fine basis
1851d99fa3c5SJeremy L Thompson   CeedInt Pf, Pc, Q = Qf;
1852d99fa3c5SJeremy L Thompson   bool isTensorF, isTensorC;
1853d99fa3c5SJeremy L Thompson   ierr = CeedBasisIsTensor(basisFine, &isTensorF); CeedChk(ierr);
1854d99fa3c5SJeremy L Thompson   ierr = CeedBasisIsTensor(basisCoarse, &isTensorC); CeedChk(ierr);
1855d99fa3c5SJeremy L Thompson   CeedScalar *interpC, *interpF, *interpCtoF, *tau;
1856d99fa3c5SJeremy L Thompson   if (isTensorF && isTensorC) {
1857d99fa3c5SJeremy L Thompson     ierr = CeedBasisGetNumNodes1D(basisFine, &Pf); CeedChk(ierr);
1858d99fa3c5SJeremy L Thompson     ierr = CeedBasisGetNumNodes1D(basisCoarse, &Pc); CeedChk(ierr);
1859d99fa3c5SJeremy L Thompson     ierr = CeedBasisGetNumQuadraturePoints1D(basisCoarse, &Q); CeedChk(ierr);
1860d99fa3c5SJeremy L Thompson   } else if (!isTensorF && !isTensorC) {
1861d99fa3c5SJeremy L Thompson     ierr = CeedBasisGetNumNodes(basisFine, &Pf); CeedChk(ierr);
1862d99fa3c5SJeremy L Thompson     ierr = CeedBasisGetNumNodes(basisCoarse, &Pc); CeedChk(ierr);
1863d99fa3c5SJeremy L Thompson   } else {
1864d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
1865e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_MINOR,
1866e15f9bd0SJeremy L Thompson                      "Bases must both be tensor or non-tensor");
1867d99fa3c5SJeremy L Thompson     // LCOV_EXCL_STOP
1868d99fa3c5SJeremy L Thompson   }
1869d99fa3c5SJeremy L Thompson 
1870d99fa3c5SJeremy L Thompson   ierr = CeedMalloc(Q*Pf, &interpF); CeedChk(ierr);
1871d99fa3c5SJeremy L Thompson   ierr = CeedMalloc(Q*Pc, &interpC); CeedChk(ierr);
1872d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(Pc*Pf, &interpCtoF); CeedChk(ierr);
1873d99fa3c5SJeremy L Thompson   ierr = CeedMalloc(Q, &tau); CeedChk(ierr);
1874d99fa3c5SJeremy L Thompson   if (isTensorF) {
1875d99fa3c5SJeremy L Thompson     memcpy(interpF, basisFine->interp1d, Q*Pf*sizeof basisFine->interp1d[0]);
1876d99fa3c5SJeremy L Thompson     memcpy(interpC, basisCoarse->interp1d, Q*Pc*sizeof basisCoarse->interp1d[0]);
1877d99fa3c5SJeremy L Thompson   } else {
1878d99fa3c5SJeremy L Thompson     memcpy(interpF, basisFine->interp, Q*Pf*sizeof basisFine->interp[0]);
1879d99fa3c5SJeremy L Thompson     memcpy(interpC, basisCoarse->interp, Q*Pc*sizeof basisCoarse->interp[0]);
1880d99fa3c5SJeremy L Thompson   }
1881d99fa3c5SJeremy L Thompson 
1882d99fa3c5SJeremy L Thompson   // -- QR Factorization, interpF = Q R
1883d99fa3c5SJeremy L Thompson   ierr = CeedQRFactorization(ceed, interpF, tau, Q, Pf); CeedChk(ierr);
1884d99fa3c5SJeremy L Thompson 
1885d99fa3c5SJeremy L Thompson   // -- Apply Qtranspose, interpC = Qtranspose interpC
1886d99fa3c5SJeremy L Thompson   CeedHouseholderApplyQ(interpC, interpF, tau, CEED_TRANSPOSE,
1887d99fa3c5SJeremy L Thompson                         Q, Pc, Pf, Pc, 1);
1888d99fa3c5SJeremy L Thompson 
1889d99fa3c5SJeremy L Thompson   // -- Apply Rinv, interpCtoF = Rinv interpC
1890d99fa3c5SJeremy L Thompson   for (CeedInt j=0; j<Pc; j++) { // Column j
1891d99fa3c5SJeremy L Thompson     interpCtoF[j+Pc*(Pf-1)] = interpC[j+Pc*(Pf-1)]/interpF[Pf*Pf-1];
1892d99fa3c5SJeremy L Thompson     for (CeedInt i=Pf-2; i>=0; i--) { // Row i
1893d99fa3c5SJeremy L Thompson       interpCtoF[j+Pc*i] = interpC[j+Pc*i];
1894d99fa3c5SJeremy L Thompson       for (CeedInt k=i+1; k<Pf; k++)
1895d99fa3c5SJeremy L Thompson         interpCtoF[j+Pc*i] -= interpF[k+Pf*i]*interpCtoF[j+Pc*k];
1896d99fa3c5SJeremy L Thompson       interpCtoF[j+Pc*i] /= interpF[i+Pf*i];
1897d99fa3c5SJeremy L Thompson     }
1898d99fa3c5SJeremy L Thompson   }
1899d99fa3c5SJeremy L Thompson   ierr = CeedFree(&tau); CeedChk(ierr);
1900d99fa3c5SJeremy L Thompson   ierr = CeedFree(&interpC); CeedChk(ierr);
1901d99fa3c5SJeremy L Thompson   ierr = CeedFree(&interpF); CeedChk(ierr);
1902d99fa3c5SJeremy L Thompson 
1903e15f9bd0SJeremy L Thompson   // Complete with interpCtoF versions of code
1904d99fa3c5SJeremy L Thompson   if (isTensorF) {
1905d99fa3c5SJeremy L Thompson     ierr = CeedOperatorMultigridLevelCreateTensorH1(opFine, PMultFine,
1906d99fa3c5SJeremy L Thompson            rstrCoarse, basisCoarse, interpCtoF, opCoarse, opProlong, opRestrict);
1907d99fa3c5SJeremy L Thompson     CeedChk(ierr);
1908d99fa3c5SJeremy L Thompson   } else {
1909d99fa3c5SJeremy L Thompson     ierr = CeedOperatorMultigridLevelCreateH1(opFine, PMultFine,
1910d99fa3c5SJeremy L Thompson            rstrCoarse, basisCoarse, interpCtoF, opCoarse, opProlong, opRestrict);
1911d99fa3c5SJeremy L Thompson     CeedChk(ierr);
1912d99fa3c5SJeremy L Thompson   }
1913d99fa3c5SJeremy L Thompson 
1914d99fa3c5SJeremy L Thompson   // Cleanup
1915d99fa3c5SJeremy L Thompson   ierr = CeedFree(&interpCtoF); CeedChk(ierr);
1916e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1917d99fa3c5SJeremy L Thompson }
1918d99fa3c5SJeremy L Thompson 
1919d99fa3c5SJeremy L Thompson /**
1920d99fa3c5SJeremy L Thompson   @brief Create a multigrid coarse operator and level transfer operators
1921d99fa3c5SJeremy L Thompson            for a CeedOperator with a tensor basis for the active basis
1922d99fa3c5SJeremy L Thompson 
1923d99fa3c5SJeremy L Thompson   @param[in] opFine       Fine grid operator
1924d99fa3c5SJeremy L Thompson   @param[in] PMultFine    L-vector multiplicity in parallel gather/scatter
1925d99fa3c5SJeremy L Thompson   @param[in] rstrCoarse   Coarse grid restriction
1926d99fa3c5SJeremy L Thompson   @param[in] basisCoarse  Coarse grid active vector basis
1927d99fa3c5SJeremy L Thompson   @param[in] interpCtoF   Matrix for coarse to fine interpolation
1928d99fa3c5SJeremy L Thompson   @param[out] opCoarse    Coarse grid operator
1929d99fa3c5SJeremy L Thompson   @param[out] opProlong   Coarse to fine operator
1930d99fa3c5SJeremy L Thompson   @param[out] opRestrict  Fine to coarse operator
1931d99fa3c5SJeremy L Thompson 
1932d99fa3c5SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1933d99fa3c5SJeremy L Thompson 
1934d99fa3c5SJeremy L Thompson   @ref User
1935d99fa3c5SJeremy L Thompson **/
1936d99fa3c5SJeremy L Thompson int CeedOperatorMultigridLevelCreateTensorH1(CeedOperator opFine,
1937d99fa3c5SJeremy L Thompson     CeedVector PMultFine, CeedElemRestriction rstrCoarse, CeedBasis basisCoarse,
1938d99fa3c5SJeremy L Thompson     const CeedScalar *interpCtoF, CeedOperator *opCoarse,
1939d99fa3c5SJeremy L Thompson     CeedOperator *opProlong, CeedOperator *opRestrict) {
1940d99fa3c5SJeremy L Thompson   int ierr;
1941d99fa3c5SJeremy L Thompson   Ceed ceed;
1942d99fa3c5SJeremy L Thompson   ierr = CeedOperatorGetCeed(opFine, &ceed); CeedChk(ierr);
1943d99fa3c5SJeremy L Thompson 
1944d99fa3c5SJeremy L Thompson   // Check for compatible quadrature spaces
1945d99fa3c5SJeremy L Thompson   CeedBasis basisFine;
1946d99fa3c5SJeremy L Thompson   ierr = CeedOperatorGetActiveBasis(opFine, &basisFine); CeedChk(ierr);
1947d99fa3c5SJeremy L Thompson   CeedInt Qf, Qc;
1948d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumQuadraturePoints(basisFine, &Qf); CeedChk(ierr);
1949d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumQuadraturePoints(basisCoarse, &Qc); CeedChk(ierr);
1950d99fa3c5SJeremy L Thompson   if (Qf != Qc)
1951d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
1952e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_DIMENSION,
1953e15f9bd0SJeremy L Thompson                      "Bases must have compatible quadrature spaces");
1954d99fa3c5SJeremy L Thompson   // LCOV_EXCL_STOP
1955d99fa3c5SJeremy L Thompson 
1956d99fa3c5SJeremy L Thompson   // Coarse to fine basis
1957d99fa3c5SJeremy L Thompson   CeedInt dim, ncomp, nnodesCoarse, P1dFine, P1dCoarse;
1958d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetDimension(basisFine, &dim); CeedChk(ierr);
1959d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumComponents(basisFine, &ncomp); CeedChk(ierr);
1960d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumNodes1D(basisFine, &P1dFine); CeedChk(ierr);
1961d99fa3c5SJeremy L Thompson   ierr = CeedElemRestrictionGetElementSize(rstrCoarse, &nnodesCoarse);
1962d99fa3c5SJeremy L Thompson   CeedChk(ierr);
1963d99fa3c5SJeremy L Thompson   P1dCoarse = dim == 1 ? nnodesCoarse :
1964d99fa3c5SJeremy L Thompson               dim == 2 ? sqrt(nnodesCoarse) :
1965d99fa3c5SJeremy L Thompson               cbrt(nnodesCoarse);
1966d99fa3c5SJeremy L Thompson   CeedScalar *qref, *qweight, *grad;
1967d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(P1dFine, &qref); CeedChk(ierr);
1968d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(P1dFine, &qweight); CeedChk(ierr);
1969d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(P1dFine*P1dCoarse*dim, &grad); CeedChk(ierr);
1970d99fa3c5SJeremy L Thompson   CeedBasis basisCtoF;
1971d99fa3c5SJeremy L Thompson   ierr = CeedBasisCreateTensorH1(ceed, dim, ncomp, P1dCoarse, P1dFine,
1972d99fa3c5SJeremy L Thompson                                  interpCtoF, grad, qref, qweight, &basisCtoF);
1973d99fa3c5SJeremy L Thompson   CeedChk(ierr);
1974d99fa3c5SJeremy L Thompson   ierr = CeedFree(&qref); CeedChk(ierr);
1975d99fa3c5SJeremy L Thompson   ierr = CeedFree(&qweight); CeedChk(ierr);
1976d99fa3c5SJeremy L Thompson   ierr = CeedFree(&grad); CeedChk(ierr);
1977d99fa3c5SJeremy L Thompson 
1978d99fa3c5SJeremy L Thompson   // Core code
1979d99fa3c5SJeremy L Thompson   ierr = CeedOperatorMultigridLevel_Core(opFine, PMultFine, rstrCoarse,
1980d99fa3c5SJeremy L Thompson                                          basisCoarse, basisCtoF, opCoarse,
1981d99fa3c5SJeremy L Thompson                                          opProlong, opRestrict);
1982d99fa3c5SJeremy L Thompson   CeedChk(ierr);
1983e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1984d99fa3c5SJeremy L Thompson }
1985d99fa3c5SJeremy L Thompson 
1986d99fa3c5SJeremy L Thompson /**
1987d99fa3c5SJeremy L Thompson   @brief Create a multigrid coarse operator and level transfer operators
1988d99fa3c5SJeremy L Thompson            for a CeedOperator with a non-tensor basis for the active vector
1989d99fa3c5SJeremy L Thompson 
1990d99fa3c5SJeremy L Thompson   @param[in] opFine       Fine grid operator
1991d99fa3c5SJeremy L Thompson   @param[in] PMultFine    L-vector multiplicity in parallel gather/scatter
1992d99fa3c5SJeremy L Thompson   @param[in] rstrCoarse   Coarse grid restriction
1993d99fa3c5SJeremy L Thompson   @param[in] basisCoarse  Coarse grid active vector basis
1994d99fa3c5SJeremy L Thompson   @param[in] interpCtoF   Matrix for coarse to fine interpolation
1995d99fa3c5SJeremy L Thompson   @param[out] opCoarse    Coarse grid operator
1996d99fa3c5SJeremy L Thompson   @param[out] opProlong   Coarse to fine operator
1997d99fa3c5SJeremy L Thompson   @param[out] opRestrict  Fine to coarse operator
1998d99fa3c5SJeremy L Thompson 
1999d99fa3c5SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
2000d99fa3c5SJeremy L Thompson 
2001d99fa3c5SJeremy L Thompson   @ref User
2002d99fa3c5SJeremy L Thompson **/
2003d99fa3c5SJeremy L Thompson int CeedOperatorMultigridLevelCreateH1(CeedOperator opFine,
2004d99fa3c5SJeremy L Thompson                                        CeedVector PMultFine,
2005d99fa3c5SJeremy L Thompson                                        CeedElemRestriction rstrCoarse,
2006d99fa3c5SJeremy L Thompson                                        CeedBasis basisCoarse,
2007d99fa3c5SJeremy L Thompson                                        const CeedScalar *interpCtoF,
2008d99fa3c5SJeremy L Thompson                                        CeedOperator *opCoarse,
2009d99fa3c5SJeremy L Thompson                                        CeedOperator *opProlong,
2010d99fa3c5SJeremy L Thompson                                        CeedOperator *opRestrict) {
2011d99fa3c5SJeremy L Thompson   int ierr;
2012d99fa3c5SJeremy L Thompson   Ceed ceed;
2013d99fa3c5SJeremy L Thompson   ierr = CeedOperatorGetCeed(opFine, &ceed); CeedChk(ierr);
2014d99fa3c5SJeremy L Thompson 
2015d99fa3c5SJeremy L Thompson   // Check for compatible quadrature spaces
2016d99fa3c5SJeremy L Thompson   CeedBasis basisFine;
2017d99fa3c5SJeremy L Thompson   ierr = CeedOperatorGetActiveBasis(opFine, &basisFine); CeedChk(ierr);
2018d99fa3c5SJeremy L Thompson   CeedInt Qf, Qc;
2019d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumQuadraturePoints(basisFine, &Qf); CeedChk(ierr);
2020d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumQuadraturePoints(basisCoarse, &Qc); CeedChk(ierr);
2021d99fa3c5SJeremy L Thompson   if (Qf != Qc)
2022d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
2023e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_DIMENSION,
2024e15f9bd0SJeremy L Thompson                      "Bases must have compatible quadrature spaces");
2025d99fa3c5SJeremy L Thompson   // LCOV_EXCL_STOP
2026d99fa3c5SJeremy L Thompson 
2027d99fa3c5SJeremy L Thompson   // Coarse to fine basis
2028d99fa3c5SJeremy L Thompson   CeedElemTopology topo;
2029d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetTopology(basisFine, &topo); CeedChk(ierr);
2030d99fa3c5SJeremy L Thompson   CeedInt dim, ncomp, nnodesCoarse, nnodesFine;
2031d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetDimension(basisFine, &dim); CeedChk(ierr);
2032d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumComponents(basisFine, &ncomp); CeedChk(ierr);
2033d99fa3c5SJeremy L Thompson   ierr = CeedBasisGetNumNodes(basisFine, &nnodesFine); CeedChk(ierr);
2034d99fa3c5SJeremy L Thompson   ierr = CeedElemRestrictionGetElementSize(rstrCoarse, &nnodesCoarse);
2035d99fa3c5SJeremy L Thompson   CeedChk(ierr);
2036d99fa3c5SJeremy L Thompson   CeedScalar *qref, *qweight, *grad;
2037d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(nnodesFine, &qref); CeedChk(ierr);
2038d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(nnodesFine, &qweight); CeedChk(ierr);
2039d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(nnodesFine*nnodesCoarse*dim, &grad); CeedChk(ierr);
2040d99fa3c5SJeremy L Thompson   CeedBasis basisCtoF;
2041d99fa3c5SJeremy L Thompson   ierr = CeedBasisCreateH1(ceed, topo, ncomp, nnodesCoarse, nnodesFine,
2042d99fa3c5SJeremy L Thompson                            interpCtoF, grad, qref, qweight, &basisCtoF);
2043d99fa3c5SJeremy L Thompson   CeedChk(ierr);
2044d99fa3c5SJeremy L Thompson   ierr = CeedFree(&qref); CeedChk(ierr);
2045d99fa3c5SJeremy L Thompson   ierr = CeedFree(&qweight); CeedChk(ierr);
2046d99fa3c5SJeremy L Thompson   ierr = CeedFree(&grad); CeedChk(ierr);
2047d99fa3c5SJeremy L Thompson 
2048d99fa3c5SJeremy L Thompson   // Core code
2049d99fa3c5SJeremy L Thompson   ierr = CeedOperatorMultigridLevel_Core(opFine, PMultFine, rstrCoarse,
2050d99fa3c5SJeremy L Thompson                                          basisCoarse, basisCtoF, opCoarse,
2051d99fa3c5SJeremy L Thompson                                          opProlong, opRestrict);
2052d99fa3c5SJeremy L Thompson   CeedChk(ierr);
2053e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2054d99fa3c5SJeremy L Thompson }
2055d99fa3c5SJeremy L Thompson 
2056d99fa3c5SJeremy L Thompson /**
20573bd813ffSjeremylt   @brief Build a FDM based approximate inverse for each element for a
20583bd813ffSjeremylt            CeedOperator
20593bd813ffSjeremylt 
20603bd813ffSjeremylt   This returns a CeedOperator and CeedVector to apply a Fast Diagonalization
20613bd813ffSjeremylt     Method based approximate inverse. This function obtains the simultaneous
20623bd813ffSjeremylt     diagonalization for the 1D mass and Laplacian operators,
20633bd813ffSjeremylt       M = V^T V, K = V^T S V.
20643bd813ffSjeremylt     The assembled QFunction is used to modify the eigenvalues from simultaneous
20653bd813ffSjeremylt     diagonalization and obtain an approximate inverse of the form
20663bd813ffSjeremylt       V^T S^hat V. The CeedOperator must be linear and non-composite. The
20673bd813ffSjeremylt     associated CeedQFunction must therefore also be linear.
20683bd813ffSjeremylt 
20693bd813ffSjeremylt   @param op             CeedOperator to create element inverses
20703bd813ffSjeremylt   @param[out] fdminv    CeedOperator to apply the action of a FDM based inverse
20713bd813ffSjeremylt                           for each element
20723bd813ffSjeremylt   @param request        Address of CeedRequest for non-blocking completion, else
20734cc79fe7SJed Brown                           @ref CEED_REQUEST_IMMEDIATE
20743bd813ffSjeremylt 
20753bd813ffSjeremylt   @return An error code: 0 - success, otherwise - failure
20763bd813ffSjeremylt 
20777a982d89SJeremy L. Thompson   @ref Backend
20783bd813ffSjeremylt **/
20793bd813ffSjeremylt int CeedOperatorCreateFDMElementInverse(CeedOperator op, CeedOperator *fdminv,
20803bd813ffSjeremylt                                         CeedRequest *request) {
20813bd813ffSjeremylt   int ierr;
2082e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
20833bd813ffSjeremylt 
2084713f43c3Sjeremylt   // Use backend version, if available
2085713f43c3Sjeremylt   if (op->CreateFDMElementInverse) {
2086713f43c3Sjeremylt     ierr = op->CreateFDMElementInverse(op, fdminv, request); CeedChk(ierr);
2087713f43c3Sjeremylt   } else {
2088713f43c3Sjeremylt     // Fallback to reference Ceed
2089713f43c3Sjeremylt     if (!op->opfallback) {
2090713f43c3Sjeremylt       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
20913bd813ffSjeremylt     }
2092713f43c3Sjeremylt     // Assemble
2093713f43c3Sjeremylt     ierr = op->opfallback->CreateFDMElementInverse(op->opfallback, fdminv,
20943bd813ffSjeremylt            request); CeedChk(ierr);
20953bd813ffSjeremylt   }
2096e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
20973bd813ffSjeremylt }
20983bd813ffSjeremylt 
20997a982d89SJeremy L. Thompson /**
21007a982d89SJeremy L. Thompson   @brief View a CeedOperator
21017a982d89SJeremy L. Thompson 
21027a982d89SJeremy L. Thompson   @param[in] op     CeedOperator to view
21037a982d89SJeremy L. Thompson   @param[in] stream Stream to write; typically stdout/stderr or a file
21047a982d89SJeremy L. Thompson 
21057a982d89SJeremy L. Thompson   @return Error code: 0 - success, otherwise - failure
21067a982d89SJeremy L. Thompson 
21077a982d89SJeremy L. Thompson   @ref User
21087a982d89SJeremy L. Thompson **/
21097a982d89SJeremy L. Thompson int CeedOperatorView(CeedOperator op, FILE *stream) {
21107a982d89SJeremy L. Thompson   int ierr;
21117a982d89SJeremy L. Thompson 
21127a982d89SJeremy L. Thompson   if (op->composite) {
21137a982d89SJeremy L. Thompson     fprintf(stream, "Composite CeedOperator\n");
21147a982d89SJeremy L. Thompson 
21157a982d89SJeremy L. Thompson     for (CeedInt i=0; i<op->numsub; i++) {
21167a982d89SJeremy L. Thompson       fprintf(stream, "  SubOperator [%d]:\n", i);
21177a982d89SJeremy L. Thompson       ierr = CeedOperatorSingleView(op->suboperators[i], 1, stream);
21187a982d89SJeremy L. Thompson       CeedChk(ierr);
21197a982d89SJeremy L. Thompson     }
21207a982d89SJeremy L. Thompson   } else {
21217a982d89SJeremy L. Thompson     fprintf(stream, "CeedOperator\n");
21227a982d89SJeremy L. Thompson     ierr = CeedOperatorSingleView(op, 0, stream); CeedChk(ierr);
21237a982d89SJeremy L. Thompson   }
2124e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
21257a982d89SJeremy L. Thompson }
21263bd813ffSjeremylt 
21273bd813ffSjeremylt /**
21283bd813ffSjeremylt   @brief Apply CeedOperator to a vector
2129d7b241e6Sjeremylt 
2130d7b241e6Sjeremylt   This computes the action of the operator on the specified (active) input,
2131d7b241e6Sjeremylt   yielding its (active) output.  All inputs and outputs must be specified using
2132d7b241e6Sjeremylt   CeedOperatorSetField().
2133d7b241e6Sjeremylt 
2134d7b241e6Sjeremylt   @param op        CeedOperator to apply
21354cc79fe7SJed Brown   @param[in] in    CeedVector containing input state or @ref CEED_VECTOR_NONE if
213634138859Sjeremylt                   there are no active inputs
2137b11c1e72Sjeremylt   @param[out] out  CeedVector to store result of applying operator (must be
21384cc79fe7SJed Brown                      distinct from @a in) or @ref CEED_VECTOR_NONE if there are no
213934138859Sjeremylt                      active outputs
2140d7b241e6Sjeremylt   @param request   Address of CeedRequest for non-blocking completion, else
21414cc79fe7SJed Brown                      @ref CEED_REQUEST_IMMEDIATE
2142b11c1e72Sjeremylt 
2143b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
2144dfdf5a53Sjeremylt 
21457a982d89SJeremy L. Thompson   @ref User
2146b11c1e72Sjeremylt **/
2147692c2638Sjeremylt int CeedOperatorApply(CeedOperator op, CeedVector in, CeedVector out,
2148692c2638Sjeremylt                       CeedRequest *request) {
2149d7b241e6Sjeremylt   int ierr;
2150e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
2151d7b241e6Sjeremylt 
2152250756a7Sjeremylt   if (op->numelements)  {
2153250756a7Sjeremylt     // Standard Operator
2154cae8b89aSjeremylt     if (op->Apply) {
2155250756a7Sjeremylt       ierr = op->Apply(op, in, out, request); CeedChk(ierr);
2156cae8b89aSjeremylt     } else {
2157cae8b89aSjeremylt       // Zero all output vectors
2158250756a7Sjeremylt       CeedQFunction qf = op->qf;
2159cae8b89aSjeremylt       for (CeedInt i=0; i<qf->numoutputfields; i++) {
2160cae8b89aSjeremylt         CeedVector vec = op->outputfields[i]->vec;
2161cae8b89aSjeremylt         if (vec == CEED_VECTOR_ACTIVE)
2162cae8b89aSjeremylt           vec = out;
2163cae8b89aSjeremylt         if (vec != CEED_VECTOR_NONE) {
2164cae8b89aSjeremylt           ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr);
2165cae8b89aSjeremylt         }
2166cae8b89aSjeremylt       }
2167250756a7Sjeremylt       // Apply
2168250756a7Sjeremylt       ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr);
2169250756a7Sjeremylt     }
2170250756a7Sjeremylt   } else if (op->composite) {
2171250756a7Sjeremylt     // Composite Operator
2172250756a7Sjeremylt     if (op->ApplyComposite) {
2173250756a7Sjeremylt       ierr = op->ApplyComposite(op, in, out, request); CeedChk(ierr);
2174250756a7Sjeremylt     } else {
2175250756a7Sjeremylt       CeedInt numsub;
2176250756a7Sjeremylt       ierr = CeedOperatorGetNumSub(op, &numsub); CeedChk(ierr);
2177250756a7Sjeremylt       CeedOperator *suboperators;
2178250756a7Sjeremylt       ierr = CeedOperatorGetSubList(op, &suboperators); CeedChk(ierr);
2179250756a7Sjeremylt 
2180250756a7Sjeremylt       // Zero all output vectors
2181250756a7Sjeremylt       if (out != CEED_VECTOR_NONE) {
2182cae8b89aSjeremylt         ierr = CeedVectorSetValue(out, 0.0); CeedChk(ierr);
2183cae8b89aSjeremylt       }
2184250756a7Sjeremylt       for (CeedInt i=0; i<numsub; i++) {
2185250756a7Sjeremylt         for (CeedInt j=0; j<suboperators[i]->qf->numoutputfields; j++) {
2186250756a7Sjeremylt           CeedVector vec = suboperators[i]->outputfields[j]->vec;
2187250756a7Sjeremylt           if (vec != CEED_VECTOR_ACTIVE && vec != CEED_VECTOR_NONE) {
2188250756a7Sjeremylt             ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr);
2189250756a7Sjeremylt           }
2190250756a7Sjeremylt         }
2191250756a7Sjeremylt       }
2192250756a7Sjeremylt       // Apply
2193250756a7Sjeremylt       for (CeedInt i=0; i<op->numsub; i++) {
2194250756a7Sjeremylt         ierr = CeedOperatorApplyAdd(op->suboperators[i], in, out, request);
2195cae8b89aSjeremylt         CeedChk(ierr);
2196cae8b89aSjeremylt       }
2197cae8b89aSjeremylt     }
2198250756a7Sjeremylt   }
2199e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2200cae8b89aSjeremylt }
2201cae8b89aSjeremylt 
2202cae8b89aSjeremylt /**
2203cae8b89aSjeremylt   @brief Apply CeedOperator to a vector and add result to output vector
2204cae8b89aSjeremylt 
2205cae8b89aSjeremylt   This computes the action of the operator on the specified (active) input,
2206cae8b89aSjeremylt   yielding its (active) output.  All inputs and outputs must be specified using
2207cae8b89aSjeremylt   CeedOperatorSetField().
2208cae8b89aSjeremylt 
2209cae8b89aSjeremylt   @param op        CeedOperator to apply
2210cae8b89aSjeremylt   @param[in] in    CeedVector containing input state or NULL if there are no
2211cae8b89aSjeremylt                      active inputs
2212cae8b89aSjeremylt   @param[out] out  CeedVector to sum in result of applying operator (must be
2213cae8b89aSjeremylt                      distinct from @a in) or NULL if there are no active outputs
2214cae8b89aSjeremylt   @param request   Address of CeedRequest for non-blocking completion, else
22154cc79fe7SJed Brown                      @ref CEED_REQUEST_IMMEDIATE
2216cae8b89aSjeremylt 
2217cae8b89aSjeremylt   @return An error code: 0 - success, otherwise - failure
2218cae8b89aSjeremylt 
22197a982d89SJeremy L. Thompson   @ref User
2220cae8b89aSjeremylt **/
2221cae8b89aSjeremylt int CeedOperatorApplyAdd(CeedOperator op, CeedVector in, CeedVector out,
2222cae8b89aSjeremylt                          CeedRequest *request) {
2223cae8b89aSjeremylt   int ierr;
2224e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
2225cae8b89aSjeremylt 
2226250756a7Sjeremylt   if (op->numelements)  {
2227250756a7Sjeremylt     // Standard Operator
2228250756a7Sjeremylt     ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr);
2229250756a7Sjeremylt   } else if (op->composite) {
2230250756a7Sjeremylt     // Composite Operator
2231250756a7Sjeremylt     if (op->ApplyAddComposite) {
2232250756a7Sjeremylt       ierr = op->ApplyAddComposite(op, in, out, request); CeedChk(ierr);
2233cae8b89aSjeremylt     } else {
2234250756a7Sjeremylt       CeedInt numsub;
2235250756a7Sjeremylt       ierr = CeedOperatorGetNumSub(op, &numsub); CeedChk(ierr);
2236250756a7Sjeremylt       CeedOperator *suboperators;
2237250756a7Sjeremylt       ierr = CeedOperatorGetSubList(op, &suboperators); CeedChk(ierr);
2238250756a7Sjeremylt 
2239250756a7Sjeremylt       for (CeedInt i=0; i<numsub; i++) {
2240250756a7Sjeremylt         ierr = CeedOperatorApplyAdd(suboperators[i], in, out, request);
2241cae8b89aSjeremylt         CeedChk(ierr);
22421d7d2407SJeremy L Thompson       }
2243250756a7Sjeremylt     }
2244250756a7Sjeremylt   }
2245e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2246d7b241e6Sjeremylt }
2247d7b241e6Sjeremylt 
2248d7b241e6Sjeremylt /**
2249b11c1e72Sjeremylt   @brief Destroy a CeedOperator
2250d7b241e6Sjeremylt 
2251d7b241e6Sjeremylt   @param op CeedOperator to destroy
2252b11c1e72Sjeremylt 
2253b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
2254dfdf5a53Sjeremylt 
22557a982d89SJeremy L. Thompson   @ref User
2256b11c1e72Sjeremylt **/
2257d7b241e6Sjeremylt int CeedOperatorDestroy(CeedOperator *op) {
2258d7b241e6Sjeremylt   int ierr;
2259d7b241e6Sjeremylt 
2260e15f9bd0SJeremy L Thompson   if (!*op || --(*op)->refcount > 0) return CEED_ERROR_SUCCESS;
2261d7b241e6Sjeremylt   if ((*op)->Destroy) {
2262d7b241e6Sjeremylt     ierr = (*op)->Destroy(*op); CeedChk(ierr);
2263d7b241e6Sjeremylt   }
2264fe2413ffSjeremylt   ierr = CeedDestroy(&(*op)->ceed); CeedChk(ierr);
2265fe2413ffSjeremylt   // Free fields
22661d102b48SJeremy L Thompson   for (int i=0; i<(*op)->nfields; i++)
226752d6035fSJeremy L Thompson     if ((*op)->inputfields[i]) {
226815910d16Sjeremylt       if ((*op)->inputfields[i]->Erestrict != CEED_ELEMRESTRICTION_NONE) {
226971352a93Sjeremylt         ierr = CeedElemRestrictionDestroy(&(*op)->inputfields[i]->Erestrict);
227071352a93Sjeremylt         CeedChk(ierr);
227115910d16Sjeremylt       }
227271352a93Sjeremylt       if ((*op)->inputfields[i]->basis != CEED_BASIS_COLLOCATED) {
227371352a93Sjeremylt         ierr = CeedBasisDestroy(&(*op)->inputfields[i]->basis); CeedChk(ierr);
227471352a93Sjeremylt       }
227571352a93Sjeremylt       if ((*op)->inputfields[i]->vec != CEED_VECTOR_ACTIVE &&
227671352a93Sjeremylt           (*op)->inputfields[i]->vec != CEED_VECTOR_NONE ) {
227771352a93Sjeremylt         ierr = CeedVectorDestroy(&(*op)->inputfields[i]->vec); CeedChk(ierr);
227871352a93Sjeremylt       }
2279d99fa3c5SJeremy L Thompson       ierr = CeedFree(&(*op)->inputfields[i]->fieldname); CeedChk(ierr);
2280fe2413ffSjeremylt       ierr = CeedFree(&(*op)->inputfields[i]); CeedChk(ierr);
2281fe2413ffSjeremylt     }
22821d102b48SJeremy L Thompson   for (int i=0; i<(*op)->nfields; i++)
2283d0eb30a5Sjeremylt     if ((*op)->outputfields[i]) {
228471352a93Sjeremylt       ierr = CeedElemRestrictionDestroy(&(*op)->outputfields[i]->Erestrict);
228571352a93Sjeremylt       CeedChk(ierr);
228671352a93Sjeremylt       if ((*op)->outputfields[i]->basis != CEED_BASIS_COLLOCATED) {
228771352a93Sjeremylt         ierr = CeedBasisDestroy(&(*op)->outputfields[i]->basis); CeedChk(ierr);
228871352a93Sjeremylt       }
228971352a93Sjeremylt       if ((*op)->outputfields[i]->vec != CEED_VECTOR_ACTIVE &&
229071352a93Sjeremylt           (*op)->outputfields[i]->vec != CEED_VECTOR_NONE ) {
229171352a93Sjeremylt         ierr = CeedVectorDestroy(&(*op)->outputfields[i]->vec); CeedChk(ierr);
229271352a93Sjeremylt       }
2293d99fa3c5SJeremy L Thompson       ierr = CeedFree(&(*op)->outputfields[i]->fieldname); CeedChk(ierr);
2294fe2413ffSjeremylt       ierr = CeedFree(&(*op)->outputfields[i]); CeedChk(ierr);
2295fe2413ffSjeremylt     }
229652d6035fSJeremy L Thompson   // Destroy suboperators
22971d102b48SJeremy L Thompson   for (int i=0; i<(*op)->numsub; i++)
229852d6035fSJeremy L Thompson     if ((*op)->suboperators[i]) {
229952d6035fSJeremy L Thompson       ierr = CeedOperatorDestroy(&(*op)->suboperators[i]); CeedChk(ierr);
230052d6035fSJeremy L Thompson     }
2301e15f9bd0SJeremy L Thompson   if ((*op)->qf)
2302e15f9bd0SJeremy L Thompson     // LCOV_EXCL_START
2303e15f9bd0SJeremy L Thompson     (*op)->qf->operatorsset--;
2304e15f9bd0SJeremy L Thompson   // LCOV_EXCL_STOP
2305d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->qf); CeedChk(ierr);
2306e15f9bd0SJeremy L Thompson   if ((*op)->dqf && (*op)->dqf != CEED_QFUNCTION_NONE)
2307e15f9bd0SJeremy L Thompson     // LCOV_EXCL_START
2308e15f9bd0SJeremy L Thompson     (*op)->dqf->operatorsset--;
2309e15f9bd0SJeremy L Thompson   // LCOV_EXCL_STOP
2310d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->dqf); CeedChk(ierr);
2311e15f9bd0SJeremy L Thompson   if ((*op)->dqfT && (*op)->dqfT != CEED_QFUNCTION_NONE)
2312e15f9bd0SJeremy L Thompson     // LCOV_EXCL_START
2313e15f9bd0SJeremy L Thompson     (*op)->dqfT->operatorsset--;
2314e15f9bd0SJeremy L Thompson   // LCOV_EXCL_STOP
2315d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->dqfT); CeedChk(ierr);
2316fe2413ffSjeremylt 
23175107b09fSJeremy L Thompson   // Destroy fallback
23185107b09fSJeremy L Thompson   if ((*op)->opfallback) {
23195107b09fSJeremy L Thompson     ierr = (*op)->qffallback->Destroy((*op)->qffallback); CeedChk(ierr);
23205107b09fSJeremy L Thompson     ierr = CeedFree(&(*op)->qffallback); CeedChk(ierr);
23215107b09fSJeremy L Thompson     ierr = (*op)->opfallback->Destroy((*op)->opfallback); CeedChk(ierr);
23225107b09fSJeremy L Thompson     ierr = CeedFree(&(*op)->opfallback); CeedChk(ierr);
23235107b09fSJeremy L Thompson   }
23245107b09fSJeremy L Thompson 
2325fe2413ffSjeremylt   ierr = CeedFree(&(*op)->inputfields); CeedChk(ierr);
2326fe2413ffSjeremylt   ierr = CeedFree(&(*op)->outputfields); CeedChk(ierr);
232752d6035fSJeremy L Thompson   ierr = CeedFree(&(*op)->suboperators); CeedChk(ierr);
2328d7b241e6Sjeremylt   ierr = CeedFree(op); CeedChk(ierr);
2329e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2330d7b241e6Sjeremylt }
2331d7b241e6Sjeremylt 
2332d7b241e6Sjeremylt /// @}
2333