15aed82e4SJeremy L Thompson // Copyright (c) 2017-2024, 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 <math.h> 113d576824SJeremy L Thompson #include <stdbool.h> 123d576824SJeremy L Thompson #include <string.h> 132b730f8bSJeremy L Thompson 1421617c04Sjeremylt #include "ceed-ref.h" 1521617c04Sjeremylt 16f10650afSjeremylt //------------------------------------------------------------------------------ 17f10650afSjeremylt // Basis Apply 18f10650afSjeremylt //------------------------------------------------------------------------------ 19db2becc9SJeremy L Thompson static int CeedBasisApplyCore_Ref(CeedBasis basis, bool apply_add, CeedInt num_elem, CeedTransposeMode t_mode, CeedEvalMode eval_mode, CeedVector U, 20db2becc9SJeremy L Thompson CeedVector V) { 21db2becc9SJeremy L Thompson bool is_tensor_basis, add = apply_add || (t_mode == CEED_TRANSPOSE); 22c4e3f59bSSebastian Grimberg CeedInt dim, num_comp, q_comp, num_nodes, num_qpts; 23ad70ee2cSJeremy L Thompson const CeedScalar *u; 24ad70ee2cSJeremy L Thompson CeedScalar *v; 25ad70ee2cSJeremy L Thompson CeedTensorContract contract; 26ad70ee2cSJeremy L Thompson CeedBasis_Ref *impl; 27ad70ee2cSJeremy L Thompson 28ad70ee2cSJeremy L Thompson CeedCallBackend(CeedBasisGetData(basis, &impl)); 292b730f8bSJeremy L Thompson CeedCallBackend(CeedBasisGetDimension(basis, &dim)); 302b730f8bSJeremy L Thompson CeedCallBackend(CeedBasisGetNumComponents(basis, &num_comp)); 31c4e3f59bSSebastian Grimberg CeedCallBackend(CeedBasisGetNumQuadratureComponents(basis, eval_mode, &q_comp)); 322b730f8bSJeremy L Thompson CeedCallBackend(CeedBasisGetNumNodes(basis, &num_nodes)); 332b730f8bSJeremy L Thompson CeedCallBackend(CeedBasisGetNumQuadraturePoints(basis, &num_qpts)); 342b730f8bSJeremy L Thompson CeedCallBackend(CeedBasisGetTensorContract(basis, &contract)); 356574a04fSJeremy L Thompson if (U != CEED_VECTOR_NONE) CeedCallBackend(CeedVectorGetArrayRead(U, CEED_MEM_HOST, &u)); 36*9bc66399SJeremy L Thompson else CeedCheck(eval_mode == CEED_EVAL_WEIGHT, CeedBasisReturnCeed(basis), CEED_ERROR_BACKEND, "An input vector is required for this CeedEvalMode"); 378d94b059Sjeremylt // Clear v if operating in transpose 38db2becc9SJeremy L Thompson if (apply_add) CeedCallBackend(CeedVectorGetArray(V, CEED_MEM_HOST, &v)); 39db2becc9SJeremy L Thompson else CeedCallBackend(CeedVectorGetArrayWrite(V, CEED_MEM_HOST, &v)); 40ad70ee2cSJeremy L Thompson 41db2becc9SJeremy L Thompson if (t_mode == CEED_TRANSPOSE && !apply_add) { 42db2becc9SJeremy L Thompson CeedSize len; 43db2becc9SJeremy L Thompson 44db2becc9SJeremy L Thompson CeedCallBackend(CeedVectorGetLength(V, &len)); 45db2becc9SJeremy L Thompson for (CeedInt i = 0; i < len; i++) v[i] = 0.0; 4621617c04Sjeremylt } 47ad70ee2cSJeremy L Thompson 486402da51SJeremy L Thompson CeedCallBackend(CeedBasisIsTensor(basis, &is_tensor_basis)); 496402da51SJeremy L Thompson if (is_tensor_basis) { 50c4e3f59bSSebastian Grimberg // Tensor basis 51d1d35e2fSjeremylt CeedInt P_1d, Q_1d; 52ad70ee2cSJeremy L Thompson 532b730f8bSJeremy L Thompson CeedCallBackend(CeedBasisGetNumNodes1D(basis, &P_1d)); 542b730f8bSJeremy L Thompson CeedCallBackend(CeedBasisGetNumQuadraturePoints1D(basis, &Q_1d)); 55d1d35e2fSjeremylt switch (eval_mode) { 568d94b059Sjeremylt // Interpolate to/from quadrature points 57a2b73c81Sjeremylt case CEED_EVAL_INTERP: { 588c1105f8SJeremy L Thompson if (impl->has_collo_interp) { 59d1d35e2fSjeremylt memcpy(v, u, num_elem * num_comp * num_nodes * sizeof(u[0])); 60dfe03796SJeremy L Thompson } else { 61d1d35e2fSjeremylt CeedInt P = P_1d, Q = Q_1d; 62ad70ee2cSJeremy L Thompson 63d1d35e2fSjeremylt if (t_mode == CEED_TRANSPOSE) { 642b730f8bSJeremy L Thompson P = Q_1d; 652b730f8bSJeremy 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; 70ad70ee2cSJeremy L Thompson 712b730f8bSJeremy L Thompson CeedCallBackend(CeedBasisGetInterp1D(basis, &interp_1d)); 7221617c04Sjeremylt for (CeedInt d = 0; d < dim; d++) { 732b730f8bSJeremy L Thompson CeedCallBackend(CeedTensorContractApply(contract, pre, P, post, Q, interp_1d, t_mode, add && (d == dim - 1), d == 0 ? u : tmp[d % 2], 742b730f8bSJeremy L Thompson d == dim - 1 ? v : tmp[(d + 1) % 2])); 7521617c04Sjeremylt pre /= P; 7621617c04Sjeremylt post *= Q; 7721617c04Sjeremylt } 78dfe03796SJeremy L Thompson } 79a2b73c81Sjeremylt } break; 808d94b059Sjeremylt // Evaluate the gradient to/from quadrature points 81a2b73c81Sjeremylt case CEED_EVAL_GRAD: { 8221617c04Sjeremylt // In CEED_NOTRANSPOSE mode: 83d1d35e2fSjeremylt // u has shape [dim, num_comp, P^dim, num_elem], row-major layout 84d1d35e2fSjeremylt // v has shape [dim, num_comp, Q^dim, num_elem], row-major layout 8521617c04Sjeremylt // In CEED_TRANSPOSE mode, the sizes of u and v are switched. 86d1d35e2fSjeremylt CeedInt P = P_1d, Q = Q_1d; 87ad70ee2cSJeremy L Thompson 88d1d35e2fSjeremylt if (t_mode == CEED_TRANSPOSE) { 891c66c397SJeremy L Thompson P = Q_1d; 901c66c397SJeremy L Thompson Q = Q_1d; 9121617c04Sjeremylt } 92d1d35e2fSjeremylt CeedInt pre = num_comp * CeedIntPow(P, dim - 1), post = num_elem; 93d1d35e2fSjeremylt const CeedScalar *interp_1d; 94ad70ee2cSJeremy L Thompson 952b730f8bSJeremy L Thompson CeedCallBackend(CeedBasisGetInterp1D(basis, &interp_1d)); 968c1105f8SJeremy L Thompson if (impl->collo_grad_1d) { 97d1d35e2fSjeremylt CeedScalar tmp[2][num_elem * num_comp * Q * CeedIntPow(P > Q ? P : Q, dim - 1)]; 98d1d35e2fSjeremylt CeedScalar interp[num_elem * num_comp * Q * CeedIntPow(P > Q ? P : Q, dim - 1)]; 99ad70ee2cSJeremy L Thompson 10084a01de5SJeremy L Thompson // Interpolate to quadrature points (NoTranspose) 10184a01de5SJeremy L Thompson // or Grad to quadrature points (Transpose) 10221617c04Sjeremylt for (CeedInt d = 0; d < dim; d++) { 1032b730f8bSJeremy L Thompson CeedCallBackend(CeedTensorContractApply(contract, pre, P, post, Q, (t_mode == CEED_NOTRANSPOSE ? interp_1d : impl->collo_grad_1d), t_mode, 104db2becc9SJeremy L Thompson (t_mode == CEED_TRANSPOSE) && (d > 0), 105db2becc9SJeremy L Thompson (t_mode == CEED_NOTRANSPOSE ? (d == 0 ? u : tmp[d % 2]) : &u[d * num_qpts * num_comp * num_elem]), 1062b730f8bSJeremy L Thompson (t_mode == CEED_NOTRANSPOSE ? (d == dim - 1 ? interp : tmp[(d + 1) % 2]) : interp))); 10721617c04Sjeremylt pre /= P; 10821617c04Sjeremylt post *= Q; 10921617c04Sjeremylt } 11084a01de5SJeremy L Thompson // Grad to quadrature points (NoTranspose) 1118795c945Sjeremylt // or Interpolate to nodes (Transpose) 112d1d35e2fSjeremylt P = Q_1d, Q = Q_1d; 113d1d35e2fSjeremylt if (t_mode == CEED_TRANSPOSE) { 1141c66c397SJeremy L Thompson P = Q_1d; 1151c66c397SJeremy L Thompson Q = P_1d; 11684a01de5SJeremy L Thompson } 117d1d35e2fSjeremylt pre = num_comp * CeedIntPow(P, dim - 1), post = num_elem; 11884a01de5SJeremy L Thompson for (CeedInt d = 0; d < dim; d++) { 1192b730f8bSJeremy L Thompson CeedCallBackend(CeedTensorContractApply( 120db2becc9SJeremy L Thompson contract, pre, P, post, Q, (t_mode == CEED_NOTRANSPOSE ? impl->collo_grad_1d : interp_1d), t_mode, 121db2becc9SJeremy L Thompson (t_mode == CEED_NOTRANSPOSE && apply_add) || (t_mode == CEED_TRANSPOSE && (d == dim - 1)), 1222b730f8bSJeremy L Thompson (t_mode == CEED_NOTRANSPOSE ? interp : (d == 0 ? interp : tmp[d % 2])), 123db2becc9SJeremy L Thompson (t_mode == CEED_NOTRANSPOSE ? &v[d * num_qpts * num_comp * num_elem] : (d == dim - 1 ? v : tmp[(d + 1) % 2])))); 12484a01de5SJeremy L Thompson pre /= P; 12584a01de5SJeremy L Thompson post *= Q; 12621617c04Sjeremylt } 1278c1105f8SJeremy L Thompson } else if (impl->has_collo_interp) { // Qpts collocated with nodes 128d1d35e2fSjeremylt const CeedScalar *grad_1d; 129ad70ee2cSJeremy L Thompson 1302b730f8bSJeremy L Thompson CeedCallBackend(CeedBasisGetGrad1D(basis, &grad_1d)); 131dfe03796SJeremy L Thompson 132dfe03796SJeremy L Thompson // Dim contractions, identity in other directions 133d1d35e2fSjeremylt CeedInt pre = num_comp * CeedIntPow(P, dim - 1), post = num_elem; 134ad70ee2cSJeremy L Thompson 135c6158135Sjeremylt for (CeedInt d = 0; d < dim; d++) { 1362b730f8bSJeremy L Thompson CeedCallBackend(CeedTensorContractApply(contract, pre, P, post, Q, grad_1d, t_mode, add && (d > 0), 137db2becc9SJeremy L Thompson t_mode == CEED_NOTRANSPOSE ? u : &u[d * num_comp * num_qpts * num_elem], 138db2becc9SJeremy L Thompson t_mode == CEED_TRANSPOSE ? v : &v[d * num_comp * num_qpts * num_elem])); 139c6158135Sjeremylt pre /= P; 140c6158135Sjeremylt post *= Q; 141dfe03796SJeremy L Thompson } 142a7bd39daSjeremylt } else { // Underintegration, P > Q 143d1d35e2fSjeremylt const CeedScalar *grad_1d; 144ad70ee2cSJeremy L Thompson 1452b730f8bSJeremy L Thompson CeedCallBackend(CeedBasisGetGrad1D(basis, &grad_1d)); 146a7bd39daSjeremylt 147d1d35e2fSjeremylt if (t_mode == CEED_TRANSPOSE) { 1481c66c397SJeremy L Thompson P = Q_1d; 1491c66c397SJeremy L Thompson Q = P_1d; 150a7bd39daSjeremylt } 151d1d35e2fSjeremylt CeedScalar tmp[2][num_elem * num_comp * Q * CeedIntPow(P > Q ? P : Q, dim - 1)]; 152a7bd39daSjeremylt 153a7bd39daSjeremylt // Dim**2 contractions, apply grad when pass == dim 154a7bd39daSjeremylt for (CeedInt p = 0; p < dim; p++) { 155d1d35e2fSjeremylt CeedInt pre = num_comp * CeedIntPow(P, dim - 1), post = num_elem; 156ad70ee2cSJeremy L Thompson 157a7bd39daSjeremylt for (CeedInt d = 0; d < dim; d++) { 1582b730f8bSJeremy L Thompson CeedCallBackend(CeedTensorContractApply( 1592b730f8bSJeremy L Thompson contract, pre, P, post, Q, (p == d) ? grad_1d : interp_1d, t_mode, add && (d == dim - 1), 160db2becc9SJeremy L Thompson (d == 0 ? (t_mode == CEED_NOTRANSPOSE ? u : &u[p * num_comp * num_qpts * num_elem]) : tmp[d % 2]), 161db2becc9SJeremy L Thompson (d == dim - 1 ? (t_mode == CEED_TRANSPOSE ? v : &v[p * num_comp * num_qpts * num_elem]) : tmp[(d + 1) % 2]))); 162a7bd39daSjeremylt pre /= P; 163a7bd39daSjeremylt post *= Q; 164a7bd39daSjeremylt } 165a7bd39daSjeremylt } 166a7bd39daSjeremylt } 167a2b73c81Sjeremylt } break; 1688d94b059Sjeremylt // Retrieve interpolation weights 169a2b73c81Sjeremylt case CEED_EVAL_WEIGHT: { 170d1d35e2fSjeremylt CeedInt Q = Q_1d; 171d1d35e2fSjeremylt const CeedScalar *q_weight_1d; 172ad70ee2cSJeremy L Thompson 173*9bc66399SJeremy L Thompson CeedCheck(t_mode == CEED_NOTRANSPOSE, CeedBasisReturnCeed(basis), CEED_ERROR_BACKEND, "CEED_EVAL_WEIGHT incompatible with CEED_TRANSPOSE"); 1742b730f8bSJeremy L Thompson CeedCallBackend(CeedBasisGetQWeights(basis, &q_weight_1d)); 17521617c04Sjeremylt for (CeedInt d = 0; d < dim; d++) { 176b5cf12eeSjeremylt CeedInt pre = CeedIntPow(Q, dim - d - 1), post = CeedIntPow(Q, d); 177ad70ee2cSJeremy L Thompson 1782b730f8bSJeremy L Thompson for (CeedInt i = 0; i < pre; i++) { 1792b730f8bSJeremy L Thompson for (CeedInt j = 0; j < Q; j++) { 18084a01de5SJeremy L Thompson for (CeedInt k = 0; k < post; k++) { 181ad70ee2cSJeremy L Thompson const CeedScalar w = q_weight_1d[j] * (d == 0 ? 1 : v[((i * Q + j) * post + k) * num_elem]); 182ad70ee2cSJeremy L Thompson 1832b730f8bSJeremy L Thompson for (CeedInt e = 0; e < num_elem; e++) v[((i * Q + j) * post + k) * num_elem + e] = w; 1842b730f8bSJeremy L Thompson } 1852b730f8bSJeremy L Thompson } 18684a01de5SJeremy L Thompson } 18721617c04Sjeremylt } 188a2b73c81Sjeremylt } break; 189c042f62fSJeremy L Thompson // LCOV_EXCL_START 190a2b73c81Sjeremylt case CEED_EVAL_DIV: 191a2b73c81Sjeremylt case CEED_EVAL_CURL: 192*9bc66399SJeremy L Thompson return CeedError(CeedBasisReturnCeed(basis), CEED_ERROR_BACKEND, "%s not supported", CeedEvalModes[eval_mode]); 193a2b73c81Sjeremylt case CEED_EVAL_NONE: 194*9bc66399SJeremy L Thompson return CeedError(CeedBasisReturnCeed(basis), CEED_ERROR_BACKEND, "CEED_EVAL_NONE does not make sense in this context"); 195c042f62fSJeremy L Thompson // LCOV_EXCL_STOP 19621617c04Sjeremylt } 197a8de75f0Sjeremylt } else { 198a8de75f0Sjeremylt // Non-tensor basis 199c4e3f59bSSebastian Grimberg CeedInt P = num_nodes, Q = num_qpts; 200ad70ee2cSJeremy L Thompson 201d1d35e2fSjeremylt switch (eval_mode) { 20284a01de5SJeremy L Thompson // Interpolate to/from quadrature points 203a8de75f0Sjeremylt case CEED_EVAL_INTERP: { 2046c58de82SJeremy L Thompson const CeedScalar *interp; 205ad70ee2cSJeremy L Thompson 2062b730f8bSJeremy L Thompson CeedCallBackend(CeedBasisGetInterp(basis, &interp)); 207c4e3f59bSSebastian Grimberg CeedCallBackend(CeedTensorContractStridedApply(contract, num_comp, P, num_elem, q_comp, Q, interp, t_mode, add, u, v)); 2082b730f8bSJeremy L Thompson } break; 20984a01de5SJeremy L Thompson // Evaluate the gradient to/from quadrature points 210a8de75f0Sjeremylt case CEED_EVAL_GRAD: { 2116c58de82SJeremy L Thompson const CeedScalar *grad; 212ad70ee2cSJeremy L Thompson 2132b730f8bSJeremy L Thompson CeedCallBackend(CeedBasisGetGrad(basis, &grad)); 214c4e3f59bSSebastian Grimberg CeedCallBackend(CeedTensorContractStridedApply(contract, num_comp, P, num_elem, q_comp, Q, grad, t_mode, add, u, v)); 215c4e3f59bSSebastian Grimberg } break; 216c4e3f59bSSebastian Grimberg // Evaluate the divergence to/from the quadrature points 217c4e3f59bSSebastian Grimberg case CEED_EVAL_DIV: { 218c4e3f59bSSebastian Grimberg const CeedScalar *div; 219ad70ee2cSJeremy L Thompson 220c4e3f59bSSebastian Grimberg CeedCallBackend(CeedBasisGetDiv(basis, &div)); 221c4e3f59bSSebastian Grimberg CeedCallBackend(CeedTensorContractStridedApply(contract, num_comp, P, num_elem, q_comp, Q, div, t_mode, add, u, v)); 222c4e3f59bSSebastian Grimberg } break; 223c4e3f59bSSebastian Grimberg // Evaluate the curl to/from the quadrature points 224c4e3f59bSSebastian Grimberg case CEED_EVAL_CURL: { 225c4e3f59bSSebastian Grimberg const CeedScalar *curl; 226ad70ee2cSJeremy L Thompson 227c4e3f59bSSebastian Grimberg CeedCallBackend(CeedBasisGetCurl(basis, &curl)); 228c4e3f59bSSebastian Grimberg CeedCallBackend(CeedTensorContractStridedApply(contract, num_comp, P, num_elem, q_comp, Q, curl, t_mode, add, u, v)); 2292b730f8bSJeremy L Thompson } break; 23084a01de5SJeremy L Thompson // Retrieve interpolation weights 231a8de75f0Sjeremylt case CEED_EVAL_WEIGHT: { 232d1d35e2fSjeremylt const CeedScalar *q_weight; 233ad70ee2cSJeremy L Thompson 234*9bc66399SJeremy L Thompson CeedCheck(t_mode == CEED_NOTRANSPOSE, CeedBasisReturnCeed(basis), CEED_ERROR_BACKEND, "CEED_EVAL_WEIGHT incompatible with CEED_TRANSPOSE"); 2352b730f8bSJeremy L Thompson CeedCallBackend(CeedBasisGetQWeights(basis, &q_weight)); 2362b730f8bSJeremy L Thompson for (CeedInt i = 0; i < num_qpts; i++) { 2372b730f8bSJeremy L Thompson for (CeedInt e = 0; e < num_elem; e++) v[i * num_elem + e] = q_weight[i]; 2382b730f8bSJeremy L Thompson } 239a8de75f0Sjeremylt } break; 24050c301a5SRezgar Shakeri // LCOV_EXCL_START 241a8de75f0Sjeremylt case CEED_EVAL_NONE: 242*9bc66399SJeremy L Thompson return CeedError(CeedBasisReturnCeed(basis), CEED_ERROR_BACKEND, "CEED_EVAL_NONE does not make sense in this context"); 243c042f62fSJeremy L Thompson // LCOV_EXCL_STOP 244a8de75f0Sjeremylt } 245a8de75f0Sjeremylt } 246a7b7f929Sjeremylt if (U != CEED_VECTOR_NONE) { 2472b730f8bSJeremy L Thompson CeedCallBackend(CeedVectorRestoreArrayRead(U, &u)); 248aedaa0e5Sjeremylt } 2492b730f8bSJeremy L Thompson CeedCallBackend(CeedVectorRestoreArray(V, &v)); 250e15f9bd0SJeremy L Thompson return CEED_ERROR_SUCCESS; 25121617c04Sjeremylt } 25221617c04Sjeremylt 253db2becc9SJeremy L Thompson static int CeedBasisApply_Ref(CeedBasis basis, CeedInt num_elem, CeedTransposeMode t_mode, CeedEvalMode eval_mode, CeedVector U, CeedVector V) { 254db2becc9SJeremy L Thompson CeedCallBackend(CeedBasisApplyCore_Ref(basis, false, num_elem, t_mode, eval_mode, U, V)); 255db2becc9SJeremy L Thompson return CEED_ERROR_SUCCESS; 256db2becc9SJeremy L Thompson } 257db2becc9SJeremy L Thompson 258db2becc9SJeremy L Thompson static int CeedBasisApplyAdd_Ref(CeedBasis basis, CeedInt num_elem, CeedTransposeMode t_mode, CeedEvalMode eval_mode, CeedVector U, CeedVector V) { 259db2becc9SJeremy L Thompson CeedCallBackend(CeedBasisApplyCore_Ref(basis, true, num_elem, t_mode, eval_mode, U, V)); 260db2becc9SJeremy L Thompson return CEED_ERROR_SUCCESS; 261db2becc9SJeremy L Thompson } 262db2becc9SJeremy L Thompson 263f10650afSjeremylt //------------------------------------------------------------------------------ 264b2165e7aSSebastian Grimberg // Basis Destroy Tensor 265b2165e7aSSebastian Grimberg //------------------------------------------------------------------------------ 266b2165e7aSSebastian Grimberg static int CeedBasisDestroyTensor_Ref(CeedBasis basis) { 267b2165e7aSSebastian Grimberg CeedBasis_Ref *impl; 268ad70ee2cSJeremy L Thompson 269b2165e7aSSebastian Grimberg CeedCallBackend(CeedBasisGetData(basis, &impl)); 270b2165e7aSSebastian Grimberg CeedCallBackend(CeedFree(&impl->collo_grad_1d)); 271b2165e7aSSebastian Grimberg CeedCallBackend(CeedFree(&impl)); 272b2165e7aSSebastian Grimberg return CEED_ERROR_SUCCESS; 273b2165e7aSSebastian Grimberg } 274b2165e7aSSebastian Grimberg 275b2165e7aSSebastian Grimberg //------------------------------------------------------------------------------ 276b2165e7aSSebastian Grimberg // Basis Create Tensor 277b2165e7aSSebastian Grimberg //------------------------------------------------------------------------------ 278b2165e7aSSebastian Grimberg int CeedBasisCreateTensorH1_Ref(CeedInt dim, CeedInt P_1d, CeedInt Q_1d, const CeedScalar *interp_1d, const CeedScalar *grad_1d, 279b2165e7aSSebastian Grimberg const CeedScalar *q_ref_1d, const CeedScalar *q_weight_1d, CeedBasis basis) { 280ca735530SJeremy L Thompson Ceed ceed, ceed_parent; 281b2165e7aSSebastian Grimberg CeedBasis_Ref *impl; 282ad70ee2cSJeremy L Thompson CeedTensorContract contract; 283ad70ee2cSJeremy L Thompson 284ad70ee2cSJeremy L Thompson CeedCallBackend(CeedBasisGetCeed(basis, &ceed)); 285ca735530SJeremy L Thompson CeedCallBackend(CeedGetParent(ceed, &ceed_parent)); 286ad70ee2cSJeremy L Thompson 287b2165e7aSSebastian Grimberg CeedCallBackend(CeedCalloc(1, &impl)); 288b2165e7aSSebastian Grimberg // Check for collocated interp 289b2165e7aSSebastian Grimberg if (Q_1d == P_1d) { 290ad70ee2cSJeremy L Thompson bool has_collocated = true; 291ad70ee2cSJeremy L Thompson 292b2165e7aSSebastian Grimberg for (CeedInt i = 0; i < P_1d; i++) { 293ad70ee2cSJeremy L Thompson has_collocated = has_collocated && (fabs(interp_1d[i + P_1d * i] - 1.0) < 1e-14); 294b2165e7aSSebastian Grimberg for (CeedInt j = 0; j < P_1d; j++) { 295ad70ee2cSJeremy L Thompson if (j != i) has_collocated = has_collocated && (fabs(interp_1d[j + P_1d * i]) < 1e-14); 296b2165e7aSSebastian Grimberg } 297b2165e7aSSebastian Grimberg } 298ad70ee2cSJeremy L Thompson impl->has_collo_interp = has_collocated; 299b2165e7aSSebastian Grimberg } 300b2165e7aSSebastian Grimberg // Calculate collocated grad 301b2165e7aSSebastian Grimberg if (Q_1d >= P_1d && !impl->has_collo_interp) { 302b2165e7aSSebastian Grimberg CeedCallBackend(CeedMalloc(Q_1d * Q_1d, &impl->collo_grad_1d)); 303b2165e7aSSebastian Grimberg CeedCallBackend(CeedBasisGetCollocatedGrad(basis, impl->collo_grad_1d)); 304b2165e7aSSebastian Grimberg } 305b2165e7aSSebastian Grimberg CeedCallBackend(CeedBasisSetData(basis, impl)); 306b2165e7aSSebastian Grimberg 307a71faab1SSebastian Grimberg CeedCallBackend(CeedTensorContractCreate(ceed_parent, &contract)); 308b2165e7aSSebastian Grimberg CeedCallBackend(CeedBasisSetTensorContract(basis, contract)); 309b2165e7aSSebastian Grimberg 310b2165e7aSSebastian Grimberg CeedCallBackend(CeedSetBackendFunction(ceed, "Basis", basis, "Apply", CeedBasisApply_Ref)); 311db2becc9SJeremy L Thompson CeedCallBackend(CeedSetBackendFunction(ceed, "Basis", basis, "ApplyAdd", CeedBasisApplyAdd_Ref)); 312b2165e7aSSebastian Grimberg CeedCallBackend(CeedSetBackendFunction(ceed, "Basis", basis, "Destroy", CeedBasisDestroyTensor_Ref)); 313*9bc66399SJeremy L Thompson CeedCallBackend(CeedDestroy(&ceed)); 314*9bc66399SJeremy L Thompson CeedCallBackend(CeedDestroy(&ceed_parent)); 315b2165e7aSSebastian Grimberg return CEED_ERROR_SUCCESS; 316b2165e7aSSebastian Grimberg } 317b2165e7aSSebastian Grimberg 318b2165e7aSSebastian Grimberg //------------------------------------------------------------------------------ 31950c301a5SRezgar Shakeri // Basis Create Non-Tensor H^1 320f10650afSjeremylt //------------------------------------------------------------------------------ 3212b730f8bSJeremy L Thompson int CeedBasisCreateH1_Ref(CeedElemTopology topo, CeedInt dim, CeedInt num_nodes, CeedInt num_qpts, const CeedScalar *interp, const CeedScalar *grad, 3222b730f8bSJeremy L Thompson const CeedScalar *q_ref, const CeedScalar *q_weight, CeedBasis basis) { 323ca735530SJeremy L Thompson Ceed ceed, ceed_parent; 324f10650afSjeremylt CeedTensorContract contract; 325ad70ee2cSJeremy L Thompson 326ad70ee2cSJeremy L Thompson CeedCallBackend(CeedBasisGetCeed(basis, &ceed)); 327ca735530SJeremy L Thompson CeedCallBackend(CeedGetParent(ceed, &ceed_parent)); 328ad70ee2cSJeremy L Thompson 329a71faab1SSebastian Grimberg CeedCallBackend(CeedTensorContractCreate(ceed_parent, &contract)); 3302b730f8bSJeremy L Thompson CeedCallBackend(CeedBasisSetTensorContract(basis, contract)); 331f10650afSjeremylt 3322b730f8bSJeremy L Thompson CeedCallBackend(CeedSetBackendFunction(ceed, "Basis", basis, "Apply", CeedBasisApply_Ref)); 333db2becc9SJeremy L Thompson CeedCallBackend(CeedSetBackendFunction(ceed, "Basis", basis, "ApplyAdd", CeedBasisApplyAdd_Ref)); 334*9bc66399SJeremy L Thompson CeedCallBackend(CeedDestroy(&ceed)); 335*9bc66399SJeremy L Thompson CeedCallBackend(CeedDestroy(&ceed_parent)); 336e15f9bd0SJeremy L Thompson return CEED_ERROR_SUCCESS; 337f10650afSjeremylt } 338f10650afSjeremylt 339f10650afSjeremylt //------------------------------------------------------------------------------ 34050c301a5SRezgar Shakeri // Basis Create Non-Tensor H(div) 34150c301a5SRezgar Shakeri //------------------------------------------------------------------------------ 3422b730f8bSJeremy L Thompson int CeedBasisCreateHdiv_Ref(CeedElemTopology topo, CeedInt dim, CeedInt num_nodes, CeedInt num_qpts, const CeedScalar *interp, const CeedScalar *div, 3432b730f8bSJeremy L Thompson const CeedScalar *q_ref, const CeedScalar *q_weight, CeedBasis basis) { 344ca735530SJeremy L Thompson Ceed ceed, ceed_parent; 34550c301a5SRezgar Shakeri CeedTensorContract contract; 346ad70ee2cSJeremy L Thompson 347ad70ee2cSJeremy L Thompson CeedCallBackend(CeedBasisGetCeed(basis, &ceed)); 348ca735530SJeremy L Thompson CeedCallBackend(CeedGetParent(ceed, &ceed_parent)); 349ad70ee2cSJeremy L Thompson 350a71faab1SSebastian Grimberg CeedCallBackend(CeedTensorContractCreate(ceed_parent, &contract)); 3512b730f8bSJeremy L Thompson CeedCallBackend(CeedBasisSetTensorContract(basis, contract)); 35250c301a5SRezgar Shakeri 3532b730f8bSJeremy L Thompson CeedCallBackend(CeedSetBackendFunction(ceed, "Basis", basis, "Apply", CeedBasisApply_Ref)); 354db2becc9SJeremy L Thompson CeedCallBackend(CeedSetBackendFunction(ceed, "Basis", basis, "ApplyAdd", CeedBasisApplyAdd_Ref)); 355*9bc66399SJeremy L Thompson CeedCallBackend(CeedDestroy(&ceed)); 356*9bc66399SJeremy L Thompson CeedCallBackend(CeedDestroy(&ceed_parent)); 35750c301a5SRezgar Shakeri return CEED_ERROR_SUCCESS; 35850c301a5SRezgar Shakeri } 35950c301a5SRezgar Shakeri 36050c301a5SRezgar Shakeri //------------------------------------------------------------------------------ 361c4e3f59bSSebastian Grimberg // Basis Create Non-Tensor H(curl) 362c4e3f59bSSebastian Grimberg //------------------------------------------------------------------------------ 363c4e3f59bSSebastian Grimberg int CeedBasisCreateHcurl_Ref(CeedElemTopology topo, CeedInt dim, CeedInt num_nodes, CeedInt num_qpts, const CeedScalar *interp, 364c4e3f59bSSebastian Grimberg const CeedScalar *curl, const CeedScalar *q_ref, const CeedScalar *q_weight, CeedBasis basis) { 365ca735530SJeremy L Thompson Ceed ceed, ceed_parent; 366c4e3f59bSSebastian Grimberg CeedTensorContract contract; 367ad70ee2cSJeremy L Thompson 368ad70ee2cSJeremy L Thompson CeedCallBackend(CeedBasisGetCeed(basis, &ceed)); 369ca735530SJeremy L Thompson CeedCallBackend(CeedGetParent(ceed, &ceed_parent)); 370ad70ee2cSJeremy L Thompson 371a71faab1SSebastian Grimberg CeedCallBackend(CeedTensorContractCreate(ceed_parent, &contract)); 372c4e3f59bSSebastian Grimberg CeedCallBackend(CeedBasisSetTensorContract(basis, contract)); 373c4e3f59bSSebastian Grimberg 374c4e3f59bSSebastian Grimberg CeedCallBackend(CeedSetBackendFunction(ceed, "Basis", basis, "Apply", CeedBasisApply_Ref)); 375db2becc9SJeremy L Thompson CeedCallBackend(CeedSetBackendFunction(ceed, "Basis", basis, "ApplyAdd", CeedBasisApplyAdd_Ref)); 376*9bc66399SJeremy L Thompson CeedCallBackend(CeedDestroy(&ceed)); 377*9bc66399SJeremy L Thompson CeedCallBackend(CeedDestroy(&ceed_parent)); 378c4e3f59bSSebastian Grimberg return CEED_ERROR_SUCCESS; 379c4e3f59bSSebastian Grimberg } 380c4e3f59bSSebastian Grimberg 381c4e3f59bSSebastian Grimberg //------------------------------------------------------------------------------ 382