xref: /libCEED/interface/ceed-operator.c (revision d1d35e2f02dc969aee8debf3fd943dd784aa847a)
1d7b241e6Sjeremylt // Copyright (c) 2017, Lawrence Livermore National Security, LLC. Produced at
2d7b241e6Sjeremylt // the Lawrence Livermore National Laboratory. LLNL-CODE-734707. All Rights
3d7b241e6Sjeremylt // reserved. See files LICENSE and NOTICE for details.
4d7b241e6Sjeremylt //
5d7b241e6Sjeremylt // This file is part of CEED, a collection of benchmarks, miniapps, software
6d7b241e6Sjeremylt // libraries and APIs for efficient high-order finite element and spectral
7d7b241e6Sjeremylt // element discretizations for exascale applications. For more information and
8d7b241e6Sjeremylt // source code availability see http://github.com/ceed.
9d7b241e6Sjeremylt //
10d7b241e6Sjeremylt // The CEED research is supported by the Exascale Computing Project 17-SC-20-SC,
11d7b241e6Sjeremylt // a collaborative effort of two U.S. Department of Energy organizations (Office
12d7b241e6Sjeremylt // of Science and the National Nuclear Security Administration) responsible for
13d7b241e6Sjeremylt // the planning and preparation of a capable exascale ecosystem, including
14d7b241e6Sjeremylt // software, applications, hardware, advanced system engineering and early
15d7b241e6Sjeremylt // testbed platforms, in support of the nation's exascale computing imperative.
16d7b241e6Sjeremylt 
17ec3da8bcSJed Brown #include <ceed/ceed.h>
18ec3da8bcSJed Brown #include <ceed/backend.h>
193d576824SJeremy L Thompson #include <ceed-impl.h>
203bd813ffSjeremylt #include <math.h>
213d576824SJeremy L Thompson #include <stdbool.h>
223d576824SJeremy L Thompson #include <stdio.h>
233d576824SJeremy L Thompson #include <string.h>
24d7b241e6Sjeremylt 
25dfdf5a53Sjeremylt /// @file
267a982d89SJeremy L. Thompson /// Implementation of CeedOperator interfaces
277a982d89SJeremy L. Thompson 
287a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
297a982d89SJeremy L. Thompson /// CeedOperator Library Internal Functions
307a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
317a982d89SJeremy L. Thompson /// @addtogroup CeedOperatorDeveloper
327a982d89SJeremy L. Thompson /// @{
337a982d89SJeremy L. Thompson 
347a982d89SJeremy L. Thompson /**
357a982d89SJeremy L. Thompson   @brief Duplicate a CeedOperator with a reference Ceed to fallback for advanced
367a982d89SJeremy L. Thompson            CeedOperator functionality
377a982d89SJeremy L. Thompson 
387a982d89SJeremy L. Thompson   @param op  CeedOperator to create fallback for
397a982d89SJeremy L. Thompson 
407a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
417a982d89SJeremy L. Thompson 
427a982d89SJeremy L. Thompson   @ref Developer
437a982d89SJeremy L. Thompson **/
447a982d89SJeremy L. Thompson int CeedOperatorCreateFallback(CeedOperator op) {
457a982d89SJeremy L. Thompson   int ierr;
467a982d89SJeremy L. Thompson 
477a982d89SJeremy L. Thompson   // Fallback Ceed
48*d1d35e2fSjeremylt   const char *resource, *fallback_resource;
497a982d89SJeremy L. Thompson   ierr = CeedGetResource(op->ceed, &resource); CeedChk(ierr);
50*d1d35e2fSjeremylt   ierr = CeedGetOperatorFallbackResource(op->ceed, &fallback_resource);
517a982d89SJeremy L. Thompson   CeedChk(ierr);
52*d1d35e2fSjeremylt   if (!strcmp(resource, fallback_resource))
537a982d89SJeremy L. Thompson     // LCOV_EXCL_START
54e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED,
55e15f9bd0SJeremy L Thompson                      "Backend %s cannot create an operator"
56*d1d35e2fSjeremylt                      "fallback to resource %s", resource, fallback_resource);
577a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
587a982d89SJeremy L. Thompson 
597a982d89SJeremy L. Thompson   // Fallback Ceed
60*d1d35e2fSjeremylt   Ceed ceed_ref;
61*d1d35e2fSjeremylt   if (!op->ceed->op_fallback_ceed) {
62*d1d35e2fSjeremylt     ierr = CeedInit(fallback_resource, &ceed_ref); CeedChk(ierr);
63*d1d35e2fSjeremylt     ceed_ref->op_fallback_parent = op->ceed;
64*d1d35e2fSjeremylt     ceed_ref->Error = op->ceed->Error;
65*d1d35e2fSjeremylt     op->ceed->op_fallback_ceed = ceed_ref;
667a982d89SJeremy L. Thompson   }
67*d1d35e2fSjeremylt   ceed_ref = op->ceed->op_fallback_ceed;
687a982d89SJeremy L. Thompson 
697a982d89SJeremy L. Thompson   // Clone Op
70*d1d35e2fSjeremylt   CeedOperator op_ref;
71*d1d35e2fSjeremylt   ierr = CeedCalloc(1, &op_ref); CeedChk(ierr);
72*d1d35e2fSjeremylt   memcpy(op_ref, op, sizeof(*op_ref));
73*d1d35e2fSjeremylt   op_ref->data = NULL;
74*d1d35e2fSjeremylt   op_ref->interface_setup = false;
75*d1d35e2fSjeremylt   op_ref->backend_setup = false;
76*d1d35e2fSjeremylt   op_ref->ceed = ceed_ref;
77*d1d35e2fSjeremylt   ierr = ceed_ref->OperatorCreate(op_ref); CeedChk(ierr);
78*d1d35e2fSjeremylt   op->op_fallback = op_ref;
797a982d89SJeremy L. Thompson 
807a982d89SJeremy L. Thompson   // Clone QF
81*d1d35e2fSjeremylt   CeedQFunction qf_ref;
82*d1d35e2fSjeremylt   ierr = CeedCalloc(1, &qf_ref); CeedChk(ierr);
83*d1d35e2fSjeremylt   memcpy(qf_ref, (op->qf), sizeof(*qf_ref));
84*d1d35e2fSjeremylt   qf_ref->data = NULL;
85*d1d35e2fSjeremylt   qf_ref->ceed = ceed_ref;
86*d1d35e2fSjeremylt   ierr = ceed_ref->QFunctionCreate(qf_ref); CeedChk(ierr);
87*d1d35e2fSjeremylt   op_ref->qf = qf_ref;
88*d1d35e2fSjeremylt   op->qf_fallback = qf_ref;
89e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
90e15f9bd0SJeremy L Thompson }
917a982d89SJeremy L. Thompson 
92e15f9bd0SJeremy L Thompson /**
93e15f9bd0SJeremy L Thompson   @brief Check if a CeedOperator Field matches the QFunction Field
94e15f9bd0SJeremy L Thompson 
95e15f9bd0SJeremy L Thompson   @param[in] ceed      Ceed object for error handling
96*d1d35e2fSjeremylt   @param[in] qf_field  QFunction Field matching Operator Field
97e15f9bd0SJeremy L Thompson   @param[in] r         Operator Field ElemRestriction
98e15f9bd0SJeremy L Thompson   @param[in] b         Operator Field Basis
99e15f9bd0SJeremy L Thompson 
100e15f9bd0SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
101e15f9bd0SJeremy L Thompson 
102e15f9bd0SJeremy L Thompson   @ref Developer
103e15f9bd0SJeremy L Thompson **/
104*d1d35e2fSjeremylt static int CeedOperatorCheckField(Ceed ceed, CeedQFunctionField qf_field,
105e15f9bd0SJeremy L Thompson                                   CeedElemRestriction r, CeedBasis b) {
106e15f9bd0SJeremy L Thompson   int ierr;
107*d1d35e2fSjeremylt   CeedEvalMode eval_mode = qf_field->eval_mode;
108*d1d35e2fSjeremylt   CeedInt dim = 1, num_comp = 1, restr_num_comp = 1, size = qf_field->size;
109e15f9bd0SJeremy L Thompson   // Restriction
110e15f9bd0SJeremy L Thompson   if (r != CEED_ELEMRESTRICTION_NONE) {
111*d1d35e2fSjeremylt     if (eval_mode == CEED_EVAL_WEIGHT) {
112e15f9bd0SJeremy L Thompson       // LCOV_EXCL_START
113e1e9e29dSJed Brown       return CeedError(ceed, CEED_ERROR_INCOMPATIBLE,
114e1e9e29dSJed Brown                        "CEED_ELEMRESTRICTION_NONE should be used "
115e15f9bd0SJeremy L Thompson                        "for a field with eval mode CEED_EVAL_WEIGHT");
116e15f9bd0SJeremy L Thompson       // LCOV_EXCL_STOP
117e15f9bd0SJeremy L Thompson     }
118*d1d35e2fSjeremylt     ierr = CeedElemRestrictionGetNumComponents(r, &restr_num_comp);
119e1e9e29dSJed Brown   }
120*d1d35e2fSjeremylt   if ((r == CEED_ELEMRESTRICTION_NONE) != (eval_mode == 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) {
129*d1d35e2fSjeremylt     if (eval_mode == CEED_EVAL_NONE)
130e1e9e29dSJed Brown       return CeedError(ceed, CEED_ERROR_INCOMPATIBLE,
131*d1d35e2fSjeremylt                        "Field '%s' configured with CEED_EVAL_NONE must "
132*d1d35e2fSjeremylt                        "be used with CEED_BASIS_COLLOCATED",
133*d1d35e2fSjeremylt                        qf_field->field_name);
134e15f9bd0SJeremy L Thompson     ierr = CeedBasisGetDimension(b, &dim); CeedChk(ierr);
135*d1d35e2fSjeremylt     ierr = CeedBasisGetNumComponents(b, &num_comp); CeedChk(ierr);
136*d1d35e2fSjeremylt     if (r != CEED_ELEMRESTRICTION_NONE && restr_num_comp != num_comp) {
137e15f9bd0SJeremy L Thompson       // LCOV_EXCL_START
138e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_DIMENSION,
139*d1d35e2fSjeremylt                        "Field '%s' of size %d and EvalMode %s: ElemRestriction "
140*d1d35e2fSjeremylt                        "has %d components, but Basis has %d components",
141*d1d35e2fSjeremylt                        qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode],
142*d1d35e2fSjeremylt                        restr_num_comp,
143*d1d35e2fSjeremylt                        num_comp);
144e15f9bd0SJeremy L Thompson       // LCOV_EXCL_STOP
145e15f9bd0SJeremy L Thompson     }
146e15f9bd0SJeremy L Thompson   }
147e15f9bd0SJeremy L Thompson   // Field size
148*d1d35e2fSjeremylt   switch(eval_mode) {
149e15f9bd0SJeremy L Thompson   case CEED_EVAL_NONE:
150*d1d35e2fSjeremylt     if (size != restr_num_comp)
151e15f9bd0SJeremy L Thompson       // LCOV_EXCL_START
152e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_DIMENSION,
153e1e9e29dSJed Brown                        "Field '%s' of size %d and EvalMode %s: ElemRestriction has %d components",
154*d1d35e2fSjeremylt                        qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode],
155*d1d35e2fSjeremylt                        restr_num_comp);
156e15f9bd0SJeremy L Thompson     // LCOV_EXCL_STOP
157e15f9bd0SJeremy L Thompson     break;
158e15f9bd0SJeremy L Thompson   case CEED_EVAL_INTERP:
159*d1d35e2fSjeremylt     if (size != num_comp)
160e15f9bd0SJeremy L Thompson       // LCOV_EXCL_START
161e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_DIMENSION,
162e1e9e29dSJed Brown                        "Field '%s' of size %d and EvalMode %s: ElemRestriction/Basis has %d components",
163*d1d35e2fSjeremylt                        qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode],
164*d1d35e2fSjeremylt                        num_comp);
165e15f9bd0SJeremy L Thompson     // LCOV_EXCL_STOP
166e15f9bd0SJeremy L Thompson     break;
167e15f9bd0SJeremy L Thompson   case CEED_EVAL_GRAD:
168*d1d35e2fSjeremylt     if (size != num_comp * dim)
169e15f9bd0SJeremy L Thompson       // LCOV_EXCL_START
170e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_DIMENSION,
171*d1d35e2fSjeremylt                        "Field '%s' of size %d and EvalMode %s in %d dimensions: "
172*d1d35e2fSjeremylt                        "ElemRestriction/Basis has %d components",
173*d1d35e2fSjeremylt                        qf_field->field_name, qf_field->size, CeedEvalModes[qf_field->eval_mode], dim,
174*d1d35e2fSjeremylt                        num_comp);
175e15f9bd0SJeremy L Thompson     // LCOV_EXCL_STOP
176e15f9bd0SJeremy L Thompson     break;
177e15f9bd0SJeremy L Thompson   case CEED_EVAL_WEIGHT:
178*d1d35e2fSjeremylt     // No additional checks required
179e15f9bd0SJeremy L Thompson     break;
180e15f9bd0SJeremy L Thompson   case CEED_EVAL_DIV:
181e15f9bd0SJeremy L Thompson     // Not implemented
182e15f9bd0SJeremy L Thompson     break;
183e15f9bd0SJeremy L Thompson   case CEED_EVAL_CURL:
184e15f9bd0SJeremy L Thompson     // Not implemented
185e15f9bd0SJeremy L Thompson     break;
186e15f9bd0SJeremy L Thompson   }
187e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1887a982d89SJeremy L. Thompson }
1897a982d89SJeremy L. Thompson 
1907a982d89SJeremy L. Thompson /**
1917a982d89SJeremy L. Thompson   @brief Check if a CeedOperator is ready to be used.
1927a982d89SJeremy L. Thompson 
1937a982d89SJeremy L. Thompson   @param[in] op  CeedOperator to check
1947a982d89SJeremy L. Thompson 
1957a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
1967a982d89SJeremy L. Thompson 
1977a982d89SJeremy L. Thompson   @ref Developer
1987a982d89SJeremy L. Thompson **/
199e2f04181SAndrew T. Barker static int CeedOperatorCheckReady(CeedOperator op) {
200e2f04181SAndrew T. Barker   int ierr;
201e2f04181SAndrew T. Barker   Ceed ceed;
202e2f04181SAndrew T. Barker   ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr);
203e2f04181SAndrew T. Barker 
204*d1d35e2fSjeremylt   if (op->interface_setup)
205e15f9bd0SJeremy L Thompson     return CEED_ERROR_SUCCESS;
2067a982d89SJeremy L. Thompson 
207e15f9bd0SJeremy L Thompson   CeedQFunction qf = op->qf;
2087a982d89SJeremy L. Thompson   if (op->composite) {
209*d1d35e2fSjeremylt     if (!op->num_suboperators)
2107a982d89SJeremy L. Thompson       // LCOV_EXCL_START
211*d1d35e2fSjeremylt       return CeedError(ceed, CEED_ERROR_INCOMPLETE, "No sub_operators set");
2127a982d89SJeremy L. Thompson     // LCOV_EXCL_STOP
2137a982d89SJeremy L. Thompson   } else {
214*d1d35e2fSjeremylt     if (op->num_fields == 0)
2157a982d89SJeremy L. Thompson       // LCOV_EXCL_START
216e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_INCOMPLETE, "No operator fields set");
2177a982d89SJeremy L. Thompson     // LCOV_EXCL_STOP
218*d1d35e2fSjeremylt     if (op->num_fields < qf->num_input_fields + qf->num_output_fields)
2197a982d89SJeremy L. Thompson       // LCOV_EXCL_START
220e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_INCOMPLETE, "Not all operator fields set");
2217a982d89SJeremy L. Thompson     // LCOV_EXCL_STOP
222*d1d35e2fSjeremylt     if (!op->has_restriction)
2237a982d89SJeremy L. Thompson       // LCOV_EXCL_START
224e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_INCOMPLETE,
225e15f9bd0SJeremy L Thompson                        "At least one restriction required");
2267a982d89SJeremy L. Thompson     // LCOV_EXCL_STOP
227*d1d35e2fSjeremylt     if (op->num_qpts == 0)
2287a982d89SJeremy L. Thompson       // LCOV_EXCL_START
229e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_INCOMPLETE,
230e15f9bd0SJeremy L Thompson                        "At least one non-collocated basis required");
2317a982d89SJeremy L. Thompson     // LCOV_EXCL_STOP
2327a982d89SJeremy L. Thompson   }
2337a982d89SJeremy L. Thompson 
234e15f9bd0SJeremy L Thompson   // Flag as immutable and ready
235*d1d35e2fSjeremylt   op->interface_setup = true;
236e15f9bd0SJeremy L Thompson   if (op->qf && op->qf != CEED_QFUNCTION_NONE)
237e15f9bd0SJeremy L Thompson     // LCOV_EXCL_START
238*d1d35e2fSjeremylt     op->qf->operators_set++;
239e15f9bd0SJeremy L Thompson   // LCOV_EXCL_STOP
240e15f9bd0SJeremy L Thompson   if (op->dqf && op->dqf != CEED_QFUNCTION_NONE)
241e15f9bd0SJeremy L Thompson     // LCOV_EXCL_START
242*d1d35e2fSjeremylt     op->dqf->operators_set++;
243e15f9bd0SJeremy L Thompson   // LCOV_EXCL_STOP
244e15f9bd0SJeremy L Thompson   if (op->dqfT && op->dqfT != CEED_QFUNCTION_NONE)
245e15f9bd0SJeremy L Thompson     // LCOV_EXCL_START
246*d1d35e2fSjeremylt     op->dqfT->operators_set++;
247e15f9bd0SJeremy L Thompson   // LCOV_EXCL_STOP
248e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2497a982d89SJeremy L. Thompson }
2507a982d89SJeremy L. Thompson 
2517a982d89SJeremy L. Thompson /**
2527a982d89SJeremy L. Thompson   @brief View a field of a CeedOperator
2537a982d89SJeremy L. Thompson 
2547a982d89SJeremy L. Thompson   @param[in] field         Operator field to view
255*d1d35e2fSjeremylt   @param[in] qf_field      QFunction field (carries field name)
256*d1d35e2fSjeremylt   @param[in] field_number  Number of field being viewed
2574c4400c7SValeria Barra   @param[in] sub           true indicates sub-operator, which increases indentation; false for top-level operator
258*d1d35e2fSjeremylt   @param[in] input         true for an input field; false for output field
2597a982d89SJeremy L. Thompson   @param[in] stream        Stream to view to, e.g., stdout
2607a982d89SJeremy L. Thompson 
2617a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
2627a982d89SJeremy L. Thompson 
2637a982d89SJeremy L. Thompson   @ref Utility
2647a982d89SJeremy L. Thompson **/
2657a982d89SJeremy L. Thompson static int CeedOperatorFieldView(CeedOperatorField field,
266*d1d35e2fSjeremylt                                  CeedQFunctionField qf_field,
267*d1d35e2fSjeremylt                                  CeedInt field_number, bool sub, bool input,
2687a982d89SJeremy L. Thompson                                  FILE *stream) {
2697a982d89SJeremy L. Thompson   const char *pre = sub ? "  " : "";
270*d1d35e2fSjeremylt   const char *in_out = input ? "Input" : "Output";
2717a982d89SJeremy L. Thompson 
2727a982d89SJeremy L. Thompson   fprintf(stream, "%s    %s Field [%d]:\n"
2737a982d89SJeremy L. Thompson           "%s      Name: \"%s\"\n",
274*d1d35e2fSjeremylt           pre, in_out, field_number, pre, qf_field->field_name);
2757a982d89SJeremy L. Thompson 
2767a982d89SJeremy L. Thompson   if (field->basis == CEED_BASIS_COLLOCATED)
2777a982d89SJeremy L. Thompson     fprintf(stream, "%s      Collocated basis\n", pre);
2787a982d89SJeremy L. Thompson 
2797a982d89SJeremy L. Thompson   if (field->vec == CEED_VECTOR_ACTIVE)
2807a982d89SJeremy L. Thompson     fprintf(stream, "%s      Active vector\n", pre);
2817a982d89SJeremy L. Thompson   else if (field->vec == CEED_VECTOR_NONE)
2827a982d89SJeremy L. Thompson     fprintf(stream, "%s      No vector\n", pre);
283e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2847a982d89SJeremy L. Thompson }
2857a982d89SJeremy L. Thompson 
2867a982d89SJeremy L. Thompson /**
2877a982d89SJeremy L. Thompson   @brief View a single CeedOperator
2887a982d89SJeremy L. Thompson 
2897a982d89SJeremy L. Thompson   @param[in] op      CeedOperator to view
2907a982d89SJeremy L. Thompson   @param[in] sub     Boolean flag for sub-operator
2917a982d89SJeremy L. Thompson   @param[in] stream  Stream to write; typically stdout/stderr or a file
2927a982d89SJeremy L. Thompson 
2937a982d89SJeremy L. Thompson   @return Error code: 0 - success, otherwise - failure
2947a982d89SJeremy L. Thompson 
2957a982d89SJeremy L. Thompson   @ref Utility
2967a982d89SJeremy L. Thompson **/
2977a982d89SJeremy L. Thompson int CeedOperatorSingleView(CeedOperator op, bool sub, FILE *stream) {
2987a982d89SJeremy L. Thompson   int ierr;
2997a982d89SJeremy L. Thompson   const char *pre = sub ? "  " : "";
3007a982d89SJeremy L. Thompson 
3017a982d89SJeremy L. Thompson   CeedInt totalfields;
3027a982d89SJeremy L. Thompson   ierr = CeedOperatorGetNumArgs(op, &totalfields); CeedChk(ierr);
3037a982d89SJeremy L. Thompson 
3047a982d89SJeremy L. Thompson   fprintf(stream, "%s  %d Field%s\n", pre, totalfields, totalfields>1 ? "s" : "");
3057a982d89SJeremy L. Thompson 
306*d1d35e2fSjeremylt   fprintf(stream, "%s  %d Input Field%s:\n", pre, op->qf->num_input_fields,
307*d1d35e2fSjeremylt           op->qf->num_input_fields>1 ? "s" : "");
308*d1d35e2fSjeremylt   for (CeedInt i=0; i<op->qf->num_input_fields; i++) {
309*d1d35e2fSjeremylt     ierr = CeedOperatorFieldView(op->input_fields[i], op->qf->input_fields[i],
3107a982d89SJeremy L. Thompson                                  i, sub, 1, stream); CeedChk(ierr);
3117a982d89SJeremy L. Thompson   }
3127a982d89SJeremy L. Thompson 
313*d1d35e2fSjeremylt   fprintf(stream, "%s  %d Output Field%s:\n", pre, op->qf->num_output_fields,
314*d1d35e2fSjeremylt           op->qf->num_output_fields>1 ? "s" : "");
315*d1d35e2fSjeremylt   for (CeedInt i=0; i<op->qf->num_output_fields; i++) {
316*d1d35e2fSjeremylt     ierr = CeedOperatorFieldView(op->output_fields[i], op->qf->output_fields[i],
3177a982d89SJeremy L. Thompson                                  i, sub, 0, stream); CeedChk(ierr);
3187a982d89SJeremy L. Thompson   }
319e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
3207a982d89SJeremy L. Thompson }
3217a982d89SJeremy L. Thompson 
322d99fa3c5SJeremy L Thompson /**
323e2f04181SAndrew T. Barker   @brief Find the active vector ElemRestriction for a CeedOperator
324e2f04181SAndrew T. Barker 
325e2f04181SAndrew T. Barker   @param[in] op            CeedOperator to find active basis for
326*d1d35e2fSjeremylt   @param[out] active_rstr  ElemRestriction for active input vector
327e2f04181SAndrew T. Barker 
328e2f04181SAndrew T. Barker   @return An error code: 0 - success, otherwise - failure
329e2f04181SAndrew T. Barker 
330e2f04181SAndrew T. Barker   @ref Utility
331e2f04181SAndrew T. Barker **/
332e2f04181SAndrew T. Barker static int CeedOperatorGetActiveElemRestriction(CeedOperator op,
333*d1d35e2fSjeremylt     CeedElemRestriction *active_rstr) {
334*d1d35e2fSjeremylt   *active_rstr = NULL;
335*d1d35e2fSjeremylt   for (int i = 0; i < op->qf->num_input_fields; i++)
336*d1d35e2fSjeremylt     if (op->input_fields[i]->vec == CEED_VECTOR_ACTIVE) {
337*d1d35e2fSjeremylt       *active_rstr = op->input_fields[i]->elem_restr;
338e2f04181SAndrew T. Barker       break;
339e2f04181SAndrew T. Barker     }
340e2f04181SAndrew T. Barker 
341*d1d35e2fSjeremylt   if (!*active_rstr) {
342e2f04181SAndrew T. Barker     // LCOV_EXCL_START
343e2f04181SAndrew T. Barker     int ierr;
344e2f04181SAndrew T. Barker     Ceed ceed;
345e2f04181SAndrew T. Barker     ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr);
346e2f04181SAndrew T. Barker     return CeedError(ceed, CEED_ERROR_INCOMPLETE,
347e2f04181SAndrew T. Barker                      "No active ElemRestriction found!");
348e2f04181SAndrew T. Barker     // LCOV_EXCL_STOP
349e2f04181SAndrew T. Barker   }
350e2f04181SAndrew T. Barker   return CEED_ERROR_SUCCESS;
351e2f04181SAndrew T. Barker }
352e2f04181SAndrew T. Barker 
353e2f04181SAndrew T. Barker /**
354d99fa3c5SJeremy L Thompson   @brief Find the active vector basis for a CeedOperator
355d99fa3c5SJeremy L Thompson 
356d99fa3c5SJeremy L Thompson   @param[in] op             CeedOperator to find active basis for
357*d1d35e2fSjeremylt   @param[out] active_basis  Basis for active input vector
358d99fa3c5SJeremy L Thompson 
359d99fa3c5SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
360d99fa3c5SJeremy L Thompson 
361d99fa3c5SJeremy L Thompson   @ ref Developer
362d99fa3c5SJeremy L Thompson **/
363d99fa3c5SJeremy L Thompson static int CeedOperatorGetActiveBasis(CeedOperator op,
364*d1d35e2fSjeremylt                                       CeedBasis *active_basis) {
365*d1d35e2fSjeremylt   *active_basis = NULL;
366*d1d35e2fSjeremylt   for (int i = 0; i < op->qf->num_input_fields; i++)
367*d1d35e2fSjeremylt     if (op->input_fields[i]->vec == CEED_VECTOR_ACTIVE) {
368*d1d35e2fSjeremylt       *active_basis = op->input_fields[i]->basis;
369d99fa3c5SJeremy L Thompson       break;
370d99fa3c5SJeremy L Thompson     }
371d99fa3c5SJeremy L Thompson 
372*d1d35e2fSjeremylt   if (!*active_basis) {
373d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
374d99fa3c5SJeremy L Thompson     int ierr;
375d99fa3c5SJeremy L Thompson     Ceed ceed;
376d99fa3c5SJeremy L Thompson     ierr = CeedOperatorGetCeed(op, &ceed); CeedChk(ierr);
377e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_MINOR,
378d99fa3c5SJeremy L Thompson                      "No active basis found for automatic multigrid setup");
379d99fa3c5SJeremy L Thompson     // LCOV_EXCL_STOP
380d99fa3c5SJeremy L Thompson   }
381e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
382d99fa3c5SJeremy L Thompson }
383d99fa3c5SJeremy L Thompson 
384d99fa3c5SJeremy L Thompson /**
385d99fa3c5SJeremy L Thompson   @brief Common code for creating a multigrid coarse operator and level
386d99fa3c5SJeremy L Thompson            transfer operators for a CeedOperator
387d99fa3c5SJeremy L Thompson 
388*d1d35e2fSjeremylt   @param[in] op_fine       Fine grid operator
389*d1d35e2fSjeremylt   @param[in] p_mult_fine   L-vector multiplicity in parallel gather/scatter
390*d1d35e2fSjeremylt   @param[in] rstr_coarse   Coarse grid restriction
391*d1d35e2fSjeremylt   @param[in] basis_coarse  Coarse grid active vector basis
392*d1d35e2fSjeremylt   @param[in] basis_c_to_f  Basis for coarse to fine interpolation
393*d1d35e2fSjeremylt   @param[out] op_coarse    Coarse grid operator
394*d1d35e2fSjeremylt   @param[out] op_prolong   Coarse to fine operator
395*d1d35e2fSjeremylt   @param[out] op_restrict  Fine to coarse operator
396d99fa3c5SJeremy L Thompson 
397d99fa3c5SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
398d99fa3c5SJeremy L Thompson 
399d99fa3c5SJeremy L Thompson   @ref Developer
400d99fa3c5SJeremy L Thompson **/
401*d1d35e2fSjeremylt static int CeedOperatorMultigridLevel_Core(CeedOperator op_fine,
402*d1d35e2fSjeremylt     CeedVector p_mult_fine, CeedElemRestriction rstr_coarse, CeedBasis basis_coarse,
403*d1d35e2fSjeremylt     CeedBasis basis_c_to_f, CeedOperator *op_coarse, CeedOperator *op_prolong,
404*d1d35e2fSjeremylt     CeedOperator *op_restrict) {
405d99fa3c5SJeremy L Thompson   int ierr;
406d99fa3c5SJeremy L Thompson   Ceed ceed;
407*d1d35e2fSjeremylt   ierr = CeedOperatorGetCeed(op_fine, &ceed); CeedChk(ierr);
408d99fa3c5SJeremy L Thompson 
409d99fa3c5SJeremy L Thompson   // Check for composite operator
410*d1d35e2fSjeremylt   bool is_composite;
411*d1d35e2fSjeremylt   ierr = CeedOperatorIsComposite(op_fine, &is_composite); CeedChk(ierr);
412*d1d35e2fSjeremylt   if (is_composite)
413d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
414e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_UNSUPPORTED,
415d99fa3c5SJeremy L Thompson                      "Automatic multigrid setup for composite operators not supported");
416d99fa3c5SJeremy L Thompson   // LCOV_EXCL_STOP
417d99fa3c5SJeremy L Thompson 
418d99fa3c5SJeremy L Thompson   // Coarse Grid
419*d1d35e2fSjeremylt   ierr = CeedOperatorCreate(ceed, op_fine->qf, op_fine->dqf, op_fine->dqfT,
420*d1d35e2fSjeremylt                             op_coarse); CeedChk(ierr);
421*d1d35e2fSjeremylt   CeedElemRestriction rstr_fine = NULL;
422d99fa3c5SJeremy L Thompson   // -- Clone input fields
423*d1d35e2fSjeremylt   for (int i = 0; i < op_fine->qf->num_input_fields; i++) {
424*d1d35e2fSjeremylt     if (op_fine->input_fields[i]->vec == CEED_VECTOR_ACTIVE) {
425*d1d35e2fSjeremylt       rstr_fine = op_fine->input_fields[i]->elem_restr;
426*d1d35e2fSjeremylt       ierr = CeedOperatorSetField(*op_coarse, op_fine->input_fields[i]->field_name,
427*d1d35e2fSjeremylt                                   rstr_coarse, basis_coarse, CEED_VECTOR_ACTIVE);
428d99fa3c5SJeremy L Thompson       CeedChk(ierr);
429d99fa3c5SJeremy L Thompson     } else {
430*d1d35e2fSjeremylt       ierr = CeedOperatorSetField(*op_coarse, op_fine->input_fields[i]->field_name,
431*d1d35e2fSjeremylt                                   op_fine->input_fields[i]->elem_restr,
432*d1d35e2fSjeremylt                                   op_fine->input_fields[i]->basis,
433*d1d35e2fSjeremylt                                   op_fine->input_fields[i]->vec); CeedChk(ierr);
434d99fa3c5SJeremy L Thompson     }
435d99fa3c5SJeremy L Thompson   }
436d99fa3c5SJeremy L Thompson   // -- Clone output fields
437*d1d35e2fSjeremylt   for (int i = 0; i < op_fine->qf->num_output_fields; i++) {
438*d1d35e2fSjeremylt     if (op_fine->output_fields[i]->vec == CEED_VECTOR_ACTIVE) {
439*d1d35e2fSjeremylt       ierr = CeedOperatorSetField(*op_coarse, op_fine->output_fields[i]->field_name,
440*d1d35e2fSjeremylt                                   rstr_coarse, basis_coarse, CEED_VECTOR_ACTIVE);
441d99fa3c5SJeremy L Thompson       CeedChk(ierr);
442d99fa3c5SJeremy L Thompson     } else {
443*d1d35e2fSjeremylt       ierr = CeedOperatorSetField(*op_coarse, op_fine->output_fields[i]->field_name,
444*d1d35e2fSjeremylt                                   op_fine->output_fields[i]->elem_restr,
445*d1d35e2fSjeremylt                                   op_fine->output_fields[i]->basis,
446*d1d35e2fSjeremylt                                   op_fine->output_fields[i]->vec); CeedChk(ierr);
447d99fa3c5SJeremy L Thompson     }
448d99fa3c5SJeremy L Thompson   }
449d99fa3c5SJeremy L Thompson 
450d99fa3c5SJeremy L Thompson   // Multiplicity vector
451*d1d35e2fSjeremylt   CeedVector mult_vec, mult_e_vec;
452*d1d35e2fSjeremylt   ierr = CeedElemRestrictionCreateVector(rstr_fine, &mult_vec, &mult_e_vec);
453d99fa3c5SJeremy L Thompson   CeedChk(ierr);
454*d1d35e2fSjeremylt   ierr = CeedVectorSetValue(mult_e_vec, 0.0); CeedChk(ierr);
455*d1d35e2fSjeremylt   ierr = CeedElemRestrictionApply(rstr_fine, CEED_NOTRANSPOSE, p_mult_fine,
456*d1d35e2fSjeremylt                                   mult_e_vec, CEED_REQUEST_IMMEDIATE); CeedChk(ierr);
457*d1d35e2fSjeremylt   ierr = CeedVectorSetValue(mult_vec, 0.0); CeedChk(ierr);
458*d1d35e2fSjeremylt   ierr = CeedElemRestrictionApply(rstr_fine, CEED_TRANSPOSE, mult_e_vec, mult_vec,
459d99fa3c5SJeremy L Thompson                                   CEED_REQUEST_IMMEDIATE); CeedChk(ierr);
460*d1d35e2fSjeremylt   ierr = CeedVectorDestroy(&mult_e_vec); CeedChk(ierr);
461*d1d35e2fSjeremylt   ierr = CeedVectorReciprocal(mult_vec); CeedChk(ierr);
462d99fa3c5SJeremy L Thompson 
463d99fa3c5SJeremy L Thompson   // Restriction
464*d1d35e2fSjeremylt   CeedInt num_comp;
465*d1d35e2fSjeremylt   ierr = CeedBasisGetNumComponents(basis_coarse, &num_comp); CeedChk(ierr);
466*d1d35e2fSjeremylt   CeedQFunction qf_restrict;
467*d1d35e2fSjeremylt   ierr = CeedQFunctionCreateInteriorByName(ceed, "Scale", &qf_restrict);
468d99fa3c5SJeremy L Thompson   CeedChk(ierr);
469*d1d35e2fSjeremylt   CeedInt *num_comp_r_data;
470*d1d35e2fSjeremylt   ierr = CeedCalloc(1, &num_comp_r_data); CeedChk(ierr);
471*d1d35e2fSjeremylt   num_comp_r_data[0] = num_comp;
472*d1d35e2fSjeremylt   CeedQFunctionContext ctx_r;
473*d1d35e2fSjeremylt   ierr = CeedQFunctionContextCreate(ceed, &ctx_r); CeedChk(ierr);
474*d1d35e2fSjeremylt   ierr = CeedQFunctionContextSetData(ctx_r, CEED_MEM_HOST, CEED_OWN_POINTER,
475*d1d35e2fSjeremylt                                      sizeof(*num_comp_r_data), num_comp_r_data);
476777ff853SJeremy L Thompson   CeedChk(ierr);
477*d1d35e2fSjeremylt   ierr = CeedQFunctionSetContext(qf_restrict, ctx_r); CeedChk(ierr);
478*d1d35e2fSjeremylt   ierr = CeedQFunctionContextDestroy(&ctx_r); CeedChk(ierr);
479*d1d35e2fSjeremylt   ierr = CeedQFunctionAddInput(qf_restrict, "input", num_comp, CEED_EVAL_NONE);
480d99fa3c5SJeremy L Thompson   CeedChk(ierr);
481*d1d35e2fSjeremylt   ierr = CeedQFunctionAddInput(qf_restrict, "scale", num_comp, CEED_EVAL_NONE);
482d99fa3c5SJeremy L Thompson   CeedChk(ierr);
483*d1d35e2fSjeremylt   ierr = CeedQFunctionAddOutput(qf_restrict, "output", num_comp,
484*d1d35e2fSjeremylt                                 CEED_EVAL_INTERP); CeedChk(ierr);
485d99fa3c5SJeremy L Thompson 
486*d1d35e2fSjeremylt   ierr = CeedOperatorCreate(ceed, qf_restrict, CEED_QFUNCTION_NONE,
487*d1d35e2fSjeremylt                             CEED_QFUNCTION_NONE, op_restrict);
488d99fa3c5SJeremy L Thompson   CeedChk(ierr);
489*d1d35e2fSjeremylt   ierr = CeedOperatorSetField(*op_restrict, "input", rstr_fine,
490d99fa3c5SJeremy L Thompson                               CEED_BASIS_COLLOCATED, CEED_VECTOR_ACTIVE);
491d99fa3c5SJeremy L Thompson   CeedChk(ierr);
492*d1d35e2fSjeremylt   ierr = CeedOperatorSetField(*op_restrict, "scale", rstr_fine,
493*d1d35e2fSjeremylt                               CEED_BASIS_COLLOCATED, mult_vec);
494d99fa3c5SJeremy L Thompson   CeedChk(ierr);
495*d1d35e2fSjeremylt   ierr = CeedOperatorSetField(*op_restrict, "output", rstr_coarse, basis_c_to_f,
496d99fa3c5SJeremy L Thompson                               CEED_VECTOR_ACTIVE); CeedChk(ierr);
497d99fa3c5SJeremy L Thompson 
498d99fa3c5SJeremy L Thompson   // Prolongation
499*d1d35e2fSjeremylt   CeedQFunction qf_prolong;
500*d1d35e2fSjeremylt   ierr = CeedQFunctionCreateInteriorByName(ceed, "Scale", &qf_prolong);
501d99fa3c5SJeremy L Thompson   CeedChk(ierr);
502*d1d35e2fSjeremylt   CeedInt *num_comp_p_data;
503*d1d35e2fSjeremylt   ierr = CeedCalloc(1, &num_comp_p_data); CeedChk(ierr);
504*d1d35e2fSjeremylt   num_comp_p_data[0] = num_comp;
505*d1d35e2fSjeremylt   CeedQFunctionContext ctx_p;
506*d1d35e2fSjeremylt   ierr = CeedQFunctionContextCreate(ceed, &ctx_p); CeedChk(ierr);
507*d1d35e2fSjeremylt   ierr = CeedQFunctionContextSetData(ctx_p, CEED_MEM_HOST, CEED_OWN_POINTER,
508*d1d35e2fSjeremylt                                      sizeof(*num_comp_p_data), num_comp_p_data);
509777ff853SJeremy L Thompson   CeedChk(ierr);
510*d1d35e2fSjeremylt   ierr = CeedQFunctionSetContext(qf_prolong, ctx_p); CeedChk(ierr);
511*d1d35e2fSjeremylt   ierr = CeedQFunctionContextDestroy(&ctx_p); CeedChk(ierr);
512*d1d35e2fSjeremylt   ierr = CeedQFunctionAddInput(qf_prolong, "input", num_comp, CEED_EVAL_INTERP);
513d99fa3c5SJeremy L Thompson   CeedChk(ierr);
514*d1d35e2fSjeremylt   ierr = CeedQFunctionAddInput(qf_prolong, "scale", num_comp, CEED_EVAL_NONE);
515d99fa3c5SJeremy L Thompson   CeedChk(ierr);
516*d1d35e2fSjeremylt   ierr = CeedQFunctionAddOutput(qf_prolong, "output", num_comp, CEED_EVAL_NONE);
517d99fa3c5SJeremy L Thompson   CeedChk(ierr);
518d99fa3c5SJeremy L Thompson 
519*d1d35e2fSjeremylt   ierr = CeedOperatorCreate(ceed, qf_prolong, CEED_QFUNCTION_NONE,
520*d1d35e2fSjeremylt                             CEED_QFUNCTION_NONE, op_prolong);
521d99fa3c5SJeremy L Thompson   CeedChk(ierr);
522*d1d35e2fSjeremylt   ierr = CeedOperatorSetField(*op_prolong, "input", rstr_coarse, basis_c_to_f,
523d99fa3c5SJeremy L Thompson                               CEED_VECTOR_ACTIVE); CeedChk(ierr);
524*d1d35e2fSjeremylt   ierr = CeedOperatorSetField(*op_prolong, "scale", rstr_fine,
525*d1d35e2fSjeremylt                               CEED_BASIS_COLLOCATED, mult_vec);
526d99fa3c5SJeremy L Thompson   CeedChk(ierr);
527*d1d35e2fSjeremylt   ierr = CeedOperatorSetField(*op_prolong, "output", rstr_fine,
528d99fa3c5SJeremy L Thompson                               CEED_BASIS_COLLOCATED, CEED_VECTOR_ACTIVE);
529d99fa3c5SJeremy L Thompson   CeedChk(ierr);
530d99fa3c5SJeremy L Thompson 
531d99fa3c5SJeremy L Thompson   // Cleanup
532*d1d35e2fSjeremylt   ierr = CeedVectorDestroy(&mult_vec); CeedChk(ierr);
533*d1d35e2fSjeremylt   ierr = CeedBasisDestroy(&basis_c_to_f); CeedChk(ierr);
534*d1d35e2fSjeremylt   ierr = CeedQFunctionDestroy(&qf_restrict); CeedChk(ierr);
535*d1d35e2fSjeremylt   ierr = CeedQFunctionDestroy(&qf_prolong); CeedChk(ierr);
536e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
537d99fa3c5SJeremy L Thompson }
538d99fa3c5SJeremy L Thompson 
5397a982d89SJeremy L. Thompson /// @}
5407a982d89SJeremy L. Thompson 
5417a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
5427a982d89SJeremy L. Thompson /// CeedOperator Backend API
5437a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
5447a982d89SJeremy L. Thompson /// @addtogroup CeedOperatorBackend
5457a982d89SJeremy L. Thompson /// @{
5467a982d89SJeremy L. Thompson 
5477a982d89SJeremy L. Thompson /**
5487a982d89SJeremy L. Thompson   @brief Get the Ceed associated with a CeedOperator
5497a982d89SJeremy L. Thompson 
5507a982d89SJeremy L. Thompson   @param op         CeedOperator
5517a982d89SJeremy L. Thompson   @param[out] ceed  Variable to store Ceed
5527a982d89SJeremy L. Thompson 
5537a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5547a982d89SJeremy L. Thompson 
5557a982d89SJeremy L. Thompson   @ref Backend
5567a982d89SJeremy L. Thompson **/
5577a982d89SJeremy L. Thompson 
5587a982d89SJeremy L. Thompson int CeedOperatorGetCeed(CeedOperator op, Ceed *ceed) {
5597a982d89SJeremy L. Thompson   *ceed = op->ceed;
560e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5617a982d89SJeremy L. Thompson }
5627a982d89SJeremy L. Thompson 
5637a982d89SJeremy L. Thompson /**
5647a982d89SJeremy L. Thompson   @brief Get the number of elements associated with a CeedOperator
5657a982d89SJeremy L. Thompson 
5667a982d89SJeremy L. Thompson   @param op             CeedOperator
567*d1d35e2fSjeremylt   @param[out] num_elem  Variable to store number of elements
5687a982d89SJeremy L. Thompson 
5697a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5707a982d89SJeremy L. Thompson 
5717a982d89SJeremy L. Thompson   @ref Backend
5727a982d89SJeremy L. Thompson **/
5737a982d89SJeremy L. Thompson 
574*d1d35e2fSjeremylt int CeedOperatorGetNumElements(CeedOperator op, CeedInt *num_elem) {
5757a982d89SJeremy L. Thompson   if (op->composite)
5767a982d89SJeremy L. Thompson     // LCOV_EXCL_START
577e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
578e15f9bd0SJeremy L Thompson                      "Not defined for composite operator");
5797a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
5807a982d89SJeremy L. Thompson 
581*d1d35e2fSjeremylt   *num_elem = op->num_elem;
582e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
5837a982d89SJeremy L. Thompson }
5847a982d89SJeremy L. Thompson 
5857a982d89SJeremy L. Thompson /**
5867a982d89SJeremy L. Thompson   @brief Get the number of quadrature points associated with a CeedOperator
5877a982d89SJeremy L. Thompson 
5887a982d89SJeremy L. Thompson   @param op             CeedOperator
589*d1d35e2fSjeremylt   @param[out] num_qpts  Variable to store vector number of quadrature points
5907a982d89SJeremy L. Thompson 
5917a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
5927a982d89SJeremy L. Thompson 
5937a982d89SJeremy L. Thompson   @ref Backend
5947a982d89SJeremy L. Thompson **/
5957a982d89SJeremy L. Thompson 
596*d1d35e2fSjeremylt int CeedOperatorGetNumQuadraturePoints(CeedOperator op, CeedInt *num_qpts) {
5977a982d89SJeremy L. Thompson   if (op->composite)
5987a982d89SJeremy L. Thompson     // LCOV_EXCL_START
599e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
600e15f9bd0SJeremy L Thompson                      "Not defined for composite operator");
6017a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
6027a982d89SJeremy L. Thompson 
603*d1d35e2fSjeremylt   *num_qpts = op->num_qpts;
604e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6057a982d89SJeremy L. Thompson }
6067a982d89SJeremy L. Thompson 
6077a982d89SJeremy L. Thompson /**
6087a982d89SJeremy L. Thompson   @brief Get the number of arguments associated with a CeedOperator
6097a982d89SJeremy L. Thompson 
6107a982d89SJeremy L. Thompson   @param op             CeedOperator
611*d1d35e2fSjeremylt   @param[out] num_args  Variable to store vector number of arguments
6127a982d89SJeremy L. Thompson 
6137a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6147a982d89SJeremy L. Thompson 
6157a982d89SJeremy L. Thompson   @ref Backend
6167a982d89SJeremy L. Thompson **/
6177a982d89SJeremy L. Thompson 
618*d1d35e2fSjeremylt int CeedOperatorGetNumArgs(CeedOperator op, CeedInt *num_args) {
6197a982d89SJeremy L. Thompson   if (op->composite)
6207a982d89SJeremy L. Thompson     // LCOV_EXCL_START
621e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
622e15f9bd0SJeremy L Thompson                      "Not defined for composite operators");
6237a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
6247a982d89SJeremy L. Thompson 
625*d1d35e2fSjeremylt   *num_args = op->num_fields;
626e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6277a982d89SJeremy L. Thompson }
6287a982d89SJeremy L. Thompson 
6297a982d89SJeremy L. Thompson /**
6307a982d89SJeremy L. Thompson   @brief Get the setup status of a CeedOperator
6317a982d89SJeremy L. Thompson 
6327a982d89SJeremy L. Thompson   @param op                  CeedOperator
633*d1d35e2fSjeremylt   @param[out] is_setup_done  Variable to store setup status
6347a982d89SJeremy L. Thompson 
6357a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6367a982d89SJeremy L. Thompson 
6377a982d89SJeremy L. Thompson   @ref Backend
6387a982d89SJeremy L. Thompson **/
6397a982d89SJeremy L. Thompson 
640*d1d35e2fSjeremylt int CeedOperatorIsSetupDone(CeedOperator op, bool *is_setup_done) {
641*d1d35e2fSjeremylt   *is_setup_done = op->backend_setup;
642e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6437a982d89SJeremy L. Thompson }
6447a982d89SJeremy L. Thompson 
6457a982d89SJeremy L. Thompson /**
6467a982d89SJeremy L. Thompson   @brief Get the QFunction associated with a CeedOperator
6477a982d89SJeremy L. Thompson 
6487a982d89SJeremy L. Thompson   @param op       CeedOperator
6497a982d89SJeremy L. Thompson   @param[out] qf  Variable to store QFunction
6507a982d89SJeremy L. Thompson 
6517a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6527a982d89SJeremy L. Thompson 
6537a982d89SJeremy L. Thompson   @ref Backend
6547a982d89SJeremy L. Thompson **/
6557a982d89SJeremy L. Thompson 
6567a982d89SJeremy L. Thompson int CeedOperatorGetQFunction(CeedOperator op, CeedQFunction *qf) {
6577a982d89SJeremy L. Thompson   if (op->composite)
6587a982d89SJeremy L. Thompson     // LCOV_EXCL_START
659e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
660e15f9bd0SJeremy L Thompson                      "Not defined for composite operator");
6617a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
6627a982d89SJeremy L. Thompson 
6637a982d89SJeremy L. Thompson   *qf = op->qf;
664e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6657a982d89SJeremy L. Thompson }
6667a982d89SJeremy L. Thompson 
6677a982d89SJeremy L. Thompson /**
668c04a41a7SJeremy L Thompson   @brief Get a boolean value indicating if the CeedOperator is composite
669c04a41a7SJeremy L Thompson 
670c04a41a7SJeremy L Thompson   @param op                 CeedOperator
671*d1d35e2fSjeremylt   @param[out] is_composite  Variable to store composite status
672c04a41a7SJeremy L Thompson 
673c04a41a7SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
674c04a41a7SJeremy L Thompson 
675c04a41a7SJeremy L Thompson   @ref Backend
676c04a41a7SJeremy L Thompson **/
677c04a41a7SJeremy L Thompson 
678*d1d35e2fSjeremylt int CeedOperatorIsComposite(CeedOperator op, bool *is_composite) {
679*d1d35e2fSjeremylt   *is_composite = op->composite;
680e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
681c04a41a7SJeremy L Thompson }
682c04a41a7SJeremy L Thompson 
683c04a41a7SJeremy L Thompson /**
684*d1d35e2fSjeremylt   @brief Get the number of sub_operators associated with a CeedOperator
6857a982d89SJeremy L. Thompson 
6867a982d89SJeremy L. Thompson   @param op                     CeedOperator
687*d1d35e2fSjeremylt   @param[out] num_suboperators  Variable to store number of sub_operators
6887a982d89SJeremy L. Thompson 
6897a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
6907a982d89SJeremy L. Thompson 
6917a982d89SJeremy L. Thompson   @ref Backend
6927a982d89SJeremy L. Thompson **/
6937a982d89SJeremy L. Thompson 
694*d1d35e2fSjeremylt int CeedOperatorGetNumSub(CeedOperator op, CeedInt *num_suboperators) {
6957a982d89SJeremy L. Thompson   if (!op->composite)
6967a982d89SJeremy L. Thompson     // LCOV_EXCL_START
697e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR, "Not a composite operator");
6987a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
6997a982d89SJeremy L. Thompson 
700*d1d35e2fSjeremylt   *num_suboperators = op->num_suboperators;
701e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
7027a982d89SJeremy L. Thompson }
7037a982d89SJeremy L. Thompson 
7047a982d89SJeremy L. Thompson /**
705*d1d35e2fSjeremylt   @brief Get the list of sub_operators associated with a CeedOperator
7067a982d89SJeremy L. Thompson 
7077a982d89SJeremy L. Thompson   @param op                  CeedOperator
708*d1d35e2fSjeremylt   @param[out] sub_operators  Variable to store list of sub_operators
7097a982d89SJeremy L. Thompson 
7107a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
7117a982d89SJeremy L. Thompson 
7127a982d89SJeremy L. Thompson   @ref Backend
7137a982d89SJeremy L. Thompson **/
7147a982d89SJeremy L. Thompson 
715*d1d35e2fSjeremylt int CeedOperatorGetSubList(CeedOperator op, CeedOperator **sub_operators) {
7167a982d89SJeremy L. Thompson   if (!op->composite)
7177a982d89SJeremy L. Thompson     // LCOV_EXCL_START
718e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR, "Not a composite operator");
7197a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
7207a982d89SJeremy L. Thompson 
721*d1d35e2fSjeremylt   *sub_operators = op->sub_operators;
722e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
7237a982d89SJeremy L. Thompson }
7247a982d89SJeremy L. Thompson 
7257a982d89SJeremy L. Thompson /**
7267a982d89SJeremy L. Thompson   @brief Get the backend data of a CeedOperator
7277a982d89SJeremy L. Thompson 
7287a982d89SJeremy L. Thompson   @param op         CeedOperator
7297a982d89SJeremy L. Thompson   @param[out] data  Variable to store data
7307a982d89SJeremy L. Thompson 
7317a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
7327a982d89SJeremy L. Thompson 
7337a982d89SJeremy L. Thompson   @ref Backend
7347a982d89SJeremy L. Thompson **/
7357a982d89SJeremy L. Thompson 
736777ff853SJeremy L Thompson int CeedOperatorGetData(CeedOperator op, void *data) {
737777ff853SJeremy L Thompson   *(void **)data = op->data;
738e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
7397a982d89SJeremy L. Thompson }
7407a982d89SJeremy L. Thompson 
7417a982d89SJeremy L. Thompson /**
7427a982d89SJeremy L. Thompson   @brief Set the backend data of a CeedOperator
7437a982d89SJeremy L. Thompson 
7447a982d89SJeremy L. Thompson   @param[out] op  CeedOperator
7457a982d89SJeremy L. Thompson   @param data     Data to set
7467a982d89SJeremy L. Thompson 
7477a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
7487a982d89SJeremy L. Thompson 
7497a982d89SJeremy L. Thompson   @ref Backend
7507a982d89SJeremy L. Thompson **/
7517a982d89SJeremy L. Thompson 
752777ff853SJeremy L Thompson int CeedOperatorSetData(CeedOperator op, void *data) {
753777ff853SJeremy L Thompson   op->data = data;
754e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
7557a982d89SJeremy L. Thompson }
7567a982d89SJeremy L. Thompson 
7577a982d89SJeremy L. Thompson /**
7587a982d89SJeremy L. Thompson   @brief Set the setup flag of a CeedOperator to True
7597a982d89SJeremy L. Thompson 
7607a982d89SJeremy L. Thompson   @param op  CeedOperator
7617a982d89SJeremy L. Thompson 
7627a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
7637a982d89SJeremy L. Thompson 
7647a982d89SJeremy L. Thompson   @ref Backend
7657a982d89SJeremy L. Thompson **/
7667a982d89SJeremy L. Thompson 
7677a982d89SJeremy L. Thompson int CeedOperatorSetSetupDone(CeedOperator op) {
768*d1d35e2fSjeremylt   op->backend_setup = true;
769e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
7707a982d89SJeremy L. Thompson }
7717a982d89SJeremy L. Thompson 
7727a982d89SJeremy L. Thompson /**
7737a982d89SJeremy L. Thompson   @brief Get the CeedOperatorFields of a CeedOperator
7747a982d89SJeremy L. Thompson 
7757a982d89SJeremy L. Thompson   @param op                  CeedOperator
776*d1d35e2fSjeremylt   @param[out] input_fields   Variable to store input_fields
777*d1d35e2fSjeremylt   @param[out] output_fields  Variable to store output_fields
7787a982d89SJeremy L. Thompson 
7797a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
7807a982d89SJeremy L. Thompson 
7817a982d89SJeremy L. Thompson   @ref Backend
7827a982d89SJeremy L. Thompson **/
7837a982d89SJeremy L. Thompson 
784*d1d35e2fSjeremylt int CeedOperatorGetFields(CeedOperator op, CeedOperatorField **input_fields,
785*d1d35e2fSjeremylt                           CeedOperatorField **output_fields) {
7867a982d89SJeremy L. Thompson   if (op->composite)
7877a982d89SJeremy L. Thompson     // LCOV_EXCL_START
788e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_MINOR,
789e15f9bd0SJeremy L Thompson                      "Not defined for composite operator");
7907a982d89SJeremy L. Thompson   // LCOV_EXCL_STOP
7917a982d89SJeremy L. Thompson 
792*d1d35e2fSjeremylt   if (input_fields) *input_fields = op->input_fields;
793*d1d35e2fSjeremylt   if (output_fields) *output_fields = op->output_fields;
794e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
7957a982d89SJeremy L. Thompson }
7967a982d89SJeremy L. Thompson 
7977a982d89SJeremy L. Thompson /**
7987a982d89SJeremy L. Thompson   @brief Get the CeedElemRestriction of a CeedOperatorField
7997a982d89SJeremy L. Thompson 
800*d1d35e2fSjeremylt   @param op_field   CeedOperatorField
8017a982d89SJeremy L. Thompson   @param[out] rstr  Variable to store CeedElemRestriction
8027a982d89SJeremy L. Thompson 
8037a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
8047a982d89SJeremy L. Thompson 
8057a982d89SJeremy L. Thompson   @ref Backend
8067a982d89SJeremy L. Thompson **/
8077a982d89SJeremy L. Thompson 
808*d1d35e2fSjeremylt int CeedOperatorFieldGetElemRestriction(CeedOperatorField op_field,
8097a982d89SJeremy L. Thompson                                         CeedElemRestriction *rstr) {
810*d1d35e2fSjeremylt   *rstr = op_field->elem_restr;
811e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
8127a982d89SJeremy L. Thompson }
8137a982d89SJeremy L. Thompson 
8147a982d89SJeremy L. Thompson /**
8157a982d89SJeremy L. Thompson   @brief Get the CeedBasis of a CeedOperatorField
8167a982d89SJeremy L. Thompson 
817*d1d35e2fSjeremylt   @param op_field    CeedOperatorField
8187a982d89SJeremy L. Thompson   @param[out] basis  Variable to store CeedBasis
8197a982d89SJeremy L. Thompson 
8207a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
8217a982d89SJeremy L. Thompson 
8227a982d89SJeremy L. Thompson   @ref Backend
8237a982d89SJeremy L. Thompson **/
8247a982d89SJeremy L. Thompson 
825*d1d35e2fSjeremylt int CeedOperatorFieldGetBasis(CeedOperatorField op_field, CeedBasis *basis) {
826*d1d35e2fSjeremylt   *basis = op_field->basis;
827e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
8287a982d89SJeremy L. Thompson }
8297a982d89SJeremy L. Thompson 
8307a982d89SJeremy L. Thompson /**
8317a982d89SJeremy L. Thompson   @brief Get the CeedVector of a CeedOperatorField
8327a982d89SJeremy L. Thompson 
833*d1d35e2fSjeremylt   @param op_field  CeedOperatorField
8347a982d89SJeremy L. Thompson   @param[out] vec  Variable to store CeedVector
8357a982d89SJeremy L. Thompson 
8367a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
8377a982d89SJeremy L. Thompson 
8387a982d89SJeremy L. Thompson   @ref Backend
8397a982d89SJeremy L. Thompson **/
8407a982d89SJeremy L. Thompson 
841*d1d35e2fSjeremylt int CeedOperatorFieldGetVector(CeedOperatorField op_field, CeedVector *vec) {
842*d1d35e2fSjeremylt   *vec = op_field->vec;
843e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
8447a982d89SJeremy L. Thompson }
8457a982d89SJeremy L. Thompson 
8467a982d89SJeremy L. Thompson /// @}
8477a982d89SJeremy L. Thompson 
8487a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
8497a982d89SJeremy L. Thompson /// CeedOperator Public API
8507a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
8517a982d89SJeremy L. Thompson /// @addtogroup CeedOperatorUser
852dfdf5a53Sjeremylt /// @{
853d7b241e6Sjeremylt 
854d7b241e6Sjeremylt /**
8550219ea01SJeremy L Thompson   @brief Create a CeedOperator and associate a CeedQFunction. A CeedBasis and
8560219ea01SJeremy L Thompson            CeedElemRestriction can be associated with CeedQFunction fields with
8570219ea01SJeremy L Thompson            \ref CeedOperatorSetField.
858d7b241e6Sjeremylt 
859b11c1e72Sjeremylt   @param ceed     A Ceed object where the CeedOperator will be created
860d7b241e6Sjeremylt   @param qf       QFunction defining the action of the operator at quadrature points
86134138859Sjeremylt   @param dqf      QFunction defining the action of the Jacobian of @a qf (or
8624cc79fe7SJed Brown                     @ref CEED_QFUNCTION_NONE)
863d7b241e6Sjeremylt   @param dqfT     QFunction defining the action of the transpose of the Jacobian
8644cc79fe7SJed Brown                     of @a qf (or @ref CEED_QFUNCTION_NONE)
865b11c1e72Sjeremylt   @param[out] op  Address of the variable where the newly created
866b11c1e72Sjeremylt                     CeedOperator will be stored
867b11c1e72Sjeremylt 
868b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
869dfdf5a53Sjeremylt 
8707a982d89SJeremy L. Thompson   @ref User
871d7b241e6Sjeremylt  */
872d7b241e6Sjeremylt int CeedOperatorCreate(Ceed ceed, CeedQFunction qf, CeedQFunction dqf,
873d7b241e6Sjeremylt                        CeedQFunction dqfT, CeedOperator *op) {
874d7b241e6Sjeremylt   int ierr;
875d7b241e6Sjeremylt 
8765fe0d4faSjeremylt   if (!ceed->OperatorCreate) {
8775fe0d4faSjeremylt     Ceed delegate;
878aefd8378Sjeremylt     ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr);
8795fe0d4faSjeremylt 
8805fe0d4faSjeremylt     if (!delegate)
881c042f62fSJeremy L Thompson       // LCOV_EXCL_START
882e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_UNSUPPORTED,
883e15f9bd0SJeremy L Thompson                        "Backend does not support OperatorCreate");
884c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
8855fe0d4faSjeremylt 
8865fe0d4faSjeremylt     ierr = CeedOperatorCreate(delegate, qf, dqf, dqfT, op); CeedChk(ierr);
887e15f9bd0SJeremy L Thompson     return CEED_ERROR_SUCCESS;
8885fe0d4faSjeremylt   }
8895fe0d4faSjeremylt 
890b3b7035fSJeremy L Thompson   if (!qf || qf == CEED_QFUNCTION_NONE)
891b3b7035fSJeremy L Thompson     // LCOV_EXCL_START
892e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_MINOR,
893e15f9bd0SJeremy L Thompson                      "Operator must have a valid QFunction.");
894b3b7035fSJeremy L Thompson   // LCOV_EXCL_STOP
895d7b241e6Sjeremylt   ierr = CeedCalloc(1, op); CeedChk(ierr);
896d7b241e6Sjeremylt   (*op)->ceed = ceed;
897*d1d35e2fSjeremylt   ceed->ref_count++;
898*d1d35e2fSjeremylt   (*op)->ref_count = 1;
899d7b241e6Sjeremylt   (*op)->qf = qf;
900*d1d35e2fSjeremylt   qf->ref_count++;
901442e7f0bSjeremylt   if (dqf && dqf != CEED_QFUNCTION_NONE) {
902d7b241e6Sjeremylt     (*op)->dqf = dqf;
903*d1d35e2fSjeremylt     dqf->ref_count++;
904442e7f0bSjeremylt   }
905442e7f0bSjeremylt   if (dqfT && dqfT != CEED_QFUNCTION_NONE) {
906d7b241e6Sjeremylt     (*op)->dqfT = dqfT;
907*d1d35e2fSjeremylt     dqfT->ref_count++;
908442e7f0bSjeremylt   }
909*d1d35e2fSjeremylt   ierr = CeedCalloc(16, &(*op)->input_fields); CeedChk(ierr);
910*d1d35e2fSjeremylt   ierr = CeedCalloc(16, &(*op)->output_fields); CeedChk(ierr);
911d7b241e6Sjeremylt   ierr = ceed->OperatorCreate(*op); CeedChk(ierr);
912e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
913d7b241e6Sjeremylt }
914d7b241e6Sjeremylt 
915d7b241e6Sjeremylt /**
91652d6035fSJeremy L Thompson   @brief Create an operator that composes the action of several operators
91752d6035fSJeremy L Thompson 
91852d6035fSJeremy L Thompson   @param ceed     A Ceed object where the CeedOperator will be created
91952d6035fSJeremy L Thompson   @param[out] op  Address of the variable where the newly created
92052d6035fSJeremy L Thompson                     Composite CeedOperator will be stored
92152d6035fSJeremy L Thompson 
92252d6035fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
92352d6035fSJeremy L Thompson 
9247a982d89SJeremy L. Thompson   @ref User
92552d6035fSJeremy L Thompson  */
92652d6035fSJeremy L Thompson int CeedCompositeOperatorCreate(Ceed ceed, CeedOperator *op) {
92752d6035fSJeremy L Thompson   int ierr;
92852d6035fSJeremy L Thompson 
92952d6035fSJeremy L Thompson   if (!ceed->CompositeOperatorCreate) {
93052d6035fSJeremy L Thompson     Ceed delegate;
931aefd8378Sjeremylt     ierr = CeedGetObjectDelegate(ceed, &delegate, "Operator"); CeedChk(ierr);
93252d6035fSJeremy L Thompson 
933250756a7Sjeremylt     if (delegate) {
93452d6035fSJeremy L Thompson       ierr = CeedCompositeOperatorCreate(delegate, op); CeedChk(ierr);
935e15f9bd0SJeremy L Thompson       return CEED_ERROR_SUCCESS;
93652d6035fSJeremy L Thompson     }
937250756a7Sjeremylt   }
93852d6035fSJeremy L Thompson 
93952d6035fSJeremy L Thompson   ierr = CeedCalloc(1, op); CeedChk(ierr);
94052d6035fSJeremy L Thompson   (*op)->ceed = ceed;
941*d1d35e2fSjeremylt   ceed->ref_count++;
94252d6035fSJeremy L Thompson   (*op)->composite = true;
943*d1d35e2fSjeremylt   ierr = CeedCalloc(16, &(*op)->sub_operators); CeedChk(ierr);
944250756a7Sjeremylt 
945250756a7Sjeremylt   if (ceed->CompositeOperatorCreate) {
94652d6035fSJeremy L Thompson     ierr = ceed->CompositeOperatorCreate(*op); CeedChk(ierr);
947250756a7Sjeremylt   }
948e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
94952d6035fSJeremy L Thompson }
95052d6035fSJeremy L Thompson 
95152d6035fSJeremy L Thompson /**
952b11c1e72Sjeremylt   @brief Provide a field to a CeedOperator for use by its CeedQFunction
953d7b241e6Sjeremylt 
954d7b241e6Sjeremylt   This function is used to specify both active and passive fields to a
955d7b241e6Sjeremylt   CeedOperator.  For passive fields, a vector @arg v must be provided.  Passive
956d7b241e6Sjeremylt   fields can inputs or outputs (updated in-place when operator is applied).
957d7b241e6Sjeremylt 
958d7b241e6Sjeremylt   Active fields must be specified using this function, but their data (in a
959d7b241e6Sjeremylt   CeedVector) is passed in CeedOperatorApply().  There can be at most one active
960d7b241e6Sjeremylt   input and at most one active output.
961d7b241e6Sjeremylt 
9628c91a0c9SJeremy L Thompson   @param op          CeedOperator on which to provide the field
963*d1d35e2fSjeremylt   @param field_name  Name of the field (to be matched with the name used by
9648795c945Sjeremylt                        CeedQFunction)
965b11c1e72Sjeremylt   @param r           CeedElemRestriction
9664cc79fe7SJed Brown   @param b           CeedBasis in which the field resides or @ref CEED_BASIS_COLLOCATED
967b11c1e72Sjeremylt                        if collocated with quadrature points
9684cc79fe7SJed Brown   @param v           CeedVector to be used by CeedOperator or @ref CEED_VECTOR_ACTIVE
9694cc79fe7SJed Brown                        if field is active or @ref CEED_VECTOR_NONE if using
9704cc79fe7SJed Brown                        @ref CEED_EVAL_WEIGHT in the QFunction
971b11c1e72Sjeremylt 
972b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
973dfdf5a53Sjeremylt 
9747a982d89SJeremy L. Thompson   @ref User
975b11c1e72Sjeremylt **/
976*d1d35e2fSjeremylt int CeedOperatorSetField(CeedOperator op, const char *field_name,
977a8d32208Sjeremylt                          CeedElemRestriction r, CeedBasis b, CeedVector v) {
978d7b241e6Sjeremylt   int ierr;
97952d6035fSJeremy L Thompson   if (op->composite)
980c042f62fSJeremy L Thompson     // LCOV_EXCL_START
981e1e9e29dSJed Brown     return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
982e15f9bd0SJeremy L Thompson                      "Cannot add field to composite operator.");
983c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
9848b067b84SJed Brown   if (!r)
985c042f62fSJeremy L Thompson     // LCOV_EXCL_START
986e1e9e29dSJed Brown     return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
987c042f62fSJeremy L Thompson                      "ElemRestriction r for field \"%s\" must be non-NULL.",
988*d1d35e2fSjeremylt                      field_name);
989c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
9908b067b84SJed Brown   if (!b)
991c042f62fSJeremy L Thompson     // LCOV_EXCL_START
992e1e9e29dSJed Brown     return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
993e15f9bd0SJeremy L Thompson                      "Basis b for field \"%s\" must be non-NULL.",
994*d1d35e2fSjeremylt                      field_name);
995c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
9968b067b84SJed Brown   if (!v)
997c042f62fSJeremy L Thompson     // LCOV_EXCL_START
998e1e9e29dSJed Brown     return CeedError(op->ceed, CEED_ERROR_INCOMPATIBLE,
999e15f9bd0SJeremy L Thompson                      "Vector v for field \"%s\" must be non-NULL.",
1000*d1d35e2fSjeremylt                      field_name);
1001c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
100252d6035fSJeremy L Thompson 
1003*d1d35e2fSjeremylt   CeedInt num_elem;
1004*d1d35e2fSjeremylt   ierr = CeedElemRestrictionGetNumElements(r, &num_elem); CeedChk(ierr);
1005*d1d35e2fSjeremylt   if (r != CEED_ELEMRESTRICTION_NONE && op->has_restriction &&
1006*d1d35e2fSjeremylt       op->num_elem != num_elem)
1007c042f62fSJeremy L Thompson     // LCOV_EXCL_START
1008e15f9bd0SJeremy L Thompson     return CeedError(op->ceed, CEED_ERROR_DIMENSION,
10091d102b48SJeremy L Thompson                      "ElemRestriction with %d elements incompatible with prior "
1010*d1d35e2fSjeremylt                      "%d elements", num_elem, op->num_elem);
1011c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
1012d7b241e6Sjeremylt 
1013*d1d35e2fSjeremylt   CeedInt num_qpts;
1014e15f9bd0SJeremy L Thompson   if (b != CEED_BASIS_COLLOCATED) {
1015*d1d35e2fSjeremylt     ierr = CeedBasisGetNumQuadraturePoints(b, &num_qpts); CeedChk(ierr);
1016*d1d35e2fSjeremylt     if (op->num_qpts && op->num_qpts != num_qpts)
1017c042f62fSJeremy L Thompson       // LCOV_EXCL_START
1018e15f9bd0SJeremy L Thompson       return CeedError(op->ceed, CEED_ERROR_DIMENSION,
1019e15f9bd0SJeremy L Thompson                        "Basis with %d quadrature points "
1020*d1d35e2fSjeremylt                        "incompatible with prior %d points", num_qpts,
1021*d1d35e2fSjeremylt                        op->num_qpts);
1022c042f62fSJeremy L Thompson     // LCOV_EXCL_STOP
1023d7b241e6Sjeremylt   }
1024*d1d35e2fSjeremylt   CeedQFunctionField qf_field;
1025*d1d35e2fSjeremylt   CeedOperatorField *op_field;
1026*d1d35e2fSjeremylt   for (CeedInt i=0; i<op->qf->num_input_fields; i++) {
1027*d1d35e2fSjeremylt     if (!strcmp(field_name, (*op->qf->input_fields[i]).field_name)) {
1028*d1d35e2fSjeremylt       qf_field = op->qf->input_fields[i];
1029*d1d35e2fSjeremylt       op_field = &op->input_fields[i];
1030d7b241e6Sjeremylt       goto found;
1031d7b241e6Sjeremylt     }
1032d7b241e6Sjeremylt   }
1033*d1d35e2fSjeremylt   for (CeedInt i=0; i<op->qf->num_output_fields; i++) {
1034*d1d35e2fSjeremylt     if (!strcmp(field_name, (*op->qf->output_fields[i]).field_name)) {
1035*d1d35e2fSjeremylt       qf_field = op->qf->output_fields[i];
1036*d1d35e2fSjeremylt       op_field = &op->output_fields[i];
1037d7b241e6Sjeremylt       goto found;
1038d7b241e6Sjeremylt     }
1039d7b241e6Sjeremylt   }
1040c042f62fSJeremy L Thompson   // LCOV_EXCL_START
1041e15f9bd0SJeremy L Thompson   return CeedError(op->ceed, CEED_ERROR_INCOMPLETE,
1042e15f9bd0SJeremy L Thompson                    "QFunction has no knowledge of field '%s'",
1043*d1d35e2fSjeremylt                    field_name);
1044c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
1045d7b241e6Sjeremylt found:
1046*d1d35e2fSjeremylt   ierr = CeedOperatorCheckField(op->ceed, qf_field, r, b); CeedChk(ierr);
1047*d1d35e2fSjeremylt   ierr = CeedCalloc(1, op_field); CeedChk(ierr);
1048e15f9bd0SJeremy L Thompson 
1049*d1d35e2fSjeremylt   (*op_field)->vec = v;
1050e15f9bd0SJeremy L Thompson   if (v != CEED_VECTOR_ACTIVE && v != CEED_VECTOR_NONE) {
1051*d1d35e2fSjeremylt     v->ref_count += 1;
1052e15f9bd0SJeremy L Thompson   }
1053e15f9bd0SJeremy L Thompson 
1054*d1d35e2fSjeremylt   (*op_field)->elem_restr = r;
1055*d1d35e2fSjeremylt   r->ref_count += 1;
1056e15f9bd0SJeremy L Thompson   if (r != CEED_ELEMRESTRICTION_NONE) {
1057*d1d35e2fSjeremylt     op->num_elem = num_elem;
1058*d1d35e2fSjeremylt     op->has_restriction = true; // Restriction set, but num_elem may be 0
1059e15f9bd0SJeremy L Thompson   }
1060d99fa3c5SJeremy L Thompson 
1061*d1d35e2fSjeremylt   (*op_field)->basis = b;
1062e15f9bd0SJeremy L Thompson   if (b != CEED_BASIS_COLLOCATED) {
1063*d1d35e2fSjeremylt     op->num_qpts = num_qpts;
1064*d1d35e2fSjeremylt     b->ref_count += 1;
1065e15f9bd0SJeremy L Thompson   }
1066e15f9bd0SJeremy L Thompson 
1067*d1d35e2fSjeremylt   op->num_fields += 1;
1068*d1d35e2fSjeremylt   size_t len = strlen(field_name);
1069d99fa3c5SJeremy L Thompson   char *tmp;
1070d99fa3c5SJeremy L Thompson   ierr = CeedCalloc(len+1, &tmp); CeedChk(ierr);
1071*d1d35e2fSjeremylt   memcpy(tmp, field_name, len+1);
1072*d1d35e2fSjeremylt   (*op_field)->field_name = tmp;
1073e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1074d7b241e6Sjeremylt }
1075d7b241e6Sjeremylt 
1076d7b241e6Sjeremylt /**
107752d6035fSJeremy L Thompson   @brief Add a sub-operator to a composite CeedOperator
1078288c0443SJeremy L Thompson 
1079*d1d35e2fSjeremylt   @param[out] composite_op  Composite CeedOperator
1080*d1d35e2fSjeremylt   @param      sub_op        Sub-operator CeedOperator
108152d6035fSJeremy L Thompson 
108252d6035fSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
108352d6035fSJeremy L Thompson 
10847a982d89SJeremy L. Thompson   @ref User
108552d6035fSJeremy L Thompson  */
1086*d1d35e2fSjeremylt int CeedCompositeOperatorAddSub(CeedOperator composite_op,
1087*d1d35e2fSjeremylt                                 CeedOperator sub_op) {
1088*d1d35e2fSjeremylt   if (!composite_op->composite)
1089c042f62fSJeremy L Thompson     // LCOV_EXCL_START
1090*d1d35e2fSjeremylt     return CeedError(composite_op->ceed, CEED_ERROR_MINOR,
1091e2f04181SAndrew T. Barker                      "CeedOperator is not a composite operator");
1092c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
109352d6035fSJeremy L Thompson 
1094*d1d35e2fSjeremylt   if (composite_op->num_suboperators == CEED_COMPOSITE_MAX)
1095c042f62fSJeremy L Thompson     // LCOV_EXCL_START
1096*d1d35e2fSjeremylt     return CeedError(composite_op->ceed, CEED_ERROR_UNSUPPORTED,
1097*d1d35e2fSjeremylt                      "Cannot add additional sub_operators");
1098c042f62fSJeremy L Thompson   // LCOV_EXCL_STOP
109952d6035fSJeremy L Thompson 
1100*d1d35e2fSjeremylt   composite_op->sub_operators[composite_op->num_suboperators] = sub_op;
1101*d1d35e2fSjeremylt   sub_op->ref_count++;
1102*d1d35e2fSjeremylt   composite_op->num_suboperators++;
1103e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
110452d6035fSJeremy L Thompson }
110552d6035fSJeremy L Thompson 
110652d6035fSJeremy L Thompson /**
11071d102b48SJeremy L Thompson   @brief Assemble a linear CeedQFunction associated with a CeedOperator
11081d102b48SJeremy L Thompson 
11091d102b48SJeremy L Thompson   This returns a CeedVector containing a matrix at each quadrature point
11101d102b48SJeremy L Thompson     providing the action of the CeedQFunction associated with the CeedOperator.
11111d102b48SJeremy L Thompson     The vector 'assembled' is of shape
11121d102b48SJeremy L Thompson       [num_elements, num_input_fields, num_output_fields, num_quad_points]
11131d102b48SJeremy L Thompson     and contains column-major matrices representing the action of the
11141d102b48SJeremy L Thompson     CeedQFunction for a corresponding quadrature point on an element. Inputs and
11151d102b48SJeremy L Thompson     outputs are in the order provided by the user when adding CeedOperator fields.
11164cc79fe7SJed Brown     For example, a CeedQFunction with inputs 'u' and 'gradu' and outputs 'gradv' and
11171d102b48SJeremy L Thompson     'v', provided in that order, would result in an assembled QFunction that
11181d102b48SJeremy L Thompson     consists of (1 + dim) x (dim + 1) matrices at each quadrature point acting
11191d102b48SJeremy L Thompson     on the input [u, du_0, du_1] and producing the output [dv_0, dv_1, v].
11201d102b48SJeremy L Thompson 
11211d102b48SJeremy L Thompson   @param op              CeedOperator to assemble CeedQFunction
11221d102b48SJeremy L Thompson   @param[out] assembled  CeedVector to store assembled CeedQFunction at
11231d102b48SJeremy L Thompson                            quadrature points
11241d102b48SJeremy L Thompson   @param[out] rstr       CeedElemRestriction for CeedVector containing assembled
11251d102b48SJeremy L Thompson                            CeedQFunction
11261d102b48SJeremy L Thompson   @param request         Address of CeedRequest for non-blocking completion, else
11274cc79fe7SJed Brown                            @ref CEED_REQUEST_IMMEDIATE
11281d102b48SJeremy L Thompson 
11291d102b48SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
11301d102b48SJeremy L Thompson 
11317a982d89SJeremy L. Thompson   @ref User
11321d102b48SJeremy L Thompson **/
113380ac2e43SJeremy L Thompson int CeedOperatorLinearAssembleQFunction(CeedOperator op, CeedVector *assembled,
11347f823360Sjeremylt                                         CeedElemRestriction *rstr,
11357f823360Sjeremylt                                         CeedRequest *request) {
11361d102b48SJeremy L Thompson   int ierr;
1137e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
11381d102b48SJeremy L Thompson 
11397172caadSjeremylt   // Backend version
114080ac2e43SJeremy L Thompson   if (op->LinearAssembleQFunction) {
1141e2f04181SAndrew T. Barker     return op->LinearAssembleQFunction(op, assembled, rstr, request);
11425107b09fSJeremy L Thompson   } else {
11435107b09fSJeremy L Thompson     // Fallback to reference Ceed
1144*d1d35e2fSjeremylt     if (!op->op_fallback) {
11455107b09fSJeremy L Thompson       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
11465107b09fSJeremy L Thompson     }
11475107b09fSJeremy L Thompson     // Assemble
1148*d1d35e2fSjeremylt     return CeedOperatorLinearAssembleQFunction(op->op_fallback, assembled,
1149e2f04181SAndrew T. Barker            rstr, request);
11505107b09fSJeremy L Thompson   }
11511d102b48SJeremy L Thompson }
11521d102b48SJeremy L Thompson 
11531d102b48SJeremy L Thompson /**
1154d965c7a7SJeremy L Thompson   @brief Assemble the diagonal of a square linear CeedOperator
1155b7ec98d8SJeremy L Thompson 
11569e9210b8SJeremy L Thompson   This overwrites a CeedVector with the diagonal of a linear CeedOperator.
1157b7ec98d8SJeremy L Thompson 
1158c04a41a7SJeremy L Thompson   Note: Currently only non-composite CeedOperators with a single field and
1159c04a41a7SJeremy L Thompson           composite CeedOperators with single field sub-operators are supported.
1160d965c7a7SJeremy L Thompson 
1161b7ec98d8SJeremy L Thompson   @param op              CeedOperator to assemble CeedQFunction
1162b7ec98d8SJeremy L Thompson   @param[out] assembled  CeedVector to store assembled CeedOperator diagonal
1163b7ec98d8SJeremy L Thompson   @param request         Address of CeedRequest for non-blocking completion, else
11644cc79fe7SJed Brown                            @ref CEED_REQUEST_IMMEDIATE
1165b7ec98d8SJeremy L Thompson 
1166b7ec98d8SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1167b7ec98d8SJeremy L Thompson 
11687a982d89SJeremy L. Thompson   @ref User
1169b7ec98d8SJeremy L Thompson **/
11702bba3ffaSJeremy L Thompson int CeedOperatorLinearAssembleDiagonal(CeedOperator op, CeedVector assembled,
11717f823360Sjeremylt                                        CeedRequest *request) {
1172b7ec98d8SJeremy L Thompson   int ierr;
1173e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
1174b7ec98d8SJeremy L Thompson 
1175b7ec98d8SJeremy L Thompson   // Use backend version, if available
117680ac2e43SJeremy L Thompson   if (op->LinearAssembleDiagonal) {
1177e2f04181SAndrew T. Barker     return op->LinearAssembleDiagonal(op, assembled, request);
11789e9210b8SJeremy L Thompson   } else if (op->LinearAssembleAddDiagonal) {
11799e9210b8SJeremy L Thompson     ierr = CeedVectorSetValue(assembled, 0.0); CeedChk(ierr);
11809e9210b8SJeremy L Thompson     return CeedOperatorLinearAssembleAddDiagonal(op, assembled, request);
11819e9210b8SJeremy L Thompson   } else {
11829e9210b8SJeremy L Thompson     // Fallback to reference Ceed
1183*d1d35e2fSjeremylt     if (!op->op_fallback) {
11849e9210b8SJeremy L Thompson       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
11859e9210b8SJeremy L Thompson     }
11869e9210b8SJeremy L Thompson     // Assemble
1187*d1d35e2fSjeremylt     return CeedOperatorLinearAssembleDiagonal(op->op_fallback, assembled,
1188e2f04181SAndrew T. Barker            request);
11899e9210b8SJeremy L Thompson   }
11909e9210b8SJeremy L Thompson }
11919e9210b8SJeremy L Thompson 
11929e9210b8SJeremy L Thompson /**
11939e9210b8SJeremy L Thompson   @brief Assemble the diagonal of a square linear CeedOperator
11949e9210b8SJeremy L Thompson 
11959e9210b8SJeremy L Thompson   This sums into a CeedVector the diagonal of a linear CeedOperator.
11969e9210b8SJeremy L Thompson 
11979e9210b8SJeremy L Thompson   Note: Currently only non-composite CeedOperators with a single field and
11989e9210b8SJeremy L Thompson           composite CeedOperators with single field sub-operators are supported.
11999e9210b8SJeremy L Thompson 
12009e9210b8SJeremy L Thompson   @param op              CeedOperator to assemble CeedQFunction
12019e9210b8SJeremy L Thompson   @param[out] assembled  CeedVector to store assembled CeedOperator diagonal
12029e9210b8SJeremy L Thompson   @param request         Address of CeedRequest for non-blocking completion, else
12039e9210b8SJeremy L Thompson                            @ref CEED_REQUEST_IMMEDIATE
12049e9210b8SJeremy L Thompson 
12059e9210b8SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
12069e9210b8SJeremy L Thompson 
12079e9210b8SJeremy L Thompson   @ref User
12089e9210b8SJeremy L Thompson **/
12099e9210b8SJeremy L Thompson int CeedOperatorLinearAssembleAddDiagonal(CeedOperator op, CeedVector assembled,
12109e9210b8SJeremy L Thompson     CeedRequest *request) {
12119e9210b8SJeremy L Thompson   int ierr;
1212e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
12139e9210b8SJeremy L Thompson 
12149e9210b8SJeremy L Thompson   // Use backend version, if available
12159e9210b8SJeremy L Thompson   if (op->LinearAssembleAddDiagonal) {
1216e2f04181SAndrew T. Barker     return op->LinearAssembleAddDiagonal(op, assembled, request);
12177172caadSjeremylt   } else {
12187172caadSjeremylt     // Fallback to reference Ceed
1219*d1d35e2fSjeremylt     if (!op->op_fallback) {
12207172caadSjeremylt       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
1221b7ec98d8SJeremy L Thompson     }
12227172caadSjeremylt     // Assemble
1223*d1d35e2fSjeremylt     return CeedOperatorLinearAssembleAddDiagonal(op->op_fallback, assembled,
1224e2f04181SAndrew T. Barker            request);
1225b7ec98d8SJeremy L Thompson   }
1226b7ec98d8SJeremy L Thompson }
1227b7ec98d8SJeremy L Thompson 
1228b7ec98d8SJeremy L Thompson /**
1229d965c7a7SJeremy L Thompson   @brief Assemble the point block diagonal of a square linear CeedOperator
1230d965c7a7SJeremy L Thompson 
12319e9210b8SJeremy L Thompson   This overwrites a CeedVector with the point block diagonal of a linear
1232d965c7a7SJeremy L Thompson     CeedOperator.
1233d965c7a7SJeremy L Thompson 
1234c04a41a7SJeremy L Thompson   Note: Currently only non-composite CeedOperators with a single field and
1235c04a41a7SJeremy L Thompson           composite CeedOperators with single field sub-operators are supported.
1236d965c7a7SJeremy L Thompson 
1237d965c7a7SJeremy L Thompson   @param op              CeedOperator to assemble CeedQFunction
1238d965c7a7SJeremy L Thompson   @param[out] assembled  CeedVector to store assembled CeedOperator point block
1239d965c7a7SJeremy L Thompson                            diagonal, provided in row-major form with an
1240*d1d35e2fSjeremylt                            @a num_comp * @a num_comp block at each node. The dimensions
1241d965c7a7SJeremy L Thompson                            of this vector are derived from the active vector
1242d965c7a7SJeremy L Thompson                            for the CeedOperator. The array has shape
1243d965c7a7SJeremy L Thompson                            [nodes, component out, component in].
1244d965c7a7SJeremy L Thompson   @param request         Address of CeedRequest for non-blocking completion, else
1245d965c7a7SJeremy L Thompson                            CEED_REQUEST_IMMEDIATE
1246d965c7a7SJeremy L Thompson 
1247d965c7a7SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1248d965c7a7SJeremy L Thompson 
1249d965c7a7SJeremy L Thompson   @ref User
1250d965c7a7SJeremy L Thompson **/
125180ac2e43SJeremy L Thompson int CeedOperatorLinearAssemblePointBlockDiagonal(CeedOperator op,
12522bba3ffaSJeremy L Thompson     CeedVector assembled, CeedRequest *request) {
1253d965c7a7SJeremy L Thompson   int ierr;
1254e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
1255d965c7a7SJeremy L Thompson 
1256d965c7a7SJeremy L Thompson   // Use backend version, if available
125780ac2e43SJeremy L Thompson   if (op->LinearAssemblePointBlockDiagonal) {
1258e2f04181SAndrew T. Barker     return op->LinearAssemblePointBlockDiagonal(op, assembled, request);
12599e9210b8SJeremy L Thompson   } else if (op->LinearAssembleAddPointBlockDiagonal) {
12609e9210b8SJeremy L Thompson     ierr = CeedVectorSetValue(assembled, 0.0); CeedChk(ierr);
12619e9210b8SJeremy L Thompson     return CeedOperatorLinearAssembleAddPointBlockDiagonal(op, assembled,
12629e9210b8SJeremy L Thompson            request);
1263d965c7a7SJeremy L Thompson   } else {
1264d965c7a7SJeremy L Thompson     // Fallback to reference Ceed
1265*d1d35e2fSjeremylt     if (!op->op_fallback) {
1266d965c7a7SJeremy L Thompson       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
1267d965c7a7SJeremy L Thompson     }
1268d965c7a7SJeremy L Thompson     // Assemble
1269*d1d35e2fSjeremylt     return CeedOperatorLinearAssemblePointBlockDiagonal(op->op_fallback,
1270e2f04181SAndrew T. Barker            assembled, request);
12719e9210b8SJeremy L Thompson   }
12729e9210b8SJeremy L Thompson }
12739e9210b8SJeremy L Thompson 
12749e9210b8SJeremy L Thompson /**
12759e9210b8SJeremy L Thompson   @brief Assemble the point block diagonal of a square linear CeedOperator
12769e9210b8SJeremy L Thompson 
12779e9210b8SJeremy L Thompson   This sums into a CeedVector with the point block diagonal of a linear
12789e9210b8SJeremy L Thompson     CeedOperator.
12799e9210b8SJeremy L Thompson 
12809e9210b8SJeremy L Thompson   Note: Currently only non-composite CeedOperators with a single field and
12819e9210b8SJeremy L Thompson           composite CeedOperators with single field sub-operators are supported.
12829e9210b8SJeremy L Thompson 
12839e9210b8SJeremy L Thompson   @param op              CeedOperator to assemble CeedQFunction
12849e9210b8SJeremy L Thompson   @param[out] assembled  CeedVector to store assembled CeedOperator point block
12859e9210b8SJeremy L Thompson                            diagonal, provided in row-major form with an
1286*d1d35e2fSjeremylt                            @a num_comp * @a num_comp block at each node. The dimensions
12879e9210b8SJeremy L Thompson                            of this vector are derived from the active vector
12889e9210b8SJeremy L Thompson                            for the CeedOperator. The array has shape
12899e9210b8SJeremy L Thompson                            [nodes, component out, component in].
12909e9210b8SJeremy L Thompson   @param request         Address of CeedRequest for non-blocking completion, else
12919e9210b8SJeremy L Thompson                            CEED_REQUEST_IMMEDIATE
12929e9210b8SJeremy L Thompson 
12939e9210b8SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
12949e9210b8SJeremy L Thompson 
12959e9210b8SJeremy L Thompson   @ref User
12969e9210b8SJeremy L Thompson **/
12979e9210b8SJeremy L Thompson int CeedOperatorLinearAssembleAddPointBlockDiagonal(CeedOperator op,
12989e9210b8SJeremy L Thompson     CeedVector assembled, CeedRequest *request) {
12999e9210b8SJeremy L Thompson   int ierr;
1300e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
13019e9210b8SJeremy L Thompson 
13029e9210b8SJeremy L Thompson   // Use backend version, if available
13039e9210b8SJeremy L Thompson   if (op->LinearAssembleAddPointBlockDiagonal) {
1304e2f04181SAndrew T. Barker     return op->LinearAssembleAddPointBlockDiagonal(op, assembled, request);
13059e9210b8SJeremy L Thompson   } else {
13069e9210b8SJeremy L Thompson     // Fallback to reference Ceed
1307*d1d35e2fSjeremylt     if (!op->op_fallback) {
13089e9210b8SJeremy L Thompson       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
13099e9210b8SJeremy L Thompson     }
13109e9210b8SJeremy L Thompson     // Assemble
1311*d1d35e2fSjeremylt     return CeedOperatorLinearAssembleAddPointBlockDiagonal(op->op_fallback,
1312e2f04181SAndrew T. Barker            assembled, request);
1313d965c7a7SJeremy L Thompson   }
1314e2f04181SAndrew T. Barker }
1315e2f04181SAndrew T. Barker 
1316e2f04181SAndrew T. Barker /**
1317e2f04181SAndrew T. Barker    @brief Build nonzero pattern for non-composite operator.
1318e2f04181SAndrew T. Barker 
1319e2f04181SAndrew T. Barker    Users should generally use CeedOperatorLinearAssembleSymbolic()
1320e2f04181SAndrew T. Barker 
1321e2f04181SAndrew T. Barker    @ref Developer
1322e2f04181SAndrew T. Barker **/
1323e2f04181SAndrew T. Barker int CeedSingleOperatorAssembleSymbolic(CeedOperator op, CeedInt offset,
1324e2f04181SAndrew T. Barker                                        CeedInt *rows, CeedInt *cols) {
1325e2f04181SAndrew T. Barker   int ierr;
1326e2f04181SAndrew T. Barker   Ceed ceed = op->ceed;
1327e2f04181SAndrew T. Barker   if (op->composite)
1328e2f04181SAndrew T. Barker     // LCOV_EXCL_START
1329e2f04181SAndrew T. Barker     return CeedError(ceed, CEED_ERROR_UNSUPPORTED,
1330e2f04181SAndrew T. Barker                      "Composite operator not supported");
1331e2f04181SAndrew T. Barker   // LCOV_EXCL_STOP
1332e2f04181SAndrew T. Barker 
1333*d1d35e2fSjeremylt   CeedElemRestriction rstr_in;
1334*d1d35e2fSjeremylt   ierr = CeedOperatorGetActiveElemRestriction(op, &rstr_in); CeedChk(ierr);
1335*d1d35e2fSjeremylt   CeedInt num_elem, elem_size, num_nodes, num_comp;
1336*d1d35e2fSjeremylt   ierr = CeedElemRestrictionGetNumElements(rstr_in, &num_elem); CeedChk(ierr);
1337*d1d35e2fSjeremylt   ierr = CeedElemRestrictionGetElementSize(rstr_in, &elem_size); CeedChk(ierr);
1338*d1d35e2fSjeremylt   ierr = CeedElemRestrictionGetLVectorSize(rstr_in, &num_nodes); CeedChk(ierr);
1339*d1d35e2fSjeremylt   ierr = CeedElemRestrictionGetNumComponents(rstr_in, &num_comp); CeedChk(ierr);
1340e2f04181SAndrew T. Barker   CeedInt layout_er[3];
1341*d1d35e2fSjeremylt   ierr = CeedElemRestrictionGetELayout(rstr_in, &layout_er); CeedChk(ierr);
1342e2f04181SAndrew T. Barker 
1343*d1d35e2fSjeremylt   CeedInt local_num_entries = elem_size*num_comp * elem_size*num_comp * num_elem;
1344e2f04181SAndrew T. Barker 
1345e2f04181SAndrew T. Barker   // Determine elem_dof relation
1346e2f04181SAndrew T. Barker   CeedVector index_vec;
1347*d1d35e2fSjeremylt   ierr = CeedVectorCreate(ceed, num_nodes, &index_vec); CeedChk(ierr);
1348e2f04181SAndrew T. Barker   CeedScalar *array;
1349e2f04181SAndrew T. Barker   ierr = CeedVectorGetArray(index_vec, CEED_MEM_HOST, &array); CeedChk(ierr);
1350*d1d35e2fSjeremylt   for (CeedInt i = 0; i < num_nodes; ++i) {
1351e2f04181SAndrew T. Barker     array[i] = i;
1352e2f04181SAndrew T. Barker   }
1353e2f04181SAndrew T. Barker   ierr = CeedVectorRestoreArray(index_vec, &array); CeedChk(ierr);
1354e2f04181SAndrew T. Barker   CeedVector elem_dof;
1355*d1d35e2fSjeremylt   ierr = CeedVectorCreate(ceed, num_elem * elem_size * num_comp, &elem_dof);
1356e2f04181SAndrew T. Barker   CeedChk(ierr);
1357e2f04181SAndrew T. Barker   ierr = CeedVectorSetValue(elem_dof, 0.0); CeedChk(ierr);
1358*d1d35e2fSjeremylt   CeedElemRestrictionApply(rstr_in, CEED_NOTRANSPOSE, index_vec,
1359e2f04181SAndrew T. Barker                            elem_dof, CEED_REQUEST_IMMEDIATE); CeedChk(ierr);
1360e2f04181SAndrew T. Barker   const CeedScalar *elem_dof_a;
1361e2f04181SAndrew T. Barker   ierr = CeedVectorGetArrayRead(elem_dof, CEED_MEM_HOST, &elem_dof_a);
1362e2f04181SAndrew T. Barker   CeedChk(ierr);
1363e2f04181SAndrew T. Barker   ierr = CeedVectorDestroy(&index_vec); CeedChk(ierr);
1364e2f04181SAndrew T. Barker 
1365e2f04181SAndrew T. Barker   // Determine i, j locations for element matrices
1366e2f04181SAndrew T. Barker   CeedInt count = 0;
1367*d1d35e2fSjeremylt   for (int e = 0; e < num_elem; ++e) {
1368*d1d35e2fSjeremylt     for (int comp_in = 0; comp_in < num_comp; ++comp_in) {
1369*d1d35e2fSjeremylt       for (int comp_out = 0; comp_out < num_comp; ++comp_out) {
1370*d1d35e2fSjeremylt         for (int i = 0; i < elem_size; ++i) {
1371*d1d35e2fSjeremylt           for (int j = 0; j < elem_size; ++j) {
1372*d1d35e2fSjeremylt             const CeedInt elem_dof_index_row = (i)*layout_er[0] +
1373*d1d35e2fSjeremylt                                                (comp_out)*layout_er[1] + e*layout_er[2];
1374*d1d35e2fSjeremylt             const CeedInt elem_dof_index_col = (j)*layout_er[0] +
1375*d1d35e2fSjeremylt                                                (comp_in)*layout_er[1] + e*layout_er[2];
1376e2f04181SAndrew T. Barker 
1377*d1d35e2fSjeremylt             const CeedInt row = elem_dof_a[elem_dof_index_row];
1378*d1d35e2fSjeremylt             const CeedInt col = elem_dof_a[elem_dof_index_col];
1379e2f04181SAndrew T. Barker 
1380e2f04181SAndrew T. Barker             rows[offset + count] = row;
1381e2f04181SAndrew T. Barker             cols[offset + count] = col;
1382e2f04181SAndrew T. Barker             count++;
1383e2f04181SAndrew T. Barker           }
1384e2f04181SAndrew T. Barker         }
1385e2f04181SAndrew T. Barker       }
1386e2f04181SAndrew T. Barker     }
1387e2f04181SAndrew T. Barker   }
1388*d1d35e2fSjeremylt   if (count != local_num_entries)
1389e2f04181SAndrew T. Barker     // LCOV_EXCL_START
1390e2f04181SAndrew T. Barker     return CeedError(ceed, CEED_ERROR_MAJOR, "Error computing assembled entries");
1391e2f04181SAndrew T. Barker   // LCOV_EXCL_STOP
1392e2f04181SAndrew T. Barker   ierr = CeedVectorRestoreArrayRead(elem_dof, &elem_dof_a); CeedChk(ierr);
1393e2f04181SAndrew T. Barker   ierr = CeedVectorDestroy(&elem_dof); CeedChk(ierr);
1394e2f04181SAndrew T. Barker 
1395e2f04181SAndrew T. Barker   return CEED_ERROR_SUCCESS;
1396e2f04181SAndrew T. Barker }
1397e2f04181SAndrew T. Barker 
1398e2f04181SAndrew T. Barker /**
1399e2f04181SAndrew T. Barker    @brief Assemble nonzero entries for non-composite operator
1400e2f04181SAndrew T. Barker 
1401e2f04181SAndrew T. Barker    Users should generally use CeedOperatorLinearAssemble()
1402e2f04181SAndrew T. Barker 
1403e2f04181SAndrew T. Barker    @ref Developer
1404e2f04181SAndrew T. Barker **/
1405e2f04181SAndrew T. Barker int CeedSingleOperatorAssemble(CeedOperator op, CeedInt offset,
1406e2f04181SAndrew T. Barker                                CeedVector values) {
1407e2f04181SAndrew T. Barker   int ierr;
1408e2f04181SAndrew T. Barker   Ceed ceed = op->ceed;;
1409e2f04181SAndrew T. Barker   if (op->composite)
1410e2f04181SAndrew T. Barker     // LCOV_EXCL_START
1411e2f04181SAndrew T. Barker     return CeedError(ceed, CEED_ERROR_UNSUPPORTED,
1412e2f04181SAndrew T. Barker                      "Composite operator not supported");
1413e2f04181SAndrew T. Barker   // LCOV_EXCL_STOP
1414e2f04181SAndrew T. Barker 
1415e2f04181SAndrew T. Barker   // Assemble QFunction
1416e2f04181SAndrew T. Barker   CeedQFunction qf;
1417e2f04181SAndrew T. Barker   ierr = CeedOperatorGetQFunction(op, &qf); CeedChk(ierr);
1418*d1d35e2fSjeremylt   CeedInt num_input_fields, num_output_fields;
1419*d1d35e2fSjeremylt   ierr= CeedQFunctionGetNumArgs(qf, &num_input_fields, &num_output_fields);
1420e2f04181SAndrew T. Barker   CeedChk(ierr);
1421*d1d35e2fSjeremylt   CeedVector assembled_qf;
1422e2f04181SAndrew T. Barker   CeedElemRestriction rstr_q;
1423e2f04181SAndrew T. Barker   ierr = CeedOperatorLinearAssembleQFunction(
1424*d1d35e2fSjeremylt            op, &assembled_qf, &rstr_q, CEED_REQUEST_IMMEDIATE); CeedChk(ierr);
1425e2f04181SAndrew T. Barker 
1426*d1d35e2fSjeremylt   CeedInt qf_length;
1427*d1d35e2fSjeremylt   ierr = CeedVectorGetLength(assembled_qf, &qf_length); CeedChk(ierr);
1428e2f04181SAndrew T. Barker 
1429e2f04181SAndrew T. Barker   CeedOperatorField *input_fields;
1430e2f04181SAndrew T. Barker   CeedOperatorField *output_fields;
1431e2f04181SAndrew T. Barker   ierr = CeedOperatorGetFields(op, &input_fields, &output_fields); CeedChk(ierr);
1432e2f04181SAndrew T. Barker 
1433e2f04181SAndrew T. Barker   // Determine active input basis
1434*d1d35e2fSjeremylt   CeedQFunctionField *qf_fields;
1435*d1d35e2fSjeremylt   ierr = CeedQFunctionGetFields(qf, &qf_fields, NULL); CeedChk(ierr);
1436*d1d35e2fSjeremylt   CeedInt num_eval_mode_in = 0, dim = 1;
1437*d1d35e2fSjeremylt   CeedEvalMode *eval_mode_in = NULL;
1438*d1d35e2fSjeremylt   CeedBasis basis_in = NULL;
1439*d1d35e2fSjeremylt   CeedElemRestriction rstr_in = NULL;
1440*d1d35e2fSjeremylt   for (CeedInt i=0; i<num_input_fields; i++) {
1441e2f04181SAndrew T. Barker     CeedVector vec;
1442e2f04181SAndrew T. Barker     ierr = CeedOperatorFieldGetVector(input_fields[i], &vec); CeedChk(ierr);
1443e2f04181SAndrew T. Barker     if (vec == CEED_VECTOR_ACTIVE) {
1444*d1d35e2fSjeremylt       ierr = CeedOperatorFieldGetBasis(input_fields[i], &basis_in);
1445e2f04181SAndrew T. Barker       CeedChk(ierr);
1446*d1d35e2fSjeremylt       ierr = CeedBasisGetDimension(basis_in, &dim); CeedChk(ierr);
1447*d1d35e2fSjeremylt       ierr = CeedOperatorFieldGetElemRestriction(input_fields[i], &rstr_in);
1448e2f04181SAndrew T. Barker       CeedChk(ierr);
1449*d1d35e2fSjeremylt       CeedEvalMode eval_mode;
1450*d1d35e2fSjeremylt       ierr = CeedQFunctionFieldGetEvalMode(qf_fields[i], &eval_mode);
1451e2f04181SAndrew T. Barker       CeedChk(ierr);
1452*d1d35e2fSjeremylt       switch (eval_mode) {
1453e2f04181SAndrew T. Barker       case CEED_EVAL_NONE:
1454e2f04181SAndrew T. Barker       case CEED_EVAL_INTERP:
1455*d1d35e2fSjeremylt         ierr = CeedRealloc(num_eval_mode_in + 1, &eval_mode_in); CeedChk(ierr);
1456*d1d35e2fSjeremylt         eval_mode_in[num_eval_mode_in] = eval_mode;
1457*d1d35e2fSjeremylt         num_eval_mode_in += 1;
1458e2f04181SAndrew T. Barker         break;
1459e2f04181SAndrew T. Barker       case CEED_EVAL_GRAD:
1460*d1d35e2fSjeremylt         ierr = CeedRealloc(num_eval_mode_in + dim, &eval_mode_in); CeedChk(ierr);
1461e2f04181SAndrew T. Barker         for (CeedInt d=0; d<dim; d++) {
1462*d1d35e2fSjeremylt           eval_mode_in[num_eval_mode_in+d] = eval_mode;
1463e2f04181SAndrew T. Barker         }
1464*d1d35e2fSjeremylt         num_eval_mode_in += dim;
1465e2f04181SAndrew T. Barker         break;
1466e2f04181SAndrew T. Barker       case CEED_EVAL_WEIGHT:
1467e2f04181SAndrew T. Barker       case CEED_EVAL_DIV:
1468e2f04181SAndrew T. Barker       case CEED_EVAL_CURL:
1469e2f04181SAndrew T. Barker         break; // Caught by QF Assembly
1470e2f04181SAndrew T. Barker       }
1471e2f04181SAndrew T. Barker     }
1472e2f04181SAndrew T. Barker   }
1473e2f04181SAndrew T. Barker 
1474e2f04181SAndrew T. Barker   // Determine active output basis
1475*d1d35e2fSjeremylt   ierr = CeedQFunctionGetFields(qf, NULL, &qf_fields); CeedChk(ierr);
1476*d1d35e2fSjeremylt   CeedInt num_eval_mode_out = 0;
1477*d1d35e2fSjeremylt   CeedEvalMode *eval_mode_out = NULL;
1478*d1d35e2fSjeremylt   CeedBasis basis_out = NULL;
1479*d1d35e2fSjeremylt   CeedElemRestriction rstr_out = NULL;
1480*d1d35e2fSjeremylt   for (CeedInt i=0; i<num_output_fields; i++) {
1481e2f04181SAndrew T. Barker     CeedVector vec;
1482e2f04181SAndrew T. Barker     ierr = CeedOperatorFieldGetVector(output_fields[i], &vec); CeedChk(ierr);
1483e2f04181SAndrew T. Barker     if (vec == CEED_VECTOR_ACTIVE) {
1484*d1d35e2fSjeremylt       ierr = CeedOperatorFieldGetBasis(output_fields[i], &basis_out);
1485e2f04181SAndrew T. Barker       CeedChk(ierr);
1486*d1d35e2fSjeremylt       ierr = CeedOperatorFieldGetElemRestriction(output_fields[i], &rstr_out);
1487e2f04181SAndrew T. Barker       CeedChk(ierr);
1488*d1d35e2fSjeremylt       CeedEvalMode eval_mode;
1489*d1d35e2fSjeremylt       ierr = CeedQFunctionFieldGetEvalMode(qf_fields[i], &eval_mode);
1490e2f04181SAndrew T. Barker       CeedChk(ierr);
1491*d1d35e2fSjeremylt       switch (eval_mode) {
1492e2f04181SAndrew T. Barker       case CEED_EVAL_NONE:
1493e2f04181SAndrew T. Barker       case CEED_EVAL_INTERP:
1494*d1d35e2fSjeremylt         ierr = CeedRealloc(num_eval_mode_out + 1, &eval_mode_out); CeedChk(ierr);
1495*d1d35e2fSjeremylt         eval_mode_out[num_eval_mode_out] = eval_mode;
1496*d1d35e2fSjeremylt         num_eval_mode_out += 1;
1497e2f04181SAndrew T. Barker         break;
1498e2f04181SAndrew T. Barker       case CEED_EVAL_GRAD:
1499*d1d35e2fSjeremylt         ierr = CeedRealloc(num_eval_mode_out + dim, &eval_mode_out); CeedChk(ierr);
1500e2f04181SAndrew T. Barker         for (CeedInt d=0; d<dim; d++) {
1501*d1d35e2fSjeremylt           eval_mode_out[num_eval_mode_out+d] = eval_mode;
1502e2f04181SAndrew T. Barker         }
1503*d1d35e2fSjeremylt         num_eval_mode_out += dim;
1504e2f04181SAndrew T. Barker         break;
1505e2f04181SAndrew T. Barker       case CEED_EVAL_WEIGHT:
1506e2f04181SAndrew T. Barker       case CEED_EVAL_DIV:
1507e2f04181SAndrew T. Barker       case CEED_EVAL_CURL:
1508e2f04181SAndrew T. Barker         break; // Caught by QF Assembly
1509e2f04181SAndrew T. Barker       }
1510e2f04181SAndrew T. Barker     }
1511e2f04181SAndrew T. Barker   }
1512e2f04181SAndrew T. Barker 
1513*d1d35e2fSjeremylt   CeedInt num_elem, elem_size, num_qpts, num_comp;
1514*d1d35e2fSjeremylt   ierr = CeedElemRestrictionGetNumElements(rstr_in, &num_elem); CeedChk(ierr);
1515*d1d35e2fSjeremylt   ierr = CeedElemRestrictionGetElementSize(rstr_in, &elem_size); CeedChk(ierr);
1516*d1d35e2fSjeremylt   ierr = CeedElemRestrictionGetNumComponents(rstr_in, &num_comp); CeedChk(ierr);
1517*d1d35e2fSjeremylt   ierr = CeedBasisGetNumQuadraturePoints(basis_in, &num_qpts); CeedChk(ierr);
1518e2f04181SAndrew T. Barker 
1519*d1d35e2fSjeremylt   CeedInt local_num_entries = elem_size*num_comp * elem_size*num_comp * num_elem;
1520e2f04181SAndrew T. Barker 
1521e2f04181SAndrew T. Barker   // loop over elements and put in data structure
1522*d1d35e2fSjeremylt   const CeedScalar *interp_in, *grad_in;
1523*d1d35e2fSjeremylt   ierr = CeedBasisGetInterp(basis_in, &interp_in); CeedChk(ierr);
1524*d1d35e2fSjeremylt   ierr = CeedBasisGetGrad(basis_in, &grad_in); CeedChk(ierr);
1525e2f04181SAndrew T. Barker 
1526*d1d35e2fSjeremylt   const CeedScalar *assembled_qf_array;
1527*d1d35e2fSjeremylt   ierr = CeedVectorGetArrayRead(assembled_qf, CEED_MEM_HOST, &assembled_qf_array);
1528e2f04181SAndrew T. Barker   CeedChk(ierr);
1529e2f04181SAndrew T. Barker 
1530e2f04181SAndrew T. Barker   CeedInt layout_qf[3];
1531e2f04181SAndrew T. Barker   ierr = CeedElemRestrictionGetELayout(rstr_q, &layout_qf); CeedChk(ierr);
1532e2f04181SAndrew T. Barker   ierr = CeedElemRestrictionDestroy(&rstr_q); CeedChk(ierr);
1533e2f04181SAndrew T. Barker 
1534*d1d35e2fSjeremylt   // we store B_mat_in, B_mat_out, BTD, elem_mat in row-major order
1535*d1d35e2fSjeremylt   CeedScalar B_mat_in[(num_qpts * num_eval_mode_in) * elem_size];
1536*d1d35e2fSjeremylt   CeedScalar B_mat_out[(num_qpts * num_eval_mode_out) * elem_size];
1537*d1d35e2fSjeremylt   CeedScalar D_mat[num_eval_mode_out * num_eval_mode_in *
1538*d1d35e2fSjeremylt                                      num_qpts]; // logically 3-tensor
1539*d1d35e2fSjeremylt   CeedScalar BTD[elem_size * num_qpts*num_eval_mode_in];
1540*d1d35e2fSjeremylt   CeedScalar elem_mat[elem_size * elem_size];
1541e2f04181SAndrew T. Barker   int count = 0;
1542e2f04181SAndrew T. Barker   CeedScalar *vals;
1543e2f04181SAndrew T. Barker   ierr = CeedVectorGetArray(values, CEED_MEM_HOST, &vals); CeedChk(ierr);
1544*d1d35e2fSjeremylt   for (int e = 0; e < num_elem; ++e) {
1545*d1d35e2fSjeremylt     for (int comp_in = 0; comp_in < num_comp; ++comp_in) {
1546*d1d35e2fSjeremylt       for (int comp_out = 0; comp_out < num_comp; ++comp_out) {
1547*d1d35e2fSjeremylt         for (int ell = 0; ell < (num_qpts * num_eval_mode_in) * elem_size; ++ell) {
1548*d1d35e2fSjeremylt           B_mat_in[ell] = 0.0;
1549e2f04181SAndrew T. Barker         }
1550*d1d35e2fSjeremylt         for (int ell = 0; ell < (num_qpts * num_eval_mode_out) * elem_size; ++ell) {
1551*d1d35e2fSjeremylt           B_mat_out[ell] = 0.0;
1552e2f04181SAndrew T. Barker         }
1553e2f04181SAndrew T. Barker         // Store block-diagonal D matrix as collection of small dense blocks
1554*d1d35e2fSjeremylt         for (int ell = 0; ell < num_eval_mode_in*num_eval_mode_out*num_qpts; ++ell) {
1555*d1d35e2fSjeremylt           D_mat[ell] = 0.0;
1556e2f04181SAndrew T. Barker         }
1557e2f04181SAndrew T. Barker         // form element matrix itself (for each block component)
1558*d1d35e2fSjeremylt         for (int ell = 0; ell < elem_size*elem_size; ++ell) {
1559e2f04181SAndrew T. Barker           elem_mat[ell] = 0.0;
1560e2f04181SAndrew T. Barker         }
1561*d1d35e2fSjeremylt         for (int q = 0; q < num_qpts; ++q) {
1562*d1d35e2fSjeremylt           for (int n = 0; n < elem_size; ++n) {
1563*d1d35e2fSjeremylt             CeedInt d_in = -1;
1564*d1d35e2fSjeremylt             for (int e_in = 0; e_in < num_eval_mode_in; ++e_in) {
1565*d1d35e2fSjeremylt               const int qq = num_eval_mode_in*q;
1566*d1d35e2fSjeremylt               if (eval_mode_in[e_in] == CEED_EVAL_INTERP) {
1567*d1d35e2fSjeremylt                 B_mat_in[(qq+e_in)*elem_size + n] += interp_in[q * elem_size + n];
1568*d1d35e2fSjeremylt               } else if (eval_mode_in[e_in] == CEED_EVAL_GRAD) {
1569*d1d35e2fSjeremylt                 d_in += 1;
1570*d1d35e2fSjeremylt                 B_mat_in[(qq+e_in)*elem_size + n] +=
1571*d1d35e2fSjeremylt                   grad_in[(d_in*num_qpts+q) * elem_size + n];
1572e2f04181SAndrew T. Barker               } else {
1573e2f04181SAndrew T. Barker                 // LCOV_EXCL_START
1574e2f04181SAndrew T. Barker                 return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Not implemented!");
1575e2f04181SAndrew T. Barker                 // LCOV_EXCL_STOP
1576e2f04181SAndrew T. Barker               }
1577e2f04181SAndrew T. Barker             }
1578*d1d35e2fSjeremylt             CeedInt d_out = -1;
1579*d1d35e2fSjeremylt             for (int e_out = 0; e_out < num_eval_mode_out; ++e_out) {
1580*d1d35e2fSjeremylt               const int qq = num_eval_mode_out*q;
1581*d1d35e2fSjeremylt               if (eval_mode_out[e_out] == CEED_EVAL_INTERP) {
1582*d1d35e2fSjeremylt                 B_mat_out[(qq+e_out)*elem_size + n] += interp_in[q * elem_size + n];
1583*d1d35e2fSjeremylt               } else if (eval_mode_out[e_out] == CEED_EVAL_GRAD) {
1584*d1d35e2fSjeremylt                 d_out += 1;
1585*d1d35e2fSjeremylt                 B_mat_out[(qq+e_out)*elem_size + n] +=
1586*d1d35e2fSjeremylt                   grad_in[(d_out*num_qpts+q) * elem_size + n];
1587e2f04181SAndrew T. Barker               } else {
1588e2f04181SAndrew T. Barker                 // LCOV_EXCL_START
1589e2f04181SAndrew T. Barker                 return CeedError(ceed, CEED_ERROR_UNSUPPORTED, "Not implemented!");
1590e2f04181SAndrew T. Barker                 // LCOV_EXCL_STOP
1591e2f04181SAndrew T. Barker               }
1592e2f04181SAndrew T. Barker             }
1593e2f04181SAndrew T. Barker           }
1594*d1d35e2fSjeremylt           for (int ei = 0; ei < num_eval_mode_out; ++ei) {
1595*d1d35e2fSjeremylt             for (int ej = 0; ej < num_eval_mode_in; ++ej) {
1596*d1d35e2fSjeremylt               const int eval_mode_index = ((ei*num_comp+comp_in)*num_eval_mode_in+ej)*num_comp
1597*d1d35e2fSjeremylt                                           +comp_out;
1598*d1d35e2fSjeremylt               const int index = q*layout_qf[0] + eval_mode_index*layout_qf[1] +
1599*d1d35e2fSjeremylt                                 e*layout_qf[2];
1600*d1d35e2fSjeremylt               D_mat[(ei*num_eval_mode_in+ej)*num_qpts + q] += assembled_qf_array[index];
1601e2f04181SAndrew T. Barker             }
1602e2f04181SAndrew T. Barker           }
1603e2f04181SAndrew T. Barker         }
1604e2f04181SAndrew T. Barker         // Compute B^T*D
1605*d1d35e2fSjeremylt         for (int ell = 0; ell < elem_size*num_qpts*num_eval_mode_in; ++ell) {
1606e2f04181SAndrew T. Barker           BTD[ell] = 0.0;
1607e2f04181SAndrew T. Barker         }
1608*d1d35e2fSjeremylt         for (int j = 0; j<elem_size; ++j) {
1609*d1d35e2fSjeremylt           for (int q = 0; q<num_qpts; ++q) {
1610*d1d35e2fSjeremylt             int qq = num_eval_mode_out*q;
1611*d1d35e2fSjeremylt             for (int ei = 0; ei < num_eval_mode_in; ++ei) {
1612*d1d35e2fSjeremylt               for (int ej = 0; ej < num_eval_mode_out; ++ej) {
1613*d1d35e2fSjeremylt                 BTD[j*(num_qpts*num_eval_mode_in) + (qq+ei)] +=
1614*d1d35e2fSjeremylt                   B_mat_out[(qq+ej)*elem_size + j] * D_mat[(ei*num_eval_mode_in+ej)*num_qpts + q];
1615e2f04181SAndrew T. Barker               }
1616e2f04181SAndrew T. Barker             }
1617e2f04181SAndrew T. Barker           }
1618e2f04181SAndrew T. Barker         }
1619e2f04181SAndrew T. Barker 
1620*d1d35e2fSjeremylt         ierr = CeedMatrixMultiply(ceed, BTD, B_mat_in, elem_mat, elem_size,
1621*d1d35e2fSjeremylt                                   elem_size, num_qpts*num_eval_mode_in); CeedChk(ierr);
1622e2f04181SAndrew T. Barker 
1623e2f04181SAndrew T. Barker         // put element matrix in coordinate data structure
1624*d1d35e2fSjeremylt         for (int i = 0; i < elem_size; ++i) {
1625*d1d35e2fSjeremylt           for (int j = 0; j < elem_size; ++j) {
1626*d1d35e2fSjeremylt             vals[offset + count] = elem_mat[i*elem_size + j];
1627e2f04181SAndrew T. Barker             count++;
1628e2f04181SAndrew T. Barker           }
1629e2f04181SAndrew T. Barker         }
1630e2f04181SAndrew T. Barker       }
1631e2f04181SAndrew T. Barker     }
1632e2f04181SAndrew T. Barker   }
1633*d1d35e2fSjeremylt   if (count != local_num_entries)
1634e2f04181SAndrew T. Barker     // LCOV_EXCL_START
1635e2f04181SAndrew T. Barker     return CeedError(ceed, CEED_ERROR_MAJOR, "Error computing entries");
1636e2f04181SAndrew T. Barker   // LCOV_EXCL_STOP
1637e2f04181SAndrew T. Barker   ierr = CeedVectorRestoreArray(values, &vals); CeedChk(ierr);
1638e2f04181SAndrew T. Barker 
1639*d1d35e2fSjeremylt   ierr = CeedVectorRestoreArrayRead(assembled_qf, &assembled_qf_array);
1640e2f04181SAndrew T. Barker   CeedChk(ierr);
1641*d1d35e2fSjeremylt   ierr = CeedVectorDestroy(&assembled_qf); CeedChk(ierr);
1642*d1d35e2fSjeremylt   ierr = CeedFree(&eval_mode_in); CeedChk(ierr);
1643*d1d35e2fSjeremylt   ierr = CeedFree(&eval_mode_out); CeedChk(ierr);
1644e2f04181SAndrew T. Barker 
1645e2f04181SAndrew T. Barker   return CEED_ERROR_SUCCESS;
1646e2f04181SAndrew T. Barker }
1647e2f04181SAndrew T. Barker 
1648e2f04181SAndrew T. Barker /**
1649e2f04181SAndrew T. Barker    @ref Utility
1650e2f04181SAndrew T. Barker **/
1651*d1d35e2fSjeremylt int CeedSingleOperatorAssemblyCountEntries(CeedOperator op,
1652*d1d35e2fSjeremylt     CeedInt *num_entries) {
1653e2f04181SAndrew T. Barker   int ierr;
1654e2f04181SAndrew T. Barker   CeedElemRestriction rstr;
1655*d1d35e2fSjeremylt   CeedInt num_elem, elem_size, num_comp;
1656e2f04181SAndrew T. Barker 
1657e2f04181SAndrew T. Barker   if (op->composite)
1658e2f04181SAndrew T. Barker     // LCOV_EXCL_START
1659e2f04181SAndrew T. Barker     return CeedError(op->ceed, CEED_ERROR_UNSUPPORTED,
1660e2f04181SAndrew T. Barker                      "Composite operator not supported");
1661e2f04181SAndrew T. Barker   // LCOV_EXCL_STOP
1662e2f04181SAndrew T. Barker   ierr = CeedOperatorGetActiveElemRestriction(op, &rstr); CeedChk(ierr);
1663*d1d35e2fSjeremylt   ierr = CeedElemRestrictionGetNumElements(rstr, &num_elem); CeedChk(ierr);
1664*d1d35e2fSjeremylt   ierr = CeedElemRestrictionGetElementSize(rstr, &elem_size); CeedChk(ierr);
1665*d1d35e2fSjeremylt   ierr = CeedElemRestrictionGetNumComponents(rstr, &num_comp); CeedChk(ierr);
1666*d1d35e2fSjeremylt   *num_entries = elem_size*num_comp * elem_size*num_comp * num_elem;
1667e2f04181SAndrew T. Barker 
1668e2f04181SAndrew T. Barker   return CEED_ERROR_SUCCESS;
1669e2f04181SAndrew T. Barker }
1670e2f04181SAndrew T. Barker 
1671e2f04181SAndrew T. Barker /**
1672e2f04181SAndrew T. Barker    @brief Fully assemble the nonzero pattern of a linear operator.
1673e2f04181SAndrew T. Barker 
1674e2f04181SAndrew T. Barker    Expected to be used in conjunction with CeedOperatorLinearAssemble()
1675e2f04181SAndrew T. Barker 
1676*d1d35e2fSjeremylt    The assembly routines use coordinate format, with num_entries tuples of the
1677e2f04181SAndrew T. Barker    form (i, j, value) which indicate that value should be added to the matrix
1678e2f04181SAndrew T. Barker    in entry (i, j). Note that the (i, j) pairs are not unique and may repeat.
1679e2f04181SAndrew T. Barker    This function returns the number of entries and their (i, j) locations,
1680e2f04181SAndrew T. Barker    while CeedOperatorLinearAssemble() provides the values in the same
1681e2f04181SAndrew T. Barker    ordering.
1682e2f04181SAndrew T. Barker 
1683e2f04181SAndrew T. Barker    This will generally be slow unless your operator is low-order.
1684e2f04181SAndrew T. Barker 
1685e2f04181SAndrew T. Barker    @param[in]  op           CeedOperator to assemble
1686*d1d35e2fSjeremylt    @param[out] num_entries  Number of entries in coordinate nonzero pattern.
1687e2f04181SAndrew T. Barker    @param[out] rows         Row number for each entry.
1688e2f04181SAndrew T. Barker    @param[out] cols         Column number for each entry.
1689e2f04181SAndrew T. Barker 
1690e2f04181SAndrew T. Barker    @ref User
1691e2f04181SAndrew T. Barker **/
1692e2f04181SAndrew T. Barker int CeedOperatorLinearAssembleSymbolic(CeedOperator op,
1693*d1d35e2fSjeremylt                                        CeedInt *num_entries, CeedInt **rows, CeedInt **cols) {
1694e2f04181SAndrew T. Barker   int ierr;
1695*d1d35e2fSjeremylt   CeedInt num_suboperators, single_entries;
1696*d1d35e2fSjeremylt   CeedOperator *sub_operators;
1697*d1d35e2fSjeremylt   bool is_composite;
1698e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
1699e2f04181SAndrew T. Barker 
1700e2f04181SAndrew T. Barker   // Use backend version, if available
1701e2f04181SAndrew T. Barker   if (op->LinearAssembleSymbolic) {
1702*d1d35e2fSjeremylt     return op->LinearAssembleSymbolic(op, num_entries, rows, cols);
1703e2f04181SAndrew T. Barker   } else {
1704e2f04181SAndrew T. Barker     // Check for valid fallback resource
1705*d1d35e2fSjeremylt     const char *resource, *fallback_resource;
1706e2f04181SAndrew T. Barker     ierr = CeedGetResource(op->ceed, &resource); CeedChk(ierr);
1707*d1d35e2fSjeremylt     ierr = CeedGetOperatorFallbackResource(op->ceed, &fallback_resource);
1708*d1d35e2fSjeremylt     if (strcmp(fallback_resource, "") && strcmp(resource, fallback_resource)) {
1709e2f04181SAndrew T. Barker       // Fallback to reference Ceed
1710*d1d35e2fSjeremylt       if (!op->op_fallback) {
1711e2f04181SAndrew T. Barker         ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
1712e2f04181SAndrew T. Barker       }
1713e2f04181SAndrew T. Barker       // Assemble
1714*d1d35e2fSjeremylt       return CeedOperatorLinearAssembleSymbolic(op->op_fallback, num_entries, rows,
1715*d1d35e2fSjeremylt              cols);
1716e2f04181SAndrew T. Barker     }
1717e2f04181SAndrew T. Barker   }
1718e2f04181SAndrew T. Barker 
1719e2f04181SAndrew T. Barker   // if neither backend nor fallback resource provides
1720e2f04181SAndrew T. Barker   // LinearAssembleSymbolic, continue with interface-level implementation
1721e2f04181SAndrew T. Barker 
1722e2f04181SAndrew T. Barker   // count entries and allocate rows, cols arrays
1723*d1d35e2fSjeremylt   ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr);
1724*d1d35e2fSjeremylt   *num_entries = 0;
1725*d1d35e2fSjeremylt   if (is_composite) {
1726*d1d35e2fSjeremylt     ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr);
1727*d1d35e2fSjeremylt     ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr);
1728*d1d35e2fSjeremylt     for (int k = 0; k < num_suboperators; ++k) {
1729*d1d35e2fSjeremylt       ierr = CeedSingleOperatorAssemblyCountEntries(sub_operators[k],
1730e2f04181SAndrew T. Barker              &single_entries); CeedChk(ierr);
1731*d1d35e2fSjeremylt       *num_entries += single_entries;
1732e2f04181SAndrew T. Barker     }
1733e2f04181SAndrew T. Barker   } else {
1734e2f04181SAndrew T. Barker     ierr = CeedSingleOperatorAssemblyCountEntries(op,
1735e2f04181SAndrew T. Barker            &single_entries); CeedChk(ierr);
1736*d1d35e2fSjeremylt     *num_entries += single_entries;
1737e2f04181SAndrew T. Barker   }
1738*d1d35e2fSjeremylt   ierr = CeedCalloc(*num_entries, rows); CeedChk(ierr);
1739*d1d35e2fSjeremylt   ierr = CeedCalloc(*num_entries, cols); CeedChk(ierr);
1740e2f04181SAndrew T. Barker 
1741e2f04181SAndrew T. Barker   // assemble nonzero locations
1742e2f04181SAndrew T. Barker   CeedInt offset = 0;
1743*d1d35e2fSjeremylt   if (is_composite) {
1744*d1d35e2fSjeremylt     ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr);
1745*d1d35e2fSjeremylt     ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr);
1746*d1d35e2fSjeremylt     for (int k = 0; k < num_suboperators; ++k) {
1747*d1d35e2fSjeremylt       ierr = CeedSingleOperatorAssembleSymbolic(sub_operators[k], offset, *rows,
1748e2f04181SAndrew T. Barker              *cols); CeedChk(ierr);
1749*d1d35e2fSjeremylt       ierr = CeedSingleOperatorAssemblyCountEntries(sub_operators[k],
1750*d1d35e2fSjeremylt              &single_entries);
1751e2f04181SAndrew T. Barker       CeedChk(ierr);
1752e2f04181SAndrew T. Barker       offset += single_entries;
1753e2f04181SAndrew T. Barker     }
1754e2f04181SAndrew T. Barker   } else {
1755e2f04181SAndrew T. Barker     ierr = CeedSingleOperatorAssembleSymbolic(op, offset, *rows, *cols);
1756e2f04181SAndrew T. Barker     CeedChk(ierr);
1757e2f04181SAndrew T. Barker   }
1758e2f04181SAndrew T. Barker 
1759e2f04181SAndrew T. Barker   return CEED_ERROR_SUCCESS;
1760e2f04181SAndrew T. Barker }
1761e2f04181SAndrew T. Barker 
1762e2f04181SAndrew T. Barker /**
1763e2f04181SAndrew T. Barker    @brief Fully assemble the nonzero entries of a linear operator.
1764e2f04181SAndrew T. Barker 
1765e2f04181SAndrew T. Barker    Expected to be used in conjunction with CeedOperatorLinearAssembleSymbolic()
1766e2f04181SAndrew T. Barker 
1767*d1d35e2fSjeremylt    The assembly routines use coordinate format, with num_entries tuples of the
1768e2f04181SAndrew T. Barker    form (i, j, value) which indicate that value should be added to the matrix
1769e2f04181SAndrew T. Barker    in entry (i, j). Note that the (i, j) pairs are not unique and may repeat.
1770e2f04181SAndrew T. Barker    This function returns the values of the nonzero entries to be added, their
1771e2f04181SAndrew T. Barker    (i, j) locations are provided by CeedOperatorLinearAssembleSymbolic()
1772e2f04181SAndrew T. Barker 
1773e2f04181SAndrew T. Barker    This will generally be slow unless your operator is low-order.
1774e2f04181SAndrew T. Barker 
1775e2f04181SAndrew T. Barker    @param[in]  op      CeedOperator to assemble
1776e2f04181SAndrew T. Barker    @param[out] values  Values to assemble into matrix
1777e2f04181SAndrew T. Barker 
1778e2f04181SAndrew T. Barker    @ref User
1779e2f04181SAndrew T. Barker **/
1780e2f04181SAndrew T. Barker int CeedOperatorLinearAssemble(CeedOperator op, CeedVector values) {
1781e2f04181SAndrew T. Barker   int ierr;
1782*d1d35e2fSjeremylt   CeedInt num_suboperators, single_entries;
1783*d1d35e2fSjeremylt   CeedOperator *sub_operators;
1784e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
1785e2f04181SAndrew T. Barker 
1786e2f04181SAndrew T. Barker   // Use backend version, if available
1787e2f04181SAndrew T. Barker   if (op->LinearAssemble) {
1788e2f04181SAndrew T. Barker     return op->LinearAssemble(op, values);
1789e2f04181SAndrew T. Barker   } else {
1790e2f04181SAndrew T. Barker     // Check for valid fallback resource
1791*d1d35e2fSjeremylt     const char *resource, *fallback_resource;
1792e2f04181SAndrew T. Barker     ierr = CeedGetResource(op->ceed, &resource); CeedChk(ierr);
1793*d1d35e2fSjeremylt     ierr = CeedGetOperatorFallbackResource(op->ceed, &fallback_resource);
1794*d1d35e2fSjeremylt     if (strcmp(fallback_resource, "") && strcmp(resource, fallback_resource)) {
1795e2f04181SAndrew T. Barker       // Fallback to reference Ceed
1796*d1d35e2fSjeremylt       if (!op->op_fallback) {
1797e2f04181SAndrew T. Barker         ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
1798e2f04181SAndrew T. Barker       }
1799e2f04181SAndrew T. Barker       // Assemble
1800*d1d35e2fSjeremylt       return CeedOperatorLinearAssemble(op->op_fallback, values);
1801e2f04181SAndrew T. Barker     }
1802e2f04181SAndrew T. Barker   }
1803e2f04181SAndrew T. Barker 
1804e2f04181SAndrew T. Barker   // if neither backend nor fallback resource provides
1805e2f04181SAndrew T. Barker   // LinearAssemble, continue with interface-level implementation
1806e2f04181SAndrew T. Barker 
1807*d1d35e2fSjeremylt   bool is_composite;
1808*d1d35e2fSjeremylt   ierr = CeedOperatorIsComposite(op, &is_composite); CeedChk(ierr);
1809e2f04181SAndrew T. Barker 
1810e2f04181SAndrew T. Barker   CeedInt offset = 0;
1811*d1d35e2fSjeremylt   if (is_composite) {
1812*d1d35e2fSjeremylt     ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr);
1813*d1d35e2fSjeremylt     ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr);
1814*d1d35e2fSjeremylt     for (int k = 0; k < num_suboperators; ++k) {
1815*d1d35e2fSjeremylt       ierr = CeedSingleOperatorAssemble(sub_operators[k], offset, values);
1816e2f04181SAndrew T. Barker       CeedChk(ierr);
1817*d1d35e2fSjeremylt       ierr = CeedSingleOperatorAssemblyCountEntries(sub_operators[k],
1818*d1d35e2fSjeremylt              &single_entries);
1819e2f04181SAndrew T. Barker       CeedChk(ierr);
1820e2f04181SAndrew T. Barker       offset += single_entries;
1821e2f04181SAndrew T. Barker     }
1822e2f04181SAndrew T. Barker   } else {
1823e2f04181SAndrew T. Barker     ierr = CeedSingleOperatorAssemble(op, offset, values); CeedChk(ierr);
1824e2f04181SAndrew T. Barker   }
1825e2f04181SAndrew T. Barker 
1826e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1827d965c7a7SJeremy L Thompson }
1828d965c7a7SJeremy L Thompson 
1829d965c7a7SJeremy L Thompson /**
1830d99fa3c5SJeremy L Thompson   @brief Create a multigrid coarse operator and level transfer operators
1831d99fa3c5SJeremy L Thompson            for a CeedOperator, creating the prolongation basis from the
1832d99fa3c5SJeremy L Thompson            fine and coarse grid interpolation
1833d99fa3c5SJeremy L Thompson 
1834*d1d35e2fSjeremylt   @param[in] op_fine       Fine grid operator
1835*d1d35e2fSjeremylt   @param[in] p_mult_fine   L-vector multiplicity in parallel gather/scatter
1836*d1d35e2fSjeremylt   @param[in] rstr_coarse   Coarse grid restriction
1837*d1d35e2fSjeremylt   @param[in] basis_coarse  Coarse grid active vector basis
1838*d1d35e2fSjeremylt   @param[out] op_coarse    Coarse grid operator
1839*d1d35e2fSjeremylt   @param[out] op_prolong   Coarse to fine operator
1840*d1d35e2fSjeremylt   @param[out] op_restrict  Fine to coarse operator
1841d99fa3c5SJeremy L Thompson 
1842d99fa3c5SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1843d99fa3c5SJeremy L Thompson 
1844d99fa3c5SJeremy L Thompson   @ref User
1845d99fa3c5SJeremy L Thompson **/
1846*d1d35e2fSjeremylt int CeedOperatorMultigridLevelCreate(CeedOperator op_fine,
1847*d1d35e2fSjeremylt                                      CeedVector p_mult_fine,
1848*d1d35e2fSjeremylt                                      CeedElemRestriction rstr_coarse, CeedBasis basis_coarse,
1849*d1d35e2fSjeremylt                                      CeedOperator *op_coarse, CeedOperator *op_prolong,
1850*d1d35e2fSjeremylt                                      CeedOperator *op_restrict) {
1851d99fa3c5SJeremy L Thompson   int ierr;
1852d99fa3c5SJeremy L Thompson   Ceed ceed;
1853*d1d35e2fSjeremylt   ierr = CeedOperatorGetCeed(op_fine, &ceed); CeedChk(ierr);
1854d99fa3c5SJeremy L Thompson 
1855d99fa3c5SJeremy L Thompson   // Check for compatible quadrature spaces
1856*d1d35e2fSjeremylt   CeedBasis basis_fine;
1857*d1d35e2fSjeremylt   ierr = CeedOperatorGetActiveBasis(op_fine, &basis_fine); CeedChk(ierr);
1858*d1d35e2fSjeremylt   CeedInt Q_f, Q_c;
1859*d1d35e2fSjeremylt   ierr = CeedBasisGetNumQuadraturePoints(basis_fine, &Q_f); CeedChk(ierr);
1860*d1d35e2fSjeremylt   ierr = CeedBasisGetNumQuadraturePoints(basis_coarse, &Q_c); CeedChk(ierr);
1861*d1d35e2fSjeremylt   if (Q_f != Q_c)
1862d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
1863e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_DIMENSION,
1864e15f9bd0SJeremy L Thompson                      "Bases must have compatible quadrature spaces");
1865d99fa3c5SJeremy L Thompson   // LCOV_EXCL_STOP
1866d99fa3c5SJeremy L Thompson 
1867d99fa3c5SJeremy L Thompson   // Coarse to fine basis
1868*d1d35e2fSjeremylt   CeedInt P_f, P_c, Q = Q_f;
1869*d1d35e2fSjeremylt   bool is_tensor_f, is_tensor_c;
1870*d1d35e2fSjeremylt   ierr = CeedBasisIsTensor(basis_fine, &is_tensor_f); CeedChk(ierr);
1871*d1d35e2fSjeremylt   ierr = CeedBasisIsTensor(basis_coarse, &is_tensor_c); CeedChk(ierr);
1872*d1d35e2fSjeremylt   CeedScalar *interp_c, *interp_f, *interp_c_to_f, *tau;
1873*d1d35e2fSjeremylt   if (is_tensor_f && is_tensor_c) {
1874*d1d35e2fSjeremylt     ierr = CeedBasisGetNumNodes1D(basis_fine, &P_f); CeedChk(ierr);
1875*d1d35e2fSjeremylt     ierr = CeedBasisGetNumNodes1D(basis_coarse, &P_c); CeedChk(ierr);
1876*d1d35e2fSjeremylt     ierr = CeedBasisGetNumQuadraturePoints1D(basis_coarse, &Q); CeedChk(ierr);
1877*d1d35e2fSjeremylt   } else if (!is_tensor_f && !is_tensor_c) {
1878*d1d35e2fSjeremylt     ierr = CeedBasisGetNumNodes(basis_fine, &P_f); CeedChk(ierr);
1879*d1d35e2fSjeremylt     ierr = CeedBasisGetNumNodes(basis_coarse, &P_c); CeedChk(ierr);
1880d99fa3c5SJeremy L Thompson   } else {
1881d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
1882e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_MINOR,
1883e15f9bd0SJeremy L Thompson                      "Bases must both be tensor or non-tensor");
1884d99fa3c5SJeremy L Thompson     // LCOV_EXCL_STOP
1885d99fa3c5SJeremy L Thompson   }
1886d99fa3c5SJeremy L Thompson 
1887*d1d35e2fSjeremylt   ierr = CeedMalloc(Q*P_f, &interp_f); CeedChk(ierr);
1888*d1d35e2fSjeremylt   ierr = CeedMalloc(Q*P_c, &interp_c); CeedChk(ierr);
1889*d1d35e2fSjeremylt   ierr = CeedCalloc(P_c*P_f, &interp_c_to_f); CeedChk(ierr);
1890d99fa3c5SJeremy L Thompson   ierr = CeedMalloc(Q, &tau); CeedChk(ierr);
1891*d1d35e2fSjeremylt   if (is_tensor_f) {
1892*d1d35e2fSjeremylt     memcpy(interp_f, basis_fine->interp_1d, Q*P_f*sizeof basis_fine->interp_1d[0]);
1893*d1d35e2fSjeremylt     memcpy(interp_c, basis_coarse->interp_1d,
1894*d1d35e2fSjeremylt            Q*P_c*sizeof basis_coarse->interp_1d[0]);
1895d99fa3c5SJeremy L Thompson   } else {
1896*d1d35e2fSjeremylt     memcpy(interp_f, basis_fine->interp, Q*P_f*sizeof basis_fine->interp[0]);
1897*d1d35e2fSjeremylt     memcpy(interp_c, basis_coarse->interp, Q*P_c*sizeof basis_coarse->interp[0]);
1898d99fa3c5SJeremy L Thompson   }
1899d99fa3c5SJeremy L Thompson 
1900*d1d35e2fSjeremylt   // -- QR Factorization, interp_f = Q R
1901*d1d35e2fSjeremylt   ierr = CeedQRFactorization(ceed, interp_f, tau, Q, P_f); CeedChk(ierr);
1902d99fa3c5SJeremy L Thompson 
1903*d1d35e2fSjeremylt   // -- Apply Qtranspose, interp_c = Qtranspose interp_c
1904*d1d35e2fSjeremylt   ierr = CeedHouseholderApplyQ(interp_c, interp_f, tau, CEED_TRANSPOSE,
1905*d1d35e2fSjeremylt                                Q, P_c, P_f, P_c, 1); CeedChk(ierr);
1906d99fa3c5SJeremy L Thompson 
1907*d1d35e2fSjeremylt   // -- Apply Rinv, interp_c_to_f = Rinv interp_c
1908*d1d35e2fSjeremylt   for (CeedInt j=0; j<P_c; j++) { // Column j
1909*d1d35e2fSjeremylt     interp_c_to_f[j+P_c*(P_f-1)] = interp_c[j+P_c*(P_f-1)]/interp_f[P_f*P_f-1];
1910*d1d35e2fSjeremylt     for (CeedInt i=P_f-2; i>=0; i--) { // Row i
1911*d1d35e2fSjeremylt       interp_c_to_f[j+P_c*i] = interp_c[j+P_c*i];
1912*d1d35e2fSjeremylt       for (CeedInt k=i+1; k<P_f; k++)
1913*d1d35e2fSjeremylt         interp_c_to_f[j+P_c*i] -= interp_f[k+P_f*i]*interp_c_to_f[j+P_c*k];
1914*d1d35e2fSjeremylt       interp_c_to_f[j+P_c*i] /= interp_f[i+P_f*i];
1915d99fa3c5SJeremy L Thompson     }
1916d99fa3c5SJeremy L Thompson   }
1917d99fa3c5SJeremy L Thompson   ierr = CeedFree(&tau); CeedChk(ierr);
1918*d1d35e2fSjeremylt   ierr = CeedFree(&interp_c); CeedChk(ierr);
1919*d1d35e2fSjeremylt   ierr = CeedFree(&interp_f); CeedChk(ierr);
1920d99fa3c5SJeremy L Thompson 
1921*d1d35e2fSjeremylt   // Complete with interp_c_to_f versions of code
1922*d1d35e2fSjeremylt   if (is_tensor_f) {
1923*d1d35e2fSjeremylt     ierr = CeedOperatorMultigridLevelCreateTensorH1(op_fine, p_mult_fine,
1924*d1d35e2fSjeremylt            rstr_coarse, basis_coarse, interp_c_to_f, op_coarse, op_prolong, op_restrict);
1925d99fa3c5SJeremy L Thompson     CeedChk(ierr);
1926d99fa3c5SJeremy L Thompson   } else {
1927*d1d35e2fSjeremylt     ierr = CeedOperatorMultigridLevelCreateH1(op_fine, p_mult_fine,
1928*d1d35e2fSjeremylt            rstr_coarse, basis_coarse, interp_c_to_f, op_coarse, op_prolong, op_restrict);
1929d99fa3c5SJeremy L Thompson     CeedChk(ierr);
1930d99fa3c5SJeremy L Thompson   }
1931d99fa3c5SJeremy L Thompson 
1932d99fa3c5SJeremy L Thompson   // Cleanup
1933*d1d35e2fSjeremylt   ierr = CeedFree(&interp_c_to_f); CeedChk(ierr);
1934e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1935d99fa3c5SJeremy L Thompson }
1936d99fa3c5SJeremy L Thompson 
1937d99fa3c5SJeremy L Thompson /**
1938d99fa3c5SJeremy L Thompson   @brief Create a multigrid coarse operator and level transfer operators
1939d99fa3c5SJeremy L Thompson            for a CeedOperator with a tensor basis for the active basis
1940d99fa3c5SJeremy L Thompson 
1941*d1d35e2fSjeremylt   @param[in] op_fine        Fine grid operator
1942*d1d35e2fSjeremylt   @param[in] p_mult_fine    L-vector multiplicity in parallel gather/scatter
1943*d1d35e2fSjeremylt   @param[in] rstr_coarse    Coarse grid restriction
1944*d1d35e2fSjeremylt   @param[in] basis_coarse   Coarse grid active vector basis
1945*d1d35e2fSjeremylt   @param[in] interp_c_to_f  Matrix for coarse to fine interpolation
1946*d1d35e2fSjeremylt   @param[out] op_coarse     Coarse grid operator
1947*d1d35e2fSjeremylt   @param[out] op_prolong    Coarse to fine operator
1948*d1d35e2fSjeremylt   @param[out] op_restrict   Fine to coarse operator
1949d99fa3c5SJeremy L Thompson 
1950d99fa3c5SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1951d99fa3c5SJeremy L Thompson 
1952d99fa3c5SJeremy L Thompson   @ref User
1953d99fa3c5SJeremy L Thompson **/
1954*d1d35e2fSjeremylt int CeedOperatorMultigridLevelCreateTensorH1(CeedOperator op_fine,
1955*d1d35e2fSjeremylt     CeedVector p_mult_fine, CeedElemRestriction rstr_coarse, CeedBasis basis_coarse,
1956*d1d35e2fSjeremylt     const CeedScalar *interp_c_to_f, CeedOperator *op_coarse,
1957*d1d35e2fSjeremylt     CeedOperator *op_prolong, CeedOperator *op_restrict) {
1958d99fa3c5SJeremy L Thompson   int ierr;
1959d99fa3c5SJeremy L Thompson   Ceed ceed;
1960*d1d35e2fSjeremylt   ierr = CeedOperatorGetCeed(op_fine, &ceed); CeedChk(ierr);
1961d99fa3c5SJeremy L Thompson 
1962d99fa3c5SJeremy L Thompson   // Check for compatible quadrature spaces
1963*d1d35e2fSjeremylt   CeedBasis basis_fine;
1964*d1d35e2fSjeremylt   ierr = CeedOperatorGetActiveBasis(op_fine, &basis_fine); CeedChk(ierr);
1965*d1d35e2fSjeremylt   CeedInt Q_f, Q_c;
1966*d1d35e2fSjeremylt   ierr = CeedBasisGetNumQuadraturePoints(basis_fine, &Q_f); CeedChk(ierr);
1967*d1d35e2fSjeremylt   ierr = CeedBasisGetNumQuadraturePoints(basis_coarse, &Q_c); CeedChk(ierr);
1968*d1d35e2fSjeremylt   if (Q_f != Q_c)
1969d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
1970e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_DIMENSION,
1971e15f9bd0SJeremy L Thompson                      "Bases must have compatible quadrature spaces");
1972d99fa3c5SJeremy L Thompson   // LCOV_EXCL_STOP
1973d99fa3c5SJeremy L Thompson 
1974d99fa3c5SJeremy L Thompson   // Coarse to fine basis
1975*d1d35e2fSjeremylt   CeedInt dim, num_comp, num_nodes_c, P_1d_f, P_1d_c;
1976*d1d35e2fSjeremylt   ierr = CeedBasisGetDimension(basis_fine, &dim); CeedChk(ierr);
1977*d1d35e2fSjeremylt   ierr = CeedBasisGetNumComponents(basis_fine, &num_comp); CeedChk(ierr);
1978*d1d35e2fSjeremylt   ierr = CeedBasisGetNumNodes1D(basis_fine, &P_1d_f); CeedChk(ierr);
1979*d1d35e2fSjeremylt   ierr = CeedElemRestrictionGetElementSize(rstr_coarse, &num_nodes_c);
1980d99fa3c5SJeremy L Thompson   CeedChk(ierr);
1981*d1d35e2fSjeremylt   P_1d_c = dim == 1 ? num_nodes_c :
1982*d1d35e2fSjeremylt            dim == 2 ? sqrt(num_nodes_c) :
1983*d1d35e2fSjeremylt            cbrt(num_nodes_c);
1984*d1d35e2fSjeremylt   CeedScalar *q_ref, *q_weight, *grad;
1985*d1d35e2fSjeremylt   ierr = CeedCalloc(P_1d_f, &q_ref); CeedChk(ierr);
1986*d1d35e2fSjeremylt   ierr = CeedCalloc(P_1d_f, &q_weight); CeedChk(ierr);
1987*d1d35e2fSjeremylt   ierr = CeedCalloc(P_1d_f*P_1d_c*dim, &grad); CeedChk(ierr);
1988*d1d35e2fSjeremylt   CeedBasis basis_c_to_f;
1989*d1d35e2fSjeremylt   ierr = CeedBasisCreateTensorH1(ceed, dim, num_comp, P_1d_c, P_1d_f,
1990*d1d35e2fSjeremylt                                  interp_c_to_f, grad, q_ref, q_weight, &basis_c_to_f);
1991d99fa3c5SJeremy L Thompson   CeedChk(ierr);
1992*d1d35e2fSjeremylt   ierr = CeedFree(&q_ref); CeedChk(ierr);
1993*d1d35e2fSjeremylt   ierr = CeedFree(&q_weight); CeedChk(ierr);
1994d99fa3c5SJeremy L Thompson   ierr = CeedFree(&grad); CeedChk(ierr);
1995d99fa3c5SJeremy L Thompson 
1996d99fa3c5SJeremy L Thompson   // Core code
1997*d1d35e2fSjeremylt   ierr = CeedOperatorMultigridLevel_Core(op_fine, p_mult_fine, rstr_coarse,
1998*d1d35e2fSjeremylt                                          basis_coarse, basis_c_to_f, op_coarse,
1999*d1d35e2fSjeremylt                                          op_prolong, op_restrict);
2000d99fa3c5SJeremy L Thompson   CeedChk(ierr);
2001e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2002d99fa3c5SJeremy L Thompson }
2003d99fa3c5SJeremy L Thompson 
2004d99fa3c5SJeremy L Thompson /**
2005d99fa3c5SJeremy L Thompson   @brief Create a multigrid coarse operator and level transfer operators
2006d99fa3c5SJeremy L Thompson            for a CeedOperator with a non-tensor basis for the active vector
2007d99fa3c5SJeremy L Thompson 
2008*d1d35e2fSjeremylt   @param[in] op_fine        Fine grid operator
2009*d1d35e2fSjeremylt   @param[in] p_mult_fine    L-vector multiplicity in parallel gather/scatter
2010*d1d35e2fSjeremylt   @param[in] rstr_coarse    Coarse grid restriction
2011*d1d35e2fSjeremylt   @param[in] basis_coarse   Coarse grid active vector basis
2012*d1d35e2fSjeremylt   @param[in] interp_c_to_f  Matrix for coarse to fine interpolation
2013*d1d35e2fSjeremylt   @param[out] op_coarse     Coarse grid operator
2014*d1d35e2fSjeremylt   @param[out] op_prolong    Coarse to fine operator
2015*d1d35e2fSjeremylt   @param[out] op_restrict   Fine to coarse operator
2016d99fa3c5SJeremy L Thompson 
2017d99fa3c5SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
2018d99fa3c5SJeremy L Thompson 
2019d99fa3c5SJeremy L Thompson   @ref User
2020d99fa3c5SJeremy L Thompson **/
2021*d1d35e2fSjeremylt int CeedOperatorMultigridLevelCreateH1(CeedOperator op_fine,
2022*d1d35e2fSjeremylt                                        CeedVector p_mult_fine,
2023*d1d35e2fSjeremylt                                        CeedElemRestriction rstr_coarse,
2024*d1d35e2fSjeremylt                                        CeedBasis basis_coarse,
2025*d1d35e2fSjeremylt                                        const CeedScalar *interp_c_to_f,
2026*d1d35e2fSjeremylt                                        CeedOperator *op_coarse,
2027*d1d35e2fSjeremylt                                        CeedOperator *op_prolong,
2028*d1d35e2fSjeremylt                                        CeedOperator *op_restrict) {
2029d99fa3c5SJeremy L Thompson   int ierr;
2030d99fa3c5SJeremy L Thompson   Ceed ceed;
2031*d1d35e2fSjeremylt   ierr = CeedOperatorGetCeed(op_fine, &ceed); CeedChk(ierr);
2032d99fa3c5SJeremy L Thompson 
2033d99fa3c5SJeremy L Thompson   // Check for compatible quadrature spaces
2034*d1d35e2fSjeremylt   CeedBasis basis_fine;
2035*d1d35e2fSjeremylt   ierr = CeedOperatorGetActiveBasis(op_fine, &basis_fine); CeedChk(ierr);
2036*d1d35e2fSjeremylt   CeedInt Q_f, Q_c;
2037*d1d35e2fSjeremylt   ierr = CeedBasisGetNumQuadraturePoints(basis_fine, &Q_f); CeedChk(ierr);
2038*d1d35e2fSjeremylt   ierr = CeedBasisGetNumQuadraturePoints(basis_coarse, &Q_c); CeedChk(ierr);
2039*d1d35e2fSjeremylt   if (Q_f != Q_c)
2040d99fa3c5SJeremy L Thompson     // LCOV_EXCL_START
2041e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_DIMENSION,
2042e15f9bd0SJeremy L Thompson                      "Bases must have compatible quadrature spaces");
2043d99fa3c5SJeremy L Thompson   // LCOV_EXCL_STOP
2044d99fa3c5SJeremy L Thompson 
2045d99fa3c5SJeremy L Thompson   // Coarse to fine basis
2046d99fa3c5SJeremy L Thompson   CeedElemTopology topo;
2047*d1d35e2fSjeremylt   ierr = CeedBasisGetTopology(basis_fine, &topo); CeedChk(ierr);
2048*d1d35e2fSjeremylt   CeedInt dim, num_comp, num_nodes_c, num_nodes_f;
2049*d1d35e2fSjeremylt   ierr = CeedBasisGetDimension(basis_fine, &dim); CeedChk(ierr);
2050*d1d35e2fSjeremylt   ierr = CeedBasisGetNumComponents(basis_fine, &num_comp); CeedChk(ierr);
2051*d1d35e2fSjeremylt   ierr = CeedBasisGetNumNodes(basis_fine, &num_nodes_f); CeedChk(ierr);
2052*d1d35e2fSjeremylt   ierr = CeedElemRestrictionGetElementSize(rstr_coarse, &num_nodes_c);
2053d99fa3c5SJeremy L Thompson   CeedChk(ierr);
2054*d1d35e2fSjeremylt   CeedScalar *q_ref, *q_weight, *grad;
2055*d1d35e2fSjeremylt   ierr = CeedCalloc(num_nodes_f, &q_ref); CeedChk(ierr);
2056*d1d35e2fSjeremylt   ierr = CeedCalloc(num_nodes_f, &q_weight); CeedChk(ierr);
2057*d1d35e2fSjeremylt   ierr = CeedCalloc(num_nodes_f*num_nodes_c*dim, &grad); CeedChk(ierr);
2058*d1d35e2fSjeremylt   CeedBasis basis_c_to_f;
2059*d1d35e2fSjeremylt   ierr = CeedBasisCreateH1(ceed, topo, num_comp, num_nodes_c, num_nodes_f,
2060*d1d35e2fSjeremylt                            interp_c_to_f, grad, q_ref, q_weight, &basis_c_to_f);
2061d99fa3c5SJeremy L Thompson   CeedChk(ierr);
2062*d1d35e2fSjeremylt   ierr = CeedFree(&q_ref); CeedChk(ierr);
2063*d1d35e2fSjeremylt   ierr = CeedFree(&q_weight); CeedChk(ierr);
2064d99fa3c5SJeremy L Thompson   ierr = CeedFree(&grad); CeedChk(ierr);
2065d99fa3c5SJeremy L Thompson 
2066d99fa3c5SJeremy L Thompson   // Core code
2067*d1d35e2fSjeremylt   ierr = CeedOperatorMultigridLevel_Core(op_fine, p_mult_fine, rstr_coarse,
2068*d1d35e2fSjeremylt                                          basis_coarse, basis_c_to_f, op_coarse,
2069*d1d35e2fSjeremylt                                          op_prolong, op_restrict);
2070d99fa3c5SJeremy L Thompson   CeedChk(ierr);
2071e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2072d99fa3c5SJeremy L Thompson }
2073d99fa3c5SJeremy L Thompson 
2074d99fa3c5SJeremy L Thompson /**
20753bd813ffSjeremylt   @brief Build a FDM based approximate inverse for each element for a
20763bd813ffSjeremylt            CeedOperator
20773bd813ffSjeremylt 
20783bd813ffSjeremylt   This returns a CeedOperator and CeedVector to apply a Fast Diagonalization
20793bd813ffSjeremylt     Method based approximate inverse. This function obtains the simultaneous
20803bd813ffSjeremylt     diagonalization for the 1D mass and Laplacian operators,
20813bd813ffSjeremylt       M = V^T V, K = V^T S V.
20823bd813ffSjeremylt     The assembled QFunction is used to modify the eigenvalues from simultaneous
20833bd813ffSjeremylt     diagonalization and obtain an approximate inverse of the form
20843bd813ffSjeremylt       V^T S^hat V. The CeedOperator must be linear and non-composite. The
20853bd813ffSjeremylt     associated CeedQFunction must therefore also be linear.
20863bd813ffSjeremylt 
20873bd813ffSjeremylt   @param op            CeedOperator to create element inverses
2088*d1d35e2fSjeremylt   @param[out] fdm_inv  CeedOperator to apply the action of a FDM based inverse
20893bd813ffSjeremylt                          for each element
20903bd813ffSjeremylt   @param request       Address of CeedRequest for non-blocking completion, else
20914cc79fe7SJed Brown                          @ref CEED_REQUEST_IMMEDIATE
20923bd813ffSjeremylt 
20933bd813ffSjeremylt   @return An error code: 0 - success, otherwise - failure
20943bd813ffSjeremylt 
20957a982d89SJeremy L. Thompson   @ref Backend
20963bd813ffSjeremylt **/
2097*d1d35e2fSjeremylt int CeedOperatorCreateFDMElementInverse(CeedOperator op, CeedOperator *fdm_inv,
20983bd813ffSjeremylt                                         CeedRequest *request) {
20993bd813ffSjeremylt   int ierr;
2100e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
21013bd813ffSjeremylt 
2102713f43c3Sjeremylt   // Use backend version, if available
2103713f43c3Sjeremylt   if (op->CreateFDMElementInverse) {
2104*d1d35e2fSjeremylt     ierr = op->CreateFDMElementInverse(op, fdm_inv, request); CeedChk(ierr);
2105713f43c3Sjeremylt   } else {
2106713f43c3Sjeremylt     // Fallback to reference Ceed
2107*d1d35e2fSjeremylt     if (!op->op_fallback) {
2108713f43c3Sjeremylt       ierr = CeedOperatorCreateFallback(op); CeedChk(ierr);
21093bd813ffSjeremylt     }
2110713f43c3Sjeremylt     // Assemble
2111*d1d35e2fSjeremylt     ierr = op->op_fallback->CreateFDMElementInverse(op->op_fallback, fdm_inv,
21123bd813ffSjeremylt            request); CeedChk(ierr);
21133bd813ffSjeremylt   }
2114e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
21153bd813ffSjeremylt }
21163bd813ffSjeremylt 
21177a982d89SJeremy L. Thompson /**
21187a982d89SJeremy L. Thompson   @brief View a CeedOperator
21197a982d89SJeremy L. Thompson 
21207a982d89SJeremy L. Thompson   @param[in] op      CeedOperator to view
21217a982d89SJeremy L. Thompson   @param[in] stream  Stream to write; typically stdout/stderr or a file
21227a982d89SJeremy L. Thompson 
21237a982d89SJeremy L. Thompson   @return Error code: 0 - success, otherwise - failure
21247a982d89SJeremy L. Thompson 
21257a982d89SJeremy L. Thompson   @ref User
21267a982d89SJeremy L. Thompson **/
21277a982d89SJeremy L. Thompson int CeedOperatorView(CeedOperator op, FILE *stream) {
21287a982d89SJeremy L. Thompson   int ierr;
21297a982d89SJeremy L. Thompson 
21307a982d89SJeremy L. Thompson   if (op->composite) {
21317a982d89SJeremy L. Thompson     fprintf(stream, "Composite CeedOperator\n");
21327a982d89SJeremy L. Thompson 
2133*d1d35e2fSjeremylt     for (CeedInt i=0; i<op->num_suboperators; i++) {
21347a982d89SJeremy L. Thompson       fprintf(stream, "  SubOperator [%d]:\n", i);
2135*d1d35e2fSjeremylt       ierr = CeedOperatorSingleView(op->sub_operators[i], 1, stream);
21367a982d89SJeremy L. Thompson       CeedChk(ierr);
21377a982d89SJeremy L. Thompson     }
21387a982d89SJeremy L. Thompson   } else {
21397a982d89SJeremy L. Thompson     fprintf(stream, "CeedOperator\n");
21407a982d89SJeremy L. Thompson     ierr = CeedOperatorSingleView(op, 0, stream); CeedChk(ierr);
21417a982d89SJeremy L. Thompson   }
2142e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
21437a982d89SJeremy L. Thompson }
21443bd813ffSjeremylt 
21453bd813ffSjeremylt /**
21463bd813ffSjeremylt   @brief Apply CeedOperator to a vector
2147d7b241e6Sjeremylt 
2148d7b241e6Sjeremylt   This computes the action of the operator on the specified (active) input,
2149d7b241e6Sjeremylt   yielding its (active) output.  All inputs and outputs must be specified using
2150d7b241e6Sjeremylt   CeedOperatorSetField().
2151d7b241e6Sjeremylt 
2152d7b241e6Sjeremylt   @param op        CeedOperator to apply
21534cc79fe7SJed Brown   @param[in] in    CeedVector containing input state or @ref CEED_VECTOR_NONE if
215434138859Sjeremylt                      there are no active inputs
2155b11c1e72Sjeremylt   @param[out] out  CeedVector to store result of applying operator (must be
21564cc79fe7SJed Brown                      distinct from @a in) or @ref CEED_VECTOR_NONE if there are no
215734138859Sjeremylt                      active outputs
2158d7b241e6Sjeremylt   @param request   Address of CeedRequest for non-blocking completion, else
21594cc79fe7SJed Brown                      @ref CEED_REQUEST_IMMEDIATE
2160b11c1e72Sjeremylt 
2161b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
2162dfdf5a53Sjeremylt 
21637a982d89SJeremy L. Thompson   @ref User
2164b11c1e72Sjeremylt **/
2165692c2638Sjeremylt int CeedOperatorApply(CeedOperator op, CeedVector in, CeedVector out,
2166692c2638Sjeremylt                       CeedRequest *request) {
2167d7b241e6Sjeremylt   int ierr;
2168e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
2169d7b241e6Sjeremylt 
2170*d1d35e2fSjeremylt   if (op->num_elem)  {
2171250756a7Sjeremylt     // Standard Operator
2172cae8b89aSjeremylt     if (op->Apply) {
2173250756a7Sjeremylt       ierr = op->Apply(op, in, out, request); CeedChk(ierr);
2174cae8b89aSjeremylt     } else {
2175cae8b89aSjeremylt       // Zero all output vectors
2176250756a7Sjeremylt       CeedQFunction qf = op->qf;
2177*d1d35e2fSjeremylt       for (CeedInt i=0; i<qf->num_output_fields; i++) {
2178*d1d35e2fSjeremylt         CeedVector vec = op->output_fields[i]->vec;
2179cae8b89aSjeremylt         if (vec == CEED_VECTOR_ACTIVE)
2180cae8b89aSjeremylt           vec = out;
2181cae8b89aSjeremylt         if (vec != CEED_VECTOR_NONE) {
2182cae8b89aSjeremylt           ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr);
2183cae8b89aSjeremylt         }
2184cae8b89aSjeremylt       }
2185250756a7Sjeremylt       // Apply
2186250756a7Sjeremylt       ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr);
2187250756a7Sjeremylt     }
2188250756a7Sjeremylt   } else if (op->composite) {
2189250756a7Sjeremylt     // Composite Operator
2190250756a7Sjeremylt     if (op->ApplyComposite) {
2191250756a7Sjeremylt       ierr = op->ApplyComposite(op, in, out, request); CeedChk(ierr);
2192250756a7Sjeremylt     } else {
2193*d1d35e2fSjeremylt       CeedInt num_suboperators;
2194*d1d35e2fSjeremylt       ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr);
2195*d1d35e2fSjeremylt       CeedOperator *sub_operators;
2196*d1d35e2fSjeremylt       ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr);
2197250756a7Sjeremylt 
2198250756a7Sjeremylt       // Zero all output vectors
2199250756a7Sjeremylt       if (out != CEED_VECTOR_NONE) {
2200cae8b89aSjeremylt         ierr = CeedVectorSetValue(out, 0.0); CeedChk(ierr);
2201cae8b89aSjeremylt       }
2202*d1d35e2fSjeremylt       for (CeedInt i=0; i<num_suboperators; i++) {
2203*d1d35e2fSjeremylt         for (CeedInt j=0; j<sub_operators[i]->qf->num_output_fields; j++) {
2204*d1d35e2fSjeremylt           CeedVector vec = sub_operators[i]->output_fields[j]->vec;
2205250756a7Sjeremylt           if (vec != CEED_VECTOR_ACTIVE && vec != CEED_VECTOR_NONE) {
2206250756a7Sjeremylt             ierr = CeedVectorSetValue(vec, 0.0); CeedChk(ierr);
2207250756a7Sjeremylt           }
2208250756a7Sjeremylt         }
2209250756a7Sjeremylt       }
2210250756a7Sjeremylt       // Apply
2211*d1d35e2fSjeremylt       for (CeedInt i=0; i<op->num_suboperators; i++) {
2212*d1d35e2fSjeremylt         ierr = CeedOperatorApplyAdd(op->sub_operators[i], in, out, request);
2213cae8b89aSjeremylt         CeedChk(ierr);
2214cae8b89aSjeremylt       }
2215cae8b89aSjeremylt     }
2216250756a7Sjeremylt   }
2217e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2218cae8b89aSjeremylt }
2219cae8b89aSjeremylt 
2220cae8b89aSjeremylt /**
2221cae8b89aSjeremylt   @brief Apply CeedOperator to a vector and add result to output vector
2222cae8b89aSjeremylt 
2223cae8b89aSjeremylt   This computes the action of the operator on the specified (active) input,
2224cae8b89aSjeremylt   yielding its (active) output.  All inputs and outputs must be specified using
2225cae8b89aSjeremylt   CeedOperatorSetField().
2226cae8b89aSjeremylt 
2227cae8b89aSjeremylt   @param op        CeedOperator to apply
2228cae8b89aSjeremylt   @param[in] in    CeedVector containing input state or NULL if there are no
2229cae8b89aSjeremylt                      active inputs
2230cae8b89aSjeremylt   @param[out] out  CeedVector to sum in result of applying operator (must be
2231cae8b89aSjeremylt                      distinct from @a in) or NULL if there are no active outputs
2232cae8b89aSjeremylt   @param request   Address of CeedRequest for non-blocking completion, else
22334cc79fe7SJed Brown                      @ref CEED_REQUEST_IMMEDIATE
2234cae8b89aSjeremylt 
2235cae8b89aSjeremylt   @return An error code: 0 - success, otherwise - failure
2236cae8b89aSjeremylt 
22377a982d89SJeremy L. Thompson   @ref User
2238cae8b89aSjeremylt **/
2239cae8b89aSjeremylt int CeedOperatorApplyAdd(CeedOperator op, CeedVector in, CeedVector out,
2240cae8b89aSjeremylt                          CeedRequest *request) {
2241cae8b89aSjeremylt   int ierr;
2242e2f04181SAndrew T. Barker   ierr = CeedOperatorCheckReady(op); CeedChk(ierr);
2243cae8b89aSjeremylt 
2244*d1d35e2fSjeremylt   if (op->num_elem)  {
2245250756a7Sjeremylt     // Standard Operator
2246250756a7Sjeremylt     ierr = op->ApplyAdd(op, in, out, request); CeedChk(ierr);
2247250756a7Sjeremylt   } else if (op->composite) {
2248250756a7Sjeremylt     // Composite Operator
2249250756a7Sjeremylt     if (op->ApplyAddComposite) {
2250250756a7Sjeremylt       ierr = op->ApplyAddComposite(op, in, out, request); CeedChk(ierr);
2251cae8b89aSjeremylt     } else {
2252*d1d35e2fSjeremylt       CeedInt num_suboperators;
2253*d1d35e2fSjeremylt       ierr = CeedOperatorGetNumSub(op, &num_suboperators); CeedChk(ierr);
2254*d1d35e2fSjeremylt       CeedOperator *sub_operators;
2255*d1d35e2fSjeremylt       ierr = CeedOperatorGetSubList(op, &sub_operators); CeedChk(ierr);
2256250756a7Sjeremylt 
2257*d1d35e2fSjeremylt       for (CeedInt i=0; i<num_suboperators; i++) {
2258*d1d35e2fSjeremylt         ierr = CeedOperatorApplyAdd(sub_operators[i], in, out, request);
2259cae8b89aSjeremylt         CeedChk(ierr);
22601d7d2407SJeremy L Thompson       }
2261250756a7Sjeremylt     }
2262250756a7Sjeremylt   }
2263e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2264d7b241e6Sjeremylt }
2265d7b241e6Sjeremylt 
2266d7b241e6Sjeremylt /**
2267b11c1e72Sjeremylt   @brief Destroy a CeedOperator
2268d7b241e6Sjeremylt 
2269d7b241e6Sjeremylt   @param op  CeedOperator to destroy
2270b11c1e72Sjeremylt 
2271b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
2272dfdf5a53Sjeremylt 
22737a982d89SJeremy L. Thompson   @ref User
2274b11c1e72Sjeremylt **/
2275d7b241e6Sjeremylt int CeedOperatorDestroy(CeedOperator *op) {
2276d7b241e6Sjeremylt   int ierr;
2277d7b241e6Sjeremylt 
2278*d1d35e2fSjeremylt   if (!*op || --(*op)->ref_count > 0) return CEED_ERROR_SUCCESS;
2279d7b241e6Sjeremylt   if ((*op)->Destroy) {
2280d7b241e6Sjeremylt     ierr = (*op)->Destroy(*op); CeedChk(ierr);
2281d7b241e6Sjeremylt   }
2282fe2413ffSjeremylt   ierr = CeedDestroy(&(*op)->ceed); CeedChk(ierr);
2283fe2413ffSjeremylt   // Free fields
2284*d1d35e2fSjeremylt   for (int i=0; i<(*op)->num_fields; i++)
2285*d1d35e2fSjeremylt     if ((*op)->input_fields[i]) {
2286*d1d35e2fSjeremylt       if ((*op)->input_fields[i]->elem_restr != CEED_ELEMRESTRICTION_NONE) {
2287*d1d35e2fSjeremylt         ierr = CeedElemRestrictionDestroy(&(*op)->input_fields[i]->elem_restr);
228871352a93Sjeremylt         CeedChk(ierr);
228915910d16Sjeremylt       }
2290*d1d35e2fSjeremylt       if ((*op)->input_fields[i]->basis != CEED_BASIS_COLLOCATED) {
2291*d1d35e2fSjeremylt         ierr = CeedBasisDestroy(&(*op)->input_fields[i]->basis); CeedChk(ierr);
229271352a93Sjeremylt       }
2293*d1d35e2fSjeremylt       if ((*op)->input_fields[i]->vec != CEED_VECTOR_ACTIVE &&
2294*d1d35e2fSjeremylt           (*op)->input_fields[i]->vec != CEED_VECTOR_NONE ) {
2295*d1d35e2fSjeremylt         ierr = CeedVectorDestroy(&(*op)->input_fields[i]->vec); CeedChk(ierr);
229671352a93Sjeremylt       }
2297*d1d35e2fSjeremylt       ierr = CeedFree(&(*op)->input_fields[i]->field_name); CeedChk(ierr);
2298*d1d35e2fSjeremylt       ierr = CeedFree(&(*op)->input_fields[i]); CeedChk(ierr);
2299fe2413ffSjeremylt     }
2300*d1d35e2fSjeremylt   for (int i=0; i<(*op)->num_fields; i++)
2301*d1d35e2fSjeremylt     if ((*op)->output_fields[i]) {
2302*d1d35e2fSjeremylt       ierr = CeedElemRestrictionDestroy(&(*op)->output_fields[i]->elem_restr);
230371352a93Sjeremylt       CeedChk(ierr);
2304*d1d35e2fSjeremylt       if ((*op)->output_fields[i]->basis != CEED_BASIS_COLLOCATED) {
2305*d1d35e2fSjeremylt         ierr = CeedBasisDestroy(&(*op)->output_fields[i]->basis); CeedChk(ierr);
230671352a93Sjeremylt       }
2307*d1d35e2fSjeremylt       if ((*op)->output_fields[i]->vec != CEED_VECTOR_ACTIVE &&
2308*d1d35e2fSjeremylt           (*op)->output_fields[i]->vec != CEED_VECTOR_NONE ) {
2309*d1d35e2fSjeremylt         ierr = CeedVectorDestroy(&(*op)->output_fields[i]->vec); CeedChk(ierr);
231071352a93Sjeremylt       }
2311*d1d35e2fSjeremylt       ierr = CeedFree(&(*op)->output_fields[i]->field_name); CeedChk(ierr);
2312*d1d35e2fSjeremylt       ierr = CeedFree(&(*op)->output_fields[i]); CeedChk(ierr);
2313fe2413ffSjeremylt     }
2314*d1d35e2fSjeremylt   // Destroy sub_operators
2315*d1d35e2fSjeremylt   for (int i=0; i<(*op)->num_suboperators; i++)
2316*d1d35e2fSjeremylt     if ((*op)->sub_operators[i]) {
2317*d1d35e2fSjeremylt       ierr = CeedOperatorDestroy(&(*op)->sub_operators[i]); CeedChk(ierr);
231852d6035fSJeremy L Thompson     }
2319e15f9bd0SJeremy L Thompson   if ((*op)->qf)
2320e15f9bd0SJeremy L Thompson     // LCOV_EXCL_START
2321*d1d35e2fSjeremylt     (*op)->qf->operators_set--;
2322e15f9bd0SJeremy L Thompson   // LCOV_EXCL_STOP
2323d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->qf); CeedChk(ierr);
2324e15f9bd0SJeremy L Thompson   if ((*op)->dqf && (*op)->dqf != CEED_QFUNCTION_NONE)
2325e15f9bd0SJeremy L Thompson     // LCOV_EXCL_START
2326*d1d35e2fSjeremylt     (*op)->dqf->operators_set--;
2327e15f9bd0SJeremy L Thompson   // LCOV_EXCL_STOP
2328d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->dqf); CeedChk(ierr);
2329e15f9bd0SJeremy L Thompson   if ((*op)->dqfT && (*op)->dqfT != CEED_QFUNCTION_NONE)
2330e15f9bd0SJeremy L Thompson     // LCOV_EXCL_START
2331*d1d35e2fSjeremylt     (*op)->dqfT->operators_set--;
2332e15f9bd0SJeremy L Thompson   // LCOV_EXCL_STOP
2333d7b241e6Sjeremylt   ierr = CeedQFunctionDestroy(&(*op)->dqfT); CeedChk(ierr);
2334fe2413ffSjeremylt 
23355107b09fSJeremy L Thompson   // Destroy fallback
2336*d1d35e2fSjeremylt   if ((*op)->op_fallback) {
2337*d1d35e2fSjeremylt     ierr = (*op)->qf_fallback->Destroy((*op)->qf_fallback); CeedChk(ierr);
2338*d1d35e2fSjeremylt     ierr = CeedFree(&(*op)->qf_fallback); CeedChk(ierr);
2339*d1d35e2fSjeremylt     ierr = (*op)->op_fallback->Destroy((*op)->op_fallback); CeedChk(ierr);
2340*d1d35e2fSjeremylt     ierr = CeedFree(&(*op)->op_fallback); CeedChk(ierr);
23415107b09fSJeremy L Thompson   }
23425107b09fSJeremy L Thompson 
2343*d1d35e2fSjeremylt   ierr = CeedFree(&(*op)->input_fields); CeedChk(ierr);
2344*d1d35e2fSjeremylt   ierr = CeedFree(&(*op)->output_fields); CeedChk(ierr);
2345*d1d35e2fSjeremylt   ierr = CeedFree(&(*op)->sub_operators); CeedChk(ierr);
2346d7b241e6Sjeremylt   ierr = CeedFree(op); CeedChk(ierr);
2347e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2348d7b241e6Sjeremylt }
2349d7b241e6Sjeremylt 
2350d7b241e6Sjeremylt /// @}
2351