xref: /libCEED/backends/ref/ceed-ref-operator.c (revision ebbcc8a346ef79f72cc33926c55f927f02fd96aa)
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,
294fc1f125SJeremy L Thompson                                        bool is_input, CeedVector *e_vecs_full,
304fc1f125SJeremy L Thompson                                        CeedVector *e_vecs, CeedVector *q_vecs,
314fc1f125SJeremy L Thompson                                        CeedInt start_e, CeedInt num_fields,
324fc1f125SJeremy L Thompson                                        CeedInt Q) {
33*ebbcc8a3SJeremy L Thompson   CeedInt ierr, num_comp, 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;
404fc1f125SJeremy L Thompson   if (is_input) {
417e7773b5SJeremy L Thompson     ierr = CeedOperatorGetFields(op, NULL, &op_fields, NULL, NULL);
427e7773b5SJeremy L Thompson     CeedChkBackend(ierr);
437e7773b5SJeremy L Thompson     ierr = CeedQFunctionGetFields(qf, NULL, &qf_fields, NULL, NULL);
447e7773b5SJeremy L Thompson     CeedChkBackend(ierr);
454fc1f125SJeremy L Thompson   } else {
464fc1f125SJeremy L Thompson     ierr = CeedOperatorGetFields(op, NULL, NULL, NULL, &op_fields);
474fc1f125SJeremy L Thompson     CeedChkBackend(ierr);
484fc1f125SJeremy L Thompson     ierr = CeedQFunctionGetFields(qf, NULL, NULL, NULL, &qf_fields);
494fc1f125SJeremy 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,
624fc1f125SJeremy L Thompson                                              &e_vecs_full[i+start_e]);
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:
72*ebbcc8a3SJeremy L Thompson       ierr = CeedOperatorFieldGetBasis(op_fields[i], &basis); CeedChkBackend(ierr);
73d1d35e2fSjeremylt       ierr = CeedQFunctionFieldGetSize(qf_fields[i], &size); CeedChkBackend(ierr);
74*ebbcc8a3SJeremy L Thompson       ierr = CeedBasisGetNumNodes(basis, &P); CeedChkBackend(ierr);
75*ebbcc8a3SJeremy L Thompson       ierr = CeedBasisGetNumComponents(basis, &num_comp); CeedChkBackend(ierr);
76*ebbcc8a3SJeremy L Thompson       ierr = CeedVectorCreate(ceed, P*num_comp, &e_vecs[i]); CeedChkBackend(ierr);
77d1d35e2fSjeremylt       ierr = CeedVectorCreate(ceed, Q*size, &q_vecs[i]); CeedChkBackend(ierr);
78885ac19cSjeremylt       break;
79885ac19cSjeremylt     case CEED_EVAL_GRAD:
80d1d35e2fSjeremylt       ierr = CeedOperatorFieldGetBasis(op_fields[i], &basis); CeedChkBackend(ierr);
81d1d35e2fSjeremylt       ierr = CeedQFunctionFieldGetSize(qf_fields[i], &size); CeedChkBackend(ierr);
82*ebbcc8a3SJeremy L Thompson       ierr = CeedBasisGetNumNodes(basis, &P); CeedChkBackend(ierr);
83*ebbcc8a3SJeremy L Thompson       ierr = CeedBasisGetNumComponents(basis, &num_comp); CeedChkBackend(ierr);
84*ebbcc8a3SJeremy L Thompson       ierr = CeedVectorCreate(ceed, P*num_comp, &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;
1078c1105f8SJeremy L Thompson   bool is_setup_done;
1088c1105f8SJeremy L Thompson   ierr = CeedOperatorIsSetupDone(op, &is_setup_done); CeedChkBackend(ierr);
1098c1105f8SJeremy L Thompson   if (is_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
1294fc1f125SJeremy L Thompson   ierr = CeedCalloc(num_input_fields + num_output_fields, &impl->e_vecs_full);
130e15f9bd0SJeremy L Thompson   CeedChkBackend(ierr);
131885ac19cSjeremylt 
1324fc1f125SJeremy L Thompson   ierr = CeedCalloc(CEED_FIELD_MAX, &impl->input_states); CeedChkBackend(ierr);
133bf4cb664SJeremy L Thompson   ierr = CeedCalloc(CEED_FIELD_MAX, &impl->e_vecs_in); CeedChkBackend(ierr);
134bf4cb664SJeremy L Thompson   ierr = CeedCalloc(CEED_FIELD_MAX, &impl->e_vecs_out); CeedChkBackend(ierr);
135bf4cb664SJeremy L Thompson   ierr = CeedCalloc(CEED_FIELD_MAX, &impl->q_vecs_in); CeedChkBackend(ierr);
136bf4cb664SJeremy L Thompson   ierr = CeedCalloc(CEED_FIELD_MAX, &impl->q_vecs_out); CeedChkBackend(ierr);
137885ac19cSjeremylt 
1384fc1f125SJeremy L Thompson   impl->num_inputs = num_input_fields;
1394fc1f125SJeremy L Thompson   impl->num_outputs = num_output_fields;
140885ac19cSjeremylt 
141d1d35e2fSjeremylt   // Set up infield and outfield e_vecs and q_vecs
142885ac19cSjeremylt   // Infields
1434fc1f125SJeremy L Thompson   ierr = CeedOperatorSetupFields_Ref(qf, op, true, impl->e_vecs_full,
144d1d35e2fSjeremylt                                      impl->e_vecs_in, impl->q_vecs_in, 0,
145d1d35e2fSjeremylt                                      num_input_fields, Q);
146e15f9bd0SJeremy L Thompson   CeedChkBackend(ierr);
147885ac19cSjeremylt   // Outfields
1484fc1f125SJeremy L Thompson   ierr = CeedOperatorSetupFields_Ref(qf, op, false, impl->e_vecs_full,
149d1d35e2fSjeremylt                                      impl->e_vecs_out, impl->q_vecs_out,
150d1d35e2fSjeremylt                                      num_input_fields, num_output_fields, Q);
151e15f9bd0SJeremy L Thompson   CeedChkBackend(ierr);
152885ac19cSjeremylt 
15316911fdaSjeremylt   // Identity QFunctions
1540b454692Sjeremylt   if (impl->is_identity_qf) {
155d1d35e2fSjeremylt     CeedEvalMode in_mode, out_mode;
156d1d35e2fSjeremylt     CeedQFunctionField *in_fields, *out_fields;
1577e7773b5SJeremy L Thompson     ierr = CeedQFunctionGetFields(qf, NULL, &in_fields, NULL, &out_fields);
158e15f9bd0SJeremy L Thompson     CeedChkBackend(ierr);
1590b454692Sjeremylt     ierr = CeedQFunctionFieldGetEvalMode(in_fields[0], &in_mode);
160d1d35e2fSjeremylt     CeedChkBackend(ierr);
1610b454692Sjeremylt     ierr = CeedQFunctionFieldGetEvalMode(out_fields[0], &out_mode);
162d1d35e2fSjeremylt     CeedChkBackend(ierr);
163d1d35e2fSjeremylt 
1640b454692Sjeremylt     if (in_mode == CEED_EVAL_NONE && out_mode == CEED_EVAL_NONE) {
1650b454692Sjeremylt       impl->is_identity_restr_op = true;
1660b454692Sjeremylt     } else {
1670b454692Sjeremylt       ierr = CeedVectorDestroy(&impl->q_vecs_out[0]); CeedChkBackend(ierr);
1680b454692Sjeremylt       impl->q_vecs_out[0] = impl->q_vecs_in[0];
1690b454692Sjeremylt       ierr = CeedVectorAddReference(impl->q_vecs_in[0]); CeedChkBackend(ierr);
17016911fdaSjeremylt     }
17116911fdaSjeremylt   }
17216911fdaSjeremylt 
173e15f9bd0SJeremy L Thompson   ierr = CeedOperatorSetSetupDone(op); CeedChkBackend(ierr);
174885ac19cSjeremylt 
175e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
176885ac19cSjeremylt }
177885ac19cSjeremylt 
178f10650afSjeremylt //------------------------------------------------------------------------------
179f10650afSjeremylt // Setup Operator Inputs
180f10650afSjeremylt //------------------------------------------------------------------------------
181d1d35e2fSjeremylt static inline int CeedOperatorSetupInputs_Ref(CeedInt num_input_fields,
182d1d35e2fSjeremylt     CeedQFunctionField *qf_input_fields, CeedOperatorField *op_input_fields,
1834fc1f125SJeremy L Thompson     CeedVector in_vec, const bool skip_active,
1844fc1f125SJeremy L Thompson     CeedScalar *e_data_full[2*CEED_FIELD_MAX],
185a0162de9SJeremy L Thompson     CeedOperator_Ref *impl, CeedRequest *request) {
1861d102b48SJeremy L Thompson   CeedInt ierr;
187d1d35e2fSjeremylt   CeedEvalMode eval_mode;
188d1bcdac9Sjeremylt   CeedVector vec;
189d1d35e2fSjeremylt   CeedElemRestriction elem_restr;
1908d713cf6Sjeremylt   uint64_t state;
191885ac19cSjeremylt 
192d1d35e2fSjeremylt   for (CeedInt i=0; i<num_input_fields; i++) {
193d1bcdac9Sjeremylt     // Get input vector
194d1d35e2fSjeremylt     ierr = CeedOperatorFieldGetVector(op_input_fields[i], &vec);
195d1d35e2fSjeremylt     CeedChkBackend(ierr);
1961d102b48SJeremy L Thompson     if (vec == CEED_VECTOR_ACTIVE) {
197d1d35e2fSjeremylt       if (skip_active)
1981d102b48SJeremy L Thompson         continue;
1991d102b48SJeremy L Thompson       else
200d1d35e2fSjeremylt         vec = in_vec;
2011d102b48SJeremy L Thompson     }
2021d102b48SJeremy L Thompson 
203d1d35e2fSjeremylt     ierr = CeedQFunctionFieldGetEvalMode(qf_input_fields[i], &eval_mode);
204e15f9bd0SJeremy L Thompson     CeedChkBackend(ierr);
2051d102b48SJeremy L Thompson     // Restrict and Evec
206d1d35e2fSjeremylt     if (eval_mode == CEED_EVAL_WEIGHT) { // Skip
2071d102b48SJeremy L Thompson     } else {
208668048e2SJed Brown       // Restrict
209e15f9bd0SJeremy L Thompson       ierr = CeedVectorGetState(vec, &state); CeedChkBackend(ierr);
2108d713cf6Sjeremylt       // Skip restriction if input is unchanged
2114fc1f125SJeremy L Thompson       if (state != impl->input_states[i] || vec == in_vec) {
212d1d35e2fSjeremylt         ierr = CeedOperatorFieldGetElemRestriction(op_input_fields[i], &elem_restr);
213e15f9bd0SJeremy L Thompson         CeedChkBackend(ierr);
214d1d35e2fSjeremylt         ierr = CeedElemRestrictionApply(elem_restr, CEED_NOTRANSPOSE, vec,
2154fc1f125SJeremy L Thompson                                         impl->e_vecs_full[i], request);
2164fc1f125SJeremy L Thompson         CeedChkBackend(ierr);
2174fc1f125SJeremy L Thompson         impl->input_states[i] = state;
2188d713cf6Sjeremylt       }
219668048e2SJed Brown       // Get evec
2204fc1f125SJeremy L Thompson       ierr = CeedVectorGetArrayRead(impl->e_vecs_full[i], CEED_MEM_HOST,
2214fc1f125SJeremy L Thompson                                     (const CeedScalar **) &e_data_full[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,
233a0162de9SJeremy L Thompson     CeedInt num_input_fields, const bool skip_active,
2344fc1f125SJeremy L Thompson     CeedScalar *e_data_full[2*CEED_FIELD_MAX], CeedOperator_Ref *impl) {
2351d102b48SJeremy L Thompson   CeedInt ierr;
236d1d35e2fSjeremylt   CeedInt dim, elem_size, size;
237d1d35e2fSjeremylt   CeedElemRestriction elem_restr;
238d1d35e2fSjeremylt   CeedEvalMode eval_mode;
2391d102b48SJeremy L Thompson   CeedBasis basis;
2401d102b48SJeremy L Thompson 
241d1d35e2fSjeremylt   for (CeedInt i=0; i<num_input_fields; i++) {
2421d102b48SJeremy L Thompson     // Skip active input
243d1d35e2fSjeremylt     if (skip_active) {
2441d102b48SJeremy L Thompson       CeedVector vec;
245d1d35e2fSjeremylt       ierr = CeedOperatorFieldGetVector(op_input_fields[i], &vec);
246d1d35e2fSjeremylt       CeedChkBackend(ierr);
2471d102b48SJeremy L Thompson       if (vec == CEED_VECTOR_ACTIVE)
2481d102b48SJeremy L Thompson         continue;
2491d102b48SJeremy L Thompson     }
250d1d35e2fSjeremylt     // Get elem_size, eval_mode, size
251d1d35e2fSjeremylt     ierr = CeedOperatorFieldGetElemRestriction(op_input_fields[i], &elem_restr);
252e15f9bd0SJeremy L Thompson     CeedChkBackend(ierr);
253d1d35e2fSjeremylt     ierr = CeedElemRestrictionGetElementSize(elem_restr, &elem_size);
254e15f9bd0SJeremy L Thompson     CeedChkBackend(ierr);
255d1d35e2fSjeremylt     ierr = CeedQFunctionFieldGetEvalMode(qf_input_fields[i], &eval_mode);
256e15f9bd0SJeremy L Thompson     CeedChkBackend(ierr);
257d1d35e2fSjeremylt     ierr = CeedQFunctionFieldGetSize(qf_input_fields[i], &size);
258d1d35e2fSjeremylt     CeedChkBackend(ierr);
259885ac19cSjeremylt     // Basis action
260d1d35e2fSjeremylt     switch(eval_mode) {
261885ac19cSjeremylt     case CEED_EVAL_NONE:
262d1d35e2fSjeremylt       ierr = CeedVectorSetArray(impl->q_vecs_in[i], CEED_MEM_HOST,
2634fc1f125SJeremy L Thompson                                 CEED_USE_POINTER, &e_data_full[i][e*Q*size]);
264d1d35e2fSjeremylt       CeedChkBackend(ierr);
265885ac19cSjeremylt       break;
266885ac19cSjeremylt     case CEED_EVAL_INTERP:
267d1d35e2fSjeremylt       ierr = CeedOperatorFieldGetBasis(op_input_fields[i], &basis);
268e15f9bd0SJeremy L Thompson       CeedChkBackend(ierr);
269d1d35e2fSjeremylt       ierr = CeedVectorSetArray(impl->e_vecs_in[i], CEED_MEM_HOST,
2704fc1f125SJeremy L Thompson                                 CEED_USE_POINTER, &e_data_full[i][e*elem_size*size]);
271e15f9bd0SJeremy L Thompson       CeedChkBackend(ierr);
272d1d35e2fSjeremylt       ierr = CeedBasisApply(basis, 1, CEED_NOTRANSPOSE, CEED_EVAL_INTERP,
273d1d35e2fSjeremylt                             impl->e_vecs_in[i], impl->q_vecs_in[i]); CeedChkBackend(ierr);
274885ac19cSjeremylt       break;
275885ac19cSjeremylt     case CEED_EVAL_GRAD:
276d1d35e2fSjeremylt       ierr = CeedOperatorFieldGetBasis(op_input_fields[i], &basis);
277e15f9bd0SJeremy L Thompson       CeedChkBackend(ierr);
278e15f9bd0SJeremy L Thompson       ierr = CeedBasisGetDimension(basis, &dim); CeedChkBackend(ierr);
279d1d35e2fSjeremylt       ierr = CeedVectorSetArray(impl->e_vecs_in[i], CEED_MEM_HOST,
2804fc1f125SJeremy L Thompson                                 CEED_USE_POINTER, &e_data_full[i][e*elem_size*size/dim]);
281e15f9bd0SJeremy L Thompson       CeedChkBackend(ierr);
282d1bcdac9Sjeremylt       ierr = CeedBasisApply(basis, 1, CEED_NOTRANSPOSE,
283d1d35e2fSjeremylt                             CEED_EVAL_GRAD, impl->e_vecs_in[i],
284d1d35e2fSjeremylt                             impl->q_vecs_in[i]); CeedChkBackend(ierr);
285885ac19cSjeremylt       break;
286885ac19cSjeremylt     case CEED_EVAL_WEIGHT:
287885ac19cSjeremylt       break;  // No action
288bbfacfcdSjeremylt     // LCOV_EXCL_START
289885ac19cSjeremylt     case CEED_EVAL_DIV:
2901d102b48SJeremy L Thompson     case CEED_EVAL_CURL: {
291d1d35e2fSjeremylt       ierr = CeedOperatorFieldGetBasis(op_input_fields[i], &basis);
292e15f9bd0SJeremy L Thompson       CeedChkBackend(ierr);
2931d102b48SJeremy L Thompson       Ceed ceed;
294e15f9bd0SJeremy L Thompson       ierr = CeedBasisGetCeed(basis, &ceed); CeedChkBackend(ierr);
295e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_BACKEND,
296e15f9bd0SJeremy L Thompson                        "Ceed evaluation mode not implemented");
297bbfacfcdSjeremylt       // LCOV_EXCL_STOP
298885ac19cSjeremylt     }
299885ac19cSjeremylt     }
300885ac19cSjeremylt   }
301e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
302885ac19cSjeremylt }
303885ac19cSjeremylt 
304f10650afSjeremylt //------------------------------------------------------------------------------
305f10650afSjeremylt // Output Basis Action
306f10650afSjeremylt //------------------------------------------------------------------------------
3071d102b48SJeremy L Thompson static inline int CeedOperatorOutputBasis_Ref(CeedInt e, CeedInt Q,
308d1d35e2fSjeremylt     CeedQFunctionField *qf_output_fields, CeedOperatorField *op_output_fields,
309d1d35e2fSjeremylt     CeedInt num_input_fields, CeedInt num_output_fields, CeedOperator op,
3104fc1f125SJeremy L Thompson     CeedScalar *e_data_full[2*CEED_FIELD_MAX], CeedOperator_Ref *impl) {
3111d102b48SJeremy L Thompson   CeedInt ierr;
312d1d35e2fSjeremylt   CeedInt dim, elem_size, size;
313d1d35e2fSjeremylt   CeedElemRestriction elem_restr;
314d1d35e2fSjeremylt   CeedEvalMode eval_mode;
3151d102b48SJeremy L Thompson   CeedBasis basis;
3161d102b48SJeremy L Thompson 
317d1d35e2fSjeremylt   for (CeedInt i=0; i<num_output_fields; i++) {
318d1d35e2fSjeremylt     // Get elem_size, eval_mode, size
319d1d35e2fSjeremylt     ierr = CeedOperatorFieldGetElemRestriction(op_output_fields[i], &elem_restr);
320e15f9bd0SJeremy L Thompson     CeedChkBackend(ierr);
321d1d35e2fSjeremylt     ierr = CeedElemRestrictionGetElementSize(elem_restr, &elem_size);
322e15f9bd0SJeremy L Thompson     CeedChkBackend(ierr);
323d1d35e2fSjeremylt     ierr = CeedQFunctionFieldGetEvalMode(qf_output_fields[i], &eval_mode);
324e15f9bd0SJeremy L Thompson     CeedChkBackend(ierr);
325d1d35e2fSjeremylt     ierr = CeedQFunctionFieldGetSize(qf_output_fields[i], &size);
326e15f9bd0SJeremy L Thompson     CeedChkBackend(ierr);
327885ac19cSjeremylt     // Basis action
328d1d35e2fSjeremylt     switch(eval_mode) {
329885ac19cSjeremylt     case CEED_EVAL_NONE:
330885ac19cSjeremylt       break; // No action
331885ac19cSjeremylt     case CEED_EVAL_INTERP:
332d1d35e2fSjeremylt       ierr = CeedOperatorFieldGetBasis(op_output_fields[i], &basis);
333e15f9bd0SJeremy L Thompson       CeedChkBackend(ierr);
334d1d35e2fSjeremylt       ierr = CeedVectorSetArray(impl->e_vecs_out[i], CEED_MEM_HOST,
335aedaa0e5Sjeremylt                                 CEED_USE_POINTER,
3364fc1f125SJeremy L Thompson                                 &e_data_full[i + num_input_fields][e*elem_size*size]);
337e15f9bd0SJeremy L Thompson       CeedChkBackend(ierr);
338aedaa0e5Sjeremylt       ierr = CeedBasisApply(basis, 1, CEED_TRANSPOSE,
339d1d35e2fSjeremylt                             CEED_EVAL_INTERP, impl->q_vecs_out[i],
340d1d35e2fSjeremylt                             impl->e_vecs_out[i]); CeedChkBackend(ierr);
341885ac19cSjeremylt       break;
342885ac19cSjeremylt     case CEED_EVAL_GRAD:
343d1d35e2fSjeremylt       ierr = CeedOperatorFieldGetBasis(op_output_fields[i], &basis);
344e15f9bd0SJeremy L Thompson       CeedChkBackend(ierr);
345e15f9bd0SJeremy L Thompson       ierr = CeedBasisGetDimension(basis, &dim); CeedChkBackend(ierr);
346d1d35e2fSjeremylt       ierr = CeedVectorSetArray(impl->e_vecs_out[i], CEED_MEM_HOST,
347aedaa0e5Sjeremylt                                 CEED_USE_POINTER,
3484fc1f125SJeremy L Thompson                                 &e_data_full[i + num_input_fields][e*elem_size*size/dim]);
349e15f9bd0SJeremy L Thompson       CeedChkBackend(ierr);
350aedaa0e5Sjeremylt       ierr = CeedBasisApply(basis, 1, CEED_TRANSPOSE,
351d1d35e2fSjeremylt                             CEED_EVAL_GRAD, impl->q_vecs_out[i],
352d1d35e2fSjeremylt                             impl->e_vecs_out[i]); CeedChkBackend(ierr);
353885ac19cSjeremylt       break;
354c042f62fSJeremy L Thompson     // LCOV_EXCL_START
355bbfacfcdSjeremylt     case CEED_EVAL_WEIGHT: {
3564ce2993fSjeremylt       Ceed ceed;
357e15f9bd0SJeremy L Thompson       ierr = CeedOperatorGetCeed(op, &ceed); CeedChkBackend(ierr);
358e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_BACKEND,
359e15f9bd0SJeremy L Thompson                        "CEED_EVAL_WEIGHT cannot be an output "
3601d102b48SJeremy L Thompson                        "evaluation mode");
3614ce2993fSjeremylt     }
362885ac19cSjeremylt     case CEED_EVAL_DIV:
3631d102b48SJeremy L Thompson     case CEED_EVAL_CURL: {
3641d102b48SJeremy L Thompson       Ceed ceed;
365e15f9bd0SJeremy L Thompson       ierr = CeedOperatorGetCeed(op, &ceed); CeedChkBackend(ierr);
366e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_BACKEND,
367e15f9bd0SJeremy L Thompson                        "Ceed evaluation mode not implemented");
3681d102b48SJeremy L Thompson       // LCOV_EXCL_STOP
369885ac19cSjeremylt     }
370885ac19cSjeremylt     }
371885ac19cSjeremylt   }
372e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
3731d102b48SJeremy L Thompson }
3741d102b48SJeremy L Thompson 
375f10650afSjeremylt //------------------------------------------------------------------------------
376f10650afSjeremylt // Restore Input Vectors
377f10650afSjeremylt //------------------------------------------------------------------------------
378d1d35e2fSjeremylt static inline int CeedOperatorRestoreInputs_Ref(CeedInt num_input_fields,
379d1d35e2fSjeremylt     CeedQFunctionField *qf_input_fields, CeedOperatorField *op_input_fields,
3804fc1f125SJeremy L Thompson     const bool skip_active, CeedScalar *e_data_full[2*CEED_FIELD_MAX],
381a0162de9SJeremy L Thompson     CeedOperator_Ref *impl) {
3821d102b48SJeremy L Thompson   CeedInt ierr;
383d1d35e2fSjeremylt   CeedEvalMode eval_mode;
3841d102b48SJeremy L Thompson 
385d1d35e2fSjeremylt   for (CeedInt i=0; i<num_input_fields; i++) {
3861d102b48SJeremy L Thompson     // Skip active inputs
387d1d35e2fSjeremylt     if (skip_active) {
3881d102b48SJeremy L Thompson       CeedVector vec;
389d1d35e2fSjeremylt       ierr = CeedOperatorFieldGetVector(op_input_fields[i], &vec);
390d1d35e2fSjeremylt       CeedChkBackend(ierr);
3911d102b48SJeremy L Thompson       if (vec == CEED_VECTOR_ACTIVE)
3921d102b48SJeremy L Thompson         continue;
3931d102b48SJeremy L Thompson     }
3941d102b48SJeremy L Thompson     // Restore input
395d1d35e2fSjeremylt     ierr = CeedQFunctionFieldGetEvalMode(qf_input_fields[i], &eval_mode);
396e15f9bd0SJeremy L Thompson     CeedChkBackend(ierr);
397d1d35e2fSjeremylt     if (eval_mode == CEED_EVAL_WEIGHT) { // Skip
3981d102b48SJeremy L Thompson     } else {
3994fc1f125SJeremy L Thompson       ierr = CeedVectorRestoreArrayRead(impl->e_vecs_full[i],
4004fc1f125SJeremy L Thompson                                         (const CeedScalar **) &e_data_full[i]);
401e15f9bd0SJeremy L Thompson       CeedChkBackend(ierr);
4021d102b48SJeremy L Thompson     }
4031d102b48SJeremy L Thompson   }
404e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
4051d102b48SJeremy L Thompson }
4061d102b48SJeremy L Thompson 
407f10650afSjeremylt //------------------------------------------------------------------------------
408f10650afSjeremylt // Operator Apply
409f10650afSjeremylt //------------------------------------------------------------------------------
410d1d35e2fSjeremylt static int CeedOperatorApplyAdd_Ref(CeedOperator op, CeedVector in_vec,
411d1d35e2fSjeremylt                                     CeedVector out_vec, CeedRequest *request) {
4121d102b48SJeremy L Thompson   int ierr;
4131d102b48SJeremy L Thompson   CeedOperator_Ref *impl;
414e15f9bd0SJeremy L Thompson   ierr = CeedOperatorGetData(op, &impl); CeedChkBackend(ierr);
4151d102b48SJeremy L Thompson   CeedQFunction qf;
416e15f9bd0SJeremy L Thompson   ierr = CeedOperatorGetQFunction(op, &qf); CeedChkBackend(ierr);
417d1d35e2fSjeremylt   CeedInt Q, num_elem, num_input_fields, num_output_fields, size;
418e15f9bd0SJeremy L Thompson   ierr = CeedOperatorGetNumQuadraturePoints(op, &Q); CeedChkBackend(ierr);
419d1d35e2fSjeremylt   ierr = CeedOperatorGetNumElements(op, &num_elem); CeedChkBackend(ierr);
420d1d35e2fSjeremylt   CeedOperatorField *op_input_fields, *op_output_fields;
4217e7773b5SJeremy L Thompson   ierr = CeedOperatorGetFields(op, &num_input_fields, &op_input_fields,
4227e7773b5SJeremy L Thompson                                &num_output_fields, &op_output_fields);
423e15f9bd0SJeremy L Thompson   CeedChkBackend(ierr);
424d1d35e2fSjeremylt   CeedQFunctionField *qf_input_fields, *qf_output_fields;
4257e7773b5SJeremy L Thompson   ierr = CeedQFunctionGetFields(qf, NULL, &qf_input_fields, NULL,
4267e7773b5SJeremy L Thompson                                 &qf_output_fields);
427e15f9bd0SJeremy L Thompson   CeedChkBackend(ierr);
428d1d35e2fSjeremylt   CeedEvalMode eval_mode;
4291d102b48SJeremy L Thompson   CeedVector vec;
430d1d35e2fSjeremylt   CeedElemRestriction elem_restr;
4314fc1f125SJeremy L Thompson   CeedScalar *e_data_full[2*CEED_FIELD_MAX] = {0};
4321d102b48SJeremy L Thompson 
4331d102b48SJeremy L Thompson   // Setup
434e15f9bd0SJeremy L Thompson   ierr = CeedOperatorSetup_Ref(op); CeedChkBackend(ierr);
4351d102b48SJeremy L Thompson 
4360b454692Sjeremylt   // Restriction only operator
4370b454692Sjeremylt   if (impl->is_identity_restr_op) {
4380b454692Sjeremylt     ierr = CeedOperatorFieldGetElemRestriction(op_input_fields[0], &elem_restr);
4390b454692Sjeremylt     CeedChkBackend(ierr);
4400b454692Sjeremylt     ierr = CeedElemRestrictionApply(elem_restr, CEED_NOTRANSPOSE, in_vec,
4414fc1f125SJeremy L Thompson                                     impl->e_vecs_full[0], request);
4424fc1f125SJeremy L Thompson     CeedChkBackend(ierr);
4430b454692Sjeremylt     ierr = CeedOperatorFieldGetElemRestriction(op_output_fields[0], &elem_restr);
4440b454692Sjeremylt     CeedChkBackend(ierr);
4454fc1f125SJeremy L Thompson     ierr = CeedElemRestrictionApply(elem_restr, CEED_TRANSPOSE,
4464fc1f125SJeremy L Thompson                                     impl->e_vecs_full[0],
4470b454692Sjeremylt                                     out_vec, request); CeedChkBackend(ierr);
4480b454692Sjeremylt     return CEED_ERROR_SUCCESS;
4490b454692Sjeremylt   }
4500b454692Sjeremylt 
4511d102b48SJeremy L Thompson   // Input Evecs and Restriction
452d1d35e2fSjeremylt   ierr = CeedOperatorSetupInputs_Ref(num_input_fields, qf_input_fields,
4534fc1f125SJeremy L Thompson                                      op_input_fields, in_vec, false, e_data_full, impl,
454e15f9bd0SJeremy L Thompson                                      request); CeedChkBackend(ierr);
4551d102b48SJeremy L Thompson 
4561d102b48SJeremy L Thompson   // Output Evecs
457d1d35e2fSjeremylt   for (CeedInt i=0; i<num_output_fields; i++) {
4589c774eddSJeremy L Thompson     ierr = CeedVectorGetArrayWrite(impl->e_vecs_full[i+impl->num_inputs],
4599c774eddSJeremy L Thompson                                    CEED_MEM_HOST, &e_data_full[i + num_input_fields]);
4609c774eddSJeremy L Thompson     CeedChkBackend(ierr);
4611d102b48SJeremy L Thompson   }
4621d102b48SJeremy L Thompson 
4631d102b48SJeremy L Thompson   // Loop through elements
464d1d35e2fSjeremylt   for (CeedInt e=0; e<num_elem; e++) {
4651d102b48SJeremy L Thompson     // Output pointers
466d1d35e2fSjeremylt     for (CeedInt i=0; i<num_output_fields; i++) {
467d1d35e2fSjeremylt       ierr = CeedQFunctionFieldGetEvalMode(qf_output_fields[i], &eval_mode);
468e15f9bd0SJeremy L Thompson       CeedChkBackend(ierr);
469d1d35e2fSjeremylt       if (eval_mode == CEED_EVAL_NONE) {
470d1d35e2fSjeremylt         ierr = CeedQFunctionFieldGetSize(qf_output_fields[i], &size);
471e15f9bd0SJeremy L Thompson         CeedChkBackend(ierr);
472d1d35e2fSjeremylt         ierr = CeedVectorSetArray(impl->q_vecs_out[i], CEED_MEM_HOST,
4731d102b48SJeremy L Thompson                                   CEED_USE_POINTER,
4744fc1f125SJeremy L Thompson                                   &e_data_full[i + num_input_fields][e*Q*size]);
475e15f9bd0SJeremy L Thompson         CeedChkBackend(ierr);
4761d102b48SJeremy L Thompson       }
4771d102b48SJeremy L Thompson     }
4781d102b48SJeremy L Thompson 
47916911fdaSjeremylt     // Input basis apply
480d1d35e2fSjeremylt     ierr = CeedOperatorInputBasis_Ref(e, Q, qf_input_fields, op_input_fields,
4814fc1f125SJeremy L Thompson                                       num_input_fields, false, e_data_full, impl);
482e15f9bd0SJeremy L Thompson     CeedChkBackend(ierr);
48316911fdaSjeremylt 
4841d102b48SJeremy L Thompson     // Q function
4850b454692Sjeremylt     if (!impl->is_identity_qf) {
486d1d35e2fSjeremylt       ierr = CeedQFunctionApply(qf, Q, impl->q_vecs_in, impl->q_vecs_out);
487e15f9bd0SJeremy L Thompson       CeedChkBackend(ierr);
48816911fdaSjeremylt     }
4891d102b48SJeremy L Thompson 
4901d102b48SJeremy L Thompson     // Output basis apply
491d1d35e2fSjeremylt     ierr = CeedOperatorOutputBasis_Ref(e, Q, qf_output_fields, op_output_fields,
492a0162de9SJeremy L Thompson                                        num_input_fields, num_output_fields, op,
4934fc1f125SJeremy L Thompson                                        e_data_full, impl); CeedChkBackend(ierr);
4941d102b48SJeremy L Thompson   }
495885ac19cSjeremylt 
496885ac19cSjeremylt   // Output restriction
497d1d35e2fSjeremylt   for (CeedInt i=0; i<num_output_fields; i++) {
498d1d35e2fSjeremylt     // Restore Evec
4994fc1f125SJeremy L Thompson     ierr = CeedVectorRestoreArray(impl->e_vecs_full[i+impl->num_inputs],
5004fc1f125SJeremy L Thompson                                   &e_data_full[i + num_input_fields]);
501e15f9bd0SJeremy L Thompson     CeedChkBackend(ierr);
502d1bcdac9Sjeremylt     // Get output vector
503d1d35e2fSjeremylt     ierr = CeedOperatorFieldGetVector(op_output_fields[i], &vec);
504e15f9bd0SJeremy L Thompson     CeedChkBackend(ierr);
505668048e2SJed Brown     // Active
506d1bcdac9Sjeremylt     if (vec == CEED_VECTOR_ACTIVE)
507d1d35e2fSjeremylt       vec = out_vec;
5087ca8db16Sjeremylt     // Restrict
509d1d35e2fSjeremylt     ierr = CeedOperatorFieldGetElemRestriction(op_output_fields[i], &elem_restr);
510e15f9bd0SJeremy L Thompson     CeedChkBackend(ierr);
511d1d35e2fSjeremylt     ierr = CeedElemRestrictionApply(elem_restr, CEED_TRANSPOSE,
5124fc1f125SJeremy L Thompson                                     impl->e_vecs_full[i+impl->num_inputs],
5134fc1f125SJeremy L Thompson                                     vec, request); CeedChkBackend(ierr);
514885ac19cSjeremylt   }
515885ac19cSjeremylt 
5167ca8db16Sjeremylt   // Restore input arrays
517d1d35e2fSjeremylt   ierr = CeedOperatorRestoreInputs_Ref(num_input_fields, qf_input_fields,
5184fc1f125SJeremy L Thompson                                        op_input_fields, false, e_data_full, impl);
519e15f9bd0SJeremy L Thompson   CeedChkBackend(ierr);
5207ca8db16Sjeremylt 
521e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
52221617c04Sjeremylt }
52321617c04Sjeremylt 
524f10650afSjeremylt //------------------------------------------------------------------------------
52570a7ffb3SJeremy L Thompson // Core code for assembling linear QFunction
526f10650afSjeremylt //------------------------------------------------------------------------------
52770a7ffb3SJeremy L Thompson static inline int CeedOperatorLinearAssembleQFunctionCore_Ref(CeedOperator op,
52870a7ffb3SJeremy L Thompson     bool build_objects, CeedVector *assembled, CeedElemRestriction *rstr,
52970a7ffb3SJeremy L Thompson     CeedRequest *request) {
5301d102b48SJeremy L Thompson   int ierr;
5311d102b48SJeremy L Thompson   CeedOperator_Ref *impl;
532e15f9bd0SJeremy L Thompson   ierr = CeedOperatorGetData(op, &impl); CeedChkBackend(ierr);
5331d102b48SJeremy L Thompson   CeedQFunction qf;
534e15f9bd0SJeremy L Thompson   ierr = CeedOperatorGetQFunction(op, &qf); CeedChkBackend(ierr);
535d1d35e2fSjeremylt   CeedInt Q, num_elem, num_input_fields, num_output_fields, size;
536e15f9bd0SJeremy L Thompson   ierr = CeedOperatorGetNumQuadraturePoints(op, &Q); CeedChkBackend(ierr);
537d1d35e2fSjeremylt   ierr = CeedOperatorGetNumElements(op, &num_elem); CeedChkBackend(ierr);
538d1d35e2fSjeremylt   CeedOperatorField *op_input_fields, *op_output_fields;
5397e7773b5SJeremy L Thompson   ierr = CeedOperatorGetFields(op, &num_input_fields, &op_input_fields,
5407e7773b5SJeremy L Thompson                                &num_output_fields, &op_output_fields);
541e15f9bd0SJeremy L Thompson   CeedChkBackend(ierr);
542d1d35e2fSjeremylt   CeedQFunctionField *qf_input_fields, *qf_output_fields;
5437e7773b5SJeremy L Thompson   ierr = CeedQFunctionGetFields(qf, NULL, &qf_input_fields, NULL,
5447e7773b5SJeremy L Thompson                                 &qf_output_fields);
545e15f9bd0SJeremy L Thompson   CeedChkBackend(ierr);
5461d102b48SJeremy L Thompson   CeedVector vec;
5474fc1f125SJeremy L Thompson   CeedInt num_active_in = impl->num_active_in,
5484fc1f125SJeremy L Thompson           num_active_out = impl->num_active_out;
549bb219a0fSJeremy L Thompson   CeedVector *active_in = impl->qf_active_in;
5501d102b48SJeremy L Thompson   CeedScalar *a, *tmp;
551d1d35e2fSjeremylt   Ceed ceed, ceed_parent;
552e15f9bd0SJeremy L Thompson   ierr = CeedOperatorGetCeed(op, &ceed); CeedChkBackend(ierr);
553d1d35e2fSjeremylt   ierr = CeedGetOperatorFallbackParentCeed(ceed, &ceed_parent);
554e15f9bd0SJeremy L Thompson   CeedChkBackend(ierr);
555d1d35e2fSjeremylt   ceed_parent = ceed_parent ? ceed_parent : ceed;
5564fc1f125SJeremy L Thompson   CeedScalar *e_data_full[2*CEED_FIELD_MAX] = {0};
5571d102b48SJeremy L Thompson 
5581d102b48SJeremy L Thompson   // Setup
559e15f9bd0SJeremy L Thompson   ierr = CeedOperatorSetup_Ref(op); CeedChkBackend(ierr);
5601d102b48SJeremy L Thompson 
56116911fdaSjeremylt   // Check for identity
5620b454692Sjeremylt   if (impl->is_identity_qf)
56316911fdaSjeremylt     // LCOV_EXCL_START
564e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_BACKEND,
565e15f9bd0SJeremy L Thompson                      "Assembling identity QFunctions not supported");
56616911fdaSjeremylt   // LCOV_EXCL_STOP
56716911fdaSjeremylt 
5681d102b48SJeremy L Thompson   // Input Evecs and Restriction
569d1d35e2fSjeremylt   ierr = CeedOperatorSetupInputs_Ref(num_input_fields, qf_input_fields,
5704fc1f125SJeremy L Thompson                                      op_input_fields, NULL, true, e_data_full,
571a0162de9SJeremy L Thompson                                      impl, request); CeedChkBackend(ierr);
5721d102b48SJeremy L Thompson 
5731d102b48SJeremy L Thompson   // Count number of active input fields
574bb219a0fSJeremy L Thompson   if (!num_active_in) {
575d1d35e2fSjeremylt     for (CeedInt i=0; i<num_input_fields; i++) {
5761d102b48SJeremy L Thompson       // Get input vector
577d1d35e2fSjeremylt       ierr = CeedOperatorFieldGetVector(op_input_fields[i], &vec);
578d1d35e2fSjeremylt       CeedChkBackend(ierr);
5791d102b48SJeremy L Thompson       // Check if active input
5801d102b48SJeremy L Thompson       if (vec == CEED_VECTOR_ACTIVE) {
581d1d35e2fSjeremylt         ierr = CeedQFunctionFieldGetSize(qf_input_fields[i], &size);
582e15f9bd0SJeremy L Thompson         CeedChkBackend(ierr);
583d1d35e2fSjeremylt         ierr = CeedVectorSetValue(impl->q_vecs_in[i], 0.0); CeedChkBackend(ierr);
584d1d35e2fSjeremylt         ierr = CeedVectorGetArray(impl->q_vecs_in[i], CEED_MEM_HOST, &tmp);
585d1d35e2fSjeremylt         CeedChkBackend(ierr);
586d1d35e2fSjeremylt         ierr = CeedRealloc(num_active_in + size, &active_in); CeedChkBackend(ierr);
5871d102b48SJeremy L Thompson         for (CeedInt field=0; field<size; field++) {
588d1d35e2fSjeremylt           ierr = CeedVectorCreate(ceed, Q, &active_in[num_active_in+field]);
589e15f9bd0SJeremy L Thompson           CeedChkBackend(ierr);
590d1d35e2fSjeremylt           ierr = CeedVectorSetArray(active_in[num_active_in+field], CEED_MEM_HOST,
59142ea3801Sjeremylt                                     CEED_USE_POINTER, &tmp[field*Q]);
592e15f9bd0SJeremy L Thompson           CeedChkBackend(ierr);
5931d102b48SJeremy L Thompson         }
594d1d35e2fSjeremylt         num_active_in += size;
595d1d35e2fSjeremylt         ierr = CeedVectorRestoreArray(impl->q_vecs_in[i], &tmp); CeedChkBackend(ierr);
5961d102b48SJeremy L Thompson       }
5971d102b48SJeremy L Thompson     }
5984fc1f125SJeremy L Thompson     impl->num_active_in = num_active_in;
599bb219a0fSJeremy L Thompson     impl->qf_active_in = active_in;
600bb219a0fSJeremy L Thompson   }
6011d102b48SJeremy L Thompson 
6021d102b48SJeremy L Thompson   // Count number of active output fields
603bb219a0fSJeremy L Thompson   if (!num_active_out) {
604d1d35e2fSjeremylt     for (CeedInt i=0; i<num_output_fields; i++) {
6051d102b48SJeremy L Thompson       // Get output vector
606d1d35e2fSjeremylt       ierr = CeedOperatorFieldGetVector(op_output_fields[i], &vec);
607e15f9bd0SJeremy L Thompson       CeedChkBackend(ierr);
6081d102b48SJeremy L Thompson       // Check if active output
6091d102b48SJeremy L Thompson       if (vec == CEED_VECTOR_ACTIVE) {
610d1d35e2fSjeremylt         ierr = CeedQFunctionFieldGetSize(qf_output_fields[i], &size);
611e15f9bd0SJeremy L Thompson         CeedChkBackend(ierr);
612d1d35e2fSjeremylt         num_active_out += size;
6131d102b48SJeremy L Thompson       }
6141d102b48SJeremy L Thompson     }
6154fc1f125SJeremy L Thompson     impl->num_active_out = num_active_out;
616bb219a0fSJeremy L Thompson   }
6171d102b48SJeremy L Thompson 
6181d102b48SJeremy L Thompson   // Check sizes
619d1d35e2fSjeremylt   if (!num_active_in || !num_active_out)
620138d4072Sjeremylt     // LCOV_EXCL_START
621e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_BACKEND,
622e15f9bd0SJeremy L Thompson                      "Cannot assemble QFunction without active inputs "
623138d4072Sjeremylt                      "and outputs");
624138d4072Sjeremylt   // LCOV_EXCL_STOP
6251d102b48SJeremy L Thompson 
62670a7ffb3SJeremy L Thompson   // Build objects if needed
62770a7ffb3SJeremy L Thompson   if (build_objects) {
6281d102b48SJeremy L Thompson     // Create output restriction
629d1d35e2fSjeremylt     CeedInt strides[3] = {1, Q, num_active_in*num_active_out*Q}; /* *NOPAD* */
630d1d35e2fSjeremylt     ierr = CeedElemRestrictionCreateStrided(ceed_parent, num_elem, Q,
631d1d35e2fSjeremylt                                             num_active_in*num_active_out,
632d1d35e2fSjeremylt                                             num_active_in*num_active_out*num_elem*Q,
633e15f9bd0SJeremy L Thompson                                             strides, rstr); CeedChkBackend(ierr);
6341d102b48SJeremy L Thompson     // Create assembled vector
635d1d35e2fSjeremylt     ierr = CeedVectorCreate(ceed_parent, num_elem*Q*num_active_in*num_active_out,
636e15f9bd0SJeremy L Thompson                             assembled); CeedChkBackend(ierr);
63770a7ffb3SJeremy L Thompson   }
63870a7ffb3SJeremy L Thompson   // Clear output vector
639e15f9bd0SJeremy L Thompson   ierr = CeedVectorSetValue(*assembled, 0.0); CeedChkBackend(ierr);
640e15f9bd0SJeremy L Thompson   ierr = CeedVectorGetArray(*assembled, CEED_MEM_HOST, &a); CeedChkBackend(ierr);
6411d102b48SJeremy L Thompson 
6421d102b48SJeremy L Thompson   // Loop through elements
643d1d35e2fSjeremylt   for (CeedInt e=0; e<num_elem; e++) {
6441d102b48SJeremy L Thompson     // Input basis apply
645d1d35e2fSjeremylt     ierr = CeedOperatorInputBasis_Ref(e, Q, qf_input_fields, op_input_fields,
6464fc1f125SJeremy L Thompson                                       num_input_fields, true, e_data_full, impl);
647e15f9bd0SJeremy L Thompson     CeedChkBackend(ierr);
6481d102b48SJeremy L Thompson 
6491d102b48SJeremy L Thompson     // Assemble QFunction
650d1d35e2fSjeremylt     for (CeedInt in=0; in<num_active_in; in++) {
6511d102b48SJeremy L Thompson       // Set Inputs
652d1d35e2fSjeremylt       ierr = CeedVectorSetValue(active_in[in], 1.0); CeedChkBackend(ierr);
653d1d35e2fSjeremylt       if (num_active_in > 1) {
654d1d35e2fSjeremylt         ierr = CeedVectorSetValue(active_in[(in+num_active_in-1)%num_active_in],
655e15f9bd0SJeremy L Thompson                                   0.0); CeedChkBackend(ierr);
65642ea3801Sjeremylt       }
6571d102b48SJeremy L Thompson       // Set Outputs
658d1d35e2fSjeremylt       for (CeedInt out=0; out<num_output_fields; out++) {
6591d102b48SJeremy L Thompson         // Get output vector
660d1d35e2fSjeremylt         ierr = CeedOperatorFieldGetVector(op_output_fields[out], &vec);
661e15f9bd0SJeremy L Thompson         CeedChkBackend(ierr);
6621d102b48SJeremy L Thompson         // Check if active output
6631d102b48SJeremy L Thompson         if (vec == CEED_VECTOR_ACTIVE) {
664d1d35e2fSjeremylt           CeedVectorSetArray(impl->q_vecs_out[out], CEED_MEM_HOST,
665e15f9bd0SJeremy L Thompson                              CEED_USE_POINTER, a); CeedChkBackend(ierr);
666d1d35e2fSjeremylt           ierr = CeedQFunctionFieldGetSize(qf_output_fields[out], &size);
667e15f9bd0SJeremy L Thompson           CeedChkBackend(ierr);
6681d102b48SJeremy L Thompson           a += size*Q; // Advance the pointer by the size of the output
6691d102b48SJeremy L Thompson         }
6701d102b48SJeremy L Thompson       }
6711d102b48SJeremy L Thompson       // Apply QFunction
672d1d35e2fSjeremylt       ierr = CeedQFunctionApply(qf, Q, impl->q_vecs_in, impl->q_vecs_out);
673e15f9bd0SJeremy L Thompson       CeedChkBackend(ierr);
6741d102b48SJeremy L Thompson     }
6751d102b48SJeremy L Thompson   }
6761d102b48SJeremy L Thompson 
6771d102b48SJeremy L Thompson   // Un-set output Qvecs to prevent accidental overwrite of Assembled
678d1d35e2fSjeremylt   for (CeedInt out=0; out<num_output_fields; out++) {
6791d102b48SJeremy L Thompson     // Get output vector
680d1d35e2fSjeremylt     ierr = CeedOperatorFieldGetVector(op_output_fields[out], &vec);
681e15f9bd0SJeremy L Thompson     CeedChkBackend(ierr);
6821d102b48SJeremy L Thompson     // Check if active output
6831d102b48SJeremy L Thompson     if (vec == CEED_VECTOR_ACTIVE) {
684d1d35e2fSjeremylt       CeedVectorTakeArray(impl->q_vecs_out[out], CEED_MEM_HOST, NULL);
685e15f9bd0SJeremy L Thompson       CeedChkBackend(ierr);
6861d102b48SJeremy L Thompson     }
6871d102b48SJeremy L Thompson   }
6881d102b48SJeremy L Thompson 
6891d102b48SJeremy L Thompson   // Restore input arrays
690d1d35e2fSjeremylt   ierr = CeedOperatorRestoreInputs_Ref(num_input_fields, qf_input_fields,
6914fc1f125SJeremy L Thompson                                        op_input_fields, true, e_data_full, impl);
692e15f9bd0SJeremy L Thompson   CeedChkBackend(ierr);
6931d102b48SJeremy L Thompson 
6941d102b48SJeremy L Thompson   // Restore output
695e15f9bd0SJeremy L Thompson   ierr = CeedVectorRestoreArray(*assembled, &a); CeedChkBackend(ierr);
6961d102b48SJeremy L Thompson 
697e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6981d102b48SJeremy L Thompson }
6991d102b48SJeremy L Thompson 
700f10650afSjeremylt //------------------------------------------------------------------------------
70170a7ffb3SJeremy L Thompson // Assemble Linear QFunction
70270a7ffb3SJeremy L Thompson //------------------------------------------------------------------------------
70370a7ffb3SJeremy L Thompson static int CeedOperatorLinearAssembleQFunction_Ref(CeedOperator op,
70470a7ffb3SJeremy L Thompson     CeedVector *assembled, CeedElemRestriction *rstr, CeedRequest *request) {
70570a7ffb3SJeremy L Thompson   return CeedOperatorLinearAssembleQFunctionCore_Ref(op, true, assembled, rstr,
70670a7ffb3SJeremy L Thompson          request);
70770a7ffb3SJeremy L Thompson }
70870a7ffb3SJeremy L Thompson 
70970a7ffb3SJeremy L Thompson //------------------------------------------------------------------------------
71070a7ffb3SJeremy L Thompson // Update Assembled Linear QFunction
71170a7ffb3SJeremy L Thompson //------------------------------------------------------------------------------
71270a7ffb3SJeremy L Thompson static int CeedOperatorLinearAssembleQFunctionUpdate_Ref(CeedOperator op,
71370a7ffb3SJeremy L Thompson     CeedVector assembled, CeedElemRestriction rstr, CeedRequest *request) {
71470a7ffb3SJeremy L Thompson   return CeedOperatorLinearAssembleQFunctionCore_Ref(op, false, &assembled,
71570a7ffb3SJeremy L Thompson          &rstr, request);
71670a7ffb3SJeremy L Thompson }
71770a7ffb3SJeremy L Thompson 
71870a7ffb3SJeremy L Thompson //------------------------------------------------------------------------------
719f10650afSjeremylt // Operator Destroy
720f10650afSjeremylt //------------------------------------------------------------------------------
721f10650afSjeremylt static int CeedOperatorDestroy_Ref(CeedOperator op) {
722f10650afSjeremylt   int ierr;
723f10650afSjeremylt   CeedOperator_Ref *impl;
724e15f9bd0SJeremy L Thompson   ierr = CeedOperatorGetData(op, &impl); CeedChkBackend(ierr);
725f10650afSjeremylt 
7264fc1f125SJeremy L Thompson   for (CeedInt i=0; i<impl->num_inputs+impl->num_outputs; i++) {
7274fc1f125SJeremy L Thompson     ierr = CeedVectorDestroy(&impl->e_vecs_full[i]); CeedChkBackend(ierr);
728f10650afSjeremylt   }
7294fc1f125SJeremy L Thompson   ierr = CeedFree(&impl->e_vecs_full); CeedChkBackend(ierr);
7304fc1f125SJeremy L Thompson   ierr = CeedFree(&impl->input_states); CeedChkBackend(ierr);
731f10650afSjeremylt 
7324fc1f125SJeremy L Thompson   for (CeedInt i=0; i<impl->num_inputs; i++) {
733d1d35e2fSjeremylt     ierr = CeedVectorDestroy(&impl->e_vecs_in[i]); CeedChkBackend(ierr);
734d1d35e2fSjeremylt     ierr = CeedVectorDestroy(&impl->q_vecs_in[i]); CeedChkBackend(ierr);
735f10650afSjeremylt   }
736d1d35e2fSjeremylt   ierr = CeedFree(&impl->e_vecs_in); CeedChkBackend(ierr);
737d1d35e2fSjeremylt   ierr = CeedFree(&impl->q_vecs_in); CeedChkBackend(ierr);
738f10650afSjeremylt 
7394fc1f125SJeremy L Thompson   for (CeedInt i=0; i<impl->num_outputs; i++) {
740d1d35e2fSjeremylt     ierr = CeedVectorDestroy(&impl->e_vecs_out[i]); CeedChkBackend(ierr);
741d1d35e2fSjeremylt     ierr = CeedVectorDestroy(&impl->q_vecs_out[i]); CeedChkBackend(ierr);
742f10650afSjeremylt   }
743d1d35e2fSjeremylt   ierr = CeedFree(&impl->e_vecs_out); CeedChkBackend(ierr);
744d1d35e2fSjeremylt   ierr = CeedFree(&impl->q_vecs_out); CeedChkBackend(ierr);
745f10650afSjeremylt 
746bb219a0fSJeremy L Thompson   // QFunction assembly
7474fc1f125SJeremy L Thompson   for (CeedInt i=0; i<impl->num_active_in; i++) {
748bb219a0fSJeremy L Thompson     ierr = CeedVectorDestroy(&impl->qf_active_in[i]); CeedChkBackend(ierr);
749bb219a0fSJeremy L Thompson   }
750bb219a0fSJeremy L Thompson   ierr = CeedFree(&impl->qf_active_in); CeedChkBackend(ierr);
751bb219a0fSJeremy L Thompson 
752e15f9bd0SJeremy L Thompson   ierr = CeedFree(&impl); CeedChkBackend(ierr);
753e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
754f10650afSjeremylt }
755f10650afSjeremylt 
756f10650afSjeremylt //------------------------------------------------------------------------------
757713f43c3Sjeremylt // Operator Create
758f10650afSjeremylt //------------------------------------------------------------------------------
75921617c04Sjeremylt int CeedOperatorCreate_Ref(CeedOperator op) {
76021617c04Sjeremylt   int ierr;
761fe2413ffSjeremylt   Ceed ceed;
762e15f9bd0SJeremy L Thompson   ierr = CeedOperatorGetCeed(op, &ceed); CeedChkBackend(ierr);
7634ce2993fSjeremylt   CeedOperator_Ref *impl;
76421617c04Sjeremylt 
765e15f9bd0SJeremy L Thompson   ierr = CeedCalloc(1, &impl); CeedChkBackend(ierr);
766e15f9bd0SJeremy L Thompson   ierr = CeedOperatorSetData(op, impl); CeedChkBackend(ierr);
767fe2413ffSjeremylt 
76880ac2e43SJeremy L Thompson   ierr = CeedSetBackendFunction(ceed, "Operator", op, "LinearAssembleQFunction",
76980ac2e43SJeremy L Thompson                                 CeedOperatorLinearAssembleQFunction_Ref);
770e15f9bd0SJeremy L Thompson   CeedChkBackend(ierr);
77170a7ffb3SJeremy L Thompson   ierr = CeedSetBackendFunction(ceed, "Operator", op,
77270a7ffb3SJeremy L Thompson                                 "LinearAssembleQFunctionUpdate",
77370a7ffb3SJeremy L Thompson                                 CeedOperatorLinearAssembleQFunctionUpdate_Ref);
77470a7ffb3SJeremy L Thompson   CeedChkBackend(ierr);
775cae8b89aSjeremylt   ierr = CeedSetBackendFunction(ceed, "Operator", op, "ApplyAdd",
776e15f9bd0SJeremy L Thompson                                 CeedOperatorApplyAdd_Ref); CeedChkBackend(ierr);
777fe2413ffSjeremylt   ierr = CeedSetBackendFunction(ceed, "Operator", op, "Destroy",
778e15f9bd0SJeremy L Thompson                                 CeedOperatorDestroy_Ref); CeedChkBackend(ierr);
779e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
78021617c04Sjeremylt }
781