xref: /libCEED/backends/ref/ceed-ref-operator.c (revision bf4cb66493dbcc06b8d25c9c91cf89fe1cab7c9b)
121617c04Sjeremylt // Copyright (c) 2017-2018, Lawrence Livermore National Security, LLC.
221617c04Sjeremylt // Produced at the Lawrence Livermore National Laboratory. LLNL-CODE-734707.
321617c04Sjeremylt // All Rights reserved. See files LICENSE and NOTICE for details.
421617c04Sjeremylt //
521617c04Sjeremylt // This file is part of CEED, a collection of benchmarks, miniapps, software
621617c04Sjeremylt // libraries and APIs for efficient high-order finite element and spectral
721617c04Sjeremylt // element discretizations for exascale applications. For more information and
821617c04Sjeremylt // source code availability see http://github.com/ceed.
921617c04Sjeremylt //
1021617c04Sjeremylt // The CEED research is supported by the Exascale Computing Project 17-SC-20-SC,
1121617c04Sjeremylt // a collaborative effort of two U.S. Department of Energy organizations (Office
1221617c04Sjeremylt // of Science and the National Nuclear Security Administration) responsible for
1321617c04Sjeremylt // the planning and preparation of a capable exascale ecosystem, including
1421617c04Sjeremylt // software, applications, hardware, advanced system engineering and early
1521617c04Sjeremylt // testbed platforms, in support of the nation's exascale computing imperative.
1621617c04Sjeremylt 
17ec3da8bcSJed Brown #include <ceed/ceed.h>
18ec3da8bcSJed Brown #include <ceed/backend.h>
193d576824SJeremy L Thompson #include <math.h>
203d576824SJeremy L Thompson #include <stdbool.h>
213d576824SJeremy L Thompson #include <stddef.h>
223d576824SJeremy L Thompson #include <stdint.h>
2321617c04Sjeremylt #include "ceed-ref.h"
2421617c04Sjeremylt 
25f10650afSjeremylt //------------------------------------------------------------------------------
26f10650afSjeremylt // Setup Input/Output Fields
27f10650afSjeremylt //------------------------------------------------------------------------------
28fe2413ffSjeremylt static int CeedOperatorSetupFields_Ref(CeedQFunction qf, CeedOperator op,
2991703d3fSjeremylt                                        bool inOrOut,
30d1d35e2fSjeremylt                                        CeedVector *full_evecs, CeedVector *e_vecs,
31d1d35e2fSjeremylt                                        CeedVector *q_vecs, CeedInt starte,
32d1d35e2fSjeremylt                                        CeedInt num_fields, CeedInt Q) {
334d537eeaSYohann   CeedInt dim, ierr, size, P;
34aedaa0e5Sjeremylt   Ceed ceed;
35e15f9bd0SJeremy L Thompson   ierr = CeedOperatorGetCeed(op, &ceed); CeedChkBackend(ierr);
36d1bcdac9Sjeremylt   CeedBasis basis;
37d1d35e2fSjeremylt   CeedElemRestriction elem_restr;
38d1d35e2fSjeremylt   CeedOperatorField *op_fields;
39d1d35e2fSjeremylt   CeedQFunctionField *qf_fields;
40fe2413ffSjeremylt   if (inOrOut) {
417e7773b5SJeremy L Thompson     ierr = CeedOperatorGetFields(op, NULL, NULL, NULL, &op_fields);
427e7773b5SJeremy L Thompson     CeedChkBackend(ierr);
437e7773b5SJeremy L Thompson     ierr = CeedQFunctionGetFields(qf, NULL, NULL, NULL, &qf_fields);
447e7773b5SJeremy L Thompson     CeedChkBackend(ierr);
45fe2413ffSjeremylt   } else {
467e7773b5SJeremy L Thompson     ierr = CeedOperatorGetFields(op, NULL, &op_fields, NULL, NULL);
477e7773b5SJeremy L Thompson     CeedChkBackend(ierr);
487e7773b5SJeremy L Thompson     ierr = CeedQFunctionGetFields(qf, NULL, &qf_fields, NULL, NULL);
497e7773b5SJeremy L Thompson     CeedChkBackend(ierr);
50fe2413ffSjeremylt   }
5121617c04Sjeremylt 
52885ac19cSjeremylt   // Loop over fields
53d1d35e2fSjeremylt   for (CeedInt i=0; i<num_fields; i++) {
54d1d35e2fSjeremylt     CeedEvalMode eval_mode;
55d1d35e2fSjeremylt     ierr = CeedQFunctionFieldGetEvalMode(qf_fields[i], &eval_mode);
56e15f9bd0SJeremy L Thompson     CeedChkBackend(ierr);
57d1d35e2fSjeremylt 
58d1d35e2fSjeremylt     if (eval_mode != CEED_EVAL_WEIGHT) {
59d1d35e2fSjeremylt       ierr = CeedOperatorFieldGetElemRestriction(op_fields[i], &elem_restr);
60d1d35e2fSjeremylt       CeedChkBackend(ierr);
61d1d35e2fSjeremylt       ierr = CeedElemRestrictionCreateVector(elem_restr, NULL,
62d1d35e2fSjeremylt                                              &full_evecs[i+starte]);
63e15f9bd0SJeremy L Thompson       CeedChkBackend(ierr);
64135a076eSjeremylt     }
65135a076eSjeremylt 
66d1d35e2fSjeremylt     switch(eval_mode) {
67885ac19cSjeremylt     case CEED_EVAL_NONE:
68d1d35e2fSjeremylt       ierr = CeedQFunctionFieldGetSize(qf_fields[i], &size); CeedChkBackend(ierr);
69d1d35e2fSjeremylt       ierr = CeedVectorCreate(ceed, Q*size, &q_vecs[i]); CeedChkBackend(ierr);
70aedaa0e5Sjeremylt       break;
71aedaa0e5Sjeremylt     case CEED_EVAL_INTERP:
72d1d35e2fSjeremylt       ierr = CeedQFunctionFieldGetSize(qf_fields[i], &size); CeedChkBackend(ierr);
73d1d35e2fSjeremylt       ierr = CeedElemRestrictionGetElementSize(elem_restr, &P);
74e15f9bd0SJeremy L Thompson       CeedChkBackend(ierr);
75d1d35e2fSjeremylt       ierr = CeedVectorCreate(ceed, P*size, &e_vecs[i]); CeedChkBackend(ierr);
76d1d35e2fSjeremylt       ierr = CeedVectorCreate(ceed, Q*size, &q_vecs[i]); CeedChkBackend(ierr);
77885ac19cSjeremylt       break;
78885ac19cSjeremylt     case CEED_EVAL_GRAD:
79d1d35e2fSjeremylt       ierr = CeedOperatorFieldGetBasis(op_fields[i], &basis); CeedChkBackend(ierr);
80d1d35e2fSjeremylt       ierr = CeedQFunctionFieldGetSize(qf_fields[i], &size); CeedChkBackend(ierr);
81e15f9bd0SJeremy L Thompson       ierr = CeedBasisGetDimension(basis, &dim); CeedChkBackend(ierr);
82d1d35e2fSjeremylt       ierr = CeedElemRestrictionGetElementSize(elem_restr, &P);
83e15f9bd0SJeremy L Thompson       CeedChkBackend(ierr);
84d1d35e2fSjeremylt       ierr = CeedVectorCreate(ceed, P*size/dim, &e_vecs[i]); CeedChkBackend(ierr);
85d1d35e2fSjeremylt       ierr = CeedVectorCreate(ceed, Q*size, &q_vecs[i]); CeedChkBackend(ierr);
86885ac19cSjeremylt       break;
87885ac19cSjeremylt     case CEED_EVAL_WEIGHT: // Only on input fields
88d1d35e2fSjeremylt       ierr = CeedOperatorFieldGetBasis(op_fields[i], &basis); CeedChkBackend(ierr);
89d1d35e2fSjeremylt       ierr = CeedVectorCreate(ceed, Q, &q_vecs[i]); CeedChkBackend(ierr);
90d1bcdac9Sjeremylt       ierr = CeedBasisApply(basis, 1, CEED_NOTRANSPOSE, CEED_EVAL_WEIGHT,
91d1d35e2fSjeremylt                             CEED_VECTOR_NONE, q_vecs[i]); CeedChkBackend(ierr);
92885ac19cSjeremylt       break;
93885ac19cSjeremylt     case CEED_EVAL_DIV:
944d537eeaSYohann       break; // Not implemented
95885ac19cSjeremylt     case CEED_EVAL_CURL:
964d537eeaSYohann       break; // Not implemented
9721617c04Sjeremylt     }
98885ac19cSjeremylt   }
99e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
10021617c04Sjeremylt }
10121617c04Sjeremylt 
102f10650afSjeremylt //------------------------------------------------------------------------------
103f10650afSjeremylt // Setup Operator
104f10650afSjeremylt //------------------------------------------------------------------------------/*
105885ac19cSjeremylt static int CeedOperatorSetup_Ref(CeedOperator op) {
10621617c04Sjeremylt   int ierr;
107d1d35e2fSjeremylt   bool setup_done;
108d1d35e2fSjeremylt   ierr = CeedOperatorIsSetupDone(op, &setup_done); CeedChkBackend(ierr);
109d1d35e2fSjeremylt   if (setup_done) return CEED_ERROR_SUCCESS;
110aedaa0e5Sjeremylt   Ceed ceed;
111e15f9bd0SJeremy L Thompson   ierr = CeedOperatorGetCeed(op, &ceed); CeedChkBackend(ierr);
1124ce2993fSjeremylt   CeedOperator_Ref *impl;
113e15f9bd0SJeremy L Thompson   ierr = CeedOperatorGetData(op, &impl); CeedChkBackend(ierr);
1144ce2993fSjeremylt   CeedQFunction qf;
115e15f9bd0SJeremy L Thompson   ierr = CeedOperatorGetQFunction(op, &qf); CeedChkBackend(ierr);
116d1d35e2fSjeremylt   CeedInt Q, num_input_fields, num_output_fields;
117e15f9bd0SJeremy L Thompson   ierr = CeedOperatorGetNumQuadraturePoints(op, &Q); CeedChkBackend(ierr);
1180b454692Sjeremylt   ierr = CeedQFunctionIsIdentity(qf, &impl->is_identity_qf); CeedChkBackend(ierr);
119d1d35e2fSjeremylt   CeedOperatorField *op_input_fields, *op_output_fields;
1207e7773b5SJeremy L Thompson   ierr = CeedOperatorGetFields(op, &num_input_fields, &op_input_fields,
1217e7773b5SJeremy L Thompson                                &num_output_fields, &op_output_fields);
122e15f9bd0SJeremy L Thompson   CeedChkBackend(ierr);
123d1d35e2fSjeremylt   CeedQFunctionField *qf_input_fields, *qf_output_fields;
1247e7773b5SJeremy L Thompson   ierr = CeedQFunctionGetFields(qf, NULL, &qf_input_fields, NULL,
1257e7773b5SJeremy L Thompson                                 &qf_output_fields);
126e15f9bd0SJeremy L Thompson   CeedChkBackend(ierr);
127885ac19cSjeremylt 
128885ac19cSjeremylt   // Allocate
129d1d35e2fSjeremylt   ierr = CeedCalloc(num_input_fields + num_output_fields, &impl->e_vecs);
130e15f9bd0SJeremy L Thompson   CeedChkBackend(ierr);
131d1d35e2fSjeremylt   ierr = CeedCalloc(num_input_fields + num_output_fields, &impl->e_data);
132e15f9bd0SJeremy L Thompson   CeedChkBackend(ierr);
133885ac19cSjeremylt 
134*bf4cb664SJeremy L Thompson   ierr = CeedCalloc(CEED_FIELD_MAX, &impl->input_state); CeedChkBackend(ierr);
135*bf4cb664SJeremy L Thompson   ierr = CeedCalloc(CEED_FIELD_MAX, &impl->e_vecs_in); CeedChkBackend(ierr);
136*bf4cb664SJeremy L Thompson   ierr = CeedCalloc(CEED_FIELD_MAX, &impl->e_vecs_out); CeedChkBackend(ierr);
137*bf4cb664SJeremy L Thompson   ierr = CeedCalloc(CEED_FIELD_MAX, &impl->q_vecs_in); CeedChkBackend(ierr);
138*bf4cb664SJeremy L Thompson   ierr = CeedCalloc(CEED_FIELD_MAX, &impl->q_vecs_out); CeedChkBackend(ierr);
139885ac19cSjeremylt 
140d1d35e2fSjeremylt   impl->num_e_vecs_in = num_input_fields;
141d1d35e2fSjeremylt   impl->num_e_vecs_out = num_output_fields;
142885ac19cSjeremylt 
143d1d35e2fSjeremylt   // Set up infield and outfield e_vecs and q_vecs
144885ac19cSjeremylt   // Infields
145d1d35e2fSjeremylt   ierr = CeedOperatorSetupFields_Ref(qf, op, 0, impl->e_vecs,
146d1d35e2fSjeremylt                                      impl->e_vecs_in, impl->q_vecs_in, 0,
147d1d35e2fSjeremylt                                      num_input_fields, Q);
148e15f9bd0SJeremy L Thompson   CeedChkBackend(ierr);
149885ac19cSjeremylt   // Outfields
150d1d35e2fSjeremylt   ierr = CeedOperatorSetupFields_Ref(qf, op, 1, impl->e_vecs,
151d1d35e2fSjeremylt                                      impl->e_vecs_out, impl->q_vecs_out,
152d1d35e2fSjeremylt                                      num_input_fields, num_output_fields, Q);
153e15f9bd0SJeremy L Thompson   CeedChkBackend(ierr);
154885ac19cSjeremylt 
15516911fdaSjeremylt   // Identity QFunctions
1560b454692Sjeremylt   if (impl->is_identity_qf) {
157d1d35e2fSjeremylt     CeedEvalMode in_mode, out_mode;
158d1d35e2fSjeremylt     CeedQFunctionField *in_fields, *out_fields;
1597e7773b5SJeremy L Thompson     ierr = CeedQFunctionGetFields(qf, NULL, &in_fields, NULL, &out_fields);
160e15f9bd0SJeremy L Thompson     CeedChkBackend(ierr);
1610b454692Sjeremylt     ierr = CeedQFunctionFieldGetEvalMode(in_fields[0], &in_mode);
162d1d35e2fSjeremylt     CeedChkBackend(ierr);
1630b454692Sjeremylt     ierr = CeedQFunctionFieldGetEvalMode(out_fields[0], &out_mode);
164d1d35e2fSjeremylt     CeedChkBackend(ierr);
165d1d35e2fSjeremylt 
1660b454692Sjeremylt     if (in_mode == CEED_EVAL_NONE && out_mode == CEED_EVAL_NONE) {
1670b454692Sjeremylt       impl->is_identity_restr_op = true;
1680b454692Sjeremylt     } else {
1690b454692Sjeremylt       ierr = CeedVectorDestroy(&impl->q_vecs_out[0]); CeedChkBackend(ierr);
1700b454692Sjeremylt       impl->q_vecs_out[0] = impl->q_vecs_in[0];
1710b454692Sjeremylt       ierr = CeedVectorAddReference(impl->q_vecs_in[0]); CeedChkBackend(ierr);
17216911fdaSjeremylt     }
17316911fdaSjeremylt   }
17416911fdaSjeremylt 
175e15f9bd0SJeremy L Thompson   ierr = CeedOperatorSetSetupDone(op); CeedChkBackend(ierr);
176885ac19cSjeremylt 
177e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
178885ac19cSjeremylt }
179885ac19cSjeremylt 
180f10650afSjeremylt //------------------------------------------------------------------------------
181f10650afSjeremylt // Setup Operator Inputs
182f10650afSjeremylt //------------------------------------------------------------------------------
183d1d35e2fSjeremylt static inline int CeedOperatorSetupInputs_Ref(CeedInt num_input_fields,
184d1d35e2fSjeremylt     CeedQFunctionField *qf_input_fields, CeedOperatorField *op_input_fields,
185d1d35e2fSjeremylt     CeedVector in_vec, const bool skip_active, CeedOperator_Ref *impl,
1861d102b48SJeremy L Thompson     CeedRequest *request) {
1871d102b48SJeremy L Thompson   CeedInt ierr;
188d1d35e2fSjeremylt   CeedEvalMode eval_mode;
189d1bcdac9Sjeremylt   CeedVector vec;
190d1d35e2fSjeremylt   CeedElemRestriction elem_restr;
1918d713cf6Sjeremylt   uint64_t state;
192885ac19cSjeremylt 
193d1d35e2fSjeremylt   for (CeedInt i=0; i<num_input_fields; i++) {
194d1bcdac9Sjeremylt     // Get input vector
195d1d35e2fSjeremylt     ierr = CeedOperatorFieldGetVector(op_input_fields[i], &vec);
196d1d35e2fSjeremylt     CeedChkBackend(ierr);
1971d102b48SJeremy L Thompson     if (vec == CEED_VECTOR_ACTIVE) {
198d1d35e2fSjeremylt       if (skip_active)
1991d102b48SJeremy L Thompson         continue;
2001d102b48SJeremy L Thompson       else
201d1d35e2fSjeremylt         vec = in_vec;
2021d102b48SJeremy L Thompson     }
2031d102b48SJeremy L Thompson 
204d1d35e2fSjeremylt     ierr = CeedQFunctionFieldGetEvalMode(qf_input_fields[i], &eval_mode);
205e15f9bd0SJeremy L Thompson     CeedChkBackend(ierr);
2061d102b48SJeremy L Thompson     // Restrict and Evec
207d1d35e2fSjeremylt     if (eval_mode == CEED_EVAL_WEIGHT) { // Skip
2081d102b48SJeremy L Thompson     } else {
209668048e2SJed Brown       // Restrict
210e15f9bd0SJeremy L Thompson       ierr = CeedVectorGetState(vec, &state); CeedChkBackend(ierr);
2118d713cf6Sjeremylt       // Skip restriction if input is unchanged
212d1d35e2fSjeremylt       if (state != impl->input_state[i] || vec == in_vec) {
213d1d35e2fSjeremylt         ierr = CeedOperatorFieldGetElemRestriction(op_input_fields[i], &elem_restr);
214e15f9bd0SJeremy L Thompson         CeedChkBackend(ierr);
215d1d35e2fSjeremylt         ierr = CeedElemRestrictionApply(elem_restr, CEED_NOTRANSPOSE, vec,
216d1d35e2fSjeremylt                                         impl->e_vecs[i], request); CeedChkBackend(ierr);
217d1d35e2fSjeremylt         impl->input_state[i] = state;
2188d713cf6Sjeremylt       }
219668048e2SJed Brown       // Get evec
220d1d35e2fSjeremylt       ierr = CeedVectorGetArrayRead(impl->e_vecs[i], CEED_MEM_HOST,
221d1d35e2fSjeremylt                                     (const CeedScalar **) &impl->e_data[i]);
222e15f9bd0SJeremy L Thompson       CeedChkBackend(ierr);
223885ac19cSjeremylt     }
224885ac19cSjeremylt   }
225e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
226885ac19cSjeremylt }
227885ac19cSjeremylt 
228f10650afSjeremylt //------------------------------------------------------------------------------
229f10650afSjeremylt // Input Basis Action
230f10650afSjeremylt //------------------------------------------------------------------------------
2311d102b48SJeremy L Thompson static inline int CeedOperatorInputBasis_Ref(CeedInt e, CeedInt Q,
232d1d35e2fSjeremylt     CeedQFunctionField *qf_input_fields, CeedOperatorField *op_input_fields,
233d1d35e2fSjeremylt     CeedInt num_input_fields, const bool skip_active, CeedOperator_Ref *impl) {
2341d102b48SJeremy L Thompson   CeedInt ierr;
235d1d35e2fSjeremylt   CeedInt dim, elem_size, size;
236d1d35e2fSjeremylt   CeedElemRestriction elem_restr;
237d1d35e2fSjeremylt   CeedEvalMode eval_mode;
2381d102b48SJeremy L Thompson   CeedBasis basis;
2391d102b48SJeremy L Thompson 
240d1d35e2fSjeremylt   for (CeedInt i=0; i<num_input_fields; i++) {
2411d102b48SJeremy L Thompson     // Skip active input
242d1d35e2fSjeremylt     if (skip_active) {
2431d102b48SJeremy L Thompson       CeedVector vec;
244d1d35e2fSjeremylt       ierr = CeedOperatorFieldGetVector(op_input_fields[i], &vec);
245d1d35e2fSjeremylt       CeedChkBackend(ierr);
2461d102b48SJeremy L Thompson       if (vec == CEED_VECTOR_ACTIVE)
2471d102b48SJeremy L Thompson         continue;
2481d102b48SJeremy L Thompson     }
249d1d35e2fSjeremylt     // Get elem_size, eval_mode, size
250d1d35e2fSjeremylt     ierr = CeedOperatorFieldGetElemRestriction(op_input_fields[i], &elem_restr);
251e15f9bd0SJeremy L Thompson     CeedChkBackend(ierr);
252d1d35e2fSjeremylt     ierr = CeedElemRestrictionGetElementSize(elem_restr, &elem_size);
253e15f9bd0SJeremy L Thompson     CeedChkBackend(ierr);
254d1d35e2fSjeremylt     ierr = CeedQFunctionFieldGetEvalMode(qf_input_fields[i], &eval_mode);
255e15f9bd0SJeremy L Thompson     CeedChkBackend(ierr);
256d1d35e2fSjeremylt     ierr = CeedQFunctionFieldGetSize(qf_input_fields[i], &size);
257d1d35e2fSjeremylt     CeedChkBackend(ierr);
258885ac19cSjeremylt     // Basis action
259d1d35e2fSjeremylt     switch(eval_mode) {
260885ac19cSjeremylt     case CEED_EVAL_NONE:
261d1d35e2fSjeremylt       ierr = CeedVectorSetArray(impl->q_vecs_in[i], CEED_MEM_HOST,
262d1d35e2fSjeremylt                                 CEED_USE_POINTER, &impl->e_data[i][e*Q*size]);
263d1d35e2fSjeremylt       CeedChkBackend(ierr);
264885ac19cSjeremylt       break;
265885ac19cSjeremylt     case CEED_EVAL_INTERP:
266d1d35e2fSjeremylt       ierr = CeedOperatorFieldGetBasis(op_input_fields[i], &basis);
267e15f9bd0SJeremy L Thompson       CeedChkBackend(ierr);
268d1d35e2fSjeremylt       ierr = CeedVectorSetArray(impl->e_vecs_in[i], CEED_MEM_HOST,
269d1d35e2fSjeremylt                                 CEED_USE_POINTER, &impl->e_data[i][e*elem_size*size]);
270e15f9bd0SJeremy L Thompson       CeedChkBackend(ierr);
271d1d35e2fSjeremylt       ierr = CeedBasisApply(basis, 1, CEED_NOTRANSPOSE, CEED_EVAL_INTERP,
272d1d35e2fSjeremylt                             impl->e_vecs_in[i], impl->q_vecs_in[i]); CeedChkBackend(ierr);
273885ac19cSjeremylt       break;
274885ac19cSjeremylt     case CEED_EVAL_GRAD:
275d1d35e2fSjeremylt       ierr = CeedOperatorFieldGetBasis(op_input_fields[i], &basis);
276e15f9bd0SJeremy L Thompson       CeedChkBackend(ierr);
277e15f9bd0SJeremy L Thompson       ierr = CeedBasisGetDimension(basis, &dim); CeedChkBackend(ierr);
278d1d35e2fSjeremylt       ierr = CeedVectorSetArray(impl->e_vecs_in[i], CEED_MEM_HOST,
279d1d35e2fSjeremylt                                 CEED_USE_POINTER, &impl->e_data[i][e*elem_size*size/dim]);
280e15f9bd0SJeremy L Thompson       CeedChkBackend(ierr);
281d1bcdac9Sjeremylt       ierr = CeedBasisApply(basis, 1, CEED_NOTRANSPOSE,
282d1d35e2fSjeremylt                             CEED_EVAL_GRAD, impl->e_vecs_in[i],
283d1d35e2fSjeremylt                             impl->q_vecs_in[i]); CeedChkBackend(ierr);
284885ac19cSjeremylt       break;
285885ac19cSjeremylt     case CEED_EVAL_WEIGHT:
286885ac19cSjeremylt       break;  // No action
287bbfacfcdSjeremylt     // LCOV_EXCL_START
288885ac19cSjeremylt     case CEED_EVAL_DIV:
2891d102b48SJeremy L Thompson     case CEED_EVAL_CURL: {
290d1d35e2fSjeremylt       ierr = CeedOperatorFieldGetBasis(op_input_fields[i], &basis);
291e15f9bd0SJeremy L Thompson       CeedChkBackend(ierr);
2921d102b48SJeremy L Thompson       Ceed ceed;
293e15f9bd0SJeremy L Thompson       ierr = CeedBasisGetCeed(basis, &ceed); CeedChkBackend(ierr);
294e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_BACKEND,
295e15f9bd0SJeremy L Thompson                        "Ceed evaluation mode not implemented");
296bbfacfcdSjeremylt       // LCOV_EXCL_STOP
297885ac19cSjeremylt     }
298885ac19cSjeremylt     }
299885ac19cSjeremylt   }
300e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
301885ac19cSjeremylt }
302885ac19cSjeremylt 
303f10650afSjeremylt //------------------------------------------------------------------------------
304f10650afSjeremylt // Output Basis Action
305f10650afSjeremylt //------------------------------------------------------------------------------
3061d102b48SJeremy L Thompson static inline int CeedOperatorOutputBasis_Ref(CeedInt e, CeedInt Q,
307d1d35e2fSjeremylt     CeedQFunctionField *qf_output_fields, CeedOperatorField *op_output_fields,
308d1d35e2fSjeremylt     CeedInt num_input_fields, CeedInt num_output_fields, CeedOperator op,
3091d102b48SJeremy L Thompson     CeedOperator_Ref *impl) {
3101d102b48SJeremy L Thompson   CeedInt ierr;
311d1d35e2fSjeremylt   CeedInt dim, elem_size, size;
312d1d35e2fSjeremylt   CeedElemRestriction elem_restr;
313d1d35e2fSjeremylt   CeedEvalMode eval_mode;
3141d102b48SJeremy L Thompson   CeedBasis basis;
3151d102b48SJeremy L Thompson 
316d1d35e2fSjeremylt   for (CeedInt i=0; i<num_output_fields; i++) {
317d1d35e2fSjeremylt     // Get elem_size, eval_mode, size
318d1d35e2fSjeremylt     ierr = CeedOperatorFieldGetElemRestriction(op_output_fields[i], &elem_restr);
319e15f9bd0SJeremy L Thompson     CeedChkBackend(ierr);
320d1d35e2fSjeremylt     ierr = CeedElemRestrictionGetElementSize(elem_restr, &elem_size);
321e15f9bd0SJeremy L Thompson     CeedChkBackend(ierr);
322d1d35e2fSjeremylt     ierr = CeedQFunctionFieldGetEvalMode(qf_output_fields[i], &eval_mode);
323e15f9bd0SJeremy L Thompson     CeedChkBackend(ierr);
324d1d35e2fSjeremylt     ierr = CeedQFunctionFieldGetSize(qf_output_fields[i], &size);
325e15f9bd0SJeremy L Thompson     CeedChkBackend(ierr);
326885ac19cSjeremylt     // Basis action
327d1d35e2fSjeremylt     switch(eval_mode) {
328885ac19cSjeremylt     case CEED_EVAL_NONE:
329885ac19cSjeremylt       break; // No action
330885ac19cSjeremylt     case CEED_EVAL_INTERP:
331d1d35e2fSjeremylt       ierr = CeedOperatorFieldGetBasis(op_output_fields[i], &basis);
332e15f9bd0SJeremy L Thompson       CeedChkBackend(ierr);
333d1d35e2fSjeremylt       ierr = CeedVectorSetArray(impl->e_vecs_out[i], CEED_MEM_HOST,
334aedaa0e5Sjeremylt                                 CEED_USE_POINTER,
335d1d35e2fSjeremylt                                 &impl->e_data[i + num_input_fields][e*elem_size*size]);
336e15f9bd0SJeremy L Thompson       CeedChkBackend(ierr);
337aedaa0e5Sjeremylt       ierr = CeedBasisApply(basis, 1, CEED_TRANSPOSE,
338d1d35e2fSjeremylt                             CEED_EVAL_INTERP, impl->q_vecs_out[i],
339d1d35e2fSjeremylt                             impl->e_vecs_out[i]); CeedChkBackend(ierr);
340885ac19cSjeremylt       break;
341885ac19cSjeremylt     case CEED_EVAL_GRAD:
342d1d35e2fSjeremylt       ierr = CeedOperatorFieldGetBasis(op_output_fields[i], &basis);
343e15f9bd0SJeremy L Thompson       CeedChkBackend(ierr);
344e15f9bd0SJeremy L Thompson       ierr = CeedBasisGetDimension(basis, &dim); CeedChkBackend(ierr);
345d1d35e2fSjeremylt       ierr = CeedVectorSetArray(impl->e_vecs_out[i], CEED_MEM_HOST,
346aedaa0e5Sjeremylt                                 CEED_USE_POINTER,
347d1d35e2fSjeremylt                                 &impl->e_data[i + num_input_fields][e*elem_size*size/dim]);
348e15f9bd0SJeremy L Thompson       CeedChkBackend(ierr);
349aedaa0e5Sjeremylt       ierr = CeedBasisApply(basis, 1, CEED_TRANSPOSE,
350d1d35e2fSjeremylt                             CEED_EVAL_GRAD, impl->q_vecs_out[i],
351d1d35e2fSjeremylt                             impl->e_vecs_out[i]); CeedChkBackend(ierr);
352885ac19cSjeremylt       break;
353c042f62fSJeremy L Thompson     // LCOV_EXCL_START
354bbfacfcdSjeremylt     case CEED_EVAL_WEIGHT: {
3554ce2993fSjeremylt       Ceed ceed;
356e15f9bd0SJeremy L Thompson       ierr = CeedOperatorGetCeed(op, &ceed); CeedChkBackend(ierr);
357e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_BACKEND,
358e15f9bd0SJeremy L Thompson                        "CEED_EVAL_WEIGHT cannot be an output "
3591d102b48SJeremy L Thompson                        "evaluation mode");
3604ce2993fSjeremylt     }
361885ac19cSjeremylt     case CEED_EVAL_DIV:
3621d102b48SJeremy L Thompson     case CEED_EVAL_CURL: {
3631d102b48SJeremy L Thompson       Ceed ceed;
364e15f9bd0SJeremy L Thompson       ierr = CeedOperatorGetCeed(op, &ceed); CeedChkBackend(ierr);
365e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_BACKEND,
366e15f9bd0SJeremy L Thompson                        "Ceed evaluation mode not implemented");
3671d102b48SJeremy L Thompson       // LCOV_EXCL_STOP
368885ac19cSjeremylt     }
369885ac19cSjeremylt     }
370885ac19cSjeremylt   }
371e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
3721d102b48SJeremy L Thompson }
3731d102b48SJeremy L Thompson 
374f10650afSjeremylt //------------------------------------------------------------------------------
375f10650afSjeremylt // Restore Input Vectors
376f10650afSjeremylt //------------------------------------------------------------------------------
377d1d35e2fSjeremylt static inline int CeedOperatorRestoreInputs_Ref(CeedInt num_input_fields,
378d1d35e2fSjeremylt     CeedQFunctionField *qf_input_fields, CeedOperatorField *op_input_fields,
379d1d35e2fSjeremylt     const bool skip_active, CeedOperator_Ref *impl) {
3801d102b48SJeremy L Thompson   CeedInt ierr;
381d1d35e2fSjeremylt   CeedEvalMode eval_mode;
3821d102b48SJeremy L Thompson 
383d1d35e2fSjeremylt   for (CeedInt i=0; i<num_input_fields; i++) {
3841d102b48SJeremy L Thompson     // Skip active inputs
385d1d35e2fSjeremylt     if (skip_active) {
3861d102b48SJeremy L Thompson       CeedVector vec;
387d1d35e2fSjeremylt       ierr = CeedOperatorFieldGetVector(op_input_fields[i], &vec);
388d1d35e2fSjeremylt       CeedChkBackend(ierr);
3891d102b48SJeremy L Thompson       if (vec == CEED_VECTOR_ACTIVE)
3901d102b48SJeremy L Thompson         continue;
3911d102b48SJeremy L Thompson     }
3921d102b48SJeremy L Thompson     // Restore input
393d1d35e2fSjeremylt     ierr = CeedQFunctionFieldGetEvalMode(qf_input_fields[i], &eval_mode);
394e15f9bd0SJeremy L Thompson     CeedChkBackend(ierr);
395d1d35e2fSjeremylt     if (eval_mode == CEED_EVAL_WEIGHT) { // Skip
3961d102b48SJeremy L Thompson     } else {
397d1d35e2fSjeremylt       ierr = CeedVectorRestoreArrayRead(impl->e_vecs[i],
398d1d35e2fSjeremylt                                         (const CeedScalar **) &impl->e_data[i]);
399e15f9bd0SJeremy L Thompson       CeedChkBackend(ierr);
4001d102b48SJeremy L Thompson     }
4011d102b48SJeremy L Thompson   }
402e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
4031d102b48SJeremy L Thompson }
4041d102b48SJeremy L Thompson 
405f10650afSjeremylt //------------------------------------------------------------------------------
406f10650afSjeremylt // Operator Apply
407f10650afSjeremylt //------------------------------------------------------------------------------
408d1d35e2fSjeremylt static int CeedOperatorApplyAdd_Ref(CeedOperator op, CeedVector in_vec,
409d1d35e2fSjeremylt                                     CeedVector out_vec, CeedRequest *request) {
4101d102b48SJeremy L Thompson   int ierr;
4111d102b48SJeremy L Thompson   CeedOperator_Ref *impl;
412e15f9bd0SJeremy L Thompson   ierr = CeedOperatorGetData(op, &impl); CeedChkBackend(ierr);
4131d102b48SJeremy L Thompson   CeedQFunction qf;
414e15f9bd0SJeremy L Thompson   ierr = CeedOperatorGetQFunction(op, &qf); CeedChkBackend(ierr);
415d1d35e2fSjeremylt   CeedInt Q, num_elem, num_input_fields, num_output_fields, size;
416e15f9bd0SJeremy L Thompson   ierr = CeedOperatorGetNumQuadraturePoints(op, &Q); CeedChkBackend(ierr);
417d1d35e2fSjeremylt   ierr = CeedOperatorGetNumElements(op, &num_elem); CeedChkBackend(ierr);
418d1d35e2fSjeremylt   CeedOperatorField *op_input_fields, *op_output_fields;
4197e7773b5SJeremy L Thompson   ierr = CeedOperatorGetFields(op, &num_input_fields, &op_input_fields,
4207e7773b5SJeremy L Thompson                                &num_output_fields, &op_output_fields);
421e15f9bd0SJeremy L Thompson   CeedChkBackend(ierr);
422d1d35e2fSjeremylt   CeedQFunctionField *qf_input_fields, *qf_output_fields;
4237e7773b5SJeremy L Thompson   ierr = CeedQFunctionGetFields(qf, NULL, &qf_input_fields, NULL,
4247e7773b5SJeremy L Thompson                                 &qf_output_fields);
425e15f9bd0SJeremy L Thompson   CeedChkBackend(ierr);
426d1d35e2fSjeremylt   CeedEvalMode eval_mode;
4271d102b48SJeremy L Thompson   CeedVector vec;
428d1d35e2fSjeremylt   CeedElemRestriction elem_restr;
4291d102b48SJeremy L Thompson 
4301d102b48SJeremy L Thompson   // Setup
431e15f9bd0SJeremy L Thompson   ierr = CeedOperatorSetup_Ref(op); CeedChkBackend(ierr);
4321d102b48SJeremy L Thompson 
4330b454692Sjeremylt   // Restriction only operator
4340b454692Sjeremylt   if (impl->is_identity_restr_op) {
4350b454692Sjeremylt     ierr = CeedOperatorFieldGetElemRestriction(op_input_fields[0], &elem_restr);
4360b454692Sjeremylt     CeedChkBackend(ierr);
4370b454692Sjeremylt     ierr = CeedElemRestrictionApply(elem_restr, CEED_NOTRANSPOSE, in_vec,
4380b454692Sjeremylt                                     impl->e_vecs[0], request); CeedChkBackend(ierr);
4390b454692Sjeremylt     ierr = CeedOperatorFieldGetElemRestriction(op_output_fields[0], &elem_restr);
4400b454692Sjeremylt     CeedChkBackend(ierr);
4410b454692Sjeremylt     ierr = CeedElemRestrictionApply(elem_restr, CEED_TRANSPOSE, impl->e_vecs[0],
4420b454692Sjeremylt                                     out_vec, request); CeedChkBackend(ierr);
4430b454692Sjeremylt     return CEED_ERROR_SUCCESS;
4440b454692Sjeremylt   }
4450b454692Sjeremylt 
4461d102b48SJeremy L Thompson   // Input Evecs and Restriction
447d1d35e2fSjeremylt   ierr = CeedOperatorSetupInputs_Ref(num_input_fields, qf_input_fields,
448d1d35e2fSjeremylt                                      op_input_fields, in_vec, false, impl,
449e15f9bd0SJeremy L Thompson                                      request); CeedChkBackend(ierr);
4501d102b48SJeremy L Thompson 
4511d102b48SJeremy L Thompson   // Output Evecs
452d1d35e2fSjeremylt   for (CeedInt i=0; i<num_output_fields; i++) {
453d1d35e2fSjeremylt     ierr = CeedVectorGetArray(impl->e_vecs[i+impl->num_e_vecs_in], CEED_MEM_HOST,
454d1d35e2fSjeremylt                               &impl->e_data[i + num_input_fields]); CeedChkBackend(ierr);
4551d102b48SJeremy L Thompson   }
4561d102b48SJeremy L Thompson 
4571d102b48SJeremy L Thompson   // Loop through elements
458d1d35e2fSjeremylt   for (CeedInt e=0; e<num_elem; e++) {
4591d102b48SJeremy L Thompson     // Output pointers
460d1d35e2fSjeremylt     for (CeedInt i=0; i<num_output_fields; i++) {
461d1d35e2fSjeremylt       ierr = CeedQFunctionFieldGetEvalMode(qf_output_fields[i], &eval_mode);
462e15f9bd0SJeremy L Thompson       CeedChkBackend(ierr);
463d1d35e2fSjeremylt       if (eval_mode == CEED_EVAL_NONE) {
464d1d35e2fSjeremylt         ierr = CeedQFunctionFieldGetSize(qf_output_fields[i], &size);
465e15f9bd0SJeremy L Thompson         CeedChkBackend(ierr);
466d1d35e2fSjeremylt         ierr = CeedVectorSetArray(impl->q_vecs_out[i], CEED_MEM_HOST,
4671d102b48SJeremy L Thompson                                   CEED_USE_POINTER,
468d1d35e2fSjeremylt                                   &impl->e_data[i + num_input_fields][e*Q*size]);
469e15f9bd0SJeremy L Thompson         CeedChkBackend(ierr);
4701d102b48SJeremy L Thompson       }
4711d102b48SJeremy L Thompson     }
4721d102b48SJeremy L Thompson 
47316911fdaSjeremylt     // Input basis apply
474d1d35e2fSjeremylt     ierr = CeedOperatorInputBasis_Ref(e, Q, qf_input_fields, op_input_fields,
475d1d35e2fSjeremylt                                       num_input_fields, false, impl);
476e15f9bd0SJeremy L Thompson     CeedChkBackend(ierr);
47716911fdaSjeremylt 
4781d102b48SJeremy L Thompson     // Q function
4790b454692Sjeremylt     if (!impl->is_identity_qf) {
480d1d35e2fSjeremylt       ierr = CeedQFunctionApply(qf, Q, impl->q_vecs_in, impl->q_vecs_out);
481e15f9bd0SJeremy L Thompson       CeedChkBackend(ierr);
48216911fdaSjeremylt     }
4831d102b48SJeremy L Thompson 
4841d102b48SJeremy L Thompson     // Output basis apply
485d1d35e2fSjeremylt     ierr = CeedOperatorOutputBasis_Ref(e, Q, qf_output_fields, op_output_fields,
486d1d35e2fSjeremylt                                        num_input_fields, num_output_fields, op, impl);
487e15f9bd0SJeremy L Thompson     CeedChkBackend(ierr);
4881d102b48SJeremy L Thompson   }
489885ac19cSjeremylt 
490885ac19cSjeremylt   // Output restriction
491d1d35e2fSjeremylt   for (CeedInt i=0; i<num_output_fields; i++) {
492d1d35e2fSjeremylt     // Restore Evec
493d1d35e2fSjeremylt     ierr = CeedVectorRestoreArray(impl->e_vecs[i+impl->num_e_vecs_in],
494d1d35e2fSjeremylt                                   &impl->e_data[i + num_input_fields]);
495e15f9bd0SJeremy L Thompson     CeedChkBackend(ierr);
496d1bcdac9Sjeremylt     // Get output vector
497d1d35e2fSjeremylt     ierr = CeedOperatorFieldGetVector(op_output_fields[i], &vec);
498e15f9bd0SJeremy L Thompson     CeedChkBackend(ierr);
499668048e2SJed Brown     // Active
500d1bcdac9Sjeremylt     if (vec == CEED_VECTOR_ACTIVE)
501d1d35e2fSjeremylt       vec = out_vec;
5027ca8db16Sjeremylt     // Restrict
503d1d35e2fSjeremylt     ierr = CeedOperatorFieldGetElemRestriction(op_output_fields[i], &elem_restr);
504e15f9bd0SJeremy L Thompson     CeedChkBackend(ierr);
505d1d35e2fSjeremylt     ierr = CeedElemRestrictionApply(elem_restr, CEED_TRANSPOSE,
506d1d35e2fSjeremylt                                     impl->e_vecs[i+impl->num_e_vecs_in], vec, request);
507e15f9bd0SJeremy L Thompson     CeedChkBackend(ierr);
508885ac19cSjeremylt   }
509885ac19cSjeremylt 
5107ca8db16Sjeremylt   // Restore input arrays
511d1d35e2fSjeremylt   ierr = CeedOperatorRestoreInputs_Ref(num_input_fields, qf_input_fields,
512d1d35e2fSjeremylt                                        op_input_fields, false, impl);
513e15f9bd0SJeremy L Thompson   CeedChkBackend(ierr);
5147ca8db16Sjeremylt 
515e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
51621617c04Sjeremylt }
51721617c04Sjeremylt 
518f10650afSjeremylt //------------------------------------------------------------------------------
51970a7ffb3SJeremy L Thompson // Core code for assembling linear QFunction
520f10650afSjeremylt //------------------------------------------------------------------------------
52170a7ffb3SJeremy L Thompson static inline int CeedOperatorLinearAssembleQFunctionCore_Ref(CeedOperator op,
52270a7ffb3SJeremy L Thompson     bool build_objects, CeedVector *assembled, CeedElemRestriction *rstr,
52370a7ffb3SJeremy L Thompson     CeedRequest *request) {
5241d102b48SJeremy L Thompson   int ierr;
5251d102b48SJeremy L Thompson   CeedOperator_Ref *impl;
526e15f9bd0SJeremy L Thompson   ierr = CeedOperatorGetData(op, &impl); CeedChkBackend(ierr);
5271d102b48SJeremy L Thompson   CeedQFunction qf;
528e15f9bd0SJeremy L Thompson   ierr = CeedOperatorGetQFunction(op, &qf); CeedChkBackend(ierr);
529d1d35e2fSjeremylt   CeedInt Q, num_elem, num_input_fields, num_output_fields, size;
530e15f9bd0SJeremy L Thompson   ierr = CeedOperatorGetNumQuadraturePoints(op, &Q); CeedChkBackend(ierr);
531d1d35e2fSjeremylt   ierr = CeedOperatorGetNumElements(op, &num_elem); CeedChkBackend(ierr);
532d1d35e2fSjeremylt   CeedOperatorField *op_input_fields, *op_output_fields;
5337e7773b5SJeremy L Thompson   ierr = CeedOperatorGetFields(op, &num_input_fields, &op_input_fields,
5347e7773b5SJeremy L Thompson                                &num_output_fields, &op_output_fields);
535e15f9bd0SJeremy L Thompson   CeedChkBackend(ierr);
536d1d35e2fSjeremylt   CeedQFunctionField *qf_input_fields, *qf_output_fields;
5377e7773b5SJeremy L Thompson   ierr = CeedQFunctionGetFields(qf, NULL, &qf_input_fields, NULL,
5387e7773b5SJeremy L Thompson                                 &qf_output_fields);
539e15f9bd0SJeremy L Thompson   CeedChkBackend(ierr);
5401d102b48SJeremy L Thompson   CeedVector vec;
541bb219a0fSJeremy L Thompson   CeedInt num_active_in = impl->qf_num_active_in,
542bb219a0fSJeremy L Thompson           num_active_out = impl->qf_num_active_out;
543bb219a0fSJeremy L Thompson   CeedVector *active_in = impl->qf_active_in;
5441d102b48SJeremy L Thompson   CeedScalar *a, *tmp;
545d1d35e2fSjeremylt   Ceed ceed, ceed_parent;
546e15f9bd0SJeremy L Thompson   ierr = CeedOperatorGetCeed(op, &ceed); CeedChkBackend(ierr);
547d1d35e2fSjeremylt   ierr = CeedGetOperatorFallbackParentCeed(ceed, &ceed_parent);
548e15f9bd0SJeremy L Thompson   CeedChkBackend(ierr);
549d1d35e2fSjeremylt   ceed_parent = ceed_parent ? ceed_parent : ceed;
5501d102b48SJeremy L Thompson 
5511d102b48SJeremy L Thompson   // Setup
552e15f9bd0SJeremy L Thompson   ierr = CeedOperatorSetup_Ref(op); CeedChkBackend(ierr);
5531d102b48SJeremy L Thompson 
55416911fdaSjeremylt   // Check for identity
5550b454692Sjeremylt   if (impl->is_identity_qf)
55616911fdaSjeremylt     // LCOV_EXCL_START
557e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_BACKEND,
558e15f9bd0SJeremy L Thompson                      "Assembling identity QFunctions not supported");
55916911fdaSjeremylt   // LCOV_EXCL_STOP
56016911fdaSjeremylt 
5611d102b48SJeremy L Thompson   // Input Evecs and Restriction
562d1d35e2fSjeremylt   ierr = CeedOperatorSetupInputs_Ref(num_input_fields, qf_input_fields,
563d1d35e2fSjeremylt                                      op_input_fields, NULL, true, impl, request);
564e15f9bd0SJeremy L Thompson   CeedChkBackend(ierr);
5651d102b48SJeremy L Thompson 
5661d102b48SJeremy L Thompson   // Count number of active input fields
567bb219a0fSJeremy L Thompson   if (!num_active_in) {
568d1d35e2fSjeremylt     for (CeedInt i=0; i<num_input_fields; i++) {
5691d102b48SJeremy L Thompson       // Get input vector
570d1d35e2fSjeremylt       ierr = CeedOperatorFieldGetVector(op_input_fields[i], &vec);
571d1d35e2fSjeremylt       CeedChkBackend(ierr);
5721d102b48SJeremy L Thompson       // Check if active input
5731d102b48SJeremy L Thompson       if (vec == CEED_VECTOR_ACTIVE) {
574d1d35e2fSjeremylt         ierr = CeedQFunctionFieldGetSize(qf_input_fields[i], &size);
575e15f9bd0SJeremy L Thompson         CeedChkBackend(ierr);
576d1d35e2fSjeremylt         ierr = CeedVectorSetValue(impl->q_vecs_in[i], 0.0); CeedChkBackend(ierr);
577d1d35e2fSjeremylt         ierr = CeedVectorGetArray(impl->q_vecs_in[i], CEED_MEM_HOST, &tmp);
578d1d35e2fSjeremylt         CeedChkBackend(ierr);
579d1d35e2fSjeremylt         ierr = CeedRealloc(num_active_in + size, &active_in); CeedChkBackend(ierr);
5801d102b48SJeremy L Thompson         for (CeedInt field=0; field<size; field++) {
581d1d35e2fSjeremylt           ierr = CeedVectorCreate(ceed, Q, &active_in[num_active_in+field]);
582e15f9bd0SJeremy L Thompson           CeedChkBackend(ierr);
583d1d35e2fSjeremylt           ierr = CeedVectorSetArray(active_in[num_active_in+field], CEED_MEM_HOST,
58442ea3801Sjeremylt                                     CEED_USE_POINTER, &tmp[field*Q]);
585e15f9bd0SJeremy L Thompson           CeedChkBackend(ierr);
5861d102b48SJeremy L Thompson         }
587d1d35e2fSjeremylt         num_active_in += size;
588d1d35e2fSjeremylt         ierr = CeedVectorRestoreArray(impl->q_vecs_in[i], &tmp); CeedChkBackend(ierr);
5891d102b48SJeremy L Thompson       }
5901d102b48SJeremy L Thompson     }
591bb219a0fSJeremy L Thompson     impl->qf_num_active_in = num_active_in;
592bb219a0fSJeremy L Thompson     impl->qf_active_in = active_in;
593bb219a0fSJeremy L Thompson   }
5941d102b48SJeremy L Thompson 
5951d102b48SJeremy L Thompson   // Count number of active output fields
596bb219a0fSJeremy L Thompson   if (!num_active_out) {
597d1d35e2fSjeremylt     for (CeedInt i=0; i<num_output_fields; i++) {
5981d102b48SJeremy L Thompson       // Get output vector
599d1d35e2fSjeremylt       ierr = CeedOperatorFieldGetVector(op_output_fields[i], &vec);
600e15f9bd0SJeremy L Thompson       CeedChkBackend(ierr);
6011d102b48SJeremy L Thompson       // Check if active output
6021d102b48SJeremy L Thompson       if (vec == CEED_VECTOR_ACTIVE) {
603d1d35e2fSjeremylt         ierr = CeedQFunctionFieldGetSize(qf_output_fields[i], &size);
604e15f9bd0SJeremy L Thompson         CeedChkBackend(ierr);
605d1d35e2fSjeremylt         num_active_out += size;
6061d102b48SJeremy L Thompson       }
6071d102b48SJeremy L Thompson     }
608bb219a0fSJeremy L Thompson     impl->qf_num_active_out = num_active_out;
609bb219a0fSJeremy L Thompson   }
6101d102b48SJeremy L Thompson 
6111d102b48SJeremy L Thompson   // Check sizes
612d1d35e2fSjeremylt   if (!num_active_in || !num_active_out)
613138d4072Sjeremylt     // LCOV_EXCL_START
614e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_BACKEND,
615e15f9bd0SJeremy L Thompson                      "Cannot assemble QFunction without active inputs "
616138d4072Sjeremylt                      "and outputs");
617138d4072Sjeremylt   // LCOV_EXCL_STOP
6181d102b48SJeremy L Thompson 
61970a7ffb3SJeremy L Thompson   // Build objects if needed
62070a7ffb3SJeremy L Thompson   if (build_objects) {
6211d102b48SJeremy L Thompson     // Create output restriction
622d1d35e2fSjeremylt     CeedInt strides[3] = {1, Q, num_active_in*num_active_out*Q}; /* *NOPAD* */
623d1d35e2fSjeremylt     ierr = CeedElemRestrictionCreateStrided(ceed_parent, num_elem, Q,
624d1d35e2fSjeremylt                                             num_active_in*num_active_out,
625d1d35e2fSjeremylt                                             num_active_in*num_active_out*num_elem*Q,
626e15f9bd0SJeremy L Thompson                                             strides, rstr); CeedChkBackend(ierr);
6271d102b48SJeremy L Thompson     // Create assembled vector
628d1d35e2fSjeremylt     ierr = CeedVectorCreate(ceed_parent, num_elem*Q*num_active_in*num_active_out,
629e15f9bd0SJeremy L Thompson                             assembled); CeedChkBackend(ierr);
63070a7ffb3SJeremy L Thompson   }
63170a7ffb3SJeremy L Thompson   // Clear output vector
632e15f9bd0SJeremy L Thompson   ierr = CeedVectorSetValue(*assembled, 0.0); CeedChkBackend(ierr);
633e15f9bd0SJeremy L Thompson   ierr = CeedVectorGetArray(*assembled, CEED_MEM_HOST, &a); CeedChkBackend(ierr);
6341d102b48SJeremy L Thompson 
6351d102b48SJeremy L Thompson   // Loop through elements
636d1d35e2fSjeremylt   for (CeedInt e=0; e<num_elem; e++) {
6371d102b48SJeremy L Thompson     // Input basis apply
638d1d35e2fSjeremylt     ierr = CeedOperatorInputBasis_Ref(e, Q, qf_input_fields, op_input_fields,
639d1d35e2fSjeremylt                                       num_input_fields, true, impl);
640e15f9bd0SJeremy L Thompson     CeedChkBackend(ierr);
6411d102b48SJeremy L Thompson 
6421d102b48SJeremy L Thompson     // Assemble QFunction
643d1d35e2fSjeremylt     for (CeedInt in=0; in<num_active_in; in++) {
6441d102b48SJeremy L Thompson       // Set Inputs
645d1d35e2fSjeremylt       ierr = CeedVectorSetValue(active_in[in], 1.0); CeedChkBackend(ierr);
646d1d35e2fSjeremylt       if (num_active_in > 1) {
647d1d35e2fSjeremylt         ierr = CeedVectorSetValue(active_in[(in+num_active_in-1)%num_active_in],
648e15f9bd0SJeremy L Thompson                                   0.0); CeedChkBackend(ierr);
64942ea3801Sjeremylt       }
6501d102b48SJeremy L Thompson       // Set Outputs
651d1d35e2fSjeremylt       for (CeedInt out=0; out<num_output_fields; out++) {
6521d102b48SJeremy L Thompson         // Get output vector
653d1d35e2fSjeremylt         ierr = CeedOperatorFieldGetVector(op_output_fields[out], &vec);
654e15f9bd0SJeremy L Thompson         CeedChkBackend(ierr);
6551d102b48SJeremy L Thompson         // Check if active output
6561d102b48SJeremy L Thompson         if (vec == CEED_VECTOR_ACTIVE) {
657d1d35e2fSjeremylt           CeedVectorSetArray(impl->q_vecs_out[out], CEED_MEM_HOST,
658e15f9bd0SJeremy L Thompson                              CEED_USE_POINTER, a); CeedChkBackend(ierr);
659d1d35e2fSjeremylt           ierr = CeedQFunctionFieldGetSize(qf_output_fields[out], &size);
660e15f9bd0SJeremy L Thompson           CeedChkBackend(ierr);
6611d102b48SJeremy L Thompson           a += size*Q; // Advance the pointer by the size of the output
6621d102b48SJeremy L Thompson         }
6631d102b48SJeremy L Thompson       }
6641d102b48SJeremy L Thompson       // Apply QFunction
665d1d35e2fSjeremylt       ierr = CeedQFunctionApply(qf, Q, impl->q_vecs_in, impl->q_vecs_out);
666e15f9bd0SJeremy L Thompson       CeedChkBackend(ierr);
6671d102b48SJeremy L Thompson     }
6681d102b48SJeremy L Thompson   }
6691d102b48SJeremy L Thompson 
6701d102b48SJeremy L Thompson   // Un-set output Qvecs to prevent accidental overwrite of Assembled
671d1d35e2fSjeremylt   for (CeedInt out=0; out<num_output_fields; out++) {
6721d102b48SJeremy L Thompson     // Get output vector
673d1d35e2fSjeremylt     ierr = CeedOperatorFieldGetVector(op_output_fields[out], &vec);
674e15f9bd0SJeremy L Thompson     CeedChkBackend(ierr);
6751d102b48SJeremy L Thompson     // Check if active output
6761d102b48SJeremy L Thompson     if (vec == CEED_VECTOR_ACTIVE) {
677d1d35e2fSjeremylt       CeedVectorTakeArray(impl->q_vecs_out[out], CEED_MEM_HOST, NULL);
678e15f9bd0SJeremy L Thompson       CeedChkBackend(ierr);
6791d102b48SJeremy L Thompson     }
6801d102b48SJeremy L Thompson   }
6811d102b48SJeremy L Thompson 
6821d102b48SJeremy L Thompson   // Restore input arrays
683d1d35e2fSjeremylt   ierr = CeedOperatorRestoreInputs_Ref(num_input_fields, qf_input_fields,
684d1d35e2fSjeremylt                                        op_input_fields, true, impl);
685e15f9bd0SJeremy L Thompson   CeedChkBackend(ierr);
6861d102b48SJeremy L Thompson 
6871d102b48SJeremy L Thompson   // Restore output
688e15f9bd0SJeremy L Thompson   ierr = CeedVectorRestoreArray(*assembled, &a); CeedChkBackend(ierr);
6891d102b48SJeremy L Thompson 
690e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6911d102b48SJeremy L Thompson }
6921d102b48SJeremy L Thompson 
693f10650afSjeremylt //------------------------------------------------------------------------------
69470a7ffb3SJeremy L Thompson // Assemble Linear QFunction
69570a7ffb3SJeremy L Thompson //------------------------------------------------------------------------------
69670a7ffb3SJeremy L Thompson static int CeedOperatorLinearAssembleQFunction_Ref(CeedOperator op,
69770a7ffb3SJeremy L Thompson     CeedVector *assembled, CeedElemRestriction *rstr, CeedRequest *request) {
69870a7ffb3SJeremy L Thompson   return CeedOperatorLinearAssembleQFunctionCore_Ref(op, true, assembled, rstr,
69970a7ffb3SJeremy L Thompson          request);
70070a7ffb3SJeremy L Thompson }
70170a7ffb3SJeremy L Thompson 
70270a7ffb3SJeremy L Thompson //------------------------------------------------------------------------------
70370a7ffb3SJeremy L Thompson // Update Assembled Linear QFunction
70470a7ffb3SJeremy L Thompson //------------------------------------------------------------------------------
70570a7ffb3SJeremy L Thompson static int CeedOperatorLinearAssembleQFunctionUpdate_Ref(CeedOperator op,
70670a7ffb3SJeremy L Thompson     CeedVector assembled, CeedElemRestriction rstr, CeedRequest *request) {
70770a7ffb3SJeremy L Thompson   return CeedOperatorLinearAssembleQFunctionCore_Ref(op, false, &assembled,
70870a7ffb3SJeremy L Thompson          &rstr, request);
70970a7ffb3SJeremy L Thompson }
71070a7ffb3SJeremy L Thompson 
71170a7ffb3SJeremy L Thompson //------------------------------------------------------------------------------
712f10650afSjeremylt // Operator Destroy
713f10650afSjeremylt //------------------------------------------------------------------------------
714f10650afSjeremylt static int CeedOperatorDestroy_Ref(CeedOperator op) {
715f10650afSjeremylt   int ierr;
716f10650afSjeremylt   CeedOperator_Ref *impl;
717e15f9bd0SJeremy L Thompson   ierr = CeedOperatorGetData(op, &impl); CeedChkBackend(ierr);
718f10650afSjeremylt 
719d1d35e2fSjeremylt   for (CeedInt i=0; i<impl->num_e_vecs_in+impl->num_e_vecs_out; i++) {
720d1d35e2fSjeremylt     ierr = CeedVectorDestroy(&impl->e_vecs[i]); CeedChkBackend(ierr);
721f10650afSjeremylt   }
722d1d35e2fSjeremylt   ierr = CeedFree(&impl->e_vecs); CeedChkBackend(ierr);
723d1d35e2fSjeremylt   ierr = CeedFree(&impl->e_data); CeedChkBackend(ierr);
724d1d35e2fSjeremylt   ierr = CeedFree(&impl->input_state); CeedChkBackend(ierr);
725f10650afSjeremylt 
726d1d35e2fSjeremylt   for (CeedInt i=0; i<impl->num_e_vecs_in; i++) {
727d1d35e2fSjeremylt     ierr = CeedVectorDestroy(&impl->e_vecs_in[i]); CeedChkBackend(ierr);
728d1d35e2fSjeremylt     ierr = CeedVectorDestroy(&impl->q_vecs_in[i]); CeedChkBackend(ierr);
729f10650afSjeremylt   }
730d1d35e2fSjeremylt   ierr = CeedFree(&impl->e_vecs_in); CeedChkBackend(ierr);
731d1d35e2fSjeremylt   ierr = CeedFree(&impl->q_vecs_in); CeedChkBackend(ierr);
732f10650afSjeremylt 
733d1d35e2fSjeremylt   for (CeedInt i=0; i<impl->num_e_vecs_out; i++) {
734d1d35e2fSjeremylt     ierr = CeedVectorDestroy(&impl->e_vecs_out[i]); CeedChkBackend(ierr);
735d1d35e2fSjeremylt     ierr = CeedVectorDestroy(&impl->q_vecs_out[i]); CeedChkBackend(ierr);
736f10650afSjeremylt   }
737d1d35e2fSjeremylt   ierr = CeedFree(&impl->e_vecs_out); CeedChkBackend(ierr);
738d1d35e2fSjeremylt   ierr = CeedFree(&impl->q_vecs_out); CeedChkBackend(ierr);
739f10650afSjeremylt 
740bb219a0fSJeremy L Thompson   // QFunction assembly
741bb219a0fSJeremy L Thompson   for (CeedInt i=0; i<impl->qf_num_active_in; i++) {
742bb219a0fSJeremy L Thompson     ierr = CeedVectorDestroy(&impl->qf_active_in[i]); CeedChkBackend(ierr);
743bb219a0fSJeremy L Thompson   }
744bb219a0fSJeremy L Thompson   ierr = CeedFree(&impl->qf_active_in); CeedChkBackend(ierr);
745bb219a0fSJeremy L Thompson 
746e15f9bd0SJeremy L Thompson   ierr = CeedFree(&impl); CeedChkBackend(ierr);
747e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
748f10650afSjeremylt }
749f10650afSjeremylt 
750f10650afSjeremylt //------------------------------------------------------------------------------
751713f43c3Sjeremylt // Operator Create
752f10650afSjeremylt //------------------------------------------------------------------------------
75321617c04Sjeremylt int CeedOperatorCreate_Ref(CeedOperator op) {
75421617c04Sjeremylt   int ierr;
755fe2413ffSjeremylt   Ceed ceed;
756e15f9bd0SJeremy L Thompson   ierr = CeedOperatorGetCeed(op, &ceed); CeedChkBackend(ierr);
7574ce2993fSjeremylt   CeedOperator_Ref *impl;
75821617c04Sjeremylt 
759e15f9bd0SJeremy L Thompson   ierr = CeedCalloc(1, &impl); CeedChkBackend(ierr);
760e15f9bd0SJeremy L Thompson   ierr = CeedOperatorSetData(op, impl); CeedChkBackend(ierr);
761fe2413ffSjeremylt 
76280ac2e43SJeremy L Thompson   ierr = CeedSetBackendFunction(ceed, "Operator", op, "LinearAssembleQFunction",
76380ac2e43SJeremy L Thompson                                 CeedOperatorLinearAssembleQFunction_Ref);
764e15f9bd0SJeremy L Thompson   CeedChkBackend(ierr);
76570a7ffb3SJeremy L Thompson   ierr = CeedSetBackendFunction(ceed, "Operator", op,
76670a7ffb3SJeremy L Thompson                                 "LinearAssembleQFunctionUpdate",
76770a7ffb3SJeremy L Thompson                                 CeedOperatorLinearAssembleQFunctionUpdate_Ref);
76870a7ffb3SJeremy L Thompson   CeedChkBackend(ierr);
769cae8b89aSjeremylt   ierr = CeedSetBackendFunction(ceed, "Operator", op, "ApplyAdd",
770e15f9bd0SJeremy L Thompson                                 CeedOperatorApplyAdd_Ref); CeedChkBackend(ierr);
771fe2413ffSjeremylt   ierr = CeedSetBackendFunction(ceed, "Operator", op, "Destroy",
772e15f9bd0SJeremy L Thompson                                 CeedOperatorDestroy_Ref); CeedChkBackend(ierr);
773e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
77421617c04Sjeremylt }
775