13d8e8822SJeremy L Thompson // Copyright (c) 2017-2022, 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 8ec3da8bcSJed Brown #include <ceed/backend.h> 9*2b730f8bSJeremy L Thompson #include <ceed/ceed.h> 103d576824SJeremy L Thompson #include <math.h> 113d576824SJeremy L Thompson #include <stdbool.h> 123d576824SJeremy L Thompson #include <string.h> 13*2b730f8bSJeremy L Thompson 1421617c04Sjeremylt #include "ceed-ref.h" 1521617c04Sjeremylt 16f10650afSjeremylt //------------------------------------------------------------------------------ 17f10650afSjeremylt // Basis Apply 18f10650afSjeremylt //------------------------------------------------------------------------------ 19*2b730f8bSJeremy L Thompson static int CeedBasisApply_Ref(CeedBasis basis, CeedInt num_elem, CeedTransposeMode t_mode, CeedEvalMode eval_mode, CeedVector U, CeedVector V) { 204ce2993fSjeremylt Ceed ceed; 21*2b730f8bSJeremy L Thompson CeedCallBackend(CeedBasisGetCeed(basis, &ceed)); 2250c301a5SRezgar Shakeri CeedInt dim, num_comp, num_nodes, num_qpts, Q_comp; 23*2b730f8bSJeremy L Thompson CeedCallBackend(CeedBasisGetDimension(basis, &dim)); 24*2b730f8bSJeremy L Thompson CeedCallBackend(CeedBasisGetNumComponents(basis, &num_comp)); 25*2b730f8bSJeremy L Thompson CeedCallBackend(CeedBasisGetNumNodes(basis, &num_nodes)); 26*2b730f8bSJeremy L Thompson CeedCallBackend(CeedBasisGetNumQuadraturePoints(basis, &num_qpts)); 27*2b730f8bSJeremy L Thompson CeedCallBackend(CeedBasisGetNumQuadratureComponents(basis, &Q_comp)); 282f86a920SJeremy L Thompson CeedTensorContract contract; 29*2b730f8bSJeremy L Thompson CeedCallBackend(CeedBasisGetTensorContract(basis, &contract)); 30d1d35e2fSjeremylt const CeedInt add = (t_mode == CEED_TRANSPOSE); 31aedaa0e5Sjeremylt const CeedScalar *u; 32aedaa0e5Sjeremylt CeedScalar *v; 33a7b7f929Sjeremylt if (U != CEED_VECTOR_NONE) { 34*2b730f8bSJeremy L Thompson CeedCallBackend(CeedVectorGetArrayRead(U, CEED_MEM_HOST, &u)); 35d1d35e2fSjeremylt } else if (eval_mode != CEED_EVAL_WEIGHT) { 36c042f62fSJeremy L Thompson // LCOV_EXCL_START 37*2b730f8bSJeremy L Thompson return CeedError(ceed, CEED_ERROR_BACKEND, "An input vector is required for this CeedEvalMode"); 38c042f62fSJeremy L Thompson // LCOV_EXCL_STOP 39aedaa0e5Sjeremylt } 40*2b730f8bSJeremy L Thompson CeedCallBackend(CeedVectorGetArrayWrite(V, CEED_MEM_HOST, &v)); 4121617c04Sjeremylt 428d94b059Sjeremylt // Clear v if operating in transpose 43d1d35e2fSjeremylt if (t_mode == CEED_TRANSPOSE) { 44d1d35e2fSjeremylt const CeedInt v_size = num_elem * num_comp * num_nodes; 45*2b730f8bSJeremy L Thompson for (CeedInt i = 0; i < v_size; i++) v[i] = (CeedScalar)0.0; 4621617c04Sjeremylt } 47d1d35e2fSjeremylt bool tensor_basis; 48*2b730f8bSJeremy L Thompson CeedCallBackend(CeedBasisIsTensor(basis, &tensor_basis)); 4984a01de5SJeremy L Thompson // Tensor basis 50d1d35e2fSjeremylt if (tensor_basis) { 51d1d35e2fSjeremylt CeedInt P_1d, Q_1d; 52*2b730f8bSJeremy L Thompson CeedCallBackend(CeedBasisGetNumNodes1D(basis, &P_1d)); 53*2b730f8bSJeremy L Thompson CeedCallBackend(CeedBasisGetNumQuadraturePoints1D(basis, &Q_1d)); 54d1d35e2fSjeremylt switch (eval_mode) { 558d94b059Sjeremylt // Interpolate to/from quadrature points 56a2b73c81Sjeremylt case CEED_EVAL_INTERP: { 57dfe03796SJeremy L Thompson CeedBasis_Ref *impl; 58*2b730f8bSJeremy L Thompson CeedCallBackend(CeedBasisGetData(basis, &impl)); 598c1105f8SJeremy L Thompson if (impl->has_collo_interp) { 60d1d35e2fSjeremylt memcpy(v, u, num_elem * num_comp * num_nodes * sizeof(u[0])); 61dfe03796SJeremy L Thompson } else { 62d1d35e2fSjeremylt CeedInt P = P_1d, Q = Q_1d; 63d1d35e2fSjeremylt if (t_mode == CEED_TRANSPOSE) { 64*2b730f8bSJeremy L Thompson P = Q_1d; 65*2b730f8bSJeremy L Thompson Q = P_1d; 6621617c04Sjeremylt } 67d1d35e2fSjeremylt CeedInt pre = num_comp * CeedIntPow(P, dim - 1), post = num_elem; 68d1d35e2fSjeremylt CeedScalar tmp[2][num_elem * num_comp * Q * CeedIntPow(P > Q ? P : Q, dim - 1)]; 69d1d35e2fSjeremylt const CeedScalar *interp_1d; 70*2b730f8bSJeremy L Thompson CeedCallBackend(CeedBasisGetInterp1D(basis, &interp_1d)); 7121617c04Sjeremylt for (CeedInt d = 0; d < dim; d++) { 72*2b730f8bSJeremy L Thompson CeedCallBackend(CeedTensorContractApply(contract, pre, P, post, Q, interp_1d, t_mode, add && (d == dim - 1), d == 0 ? u : tmp[d % 2], 73*2b730f8bSJeremy L Thompson d == dim - 1 ? v : tmp[(d + 1) % 2])); 7421617c04Sjeremylt pre /= P; 7521617c04Sjeremylt post *= Q; 7621617c04Sjeremylt } 77dfe03796SJeremy L Thompson } 78a2b73c81Sjeremylt } break; 798d94b059Sjeremylt // Evaluate the gradient to/from quadrature points 80a2b73c81Sjeremylt case CEED_EVAL_GRAD: { 8121617c04Sjeremylt // In CEED_NOTRANSPOSE mode: 82d1d35e2fSjeremylt // u has shape [dim, num_comp, P^dim, num_elem], row-major layout 83d1d35e2fSjeremylt // v has shape [dim, num_comp, Q^dim, num_elem], row-major layout 8421617c04Sjeremylt // In CEED_TRANSPOSE mode, the sizes of u and v are switched. 85d1d35e2fSjeremylt CeedInt P = P_1d, Q = Q_1d; 86d1d35e2fSjeremylt if (t_mode == CEED_TRANSPOSE) { 87d1d35e2fSjeremylt P = Q_1d, Q = Q_1d; 8821617c04Sjeremylt } 8984a01de5SJeremy L Thompson CeedBasis_Ref *impl; 90*2b730f8bSJeremy L Thompson CeedCallBackend(CeedBasisGetData(basis, &impl)); 91d1d35e2fSjeremylt CeedInt pre = num_comp * CeedIntPow(P, dim - 1), post = num_elem; 92d1d35e2fSjeremylt const CeedScalar *interp_1d; 93*2b730f8bSJeremy L Thompson CeedCallBackend(CeedBasisGetInterp1D(basis, &interp_1d)); 948c1105f8SJeremy L Thompson if (impl->collo_grad_1d) { 95d1d35e2fSjeremylt CeedScalar tmp[2][num_elem * num_comp * Q * CeedIntPow(P > Q ? P : Q, dim - 1)]; 96d1d35e2fSjeremylt CeedScalar interp[num_elem * num_comp * Q * CeedIntPow(P > Q ? P : Q, dim - 1)]; 9784a01de5SJeremy L Thompson // Interpolate to quadrature points (NoTranspose) 9884a01de5SJeremy L Thompson // or Grad to quadrature points (Transpose) 9921617c04Sjeremylt for (CeedInt d = 0; d < dim; d++) { 100*2b730f8bSJeremy L Thompson CeedCallBackend(CeedTensorContractApply(contract, pre, P, post, Q, (t_mode == CEED_NOTRANSPOSE ? interp_1d : impl->collo_grad_1d), t_mode, 101*2b730f8bSJeremy L Thompson add && (d > 0), 102*2b730f8bSJeremy L Thompson (t_mode == CEED_NOTRANSPOSE ? (d == 0 ? u : tmp[d % 2]) : u + d * num_qpts * num_comp * num_elem), 103*2b730f8bSJeremy L Thompson (t_mode == CEED_NOTRANSPOSE ? (d == dim - 1 ? interp : tmp[(d + 1) % 2]) : interp))); 10421617c04Sjeremylt pre /= P; 10521617c04Sjeremylt post *= Q; 10621617c04Sjeremylt } 10784a01de5SJeremy L Thompson // Grad to quadrature points (NoTranspose) 1088795c945Sjeremylt // or Interpolate to nodes (Transpose) 109d1d35e2fSjeremylt P = Q_1d, Q = Q_1d; 110d1d35e2fSjeremylt if (t_mode == CEED_TRANSPOSE) { 111d1d35e2fSjeremylt P = Q_1d, Q = P_1d; 11284a01de5SJeremy L Thompson } 113d1d35e2fSjeremylt pre = num_comp * CeedIntPow(P, dim - 1), post = num_elem; 11484a01de5SJeremy L Thompson for (CeedInt d = 0; d < dim; d++) { 115*2b730f8bSJeremy L Thompson CeedCallBackend(CeedTensorContractApply( 116*2b730f8bSJeremy L Thompson contract, pre, P, post, Q, (t_mode == CEED_NOTRANSPOSE ? impl->collo_grad_1d : interp_1d), t_mode, add && (d == dim - 1), 117*2b730f8bSJeremy L Thompson (t_mode == CEED_NOTRANSPOSE ? interp : (d == 0 ? interp : tmp[d % 2])), 118*2b730f8bSJeremy L Thompson (t_mode == CEED_NOTRANSPOSE ? v + d * num_qpts * num_comp * num_elem : (d == dim - 1 ? v : tmp[(d + 1) % 2])))); 11984a01de5SJeremy L Thompson pre /= P; 12084a01de5SJeremy L Thompson post *= Q; 12121617c04Sjeremylt } 1228c1105f8SJeremy L Thompson } else if (impl->has_collo_interp) { // Qpts collocated with nodes 123d1d35e2fSjeremylt const CeedScalar *grad_1d; 124*2b730f8bSJeremy L Thompson CeedCallBackend(CeedBasisGetGrad1D(basis, &grad_1d)); 125dfe03796SJeremy L Thompson 126dfe03796SJeremy L Thompson // Dim contractions, identity in other directions 127d1d35e2fSjeremylt CeedInt pre = num_comp * CeedIntPow(P, dim - 1), post = num_elem; 128c6158135Sjeremylt for (CeedInt d = 0; d < dim; d++) { 129*2b730f8bSJeremy L Thompson CeedCallBackend(CeedTensorContractApply(contract, pre, P, post, Q, grad_1d, t_mode, add && (d > 0), 130*2b730f8bSJeremy L Thompson t_mode == CEED_NOTRANSPOSE ? u : u + d * num_comp * num_qpts * num_elem, 131*2b730f8bSJeremy L Thompson t_mode == CEED_TRANSPOSE ? v : v + d * num_comp * num_qpts * num_elem)); 132c6158135Sjeremylt pre /= P; 133c6158135Sjeremylt post *= Q; 134dfe03796SJeremy L Thompson } 135a7bd39daSjeremylt } else { // Underintegration, P > Q 136d1d35e2fSjeremylt const CeedScalar *grad_1d; 137*2b730f8bSJeremy L Thompson CeedCallBackend(CeedBasisGetGrad1D(basis, &grad_1d)); 138a7bd39daSjeremylt 139d1d35e2fSjeremylt if (t_mode == CEED_TRANSPOSE) { 140d1d35e2fSjeremylt P = Q_1d, Q = P_1d; 141a7bd39daSjeremylt } 142d1d35e2fSjeremylt CeedScalar tmp[2][num_elem * num_comp * Q * CeedIntPow(P > Q ? P : Q, dim - 1)]; 143a7bd39daSjeremylt 144a7bd39daSjeremylt // Dim**2 contractions, apply grad when pass == dim 145a7bd39daSjeremylt for (CeedInt p = 0; p < dim; p++) { 146d1d35e2fSjeremylt CeedInt pre = num_comp * CeedIntPow(P, dim - 1), post = num_elem; 147a7bd39daSjeremylt for (CeedInt d = 0; d < dim; d++) { 148*2b730f8bSJeremy L Thompson CeedCallBackend(CeedTensorContractApply( 149*2b730f8bSJeremy L Thompson contract, pre, P, post, Q, (p == d) ? grad_1d : interp_1d, t_mode, add && (d == dim - 1), 150*2b730f8bSJeremy L Thompson (d == 0 ? (t_mode == CEED_NOTRANSPOSE ? u : u + p * num_comp * num_qpts * num_elem) : tmp[d % 2]), 151*2b730f8bSJeremy L Thompson (d == dim - 1 ? (t_mode == CEED_TRANSPOSE ? v : v + p * num_comp * num_qpts * num_elem) : tmp[(d + 1) % 2]))); 152a7bd39daSjeremylt pre /= P; 153a7bd39daSjeremylt post *= Q; 154a7bd39daSjeremylt } 155a7bd39daSjeremylt } 156a7bd39daSjeremylt } 157a2b73c81Sjeremylt } break; 1588d94b059Sjeremylt // Retrieve interpolation weights 159a2b73c81Sjeremylt case CEED_EVAL_WEIGHT: { 160*2b730f8bSJeremy L Thompson if (t_mode == CEED_TRANSPOSE) { 161c042f62fSJeremy L Thompson // LCOV_EXCL_START 162*2b730f8bSJeremy L Thompson return CeedError(ceed, CEED_ERROR_BACKEND, "CEED_EVAL_WEIGHT incompatible with CEED_TRANSPOSE"); 163c042f62fSJeremy L Thompson // LCOV_EXCL_STOP 164*2b730f8bSJeremy L Thompson } 165d1d35e2fSjeremylt CeedInt Q = Q_1d; 166d1d35e2fSjeremylt const CeedScalar *q_weight_1d; 167*2b730f8bSJeremy L Thompson CeedCallBackend(CeedBasisGetQWeights(basis, &q_weight_1d)); 16821617c04Sjeremylt for (CeedInt d = 0; d < dim; d++) { 169b5cf12eeSjeremylt CeedInt pre = CeedIntPow(Q, dim - d - 1), post = CeedIntPow(Q, d); 170*2b730f8bSJeremy L Thompson for (CeedInt i = 0; i < pre; i++) { 171*2b730f8bSJeremy L Thompson for (CeedInt j = 0; j < Q; j++) { 17284a01de5SJeremy L Thompson for (CeedInt k = 0; k < post; k++) { 173*2b730f8bSJeremy L Thompson CeedScalar w = q_weight_1d[j] * (d == 0 ? 1 : v[((i * Q + j) * post + k) * num_elem]); 174*2b730f8bSJeremy L Thompson for (CeedInt e = 0; e < num_elem; e++) v[((i * Q + j) * post + k) * num_elem + e] = w; 175*2b730f8bSJeremy L Thompson } 176*2b730f8bSJeremy L Thompson } 17784a01de5SJeremy L Thompson } 17821617c04Sjeremylt } 179a2b73c81Sjeremylt } break; 180c042f62fSJeremy L Thompson // LCOV_EXCL_START 1818d94b059Sjeremylt // Evaluate the divergence to/from the quadrature points 182a2b73c81Sjeremylt case CEED_EVAL_DIV: 183e15f9bd0SJeremy L Thompson return CeedError(ceed, CEED_ERROR_BACKEND, "CEED_EVAL_DIV not supported"); 1848d94b059Sjeremylt // Evaluate the curl to/from the quadrature points 185a2b73c81Sjeremylt case CEED_EVAL_CURL: 186e15f9bd0SJeremy L Thompson return CeedError(ceed, CEED_ERROR_BACKEND, "CEED_EVAL_CURL not supported"); 1878d94b059Sjeremylt // Take no action, BasisApply should not have been called 188a2b73c81Sjeremylt case CEED_EVAL_NONE: 189*2b730f8bSJeremy L Thompson return CeedError(ceed, CEED_ERROR_BACKEND, "CEED_EVAL_NONE does not make sense in this context"); 190c042f62fSJeremy L Thompson // LCOV_EXCL_STOP 19121617c04Sjeremylt } 192a8de75f0Sjeremylt } else { 193a8de75f0Sjeremylt // Non-tensor basis 194d1d35e2fSjeremylt switch (eval_mode) { 19584a01de5SJeremy L Thompson // Interpolate to/from quadrature points 196a8de75f0Sjeremylt case CEED_EVAL_INTERP: { 19750c301a5SRezgar Shakeri CeedInt P = num_nodes, Q = Q_comp * num_qpts; 1986c58de82SJeremy L Thompson const CeedScalar *interp; 199*2b730f8bSJeremy L Thompson CeedCallBackend(CeedBasisGetInterp(basis, &interp)); 200d1d35e2fSjeremylt if (t_mode == CEED_TRANSPOSE) { 201*2b730f8bSJeremy L Thompson P = Q_comp * num_qpts; 202*2b730f8bSJeremy L Thompson Q = num_nodes; 203a8de75f0Sjeremylt } 204*2b730f8bSJeremy L Thompson CeedCallBackend(CeedTensorContractApply(contract, num_comp, P, num_elem, Q, interp, t_mode, add, u, v)); 205*2b730f8bSJeremy L Thompson } break; 20684a01de5SJeremy L Thompson // Evaluate the gradient to/from quadrature points 207a8de75f0Sjeremylt case CEED_EVAL_GRAD: { 208d1d35e2fSjeremylt CeedInt P = num_nodes, Q = num_qpts; 209d1d35e2fSjeremylt CeedInt dim_stride = num_qpts * num_comp * num_elem; 210d1d35e2fSjeremylt CeedInt grad_stride = num_qpts * num_nodes; 2116c58de82SJeremy L Thompson const CeedScalar *grad; 212*2b730f8bSJeremy L Thompson CeedCallBackend(CeedBasisGetGrad(basis, &grad)); 213d1d35e2fSjeremylt if (t_mode == CEED_TRANSPOSE) { 214*2b730f8bSJeremy L Thompson P = num_qpts; 215*2b730f8bSJeremy L Thompson Q = num_nodes; 216475a782bSnbeams for (CeedInt d = 0; d < dim; d++) { 217*2b730f8bSJeremy L Thompson CeedCallBackend(CeedTensorContractApply(contract, num_comp, P, num_elem, Q, grad + d * grad_stride, t_mode, add, u + d * dim_stride, v)); 218475a782bSnbeams } 219475a782bSnbeams } else { 220475a782bSnbeams for (CeedInt d = 0; d < dim; d++) { 221*2b730f8bSJeremy L Thompson CeedCallBackend(CeedTensorContractApply(contract, num_comp, P, num_elem, Q, grad + d * grad_stride, t_mode, add, u, v + d * dim_stride)); 222475a782bSnbeams } 223475a782bSnbeams } 224*2b730f8bSJeremy L Thompson } break; 22584a01de5SJeremy L Thompson // Retrieve interpolation weights 226a8de75f0Sjeremylt case CEED_EVAL_WEIGHT: { 227*2b730f8bSJeremy L Thompson if (t_mode == CEED_TRANSPOSE) { 228c042f62fSJeremy L Thompson // LCOV_EXCL_START 229*2b730f8bSJeremy L Thompson return CeedError(ceed, CEED_ERROR_BACKEND, "CEED_EVAL_WEIGHT incompatible with CEED_TRANSPOSE"); 230c042f62fSJeremy L Thompson // LCOV_EXCL_STOP 231*2b730f8bSJeremy L Thompson } 232d1d35e2fSjeremylt const CeedScalar *q_weight; 233*2b730f8bSJeremy L Thompson CeedCallBackend(CeedBasisGetQWeights(basis, &q_weight)); 234*2b730f8bSJeremy L Thompson for (CeedInt i = 0; i < num_qpts; i++) { 235*2b730f8bSJeremy L Thompson for (CeedInt e = 0; e < num_elem; e++) v[i * num_elem + e] = q_weight[i]; 236*2b730f8bSJeremy L Thompson } 237a8de75f0Sjeremylt } break; 23884a01de5SJeremy L Thompson // Evaluate the divergence to/from the quadrature points 23950c301a5SRezgar Shakeri case CEED_EVAL_DIV: { 24050c301a5SRezgar Shakeri CeedInt P = num_nodes, Q = num_qpts; 24150c301a5SRezgar Shakeri const CeedScalar *div; 242*2b730f8bSJeremy L Thompson CeedCallBackend(CeedBasisGetDiv(basis, &div)); 24350c301a5SRezgar Shakeri if (t_mode == CEED_TRANSPOSE) { 244*2b730f8bSJeremy L Thompson P = num_qpts; 245*2b730f8bSJeremy L Thompson Q = num_nodes; 24650c301a5SRezgar Shakeri } 247*2b730f8bSJeremy L Thompson CeedCallBackend(CeedTensorContractApply(contract, num_comp, P, num_elem, Q, div, t_mode, add, u, v)); 24850c301a5SRezgar Shakeri } break; 24950c301a5SRezgar Shakeri // LCOV_EXCL_START 25084a01de5SJeremy L Thompson // Evaluate the curl to/from the quadrature points 251a8de75f0Sjeremylt case CEED_EVAL_CURL: 252e15f9bd0SJeremy L Thompson return CeedError(ceed, CEED_ERROR_BACKEND, "CEED_EVAL_CURL not supported"); 25384a01de5SJeremy L Thompson // Take no action, BasisApply should not have been called 254a8de75f0Sjeremylt case CEED_EVAL_NONE: 255*2b730f8bSJeremy L Thompson return CeedError(ceed, CEED_ERROR_BACKEND, "CEED_EVAL_NONE does not make sense in this context"); 256c042f62fSJeremy L Thompson // LCOV_EXCL_STOP 257a8de75f0Sjeremylt } 258a8de75f0Sjeremylt } 259a7b7f929Sjeremylt if (U != CEED_VECTOR_NONE) { 260*2b730f8bSJeremy L Thompson CeedCallBackend(CeedVectorRestoreArrayRead(U, &u)); 261aedaa0e5Sjeremylt } 262*2b730f8bSJeremy L Thompson CeedCallBackend(CeedVectorRestoreArray(V, &v)); 263e15f9bd0SJeremy L Thompson return CEED_ERROR_SUCCESS; 26421617c04Sjeremylt } 26521617c04Sjeremylt 266f10650afSjeremylt //------------------------------------------------------------------------------ 26750c301a5SRezgar Shakeri // Basis Create Non-Tensor H^1 268f10650afSjeremylt //------------------------------------------------------------------------------ 269*2b730f8bSJeremy L Thompson int CeedBasisCreateH1_Ref(CeedElemTopology topo, CeedInt dim, CeedInt num_nodes, CeedInt num_qpts, const CeedScalar *interp, const CeedScalar *grad, 270*2b730f8bSJeremy L Thompson const CeedScalar *q_ref, const CeedScalar *q_weight, CeedBasis basis) { 271f10650afSjeremylt Ceed ceed; 272*2b730f8bSJeremy L Thompson CeedCallBackend(CeedBasisGetCeed(basis, &ceed)); 273f10650afSjeremylt 274f10650afSjeremylt Ceed parent; 275*2b730f8bSJeremy L Thompson CeedCallBackend(CeedGetParent(ceed, &parent)); 276f10650afSjeremylt CeedTensorContract contract; 277*2b730f8bSJeremy L Thompson CeedCallBackend(CeedTensorContractCreate(parent, basis, &contract)); 278*2b730f8bSJeremy L Thompson CeedCallBackend(CeedBasisSetTensorContract(basis, contract)); 279f10650afSjeremylt 280*2b730f8bSJeremy L Thompson CeedCallBackend(CeedSetBackendFunction(ceed, "Basis", basis, "Apply", CeedBasisApply_Ref)); 281f10650afSjeremylt 282e15f9bd0SJeremy L Thompson return CEED_ERROR_SUCCESS; 283f10650afSjeremylt } 284f10650afSjeremylt 285f10650afSjeremylt //------------------------------------------------------------------------------ 28650c301a5SRezgar Shakeri // Basis Create Non-Tensor H(div) 28750c301a5SRezgar Shakeri //------------------------------------------------------------------------------ 288*2b730f8bSJeremy L Thompson int CeedBasisCreateHdiv_Ref(CeedElemTopology topo, CeedInt dim, CeedInt num_nodes, CeedInt num_qpts, const CeedScalar *interp, const CeedScalar *div, 289*2b730f8bSJeremy L Thompson const CeedScalar *q_ref, const CeedScalar *q_weight, CeedBasis basis) { 29050c301a5SRezgar Shakeri Ceed ceed; 291*2b730f8bSJeremy L Thompson CeedCallBackend(CeedBasisGetCeed(basis, &ceed)); 29250c301a5SRezgar Shakeri 29350c301a5SRezgar Shakeri Ceed parent; 294*2b730f8bSJeremy L Thompson CeedCallBackend(CeedGetParent(ceed, &parent)); 29550c301a5SRezgar Shakeri CeedTensorContract contract; 296*2b730f8bSJeremy L Thompson CeedCallBackend(CeedTensorContractCreate(parent, basis, &contract)); 297*2b730f8bSJeremy L Thompson CeedCallBackend(CeedBasisSetTensorContract(basis, contract)); 29850c301a5SRezgar Shakeri 299*2b730f8bSJeremy L Thompson CeedCallBackend(CeedSetBackendFunction(ceed, "Basis", basis, "Apply", CeedBasisApply_Ref)); 30050c301a5SRezgar Shakeri 30150c301a5SRezgar Shakeri return CEED_ERROR_SUCCESS; 30250c301a5SRezgar Shakeri } 30350c301a5SRezgar Shakeri 30450c301a5SRezgar Shakeri //------------------------------------------------------------------------------ 305f10650afSjeremylt // Basis Destroy Tensor 306f10650afSjeremylt //------------------------------------------------------------------------------ 30784a01de5SJeremy L Thompson static int CeedBasisDestroyTensor_Ref(CeedBasis basis) { 30884a01de5SJeremy L Thompson CeedBasis_Ref *impl; 309*2b730f8bSJeremy L Thompson CeedCallBackend(CeedBasisGetData(basis, &impl)); 310*2b730f8bSJeremy L Thompson CeedCallBackend(CeedFree(&impl->collo_grad_1d)); 311*2b730f8bSJeremy L Thompson CeedCallBackend(CeedFree(&impl)); 31284a01de5SJeremy L Thompson 313e15f9bd0SJeremy L Thompson return CEED_ERROR_SUCCESS; 31421617c04Sjeremylt } 31521617c04Sjeremylt 316f10650afSjeremylt //------------------------------------------------------------------------------ 317f10650afSjeremylt // Basis Create Tensor 318f10650afSjeremylt //------------------------------------------------------------------------------ 319*2b730f8bSJeremy L Thompson int CeedBasisCreateTensorH1_Ref(CeedInt dim, CeedInt P_1d, CeedInt Q_1d, const CeedScalar *interp_1d, const CeedScalar *grad_1d, 320*2b730f8bSJeremy L Thompson const CeedScalar *q_ref_1d, const CeedScalar *q_weight_1d, CeedBasis basis) { 321fe2413ffSjeremylt Ceed ceed; 322*2b730f8bSJeremy L Thompson CeedCallBackend(CeedBasisGetCeed(basis, &ceed)); 32384a01de5SJeremy L Thompson CeedBasis_Ref *impl; 324*2b730f8bSJeremy L Thompson CeedCallBackend(CeedCalloc(1, &impl)); 325dfe03796SJeremy L Thompson // Check for collocated interp 326d1d35e2fSjeremylt if (Q_1d == P_1d) { 327dfe03796SJeremy L Thompson bool collocated = 1; 328d1d35e2fSjeremylt for (CeedInt i = 0; i < P_1d; i++) { 329d1d35e2fSjeremylt collocated = collocated && (fabs(interp_1d[i + P_1d * i] - 1.0) < 1e-14); 330*2b730f8bSJeremy L Thompson for (CeedInt j = 0; j < P_1d; j++) { 331*2b730f8bSJeremy L Thompson if (j != i) collocated = collocated && (fabs(interp_1d[j + P_1d * i]) < 1e-14); 332*2b730f8bSJeremy L Thompson } 333dfe03796SJeremy L Thompson } 3348c1105f8SJeremy L Thompson impl->has_collo_interp = collocated; 335dfe03796SJeremy L Thompson } 336dfe03796SJeremy L Thompson // Calculate collocated grad 3378c1105f8SJeremy L Thompson if (Q_1d >= P_1d && !impl->has_collo_interp) { 338*2b730f8bSJeremy L Thompson CeedCallBackend(CeedMalloc(Q_1d * Q_1d, &impl->collo_grad_1d)); 339*2b730f8bSJeremy L Thompson CeedCallBackend(CeedBasisGetCollocatedGrad(basis, impl->collo_grad_1d)); 340a7bd39daSjeremylt } 341*2b730f8bSJeremy L Thompson CeedCallBackend(CeedBasisSetData(basis, impl)); 342fe2413ffSjeremylt 3432f86a920SJeremy L Thompson Ceed parent; 344*2b730f8bSJeremy L Thompson CeedCallBackend(CeedGetParent(ceed, &parent)); 3452f86a920SJeremy L Thompson CeedTensorContract contract; 346*2b730f8bSJeremy L Thompson CeedCallBackend(CeedTensorContractCreate(parent, basis, &contract)); 347*2b730f8bSJeremy L Thompson CeedCallBackend(CeedBasisSetTensorContract(basis, contract)); 3482f86a920SJeremy L Thompson 349*2b730f8bSJeremy L Thompson CeedCallBackend(CeedSetBackendFunction(ceed, "Basis", basis, "Apply", CeedBasisApply_Ref)); 350*2b730f8bSJeremy L Thompson CeedCallBackend(CeedSetBackendFunction(ceed, "Basis", basis, "Destroy", CeedBasisDestroyTensor_Ref)); 351e15f9bd0SJeremy L Thompson return CEED_ERROR_SUCCESS; 35221617c04Sjeremylt } 353a8de75f0Sjeremylt 354f10650afSjeremylt //------------------------------------------------------------------------------ 355