xref: /libCEED/backends/ref/ceed-ref-operator.c (revision de5bf46bcc909da70680c51facd7097145cfeaa6)
1d275d636SJeremy L Thompson // Copyright (c) 2017-2025, Lawrence Livermore National Security, LLC and other CEED contributors.
23d8e8822SJeremy L Thompson // All Rights Reserved. See the top-level LICENSE and NOTICE files for details.
321617c04Sjeremylt //
43d8e8822SJeremy L Thompson // SPDX-License-Identifier: BSD-2-Clause
521617c04Sjeremylt //
63d8e8822SJeremy L Thompson // This file is part of CEED:  http://github.com/ceed
721617c04Sjeremylt 
849aac155SJeremy L Thompson #include <ceed.h>
9ec3da8bcSJed Brown #include <ceed/backend.h>
103d576824SJeremy L Thompson #include <stdbool.h>
113d576824SJeremy L Thompson #include <stddef.h>
123d576824SJeremy L Thompson #include <stdint.h>
132b730f8bSJeremy L Thompson 
1421617c04Sjeremylt #include "ceed-ref.h"
1521617c04Sjeremylt 
16f10650afSjeremylt //------------------------------------------------------------------------------
17f10650afSjeremylt // Setup Input/Output Fields
18f10650afSjeremylt //------------------------------------------------------------------------------
19f8a0df59SJeremy L Thompson static int CeedOperatorSetupFields_Ref(CeedQFunction qf, CeedOperator op, bool is_input, bool *skip_rstr, CeedInt *e_data_out_indices,
20f8a0df59SJeremy L Thompson                                        bool *apply_add_basis, CeedVector *e_vecs_full, CeedVector *e_vecs, CeedVector *q_vecs, CeedInt start_e,
21f8a0df59SJeremy L Thompson                                        CeedInt num_fields, CeedInt Q) {
22aedaa0e5Sjeremylt   Ceed                ceed;
236efa0d72SZach Atkins   CeedSize            e_size, q_size;
24ad70ee2cSJeremy L Thompson   CeedInt             num_comp, size, P;
25d1d35e2fSjeremylt   CeedQFunctionField *qf_fields;
26ad70ee2cSJeremy L Thompson   CeedOperatorField  *op_fields;
27ad70ee2cSJeremy L Thompson 
28e910d748SJeremy L Thompson   {
29e910d748SJeremy L Thompson     Ceed ceed_parent;
30e910d748SJeremy L Thompson 
31ad70ee2cSJeremy L Thompson     CeedCallBackend(CeedOperatorGetCeed(op, &ceed));
32e910d748SJeremy L Thompson     CeedCallBackend(CeedGetParent(ceed, &ceed_parent));
339bc66399SJeremy L Thompson     CeedCallBackend(CeedReferenceCopy(ceed_parent, &ceed));
349bc66399SJeremy L Thompson     CeedCallBackend(CeedDestroy(&ceed_parent));
35e910d748SJeremy L Thompson   }
364fc1f125SJeremy L Thompson   if (is_input) {
372b730f8bSJeremy L Thompson     CeedCallBackend(CeedOperatorGetFields(op, NULL, &op_fields, NULL, NULL));
382b730f8bSJeremy L Thompson     CeedCallBackend(CeedQFunctionGetFields(qf, NULL, &qf_fields, NULL, NULL));
394fc1f125SJeremy L Thompson   } else {
402b730f8bSJeremy L Thompson     CeedCallBackend(CeedOperatorGetFields(op, NULL, NULL, NULL, &op_fields));
412b730f8bSJeremy L Thompson     CeedCallBackend(CeedQFunctionGetFields(qf, NULL, NULL, NULL, &qf_fields));
42fe2413ffSjeremylt   }
4321617c04Sjeremylt 
44885ac19cSjeremylt   // Loop over fields
45d1d35e2fSjeremylt   for (CeedInt i = 0; i < num_fields; i++) {
46d1d35e2fSjeremylt     CeedEvalMode        eval_mode;
47edb2538eSJeremy L Thompson     CeedElemRestriction elem_rstr;
48ad70ee2cSJeremy L Thompson     CeedBasis           basis;
49d1d35e2fSjeremylt 
50ad70ee2cSJeremy L Thompson     CeedCallBackend(CeedQFunctionFieldGetEvalMode(qf_fields[i], &eval_mode));
51d1d35e2fSjeremylt     if (eval_mode != CEED_EVAL_WEIGHT) {
52edb2538eSJeremy L Thompson       CeedCallBackend(CeedOperatorFieldGetElemRestriction(op_fields[i], &elem_rstr));
53edb2538eSJeremy L Thompson       CeedCallBackend(CeedElemRestrictionCreateVector(elem_rstr, NULL, &e_vecs_full[i + start_e]));
54681d0ea7SJeremy L Thompson       CeedCallBackend(CeedElemRestrictionDestroy(&elem_rstr));
55135a076eSjeremylt     }
56135a076eSjeremylt 
57d1d35e2fSjeremylt     switch (eval_mode) {
58885ac19cSjeremylt       case CEED_EVAL_NONE:
592b730f8bSJeremy L Thompson         CeedCallBackend(CeedQFunctionFieldGetSize(qf_fields[i], &size));
60d2643443SJeremy L Thompson         q_size = (CeedSize)Q * size;
612b730f8bSJeremy L Thompson         CeedCallBackend(CeedVectorCreate(ceed, q_size, &q_vecs[i]));
62aedaa0e5Sjeremylt         break;
63aedaa0e5Sjeremylt       case CEED_EVAL_INTERP:
64885ac19cSjeremylt       case CEED_EVAL_GRAD:
65a915a514Srezgarshakeri       case CEED_EVAL_DIV:
66c4e3f59bSSebastian Grimberg       case CEED_EVAL_CURL:
672b730f8bSJeremy L Thompson         CeedCallBackend(CeedOperatorFieldGetBasis(op_fields[i], &basis));
682b730f8bSJeremy L Thompson         CeedCallBackend(CeedQFunctionFieldGetSize(qf_fields[i], &size));
692b730f8bSJeremy L Thompson         CeedCallBackend(CeedBasisGetNumNodes(basis, &P));
702b730f8bSJeremy L Thompson         CeedCallBackend(CeedBasisGetNumComponents(basis, &num_comp));
71d2643443SJeremy L Thompson         e_size = (CeedSize)P * num_comp;
722b730f8bSJeremy L Thompson         CeedCallBackend(CeedVectorCreate(ceed, e_size, &e_vecs[i]));
73d2643443SJeremy L Thompson         q_size = (CeedSize)Q * size;
742b730f8bSJeremy L Thompson         CeedCallBackend(CeedVectorCreate(ceed, q_size, &q_vecs[i]));
75681d0ea7SJeremy L Thompson         CeedCallBackend(CeedBasisDestroy(&basis));
76885ac19cSjeremylt         break;
77885ac19cSjeremylt       case CEED_EVAL_WEIGHT:  // Only on input fields
782b730f8bSJeremy L Thompson         CeedCallBackend(CeedOperatorFieldGetBasis(op_fields[i], &basis));
79d2643443SJeremy L Thompson         q_size = (CeedSize)Q;
802b730f8bSJeremy L Thompson         CeedCallBackend(CeedVectorCreate(ceed, q_size, &q_vecs[i]));
812b730f8bSJeremy L Thompson         CeedCallBackend(CeedBasisApply(basis, 1, CEED_NOTRANSPOSE, CEED_EVAL_WEIGHT, CEED_VECTOR_NONE, q_vecs[i]));
82681d0ea7SJeremy L Thompson         CeedCallBackend(CeedBasisDestroy(&basis));
83885ac19cSjeremylt         break;
8421617c04Sjeremylt     }
85885ac19cSjeremylt   }
86f8a0df59SJeremy L Thompson   // Drop duplicate restrictions
873aab95c0SJeremy L Thompson   if (is_input) {
883aab95c0SJeremy L Thompson     for (CeedInt i = 0; i < num_fields; i++) {
893aab95c0SJeremy L Thompson       CeedVector          vec_i;
903aab95c0SJeremy L Thompson       CeedElemRestriction rstr_i;
913aab95c0SJeremy L Thompson 
923aab95c0SJeremy L Thompson       CeedCallBackend(CeedOperatorFieldGetVector(op_fields[i], &vec_i));
933aab95c0SJeremy L Thompson       CeedCallBackend(CeedOperatorFieldGetElemRestriction(op_fields[i], &rstr_i));
943aab95c0SJeremy L Thompson       for (CeedInt j = i + 1; j < num_fields; j++) {
953aab95c0SJeremy L Thompson         CeedVector          vec_j;
963aab95c0SJeremy L Thompson         CeedElemRestriction rstr_j;
973aab95c0SJeremy L Thompson 
983aab95c0SJeremy L Thompson         CeedCallBackend(CeedOperatorFieldGetVector(op_fields[j], &vec_j));
993aab95c0SJeremy L Thompson         CeedCallBackend(CeedOperatorFieldGetElemRestriction(op_fields[j], &rstr_j));
1003aab95c0SJeremy L Thompson         if (vec_i == vec_j && rstr_i == rstr_j) {
1013aab95c0SJeremy L Thompson           CeedCallBackend(CeedVectorReferenceCopy(e_vecs[i], &e_vecs[j]));
102f8a0df59SJeremy L Thompson           CeedCallBackend(CeedVectorReferenceCopy(e_vecs_full[i + start_e], &e_vecs_full[j + start_e]));
1033aab95c0SJeremy L Thompson           skip_rstr[j] = true;
1043aab95c0SJeremy L Thompson         }
105681d0ea7SJeremy L Thompson         CeedCallBackend(CeedVectorDestroy(&vec_j));
106681d0ea7SJeremy L Thompson         CeedCallBackend(CeedElemRestrictionDestroy(&rstr_j));
1073aab95c0SJeremy L Thompson       }
108681d0ea7SJeremy L Thompson       CeedCallBackend(CeedVectorDestroy(&vec_i));
109681d0ea7SJeremy L Thompson       CeedCallBackend(CeedElemRestrictionDestroy(&rstr_i));
1103aab95c0SJeremy L Thompson     }
111f8a0df59SJeremy L Thompson   } else {
112f8a0df59SJeremy L Thompson     for (CeedInt i = num_fields - 1; i >= 0; i--) {
113f8a0df59SJeremy L Thompson       CeedVector          vec_i;
114f8a0df59SJeremy L Thompson       CeedElemRestriction rstr_i;
115f8a0df59SJeremy L Thompson 
116f8a0df59SJeremy L Thompson       CeedCallBackend(CeedOperatorFieldGetVector(op_fields[i], &vec_i));
117f8a0df59SJeremy L Thompson       CeedCallBackend(CeedOperatorFieldGetElemRestriction(op_fields[i], &rstr_i));
118f8a0df59SJeremy L Thompson       for (CeedInt j = i - 1; j >= 0; j--) {
119f8a0df59SJeremy L Thompson         CeedVector          vec_j;
120f8a0df59SJeremy L Thompson         CeedElemRestriction rstr_j;
121f8a0df59SJeremy L Thompson 
122f8a0df59SJeremy L Thompson         CeedCallBackend(CeedOperatorFieldGetVector(op_fields[j], &vec_j));
123f8a0df59SJeremy L Thompson         CeedCallBackend(CeedOperatorFieldGetElemRestriction(op_fields[j], &rstr_j));
124f8a0df59SJeremy L Thompson         if (vec_i == vec_j && rstr_i == rstr_j) {
125f8a0df59SJeremy L Thompson           CeedCallBackend(CeedVectorReferenceCopy(e_vecs[i], &e_vecs[j]));
126f8a0df59SJeremy L Thompson           CeedCallBackend(CeedVectorReferenceCopy(e_vecs_full[i + start_e], &e_vecs_full[j + start_e]));
127f8a0df59SJeremy L Thompson           skip_rstr[j]          = true;
128f8a0df59SJeremy L Thompson           apply_add_basis[i]    = true;
129f8a0df59SJeremy L Thompson           e_data_out_indices[j] = i;
130f8a0df59SJeremy L Thompson         }
131681d0ea7SJeremy L Thompson         CeedCallBackend(CeedVectorDestroy(&vec_j));
132681d0ea7SJeremy L Thompson         CeedCallBackend(CeedElemRestrictionDestroy(&rstr_j));
133f8a0df59SJeremy L Thompson       }
134681d0ea7SJeremy L Thompson       CeedCallBackend(CeedVectorDestroy(&vec_i));
135681d0ea7SJeremy L Thompson       CeedCallBackend(CeedElemRestrictionDestroy(&rstr_i));
136f8a0df59SJeremy L Thompson     }
1373aab95c0SJeremy L Thompson   }
1389bc66399SJeremy L Thompson   CeedCallBackend(CeedDestroy(&ceed));
139e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
14021617c04Sjeremylt }
14121617c04Sjeremylt 
142f10650afSjeremylt //------------------------------------------------------------------------------
143f10650afSjeremylt // Setup Operator
144f10650afSjeremylt //------------------------------------------------------------------------------/*
145885ac19cSjeremylt static int CeedOperatorSetup_Ref(CeedOperator op) {
1468c1105f8SJeremy L Thompson   bool                is_setup_done;
147ad70ee2cSJeremy L Thompson   CeedInt             Q, num_input_fields, num_output_fields;
148ad70ee2cSJeremy L Thompson   CeedQFunctionField *qf_input_fields, *qf_output_fields;
149ad70ee2cSJeremy L Thompson   CeedQFunction       qf;
150ad70ee2cSJeremy L Thompson   CeedOperatorField  *op_input_fields, *op_output_fields;
151ad70ee2cSJeremy L Thompson   CeedOperator_Ref   *impl;
152ad70ee2cSJeremy L Thompson 
1532b730f8bSJeremy L Thompson   CeedCallBackend(CeedOperatorIsSetupDone(op, &is_setup_done));
1548c1105f8SJeremy L Thompson   if (is_setup_done) return CEED_ERROR_SUCCESS;
155ad70ee2cSJeremy L Thompson 
1562b730f8bSJeremy L Thompson   CeedCallBackend(CeedOperatorGetData(op, &impl));
1572b730f8bSJeremy L Thompson   CeedCallBackend(CeedOperatorGetQFunction(op, &qf));
1582b730f8bSJeremy L Thompson   CeedCallBackend(CeedOperatorGetNumQuadraturePoints(op, &Q));
1592b730f8bSJeremy L Thompson   CeedCallBackend(CeedQFunctionIsIdentity(qf, &impl->is_identity_qf));
1602b730f8bSJeremy L Thompson   CeedCallBackend(CeedOperatorGetFields(op, &num_input_fields, &op_input_fields, &num_output_fields, &op_output_fields));
1612b730f8bSJeremy L Thompson   CeedCallBackend(CeedQFunctionGetFields(qf, NULL, &qf_input_fields, NULL, &qf_output_fields));
162885ac19cSjeremylt 
163885ac19cSjeremylt   // Allocate
1642b730f8bSJeremy L Thompson   CeedCallBackend(CeedCalloc(num_input_fields + num_output_fields, &impl->e_vecs_full));
165885ac19cSjeremylt 
1663aab95c0SJeremy L Thompson   CeedCallBackend(CeedCalloc(CEED_FIELD_MAX, &impl->skip_rstr_in));
167f8a0df59SJeremy L Thompson   CeedCallBackend(CeedCalloc(CEED_FIELD_MAX, &impl->skip_rstr_out));
168f8a0df59SJeremy L Thompson   CeedCallBackend(CeedCalloc(CEED_FIELD_MAX, &impl->e_data_out_indices));
169f8a0df59SJeremy L Thompson   CeedCallBackend(CeedCalloc(CEED_FIELD_MAX, &impl->apply_add_basis_out));
1702b730f8bSJeremy L Thompson   CeedCallBackend(CeedCalloc(CEED_FIELD_MAX, &impl->input_states));
1712b730f8bSJeremy L Thompson   CeedCallBackend(CeedCalloc(CEED_FIELD_MAX, &impl->e_vecs_in));
1722b730f8bSJeremy L Thompson   CeedCallBackend(CeedCalloc(CEED_FIELD_MAX, &impl->e_vecs_out));
1732b730f8bSJeremy L Thompson   CeedCallBackend(CeedCalloc(CEED_FIELD_MAX, &impl->q_vecs_in));
1742b730f8bSJeremy L Thompson   CeedCallBackend(CeedCalloc(CEED_FIELD_MAX, &impl->q_vecs_out));
175885ac19cSjeremylt 
1764fc1f125SJeremy L Thompson   impl->num_inputs  = num_input_fields;
1774fc1f125SJeremy L Thompson   impl->num_outputs = num_output_fields;
178885ac19cSjeremylt 
179d1d35e2fSjeremylt   // Set up infield and outfield e_vecs and q_vecs
180885ac19cSjeremylt   // Infields
181f8a0df59SJeremy L Thompson   CeedCallBackend(CeedOperatorSetupFields_Ref(qf, op, true, impl->skip_rstr_in, NULL, NULL, impl->e_vecs_full, impl->e_vecs_in, impl->q_vecs_in, 0,
182f8a0df59SJeremy L Thompson                                               num_input_fields, Q));
1833aab95c0SJeremy L Thompson   // Outfields
184f8a0df59SJeremy L Thompson   CeedCallBackend(CeedOperatorSetupFields_Ref(qf, op, false, impl->skip_rstr_out, impl->e_data_out_indices, impl->apply_add_basis_out,
185f8a0df59SJeremy L Thompson                                               impl->e_vecs_full, impl->e_vecs_out, impl->q_vecs_out, num_input_fields, num_output_fields, Q));
186885ac19cSjeremylt 
18716911fdaSjeremylt   // Identity QFunctions
1880b454692Sjeremylt   if (impl->is_identity_qf) {
189d1d35e2fSjeremylt     CeedEvalMode        in_mode, out_mode;
190d1d35e2fSjeremylt     CeedQFunctionField *in_fields, *out_fields;
191ad70ee2cSJeremy L Thompson 
1922b730f8bSJeremy L Thompson     CeedCallBackend(CeedQFunctionGetFields(qf, NULL, &in_fields, NULL, &out_fields));
1932b730f8bSJeremy L Thompson     CeedCallBackend(CeedQFunctionFieldGetEvalMode(in_fields[0], &in_mode));
1942b730f8bSJeremy L Thompson     CeedCallBackend(CeedQFunctionFieldGetEvalMode(out_fields[0], &out_mode));
195d1d35e2fSjeremylt 
1960b454692Sjeremylt     if (in_mode == CEED_EVAL_NONE && out_mode == CEED_EVAL_NONE) {
197edb2538eSJeremy L Thompson       impl->is_identity_rstr_op = true;
1980b454692Sjeremylt     } else {
199db002c03SJeremy L Thompson       CeedCallBackend(CeedVectorReferenceCopy(impl->q_vecs_in[0], &impl->q_vecs_out[0]));
20016911fdaSjeremylt     }
20116911fdaSjeremylt   }
20216911fdaSjeremylt 
2032b730f8bSJeremy L Thompson   CeedCallBackend(CeedOperatorSetSetupDone(op));
204c11e12f4SJeremy L Thompson   CeedCallBackend(CeedQFunctionDestroy(&qf));
205e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
206885ac19cSjeremylt }
207885ac19cSjeremylt 
208f10650afSjeremylt //------------------------------------------------------------------------------
209f10650afSjeremylt // Setup Operator Inputs
210f10650afSjeremylt //------------------------------------------------------------------------------
2112b730f8bSJeremy L Thompson static inline int CeedOperatorSetupInputs_Ref(CeedInt num_input_fields, CeedQFunctionField *qf_input_fields, CeedOperatorField *op_input_fields,
2122b730f8bSJeremy L Thompson                                               CeedVector in_vec, const bool skip_active, CeedScalar *e_data_full[2 * CEED_FIELD_MAX],
213a0162de9SJeremy L Thompson                                               CeedOperator_Ref *impl, CeedRequest *request) {
214ad70ee2cSJeremy L Thompson   for (CeedInt i = 0; i < num_input_fields; i++) {
215681d0ea7SJeremy L Thompson     bool         is_active;
216ad70ee2cSJeremy L Thompson     uint64_t     state;
217d1d35e2fSjeremylt     CeedEvalMode eval_mode;
218d1bcdac9Sjeremylt     CeedVector   vec;
219885ac19cSjeremylt 
220d1bcdac9Sjeremylt     // Get input vector
2212b730f8bSJeremy L Thompson     CeedCallBackend(CeedOperatorFieldGetVector(op_input_fields[i], &vec));
222681d0ea7SJeremy L Thompson     is_active = vec == CEED_VECTOR_ACTIVE;
223681d0ea7SJeremy L Thompson     if (is_active) {
2242b730f8bSJeremy L Thompson       if (skip_active) continue;
2252b730f8bSJeremy L Thompson       else vec = in_vec;
2261d102b48SJeremy L Thompson     }
2271d102b48SJeremy L Thompson 
2282b730f8bSJeremy L Thompson     CeedCallBackend(CeedQFunctionFieldGetEvalMode(qf_input_fields[i], &eval_mode));
2291d102b48SJeremy L Thompson     // Restrict and Evec
230d1d35e2fSjeremylt     if (eval_mode == CEED_EVAL_WEIGHT) {  // Skip
2311d102b48SJeremy L Thompson     } else {
232668048e2SJed Brown       // Restrict
2332b730f8bSJeremy L Thompson       CeedCallBackend(CeedVectorGetState(vec, &state));
2348d713cf6Sjeremylt       // Skip restriction if input is unchanged
2353aab95c0SJeremy L Thompson       if ((state != impl->input_states[i] || vec == in_vec) && !impl->skip_rstr_in[i]) {
236681d0ea7SJeremy L Thompson         CeedElemRestriction elem_rstr;
237681d0ea7SJeremy L Thompson 
238edb2538eSJeremy L Thompson         CeedCallBackend(CeedOperatorFieldGetElemRestriction(op_input_fields[i], &elem_rstr));
239edb2538eSJeremy L Thompson         CeedCallBackend(CeedElemRestrictionApply(elem_rstr, CEED_NOTRANSPOSE, vec, impl->e_vecs_full[i], request));
240681d0ea7SJeremy L Thompson         CeedCallBackend(CeedElemRestrictionDestroy(&elem_rstr));
2418d713cf6Sjeremylt       }
2423aab95c0SJeremy L Thompson       impl->input_states[i] = state;
243668048e2SJed Brown       // Get evec
2442b730f8bSJeremy L Thompson       CeedCallBackend(CeedVectorGetArrayRead(impl->e_vecs_full[i], CEED_MEM_HOST, (const CeedScalar **)&e_data_full[i]));
245885ac19cSjeremylt     }
246681d0ea7SJeremy L Thompson     if (!is_active) CeedCallBackend(CeedVectorDestroy(&vec));
247885ac19cSjeremylt   }
248e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
249885ac19cSjeremylt }
250885ac19cSjeremylt 
251f10650afSjeremylt //------------------------------------------------------------------------------
252f10650afSjeremylt // Input Basis Action
253f10650afSjeremylt //------------------------------------------------------------------------------
2542b730f8bSJeremy L Thompson static inline int CeedOperatorInputBasis_Ref(CeedInt e, CeedInt Q, CeedQFunctionField *qf_input_fields, CeedOperatorField *op_input_fields,
2552b730f8bSJeremy L Thompson                                              CeedInt num_input_fields, const bool skip_active, CeedScalar *e_data_full[2 * CEED_FIELD_MAX],
2562b730f8bSJeremy L Thompson                                              CeedOperator_Ref *impl) {
257ad70ee2cSJeremy L Thompson   for (CeedInt i = 0; i < num_input_fields; i++) {
258a915a514Srezgarshakeri     CeedInt             elem_size, size, num_comp;
259d1d35e2fSjeremylt     CeedEvalMode        eval_mode;
260edb2538eSJeremy L Thompson     CeedElemRestriction elem_rstr;
2611d102b48SJeremy L Thompson     CeedBasis           basis;
2621d102b48SJeremy L Thompson 
2631d102b48SJeremy L Thompson     // Skip active input
264d1d35e2fSjeremylt     if (skip_active) {
265681d0ea7SJeremy L Thompson       bool       is_active;
2661d102b48SJeremy L Thompson       CeedVector vec;
267ad70ee2cSJeremy L Thompson 
2682b730f8bSJeremy L Thompson       CeedCallBackend(CeedOperatorFieldGetVector(op_input_fields[i], &vec));
269681d0ea7SJeremy L Thompson       is_active = vec == CEED_VECTOR_ACTIVE;
270681d0ea7SJeremy L Thompson       CeedCallBackend(CeedVectorDestroy(&vec));
271681d0ea7SJeremy L Thompson       if (is_active) continue;
2721d102b48SJeremy L Thompson     }
273d1d35e2fSjeremylt     // Get elem_size, eval_mode, size
274edb2538eSJeremy L Thompson     CeedCallBackend(CeedOperatorFieldGetElemRestriction(op_input_fields[i], &elem_rstr));
275edb2538eSJeremy L Thompson     CeedCallBackend(CeedElemRestrictionGetElementSize(elem_rstr, &elem_size));
276681d0ea7SJeremy L Thompson     CeedCallBackend(CeedElemRestrictionDestroy(&elem_rstr));
2772b730f8bSJeremy L Thompson     CeedCallBackend(CeedQFunctionFieldGetEvalMode(qf_input_fields[i], &eval_mode));
2782b730f8bSJeremy L Thompson     CeedCallBackend(CeedQFunctionFieldGetSize(qf_input_fields[i], &size));
279885ac19cSjeremylt     // Basis action
280d1d35e2fSjeremylt     switch (eval_mode) {
281885ac19cSjeremylt       case CEED_EVAL_NONE:
28281670346SSebastian Grimberg         CeedCallBackend(CeedVectorSetArray(impl->q_vecs_in[i], CEED_MEM_HOST, CEED_USE_POINTER, &e_data_full[i][(CeedSize)e * Q * size]));
283885ac19cSjeremylt         break;
284885ac19cSjeremylt       case CEED_EVAL_INTERP:
285885ac19cSjeremylt       case CEED_EVAL_GRAD:
286a915a514Srezgarshakeri       case CEED_EVAL_DIV:
287c4e3f59bSSebastian Grimberg       case CEED_EVAL_CURL:
288a915a514Srezgarshakeri         CeedCallBackend(CeedOperatorFieldGetBasis(op_input_fields[i], &basis));
289a915a514Srezgarshakeri         CeedCallBackend(CeedBasisGetNumComponents(basis, &num_comp));
29081670346SSebastian Grimberg         CeedCallBackend(CeedVectorSetArray(impl->e_vecs_in[i], CEED_MEM_HOST, CEED_USE_POINTER, &e_data_full[i][(CeedSize)e * elem_size * num_comp]));
291c4e3f59bSSebastian Grimberg         CeedCallBackend(CeedBasisApply(basis, 1, CEED_NOTRANSPOSE, eval_mode, impl->e_vecs_in[i], impl->q_vecs_in[i]));
292681d0ea7SJeremy L Thompson         CeedCallBackend(CeedBasisDestroy(&basis));
293a915a514Srezgarshakeri         break;
294885ac19cSjeremylt       case CEED_EVAL_WEIGHT:
295885ac19cSjeremylt         break;  // No action
296885ac19cSjeremylt     }
297885ac19cSjeremylt   }
298e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
299885ac19cSjeremylt }
300885ac19cSjeremylt 
301f10650afSjeremylt //------------------------------------------------------------------------------
302f10650afSjeremylt // Output Basis Action
303f10650afSjeremylt //------------------------------------------------------------------------------
3042b730f8bSJeremy L Thompson static inline int CeedOperatorOutputBasis_Ref(CeedInt e, CeedInt Q, CeedQFunctionField *qf_output_fields, CeedOperatorField *op_output_fields,
305f8a0df59SJeremy L Thompson                                               CeedInt num_input_fields, CeedInt num_output_fields, bool *apply_add_basis, CeedOperator op,
3064fc1f125SJeremy L Thompson                                               CeedScalar *e_data_full[2 * CEED_FIELD_MAX], CeedOperator_Ref *impl) {
307ad70ee2cSJeremy L Thompson   for (CeedInt i = 0; i < num_output_fields; i++) {
308a915a514Srezgarshakeri     CeedInt             elem_size, num_comp;
309d1d35e2fSjeremylt     CeedEvalMode        eval_mode;
310edb2538eSJeremy L Thompson     CeedElemRestriction elem_rstr;
3111d102b48SJeremy L Thompson     CeedBasis           basis;
3121d102b48SJeremy L Thompson 
313a915a514Srezgarshakeri     // Get elem_size, eval_mode
314edb2538eSJeremy L Thompson     CeedCallBackend(CeedOperatorFieldGetElemRestriction(op_output_fields[i], &elem_rstr));
315edb2538eSJeremy L Thompson     CeedCallBackend(CeedElemRestrictionGetElementSize(elem_rstr, &elem_size));
316681d0ea7SJeremy L Thompson     CeedCallBackend(CeedElemRestrictionDestroy(&elem_rstr));
3172b730f8bSJeremy L Thompson     CeedCallBackend(CeedQFunctionFieldGetEvalMode(qf_output_fields[i], &eval_mode));
318885ac19cSjeremylt     // Basis action
319d1d35e2fSjeremylt     switch (eval_mode) {
320885ac19cSjeremylt       case CEED_EVAL_NONE:
321885ac19cSjeremylt         break;  // No action
322885ac19cSjeremylt       case CEED_EVAL_INTERP:
323885ac19cSjeremylt       case CEED_EVAL_GRAD:
324a915a514Srezgarshakeri       case CEED_EVAL_DIV:
325c4e3f59bSSebastian Grimberg       case CEED_EVAL_CURL:
326a915a514Srezgarshakeri         CeedCallBackend(CeedOperatorFieldGetBasis(op_output_fields[i], &basis));
327a915a514Srezgarshakeri         CeedCallBackend(CeedBasisGetNumComponents(basis, &num_comp));
32881670346SSebastian Grimberg         CeedCallBackend(CeedVectorSetArray(impl->e_vecs_out[i], CEED_MEM_HOST, CEED_USE_POINTER,
32981670346SSebastian Grimberg                                            &e_data_full[i + num_input_fields][(CeedSize)e * elem_size * num_comp]));
330f8a0df59SJeremy L Thompson         if (apply_add_basis[i]) {
331f8a0df59SJeremy L Thompson           CeedCallBackend(CeedBasisApplyAdd(basis, 1, CEED_TRANSPOSE, eval_mode, impl->q_vecs_out[i], impl->e_vecs_out[i]));
332f8a0df59SJeremy L Thompson         } else {
333c4e3f59bSSebastian Grimberg           CeedCallBackend(CeedBasisApply(basis, 1, CEED_TRANSPOSE, eval_mode, impl->q_vecs_out[i], impl->e_vecs_out[i]));
334f8a0df59SJeremy L Thompson         }
335681d0ea7SJeremy L Thompson         CeedCallBackend(CeedBasisDestroy(&basis));
336a915a514Srezgarshakeri         break;
337c042f62fSJeremy L Thompson       // LCOV_EXCL_START
338bbfacfcdSjeremylt       case CEED_EVAL_WEIGHT: {
3396e536b99SJeremy L Thompson         return CeedError(CeedOperatorReturnCeed(op), CEED_ERROR_BACKEND, "CEED_EVAL_WEIGHT cannot be an output evaluation mode");
3401d102b48SJeremy L Thompson         // LCOV_EXCL_STOP
341885ac19cSjeremylt       }
342885ac19cSjeremylt     }
343885ac19cSjeremylt   }
344e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
3451d102b48SJeremy L Thompson }
3461d102b48SJeremy L Thompson 
347f10650afSjeremylt //------------------------------------------------------------------------------
348f10650afSjeremylt // Restore Input Vectors
349f10650afSjeremylt //------------------------------------------------------------------------------
3502b730f8bSJeremy L Thompson static inline int CeedOperatorRestoreInputs_Ref(CeedInt num_input_fields, CeedQFunctionField *qf_input_fields, CeedOperatorField *op_input_fields,
3512b730f8bSJeremy L Thompson                                                 const bool skip_active, CeedScalar *e_data_full[2 * CEED_FIELD_MAX], CeedOperator_Ref *impl) {
352ad70ee2cSJeremy L Thompson   for (CeedInt i = 0; i < num_input_fields; i++) {
353d1d35e2fSjeremylt     CeedEvalMode eval_mode;
3541d102b48SJeremy L Thompson 
3551d102b48SJeremy L Thompson     // Skip active inputs
356d1d35e2fSjeremylt     if (skip_active) {
357681d0ea7SJeremy L Thompson       bool       is_active;
3581d102b48SJeremy L Thompson       CeedVector vec;
359ad70ee2cSJeremy L Thompson 
3602b730f8bSJeremy L Thompson       CeedCallBackend(CeedOperatorFieldGetVector(op_input_fields[i], &vec));
361681d0ea7SJeremy L Thompson       is_active = vec == CEED_VECTOR_ACTIVE;
362681d0ea7SJeremy L Thompson       CeedCallBackend(CeedVectorDestroy(&vec));
363681d0ea7SJeremy L Thompson       if (is_active) continue;
3641d102b48SJeremy L Thompson     }
3651d102b48SJeremy L Thompson     // Restore input
3662b730f8bSJeremy L Thompson     CeedCallBackend(CeedQFunctionFieldGetEvalMode(qf_input_fields[i], &eval_mode));
367d1d35e2fSjeremylt     if (eval_mode == CEED_EVAL_WEIGHT) {  // Skip
3681d102b48SJeremy L Thompson     } else {
3692b730f8bSJeremy L Thompson       CeedCallBackend(CeedVectorRestoreArrayRead(impl->e_vecs_full[i], (const CeedScalar **)&e_data_full[i]));
3701d102b48SJeremy L Thompson     }
3711d102b48SJeremy L Thompson   }
372e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
3731d102b48SJeremy L Thompson }
3741d102b48SJeremy L Thompson 
375f10650afSjeremylt //------------------------------------------------------------------------------
376f10650afSjeremylt // Operator Apply
377f10650afSjeremylt //------------------------------------------------------------------------------
3782b730f8bSJeremy L Thompson static int CeedOperatorApplyAdd_Ref(CeedOperator op, CeedVector in_vec, CeedVector out_vec, CeedRequest *request) {
379d1d35e2fSjeremylt   CeedInt             Q, num_elem, num_input_fields, num_output_fields, size;
380ad70ee2cSJeremy L Thompson   CeedEvalMode        eval_mode;
381ad70ee2cSJeremy L Thompson   CeedScalar         *e_data_full[2 * CEED_FIELD_MAX] = {NULL};
382ad70ee2cSJeremy L Thompson   CeedQFunctionField *qf_input_fields, *qf_output_fields;
383ad70ee2cSJeremy L Thompson   CeedQFunction       qf;
384ad70ee2cSJeremy L Thompson   CeedOperatorField  *op_input_fields, *op_output_fields;
385ad70ee2cSJeremy L Thompson   CeedOperator_Ref   *impl;
386ad70ee2cSJeremy L Thompson 
3871d102b48SJeremy L Thompson   // Setup
3882b730f8bSJeremy L Thompson   CeedCallBackend(CeedOperatorSetup_Ref(op));
3891d102b48SJeremy L Thompson 
390c11e12f4SJeremy L Thompson   CeedCallBackend(CeedOperatorGetData(op, &impl));
391c11e12f4SJeremy L Thompson   CeedCallBackend(CeedOperatorGetFields(op, &num_input_fields, &op_input_fields, &num_output_fields, &op_output_fields));
392c11e12f4SJeremy L Thompson 
3930b454692Sjeremylt   // Restriction only operator
394edb2538eSJeremy L Thompson   if (impl->is_identity_rstr_op) {
395edb2538eSJeremy L Thompson     CeedElemRestriction elem_rstr;
396ad70ee2cSJeremy L Thompson 
397edb2538eSJeremy L Thompson     CeedCallBackend(CeedOperatorFieldGetElemRestriction(op_input_fields[0], &elem_rstr));
398edb2538eSJeremy L Thompson     CeedCallBackend(CeedElemRestrictionApply(elem_rstr, CEED_NOTRANSPOSE, in_vec, impl->e_vecs_full[0], request));
399681d0ea7SJeremy L Thompson     CeedCallBackend(CeedElemRestrictionDestroy(&elem_rstr));
400edb2538eSJeremy L Thompson     CeedCallBackend(CeedOperatorFieldGetElemRestriction(op_output_fields[0], &elem_rstr));
401edb2538eSJeremy L Thompson     CeedCallBackend(CeedElemRestrictionApply(elem_rstr, CEED_TRANSPOSE, impl->e_vecs_full[0], out_vec, request));
402681d0ea7SJeremy L Thompson     CeedCallBackend(CeedElemRestrictionDestroy(&elem_rstr));
4030b454692Sjeremylt     return CEED_ERROR_SUCCESS;
4040b454692Sjeremylt   }
4050b454692Sjeremylt 
406c11e12f4SJeremy L Thompson   CeedCallBackend(CeedOperatorGetQFunction(op, &qf));
407c11e12f4SJeremy L Thompson   CeedCallBackend(CeedOperatorGetNumQuadraturePoints(op, &Q));
408c11e12f4SJeremy L Thompson   CeedCallBackend(CeedOperatorGetNumElements(op, &num_elem));
409c11e12f4SJeremy L Thompson   CeedCallBackend(CeedQFunctionGetFields(qf, NULL, &qf_input_fields, NULL, &qf_output_fields));
410c11e12f4SJeremy L Thompson 
4111d102b48SJeremy L Thompson   // Input Evecs and Restriction
4122b730f8bSJeremy L Thompson   CeedCallBackend(CeedOperatorSetupInputs_Ref(num_input_fields, qf_input_fields, op_input_fields, in_vec, false, e_data_full, impl, request));
4131d102b48SJeremy L Thompson 
4141d102b48SJeremy L Thompson   // Output Evecs
415f8a0df59SJeremy L Thompson   for (CeedInt i = num_output_fields - 1; i >= 0; i--) {
416f8a0df59SJeremy L Thompson     if (impl->skip_rstr_out[i]) {
417f8a0df59SJeremy L Thompson       e_data_full[i + num_input_fields] = e_data_full[impl->e_data_out_indices[i] + num_input_fields];
418f8a0df59SJeremy L Thompson     } else {
4192b730f8bSJeremy L Thompson       CeedCallBackend(CeedVectorGetArrayWrite(impl->e_vecs_full[i + impl->num_inputs], CEED_MEM_HOST, &e_data_full[i + num_input_fields]));
4201d102b48SJeremy L Thompson     }
421f8a0df59SJeremy L Thompson   }
4221d102b48SJeremy L Thompson 
4231d102b48SJeremy L Thompson   // Loop through elements
424d1d35e2fSjeremylt   for (CeedInt e = 0; e < num_elem; e++) {
4251d102b48SJeremy L Thompson     // Output pointers
426d1d35e2fSjeremylt     for (CeedInt i = 0; i < num_output_fields; i++) {
4272b730f8bSJeremy L Thompson       CeedCallBackend(CeedQFunctionFieldGetEvalMode(qf_output_fields[i], &eval_mode));
428d1d35e2fSjeremylt       if (eval_mode == CEED_EVAL_NONE) {
4292b730f8bSJeremy L Thompson         CeedCallBackend(CeedQFunctionFieldGetSize(qf_output_fields[i], &size));
43081670346SSebastian Grimberg         CeedCallBackend(
43181670346SSebastian Grimberg             CeedVectorSetArray(impl->q_vecs_out[i], CEED_MEM_HOST, CEED_USE_POINTER, &e_data_full[i + num_input_fields][(CeedSize)e * Q * size]));
4321d102b48SJeremy L Thompson       }
4331d102b48SJeremy L Thompson     }
4341d102b48SJeremy L Thompson 
43516911fdaSjeremylt     // Input basis apply
4362b730f8bSJeremy L Thompson     CeedCallBackend(CeedOperatorInputBasis_Ref(e, Q, qf_input_fields, op_input_fields, num_input_fields, false, e_data_full, impl));
43716911fdaSjeremylt 
4381d102b48SJeremy L Thompson     // Q function
4390b454692Sjeremylt     if (!impl->is_identity_qf) {
4402b730f8bSJeremy L Thompson       CeedCallBackend(CeedQFunctionApply(qf, Q, impl->q_vecs_in, impl->q_vecs_out));
44116911fdaSjeremylt     }
4421d102b48SJeremy L Thompson 
4431d102b48SJeremy L Thompson     // Output basis apply
444f8a0df59SJeremy L Thompson     CeedCallBackend(CeedOperatorOutputBasis_Ref(e, Q, qf_output_fields, op_output_fields, num_input_fields, num_output_fields,
445f8a0df59SJeremy L Thompson                                                 impl->apply_add_basis_out, op, e_data_full, impl));
4461d102b48SJeremy L Thompson   }
447885ac19cSjeremylt 
448885ac19cSjeremylt   // Output restriction
449d1d35e2fSjeremylt   for (CeedInt i = 0; i < num_output_fields; i++) {
450681d0ea7SJeremy L Thompson     bool                is_active;
451ad70ee2cSJeremy L Thompson     CeedVector          vec;
452edb2538eSJeremy L Thompson     CeedElemRestriction elem_rstr;
453ad70ee2cSJeremy L Thompson 
454f8a0df59SJeremy L Thompson     if (impl->skip_rstr_out[i]) continue;
455d1d35e2fSjeremylt     // Restore Evec
4562b730f8bSJeremy L Thompson     CeedCallBackend(CeedVectorRestoreArray(impl->e_vecs_full[i + impl->num_inputs], &e_data_full[i + num_input_fields]));
457d1bcdac9Sjeremylt     // Get output vector
4582b730f8bSJeremy L Thompson     CeedCallBackend(CeedOperatorFieldGetVector(op_output_fields[i], &vec));
459668048e2SJed Brown     // Active
460681d0ea7SJeremy L Thompson     is_active = vec == CEED_VECTOR_ACTIVE;
461681d0ea7SJeremy L Thompson     if (is_active) vec = out_vec;
4627ca8db16Sjeremylt     // Restrict
463edb2538eSJeremy L Thompson     CeedCallBackend(CeedOperatorFieldGetElemRestriction(op_output_fields[i], &elem_rstr));
464edb2538eSJeremy L Thompson     CeedCallBackend(CeedElemRestrictionApply(elem_rstr, CEED_TRANSPOSE, impl->e_vecs_full[i + impl->num_inputs], vec, request));
465681d0ea7SJeremy L Thompson     if (!is_active) CeedCallBackend(CeedVectorDestroy(&vec));
466681d0ea7SJeremy L Thompson     CeedCallBackend(CeedElemRestrictionDestroy(&elem_rstr));
467885ac19cSjeremylt   }
468885ac19cSjeremylt 
4697ca8db16Sjeremylt   // Restore input arrays
4702b730f8bSJeremy L Thompson   CeedCallBackend(CeedOperatorRestoreInputs_Ref(num_input_fields, qf_input_fields, op_input_fields, false, e_data_full, impl));
471c11e12f4SJeremy L Thompson   CeedCallBackend(CeedQFunctionDestroy(&qf));
472e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
47321617c04Sjeremylt }
47421617c04Sjeremylt 
475f10650afSjeremylt //------------------------------------------------------------------------------
47670a7ffb3SJeremy L Thompson // Core code for assembling linear QFunction
477f10650afSjeremylt //------------------------------------------------------------------------------
4782b730f8bSJeremy L Thompson static inline int CeedOperatorLinearAssembleQFunctionCore_Ref(CeedOperator op, bool build_objects, CeedVector *assembled, CeedElemRestriction *rstr,
47970a7ffb3SJeremy L Thompson                                                               CeedRequest *request) {
4809bc66399SJeremy L Thompson   Ceed                ceed_parent;
481ff8551c5SJeremy L Thompson   CeedInt             qf_size_in, qf_size_out, Q, num_elem, num_input_fields, num_output_fields;
482ad70ee2cSJeremy L Thompson   CeedScalar         *assembled_array, *e_data_full[2 * CEED_FIELD_MAX] = {NULL};
483ad70ee2cSJeremy L Thompson   CeedQFunctionField *qf_input_fields, *qf_output_fields;
484ad70ee2cSJeremy L Thompson   CeedQFunction       qf;
485ad70ee2cSJeremy L Thompson   CeedOperatorField  *op_input_fields, *op_output_fields;
486ad70ee2cSJeremy L Thompson   CeedOperator_Ref   *impl;
487ad70ee2cSJeremy L Thompson 
488e910d748SJeremy L Thompson   CeedCallBackend(CeedOperatorGetFallbackParentCeed(op, &ceed_parent));
489e984cf9aSJeremy L Thompson   CeedCallBackend(CeedOperatorGetData(op, &impl));
490ff8551c5SJeremy L Thompson   qf_size_in  = impl->qf_size_in;
491ff8551c5SJeremy L Thompson   qf_size_out = impl->qf_size_out;
492e984cf9aSJeremy L Thompson   CeedCallBackend(CeedOperatorGetQFunction(op, &qf));
493e984cf9aSJeremy L Thompson   CeedCallBackend(CeedOperatorGetNumQuadraturePoints(op, &Q));
494e984cf9aSJeremy L Thompson   CeedCallBackend(CeedOperatorGetNumElements(op, &num_elem));
495e984cf9aSJeremy L Thompson   CeedCallBackend(CeedQFunctionGetFields(qf, NULL, &qf_input_fields, NULL, &qf_output_fields));
496e984cf9aSJeremy L Thompson   CeedCallBackend(CeedOperatorGetFields(op, &num_input_fields, &op_input_fields, &num_output_fields, &op_output_fields));
4971d102b48SJeremy L Thompson 
4981d102b48SJeremy L Thompson   // Setup
4992b730f8bSJeremy L Thompson   CeedCallBackend(CeedOperatorSetup_Ref(op));
5001d102b48SJeremy L Thompson 
501506b1a0cSSebastian Grimberg   // Check for restriction only operator
5029bc66399SJeremy L Thompson   CeedCheck(!impl->is_identity_rstr_op, CeedOperatorReturnCeed(op), CEED_ERROR_BACKEND, "Assembling restriction only operators is not supported");
50316911fdaSjeremylt 
5041d102b48SJeremy L Thompson   // Input Evecs and Restriction
5052b730f8bSJeremy L Thompson   CeedCallBackend(CeedOperatorSetupInputs_Ref(num_input_fields, qf_input_fields, op_input_fields, NULL, true, e_data_full, impl, request));
5061d102b48SJeremy L Thompson 
5071d102b48SJeremy L Thompson   // Count number of active input fields
508ff8551c5SJeremy L Thompson   if (qf_size_in == 0) {
509d1d35e2fSjeremylt     for (CeedInt i = 0; i < num_input_fields; i++) {
510c7b67790SJeremy L Thompson       CeedInt    field_size;
511ad70ee2cSJeremy L Thompson       CeedVector vec;
512ad70ee2cSJeremy L Thompson 
5131d102b48SJeremy L Thompson       // Get input vector
5142b730f8bSJeremy L Thompson       CeedCallBackend(CeedOperatorFieldGetVector(op_input_fields[i], &vec));
5151d102b48SJeremy L Thompson       // Check if active input
5161d102b48SJeremy L Thompson       if (vec == CEED_VECTOR_ACTIVE) {
517c7b67790SJeremy L Thompson         CeedCallBackend(CeedQFunctionFieldGetSize(qf_input_fields[i], &field_size));
5182b730f8bSJeremy L Thompson         CeedCallBackend(CeedVectorSetValue(impl->q_vecs_in[i], 0.0));
519ff8551c5SJeremy L Thompson         qf_size_in += field_size;
5201d102b48SJeremy L Thompson       }
521681d0ea7SJeremy L Thompson       CeedCallBackend(CeedVectorDestroy(&vec));
5221d102b48SJeremy L Thompson     }
5239bc66399SJeremy L Thompson     CeedCheck(qf_size_in > 0, CeedOperatorReturnCeed(op), CEED_ERROR_BACKEND, "Cannot assemble QFunction without active inputs and outputs");
524ff8551c5SJeremy L Thompson     impl->qf_size_in = qf_size_in;
525bb219a0fSJeremy L Thompson   }
5261d102b48SJeremy L Thompson 
5271d102b48SJeremy L Thompson   // Count number of active output fields
528ff8551c5SJeremy L Thompson   if (qf_size_out == 0) {
529d1d35e2fSjeremylt     for (CeedInt i = 0; i < num_output_fields; i++) {
530c7b67790SJeremy L Thompson       CeedInt    field_size;
531ad70ee2cSJeremy L Thompson       CeedVector vec;
532ad70ee2cSJeremy L Thompson 
5331d102b48SJeremy L Thompson       // Get output vector
5342b730f8bSJeremy L Thompson       CeedCallBackend(CeedOperatorFieldGetVector(op_output_fields[i], &vec));
5351d102b48SJeremy L Thompson       // Check if active output
5361d102b48SJeremy L Thompson       if (vec == CEED_VECTOR_ACTIVE) {
537c7b67790SJeremy L Thompson         CeedCallBackend(CeedQFunctionFieldGetSize(qf_output_fields[i], &field_size));
538ff8551c5SJeremy L Thompson         qf_size_out += field_size;
5391d102b48SJeremy L Thompson       }
540681d0ea7SJeremy L Thompson       CeedCallBackend(CeedVectorDestroy(&vec));
5411d102b48SJeremy L Thompson     }
5429bc66399SJeremy L Thompson     CeedCheck(qf_size_out > 0, CeedOperatorReturnCeed(op), CEED_ERROR_BACKEND, "Cannot assemble QFunction without active inputs and outputs");
543ff8551c5SJeremy L Thompson     impl->qf_size_out = qf_size_out;
544bb219a0fSJeremy L Thompson   }
5451d102b48SJeremy L Thompson 
54670a7ffb3SJeremy L Thompson   // Build objects if needed
54770a7ffb3SJeremy L Thompson   if (build_objects) {
548ff8551c5SJeremy L Thompson     const CeedSize l_size     = (CeedSize)num_elem * Q * qf_size_in * qf_size_out;
549ff8551c5SJeremy L Thompson     CeedInt        strides[3] = {1, Q, qf_size_in * qf_size_out * Q}; /* *NOPAD* */
550ad70ee2cSJeremy L Thompson 
551ad70ee2cSJeremy L Thompson     // Create output restriction
5520a5597ceSJeremy L Thompson     CeedCallBackend(CeedElemRestrictionCreateStrided(ceed_parent, num_elem, Q, qf_size_in * qf_size_out,
5530a5597ceSJeremy L Thompson                                                      (CeedSize)qf_size_in * (CeedSize)qf_size_out * (CeedSize)num_elem * (CeedSize)Q, strides, rstr));
5541d102b48SJeremy L Thompson     // Create assembled vector
555e910d748SJeremy L Thompson     CeedCallBackend(CeedVectorCreate(ceed_parent, l_size, assembled));
55670a7ffb3SJeremy L Thompson   }
55770a7ffb3SJeremy L Thompson   // Clear output vector
5582b730f8bSJeremy L Thompson   CeedCallBackend(CeedVectorSetValue(*assembled, 0.0));
559ad70ee2cSJeremy L Thompson   CeedCallBackend(CeedVectorGetArray(*assembled, CEED_MEM_HOST, &assembled_array));
5601d102b48SJeremy L Thompson 
5611d102b48SJeremy L Thompson   // Loop through elements
562d1d35e2fSjeremylt   for (CeedInt e = 0; e < num_elem; e++) {
5631d102b48SJeremy L Thompson     // Input basis apply
5642b730f8bSJeremy L Thompson     CeedCallBackend(CeedOperatorInputBasis_Ref(e, Q, qf_input_fields, op_input_fields, num_input_fields, true, e_data_full, impl));
5651d102b48SJeremy L Thompson 
5661d102b48SJeremy L Thompson     // Assemble QFunction
567c7b67790SJeremy L Thompson 
568c7b67790SJeremy L Thompson     for (CeedInt i = 0; i < num_input_fields; i++) {
569681d0ea7SJeremy L Thompson       bool       is_active;
570c7b67790SJeremy L Thompson       CeedInt    field_size;
571c7b67790SJeremy L Thompson       CeedVector vec;
572c7b67790SJeremy L Thompson 
5731d102b48SJeremy L Thompson       // Set Inputs
574c7b67790SJeremy L Thompson       CeedCallBackend(CeedOperatorFieldGetVector(op_input_fields[i], &vec));
575681d0ea7SJeremy L Thompson       is_active = vec == CEED_VECTOR_ACTIVE;
576681d0ea7SJeremy L Thompson       CeedCallBackend(CeedVectorDestroy(&vec));
577681d0ea7SJeremy L Thompson       if (!is_active) continue;
578c7b67790SJeremy L Thompson       CeedCallBackend(CeedQFunctionFieldGetSize(qf_input_fields[i], &field_size));
579c7b67790SJeremy L Thompson       for (CeedInt field = 0; field < field_size; field++) {
580c7b67790SJeremy L Thompson         // Set current portion of input to 1.0
581c7b67790SJeremy L Thompson         {
582c7b67790SJeremy L Thompson           CeedScalar *array;
583c7b67790SJeremy L Thompson 
584c7b67790SJeremy L Thompson           CeedCallBackend(CeedVectorGetArray(impl->q_vecs_in[i], CEED_MEM_HOST, &array));
585c7b67790SJeremy L Thompson           for (CeedInt j = 0; j < Q; j++) array[field * Q + j] = 1.0;
586c7b67790SJeremy L Thompson           CeedCallBackend(CeedVectorRestoreArray(impl->q_vecs_in[i], &array));
58742ea3801Sjeremylt         }
588c7b67790SJeremy L Thompson 
589506b1a0cSSebastian Grimberg         if (!impl->is_identity_qf) {
5901d102b48SJeremy L Thompson           // Set Outputs
591d1d35e2fSjeremylt           for (CeedInt out = 0; out < num_output_fields; out++) {
592ad70ee2cSJeremy L Thompson             CeedVector vec;
593ad70ee2cSJeremy L Thompson 
5941d102b48SJeremy L Thompson             // Get output vector
5952b730f8bSJeremy L Thompson             CeedCallBackend(CeedOperatorFieldGetVector(op_output_fields[out], &vec));
5961d102b48SJeremy L Thompson             // Check if active output
5971d102b48SJeremy L Thompson             if (vec == CEED_VECTOR_ACTIVE) {
598c7b67790SJeremy L Thompson               CeedInt field_size;
599c7b67790SJeremy L Thompson 
600ad70ee2cSJeremy L Thompson               CeedCallBackend(CeedVectorSetArray(impl->q_vecs_out[out], CEED_MEM_HOST, CEED_USE_POINTER, assembled_array));
601c7b67790SJeremy L Thompson               CeedCallBackend(CeedQFunctionFieldGetSize(qf_output_fields[out], &field_size));
602c7b67790SJeremy L Thompson               assembled_array += field_size * Q;  // Advance the pointer by the size of the output
6031d102b48SJeremy L Thompson             }
604681d0ea7SJeremy L Thompson             CeedCallBackend(CeedVectorDestroy(&vec));
6051d102b48SJeremy L Thompson           }
6061d102b48SJeremy L Thompson           // Apply QFunction
6072b730f8bSJeremy L Thompson           CeedCallBackend(CeedQFunctionApply(qf, Q, impl->q_vecs_in, impl->q_vecs_out));
608506b1a0cSSebastian Grimberg         } else {
609c7b67790SJeremy L Thompson           CeedInt           field_size;
610c7b67790SJeremy L Thompson           const CeedScalar *array;
611506b1a0cSSebastian Grimberg 
612506b1a0cSSebastian Grimberg           // Copy Identity Outputs
613c7b67790SJeremy L Thompson           CeedCallBackend(CeedQFunctionFieldGetSize(qf_output_fields[0], &field_size));
614c7b67790SJeremy L Thompson           CeedCallBackend(CeedVectorGetArrayRead(impl->q_vecs_out[0], CEED_MEM_HOST, &array));
615c7b67790SJeremy L Thompson           for (CeedInt j = 0; j < field_size * Q; j++) assembled_array[j] = array[j];
616c7b67790SJeremy L Thompson           CeedCallBackend(CeedVectorRestoreArrayRead(impl->q_vecs_out[0], &array));
617c7b67790SJeremy L Thompson           assembled_array += field_size * Q;
618c7b67790SJeremy L Thompson         }
619c7b67790SJeremy L Thompson         // Reset input to 0.0
620c7b67790SJeremy L Thompson         {
621c7b67790SJeremy L Thompson           CeedScalar *array;
622c7b67790SJeremy L Thompson 
623c7b67790SJeremy L Thompson           CeedCallBackend(CeedVectorGetArray(impl->q_vecs_in[i], CEED_MEM_HOST, &array));
624c7b67790SJeremy L Thompson           for (CeedInt j = 0; j < Q; j++) array[field * Q + j] = 0.0;
625c7b67790SJeremy L Thompson           CeedCallBackend(CeedVectorRestoreArray(impl->q_vecs_in[i], &array));
626c7b67790SJeremy L Thompson         }
627506b1a0cSSebastian Grimberg       }
6281d102b48SJeremy L Thompson     }
6291d102b48SJeremy L Thompson   }
6301d102b48SJeremy L Thompson 
6311d102b48SJeremy L Thompson   // Un-set output Qvecs to prevent accidental overwrite of Assembled
632506b1a0cSSebastian Grimberg   if (!impl->is_identity_qf) {
633d1d35e2fSjeremylt     for (CeedInt out = 0; out < num_output_fields; out++) {
634ad70ee2cSJeremy L Thompson       CeedVector vec;
635ad70ee2cSJeremy L Thompson 
6361d102b48SJeremy L Thompson       // Get output vector
6372b730f8bSJeremy L Thompson       CeedCallBackend(CeedOperatorFieldGetVector(op_output_fields[out], &vec));
6381d102b48SJeremy L Thompson       // Check if active output
639056ea4bdSJeremy L Thompson       if (vec == CEED_VECTOR_ACTIVE && num_elem > 0) {
6402b730f8bSJeremy L Thompson         CeedCallBackend(CeedVectorTakeArray(impl->q_vecs_out[out], CEED_MEM_HOST, NULL));
6411d102b48SJeremy L Thompson       }
642681d0ea7SJeremy L Thompson       CeedCallBackend(CeedVectorDestroy(&vec));
6431d102b48SJeremy L Thompson     }
644506b1a0cSSebastian Grimberg   }
6451d102b48SJeremy L Thompson 
6461d102b48SJeremy L Thompson   // Restore input arrays
6472b730f8bSJeremy L Thompson   CeedCallBackend(CeedOperatorRestoreInputs_Ref(num_input_fields, qf_input_fields, op_input_fields, true, e_data_full, impl));
6481d102b48SJeremy L Thompson 
6491d102b48SJeremy L Thompson   // Restore output
650ad70ee2cSJeremy L Thompson   CeedCallBackend(CeedVectorRestoreArray(*assembled, &assembled_array));
6519bc66399SJeremy L Thompson   CeedCallBackend(CeedDestroy(&ceed_parent));
652c11e12f4SJeremy L Thompson   CeedCallBackend(CeedQFunctionDestroy(&qf));
653e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6541d102b48SJeremy L Thompson }
6551d102b48SJeremy L Thompson 
656f10650afSjeremylt //------------------------------------------------------------------------------
65770a7ffb3SJeremy L Thompson // Assemble Linear QFunction
65870a7ffb3SJeremy L Thompson //------------------------------------------------------------------------------
6592b730f8bSJeremy L Thompson static int CeedOperatorLinearAssembleQFunction_Ref(CeedOperator op, CeedVector *assembled, CeedElemRestriction *rstr, CeedRequest *request) {
6602b730f8bSJeremy L Thompson   return CeedOperatorLinearAssembleQFunctionCore_Ref(op, true, assembled, rstr, request);
66170a7ffb3SJeremy L Thompson }
66270a7ffb3SJeremy L Thompson 
66370a7ffb3SJeremy L Thompson //------------------------------------------------------------------------------
66470a7ffb3SJeremy L Thompson // Update Assembled Linear QFunction
66570a7ffb3SJeremy L Thompson //------------------------------------------------------------------------------
6662b730f8bSJeremy L Thompson static int CeedOperatorLinearAssembleQFunctionUpdate_Ref(CeedOperator op, CeedVector assembled, CeedElemRestriction rstr, CeedRequest *request) {
6672b730f8bSJeremy L Thompson   return CeedOperatorLinearAssembleQFunctionCore_Ref(op, false, &assembled, &rstr, request);
66870a7ffb3SJeremy L Thompson }
66970a7ffb3SJeremy L Thompson 
67070a7ffb3SJeremy L Thompson //------------------------------------------------------------------------------
67148acf710SJeremy L Thompson // Setup Input/Output Fields
67248acf710SJeremy L Thompson //------------------------------------------------------------------------------
673f8a0df59SJeremy L Thompson static int CeedOperatorSetupFieldsAtPoints_Ref(CeedQFunction qf, CeedOperator op, bool is_input, bool *skip_rstr, bool *apply_add_basis,
674f8a0df59SJeremy L Thompson                                                CeedVector *e_vecs_full, CeedVector *e_vecs, CeedVector *q_vecs, CeedInt start_e, CeedInt num_fields,
675f8a0df59SJeremy L Thompson                                                CeedInt Q) {
67648acf710SJeremy L Thompson   Ceed                ceed;
67748acf710SJeremy L Thompson   CeedSize            e_size, q_size;
678ff1bc20eSJeremy L Thompson   CeedInt             max_num_points, num_comp, size, P;
67948acf710SJeremy L Thompson   CeedQFunctionField *qf_fields;
68048acf710SJeremy L Thompson   CeedOperatorField  *op_fields;
68148acf710SJeremy L Thompson 
682e910d748SJeremy L Thompson   {
683e910d748SJeremy L Thompson     Ceed ceed_parent;
684e910d748SJeremy L Thompson 
68548acf710SJeremy L Thompson     CeedCallBackend(CeedOperatorGetCeed(op, &ceed));
686e910d748SJeremy L Thompson     CeedCallBackend(CeedGetParent(ceed, &ceed_parent));
6879bc66399SJeremy L Thompson     CeedCallBackend(CeedReferenceCopy(ceed_parent, &ceed));
6889bc66399SJeremy L Thompson     CeedCallBackend(CeedDestroy(&ceed_parent));
689e910d748SJeremy L Thompson   }
69048acf710SJeremy L Thompson   if (is_input) {
69148acf710SJeremy L Thompson     CeedCallBackend(CeedOperatorGetFields(op, NULL, &op_fields, NULL, NULL));
69248acf710SJeremy L Thompson     CeedCallBackend(CeedQFunctionGetFields(qf, NULL, &qf_fields, NULL, NULL));
69348acf710SJeremy L Thompson   } else {
69448acf710SJeremy L Thompson     CeedCallBackend(CeedOperatorGetFields(op, NULL, NULL, NULL, &op_fields));
69548acf710SJeremy L Thompson     CeedCallBackend(CeedQFunctionGetFields(qf, NULL, NULL, NULL, &qf_fields));
69648acf710SJeremy L Thompson   }
69748acf710SJeremy L Thompson 
69848acf710SJeremy L Thompson   // Get max number of points
69948acf710SJeremy L Thompson   {
70048acf710SJeremy L Thompson     CeedInt             dim;
70148acf710SJeremy L Thompson     CeedElemRestriction rstr_points = NULL;
70248acf710SJeremy L Thompson     CeedOperator_Ref   *impl;
70348acf710SJeremy L Thompson 
70448acf710SJeremy L Thompson     CeedCallBackend(CeedOperatorAtPointsGetPoints(op, &rstr_points, NULL));
70548acf710SJeremy L Thompson     CeedCallBackend(CeedElemRestrictionGetMaxPointsInElement(rstr_points, &max_num_points));
70648acf710SJeremy L Thompson     CeedCallBackend(CeedElemRestrictionGetNumComponents(rstr_points, &dim));
70748acf710SJeremy L Thompson     CeedCallBackend(CeedElemRestrictionDestroy(&rstr_points));
70848acf710SJeremy L Thompson     CeedCallBackend(CeedOperatorGetData(op, &impl));
709b37f8825SJeremy L Thompson     if (is_input) {
710b37f8825SJeremy L Thompson       CeedCallBackend(CeedVectorCreate(ceed, dim * max_num_points, &impl->point_coords_elem));
711b37f8825SJeremy L Thompson       CeedCallBackend(CeedVectorSetValue(impl->point_coords_elem, 0.0));
712b37f8825SJeremy L Thompson     }
71348acf710SJeremy L Thompson   }
71448acf710SJeremy L Thompson 
71548acf710SJeremy L Thompson   // Loop over fields
71648acf710SJeremy L Thompson   for (CeedInt i = 0; i < num_fields; i++) {
71748acf710SJeremy L Thompson     CeedEvalMode eval_mode;
71848acf710SJeremy L Thompson     CeedBasis    basis;
71948acf710SJeremy L Thompson 
72048acf710SJeremy L Thompson     CeedCallBackend(CeedQFunctionFieldGetEvalMode(qf_fields[i], &eval_mode));
72148acf710SJeremy L Thompson     if (eval_mode != CEED_EVAL_WEIGHT) {
72248acf710SJeremy L Thompson       CeedElemRestriction elem_rstr;
72348acf710SJeremy L Thompson 
72448acf710SJeremy L Thompson       CeedCallBackend(CeedOperatorFieldGetElemRestriction(op_fields[i], &elem_rstr));
72548acf710SJeremy L Thompson       CeedCallBackend(CeedElemRestrictionCreateVector(elem_rstr, NULL, &e_vecs_full[i + start_e]));
726681d0ea7SJeremy L Thompson       CeedCallBackend(CeedElemRestrictionDestroy(&elem_rstr));
727ff1bc20eSJeremy L Thompson       CeedCallBackend(CeedVectorSetValue(e_vecs_full[i + start_e], 0.0));
7286efa0d72SZach Atkins     }
72948acf710SJeremy L Thompson 
73048acf710SJeremy L Thompson     switch (eval_mode) {
73138e83183SJeremy L Thompson       case CEED_EVAL_NONE: {
73238e83183SJeremy L Thompson         CeedVector vec;
73338e83183SJeremy L Thompson 
73448acf710SJeremy L Thompson         CeedCallBackend(CeedQFunctionFieldGetSize(qf_fields[i], &size));
73548acf710SJeremy L Thompson         e_size = (CeedSize)max_num_points * size;
73648acf710SJeremy L Thompson         CeedCallBackend(CeedVectorCreate(ceed, e_size, &e_vecs[i]));
73738e83183SJeremy L Thompson         CeedCallBackend(CeedOperatorFieldGetVector(op_fields[i], &vec));
73838e83183SJeremy L Thompson         if (vec == CEED_VECTOR_ACTIVE || !is_input) {
73938e83183SJeremy L Thompson           CeedCallBackend(CeedVectorReferenceCopy(e_vecs[i], &q_vecs[i]));
74038e83183SJeremy L Thompson         } else {
74148acf710SJeremy L Thompson           q_size = (CeedSize)max_num_points * size;
74248acf710SJeremy L Thompson           CeedCallBackend(CeedVectorCreate(ceed, q_size, &q_vecs[i]));
74338e83183SJeremy L Thompson         }
744681d0ea7SJeremy L Thompson         CeedCallBackend(CeedVectorDestroy(&vec));
74548acf710SJeremy L Thompson         break;
74638e83183SJeremy L Thompson       }
74748acf710SJeremy L Thompson       case CEED_EVAL_INTERP:
74848acf710SJeremy L Thompson       case CEED_EVAL_GRAD:
74948acf710SJeremy L Thompson       case CEED_EVAL_DIV:
75048acf710SJeremy L Thompson       case CEED_EVAL_CURL:
75148acf710SJeremy L Thompson         CeedCallBackend(CeedOperatorFieldGetBasis(op_fields[i], &basis));
75248acf710SJeremy L Thompson         CeedCallBackend(CeedQFunctionFieldGetSize(qf_fields[i], &size));
75348acf710SJeremy L Thompson         CeedCallBackend(CeedBasisGetNumNodes(basis, &P));
75448acf710SJeremy L Thompson         CeedCallBackend(CeedBasisGetNumComponents(basis, &num_comp));
75548acf710SJeremy L Thompson         e_size = (CeedSize)P * num_comp;
75648acf710SJeremy L Thompson         CeedCallBackend(CeedVectorCreate(ceed, e_size, &e_vecs[i]));
75748acf710SJeremy L Thompson         q_size = (CeedSize)max_num_points * size;
75848acf710SJeremy L Thompson         CeedCallBackend(CeedVectorCreate(ceed, q_size, &q_vecs[i]));
759681d0ea7SJeremy L Thompson         CeedCallBackend(CeedBasisDestroy(&basis));
76048acf710SJeremy L Thompson         break;
76148acf710SJeremy L Thompson       case CEED_EVAL_WEIGHT:  // Only on input fields
76248acf710SJeremy L Thompson         CeedCallBackend(CeedOperatorFieldGetBasis(op_fields[i], &basis));
76348acf710SJeremy L Thompson         q_size = (CeedSize)max_num_points;
76448acf710SJeremy L Thompson         CeedCallBackend(CeedVectorCreate(ceed, q_size, &q_vecs[i]));
76548acf710SJeremy L Thompson         CeedCallBackend(
766fc0f7cc6SJeremy L Thompson             CeedBasisApplyAtPoints(basis, 1, &max_num_points, CEED_NOTRANSPOSE, CEED_EVAL_WEIGHT, CEED_VECTOR_NONE, CEED_VECTOR_NONE, q_vecs[i]));
767681d0ea7SJeremy L Thompson         CeedCallBackend(CeedBasisDestroy(&basis));
76848acf710SJeremy L Thompson         break;
76948acf710SJeremy L Thompson     }
770ecc797dfSJeremy L Thompson     // Initialize full arrays for E-vectors and Q-vectors
771297a0f46SJeremy L Thompson     if (e_vecs[i]) CeedCallBackend(CeedVectorSetValue(e_vecs[i], 0.0));
772297a0f46SJeremy L Thompson     if (eval_mode != CEED_EVAL_WEIGHT) CeedCallBackend(CeedVectorSetValue(q_vecs[i], 0.0));
77348acf710SJeremy L Thompson   }
774f8a0df59SJeremy L Thompson   // Drop duplicate restrictions
7753aab95c0SJeremy L Thompson   if (is_input) {
7763aab95c0SJeremy L Thompson     for (CeedInt i = 0; i < num_fields; i++) {
7773aab95c0SJeremy L Thompson       CeedVector          vec_i;
7783aab95c0SJeremy L Thompson       CeedElemRestriction rstr_i;
7793aab95c0SJeremy L Thompson 
7803aab95c0SJeremy L Thompson       CeedCallBackend(CeedOperatorFieldGetVector(op_fields[i], &vec_i));
7813aab95c0SJeremy L Thompson       CeedCallBackend(CeedOperatorFieldGetElemRestriction(op_fields[i], &rstr_i));
7823aab95c0SJeremy L Thompson       for (CeedInt j = i + 1; j < num_fields; j++) {
7833aab95c0SJeremy L Thompson         CeedVector          vec_j;
7843aab95c0SJeremy L Thompson         CeedElemRestriction rstr_j;
7853aab95c0SJeremy L Thompson 
7863aab95c0SJeremy L Thompson         CeedCallBackend(CeedOperatorFieldGetVector(op_fields[j], &vec_j));
7873aab95c0SJeremy L Thompson         CeedCallBackend(CeedOperatorFieldGetElemRestriction(op_fields[j], &rstr_j));
7883aab95c0SJeremy L Thompson         if (vec_i == vec_j && rstr_i == rstr_j) {
7893aab95c0SJeremy L Thompson           CeedCallBackend(CeedVectorReferenceCopy(e_vecs[i], &e_vecs[j]));
790f8a0df59SJeremy L Thompson           CeedCallBackend(CeedVectorReferenceCopy(e_vecs_full[i + start_e], &e_vecs_full[j + start_e]));
7913aab95c0SJeremy L Thompson           skip_rstr[j] = true;
7923aab95c0SJeremy L Thompson         }
793681d0ea7SJeremy L Thompson         CeedCallBackend(CeedVectorDestroy(&vec_j));
794681d0ea7SJeremy L Thompson         CeedCallBackend(CeedElemRestrictionDestroy(&rstr_j));
7953aab95c0SJeremy L Thompson       }
796681d0ea7SJeremy L Thompson       CeedCallBackend(CeedVectorDestroy(&vec_i));
797681d0ea7SJeremy L Thompson       CeedCallBackend(CeedElemRestrictionDestroy(&rstr_i));
7983aab95c0SJeremy L Thompson     }
799f8a0df59SJeremy L Thompson   } else {
800f8a0df59SJeremy L Thompson     for (CeedInt i = num_fields - 1; i >= 0; i--) {
801f8a0df59SJeremy L Thompson       CeedVector          vec_i;
802f8a0df59SJeremy L Thompson       CeedElemRestriction rstr_i;
803f8a0df59SJeremy L Thompson 
804f8a0df59SJeremy L Thompson       CeedCallBackend(CeedOperatorFieldGetVector(op_fields[i], &vec_i));
805f8a0df59SJeremy L Thompson       CeedCallBackend(CeedOperatorFieldGetElemRestriction(op_fields[i], &rstr_i));
806f8a0df59SJeremy L Thompson       for (CeedInt j = i - 1; j >= 0; j--) {
807f8a0df59SJeremy L Thompson         CeedVector          vec_j;
808f8a0df59SJeremy L Thompson         CeedElemRestriction rstr_j;
809f8a0df59SJeremy L Thompson 
810f8a0df59SJeremy L Thompson         CeedCallBackend(CeedOperatorFieldGetVector(op_fields[j], &vec_j));
811f8a0df59SJeremy L Thompson         CeedCallBackend(CeedOperatorFieldGetElemRestriction(op_fields[j], &rstr_j));
812f8a0df59SJeremy L Thompson         if (vec_i == vec_j && rstr_i == rstr_j) {
813f8a0df59SJeremy L Thompson           CeedCallBackend(CeedVectorReferenceCopy(e_vecs[i], &e_vecs[j]));
814f8a0df59SJeremy L Thompson           CeedCallBackend(CeedVectorReferenceCopy(e_vecs_full[i + start_e], &e_vecs_full[j + start_e]));
815f8a0df59SJeremy L Thompson           skip_rstr[j]       = true;
816f8a0df59SJeremy L Thompson           apply_add_basis[i] = true;
817f8a0df59SJeremy L Thompson         }
818681d0ea7SJeremy L Thompson         CeedCallBackend(CeedVectorDestroy(&vec_j));
819681d0ea7SJeremy L Thompson         CeedCallBackend(CeedElemRestrictionDestroy(&rstr_j));
820f8a0df59SJeremy L Thompson       }
821681d0ea7SJeremy L Thompson       CeedCallBackend(CeedVectorDestroy(&vec_i));
822681d0ea7SJeremy L Thompson       CeedCallBackend(CeedElemRestrictionDestroy(&rstr_i));
823f8a0df59SJeremy L Thompson     }
8243aab95c0SJeremy L Thompson   }
8259bc66399SJeremy L Thompson   CeedCallBackend(CeedDestroy(&ceed));
82648acf710SJeremy L Thompson   return CEED_ERROR_SUCCESS;
82748acf710SJeremy L Thompson }
82848acf710SJeremy L Thompson 
82948acf710SJeremy L Thompson //------------------------------------------------------------------------------
83048acf710SJeremy L Thompson // Setup Operator
83148acf710SJeremy L Thompson //------------------------------------------------------------------------------
83248acf710SJeremy L Thompson static int CeedOperatorSetupAtPoints_Ref(CeedOperator op) {
83348acf710SJeremy L Thompson   bool                is_setup_done;
83448acf710SJeremy L Thompson   CeedInt             Q, num_input_fields, num_output_fields;
83548acf710SJeremy L Thompson   CeedQFunctionField *qf_input_fields, *qf_output_fields;
83648acf710SJeremy L Thompson   CeedQFunction       qf;
83748acf710SJeremy L Thompson   CeedOperatorField  *op_input_fields, *op_output_fields;
83848acf710SJeremy L Thompson   CeedOperator_Ref   *impl;
83948acf710SJeremy L Thompson 
84048acf710SJeremy L Thompson   CeedCallBackend(CeedOperatorIsSetupDone(op, &is_setup_done));
84148acf710SJeremy L Thompson   if (is_setup_done) return CEED_ERROR_SUCCESS;
84248acf710SJeremy L Thompson 
84348acf710SJeremy L Thompson   CeedCallBackend(CeedOperatorGetData(op, &impl));
84448acf710SJeremy L Thompson   CeedCallBackend(CeedOperatorGetQFunction(op, &qf));
84548acf710SJeremy L Thompson   CeedCallBackend(CeedOperatorGetNumQuadraturePoints(op, &Q));
84648acf710SJeremy L Thompson   CeedCallBackend(CeedQFunctionIsIdentity(qf, &impl->is_identity_qf));
84748acf710SJeremy L Thompson   CeedCallBackend(CeedOperatorGetFields(op, &num_input_fields, &op_input_fields, &num_output_fields, &op_output_fields));
84848acf710SJeremy L Thompson   CeedCallBackend(CeedQFunctionGetFields(qf, NULL, &qf_input_fields, NULL, &qf_output_fields));
84948acf710SJeremy L Thompson 
85048acf710SJeremy L Thompson   // Allocate
85148acf710SJeremy L Thompson   CeedCallBackend(CeedCalloc(num_input_fields + num_output_fields, &impl->e_vecs_full));
85248acf710SJeremy L Thompson 
8533aab95c0SJeremy L Thompson   CeedCallBackend(CeedCalloc(CEED_FIELD_MAX, &impl->skip_rstr_in));
854f8a0df59SJeremy L Thompson   CeedCallBackend(CeedCalloc(CEED_FIELD_MAX, &impl->skip_rstr_out));
855f8a0df59SJeremy L Thompson   CeedCallBackend(CeedCalloc(CEED_FIELD_MAX, &impl->apply_add_basis_out));
85648acf710SJeremy L Thompson   CeedCallBackend(CeedCalloc(CEED_FIELD_MAX, &impl->input_states));
85748acf710SJeremy L Thompson   CeedCallBackend(CeedCalloc(CEED_FIELD_MAX, &impl->e_vecs_in));
85848acf710SJeremy L Thompson   CeedCallBackend(CeedCalloc(CEED_FIELD_MAX, &impl->e_vecs_out));
85948acf710SJeremy L Thompson   CeedCallBackend(CeedCalloc(CEED_FIELD_MAX, &impl->q_vecs_in));
86048acf710SJeremy L Thompson   CeedCallBackend(CeedCalloc(CEED_FIELD_MAX, &impl->q_vecs_out));
86148acf710SJeremy L Thompson 
86248acf710SJeremy L Thompson   impl->num_inputs  = num_input_fields;
86348acf710SJeremy L Thompson   impl->num_outputs = num_output_fields;
86448acf710SJeremy L Thompson 
86548acf710SJeremy L Thompson   // Set up infield and outfield pointer arrays
86648acf710SJeremy L Thompson   // Infields
867f8a0df59SJeremy L Thompson   CeedCallBackend(CeedOperatorSetupFieldsAtPoints_Ref(qf, op, true, impl->skip_rstr_in, NULL, impl->e_vecs_full, impl->e_vecs_in, impl->q_vecs_in, 0,
8683aab95c0SJeremy L Thompson                                                       num_input_fields, Q));
86948acf710SJeremy L Thompson   // Outfields
870f8a0df59SJeremy L Thompson   CeedCallBackend(CeedOperatorSetupFieldsAtPoints_Ref(qf, op, false, impl->skip_rstr_out, impl->apply_add_basis_out, impl->e_vecs_full,
871f8a0df59SJeremy L Thompson                                                       impl->e_vecs_out, impl->q_vecs_out, num_input_fields, num_output_fields, Q));
87248acf710SJeremy L Thompson 
87348acf710SJeremy L Thompson   // Identity QFunctions
87448acf710SJeremy L Thompson   if (impl->is_identity_qf) {
87548acf710SJeremy L Thompson     CeedCallBackend(CeedVectorReferenceCopy(impl->q_vecs_in[0], &impl->q_vecs_out[0]));
87638e83183SJeremy L Thompson     CeedCallBackend(CeedVectorReferenceCopy(impl->q_vecs_in[0], &impl->e_vecs_out[0]));
87748acf710SJeremy L Thompson   }
87848acf710SJeremy L Thompson 
87948acf710SJeremy L Thompson   CeedCallBackend(CeedOperatorSetSetupDone(op));
880c11e12f4SJeremy L Thompson   CeedCallBackend(CeedQFunctionDestroy(&qf));
88148acf710SJeremy L Thompson   return CEED_ERROR_SUCCESS;
88248acf710SJeremy L Thompson }
88348acf710SJeremy L Thompson 
88448acf710SJeremy L Thompson //------------------------------------------------------------------------------
88548acf710SJeremy L Thompson // Input Basis Action
88648acf710SJeremy L Thompson //------------------------------------------------------------------------------
88748acf710SJeremy L Thompson static inline int CeedOperatorInputBasisAtPoints_Ref(CeedInt e, CeedInt num_points_offset, CeedInt num_points, CeedQFunctionField *qf_input_fields,
88848acf710SJeremy L Thompson                                                      CeedOperatorField *op_input_fields, CeedInt num_input_fields, CeedVector in_vec,
88948fdef17SJeremy L Thompson                                                      CeedVector point_coords_elem, bool skip_active, bool skip_passive,
89048fdef17SJeremy L Thompson                                                      CeedScalar *e_data[2 * CEED_FIELD_MAX], CeedOperator_Ref *impl, CeedRequest *request) {
89148acf710SJeremy L Thompson   for (CeedInt i = 0; i < num_input_fields; i++) {
892681d0ea7SJeremy L Thompson     bool                is_active;
89348acf710SJeremy L Thompson     CeedInt             elem_size, size, num_comp;
89448acf710SJeremy L Thompson     CeedRestrictionType rstr_type;
89548acf710SJeremy L Thompson     CeedEvalMode        eval_mode;
89648acf710SJeremy L Thompson     CeedVector          vec;
89748acf710SJeremy L Thompson     CeedElemRestriction elem_rstr;
89848acf710SJeremy L Thompson     CeedBasis           basis;
89948acf710SJeremy L Thompson 
90048acf710SJeremy L Thompson     // Skip active input
901681d0ea7SJeremy L Thompson     CeedCallBackend(CeedOperatorFieldGetVector(op_input_fields[i], &vec));
902681d0ea7SJeremy L Thompson     is_active = vec == CEED_VECTOR_ACTIVE;
903681d0ea7SJeremy L Thompson     CeedCallBackend(CeedVectorDestroy(&vec));
904681d0ea7SJeremy L Thompson     if (skip_active && is_active) continue;
90548fdef17SJeremy L Thompson     if (skip_passive && !is_active) continue;
90648acf710SJeremy L Thompson 
90748acf710SJeremy L Thompson     // Get elem_size, eval_mode, size
90848acf710SJeremy L Thompson     CeedCallBackend(CeedOperatorFieldGetElemRestriction(op_input_fields[i], &elem_rstr));
90948acf710SJeremy L Thompson     CeedCallBackend(CeedElemRestrictionGetType(elem_rstr, &rstr_type));
91048acf710SJeremy L Thompson     CeedCallBackend(CeedQFunctionFieldGetEvalMode(qf_input_fields[i], &eval_mode));
91148acf710SJeremy L Thompson     CeedCallBackend(CeedQFunctionFieldGetSize(qf_input_fields[i], &size));
91248acf710SJeremy L Thompson     // Restrict block active input
91348fdef17SJeremy L Thompson     // When skipping passive inputs, we're doing assembly and should not restrict
91448fdef17SJeremy L Thompson     if (is_active && !impl->skip_rstr_in[i] && !skip_passive) {
91548acf710SJeremy L Thompson       if (rstr_type == CEED_RESTRICTION_POINTS) {
91648acf710SJeremy L Thompson         CeedCallBackend(CeedElemRestrictionApplyAtPointsInElement(elem_rstr, e, CEED_NOTRANSPOSE, in_vec, impl->e_vecs_in[i], request));
91748acf710SJeremy L Thompson       } else {
91848acf710SJeremy L Thompson         CeedCallBackend(CeedElemRestrictionApplyBlock(elem_rstr, e, CEED_NOTRANSPOSE, in_vec, impl->e_vecs_in[i], request));
91948acf710SJeremy L Thompson       }
92048acf710SJeremy L Thompson     }
92148acf710SJeremy L Thompson     // Basis action
92248acf710SJeremy L Thompson     switch (eval_mode) {
92348acf710SJeremy L Thompson       case CEED_EVAL_NONE:
924681d0ea7SJeremy L Thompson         if (!is_active) {
92548acf710SJeremy L Thompson           CeedCallBackend(CeedVectorSetArray(impl->q_vecs_in[i], CEED_MEM_HOST, CEED_USE_POINTER, &e_data[i][num_points_offset * size]));
92648acf710SJeremy L Thompson         }
92748acf710SJeremy L Thompson         break;
92848acf710SJeremy L Thompson       // Note - these basis eval modes require FEM fields
92948acf710SJeremy L Thompson       case CEED_EVAL_INTERP:
93048acf710SJeremy L Thompson       case CEED_EVAL_GRAD:
93148acf710SJeremy L Thompson       case CEED_EVAL_DIV:
93248acf710SJeremy L Thompson       case CEED_EVAL_CURL:
93348acf710SJeremy L Thompson         CeedCallBackend(CeedOperatorFieldGetBasis(op_input_fields[i], &basis));
934681d0ea7SJeremy L Thompson         if (!is_active) {
93548acf710SJeremy L Thompson           CeedCallBackend(CeedBasisGetNumComponents(basis, &num_comp));
93648acf710SJeremy L Thompson           CeedCallBackend(CeedElemRestrictionGetElementSize(elem_rstr, &elem_size));
93781670346SSebastian Grimberg           CeedCallBackend(CeedVectorSetArray(impl->e_vecs_in[i], CEED_MEM_HOST, CEED_USE_POINTER, &e_data[i][(CeedSize)e * elem_size * num_comp]));
93848acf710SJeremy L Thompson         }
93948acf710SJeremy L Thompson         CeedCallBackend(
940fc0f7cc6SJeremy L Thompson             CeedBasisApplyAtPoints(basis, 1, &num_points, CEED_NOTRANSPOSE, eval_mode, point_coords_elem, impl->e_vecs_in[i], impl->q_vecs_in[i]));
941681d0ea7SJeremy L Thompson         CeedCallBackend(CeedBasisDestroy(&basis));
94248acf710SJeremy L Thompson         break;
94348acf710SJeremy L Thompson       case CEED_EVAL_WEIGHT:
94448acf710SJeremy L Thompson         break;  // No action
94548acf710SJeremy L Thompson     }
946681d0ea7SJeremy L Thompson     CeedCallBackend(CeedElemRestrictionDestroy(&elem_rstr));
94748acf710SJeremy L Thompson   }
94848acf710SJeremy L Thompson   return CEED_ERROR_SUCCESS;
94948acf710SJeremy L Thompson }
95048acf710SJeremy L Thompson 
95148acf710SJeremy L Thompson //------------------------------------------------------------------------------
95248acf710SJeremy L Thompson // Output Basis Action
95348acf710SJeremy L Thompson //------------------------------------------------------------------------------
95448acf710SJeremy L Thompson static inline int CeedOperatorOutputBasisAtPoints_Ref(CeedInt e, CeedInt num_points_offset, CeedInt num_points, CeedQFunctionField *qf_output_fields,
95548acf710SJeremy L Thompson                                                       CeedOperatorField *op_output_fields, CeedInt num_input_fields, CeedInt num_output_fields,
956f8a0df59SJeremy L Thompson                                                       bool *apply_add_basis, bool *skip_rstr, CeedOperator op, CeedVector out_vec,
95748fdef17SJeremy L Thompson                                                       CeedVector point_coords_elem, bool skip_passive, CeedOperator_Ref *impl, CeedRequest *request) {
95848acf710SJeremy L Thompson   for (CeedInt i = 0; i < num_output_fields; i++) {
959681d0ea7SJeremy L Thompson     bool                is_active;
96048acf710SJeremy L Thompson     CeedRestrictionType rstr_type;
96148acf710SJeremy L Thompson     CeedEvalMode        eval_mode;
96248acf710SJeremy L Thompson     CeedVector          vec;
96348acf710SJeremy L Thompson     CeedElemRestriction elem_rstr;
96448acf710SJeremy L Thompson     CeedBasis           basis;
96548acf710SJeremy L Thompson 
96648fdef17SJeremy L Thompson     // Skip active input
96748fdef17SJeremy L Thompson     CeedCallBackend(CeedOperatorFieldGetVector(op_output_fields[i], &vec));
96848fdef17SJeremy L Thompson     is_active = vec == CEED_VECTOR_ACTIVE;
96948fdef17SJeremy L Thompson     CeedCallBackend(CeedVectorDestroy(&vec));
97048fdef17SJeremy L Thompson     if (skip_passive && !is_active) continue;
97148fdef17SJeremy L Thompson 
97248acf710SJeremy L Thompson     // Get elem_size, eval_mode, size
97348acf710SJeremy L Thompson     CeedCallBackend(CeedOperatorFieldGetElemRestriction(op_output_fields[i], &elem_rstr));
97448acf710SJeremy L Thompson     CeedCallBackend(CeedQFunctionFieldGetEvalMode(qf_output_fields[i], &eval_mode));
97548acf710SJeremy L Thompson     // Basis action
97648acf710SJeremy L Thompson     switch (eval_mode) {
97748acf710SJeremy L Thompson       case CEED_EVAL_NONE:
97848acf710SJeremy L Thompson         break;  // No action
97948acf710SJeremy L Thompson       case CEED_EVAL_INTERP:
98048acf710SJeremy L Thompson       case CEED_EVAL_GRAD:
98148acf710SJeremy L Thompson       case CEED_EVAL_DIV:
98248acf710SJeremy L Thompson       case CEED_EVAL_CURL:
98348acf710SJeremy L Thompson         CeedCallBackend(CeedOperatorFieldGetBasis(op_output_fields[i], &basis));
984f8a0df59SJeremy L Thompson         if (apply_add_basis[i]) {
985f8a0df59SJeremy L Thompson           CeedCallBackend(CeedBasisApplyAddAtPoints(basis, 1, &num_points, CEED_TRANSPOSE, eval_mode, point_coords_elem, impl->q_vecs_out[i],
986f8a0df59SJeremy L Thompson                                                     impl->e_vecs_out[i]));
987f8a0df59SJeremy L Thompson         } else {
98848acf710SJeremy L Thompson           CeedCallBackend(
989fc0f7cc6SJeremy L Thompson               CeedBasisApplyAtPoints(basis, 1, &num_points, CEED_TRANSPOSE, eval_mode, point_coords_elem, impl->q_vecs_out[i], impl->e_vecs_out[i]));
990f8a0df59SJeremy L Thompson         }
991681d0ea7SJeremy L Thompson         CeedCallBackend(CeedBasisDestroy(&basis));
99248acf710SJeremy L Thompson         break;
99348acf710SJeremy L Thompson       // LCOV_EXCL_START
99448acf710SJeremy L Thompson       case CEED_EVAL_WEIGHT: {
9956e536b99SJeremy L Thompson         return CeedError(CeedOperatorReturnCeed(op), CEED_ERROR_BACKEND, "CEED_EVAL_WEIGHT cannot be an output evaluation mode");
99648acf710SJeremy L Thompson         // LCOV_EXCL_STOP
99748acf710SJeremy L Thompson       }
99848acf710SJeremy L Thompson     }
99948acf710SJeremy L Thompson     // Restrict output block
100048fdef17SJeremy L Thompson     // When skipping passive outputs, we're doing assembly and should not restrict
100148fdef17SJeremy L Thompson     if (skip_rstr[i] || skip_passive) {
1002bbac207aSZach Atkins       CeedCallBackend(CeedElemRestrictionDestroy(&elem_rstr));
1003bbac207aSZach Atkins       continue;
1004bbac207aSZach Atkins     }
1005bbac207aSZach Atkins 
100648acf710SJeremy L Thompson     // Get output vector
100748acf710SJeremy L Thompson     CeedCallBackend(CeedElemRestrictionGetType(elem_rstr, &rstr_type));
100848acf710SJeremy L Thompson     CeedCallBackend(CeedOperatorFieldGetVector(op_output_fields[i], &vec));
1009681d0ea7SJeremy L Thompson     if (is_active) vec = out_vec;
101048acf710SJeremy L Thompson     // Restrict
101148acf710SJeremy L Thompson     if (rstr_type == CEED_RESTRICTION_POINTS) {
101248acf710SJeremy L Thompson       CeedCallBackend(CeedElemRestrictionApplyAtPointsInElement(elem_rstr, e, CEED_TRANSPOSE, impl->e_vecs_out[i], vec, request));
101348acf710SJeremy L Thompson     } else {
101448acf710SJeremy L Thompson       CeedCallBackend(CeedElemRestrictionApplyBlock(elem_rstr, e, CEED_TRANSPOSE, impl->e_vecs_out[i], vec, request));
101548acf710SJeremy L Thompson     }
1016681d0ea7SJeremy L Thompson     if (!is_active) CeedCallBackend(CeedVectorDestroy(&vec));
1017681d0ea7SJeremy L Thompson     CeedCallBackend(CeedElemRestrictionDestroy(&elem_rstr));
101848acf710SJeremy L Thompson   }
101948acf710SJeremy L Thompson   return CEED_ERROR_SUCCESS;
102048acf710SJeremy L Thompson }
102148acf710SJeremy L Thompson 
102248acf710SJeremy L Thompson //------------------------------------------------------------------------------
102348acf710SJeremy L Thompson // Operator Apply
102448acf710SJeremy L Thompson //------------------------------------------------------------------------------
102548acf710SJeremy L Thompson static int CeedOperatorApplyAddAtPoints_Ref(CeedOperator op, CeedVector in_vec, CeedVector out_vec, CeedRequest *request) {
102648acf710SJeremy L Thompson   CeedInt             num_points_offset          = 0, num_input_fields, num_output_fields, num_elem;
102748acf710SJeremy L Thompson   CeedScalar         *e_data[2 * CEED_FIELD_MAX] = {0};
102848acf710SJeremy L Thompson   CeedVector          point_coords               = NULL;
102948acf710SJeremy L Thompson   CeedElemRestriction rstr_points                = NULL;
103048acf710SJeremy L Thompson   CeedQFunctionField *qf_input_fields, *qf_output_fields;
103148acf710SJeremy L Thompson   CeedQFunction       qf;
103248acf710SJeremy L Thompson   CeedOperatorField  *op_input_fields, *op_output_fields;
103348acf710SJeremy L Thompson   CeedOperator_Ref   *impl;
103448acf710SJeremy L Thompson 
103548acf710SJeremy L Thompson   CeedCallBackend(CeedOperatorGetData(op, &impl));
103648acf710SJeremy L Thompson   CeedCallBackend(CeedOperatorGetNumElements(op, &num_elem));
103748acf710SJeremy L Thompson   CeedCallBackend(CeedOperatorGetQFunction(op, &qf));
103848acf710SJeremy L Thompson   CeedCallBackend(CeedOperatorGetFields(op, &num_input_fields, &op_input_fields, &num_output_fields, &op_output_fields));
103948acf710SJeremy L Thompson   CeedCallBackend(CeedQFunctionGetFields(qf, NULL, &qf_input_fields, NULL, &qf_output_fields));
104048acf710SJeremy L Thompson 
104148acf710SJeremy L Thompson   // Setup
104248acf710SJeremy L Thompson   CeedCallBackend(CeedOperatorSetupAtPoints_Ref(op));
104348acf710SJeremy L Thompson 
104448acf710SJeremy L Thompson   // Point coordinates
104548acf710SJeremy L Thompson   CeedCallBackend(CeedOperatorAtPointsGetPoints(op, &rstr_points, &point_coords));
104648acf710SJeremy L Thompson 
104748acf710SJeremy L Thompson   // Input Evecs and Restriction
10486cde1da6SZach Atkins   CeedCallBackend(CeedOperatorSetupInputs_Ref(num_input_fields, qf_input_fields, op_input_fields, NULL, true, e_data, impl, request));
104948acf710SJeremy L Thompson 
105048acf710SJeremy L Thompson   // Loop through elements
105148acf710SJeremy L Thompson   for (CeedInt e = 0; e < num_elem; e++) {
105248acf710SJeremy L Thompson     CeedInt num_points;
105348acf710SJeremy L Thompson 
105448acf710SJeremy L Thompson     // Setup points for element
105548acf710SJeremy L Thompson     CeedCallBackend(CeedElemRestrictionApplyAtPointsInElement(rstr_points, e, CEED_NOTRANSPOSE, point_coords, impl->point_coords_elem, request));
105648acf710SJeremy L Thompson     CeedCallBackend(CeedElemRestrictionGetNumPointsInElement(rstr_points, e, &num_points));
1057*de5bf46bSZach Atkins     if (num_points < 1) continue;
105848acf710SJeremy L Thompson 
105948acf710SJeremy L Thompson     // Input basis apply
106048acf710SJeremy L Thompson     CeedCallBackend(CeedOperatorInputBasisAtPoints_Ref(e, num_points_offset, num_points, qf_input_fields, op_input_fields, num_input_fields, in_vec,
106148fdef17SJeremy L Thompson                                                        impl->point_coords_elem, false, false, e_data, impl, request));
106248acf710SJeremy L Thompson 
106348acf710SJeremy L Thompson     // Q function
106448acf710SJeremy L Thompson     if (!impl->is_identity_qf) {
106548acf710SJeremy L Thompson       CeedCallBackend(CeedQFunctionApply(qf, num_points, impl->q_vecs_in, impl->q_vecs_out));
106648acf710SJeremy L Thompson     }
106748acf710SJeremy L Thompson 
106848acf710SJeremy L Thompson     // Output basis apply and restriction
106948acf710SJeremy L Thompson     CeedCallBackend(CeedOperatorOutputBasisAtPoints_Ref(e, num_points_offset, num_points, qf_output_fields, op_output_fields, num_input_fields,
1070f8a0df59SJeremy L Thompson                                                         num_output_fields, impl->apply_add_basis_out, impl->skip_rstr_out, op, out_vec,
107148fdef17SJeremy L Thompson                                                         impl->point_coords_elem, false, impl, request));
107248acf710SJeremy L Thompson 
107348acf710SJeremy L Thompson     num_points_offset += num_points;
107448acf710SJeremy L Thompson   }
107548acf710SJeremy L Thompson 
107648acf710SJeremy L Thompson   // Restore input arrays
10776cde1da6SZach Atkins   CeedCallBackend(CeedOperatorRestoreInputs_Ref(num_input_fields, qf_input_fields, op_input_fields, true, e_data, impl));
107848acf710SJeremy L Thompson 
107948acf710SJeremy L Thompson   // Cleanup point coordinates
108048acf710SJeremy L Thompson   CeedCallBackend(CeedVectorDestroy(&point_coords));
108148acf710SJeremy L Thompson   CeedCallBackend(CeedElemRestrictionDestroy(&rstr_points));
1082c11e12f4SJeremy L Thompson   CeedCallBackend(CeedQFunctionDestroy(&qf));
108348acf710SJeremy L Thompson   return CEED_ERROR_SUCCESS;
108448acf710SJeremy L Thompson }
108548acf710SJeremy L Thompson 
108648acf710SJeremy L Thompson //------------------------------------------------------------------------------
1087e13f2367SZach Atkins // Core code for assembling linear QFunction
1088e13f2367SZach Atkins //------------------------------------------------------------------------------
1089e13f2367SZach Atkins static inline int CeedOperatorLinearAssembleQFunctionAtPointsCore_Ref(CeedOperator op, bool build_objects, CeedVector *assembled,
1090e13f2367SZach Atkins                                                                       CeedElemRestriction *rstr, CeedRequest *request) {
1091e13f2367SZach Atkins   Ceed                ceed;
1092ff8551c5SJeremy L Thompson   CeedInt             qf_size_in, qf_size_out, max_num_points, num_elem, num_input_fields, num_output_fields, num_points_offset = 0;
1093e13f2367SZach Atkins   CeedScalar         *assembled_array, *e_data_full[2 * CEED_FIELD_MAX] = {NULL};
1094c7b67790SJeremy L Thompson   CeedVector          point_coords = NULL;
1095e13f2367SZach Atkins   CeedQFunctionField *qf_input_fields, *qf_output_fields;
1096e13f2367SZach Atkins   CeedQFunction       qf;
1097e13f2367SZach Atkins   CeedOperatorField  *op_input_fields, *op_output_fields;
1098e13f2367SZach Atkins   CeedOperator_Ref   *impl;
1099e13f2367SZach Atkins   CeedElemRestriction rstr_points = NULL;
1100e13f2367SZach Atkins 
1101e13f2367SZach Atkins   CeedCallBackend(CeedOperatorGetCeed(op, &ceed));
1102e13f2367SZach Atkins   CeedCallBackend(CeedOperatorGetData(op, &impl));
1103ff8551c5SJeremy L Thompson   qf_size_in  = impl->qf_size_in;
1104ff8551c5SJeremy L Thompson   qf_size_out = impl->qf_size_out;
1105e13f2367SZach Atkins   CeedCallBackend(CeedOperatorGetQFunction(op, &qf));
1106e13f2367SZach Atkins   CeedCallBackend(CeedOperatorGetNumElements(op, &num_elem));
1107e13f2367SZach Atkins   CeedCallBackend(CeedQFunctionGetFields(qf, NULL, &qf_input_fields, NULL, &qf_output_fields));
1108e13f2367SZach Atkins   CeedCallBackend(CeedOperatorGetFields(op, &num_input_fields, &op_input_fields, &num_output_fields, &op_output_fields));
1109e13f2367SZach Atkins 
1110e13f2367SZach Atkins   // Setup
1111e13f2367SZach Atkins   CeedCallBackend(CeedOperatorSetupAtPoints_Ref(op));
1112e13f2367SZach Atkins 
1113e13f2367SZach Atkins   // Check for restriction only operator
1114e13f2367SZach Atkins   CeedCheck(!impl->is_identity_rstr_op, ceed, CEED_ERROR_BACKEND, "Assembling restriction only operators is not supported");
1115e13f2367SZach Atkins 
1116e13f2367SZach Atkins   // Point coordinates
1117e13f2367SZach Atkins   CeedCallBackend(CeedOperatorAtPointsGetPoints(op, &rstr_points, &point_coords));
1118e13f2367SZach Atkins   CeedCallBackend(CeedElemRestrictionGetMaxPointsInElement(rstr_points, &max_num_points));
1119e13f2367SZach Atkins 
1120e13f2367SZach Atkins   // Input Evecs and Restriction
1121e13f2367SZach Atkins   CeedCallBackend(CeedOperatorSetupInputs_Ref(num_input_fields, qf_input_fields, op_input_fields, NULL, true, e_data_full, impl, request));
1122e13f2367SZach Atkins 
1123e13f2367SZach Atkins   // Count number of active input fields
1124ff8551c5SJeremy L Thompson   if (qf_size_in == 0) {
1125e13f2367SZach Atkins     for (CeedInt i = 0; i < num_input_fields; i++) {
1126e13f2367SZach Atkins       CeedInt    field_size;
1127e13f2367SZach Atkins       CeedVector vec;
1128e13f2367SZach Atkins 
1129e13f2367SZach Atkins       // Get input vector
1130e13f2367SZach Atkins       CeedCallBackend(CeedOperatorFieldGetVector(op_input_fields[i], &vec));
1131e13f2367SZach Atkins       // Check if active input
1132e13f2367SZach Atkins       if (vec == CEED_VECTOR_ACTIVE) {
1133e13f2367SZach Atkins         // Check that all active inputs are nodal fields
1134e13f2367SZach Atkins         {
1135e13f2367SZach Atkins           CeedElemRestriction elem_rstr;
1136e13f2367SZach Atkins           bool                is_at_points = false;
1137e13f2367SZach Atkins 
1138e13f2367SZach Atkins           CeedCallBackend(CeedOperatorFieldGetElemRestriction(op_input_fields[i], &elem_rstr));
1139637baffdSJeremy L Thompson           CeedCallBackend(CeedElemRestrictionIsAtPoints(elem_rstr, &is_at_points));
1140681d0ea7SJeremy L Thompson           CeedCallBackend(CeedElemRestrictionDestroy(&elem_rstr));
1141e13f2367SZach Atkins           CeedCheck(!is_at_points, ceed, CEED_ERROR_BACKEND, "Cannot assemble QFunction with active input at points");
1142e13f2367SZach Atkins         }
1143e13f2367SZach Atkins         // Get size of active input
1144e13f2367SZach Atkins         CeedCallBackend(CeedQFunctionFieldGetSize(qf_input_fields[i], &field_size));
1145ff8551c5SJeremy L Thompson         qf_size_in += field_size;
1146e13f2367SZach Atkins       }
1147681d0ea7SJeremy L Thompson       CeedCallBackend(CeedVectorDestroy(&vec));
1148e13f2367SZach Atkins     }
1149ff8551c5SJeremy L Thompson     CeedCheck(qf_size_in, ceed, CEED_ERROR_BACKEND, "Cannot assemble QFunction without active inputs and outputs");
1150ff8551c5SJeremy L Thompson     impl->qf_size_in = qf_size_in;
1151e13f2367SZach Atkins   }
1152e13f2367SZach Atkins 
1153e13f2367SZach Atkins   // Count number of active output fields
1154ff8551c5SJeremy L Thompson   if (qf_size_out == 0) {
1155e13f2367SZach Atkins     for (CeedInt i = 0; i < num_output_fields; i++) {
1156e13f2367SZach Atkins       CeedInt    field_size;
1157c7b67790SJeremy L Thompson       CeedVector vec;
1158e13f2367SZach Atkins 
1159e13f2367SZach Atkins       // Get output vector
1160e13f2367SZach Atkins       CeedCallBackend(CeedOperatorFieldGetVector(op_output_fields[i], &vec));
1161e13f2367SZach Atkins       // Check if active output
1162e13f2367SZach Atkins       if (vec == CEED_VECTOR_ACTIVE) {
1163e13f2367SZach Atkins         // Check that all active inputs are nodal fields
1164e13f2367SZach Atkins         {
1165e13f2367SZach Atkins           CeedElemRestriction elem_rstr;
1166e13f2367SZach Atkins           bool                is_at_points = false;
1167e13f2367SZach Atkins 
1168e13f2367SZach Atkins           CeedCallBackend(CeedOperatorFieldGetElemRestriction(op_output_fields[i], &elem_rstr));
1169637baffdSJeremy L Thompson           CeedCallBackend(CeedElemRestrictionIsAtPoints(elem_rstr, &is_at_points));
1170681d0ea7SJeremy L Thompson           CeedCallBackend(CeedElemRestrictionDestroy(&elem_rstr));
1171e13f2367SZach Atkins           CeedCheck(!is_at_points, ceed, CEED_ERROR_BACKEND, "Cannot assemble QFunction with active input at points");
1172e13f2367SZach Atkins         }
1173e13f2367SZach Atkins         // Get size of active output
1174e13f2367SZach Atkins         CeedCallBackend(CeedQFunctionFieldGetSize(qf_output_fields[i], &field_size));
1175c7b67790SJeremy L Thompson         CeedCallBackend(CeedVectorSetValue(impl->q_vecs_in[i], 0.0));
1176ff8551c5SJeremy L Thompson         qf_size_out += field_size;
1177e13f2367SZach Atkins       }
1178681d0ea7SJeremy L Thompson       CeedCallBackend(CeedVectorDestroy(&vec));
1179e13f2367SZach Atkins     }
1180ff8551c5SJeremy L Thompson     CeedCheck(qf_size_out > 0, ceed, CEED_ERROR_BACKEND, "Cannot assemble QFunction without active inputs and outputs");
1181ff8551c5SJeremy L Thompson     impl->qf_size_out = qf_size_out;
1182e13f2367SZach Atkins   }
1183e13f2367SZach Atkins 
1184e13f2367SZach Atkins   // Build objects if needed
1185e13f2367SZach Atkins   if (build_objects) {
1186e13f2367SZach Atkins     CeedInt        num_points_total;
1187e13f2367SZach Atkins     const CeedInt *offsets;
1188e13f2367SZach Atkins 
1189e13f2367SZach Atkins     CeedCallBackend(CeedElemRestrictionGetNumPoints(rstr_points, &num_points_total));
1190e13f2367SZach Atkins 
1191e13f2367SZach Atkins     // Create output restriction (at points)
1192e13f2367SZach Atkins     CeedCallBackend(CeedElemRestrictionGetOffsets(rstr_points, CEED_MEM_HOST, &offsets));
1193ff8551c5SJeremy L Thompson     CeedCallBackend(CeedElemRestrictionCreateAtPoints(ceed, num_elem, num_points_total, qf_size_in * qf_size_out,
1194ff8551c5SJeremy L Thompson                                                       qf_size_in * qf_size_out * num_points_total, CEED_MEM_HOST, CEED_COPY_VALUES, offsets, rstr));
1195e13f2367SZach Atkins     CeedCallBackend(CeedElemRestrictionRestoreOffsets(rstr_points, &offsets));
1196e13f2367SZach Atkins 
1197e13f2367SZach Atkins     // Create assembled vector
1198e13f2367SZach Atkins     CeedCallBackend(CeedElemRestrictionCreateVector(*rstr, assembled, NULL));
1199e13f2367SZach Atkins   }
1200e13f2367SZach Atkins   // Clear output vector
1201e13f2367SZach Atkins   CeedCallBackend(CeedVectorSetValue(*assembled, 0.0));
1202e13f2367SZach Atkins   CeedCallBackend(CeedVectorGetArray(*assembled, CEED_MEM_HOST, &assembled_array));
1203e13f2367SZach Atkins 
1204e13f2367SZach Atkins   // Loop through elements
1205e13f2367SZach Atkins   for (CeedInt e = 0; e < num_elem; e++) {
1206e13f2367SZach Atkins     CeedInt num_points;
1207e13f2367SZach Atkins 
1208e13f2367SZach Atkins     // Setup points for element
1209e13f2367SZach Atkins     CeedCallBackend(CeedElemRestrictionApplyAtPointsInElement(rstr_points, e, CEED_NOTRANSPOSE, point_coords, impl->point_coords_elem, request));
1210e13f2367SZach Atkins     CeedCallBackend(CeedElemRestrictionGetNumPointsInElement(rstr_points, e, &num_points));
1211e13f2367SZach Atkins 
1212e13f2367SZach Atkins     // Input basis apply
1213e13f2367SZach Atkins     CeedCallBackend(CeedOperatorInputBasisAtPoints_Ref(e, num_points_offset, num_points, qf_input_fields, op_input_fields, num_input_fields, NULL,
121448fdef17SJeremy L Thompson                                                        impl->point_coords_elem, true, false, e_data_full, impl, request));
1215e13f2367SZach Atkins 
1216e13f2367SZach Atkins     // Assemble QFunction
1217c7b67790SJeremy L Thompson     for (CeedInt i = 0; i < num_input_fields; i++) {
1218681d0ea7SJeremy L Thompson       bool       is_active;
1219c7b67790SJeremy L Thompson       CeedInt    field_size;
1220c7b67790SJeremy L Thompson       CeedVector vec;
1221c7b67790SJeremy L Thompson 
1222c7b67790SJeremy L Thompson       // Get input vector
1223c7b67790SJeremy L Thompson       CeedCallBackend(CeedOperatorFieldGetVector(op_input_fields[i], &vec));
1224681d0ea7SJeremy L Thompson       is_active = vec == CEED_VECTOR_ACTIVE;
1225681d0ea7SJeremy L Thompson       CeedCallBackend(CeedVectorDestroy(&vec));
1226c7b67790SJeremy L Thompson       // Check if active input
1227681d0ea7SJeremy L Thompson       if (!is_active) continue;
1228c7b67790SJeremy L Thompson       // Get size of active input
1229c7b67790SJeremy L Thompson       CeedCallBackend(CeedQFunctionFieldGetSize(qf_input_fields[i], &field_size));
1230c7b67790SJeremy L Thompson       for (CeedInt field = 0; field < field_size; field++) {
1231c7b67790SJeremy L Thompson         // Set current portion of input to 1.0
1232c7b67790SJeremy L Thompson         {
1233c7b67790SJeremy L Thompson           CeedScalar *array;
1234c7b67790SJeremy L Thompson 
1235c7b67790SJeremy L Thompson           CeedCallBackend(CeedVectorGetArray(impl->q_vecs_in[i], CEED_MEM_HOST, &array));
1236c7b67790SJeremy L Thompson           for (CeedInt j = 0; j < num_points; j++) array[field * num_points + j] = 1.0;
1237c7b67790SJeremy L Thompson           CeedCallBackend(CeedVectorRestoreArray(impl->q_vecs_in[i], &array));
1238e13f2367SZach Atkins         }
1239c7b67790SJeremy L Thompson 
1240e13f2367SZach Atkins         if (!impl->is_identity_qf) {
1241e13f2367SZach Atkins           // Set Outputs
1242e13f2367SZach Atkins           for (CeedInt out = 0; out < num_output_fields; out++) {
1243e13f2367SZach Atkins             CeedVector vec;
1244e13f2367SZach Atkins             CeedInt    field_size;
1245e13f2367SZach Atkins 
1246e13f2367SZach Atkins             // Get output vector
1247e13f2367SZach Atkins             CeedCallBackend(CeedOperatorFieldGetVector(op_output_fields[out], &vec));
1248e13f2367SZach Atkins             // Check if active output
1249e13f2367SZach Atkins             if (vec == CEED_VECTOR_ACTIVE) {
1250e13f2367SZach Atkins               CeedCallBackend(CeedVectorSetArray(impl->q_vecs_out[out], CEED_MEM_HOST, CEED_USE_POINTER, assembled_array));
1251e13f2367SZach Atkins               CeedCallBackend(CeedQFunctionFieldGetSize(qf_output_fields[out], &field_size));
1252e13f2367SZach Atkins               assembled_array += field_size * num_points;  // Advance the pointer by the size of the output
1253e13f2367SZach Atkins             }
1254681d0ea7SJeremy L Thompson             CeedCallBackend(CeedVectorDestroy(&vec));
1255e13f2367SZach Atkins           }
1256e13f2367SZach Atkins           // Apply QFunction
1257e13f2367SZach Atkins           CeedCallBackend(CeedQFunctionApply(qf, num_points, impl->q_vecs_in, impl->q_vecs_out));
1258e13f2367SZach Atkins         } else {
1259c7b67790SJeremy L Thompson           const CeedScalar *array;
1260e13f2367SZach Atkins           CeedInt           field_size;
1261e13f2367SZach Atkins 
1262e13f2367SZach Atkins           // Copy Identity Outputs
1263e13f2367SZach Atkins           CeedCallBackend(CeedQFunctionFieldGetSize(qf_output_fields[0], &field_size));
1264c7b67790SJeremy L Thompson           CeedCallBackend(CeedVectorGetArrayRead(impl->q_vecs_out[0], CEED_MEM_HOST, &array));
1265c7b67790SJeremy L Thompson           for (CeedInt j = 0; j < field_size * num_points; j++) assembled_array[j] = array[j];
1266c7b67790SJeremy L Thompson           CeedCallBackend(CeedVectorRestoreArrayRead(impl->q_vecs_out[0], &array));
1267e13f2367SZach Atkins           assembled_array += field_size * num_points;
1268e13f2367SZach Atkins         }
1269c7b67790SJeremy L Thompson         // Reset input to 0.0
1270c7b67790SJeremy L Thompson         {
1271c7b67790SJeremy L Thompson           CeedScalar *array;
1272c7b67790SJeremy L Thompson 
1273c7b67790SJeremy L Thompson           CeedCallBackend(CeedVectorGetArray(impl->q_vecs_in[i], CEED_MEM_HOST, &array));
1274c7b67790SJeremy L Thompson           for (CeedInt j = 0; j < num_points; j++) array[field * num_points + j] = 0.0;
1275c7b67790SJeremy L Thompson           CeedCallBackend(CeedVectorRestoreArray(impl->q_vecs_in[i], &array));
1276c7b67790SJeremy L Thompson         }
1277c7b67790SJeremy L Thompson       }
1278e13f2367SZach Atkins     }
1279e13f2367SZach Atkins     num_points_offset += num_points;
1280e13f2367SZach Atkins   }
1281e13f2367SZach Atkins 
1282e13f2367SZach Atkins   // Un-set output Qvecs to prevent accidental overwrite of Assembled
1283e13f2367SZach Atkins   if (!impl->is_identity_qf) {
1284e13f2367SZach Atkins     for (CeedInt out = 0; out < num_output_fields; out++) {
1285e13f2367SZach Atkins       CeedVector vec;
1286e13f2367SZach Atkins 
1287e13f2367SZach Atkins       // Get output vector
1288e13f2367SZach Atkins       CeedCallBackend(CeedOperatorFieldGetVector(op_output_fields[out], &vec));
1289e13f2367SZach Atkins       // Check if active output
1290e13f2367SZach Atkins       if (vec == CEED_VECTOR_ACTIVE && num_elem > 0) {
1291e13f2367SZach Atkins         CeedCallBackend(CeedVectorTakeArray(impl->q_vecs_out[out], CEED_MEM_HOST, NULL));
1292e13f2367SZach Atkins       }
1293681d0ea7SJeremy L Thompson       CeedCallBackend(CeedVectorDestroy(&vec));
1294e13f2367SZach Atkins     }
1295e13f2367SZach Atkins   }
1296e13f2367SZach Atkins 
1297e13f2367SZach Atkins   // Restore input arrays
1298e13f2367SZach Atkins   CeedCallBackend(CeedOperatorRestoreInputs_Ref(num_input_fields, qf_input_fields, op_input_fields, true, e_data_full, impl));
1299e13f2367SZach Atkins 
1300e13f2367SZach Atkins   // Restore output
1301e13f2367SZach Atkins   CeedCallBackend(CeedVectorRestoreArray(*assembled, &assembled_array));
1302e13f2367SZach Atkins 
1303e13f2367SZach Atkins   // Cleanup
13049bc66399SJeremy L Thompson   CeedCallBackend(CeedDestroy(&ceed));
1305e13f2367SZach Atkins   CeedCallBackend(CeedVectorDestroy(&point_coords));
1306e13f2367SZach Atkins   CeedCallBackend(CeedElemRestrictionDestroy(&rstr_points));
1307c11e12f4SJeremy L Thompson   CeedCallBackend(CeedQFunctionDestroy(&qf));
1308e13f2367SZach Atkins   return CEED_ERROR_SUCCESS;
1309e13f2367SZach Atkins }
1310e13f2367SZach Atkins 
1311e13f2367SZach Atkins //------------------------------------------------------------------------------
1312e13f2367SZach Atkins // Assemble Linear QFunction
1313e13f2367SZach Atkins //------------------------------------------------------------------------------
1314e13f2367SZach Atkins static int CeedOperatorLinearAssembleQFunctionAtPoints_Ref(CeedOperator op, CeedVector *assembled, CeedElemRestriction *rstr, CeedRequest *request) {
1315e13f2367SZach Atkins   return CeedOperatorLinearAssembleQFunctionAtPointsCore_Ref(op, true, assembled, rstr, request);
1316e13f2367SZach Atkins }
1317e13f2367SZach Atkins 
1318e13f2367SZach Atkins //------------------------------------------------------------------------------
1319e13f2367SZach Atkins // Update Assembled Linear QFunction
1320e13f2367SZach Atkins //------------------------------------------------------------------------------
1321e13f2367SZach Atkins static int CeedOperatorLinearAssembleQFunctionAtPointsUpdate_Ref(CeedOperator op, CeedVector assembled, CeedElemRestriction rstr,
1322e13f2367SZach Atkins                                                                  CeedRequest *request) {
1323e13f2367SZach Atkins   return CeedOperatorLinearAssembleQFunctionAtPointsCore_Ref(op, false, &assembled, &rstr, request);
1324e13f2367SZach Atkins }
1325e13f2367SZach Atkins 
1326e13f2367SZach Atkins //------------------------------------------------------------------------------
1327fb133d4bSJeremy L Thompson // Assemble Operator Diagonal AtPoints
1328e13f2367SZach Atkins //------------------------------------------------------------------------------
1329fb133d4bSJeremy L Thompson static int CeedOperatorLinearAssembleAddDiagonalAtPoints_Ref(CeedOperator op, CeedVector assembled, CeedRequest *request) {
1330382e9c83SJeremy L Thompson   CeedInt             num_points_offset = 0, num_input_fields, num_output_fields, num_elem, num_comp_active = 1;
1331fb133d4bSJeremy L Thompson   CeedScalar         *e_data[2 * CEED_FIELD_MAX] = {0};
1332fb133d4bSJeremy L Thompson   Ceed                ceed;
1333fb133d4bSJeremy L Thompson   CeedVector          point_coords = NULL, in_vec, out_vec;
1334fb133d4bSJeremy L Thompson   CeedElemRestriction rstr_points  = NULL;
1335fb133d4bSJeremy L Thompson   CeedQFunctionField *qf_input_fields, *qf_output_fields;
1336fb133d4bSJeremy L Thompson   CeedQFunction       qf;
1337fb133d4bSJeremy L Thompson   CeedOperatorField  *op_input_fields, *op_output_fields;
1338fb133d4bSJeremy L Thompson   CeedOperator_Ref   *impl;
1339fb133d4bSJeremy L Thompson 
1340fb133d4bSJeremy L Thompson   CeedCallBackend(CeedOperatorGetData(op, &impl));
1341fb133d4bSJeremy L Thompson   CeedCallBackend(CeedOperatorGetNumElements(op, &num_elem));
1342fb133d4bSJeremy L Thompson   CeedCallBackend(CeedOperatorGetQFunction(op, &qf));
1343fb133d4bSJeremy L Thompson   CeedCallBackend(CeedOperatorGetFields(op, &num_input_fields, &op_input_fields, &num_output_fields, &op_output_fields));
1344fb133d4bSJeremy L Thompson   CeedCallBackend(CeedQFunctionGetFields(qf, NULL, &qf_input_fields, NULL, &qf_output_fields));
1345fb133d4bSJeremy L Thompson 
1346fb133d4bSJeremy L Thompson   // Setup
1347fb133d4bSJeremy L Thompson   CeedCallBackend(CeedOperatorSetupAtPoints_Ref(op));
1348fb133d4bSJeremy L Thompson 
1349fb133d4bSJeremy L Thompson   // Ceed
1350fb133d4bSJeremy L Thompson   {
1351fb133d4bSJeremy L Thompson     Ceed ceed_parent;
1352fb133d4bSJeremy L Thompson 
1353fb133d4bSJeremy L Thompson     CeedCallBackend(CeedOperatorGetCeed(op, &ceed));
1354fb133d4bSJeremy L Thompson     CeedCallBackend(CeedGetParent(ceed, &ceed_parent));
13559bc66399SJeremy L Thompson     CeedCallBackend(CeedReferenceCopy(ceed_parent, &ceed));
13569bc66399SJeremy L Thompson     CeedCallBackend(CeedDestroy(&ceed_parent));
1357fb133d4bSJeremy L Thompson   }
1358fb133d4bSJeremy L Thompson 
1359fb133d4bSJeremy L Thompson   // Point coordinates
1360fb133d4bSJeremy L Thompson   CeedCallBackend(CeedOperatorAtPointsGetPoints(op, &rstr_points, &point_coords));
1361fb133d4bSJeremy L Thompson 
1362fb133d4bSJeremy L Thompson   // Input and output vectors
1363fb133d4bSJeremy L Thompson   {
1364fb133d4bSJeremy L Thompson     CeedSize input_size, output_size;
1365fb133d4bSJeremy L Thompson 
1366fb133d4bSJeremy L Thompson     CeedCallBackend(CeedOperatorGetActiveVectorLengths(op, &input_size, &output_size));
1367fb133d4bSJeremy L Thompson     CeedCallBackend(CeedVectorCreate(ceed, input_size, &in_vec));
1368fb133d4bSJeremy L Thompson     CeedCallBackend(CeedVectorCreate(ceed, output_size, &out_vec));
1369fb133d4bSJeremy L Thompson     CeedCallBackend(CeedVectorSetValue(out_vec, 0.0));
1370fb133d4bSJeremy L Thompson   }
1371fb133d4bSJeremy L Thompson 
137248fdef17SJeremy L Thompson   // Clear input Evecs
137386e10729SJeremy L Thompson   for (CeedInt i = 0; i < num_input_fields; i++) {
1374681d0ea7SJeremy L Thompson     bool       is_active;
137586e10729SJeremy L Thompson     CeedVector vec;
137686e10729SJeremy L Thompson 
137786e10729SJeremy L Thompson     CeedCallBackend(CeedOperatorFieldGetVector(op_input_fields[i], &vec));
1378681d0ea7SJeremy L Thompson     is_active = vec == CEED_VECTOR_ACTIVE;
1379681d0ea7SJeremy L Thompson     CeedCallBackend(CeedVectorDestroy(&vec));
138048fdef17SJeremy L Thompson     if (!is_active || impl->skip_rstr_in[i]) continue;
138148fdef17SJeremy L Thompson     CeedCallBackend(CeedVectorSetValue(impl->e_vecs_in[i], 0.0));
138286e10729SJeremy L Thompson   }
1383382e9c83SJeremy L Thompson 
1384fb133d4bSJeremy L Thompson   // Input Evecs and Restriction
1385fb133d4bSJeremy L Thompson   CeedCallBackend(CeedOperatorSetupInputs_Ref(num_input_fields, qf_input_fields, op_input_fields, NULL, true, e_data, impl, request));
1386fb133d4bSJeremy L Thompson 
1387fb133d4bSJeremy L Thompson   // Loop through elements
1388fb133d4bSJeremy L Thompson   for (CeedInt e = 0; e < num_elem; e++) {
1389fb133d4bSJeremy L Thompson     CeedInt num_points, e_vec_size = 0;
1390fb133d4bSJeremy L Thompson 
1391fb133d4bSJeremy L Thompson     // Setup points for element
1392fb133d4bSJeremy L Thompson     CeedCallBackend(CeedElemRestrictionApplyAtPointsInElement(rstr_points, e, CEED_NOTRANSPOSE, point_coords, impl->point_coords_elem, request));
1393fb133d4bSJeremy L Thompson     CeedCallBackend(CeedElemRestrictionGetNumPointsInElement(rstr_points, e, &num_points));
1394fb133d4bSJeremy L Thompson 
1395fb133d4bSJeremy L Thompson     // Input basis apply for non-active bases
1396fb133d4bSJeremy L Thompson     CeedCallBackend(CeedOperatorInputBasisAtPoints_Ref(e, num_points_offset, num_points, qf_input_fields, op_input_fields, num_input_fields, in_vec,
139748fdef17SJeremy L Thompson                                                        impl->point_coords_elem, true, false, e_data, impl, request));
1398fb133d4bSJeremy L Thompson 
1399fb133d4bSJeremy L Thompson     // Loop over points on element
1400fb133d4bSJeremy L Thompson     for (CeedInt i = 0; i < num_input_fields; i++) {
1401681d0ea7SJeremy L Thompson       bool                is_active_at_points = true, is_active;
1402382e9c83SJeremy L Thompson       CeedInt             elem_size_active    = 1;
1403382e9c83SJeremy L Thompson       CeedRestrictionType rstr_type;
1404fb133d4bSJeremy L Thompson       CeedVector          vec;
1405382e9c83SJeremy L Thompson       CeedElemRestriction elem_rstr;
1406fb133d4bSJeremy L Thompson 
1407382e9c83SJeremy L Thompson       // -- Skip non-active input
1408681d0ea7SJeremy L Thompson       CeedCallBackend(CeedOperatorFieldGetVector(op_input_fields[i], &vec));
1409681d0ea7SJeremy L Thompson       is_active = vec == CEED_VECTOR_ACTIVE;
1410681d0ea7SJeremy L Thompson       CeedCallBackend(CeedVectorDestroy(&vec));
141148fdef17SJeremy L Thompson       if (!is_active || impl->skip_rstr_in[i]) continue;
1412fb133d4bSJeremy L Thompson 
1413382e9c83SJeremy L Thompson       // -- Get active restriction type
1414382e9c83SJeremy L Thompson       CeedCallBackend(CeedOperatorFieldGetElemRestriction(op_input_fields[i], &elem_rstr));
1415382e9c83SJeremy L Thompson       CeedCallBackend(CeedElemRestrictionGetType(elem_rstr, &rstr_type));
1416382e9c83SJeremy L Thompson       is_active_at_points = rstr_type == CEED_RESTRICTION_POINTS;
1417382e9c83SJeremy L Thompson       if (!is_active_at_points) CeedCallBackend(CeedElemRestrictionGetElementSize(elem_rstr, &elem_size_active));
1418382e9c83SJeremy L Thompson       else elem_size_active = num_points;
1419382e9c83SJeremy L Thompson       CeedCallBackend(CeedElemRestrictionGetNumComponents(elem_rstr, &num_comp_active));
1420681d0ea7SJeremy L Thompson       CeedCallBackend(CeedElemRestrictionDestroy(&elem_rstr));
1421382e9c83SJeremy L Thompson 
1422382e9c83SJeremy L Thompson       e_vec_size = elem_size_active * num_comp_active;
1423382e9c83SJeremy L Thompson       for (CeedInt s = 0; s < e_vec_size; s++) {
1424382e9c83SJeremy L Thompson         // -- Update unit vector
1425fb133d4bSJeremy L Thompson         {
1426fb133d4bSJeremy L Thompson           CeedScalar *array;
1427fb133d4bSJeremy L Thompson 
1428fb133d4bSJeremy L Thompson           CeedCallBackend(CeedVectorGetArray(impl->e_vecs_in[i], CEED_MEM_HOST, &array));
1429fb133d4bSJeremy L Thompson           array[s] = 1.0;
1430fb133d4bSJeremy L Thompson           if (s > 0) array[s - 1] = 0.0;
1431fb133d4bSJeremy L Thompson           CeedCallBackend(CeedVectorRestoreArray(impl->e_vecs_in[i], &array));
1432fb133d4bSJeremy L Thompson         }
143348fdef17SJeremy L Thompson         // Input basis apply for active bases
143448fdef17SJeremy L Thompson         CeedCallBackend(CeedOperatorInputBasisAtPoints_Ref(e, num_points_offset, num_points, qf_input_fields, op_input_fields, num_input_fields,
143548fdef17SJeremy L Thompson                                                            in_vec, impl->point_coords_elem, false, true, e_data, impl, request));
1436fb133d4bSJeremy L Thompson 
1437fb133d4bSJeremy L Thompson         // -- Q function
1438fb133d4bSJeremy L Thompson         if (!impl->is_identity_qf) {
1439fb133d4bSJeremy L Thompson           CeedCallBackend(CeedQFunctionApply(qf, num_points, impl->q_vecs_in, impl->q_vecs_out));
1440fb133d4bSJeremy L Thompson         }
1441fb133d4bSJeremy L Thompson 
1442fb133d4bSJeremy L Thompson         // -- Output basis apply and restriction
1443fb133d4bSJeremy L Thompson         CeedCallBackend(CeedOperatorOutputBasisAtPoints_Ref(e, num_points_offset, num_points, qf_output_fields, op_output_fields, num_input_fields,
1444f8a0df59SJeremy L Thompson                                                             num_output_fields, impl->apply_add_basis_out, impl->skip_rstr_out, op, out_vec,
144548fdef17SJeremy L Thompson                                                             impl->point_coords_elem, true, impl, request));
1446fb133d4bSJeremy L Thompson 
1447fb133d4bSJeremy L Thompson         // -- Grab diagonal value
144886e10729SJeremy L Thompson         for (CeedInt j = 0; j < num_output_fields; j++) {
1449681d0ea7SJeremy L Thompson           bool                is_active;
1450382e9c83SJeremy L Thompson           CeedInt             elem_size = 0;
1451fb133d4bSJeremy L Thompson           CeedRestrictionType rstr_type;
1452fb133d4bSJeremy L Thompson           CeedVector          vec;
1453fb133d4bSJeremy L Thompson           CeedElemRestriction elem_rstr;
1454fb133d4bSJeremy L Thompson 
14550c7f167fSZach Atkins           // ---- Skip non-active output
1456681d0ea7SJeremy L Thompson           CeedCallBackend(CeedOperatorFieldGetVector(op_output_fields[j], &vec));
1457681d0ea7SJeremy L Thompson           is_active = vec == CEED_VECTOR_ACTIVE;
1458681d0ea7SJeremy L Thompson           CeedCallBackend(CeedVectorDestroy(&vec));
145948fdef17SJeremy L Thompson           if (!is_active || impl->skip_rstr_out[j]) continue;
1460fb133d4bSJeremy L Thompson 
1461382e9c83SJeremy L Thompson           // ---- Check if elem size matches
146286e10729SJeremy L Thompson           CeedCallBackend(CeedOperatorFieldGetElemRestriction(op_output_fields[j], &elem_rstr));
1463382e9c83SJeremy L Thompson           CeedCallBackend(CeedElemRestrictionGetType(elem_rstr, &rstr_type));
146469d19bacSJeremy L Thompson           if (is_active_at_points && rstr_type != CEED_RESTRICTION_POINTS) {
146569d19bacSJeremy L Thompson             CeedCallBackend(CeedElemRestrictionDestroy(&elem_rstr));
146669d19bacSJeremy L Thompson             continue;
146769d19bacSJeremy L Thompson           }
1468382e9c83SJeremy L Thompson           if (rstr_type == CEED_RESTRICTION_POINTS) {
1469382e9c83SJeremy L Thompson             CeedCallBackend(CeedElemRestrictionGetNumPointsInElement(elem_rstr, e, &elem_size));
1470382e9c83SJeremy L Thompson           } else {
1471382e9c83SJeremy L Thompson             CeedCallBackend(CeedElemRestrictionGetElementSize(elem_rstr, &elem_size));
1472382e9c83SJeremy L Thompson           }
1473382e9c83SJeremy L Thompson           {
1474382e9c83SJeremy L Thompson             CeedInt num_comp = 0;
1475382e9c83SJeremy L Thompson 
1476382e9c83SJeremy L Thompson             CeedCallBackend(CeedElemRestrictionGetNumComponents(elem_rstr, &num_comp));
147769d19bacSJeremy L Thompson             if (e_vec_size != num_comp * elem_size) {
147869d19bacSJeremy L Thompson               CeedCallBackend(CeedElemRestrictionDestroy(&elem_rstr));
147969d19bacSJeremy L Thompson               continue;
148069d19bacSJeremy L Thompson             }
1481382e9c83SJeremy L Thompson           }
1482fb133d4bSJeremy L Thompson           // ---- Update output vector
1483fb133d4bSJeremy L Thompson           {
1484fb133d4bSJeremy L Thompson             CeedScalar *array, current_value = 0.0;
1485fb133d4bSJeremy L Thompson 
148686e10729SJeremy L Thompson             CeedCallBackend(CeedVectorGetArray(impl->e_vecs_out[j], CEED_MEM_HOST, &array));
1487fb133d4bSJeremy L Thompson             current_value = array[s];
148886e10729SJeremy L Thompson             CeedCallBackend(CeedVectorRestoreArray(impl->e_vecs_out[j], &array));
148986e10729SJeremy L Thompson             CeedCallBackend(CeedVectorSetValue(impl->e_vecs_out[j], 0.0));
149086e10729SJeremy L Thompson             CeedCallBackend(CeedVectorGetArray(impl->e_vecs_out[j], CEED_MEM_HOST, &array));
1491fb133d4bSJeremy L Thompson             array[s] = current_value;
149286e10729SJeremy L Thompson             CeedCallBackend(CeedVectorRestoreArray(impl->e_vecs_out[j], &array));
1493fb133d4bSJeremy L Thompson           }
1494fb133d4bSJeremy L Thompson           // ---- Restrict output block
1495fb133d4bSJeremy L Thompson           if (rstr_type == CEED_RESTRICTION_POINTS) {
149686e10729SJeremy L Thompson             CeedCallBackend(CeedElemRestrictionApplyAtPointsInElement(elem_rstr, e, CEED_TRANSPOSE, impl->e_vecs_out[j], assembled, request));
1497fb133d4bSJeremy L Thompson           } else {
149886e10729SJeremy L Thompson             CeedCallBackend(CeedElemRestrictionApplyBlock(elem_rstr, e, CEED_TRANSPOSE, impl->e_vecs_out[j], assembled, request));
1499fb133d4bSJeremy L Thompson           }
1500681d0ea7SJeremy L Thompson           CeedCallBackend(CeedElemRestrictionDestroy(&elem_rstr));
1501fb133d4bSJeremy L Thompson         }
1502382e9c83SJeremy L Thompson         // -- Reset unit vector
150348fdef17SJeremy L Thompson         if (s == e_vec_size - 1) {
150448fdef17SJeremy L Thompson           CeedScalar *array;
150548fdef17SJeremy L Thompson 
150648fdef17SJeremy L Thompson           CeedCallBackend(CeedVectorGetArray(impl->e_vecs_in[i], CEED_MEM_HOST, &array));
150748fdef17SJeremy L Thompson           array[s] = 0.0;
150848fdef17SJeremy L Thompson           CeedCallBackend(CeedVectorRestoreArray(impl->e_vecs_in[i], &array));
150948fdef17SJeremy L Thompson         }
1510382e9c83SJeremy L Thompson       }
1511fb133d4bSJeremy L Thompson     }
1512fb133d4bSJeremy L Thompson     num_points_offset += num_points;
1513fb133d4bSJeremy L Thompson   }
1514fb133d4bSJeremy L Thompson 
1515fb133d4bSJeremy L Thompson   // Restore input arrays
1516fb133d4bSJeremy L Thompson   CeedCallBackend(CeedOperatorRestoreInputs_Ref(num_input_fields, qf_input_fields, op_input_fields, true, e_data, impl));
1517fb133d4bSJeremy L Thompson 
1518fb133d4bSJeremy L Thompson   // Cleanup
15199bc66399SJeremy L Thompson   CeedCallBackend(CeedDestroy(&ceed));
1520fb133d4bSJeremy L Thompson   CeedCallBackend(CeedVectorDestroy(&in_vec));
1521fb133d4bSJeremy L Thompson   CeedCallBackend(CeedVectorDestroy(&out_vec));
1522fb133d4bSJeremy L Thompson   CeedCallBackend(CeedVectorDestroy(&point_coords));
1523fb133d4bSJeremy L Thompson   CeedCallBackend(CeedElemRestrictionDestroy(&rstr_points));
1524c11e12f4SJeremy L Thompson   CeedCallBackend(CeedQFunctionDestroy(&qf));
1525fb133d4bSJeremy L Thompson   return CEED_ERROR_SUCCESS;
1526fb133d4bSJeremy L Thompson }
1527e13f2367SZach Atkins 
1528e13f2367SZach Atkins //------------------------------------------------------------------------------
15291b95d8c6SJeremy L Thompson // Assemble Operator AtPoints
15301b95d8c6SJeremy L Thompson //------------------------------------------------------------------------------
1531ed094490SJeremy L Thompson static int CeedOperatorAssembleSingleAtPoints_Ref(CeedOperator op, CeedInt offset, CeedVector values) {
15321b95d8c6SJeremy L Thompson   CeedInt             num_points_offset = 0, num_input_fields, num_output_fields, num_elem, num_comp_active = 1;
15331b95d8c6SJeremy L Thompson   CeedScalar         *e_data[2 * CEED_FIELD_MAX] = {0}, *assembled;
15341b95d8c6SJeremy L Thompson   Ceed                ceed;
15351b95d8c6SJeremy L Thompson   CeedVector          point_coords = NULL, in_vec, out_vec;
15361b95d8c6SJeremy L Thompson   CeedElemRestriction rstr_points  = NULL;
15371b95d8c6SJeremy L Thompson   CeedQFunctionField *qf_input_fields, *qf_output_fields;
15381b95d8c6SJeremy L Thompson   CeedQFunction       qf;
15391b95d8c6SJeremy L Thompson   CeedOperatorField  *op_input_fields, *op_output_fields;
15401b95d8c6SJeremy L Thompson   CeedOperator_Ref   *impl;
15411b95d8c6SJeremy L Thompson 
15421b95d8c6SJeremy L Thompson   CeedCallBackend(CeedOperatorGetData(op, &impl));
15431b95d8c6SJeremy L Thompson   CeedCallBackend(CeedOperatorGetNumElements(op, &num_elem));
15441b95d8c6SJeremy L Thompson   CeedCallBackend(CeedOperatorGetQFunction(op, &qf));
15451b95d8c6SJeremy L Thompson   CeedCallBackend(CeedOperatorGetFields(op, &num_input_fields, &op_input_fields, &num_output_fields, &op_output_fields));
15461b95d8c6SJeremy L Thompson   CeedCallBackend(CeedQFunctionGetFields(qf, NULL, &qf_input_fields, NULL, &qf_output_fields));
15471b95d8c6SJeremy L Thompson 
15481b95d8c6SJeremy L Thompson   // Setup
15491b95d8c6SJeremy L Thompson   CeedCallBackend(CeedOperatorSetupAtPoints_Ref(op));
15501b95d8c6SJeremy L Thompson 
15511b95d8c6SJeremy L Thompson   // Ceed
15521b95d8c6SJeremy L Thompson   {
15531b95d8c6SJeremy L Thompson     Ceed ceed_parent;
15541b95d8c6SJeremy L Thompson 
15551b95d8c6SJeremy L Thompson     CeedCallBackend(CeedOperatorGetCeed(op, &ceed));
15561b95d8c6SJeremy L Thompson     CeedCallBackend(CeedGetParent(ceed, &ceed_parent));
15571b95d8c6SJeremy L Thompson     CeedCallBackend(CeedReferenceCopy(ceed_parent, &ceed));
15581b95d8c6SJeremy L Thompson     CeedCallBackend(CeedDestroy(&ceed_parent));
15591b95d8c6SJeremy L Thompson   }
15601b95d8c6SJeremy L Thompson 
15611b95d8c6SJeremy L Thompson   // Point coordinates
15621b95d8c6SJeremy L Thompson   CeedCallBackend(CeedOperatorAtPointsGetPoints(op, &rstr_points, &point_coords));
15631b95d8c6SJeremy L Thompson 
15641b95d8c6SJeremy L Thompson   // Input and output vectors
15651b95d8c6SJeremy L Thompson   {
15661b95d8c6SJeremy L Thompson     CeedSize input_size, output_size;
15671b95d8c6SJeremy L Thompson 
15681b95d8c6SJeremy L Thompson     CeedCallBackend(CeedOperatorGetActiveVectorLengths(op, &input_size, &output_size));
15691b95d8c6SJeremy L Thompson     CeedCallBackend(CeedVectorCreate(ceed, input_size, &in_vec));
15701b95d8c6SJeremy L Thompson     CeedCallBackend(CeedVectorCreate(ceed, output_size, &out_vec));
15711b95d8c6SJeremy L Thompson     CeedCallBackend(CeedVectorSetValue(out_vec, 0.0));
15721b95d8c6SJeremy L Thompson   }
15731b95d8c6SJeremy L Thompson 
15741b95d8c6SJeremy L Thompson   // Assembled array
15751b95d8c6SJeremy L Thompson   CeedCallBackend(CeedVectorGetArray(values, CEED_MEM_HOST, &assembled));
15761b95d8c6SJeremy L Thompson 
15771b95d8c6SJeremy L Thompson   // Clear input Evecs
15781b95d8c6SJeremy L Thompson   for (CeedInt i = 0; i < num_input_fields; i++) {
15791b95d8c6SJeremy L Thompson     bool       is_active;
15801b95d8c6SJeremy L Thompson     CeedVector vec;
15811b95d8c6SJeremy L Thompson 
15821b95d8c6SJeremy L Thompson     CeedCallBackend(CeedOperatorFieldGetVector(op_input_fields[i], &vec));
15831b95d8c6SJeremy L Thompson     is_active = vec == CEED_VECTOR_ACTIVE;
15841b95d8c6SJeremy L Thompson     CeedCallBackend(CeedVectorDestroy(&vec));
15851b95d8c6SJeremy L Thompson     if (!is_active || impl->skip_rstr_in[i]) continue;
15861b95d8c6SJeremy L Thompson     CeedCallBackend(CeedVectorSetValue(impl->e_vecs_in[i], 0.0));
15871b95d8c6SJeremy L Thompson   }
15881b95d8c6SJeremy L Thompson 
15891b95d8c6SJeremy L Thompson   // Input Evecs and Restriction
15901b95d8c6SJeremy L Thompson   CeedCallBackend(CeedOperatorSetupInputs_Ref(num_input_fields, qf_input_fields, op_input_fields, NULL, true, e_data, impl, CEED_REQUEST_IMMEDIATE));
15911b95d8c6SJeremy L Thompson 
15921b95d8c6SJeremy L Thompson   // Loop through elements
15931b95d8c6SJeremy L Thompson   for (CeedInt e = 0; e < num_elem; e++) {
15941b95d8c6SJeremy L Thompson     CeedInt num_points, e_vec_size = 0;
15951b95d8c6SJeremy L Thompson 
15961b95d8c6SJeremy L Thompson     // Setup points for element
15971b95d8c6SJeremy L Thompson     CeedCallBackend(
15981b95d8c6SJeremy L Thompson         CeedElemRestrictionApplyAtPointsInElement(rstr_points, e, CEED_NOTRANSPOSE, point_coords, impl->point_coords_elem, CEED_REQUEST_IMMEDIATE));
15991b95d8c6SJeremy L Thompson     CeedCallBackend(CeedElemRestrictionGetNumPointsInElement(rstr_points, e, &num_points));
16001b95d8c6SJeremy L Thompson 
16011b95d8c6SJeremy L Thompson     // Input basis apply for non-active bases
16021b95d8c6SJeremy L Thompson     CeedCallBackend(CeedOperatorInputBasisAtPoints_Ref(e, num_points_offset, num_points, qf_input_fields, op_input_fields, num_input_fields, in_vec,
16031b95d8c6SJeremy L Thompson                                                        impl->point_coords_elem, true, false, e_data, impl, CEED_REQUEST_IMMEDIATE));
16041b95d8c6SJeremy L Thompson 
16051b95d8c6SJeremy L Thompson     // Loop over points on element
16061b95d8c6SJeremy L Thompson     for (CeedInt i = 0; i < num_input_fields; i++) {
16071b95d8c6SJeremy L Thompson       bool                is_active_at_points = true, is_active;
16081b95d8c6SJeremy L Thompson       CeedInt             elem_size_active    = 1;
16091b95d8c6SJeremy L Thompson       CeedRestrictionType rstr_type;
16101b95d8c6SJeremy L Thompson       CeedVector          vec;
16111b95d8c6SJeremy L Thompson       CeedElemRestriction elem_rstr;
16121b95d8c6SJeremy L Thompson 
16131b95d8c6SJeremy L Thompson       // -- Skip non-active input
16141b95d8c6SJeremy L Thompson       CeedCallBackend(CeedOperatorFieldGetVector(op_input_fields[i], &vec));
16151b95d8c6SJeremy L Thompson       is_active = vec == CEED_VECTOR_ACTIVE;
16161b95d8c6SJeremy L Thompson       CeedCallBackend(CeedVectorDestroy(&vec));
16171b95d8c6SJeremy L Thompson       if (!is_active || impl->skip_rstr_in[i]) continue;
16181b95d8c6SJeremy L Thompson 
16191b95d8c6SJeremy L Thompson       // -- Get active restriction type
16201b95d8c6SJeremy L Thompson       CeedCallBackend(CeedOperatorFieldGetElemRestriction(op_input_fields[i], &elem_rstr));
16211b95d8c6SJeremy L Thompson       CeedCallBackend(CeedElemRestrictionGetType(elem_rstr, &rstr_type));
16221b95d8c6SJeremy L Thompson       is_active_at_points = rstr_type == CEED_RESTRICTION_POINTS;
16231b95d8c6SJeremy L Thompson       if (!is_active_at_points) CeedCallBackend(CeedElemRestrictionGetElementSize(elem_rstr, &elem_size_active));
16241b95d8c6SJeremy L Thompson       else elem_size_active = num_points;
16251b95d8c6SJeremy L Thompson       CeedCallBackend(CeedElemRestrictionGetNumComponents(elem_rstr, &num_comp_active));
16261b95d8c6SJeremy L Thompson       CeedCallBackend(CeedElemRestrictionDestroy(&elem_rstr));
16271b95d8c6SJeremy L Thompson 
16281b95d8c6SJeremy L Thompson       e_vec_size = elem_size_active * num_comp_active;
16291b95d8c6SJeremy L Thompson       for (CeedInt s = 0; s < e_vec_size; s++) {
16301b95d8c6SJeremy L Thompson         const CeedInt comp_in = s / elem_size_active;
16311b95d8c6SJeremy L Thompson         const CeedInt node_in = s % elem_size_active;
16321b95d8c6SJeremy L Thompson 
16331b95d8c6SJeremy L Thompson         // -- Update unit vector
16341b95d8c6SJeremy L Thompson         {
16351b95d8c6SJeremy L Thompson           CeedScalar *array;
16361b95d8c6SJeremy L Thompson 
16371b95d8c6SJeremy L Thompson           if (s == 0) CeedCallBackend(CeedVectorSetValue(impl->e_vecs_in[i], 0.0));
16381b95d8c6SJeremy L Thompson           CeedCallBackend(CeedVectorGetArray(impl->e_vecs_in[i], CEED_MEM_HOST, &array));
16391b95d8c6SJeremy L Thompson           array[s] = 1.0;
16401b95d8c6SJeremy L Thompson           if (s > 0) array[s - 1] = 0.0;
16411b95d8c6SJeremy L Thompson           CeedCallBackend(CeedVectorRestoreArray(impl->e_vecs_in[i], &array));
16421b95d8c6SJeremy L Thompson         }
16431b95d8c6SJeremy L Thompson         // Input basis apply for active bases
16441b95d8c6SJeremy L Thompson         CeedCallBackend(CeedOperatorInputBasisAtPoints_Ref(e, num_points_offset, num_points, qf_input_fields, op_input_fields, num_input_fields,
16451b95d8c6SJeremy L Thompson                                                            in_vec, impl->point_coords_elem, false, true, e_data, impl, CEED_REQUEST_IMMEDIATE));
16461b95d8c6SJeremy L Thompson 
16471b95d8c6SJeremy L Thompson         // -- Q function
16481b95d8c6SJeremy L Thompson         if (!impl->is_identity_qf) {
16491b95d8c6SJeremy L Thompson           CeedCallBackend(CeedQFunctionApply(qf, num_points, impl->q_vecs_in, impl->q_vecs_out));
16501b95d8c6SJeremy L Thompson         }
16511b95d8c6SJeremy L Thompson 
16521b95d8c6SJeremy L Thompson         // -- Output basis apply and restriction
16531b95d8c6SJeremy L Thompson         CeedCallBackend(CeedOperatorOutputBasisAtPoints_Ref(e, num_points_offset, num_points, qf_output_fields, op_output_fields, num_input_fields,
16541b95d8c6SJeremy L Thompson                                                             num_output_fields, impl->apply_add_basis_out, impl->skip_rstr_out, op, out_vec,
16551b95d8c6SJeremy L Thompson                                                             impl->point_coords_elem, true, impl, CEED_REQUEST_IMMEDIATE));
16561b95d8c6SJeremy L Thompson 
16571b95d8c6SJeremy L Thompson         // -- Build element matrix
16581b95d8c6SJeremy L Thompson         for (CeedInt j = 0; j < num_output_fields; j++) {
16591b95d8c6SJeremy L Thompson           bool                is_active;
16601b95d8c6SJeremy L Thompson           CeedInt             elem_size = 0;
16611b95d8c6SJeremy L Thompson           CeedRestrictionType rstr_type;
16621b95d8c6SJeremy L Thompson           CeedVector          vec;
16631b95d8c6SJeremy L Thompson           CeedElemRestriction elem_rstr;
16641b95d8c6SJeremy L Thompson 
16651b95d8c6SJeremy L Thompson           // ---- Skip non-active output
16661b95d8c6SJeremy L Thompson           CeedCallBackend(CeedOperatorFieldGetVector(op_output_fields[j], &vec));
16671b95d8c6SJeremy L Thompson           is_active = vec == CEED_VECTOR_ACTIVE;
16681b95d8c6SJeremy L Thompson           CeedCallBackend(CeedVectorDestroy(&vec));
16691b95d8c6SJeremy L Thompson           if (!is_active || impl->skip_rstr_out[j]) continue;
16701b95d8c6SJeremy L Thompson 
16711b95d8c6SJeremy L Thompson           // ---- Check if elem size matches
16721b95d8c6SJeremy L Thompson           CeedCallBackend(CeedOperatorFieldGetElemRestriction(op_output_fields[j], &elem_rstr));
16731b95d8c6SJeremy L Thompson           CeedCallBackend(CeedElemRestrictionGetType(elem_rstr, &rstr_type));
16741b95d8c6SJeremy L Thompson           if (is_active_at_points && rstr_type != CEED_RESTRICTION_POINTS) {
16751b95d8c6SJeremy L Thompson             CeedCallBackend(CeedElemRestrictionDestroy(&elem_rstr));
16761b95d8c6SJeremy L Thompson             continue;
16771b95d8c6SJeremy L Thompson           }
16781b95d8c6SJeremy L Thompson           if (rstr_type == CEED_RESTRICTION_POINTS) {
16791b95d8c6SJeremy L Thompson             CeedCallBackend(CeedElemRestrictionGetNumPointsInElement(elem_rstr, e, &elem_size));
16801b95d8c6SJeremy L Thompson           } else {
16811b95d8c6SJeremy L Thompson             CeedCallBackend(CeedElemRestrictionGetElementSize(elem_rstr, &elem_size));
16821b95d8c6SJeremy L Thompson           }
16831b95d8c6SJeremy L Thompson           {
16841b95d8c6SJeremy L Thompson             CeedInt num_comp = 0;
16851b95d8c6SJeremy L Thompson 
16861b95d8c6SJeremy L Thompson             CeedCallBackend(CeedElemRestrictionGetNumComponents(elem_rstr, &num_comp));
16871b95d8c6SJeremy L Thompson             CeedCallBackend(CeedElemRestrictionDestroy(&elem_rstr));
16881b95d8c6SJeremy L Thompson             if (e_vec_size != num_comp * elem_size) continue;
16891b95d8c6SJeremy L Thompson           }
16901b95d8c6SJeremy L Thompson           // ---- Copy output
16911b95d8c6SJeremy L Thompson           {
16921b95d8c6SJeremy L Thompson             const CeedScalar *output;
16931b95d8c6SJeremy L Thompson 
16941b95d8c6SJeremy L Thompson             CeedCallBackend(CeedVectorGetArrayRead(impl->e_vecs_out[j], CEED_MEM_HOST, &output));
16951b95d8c6SJeremy L Thompson             for (CeedInt k = 0; k < e_vec_size; k++) {
16961b95d8c6SJeremy L Thompson               const CeedInt comp_out = k / elem_size_active;
16971b95d8c6SJeremy L Thompson               const CeedInt node_out = k % elem_size_active;
16981b95d8c6SJeremy L Thompson 
16991b95d8c6SJeremy L Thompson               assembled[offset + e * e_vec_size * e_vec_size + (comp_in * num_comp_active + comp_out) * elem_size_active * elem_size_active +
17001b95d8c6SJeremy L Thompson                         node_out * elem_size_active + node_in] = output[k];
17011b95d8c6SJeremy L Thompson             }
17021b95d8c6SJeremy L Thompson             CeedCallBackend(CeedVectorRestoreArrayRead(impl->e_vecs_out[j], &output));
17031b95d8c6SJeremy L Thompson           }
17041b95d8c6SJeremy L Thompson         }
17051b95d8c6SJeremy L Thompson         // -- Reset unit vector
17061b95d8c6SJeremy L Thompson         if (s == e_vec_size - 1) {
17071b95d8c6SJeremy L Thompson           CeedScalar *array;
17081b95d8c6SJeremy L Thompson 
17091b95d8c6SJeremy L Thompson           CeedCallBackend(CeedVectorGetArray(impl->e_vecs_in[i], CEED_MEM_HOST, &array));
17101b95d8c6SJeremy L Thompson           array[s] = 0.0;
17111b95d8c6SJeremy L Thompson           CeedCallBackend(CeedVectorRestoreArray(impl->e_vecs_in[i], &array));
17121b95d8c6SJeremy L Thompson         }
17131b95d8c6SJeremy L Thompson       }
17141b95d8c6SJeremy L Thompson     }
17151b95d8c6SJeremy L Thompson     num_points_offset += num_points;
17161b95d8c6SJeremy L Thompson   }
17171b95d8c6SJeremy L Thompson 
17181b95d8c6SJeremy L Thompson   // Restore input arrays
17191b95d8c6SJeremy L Thompson   CeedCallBackend(CeedOperatorRestoreInputs_Ref(num_input_fields, qf_input_fields, op_input_fields, true, e_data, impl));
17201b95d8c6SJeremy L Thompson 
17211b95d8c6SJeremy L Thompson   // Restore assembled values
17221b95d8c6SJeremy L Thompson   CeedCallBackend(CeedVectorRestoreArray(values, &assembled));
17231b95d8c6SJeremy L Thompson 
17241b95d8c6SJeremy L Thompson   // Cleanup
17251b95d8c6SJeremy L Thompson   CeedCallBackend(CeedDestroy(&ceed));
17261b95d8c6SJeremy L Thompson   CeedCallBackend(CeedVectorDestroy(&in_vec));
17271b95d8c6SJeremy L Thompson   CeedCallBackend(CeedVectorDestroy(&out_vec));
17281b95d8c6SJeremy L Thompson   CeedCallBackend(CeedVectorDestroy(&point_coords));
17291b95d8c6SJeremy L Thompson   CeedCallBackend(CeedElemRestrictionDestroy(&rstr_points));
17301b95d8c6SJeremy L Thompson   CeedCallBackend(CeedQFunctionDestroy(&qf));
17311b95d8c6SJeremy L Thompson   return CEED_ERROR_SUCCESS;
17321b95d8c6SJeremy L Thompson }
17331b95d8c6SJeremy L Thompson 
17341b95d8c6SJeremy L Thompson //------------------------------------------------------------------------------
1735f10650afSjeremylt // Operator Destroy
1736f10650afSjeremylt //------------------------------------------------------------------------------
1737f10650afSjeremylt static int CeedOperatorDestroy_Ref(CeedOperator op) {
1738f10650afSjeremylt   CeedOperator_Ref *impl;
1739f10650afSjeremylt 
1740ad70ee2cSJeremy L Thompson   CeedCallBackend(CeedOperatorGetData(op, &impl));
17413aab95c0SJeremy L Thompson   CeedCallBackend(CeedFree(&impl->skip_rstr_in));
1742f8a0df59SJeremy L Thompson   CeedCallBackend(CeedFree(&impl->skip_rstr_out));
1743f8a0df59SJeremy L Thompson   CeedCallBackend(CeedFree(&impl->e_data_out_indices));
1744f8a0df59SJeremy L Thompson   CeedCallBackend(CeedFree(&impl->apply_add_basis_out));
17454fc1f125SJeremy L Thompson   for (CeedInt i = 0; i < impl->num_inputs + impl->num_outputs; i++) {
17462b730f8bSJeremy L Thompson     CeedCallBackend(CeedVectorDestroy(&impl->e_vecs_full[i]));
1747f10650afSjeremylt   }
17482b730f8bSJeremy L Thompson   CeedCallBackend(CeedFree(&impl->e_vecs_full));
17492b730f8bSJeremy L Thompson   CeedCallBackend(CeedFree(&impl->input_states));
1750f10650afSjeremylt 
17514fc1f125SJeremy L Thompson   for (CeedInt i = 0; i < impl->num_inputs; i++) {
17522b730f8bSJeremy L Thompson     CeedCallBackend(CeedVectorDestroy(&impl->e_vecs_in[i]));
17532b730f8bSJeremy L Thompson     CeedCallBackend(CeedVectorDestroy(&impl->q_vecs_in[i]));
1754f10650afSjeremylt   }
17552b730f8bSJeremy L Thompson   CeedCallBackend(CeedFree(&impl->e_vecs_in));
17562b730f8bSJeremy L Thompson   CeedCallBackend(CeedFree(&impl->q_vecs_in));
1757f10650afSjeremylt 
17584fc1f125SJeremy L Thompson   for (CeedInt i = 0; i < impl->num_outputs; i++) {
17592b730f8bSJeremy L Thompson     CeedCallBackend(CeedVectorDestroy(&impl->e_vecs_out[i]));
17602b730f8bSJeremy L Thompson     CeedCallBackend(CeedVectorDestroy(&impl->q_vecs_out[i]));
1761f10650afSjeremylt   }
17622b730f8bSJeremy L Thompson   CeedCallBackend(CeedFree(&impl->e_vecs_out));
17632b730f8bSJeremy L Thompson   CeedCallBackend(CeedFree(&impl->q_vecs_out));
176448acf710SJeremy L Thompson   CeedCallBackend(CeedVectorDestroy(&impl->point_coords_elem));
1765f10650afSjeremylt 
17662b730f8bSJeremy L Thompson   CeedCallBackend(CeedFree(&impl));
1767e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1768f10650afSjeremylt }
1769f10650afSjeremylt 
1770f10650afSjeremylt //------------------------------------------------------------------------------
1771713f43c3Sjeremylt // Operator Create
1772f10650afSjeremylt //------------------------------------------------------------------------------
177321617c04Sjeremylt int CeedOperatorCreate_Ref(CeedOperator op) {
1774fe2413ffSjeremylt   Ceed              ceed;
17754ce2993fSjeremylt   CeedOperator_Ref *impl;
177621617c04Sjeremylt 
1777ad70ee2cSJeremy L Thompson   CeedCallBackend(CeedOperatorGetCeed(op, &ceed));
17782b730f8bSJeremy L Thompson   CeedCallBackend(CeedCalloc(1, &impl));
17792b730f8bSJeremy L Thompson   CeedCallBackend(CeedOperatorSetData(op, impl));
17802b730f8bSJeremy L Thompson   CeedCallBackend(CeedSetBackendFunction(ceed, "Operator", op, "LinearAssembleQFunction", CeedOperatorLinearAssembleQFunction_Ref));
17812b730f8bSJeremy L Thompson   CeedCallBackend(CeedSetBackendFunction(ceed, "Operator", op, "LinearAssembleQFunctionUpdate", CeedOperatorLinearAssembleQFunctionUpdate_Ref));
17822b730f8bSJeremy L Thompson   CeedCallBackend(CeedSetBackendFunction(ceed, "Operator", op, "ApplyAdd", CeedOperatorApplyAdd_Ref));
17832b730f8bSJeremy L Thompson   CeedCallBackend(CeedSetBackendFunction(ceed, "Operator", op, "Destroy", CeedOperatorDestroy_Ref));
17849bc66399SJeremy L Thompson   CeedCallBackend(CeedDestroy(&ceed));
1785e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
178621617c04Sjeremylt }
17872a86cc9dSSebastian Grimberg 
17882a86cc9dSSebastian Grimberg //------------------------------------------------------------------------------
178948acf710SJeremy L Thompson // Operator Create At Points
179048acf710SJeremy L Thompson //------------------------------------------------------------------------------
179148acf710SJeremy L Thompson int CeedOperatorCreateAtPoints_Ref(CeedOperator op) {
179248acf710SJeremy L Thompson   Ceed              ceed;
179348acf710SJeremy L Thompson   CeedOperator_Ref *impl;
179448acf710SJeremy L Thompson 
179548acf710SJeremy L Thompson   CeedCallBackend(CeedOperatorGetCeed(op, &ceed));
179648acf710SJeremy L Thompson   CeedCallBackend(CeedCalloc(1, &impl));
179748acf710SJeremy L Thompson   CeedCallBackend(CeedOperatorSetData(op, impl));
1798e13f2367SZach Atkins   CeedCallBackend(CeedSetBackendFunction(ceed, "Operator", op, "LinearAssembleQFunction", CeedOperatorLinearAssembleQFunctionAtPoints_Ref));
1799e13f2367SZach Atkins   CeedCallBackend(
1800e13f2367SZach Atkins       CeedSetBackendFunction(ceed, "Operator", op, "LinearAssembleQFunctionUpdate", CeedOperatorLinearAssembleQFunctionAtPointsUpdate_Ref));
1801fb133d4bSJeremy L Thompson   CeedCallBackend(CeedSetBackendFunction(ceed, "Operator", op, "LinearAssembleAddDiagonal", CeedOperatorLinearAssembleAddDiagonalAtPoints_Ref));
1802ed094490SJeremy L Thompson   CeedCallBackend(CeedSetBackendFunction(ceed, "Operator", op, "LinearAssembleSingle", CeedOperatorAssembleSingleAtPoints_Ref));
180348acf710SJeremy L Thompson   CeedCallBackend(CeedSetBackendFunction(ceed, "Operator", op, "ApplyAdd", CeedOperatorApplyAddAtPoints_Ref));
180448acf710SJeremy L Thompson   CeedCallBackend(CeedSetBackendFunction(ceed, "Operator", op, "Destroy", CeedOperatorDestroy_Ref));
18059bc66399SJeremy L Thompson   CeedCallBackend(CeedDestroy(&ceed));
180648acf710SJeremy L Thompson   return CEED_ERROR_SUCCESS;
180748acf710SJeremy L Thompson }
180848acf710SJeremy L Thompson 
180948acf710SJeremy L Thompson //------------------------------------------------------------------------------
1810