xref: /libCEED/rust/libceed-sys/c-src/backends/ref/ceed-ref-operator.c (revision 3d8e882215d238700cdceb37404f76ca7fa24eaa)
1*3d8e8822SJeremy L Thompson // Copyright (c) 2017-2022, Lawrence Livermore National Security, LLC and other CEED contributors.
2*3d8e8822SJeremy L Thompson // All Rights Reserved. See the top-level LICENSE and NOTICE files for details.
321617c04Sjeremylt //
4*3d8e8822SJeremy L Thompson // SPDX-License-Identifier: BSD-2-Clause
521617c04Sjeremylt //
6*3d8e8822SJeremy L Thompson // This file is part of CEED:  http://github.com/ceed
721617c04Sjeremylt 
8ec3da8bcSJed Brown #include <ceed/ceed.h>
9ec3da8bcSJed Brown #include <ceed/backend.h>
103d576824SJeremy L Thompson #include <math.h>
113d576824SJeremy L Thompson #include <stdbool.h>
123d576824SJeremy L Thompson #include <stddef.h>
133d576824SJeremy L Thompson #include <stdint.h>
1421617c04Sjeremylt #include "ceed-ref.h"
1521617c04Sjeremylt 
16f10650afSjeremylt //------------------------------------------------------------------------------
17f10650afSjeremylt // Setup Input/Output Fields
18f10650afSjeremylt //------------------------------------------------------------------------------
19fe2413ffSjeremylt static int CeedOperatorSetupFields_Ref(CeedQFunction qf, CeedOperator op,
204fc1f125SJeremy L Thompson                                        bool is_input, CeedVector *e_vecs_full,
214fc1f125SJeremy L Thompson                                        CeedVector *e_vecs, CeedVector *q_vecs,
224fc1f125SJeremy L Thompson                                        CeedInt start_e, CeedInt num_fields,
234fc1f125SJeremy L Thompson                                        CeedInt Q) {
24ebbcc8a3SJeremy L Thompson   CeedInt ierr, num_comp, size, P;
25aedaa0e5Sjeremylt   Ceed ceed;
26e15f9bd0SJeremy L Thompson   ierr = CeedOperatorGetCeed(op, &ceed); CeedChkBackend(ierr);
27d1bcdac9Sjeremylt   CeedBasis basis;
28d1d35e2fSjeremylt   CeedElemRestriction elem_restr;
29d1d35e2fSjeremylt   CeedOperatorField *op_fields;
30d1d35e2fSjeremylt   CeedQFunctionField *qf_fields;
314fc1f125SJeremy L Thompson   if (is_input) {
327e7773b5SJeremy L Thompson     ierr = CeedOperatorGetFields(op, NULL, &op_fields, NULL, NULL);
337e7773b5SJeremy L Thompson     CeedChkBackend(ierr);
347e7773b5SJeremy L Thompson     ierr = CeedQFunctionGetFields(qf, NULL, &qf_fields, NULL, NULL);
357e7773b5SJeremy L Thompson     CeedChkBackend(ierr);
364fc1f125SJeremy L Thompson   } else {
374fc1f125SJeremy L Thompson     ierr = CeedOperatorGetFields(op, NULL, NULL, NULL, &op_fields);
384fc1f125SJeremy L Thompson     CeedChkBackend(ierr);
394fc1f125SJeremy L Thompson     ierr = CeedQFunctionGetFields(qf, NULL, NULL, NULL, &qf_fields);
404fc1f125SJeremy L Thompson     CeedChkBackend(ierr);
41fe2413ffSjeremylt   }
4221617c04Sjeremylt 
43885ac19cSjeremylt   // Loop over fields
44d1d35e2fSjeremylt   for (CeedInt i=0; i<num_fields; i++) {
45d1d35e2fSjeremylt     CeedEvalMode eval_mode;
46d1d35e2fSjeremylt     ierr = CeedQFunctionFieldGetEvalMode(qf_fields[i], &eval_mode);
47e15f9bd0SJeremy L Thompson     CeedChkBackend(ierr);
48d1d35e2fSjeremylt 
49d1d35e2fSjeremylt     if (eval_mode != CEED_EVAL_WEIGHT) {
50d1d35e2fSjeremylt       ierr = CeedOperatorFieldGetElemRestriction(op_fields[i], &elem_restr);
51d1d35e2fSjeremylt       CeedChkBackend(ierr);
52d1d35e2fSjeremylt       ierr = CeedElemRestrictionCreateVector(elem_restr, NULL,
534fc1f125SJeremy L Thompson                                              &e_vecs_full[i+start_e]);
54e15f9bd0SJeremy L Thompson       CeedChkBackend(ierr);
55135a076eSjeremylt     }
56135a076eSjeremylt 
57d1d35e2fSjeremylt     switch(eval_mode) {
58885ac19cSjeremylt     case CEED_EVAL_NONE:
59d1d35e2fSjeremylt       ierr = CeedQFunctionFieldGetSize(qf_fields[i], &size); CeedChkBackend(ierr);
60d1d35e2fSjeremylt       ierr = CeedVectorCreate(ceed, Q*size, &q_vecs[i]); CeedChkBackend(ierr);
61aedaa0e5Sjeremylt       break;
62aedaa0e5Sjeremylt     case CEED_EVAL_INTERP:
63885ac19cSjeremylt     case CEED_EVAL_GRAD:
64d1d35e2fSjeremylt       ierr = CeedOperatorFieldGetBasis(op_fields[i], &basis); CeedChkBackend(ierr);
65d1d35e2fSjeremylt       ierr = CeedQFunctionFieldGetSize(qf_fields[i], &size); CeedChkBackend(ierr);
66ebbcc8a3SJeremy L Thompson       ierr = CeedBasisGetNumNodes(basis, &P); CeedChkBackend(ierr);
67ebbcc8a3SJeremy L Thompson       ierr = CeedBasisGetNumComponents(basis, &num_comp); CeedChkBackend(ierr);
68ebbcc8a3SJeremy L Thompson       ierr = CeedVectorCreate(ceed, P*num_comp, &e_vecs[i]); CeedChkBackend(ierr);
69d1d35e2fSjeremylt       ierr = CeedVectorCreate(ceed, Q*size, &q_vecs[i]); CeedChkBackend(ierr);
70885ac19cSjeremylt       break;
71885ac19cSjeremylt     case CEED_EVAL_WEIGHT: // Only on input fields
72d1d35e2fSjeremylt       ierr = CeedOperatorFieldGetBasis(op_fields[i], &basis); CeedChkBackend(ierr);
73d1d35e2fSjeremylt       ierr = CeedVectorCreate(ceed, Q, &q_vecs[i]); CeedChkBackend(ierr);
74d1bcdac9Sjeremylt       ierr = CeedBasisApply(basis, 1, CEED_NOTRANSPOSE, CEED_EVAL_WEIGHT,
75d1d35e2fSjeremylt                             CEED_VECTOR_NONE, q_vecs[i]); CeedChkBackend(ierr);
76885ac19cSjeremylt       break;
77885ac19cSjeremylt     case CEED_EVAL_DIV:
784d537eeaSYohann       break; // Not implemented
79885ac19cSjeremylt     case CEED_EVAL_CURL:
804d537eeaSYohann       break; // Not implemented
8121617c04Sjeremylt     }
82885ac19cSjeremylt   }
83e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
8421617c04Sjeremylt }
8521617c04Sjeremylt 
86f10650afSjeremylt //------------------------------------------------------------------------------
87f10650afSjeremylt // Setup Operator
88f10650afSjeremylt //------------------------------------------------------------------------------/*
89885ac19cSjeremylt static int CeedOperatorSetup_Ref(CeedOperator op) {
9021617c04Sjeremylt   int ierr;
918c1105f8SJeremy L Thompson   bool is_setup_done;
928c1105f8SJeremy L Thompson   ierr = CeedOperatorIsSetupDone(op, &is_setup_done); CeedChkBackend(ierr);
938c1105f8SJeremy L Thompson   if (is_setup_done) return CEED_ERROR_SUCCESS;
94aedaa0e5Sjeremylt   Ceed ceed;
95e15f9bd0SJeremy L Thompson   ierr = CeedOperatorGetCeed(op, &ceed); CeedChkBackend(ierr);
964ce2993fSjeremylt   CeedOperator_Ref *impl;
97e15f9bd0SJeremy L Thompson   ierr = CeedOperatorGetData(op, &impl); CeedChkBackend(ierr);
984ce2993fSjeremylt   CeedQFunction qf;
99e15f9bd0SJeremy L Thompson   ierr = CeedOperatorGetQFunction(op, &qf); CeedChkBackend(ierr);
100d1d35e2fSjeremylt   CeedInt Q, num_input_fields, num_output_fields;
101e15f9bd0SJeremy L Thompson   ierr = CeedOperatorGetNumQuadraturePoints(op, &Q); CeedChkBackend(ierr);
1020b454692Sjeremylt   ierr = CeedQFunctionIsIdentity(qf, &impl->is_identity_qf); CeedChkBackend(ierr);
103d1d35e2fSjeremylt   CeedOperatorField *op_input_fields, *op_output_fields;
1047e7773b5SJeremy L Thompson   ierr = CeedOperatorGetFields(op, &num_input_fields, &op_input_fields,
1057e7773b5SJeremy L Thompson                                &num_output_fields, &op_output_fields);
106e15f9bd0SJeremy L Thompson   CeedChkBackend(ierr);
107d1d35e2fSjeremylt   CeedQFunctionField *qf_input_fields, *qf_output_fields;
1087e7773b5SJeremy L Thompson   ierr = CeedQFunctionGetFields(qf, NULL, &qf_input_fields, NULL,
1097e7773b5SJeremy L Thompson                                 &qf_output_fields);
110e15f9bd0SJeremy L Thompson   CeedChkBackend(ierr);
111885ac19cSjeremylt 
112885ac19cSjeremylt   // Allocate
1134fc1f125SJeremy L Thompson   ierr = CeedCalloc(num_input_fields + num_output_fields, &impl->e_vecs_full);
114e15f9bd0SJeremy L Thompson   CeedChkBackend(ierr);
115885ac19cSjeremylt 
1164fc1f125SJeremy L Thompson   ierr = CeedCalloc(CEED_FIELD_MAX, &impl->input_states); CeedChkBackend(ierr);
117bf4cb664SJeremy L Thompson   ierr = CeedCalloc(CEED_FIELD_MAX, &impl->e_vecs_in); CeedChkBackend(ierr);
118bf4cb664SJeremy L Thompson   ierr = CeedCalloc(CEED_FIELD_MAX, &impl->e_vecs_out); CeedChkBackend(ierr);
119bf4cb664SJeremy L Thompson   ierr = CeedCalloc(CEED_FIELD_MAX, &impl->q_vecs_in); CeedChkBackend(ierr);
120bf4cb664SJeremy L Thompson   ierr = CeedCalloc(CEED_FIELD_MAX, &impl->q_vecs_out); CeedChkBackend(ierr);
121885ac19cSjeremylt 
1224fc1f125SJeremy L Thompson   impl->num_inputs = num_input_fields;
1234fc1f125SJeremy L Thompson   impl->num_outputs = num_output_fields;
124885ac19cSjeremylt 
125d1d35e2fSjeremylt   // Set up infield and outfield e_vecs and q_vecs
126885ac19cSjeremylt   // Infields
1274fc1f125SJeremy L Thompson   ierr = CeedOperatorSetupFields_Ref(qf, op, true, impl->e_vecs_full,
128d1d35e2fSjeremylt                                      impl->e_vecs_in, impl->q_vecs_in, 0,
129d1d35e2fSjeremylt                                      num_input_fields, Q);
130e15f9bd0SJeremy L Thompson   CeedChkBackend(ierr);
131885ac19cSjeremylt   // Outfields
1324fc1f125SJeremy L Thompson   ierr = CeedOperatorSetupFields_Ref(qf, op, false, impl->e_vecs_full,
133d1d35e2fSjeremylt                                      impl->e_vecs_out, impl->q_vecs_out,
134d1d35e2fSjeremylt                                      num_input_fields, num_output_fields, Q);
135e15f9bd0SJeremy L Thompson   CeedChkBackend(ierr);
136885ac19cSjeremylt 
13716911fdaSjeremylt   // Identity QFunctions
1380b454692Sjeremylt   if (impl->is_identity_qf) {
139d1d35e2fSjeremylt     CeedEvalMode in_mode, out_mode;
140d1d35e2fSjeremylt     CeedQFunctionField *in_fields, *out_fields;
1417e7773b5SJeremy L Thompson     ierr = CeedQFunctionGetFields(qf, NULL, &in_fields, NULL, &out_fields);
142e15f9bd0SJeremy L Thompson     CeedChkBackend(ierr);
1430b454692Sjeremylt     ierr = CeedQFunctionFieldGetEvalMode(in_fields[0], &in_mode);
144d1d35e2fSjeremylt     CeedChkBackend(ierr);
1450b454692Sjeremylt     ierr = CeedQFunctionFieldGetEvalMode(out_fields[0], &out_mode);
146d1d35e2fSjeremylt     CeedChkBackend(ierr);
147d1d35e2fSjeremylt 
1480b454692Sjeremylt     if (in_mode == CEED_EVAL_NONE && out_mode == CEED_EVAL_NONE) {
1490b454692Sjeremylt       impl->is_identity_restr_op = true;
1500b454692Sjeremylt     } else {
1510b454692Sjeremylt       ierr = CeedVectorDestroy(&impl->q_vecs_out[0]); CeedChkBackend(ierr);
1520b454692Sjeremylt       impl->q_vecs_out[0] = impl->q_vecs_in[0];
1530b454692Sjeremylt       ierr = CeedVectorAddReference(impl->q_vecs_in[0]); CeedChkBackend(ierr);
15416911fdaSjeremylt     }
15516911fdaSjeremylt   }
15616911fdaSjeremylt 
157e15f9bd0SJeremy L Thompson   ierr = CeedOperatorSetSetupDone(op); CeedChkBackend(ierr);
158885ac19cSjeremylt 
159e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
160885ac19cSjeremylt }
161885ac19cSjeremylt 
162f10650afSjeremylt //------------------------------------------------------------------------------
163f10650afSjeremylt // Setup Operator Inputs
164f10650afSjeremylt //------------------------------------------------------------------------------
165d1d35e2fSjeremylt static inline int CeedOperatorSetupInputs_Ref(CeedInt num_input_fields,
166d1d35e2fSjeremylt     CeedQFunctionField *qf_input_fields, CeedOperatorField *op_input_fields,
1674fc1f125SJeremy L Thompson     CeedVector in_vec, const bool skip_active,
1684fc1f125SJeremy L Thompson     CeedScalar *e_data_full[2*CEED_FIELD_MAX],
169a0162de9SJeremy L Thompson     CeedOperator_Ref *impl, CeedRequest *request) {
1701d102b48SJeremy L Thompson   CeedInt ierr;
171d1d35e2fSjeremylt   CeedEvalMode eval_mode;
172d1bcdac9Sjeremylt   CeedVector vec;
173d1d35e2fSjeremylt   CeedElemRestriction elem_restr;
1748d713cf6Sjeremylt   uint64_t state;
175885ac19cSjeremylt 
176d1d35e2fSjeremylt   for (CeedInt i=0; i<num_input_fields; i++) {
177d1bcdac9Sjeremylt     // Get input vector
178d1d35e2fSjeremylt     ierr = CeedOperatorFieldGetVector(op_input_fields[i], &vec);
179d1d35e2fSjeremylt     CeedChkBackend(ierr);
1801d102b48SJeremy L Thompson     if (vec == CEED_VECTOR_ACTIVE) {
181d1d35e2fSjeremylt       if (skip_active)
1821d102b48SJeremy L Thompson         continue;
1831d102b48SJeremy L Thompson       else
184d1d35e2fSjeremylt         vec = in_vec;
1851d102b48SJeremy L Thompson     }
1861d102b48SJeremy L Thompson 
187d1d35e2fSjeremylt     ierr = CeedQFunctionFieldGetEvalMode(qf_input_fields[i], &eval_mode);
188e15f9bd0SJeremy L Thompson     CeedChkBackend(ierr);
1891d102b48SJeremy L Thompson     // Restrict and Evec
190d1d35e2fSjeremylt     if (eval_mode == CEED_EVAL_WEIGHT) { // Skip
1911d102b48SJeremy L Thompson     } else {
192668048e2SJed Brown       // Restrict
193e15f9bd0SJeremy L Thompson       ierr = CeedVectorGetState(vec, &state); CeedChkBackend(ierr);
1948d713cf6Sjeremylt       // Skip restriction if input is unchanged
1954fc1f125SJeremy L Thompson       if (state != impl->input_states[i] || vec == in_vec) {
196d1d35e2fSjeremylt         ierr = CeedOperatorFieldGetElemRestriction(op_input_fields[i], &elem_restr);
197e15f9bd0SJeremy L Thompson         CeedChkBackend(ierr);
198d1d35e2fSjeremylt         ierr = CeedElemRestrictionApply(elem_restr, CEED_NOTRANSPOSE, vec,
1994fc1f125SJeremy L Thompson                                         impl->e_vecs_full[i], request);
2004fc1f125SJeremy L Thompson         CeedChkBackend(ierr);
2014fc1f125SJeremy L Thompson         impl->input_states[i] = state;
2028d713cf6Sjeremylt       }
203668048e2SJed Brown       // Get evec
2044fc1f125SJeremy L Thompson       ierr = CeedVectorGetArrayRead(impl->e_vecs_full[i], CEED_MEM_HOST,
2054fc1f125SJeremy L Thompson                                     (const CeedScalar **) &e_data_full[i]);
206e15f9bd0SJeremy L Thompson       CeedChkBackend(ierr);
207885ac19cSjeremylt     }
208885ac19cSjeremylt   }
209e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
210885ac19cSjeremylt }
211885ac19cSjeremylt 
212f10650afSjeremylt //------------------------------------------------------------------------------
213f10650afSjeremylt // Input Basis Action
214f10650afSjeremylt //------------------------------------------------------------------------------
2151d102b48SJeremy L Thompson static inline int CeedOperatorInputBasis_Ref(CeedInt e, CeedInt Q,
216d1d35e2fSjeremylt     CeedQFunctionField *qf_input_fields, CeedOperatorField *op_input_fields,
217a0162de9SJeremy L Thompson     CeedInt num_input_fields, const bool skip_active,
2184fc1f125SJeremy L Thompson     CeedScalar *e_data_full[2*CEED_FIELD_MAX], CeedOperator_Ref *impl) {
2191d102b48SJeremy L Thompson   CeedInt ierr;
220d1d35e2fSjeremylt   CeedInt dim, elem_size, size;
221d1d35e2fSjeremylt   CeedElemRestriction elem_restr;
222d1d35e2fSjeremylt   CeedEvalMode eval_mode;
2231d102b48SJeremy L Thompson   CeedBasis basis;
2241d102b48SJeremy L Thompson 
225d1d35e2fSjeremylt   for (CeedInt i=0; i<num_input_fields; i++) {
2261d102b48SJeremy L Thompson     // Skip active input
227d1d35e2fSjeremylt     if (skip_active) {
2281d102b48SJeremy L Thompson       CeedVector vec;
229d1d35e2fSjeremylt       ierr = CeedOperatorFieldGetVector(op_input_fields[i], &vec);
230d1d35e2fSjeremylt       CeedChkBackend(ierr);
2311d102b48SJeremy L Thompson       if (vec == CEED_VECTOR_ACTIVE)
2321d102b48SJeremy L Thompson         continue;
2331d102b48SJeremy L Thompson     }
234d1d35e2fSjeremylt     // Get elem_size, eval_mode, size
235d1d35e2fSjeremylt     ierr = CeedOperatorFieldGetElemRestriction(op_input_fields[i], &elem_restr);
236e15f9bd0SJeremy L Thompson     CeedChkBackend(ierr);
237d1d35e2fSjeremylt     ierr = CeedElemRestrictionGetElementSize(elem_restr, &elem_size);
238e15f9bd0SJeremy L Thompson     CeedChkBackend(ierr);
239d1d35e2fSjeremylt     ierr = CeedQFunctionFieldGetEvalMode(qf_input_fields[i], &eval_mode);
240e15f9bd0SJeremy L Thompson     CeedChkBackend(ierr);
241d1d35e2fSjeremylt     ierr = CeedQFunctionFieldGetSize(qf_input_fields[i], &size);
242d1d35e2fSjeremylt     CeedChkBackend(ierr);
243885ac19cSjeremylt     // Basis action
244d1d35e2fSjeremylt     switch(eval_mode) {
245885ac19cSjeremylt     case CEED_EVAL_NONE:
246d1d35e2fSjeremylt       ierr = CeedVectorSetArray(impl->q_vecs_in[i], CEED_MEM_HOST,
2474fc1f125SJeremy L Thompson                                 CEED_USE_POINTER, &e_data_full[i][e*Q*size]);
248d1d35e2fSjeremylt       CeedChkBackend(ierr);
249885ac19cSjeremylt       break;
250885ac19cSjeremylt     case CEED_EVAL_INTERP:
251d1d35e2fSjeremylt       ierr = CeedOperatorFieldGetBasis(op_input_fields[i], &basis);
252e15f9bd0SJeremy L Thompson       CeedChkBackend(ierr);
253d1d35e2fSjeremylt       ierr = CeedVectorSetArray(impl->e_vecs_in[i], CEED_MEM_HOST,
2544fc1f125SJeremy L Thompson                                 CEED_USE_POINTER, &e_data_full[i][e*elem_size*size]);
255e15f9bd0SJeremy L Thompson       CeedChkBackend(ierr);
256d1d35e2fSjeremylt       ierr = CeedBasisApply(basis, 1, CEED_NOTRANSPOSE, CEED_EVAL_INTERP,
257d1d35e2fSjeremylt                             impl->e_vecs_in[i], impl->q_vecs_in[i]); CeedChkBackend(ierr);
258885ac19cSjeremylt       break;
259885ac19cSjeremylt     case CEED_EVAL_GRAD:
260d1d35e2fSjeremylt       ierr = CeedOperatorFieldGetBasis(op_input_fields[i], &basis);
261e15f9bd0SJeremy L Thompson       CeedChkBackend(ierr);
262e15f9bd0SJeremy L Thompson       ierr = CeedBasisGetDimension(basis, &dim); CeedChkBackend(ierr);
263d1d35e2fSjeremylt       ierr = CeedVectorSetArray(impl->e_vecs_in[i], CEED_MEM_HOST,
2644fc1f125SJeremy L Thompson                                 CEED_USE_POINTER, &e_data_full[i][e*elem_size*size/dim]);
265e15f9bd0SJeremy L Thompson       CeedChkBackend(ierr);
266d1bcdac9Sjeremylt       ierr = CeedBasisApply(basis, 1, CEED_NOTRANSPOSE,
267d1d35e2fSjeremylt                             CEED_EVAL_GRAD, impl->e_vecs_in[i],
268d1d35e2fSjeremylt                             impl->q_vecs_in[i]); CeedChkBackend(ierr);
269885ac19cSjeremylt       break;
270885ac19cSjeremylt     case CEED_EVAL_WEIGHT:
271885ac19cSjeremylt       break;  // No action
272bbfacfcdSjeremylt     // LCOV_EXCL_START
273885ac19cSjeremylt     case CEED_EVAL_DIV:
2741d102b48SJeremy L Thompson     case CEED_EVAL_CURL: {
275d1d35e2fSjeremylt       ierr = CeedOperatorFieldGetBasis(op_input_fields[i], &basis);
276e15f9bd0SJeremy L Thompson       CeedChkBackend(ierr);
2771d102b48SJeremy L Thompson       Ceed ceed;
278e15f9bd0SJeremy L Thompson       ierr = CeedBasisGetCeed(basis, &ceed); CeedChkBackend(ierr);
279e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_BACKEND,
280e15f9bd0SJeremy L Thompson                        "Ceed evaluation mode not implemented");
281bbfacfcdSjeremylt       // LCOV_EXCL_STOP
282885ac19cSjeremylt     }
283885ac19cSjeremylt     }
284885ac19cSjeremylt   }
285e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
286885ac19cSjeremylt }
287885ac19cSjeremylt 
288f10650afSjeremylt //------------------------------------------------------------------------------
289f10650afSjeremylt // Output Basis Action
290f10650afSjeremylt //------------------------------------------------------------------------------
2911d102b48SJeremy L Thompson static inline int CeedOperatorOutputBasis_Ref(CeedInt e, CeedInt Q,
292d1d35e2fSjeremylt     CeedQFunctionField *qf_output_fields, CeedOperatorField *op_output_fields,
293d1d35e2fSjeremylt     CeedInt num_input_fields, CeedInt num_output_fields, CeedOperator op,
2944fc1f125SJeremy L Thompson     CeedScalar *e_data_full[2*CEED_FIELD_MAX], CeedOperator_Ref *impl) {
2951d102b48SJeremy L Thompson   CeedInt ierr;
296d1d35e2fSjeremylt   CeedInt dim, elem_size, size;
297d1d35e2fSjeremylt   CeedElemRestriction elem_restr;
298d1d35e2fSjeremylt   CeedEvalMode eval_mode;
2991d102b48SJeremy L Thompson   CeedBasis basis;
3001d102b48SJeremy L Thompson 
301d1d35e2fSjeremylt   for (CeedInt i=0; i<num_output_fields; i++) {
302d1d35e2fSjeremylt     // Get elem_size, eval_mode, size
303d1d35e2fSjeremylt     ierr = CeedOperatorFieldGetElemRestriction(op_output_fields[i], &elem_restr);
304e15f9bd0SJeremy L Thompson     CeedChkBackend(ierr);
305d1d35e2fSjeremylt     ierr = CeedElemRestrictionGetElementSize(elem_restr, &elem_size);
306e15f9bd0SJeremy L Thompson     CeedChkBackend(ierr);
307d1d35e2fSjeremylt     ierr = CeedQFunctionFieldGetEvalMode(qf_output_fields[i], &eval_mode);
308e15f9bd0SJeremy L Thompson     CeedChkBackend(ierr);
309d1d35e2fSjeremylt     ierr = CeedQFunctionFieldGetSize(qf_output_fields[i], &size);
310e15f9bd0SJeremy L Thompson     CeedChkBackend(ierr);
311885ac19cSjeremylt     // Basis action
312d1d35e2fSjeremylt     switch(eval_mode) {
313885ac19cSjeremylt     case CEED_EVAL_NONE:
314885ac19cSjeremylt       break; // No action
315885ac19cSjeremylt     case CEED_EVAL_INTERP:
316d1d35e2fSjeremylt       ierr = CeedOperatorFieldGetBasis(op_output_fields[i], &basis);
317e15f9bd0SJeremy L Thompson       CeedChkBackend(ierr);
318d1d35e2fSjeremylt       ierr = CeedVectorSetArray(impl->e_vecs_out[i], CEED_MEM_HOST,
319aedaa0e5Sjeremylt                                 CEED_USE_POINTER,
3204fc1f125SJeremy L Thompson                                 &e_data_full[i + num_input_fields][e*elem_size*size]);
321e15f9bd0SJeremy L Thompson       CeedChkBackend(ierr);
322aedaa0e5Sjeremylt       ierr = CeedBasisApply(basis, 1, CEED_TRANSPOSE,
323d1d35e2fSjeremylt                             CEED_EVAL_INTERP, impl->q_vecs_out[i],
324d1d35e2fSjeremylt                             impl->e_vecs_out[i]); CeedChkBackend(ierr);
325885ac19cSjeremylt       break;
326885ac19cSjeremylt     case CEED_EVAL_GRAD:
327d1d35e2fSjeremylt       ierr = CeedOperatorFieldGetBasis(op_output_fields[i], &basis);
328e15f9bd0SJeremy L Thompson       CeedChkBackend(ierr);
329e15f9bd0SJeremy L Thompson       ierr = CeedBasisGetDimension(basis, &dim); CeedChkBackend(ierr);
330d1d35e2fSjeremylt       ierr = CeedVectorSetArray(impl->e_vecs_out[i], CEED_MEM_HOST,
331aedaa0e5Sjeremylt                                 CEED_USE_POINTER,
3324fc1f125SJeremy L Thompson                                 &e_data_full[i + num_input_fields][e*elem_size*size/dim]);
333e15f9bd0SJeremy L Thompson       CeedChkBackend(ierr);
334aedaa0e5Sjeremylt       ierr = CeedBasisApply(basis, 1, CEED_TRANSPOSE,
335d1d35e2fSjeremylt                             CEED_EVAL_GRAD, impl->q_vecs_out[i],
336d1d35e2fSjeremylt                             impl->e_vecs_out[i]); CeedChkBackend(ierr);
337885ac19cSjeremylt       break;
338c042f62fSJeremy L Thompson     // LCOV_EXCL_START
339bbfacfcdSjeremylt     case CEED_EVAL_WEIGHT: {
3404ce2993fSjeremylt       Ceed ceed;
341e15f9bd0SJeremy L Thompson       ierr = CeedOperatorGetCeed(op, &ceed); CeedChkBackend(ierr);
342e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_BACKEND,
343e15f9bd0SJeremy L Thompson                        "CEED_EVAL_WEIGHT cannot be an output "
3441d102b48SJeremy L Thompson                        "evaluation mode");
3454ce2993fSjeremylt     }
346885ac19cSjeremylt     case CEED_EVAL_DIV:
3471d102b48SJeremy L Thompson     case CEED_EVAL_CURL: {
3481d102b48SJeremy L Thompson       Ceed ceed;
349e15f9bd0SJeremy L Thompson       ierr = CeedOperatorGetCeed(op, &ceed); CeedChkBackend(ierr);
350e15f9bd0SJeremy L Thompson       return CeedError(ceed, CEED_ERROR_BACKEND,
351e15f9bd0SJeremy L Thompson                        "Ceed evaluation mode not implemented");
3521d102b48SJeremy L Thompson       // LCOV_EXCL_STOP
353885ac19cSjeremylt     }
354885ac19cSjeremylt     }
355885ac19cSjeremylt   }
356e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
3571d102b48SJeremy L Thompson }
3581d102b48SJeremy L Thompson 
359f10650afSjeremylt //------------------------------------------------------------------------------
360f10650afSjeremylt // Restore Input Vectors
361f10650afSjeremylt //------------------------------------------------------------------------------
362d1d35e2fSjeremylt static inline int CeedOperatorRestoreInputs_Ref(CeedInt num_input_fields,
363d1d35e2fSjeremylt     CeedQFunctionField *qf_input_fields, CeedOperatorField *op_input_fields,
3644fc1f125SJeremy L Thompson     const bool skip_active, CeedScalar *e_data_full[2*CEED_FIELD_MAX],
365a0162de9SJeremy L Thompson     CeedOperator_Ref *impl) {
3661d102b48SJeremy L Thompson   CeedInt ierr;
367d1d35e2fSjeremylt   CeedEvalMode eval_mode;
3681d102b48SJeremy L Thompson 
369d1d35e2fSjeremylt   for (CeedInt i=0; i<num_input_fields; i++) {
3701d102b48SJeremy L Thompson     // Skip active inputs
371d1d35e2fSjeremylt     if (skip_active) {
3721d102b48SJeremy L Thompson       CeedVector vec;
373d1d35e2fSjeremylt       ierr = CeedOperatorFieldGetVector(op_input_fields[i], &vec);
374d1d35e2fSjeremylt       CeedChkBackend(ierr);
3751d102b48SJeremy L Thompson       if (vec == CEED_VECTOR_ACTIVE)
3761d102b48SJeremy L Thompson         continue;
3771d102b48SJeremy L Thompson     }
3781d102b48SJeremy L Thompson     // Restore input
379d1d35e2fSjeremylt     ierr = CeedQFunctionFieldGetEvalMode(qf_input_fields[i], &eval_mode);
380e15f9bd0SJeremy L Thompson     CeedChkBackend(ierr);
381d1d35e2fSjeremylt     if (eval_mode == CEED_EVAL_WEIGHT) { // Skip
3821d102b48SJeremy L Thompson     } else {
3834fc1f125SJeremy L Thompson       ierr = CeedVectorRestoreArrayRead(impl->e_vecs_full[i],
3844fc1f125SJeremy L Thompson                                         (const CeedScalar **) &e_data_full[i]);
385e15f9bd0SJeremy L Thompson       CeedChkBackend(ierr);
3861d102b48SJeremy L Thompson     }
3871d102b48SJeremy L Thompson   }
388e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
3891d102b48SJeremy L Thompson }
3901d102b48SJeremy L Thompson 
391f10650afSjeremylt //------------------------------------------------------------------------------
392f10650afSjeremylt // Operator Apply
393f10650afSjeremylt //------------------------------------------------------------------------------
394d1d35e2fSjeremylt static int CeedOperatorApplyAdd_Ref(CeedOperator op, CeedVector in_vec,
395d1d35e2fSjeremylt                                     CeedVector out_vec, CeedRequest *request) {
3961d102b48SJeremy L Thompson   int ierr;
3971d102b48SJeremy L Thompson   CeedOperator_Ref *impl;
398e15f9bd0SJeremy L Thompson   ierr = CeedOperatorGetData(op, &impl); CeedChkBackend(ierr);
3991d102b48SJeremy L Thompson   CeedQFunction qf;
400e15f9bd0SJeremy L Thompson   ierr = CeedOperatorGetQFunction(op, &qf); CeedChkBackend(ierr);
401d1d35e2fSjeremylt   CeedInt Q, num_elem, num_input_fields, num_output_fields, size;
402e15f9bd0SJeremy L Thompson   ierr = CeedOperatorGetNumQuadraturePoints(op, &Q); CeedChkBackend(ierr);
403d1d35e2fSjeremylt   ierr = CeedOperatorGetNumElements(op, &num_elem); CeedChkBackend(ierr);
404d1d35e2fSjeremylt   CeedOperatorField *op_input_fields, *op_output_fields;
4057e7773b5SJeremy L Thompson   ierr = CeedOperatorGetFields(op, &num_input_fields, &op_input_fields,
4067e7773b5SJeremy L Thompson                                &num_output_fields, &op_output_fields);
407e15f9bd0SJeremy L Thompson   CeedChkBackend(ierr);
408d1d35e2fSjeremylt   CeedQFunctionField *qf_input_fields, *qf_output_fields;
4097e7773b5SJeremy L Thompson   ierr = CeedQFunctionGetFields(qf, NULL, &qf_input_fields, NULL,
4107e7773b5SJeremy L Thompson                                 &qf_output_fields);
411e15f9bd0SJeremy L Thompson   CeedChkBackend(ierr);
412d1d35e2fSjeremylt   CeedEvalMode eval_mode;
4131d102b48SJeremy L Thompson   CeedVector vec;
414d1d35e2fSjeremylt   CeedElemRestriction elem_restr;
4154fc1f125SJeremy L Thompson   CeedScalar *e_data_full[2*CEED_FIELD_MAX] = {0};
4161d102b48SJeremy L Thompson 
4171d102b48SJeremy L Thompson   // Setup
418e15f9bd0SJeremy L Thompson   ierr = CeedOperatorSetup_Ref(op); CeedChkBackend(ierr);
4191d102b48SJeremy L Thompson 
4200b454692Sjeremylt   // Restriction only operator
4210b454692Sjeremylt   if (impl->is_identity_restr_op) {
4220b454692Sjeremylt     ierr = CeedOperatorFieldGetElemRestriction(op_input_fields[0], &elem_restr);
4230b454692Sjeremylt     CeedChkBackend(ierr);
4240b454692Sjeremylt     ierr = CeedElemRestrictionApply(elem_restr, CEED_NOTRANSPOSE, in_vec,
4254fc1f125SJeremy L Thompson                                     impl->e_vecs_full[0], request);
4264fc1f125SJeremy L Thompson     CeedChkBackend(ierr);
4270b454692Sjeremylt     ierr = CeedOperatorFieldGetElemRestriction(op_output_fields[0], &elem_restr);
4280b454692Sjeremylt     CeedChkBackend(ierr);
4294fc1f125SJeremy L Thompson     ierr = CeedElemRestrictionApply(elem_restr, CEED_TRANSPOSE,
4304fc1f125SJeremy L Thompson                                     impl->e_vecs_full[0],
4310b454692Sjeremylt                                     out_vec, request); CeedChkBackend(ierr);
4320b454692Sjeremylt     return CEED_ERROR_SUCCESS;
4330b454692Sjeremylt   }
4340b454692Sjeremylt 
4351d102b48SJeremy L Thompson   // Input Evecs and Restriction
436d1d35e2fSjeremylt   ierr = CeedOperatorSetupInputs_Ref(num_input_fields, qf_input_fields,
4374fc1f125SJeremy L Thompson                                      op_input_fields, in_vec, false, e_data_full, impl,
438e15f9bd0SJeremy L Thompson                                      request); CeedChkBackend(ierr);
4391d102b48SJeremy L Thompson 
4401d102b48SJeremy L Thompson   // Output Evecs
441d1d35e2fSjeremylt   for (CeedInt i=0; i<num_output_fields; i++) {
4429c774eddSJeremy L Thompson     ierr = CeedVectorGetArrayWrite(impl->e_vecs_full[i+impl->num_inputs],
4439c774eddSJeremy L Thompson                                    CEED_MEM_HOST, &e_data_full[i + num_input_fields]);
4449c774eddSJeremy L Thompson     CeedChkBackend(ierr);
4451d102b48SJeremy L Thompson   }
4461d102b48SJeremy L Thompson 
4471d102b48SJeremy L Thompson   // Loop through elements
448d1d35e2fSjeremylt   for (CeedInt e=0; e<num_elem; e++) {
4491d102b48SJeremy L Thompson     // Output pointers
450d1d35e2fSjeremylt     for (CeedInt i=0; i<num_output_fields; i++) {
451d1d35e2fSjeremylt       ierr = CeedQFunctionFieldGetEvalMode(qf_output_fields[i], &eval_mode);
452e15f9bd0SJeremy L Thompson       CeedChkBackend(ierr);
453d1d35e2fSjeremylt       if (eval_mode == CEED_EVAL_NONE) {
454d1d35e2fSjeremylt         ierr = CeedQFunctionFieldGetSize(qf_output_fields[i], &size);
455e15f9bd0SJeremy L Thompson         CeedChkBackend(ierr);
456d1d35e2fSjeremylt         ierr = CeedVectorSetArray(impl->q_vecs_out[i], CEED_MEM_HOST,
4571d102b48SJeremy L Thompson                                   CEED_USE_POINTER,
4584fc1f125SJeremy L Thompson                                   &e_data_full[i + num_input_fields][e*Q*size]);
459e15f9bd0SJeremy L Thompson         CeedChkBackend(ierr);
4601d102b48SJeremy L Thompson       }
4611d102b48SJeremy L Thompson     }
4621d102b48SJeremy L Thompson 
46316911fdaSjeremylt     // Input basis apply
464d1d35e2fSjeremylt     ierr = CeedOperatorInputBasis_Ref(e, Q, qf_input_fields, op_input_fields,
4654fc1f125SJeremy L Thompson                                       num_input_fields, false, e_data_full, impl);
466e15f9bd0SJeremy L Thompson     CeedChkBackend(ierr);
46716911fdaSjeremylt 
4681d102b48SJeremy L Thompson     // Q function
4690b454692Sjeremylt     if (!impl->is_identity_qf) {
470d1d35e2fSjeremylt       ierr = CeedQFunctionApply(qf, Q, impl->q_vecs_in, impl->q_vecs_out);
471e15f9bd0SJeremy L Thompson       CeedChkBackend(ierr);
47216911fdaSjeremylt     }
4731d102b48SJeremy L Thompson 
4741d102b48SJeremy L Thompson     // Output basis apply
475d1d35e2fSjeremylt     ierr = CeedOperatorOutputBasis_Ref(e, Q, qf_output_fields, op_output_fields,
476a0162de9SJeremy L Thompson                                        num_input_fields, num_output_fields, op,
4774fc1f125SJeremy L Thompson                                        e_data_full, impl); CeedChkBackend(ierr);
4781d102b48SJeremy L Thompson   }
479885ac19cSjeremylt 
480885ac19cSjeremylt   // Output restriction
481d1d35e2fSjeremylt   for (CeedInt i=0; i<num_output_fields; i++) {
482d1d35e2fSjeremylt     // Restore Evec
4834fc1f125SJeremy L Thompson     ierr = CeedVectorRestoreArray(impl->e_vecs_full[i+impl->num_inputs],
4844fc1f125SJeremy L Thompson                                   &e_data_full[i + num_input_fields]);
485e15f9bd0SJeremy L Thompson     CeedChkBackend(ierr);
486d1bcdac9Sjeremylt     // Get output vector
487d1d35e2fSjeremylt     ierr = CeedOperatorFieldGetVector(op_output_fields[i], &vec);
488e15f9bd0SJeremy L Thompson     CeedChkBackend(ierr);
489668048e2SJed Brown     // Active
490d1bcdac9Sjeremylt     if (vec == CEED_VECTOR_ACTIVE)
491d1d35e2fSjeremylt       vec = out_vec;
4927ca8db16Sjeremylt     // Restrict
493d1d35e2fSjeremylt     ierr = CeedOperatorFieldGetElemRestriction(op_output_fields[i], &elem_restr);
494e15f9bd0SJeremy L Thompson     CeedChkBackend(ierr);
495d1d35e2fSjeremylt     ierr = CeedElemRestrictionApply(elem_restr, CEED_TRANSPOSE,
4964fc1f125SJeremy L Thompson                                     impl->e_vecs_full[i+impl->num_inputs],
4974fc1f125SJeremy L Thompson                                     vec, request); CeedChkBackend(ierr);
498885ac19cSjeremylt   }
499885ac19cSjeremylt 
5007ca8db16Sjeremylt   // Restore input arrays
501d1d35e2fSjeremylt   ierr = CeedOperatorRestoreInputs_Ref(num_input_fields, qf_input_fields,
5024fc1f125SJeremy L Thompson                                        op_input_fields, false, e_data_full, impl);
503e15f9bd0SJeremy L Thompson   CeedChkBackend(ierr);
5047ca8db16Sjeremylt 
505e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
50621617c04Sjeremylt }
50721617c04Sjeremylt 
508f10650afSjeremylt //------------------------------------------------------------------------------
50970a7ffb3SJeremy L Thompson // Core code for assembling linear QFunction
510f10650afSjeremylt //------------------------------------------------------------------------------
51170a7ffb3SJeremy L Thompson static inline int CeedOperatorLinearAssembleQFunctionCore_Ref(CeedOperator op,
51270a7ffb3SJeremy L Thompson     bool build_objects, CeedVector *assembled, CeedElemRestriction *rstr,
51370a7ffb3SJeremy L Thompson     CeedRequest *request) {
5141d102b48SJeremy L Thompson   int ierr;
5151d102b48SJeremy L Thompson   CeedOperator_Ref *impl;
516e15f9bd0SJeremy L Thompson   ierr = CeedOperatorGetData(op, &impl); CeedChkBackend(ierr);
5171d102b48SJeremy L Thompson   CeedQFunction qf;
518e15f9bd0SJeremy L Thompson   ierr = CeedOperatorGetQFunction(op, &qf); CeedChkBackend(ierr);
519d1d35e2fSjeremylt   CeedInt Q, num_elem, num_input_fields, num_output_fields, size;
520e15f9bd0SJeremy L Thompson   ierr = CeedOperatorGetNumQuadraturePoints(op, &Q); CeedChkBackend(ierr);
521d1d35e2fSjeremylt   ierr = CeedOperatorGetNumElements(op, &num_elem); CeedChkBackend(ierr);
522d1d35e2fSjeremylt   CeedOperatorField *op_input_fields, *op_output_fields;
5237e7773b5SJeremy L Thompson   ierr = CeedOperatorGetFields(op, &num_input_fields, &op_input_fields,
5247e7773b5SJeremy L Thompson                                &num_output_fields, &op_output_fields);
525e15f9bd0SJeremy L Thompson   CeedChkBackend(ierr);
526d1d35e2fSjeremylt   CeedQFunctionField *qf_input_fields, *qf_output_fields;
5277e7773b5SJeremy L Thompson   ierr = CeedQFunctionGetFields(qf, NULL, &qf_input_fields, NULL,
5287e7773b5SJeremy L Thompson                                 &qf_output_fields);
529e15f9bd0SJeremy L Thompson   CeedChkBackend(ierr);
5301d102b48SJeremy L Thompson   CeedVector vec;
5314fc1f125SJeremy L Thompson   CeedInt num_active_in = impl->num_active_in,
5324fc1f125SJeremy L Thompson           num_active_out = impl->num_active_out;
533bb219a0fSJeremy L Thompson   CeedVector *active_in = impl->qf_active_in;
5341d102b48SJeremy L Thompson   CeedScalar *a, *tmp;
535d1d35e2fSjeremylt   Ceed ceed, ceed_parent;
536e15f9bd0SJeremy L Thompson   ierr = CeedOperatorGetCeed(op, &ceed); CeedChkBackend(ierr);
537d1d35e2fSjeremylt   ierr = CeedGetOperatorFallbackParentCeed(ceed, &ceed_parent);
538e15f9bd0SJeremy L Thompson   CeedChkBackend(ierr);
539d1d35e2fSjeremylt   ceed_parent = ceed_parent ? ceed_parent : ceed;
5404fc1f125SJeremy L Thompson   CeedScalar *e_data_full[2*CEED_FIELD_MAX] = {0};
5411d102b48SJeremy L Thompson 
5421d102b48SJeremy L Thompson   // Setup
543e15f9bd0SJeremy L Thompson   ierr = CeedOperatorSetup_Ref(op); CeedChkBackend(ierr);
5441d102b48SJeremy L Thompson 
54516911fdaSjeremylt   // Check for identity
5460b454692Sjeremylt   if (impl->is_identity_qf)
54716911fdaSjeremylt     // LCOV_EXCL_START
548e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_BACKEND,
549e15f9bd0SJeremy L Thompson                      "Assembling identity QFunctions not supported");
55016911fdaSjeremylt   // LCOV_EXCL_STOP
55116911fdaSjeremylt 
5521d102b48SJeremy L Thompson   // Input Evecs and Restriction
553d1d35e2fSjeremylt   ierr = CeedOperatorSetupInputs_Ref(num_input_fields, qf_input_fields,
5544fc1f125SJeremy L Thompson                                      op_input_fields, NULL, true, e_data_full,
555a0162de9SJeremy L Thompson                                      impl, request); CeedChkBackend(ierr);
5561d102b48SJeremy L Thompson 
5571d102b48SJeremy L Thompson   // Count number of active input fields
558bb219a0fSJeremy L Thompson   if (!num_active_in) {
559d1d35e2fSjeremylt     for (CeedInt i=0; i<num_input_fields; i++) {
5601d102b48SJeremy L Thompson       // Get input vector
561d1d35e2fSjeremylt       ierr = CeedOperatorFieldGetVector(op_input_fields[i], &vec);
562d1d35e2fSjeremylt       CeedChkBackend(ierr);
5631d102b48SJeremy L Thompson       // Check if active input
5641d102b48SJeremy L Thompson       if (vec == CEED_VECTOR_ACTIVE) {
565d1d35e2fSjeremylt         ierr = CeedQFunctionFieldGetSize(qf_input_fields[i], &size);
566e15f9bd0SJeremy L Thompson         CeedChkBackend(ierr);
567d1d35e2fSjeremylt         ierr = CeedVectorSetValue(impl->q_vecs_in[i], 0.0); CeedChkBackend(ierr);
568d1d35e2fSjeremylt         ierr = CeedVectorGetArray(impl->q_vecs_in[i], CEED_MEM_HOST, &tmp);
569d1d35e2fSjeremylt         CeedChkBackend(ierr);
570d1d35e2fSjeremylt         ierr = CeedRealloc(num_active_in + size, &active_in); CeedChkBackend(ierr);
5711d102b48SJeremy L Thompson         for (CeedInt field=0; field<size; field++) {
572d1d35e2fSjeremylt           ierr = CeedVectorCreate(ceed, Q, &active_in[num_active_in+field]);
573e15f9bd0SJeremy L Thompson           CeedChkBackend(ierr);
574d1d35e2fSjeremylt           ierr = CeedVectorSetArray(active_in[num_active_in+field], CEED_MEM_HOST,
57542ea3801Sjeremylt                                     CEED_USE_POINTER, &tmp[field*Q]);
576e15f9bd0SJeremy L Thompson           CeedChkBackend(ierr);
5771d102b48SJeremy L Thompson         }
578d1d35e2fSjeremylt         num_active_in += size;
579d1d35e2fSjeremylt         ierr = CeedVectorRestoreArray(impl->q_vecs_in[i], &tmp); CeedChkBackend(ierr);
5801d102b48SJeremy L Thompson       }
5811d102b48SJeremy L Thompson     }
5824fc1f125SJeremy L Thompson     impl->num_active_in = num_active_in;
583bb219a0fSJeremy L Thompson     impl->qf_active_in = active_in;
584bb219a0fSJeremy L Thompson   }
5851d102b48SJeremy L Thompson 
5861d102b48SJeremy L Thompson   // Count number of active output fields
587bb219a0fSJeremy L Thompson   if (!num_active_out) {
588d1d35e2fSjeremylt     for (CeedInt i=0; i<num_output_fields; i++) {
5891d102b48SJeremy L Thompson       // Get output vector
590d1d35e2fSjeremylt       ierr = CeedOperatorFieldGetVector(op_output_fields[i], &vec);
591e15f9bd0SJeremy L Thompson       CeedChkBackend(ierr);
5921d102b48SJeremy L Thompson       // Check if active output
5931d102b48SJeremy L Thompson       if (vec == CEED_VECTOR_ACTIVE) {
594d1d35e2fSjeremylt         ierr = CeedQFunctionFieldGetSize(qf_output_fields[i], &size);
595e15f9bd0SJeremy L Thompson         CeedChkBackend(ierr);
596d1d35e2fSjeremylt         num_active_out += size;
5971d102b48SJeremy L Thompson       }
5981d102b48SJeremy L Thompson     }
5994fc1f125SJeremy L Thompson     impl->num_active_out = num_active_out;
600bb219a0fSJeremy L Thompson   }
6011d102b48SJeremy L Thompson 
6021d102b48SJeremy L Thompson   // Check sizes
603d1d35e2fSjeremylt   if (!num_active_in || !num_active_out)
604138d4072Sjeremylt     // LCOV_EXCL_START
605e15f9bd0SJeremy L Thompson     return CeedError(ceed, CEED_ERROR_BACKEND,
606e15f9bd0SJeremy L Thompson                      "Cannot assemble QFunction without active inputs "
607138d4072Sjeremylt                      "and outputs");
608138d4072Sjeremylt   // LCOV_EXCL_STOP
6091d102b48SJeremy L Thompson 
61070a7ffb3SJeremy L Thompson   // Build objects if needed
61170a7ffb3SJeremy L Thompson   if (build_objects) {
6121d102b48SJeremy L Thompson     // Create output restriction
613d1d35e2fSjeremylt     CeedInt strides[3] = {1, Q, num_active_in*num_active_out*Q}; /* *NOPAD* */
614d1d35e2fSjeremylt     ierr = CeedElemRestrictionCreateStrided(ceed_parent, num_elem, Q,
615d1d35e2fSjeremylt                                             num_active_in*num_active_out,
616d1d35e2fSjeremylt                                             num_active_in*num_active_out*num_elem*Q,
617e15f9bd0SJeremy L Thompson                                             strides, rstr); CeedChkBackend(ierr);
6181d102b48SJeremy L Thompson     // Create assembled vector
619d1d35e2fSjeremylt     ierr = CeedVectorCreate(ceed_parent, num_elem*Q*num_active_in*num_active_out,
620e15f9bd0SJeremy L Thompson                             assembled); CeedChkBackend(ierr);
62170a7ffb3SJeremy L Thompson   }
62270a7ffb3SJeremy L Thompson   // Clear output vector
623e15f9bd0SJeremy L Thompson   ierr = CeedVectorSetValue(*assembled, 0.0); CeedChkBackend(ierr);
624e15f9bd0SJeremy L Thompson   ierr = CeedVectorGetArray(*assembled, CEED_MEM_HOST, &a); CeedChkBackend(ierr);
6251d102b48SJeremy L Thompson 
6261d102b48SJeremy L Thompson   // Loop through elements
627d1d35e2fSjeremylt   for (CeedInt e=0; e<num_elem; e++) {
6281d102b48SJeremy L Thompson     // Input basis apply
629d1d35e2fSjeremylt     ierr = CeedOperatorInputBasis_Ref(e, Q, qf_input_fields, op_input_fields,
6304fc1f125SJeremy L Thompson                                       num_input_fields, true, e_data_full, impl);
631e15f9bd0SJeremy L Thompson     CeedChkBackend(ierr);
6321d102b48SJeremy L Thompson 
6331d102b48SJeremy L Thompson     // Assemble QFunction
634d1d35e2fSjeremylt     for (CeedInt in=0; in<num_active_in; in++) {
6351d102b48SJeremy L Thompson       // Set Inputs
636d1d35e2fSjeremylt       ierr = CeedVectorSetValue(active_in[in], 1.0); CeedChkBackend(ierr);
637d1d35e2fSjeremylt       if (num_active_in > 1) {
638d1d35e2fSjeremylt         ierr = CeedVectorSetValue(active_in[(in+num_active_in-1)%num_active_in],
639e15f9bd0SJeremy L Thompson                                   0.0); CeedChkBackend(ierr);
64042ea3801Sjeremylt       }
6411d102b48SJeremy L Thompson       // Set Outputs
642d1d35e2fSjeremylt       for (CeedInt out=0; out<num_output_fields; out++) {
6431d102b48SJeremy L Thompson         // Get output vector
644d1d35e2fSjeremylt         ierr = CeedOperatorFieldGetVector(op_output_fields[out], &vec);
645e15f9bd0SJeremy L Thompson         CeedChkBackend(ierr);
6461d102b48SJeremy L Thompson         // Check if active output
6471d102b48SJeremy L Thompson         if (vec == CEED_VECTOR_ACTIVE) {
648d1d35e2fSjeremylt           CeedVectorSetArray(impl->q_vecs_out[out], CEED_MEM_HOST,
649e15f9bd0SJeremy L Thompson                              CEED_USE_POINTER, a); CeedChkBackend(ierr);
650d1d35e2fSjeremylt           ierr = CeedQFunctionFieldGetSize(qf_output_fields[out], &size);
651e15f9bd0SJeremy L Thompson           CeedChkBackend(ierr);
6521d102b48SJeremy L Thompson           a += size*Q; // Advance the pointer by the size of the output
6531d102b48SJeremy L Thompson         }
6541d102b48SJeremy L Thompson       }
6551d102b48SJeremy L Thompson       // Apply QFunction
656d1d35e2fSjeremylt       ierr = CeedQFunctionApply(qf, Q, impl->q_vecs_in, impl->q_vecs_out);
657e15f9bd0SJeremy L Thompson       CeedChkBackend(ierr);
6581d102b48SJeremy L Thompson     }
6591d102b48SJeremy L Thompson   }
6601d102b48SJeremy L Thompson 
6611d102b48SJeremy L Thompson   // Un-set output Qvecs to prevent accidental overwrite of Assembled
662d1d35e2fSjeremylt   for (CeedInt out=0; out<num_output_fields; out++) {
6631d102b48SJeremy L Thompson     // Get output vector
664d1d35e2fSjeremylt     ierr = CeedOperatorFieldGetVector(op_output_fields[out], &vec);
665e15f9bd0SJeremy L Thompson     CeedChkBackend(ierr);
6661d102b48SJeremy L Thompson     // Check if active output
6671d102b48SJeremy L Thompson     if (vec == CEED_VECTOR_ACTIVE) {
668d1d35e2fSjeremylt       CeedVectorTakeArray(impl->q_vecs_out[out], CEED_MEM_HOST, NULL);
669e15f9bd0SJeremy L Thompson       CeedChkBackend(ierr);
6701d102b48SJeremy L Thompson     }
6711d102b48SJeremy L Thompson   }
6721d102b48SJeremy L Thompson 
6731d102b48SJeremy L Thompson   // Restore input arrays
674d1d35e2fSjeremylt   ierr = CeedOperatorRestoreInputs_Ref(num_input_fields, qf_input_fields,
6754fc1f125SJeremy L Thompson                                        op_input_fields, true, e_data_full, impl);
676e15f9bd0SJeremy L Thompson   CeedChkBackend(ierr);
6771d102b48SJeremy L Thompson 
6781d102b48SJeremy L Thompson   // Restore output
679e15f9bd0SJeremy L Thompson   ierr = CeedVectorRestoreArray(*assembled, &a); CeedChkBackend(ierr);
6801d102b48SJeremy L Thompson 
681e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6821d102b48SJeremy L Thompson }
6831d102b48SJeremy L Thompson 
684f10650afSjeremylt //------------------------------------------------------------------------------
68570a7ffb3SJeremy L Thompson // Assemble Linear QFunction
68670a7ffb3SJeremy L Thompson //------------------------------------------------------------------------------
68770a7ffb3SJeremy L Thompson static int CeedOperatorLinearAssembleQFunction_Ref(CeedOperator op,
68870a7ffb3SJeremy L Thompson     CeedVector *assembled, CeedElemRestriction *rstr, CeedRequest *request) {
68970a7ffb3SJeremy L Thompson   return CeedOperatorLinearAssembleQFunctionCore_Ref(op, true, assembled, rstr,
69070a7ffb3SJeremy L Thompson          request);
69170a7ffb3SJeremy L Thompson }
69270a7ffb3SJeremy L Thompson 
69370a7ffb3SJeremy L Thompson //------------------------------------------------------------------------------
69470a7ffb3SJeremy L Thompson // Update Assembled Linear QFunction
69570a7ffb3SJeremy L Thompson //------------------------------------------------------------------------------
69670a7ffb3SJeremy L Thompson static int CeedOperatorLinearAssembleQFunctionUpdate_Ref(CeedOperator op,
69770a7ffb3SJeremy L Thompson     CeedVector assembled, CeedElemRestriction rstr, CeedRequest *request) {
69870a7ffb3SJeremy L Thompson   return CeedOperatorLinearAssembleQFunctionCore_Ref(op, false, &assembled,
69970a7ffb3SJeremy L Thompson          &rstr, request);
70070a7ffb3SJeremy L Thompson }
70170a7ffb3SJeremy L Thompson 
70270a7ffb3SJeremy L Thompson //------------------------------------------------------------------------------
703f10650afSjeremylt // Operator Destroy
704f10650afSjeremylt //------------------------------------------------------------------------------
705f10650afSjeremylt static int CeedOperatorDestroy_Ref(CeedOperator op) {
706f10650afSjeremylt   int ierr;
707f10650afSjeremylt   CeedOperator_Ref *impl;
708e15f9bd0SJeremy L Thompson   ierr = CeedOperatorGetData(op, &impl); CeedChkBackend(ierr);
709f10650afSjeremylt 
7104fc1f125SJeremy L Thompson   for (CeedInt i=0; i<impl->num_inputs+impl->num_outputs; i++) {
7114fc1f125SJeremy L Thompson     ierr = CeedVectorDestroy(&impl->e_vecs_full[i]); CeedChkBackend(ierr);
712f10650afSjeremylt   }
7134fc1f125SJeremy L Thompson   ierr = CeedFree(&impl->e_vecs_full); CeedChkBackend(ierr);
7144fc1f125SJeremy L Thompson   ierr = CeedFree(&impl->input_states); CeedChkBackend(ierr);
715f10650afSjeremylt 
7164fc1f125SJeremy L Thompson   for (CeedInt i=0; i<impl->num_inputs; i++) {
717d1d35e2fSjeremylt     ierr = CeedVectorDestroy(&impl->e_vecs_in[i]); CeedChkBackend(ierr);
718d1d35e2fSjeremylt     ierr = CeedVectorDestroy(&impl->q_vecs_in[i]); CeedChkBackend(ierr);
719f10650afSjeremylt   }
720d1d35e2fSjeremylt   ierr = CeedFree(&impl->e_vecs_in); CeedChkBackend(ierr);
721d1d35e2fSjeremylt   ierr = CeedFree(&impl->q_vecs_in); CeedChkBackend(ierr);
722f10650afSjeremylt 
7234fc1f125SJeremy L Thompson   for (CeedInt i=0; i<impl->num_outputs; i++) {
724d1d35e2fSjeremylt     ierr = CeedVectorDestroy(&impl->e_vecs_out[i]); CeedChkBackend(ierr);
725d1d35e2fSjeremylt     ierr = CeedVectorDestroy(&impl->q_vecs_out[i]); CeedChkBackend(ierr);
726f10650afSjeremylt   }
727d1d35e2fSjeremylt   ierr = CeedFree(&impl->e_vecs_out); CeedChkBackend(ierr);
728d1d35e2fSjeremylt   ierr = CeedFree(&impl->q_vecs_out); CeedChkBackend(ierr);
729f10650afSjeremylt 
730bb219a0fSJeremy L Thompson   // QFunction assembly
7314fc1f125SJeremy L Thompson   for (CeedInt i=0; i<impl->num_active_in; i++) {
732bb219a0fSJeremy L Thompson     ierr = CeedVectorDestroy(&impl->qf_active_in[i]); CeedChkBackend(ierr);
733bb219a0fSJeremy L Thompson   }
734bb219a0fSJeremy L Thompson   ierr = CeedFree(&impl->qf_active_in); CeedChkBackend(ierr);
735bb219a0fSJeremy L Thompson 
736e15f9bd0SJeremy L Thompson   ierr = CeedFree(&impl); CeedChkBackend(ierr);
737e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
738f10650afSjeremylt }
739f10650afSjeremylt 
740f10650afSjeremylt //------------------------------------------------------------------------------
741713f43c3Sjeremylt // Operator Create
742f10650afSjeremylt //------------------------------------------------------------------------------
74321617c04Sjeremylt int CeedOperatorCreate_Ref(CeedOperator op) {
74421617c04Sjeremylt   int ierr;
745fe2413ffSjeremylt   Ceed ceed;
746e15f9bd0SJeremy L Thompson   ierr = CeedOperatorGetCeed(op, &ceed); CeedChkBackend(ierr);
7474ce2993fSjeremylt   CeedOperator_Ref *impl;
74821617c04Sjeremylt 
749e15f9bd0SJeremy L Thompson   ierr = CeedCalloc(1, &impl); CeedChkBackend(ierr);
750e15f9bd0SJeremy L Thompson   ierr = CeedOperatorSetData(op, impl); CeedChkBackend(ierr);
751fe2413ffSjeremylt 
75280ac2e43SJeremy L Thompson   ierr = CeedSetBackendFunction(ceed, "Operator", op, "LinearAssembleQFunction",
75380ac2e43SJeremy L Thompson                                 CeedOperatorLinearAssembleQFunction_Ref);
754e15f9bd0SJeremy L Thompson   CeedChkBackend(ierr);
75570a7ffb3SJeremy L Thompson   ierr = CeedSetBackendFunction(ceed, "Operator", op,
75670a7ffb3SJeremy L Thompson                                 "LinearAssembleQFunctionUpdate",
75770a7ffb3SJeremy L Thompson                                 CeedOperatorLinearAssembleQFunctionUpdate_Ref);
75870a7ffb3SJeremy L Thompson   CeedChkBackend(ierr);
759cae8b89aSjeremylt   ierr = CeedSetBackendFunction(ceed, "Operator", op, "ApplyAdd",
760e15f9bd0SJeremy L Thompson                                 CeedOperatorApplyAdd_Ref); CeedChkBackend(ierr);
761fe2413ffSjeremylt   ierr = CeedSetBackendFunction(ceed, "Operator", op, "Destroy",
762e15f9bd0SJeremy L Thompson                                 CeedOperatorDestroy_Ref); CeedChkBackend(ierr);
763e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
76421617c04Sjeremylt }
765