xref: /libCEED/interface/ceed-basis.c (revision f2989f2b3b8649d855bed22b6730ee0ecfa6b31b)
19ba83ac0SJeremy L Thompson // Copyright (c) 2017-2026, 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.
3d7b241e6Sjeremylt //
43d8e8822SJeremy L Thompson // SPDX-License-Identifier: BSD-2-Clause
5d7b241e6Sjeremylt //
63d8e8822SJeremy L Thompson // This file is part of CEED:  http://github.com/ceed
7d7b241e6Sjeremylt 
83d576824SJeremy L Thompson #include <ceed-impl.h>
949aac155SJeremy L Thompson #include <ceed.h>
102b730f8bSJeremy L Thompson #include <ceed/backend.h>
11d7b241e6Sjeremylt #include <math.h>
123d576824SJeremy L Thompson #include <stdbool.h>
13d7b241e6Sjeremylt #include <stdio.h>
14d7b241e6Sjeremylt #include <string.h>
15d7b241e6Sjeremylt 
167a982d89SJeremy L. Thompson /// @file
177a982d89SJeremy L. Thompson /// Implementation of CeedBasis interfaces
187a982d89SJeremy L. Thompson 
19d7b241e6Sjeremylt /// @cond DOXYGEN_SKIP
20356036faSJeremy L Thompson static struct CeedBasis_private ceed_basis_none;
21d7b241e6Sjeremylt /// @endcond
22d7b241e6Sjeremylt 
237a982d89SJeremy L. Thompson /// @addtogroup CeedBasisUser
247a982d89SJeremy L. Thompson /// @{
257a982d89SJeremy L. Thompson 
26ca94c3ddSJeremy L Thompson /// Argument for @ref CeedOperatorSetField() indicating that the field does not require a `CeedBasis`
27356036faSJeremy L Thompson const CeedBasis CEED_BASIS_NONE = &ceed_basis_none;
28356036faSJeremy L Thompson 
297a982d89SJeremy L. Thompson /// @}
307a982d89SJeremy L. Thompson 
317a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
327a982d89SJeremy L. Thompson /// CeedBasis Library Internal Functions
337a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
347a982d89SJeremy L. Thompson /// @addtogroup CeedBasisDeveloper
357a982d89SJeremy L. Thompson /// @{
367a982d89SJeremy L. Thompson 
377a982d89SJeremy L. Thompson /**
383778dbaaSJeremy L Thompson   @brief Compute Chebyshev polynomial values at a point
393778dbaaSJeremy L Thompson 
403778dbaaSJeremy L Thompson   @param[in]  x           Coordinate to evaluate Chebyshev polynomials at
41ca94c3ddSJeremy L Thompson   @param[in]  n           Number of Chebyshev polynomials to evaluate, `n >= 2`
423778dbaaSJeremy L Thompson   @param[out] chebyshev_x Array of Chebyshev polynomial values
433778dbaaSJeremy L Thompson 
443778dbaaSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
453778dbaaSJeremy L Thompson 
463778dbaaSJeremy L Thompson   @ref Developer
473778dbaaSJeremy L Thompson **/
CeedChebyshevPolynomialsAtPoint(CeedScalar x,CeedInt n,CeedScalar * chebyshev_x)483778dbaaSJeremy L Thompson static int CeedChebyshevPolynomialsAtPoint(CeedScalar x, CeedInt n, CeedScalar *chebyshev_x) {
493778dbaaSJeremy L Thompson   chebyshev_x[0] = 1.0;
503778dbaaSJeremy L Thompson   chebyshev_x[1] = 2 * x;
513778dbaaSJeremy L Thompson   for (CeedInt i = 2; i < n; i++) chebyshev_x[i] = 2 * x * chebyshev_x[i - 1] - chebyshev_x[i - 2];
523778dbaaSJeremy L Thompson   return CEED_ERROR_SUCCESS;
533778dbaaSJeremy L Thompson }
543778dbaaSJeremy L Thompson 
553778dbaaSJeremy L Thompson /**
563778dbaaSJeremy L Thompson   @brief Compute values of the derivative of Chebyshev polynomials at a point
573778dbaaSJeremy L Thompson 
583778dbaaSJeremy L Thompson   @param[in]  x            Coordinate to evaluate derivative of Chebyshev polynomials at
59ca94c3ddSJeremy L Thompson   @param[in]  n            Number of Chebyshev polynomials to evaluate, `n >= 2`
606cec60aaSJed Brown   @param[out] chebyshev_dx Array of Chebyshev polynomial derivative values
613778dbaaSJeremy L Thompson 
623778dbaaSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
633778dbaaSJeremy L Thompson 
643778dbaaSJeremy L Thompson   @ref Developer
653778dbaaSJeremy L Thompson **/
CeedChebyshevDerivativeAtPoint(CeedScalar x,CeedInt n,CeedScalar * chebyshev_dx)663778dbaaSJeremy L Thompson static int CeedChebyshevDerivativeAtPoint(CeedScalar x, CeedInt n, CeedScalar *chebyshev_dx) {
673778dbaaSJeremy L Thompson   CeedScalar chebyshev_x[3];
683778dbaaSJeremy L Thompson 
693778dbaaSJeremy L Thompson   chebyshev_x[1]  = 1.0;
703778dbaaSJeremy L Thompson   chebyshev_x[2]  = 2 * x;
713778dbaaSJeremy L Thompson   chebyshev_dx[0] = 0.0;
723778dbaaSJeremy L Thompson   chebyshev_dx[1] = 2.0;
733778dbaaSJeremy L Thompson   for (CeedInt i = 2; i < n; i++) {
743778dbaaSJeremy L Thompson     chebyshev_x[0]  = chebyshev_x[1];
753778dbaaSJeremy L Thompson     chebyshev_x[1]  = chebyshev_x[2];
763778dbaaSJeremy L Thompson     chebyshev_x[2]  = 2 * x * chebyshev_x[1] - chebyshev_x[0];
773778dbaaSJeremy L Thompson     chebyshev_dx[i] = 2 * x * chebyshev_dx[i - 1] + 2 * chebyshev_x[1] - chebyshev_dx[i - 2];
783778dbaaSJeremy L Thompson   }
793778dbaaSJeremy L Thompson   return CEED_ERROR_SUCCESS;
803778dbaaSJeremy L Thompson }
813778dbaaSJeremy L Thompson 
823778dbaaSJeremy L Thompson /**
83ca94c3ddSJeremy L Thompson   @brief Compute Householder reflection.
847a982d89SJeremy L. Thompson 
85ca94c3ddSJeremy L Thompson   Computes \f$A = (I - b v v^T) A\f$, where \f$A\f$ is an \f$m \times n\f$ matrix indexed as `A[i*row + j*col]`.
867a982d89SJeremy L. Thompson 
877a982d89SJeremy L. Thompson   @param[in,out] A   Matrix to apply Householder reflection to, in place
88ea61e9acSJeremy L Thompson   @param[in]     v   Householder vector
89ea61e9acSJeremy L Thompson   @param[in]     b   Scaling factor
90ca94c3ddSJeremy L Thompson   @param[in]     m   Number of rows in `A`
91ca94c3ddSJeremy L Thompson   @param[in]     n   Number of columns in `A`
92ea61e9acSJeremy L Thompson   @param[in]     row Row stride
93ea61e9acSJeremy L Thompson   @param[in]     col Col stride
947a982d89SJeremy L. Thompson 
957a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
967a982d89SJeremy L. Thompson 
977a982d89SJeremy L. Thompson   @ref Developer
987a982d89SJeremy L. Thompson **/
CeedHouseholderReflect(CeedScalar * A,const CeedScalar * v,CeedScalar b,CeedInt m,CeedInt n,CeedInt row,CeedInt col)992b730f8bSJeremy L Thompson static int CeedHouseholderReflect(CeedScalar *A, const CeedScalar *v, CeedScalar b, CeedInt m, CeedInt n, CeedInt row, CeedInt col) {
1007a982d89SJeremy L. Thompson   for (CeedInt j = 0; j < n; j++) {
1017a982d89SJeremy L. Thompson     CeedScalar w = A[0 * row + j * col];
1021c66c397SJeremy L Thompson 
1032b730f8bSJeremy L Thompson     for (CeedInt i = 1; i < m; i++) w += v[i] * A[i * row + j * col];
1047a982d89SJeremy L. Thompson     A[0 * row + j * col] -= b * w;
1052b730f8bSJeremy L Thompson     for (CeedInt i = 1; i < m; i++) A[i * row + j * col] -= b * w * v[i];
1067a982d89SJeremy L. Thompson   }
107e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1087a982d89SJeremy L. Thompson }
1097a982d89SJeremy L. Thompson 
1107a982d89SJeremy L. Thompson /**
1117a982d89SJeremy L. Thompson   @brief Compute Givens rotation
1127a982d89SJeremy L. Thompson 
113ca94c3ddSJeremy L Thompson   Computes \f$A = G A\f$ (or \f$G^T A\f$ in transpose mode), where \f$A\f$ is an \f$m \times n\f$ matrix indexed as `A[i*n + j*m]`.
1147a982d89SJeremy L. Thompson 
1157a982d89SJeremy L. Thompson   @param[in,out] A      Row major matrix to apply Givens rotation to, in place
116ea61e9acSJeremy L Thompson   @param[in]     c      Cosine factor
117ea61e9acSJeremy L Thompson   @param[in]     s      Sine factor
118ca94c3ddSJeremy L Thompson   @param[in]     t_mode @ref CEED_NOTRANSPOSE to rotate the basis counter-clockwise, which has the effect of rotating columns of `A` clockwise;
1194cc79fe7SJed Brown                           @ref CEED_TRANSPOSE for the opposite rotation
120ea61e9acSJeremy L Thompson   @param[in]     i      First row/column to apply rotation
121ea61e9acSJeremy L Thompson   @param[in]     k      Second row/column to apply rotation
122ca94c3ddSJeremy L Thompson   @param[in]     m      Number of rows in `A`
123ca94c3ddSJeremy L Thompson   @param[in]     n      Number of columns in `A`
1247a982d89SJeremy L. Thompson 
1257a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
1267a982d89SJeremy L. Thompson 
1277a982d89SJeremy L. Thompson   @ref Developer
1287a982d89SJeremy L. Thompson **/
CeedGivensRotation(CeedScalar * A,CeedScalar c,CeedScalar s,CeedTransposeMode t_mode,CeedInt i,CeedInt k,CeedInt m,CeedInt n)1292b730f8bSJeremy L Thompson static int CeedGivensRotation(CeedScalar *A, CeedScalar c, CeedScalar s, CeedTransposeMode t_mode, CeedInt i, CeedInt k, CeedInt m, CeedInt n) {
130d1d35e2fSjeremylt   CeedInt stride_j = 1, stride_ik = m, num_its = n;
1311c66c397SJeremy L Thompson 
132d1d35e2fSjeremylt   if (t_mode == CEED_NOTRANSPOSE) {
1332b730f8bSJeremy L Thompson     stride_j  = n;
1342b730f8bSJeremy L Thompson     stride_ik = 1;
1352b730f8bSJeremy L Thompson     num_its   = m;
1367a982d89SJeremy L. Thompson   }
1377a982d89SJeremy L. Thompson 
1387a982d89SJeremy L. Thompson   // Apply rotation
139d1d35e2fSjeremylt   for (CeedInt j = 0; j < num_its; j++) {
140d1d35e2fSjeremylt     CeedScalar tau1 = A[i * stride_ik + j * stride_j], tau2 = A[k * stride_ik + j * stride_j];
1411c66c397SJeremy L Thompson 
142d1d35e2fSjeremylt     A[i * stride_ik + j * stride_j] = c * tau1 - s * tau2;
143d1d35e2fSjeremylt     A[k * stride_ik + j * stride_j] = s * tau1 + c * tau2;
1447a982d89SJeremy L. Thompson   }
145e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1467a982d89SJeremy L. Thompson }
1477a982d89SJeremy L. Thompson 
1487a982d89SJeremy L. Thompson /**
149ca94c3ddSJeremy L Thompson   @brief View an array stored in a `CeedBasis`
1507a982d89SJeremy L. Thompson 
1510a0da059Sjeremylt   @param[in] name   Name of array
152d1d35e2fSjeremylt   @param[in] fp_fmt Printing format
1530a0da059Sjeremylt   @param[in] m      Number of rows in array
1540a0da059Sjeremylt   @param[in] n      Number of columns in array
1550a0da059Sjeremylt   @param[in] a      Array to be viewed
1564c789ea2SJeremy L Thompson   @param[in] tabs   Tabs to append before each new line
157ca94c3ddSJeremy L Thompson   @param[in] stream Stream to view to, e.g., `stdout`
1587a982d89SJeremy L. Thompson 
1597a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
1607a982d89SJeremy L. Thompson 
1617a982d89SJeremy L. Thompson   @ref Developer
1627a982d89SJeremy L. Thompson **/
CeedScalarView(const char * name,const char * fp_fmt,CeedInt m,CeedInt n,const CeedScalar * a,const char * tabs,FILE * stream)1634c789ea2SJeremy L Thompson static int CeedScalarView(const char *name, const char *fp_fmt, CeedInt m, CeedInt n, const CeedScalar *a, const char *tabs, FILE *stream) {
164edf04919SJeremy L Thompson   if (m > 1) {
1654c789ea2SJeremy L Thompson     fprintf(stream, "%s  %s:\n", tabs, name);
166edf04919SJeremy L Thompson   } else {
167edf04919SJeremy L Thompson     char padded_name[12];
168edf04919SJeremy L Thompson 
169edf04919SJeremy L Thompson     snprintf(padded_name, 11, "%s:", name);
1704c789ea2SJeremy L Thompson     fprintf(stream, "%s  %-10s", tabs, padded_name);
171edf04919SJeremy L Thompson   }
17292ae7e47SJeremy L Thompson   for (CeedInt i = 0; i < m; i++) {
1734c789ea2SJeremy L Thompson     if (m > 1) fprintf(stream, "%s    [%" CeedInt_FMT "]", tabs, i);
1742b730f8bSJeremy L Thompson     for (CeedInt j = 0; j < n; j++) fprintf(stream, fp_fmt, fabs(a[i * n + j]) > 1E-14 ? a[i * n + j] : 0);
1757a982d89SJeremy L. Thompson     fputs("\n", stream);
1767a982d89SJeremy L. Thompson   }
177e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1787a982d89SJeremy L. Thompson }
1797a982d89SJeremy L. Thompson 
180a76a04e7SJeremy L Thompson /**
181b0f67a9cSJeremy L Thompson   @brief View a `CeedBasis` passed as a `CeedObject`
182b0f67a9cSJeremy L Thompson 
183b0f67a9cSJeremy L Thompson   @param[in] basis  `CeedBasis` to view
184b0f67a9cSJeremy L Thompson   @param[in] stream Filestream to write to
185b0f67a9cSJeremy L Thompson 
186b0f67a9cSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
187b0f67a9cSJeremy L Thompson 
188b0f67a9cSJeremy L Thompson   @ref Developer
189b0f67a9cSJeremy L Thompson **/
CeedBasisView_Object(CeedObject basis,FILE * stream)190b0f67a9cSJeremy L Thompson static int CeedBasisView_Object(CeedObject basis, FILE *stream) {
191b0f67a9cSJeremy L Thompson   CeedCall(CeedBasisView((CeedBasis)basis, stream));
192b0f67a9cSJeremy L Thompson   return CEED_ERROR_SUCCESS;
193b0f67a9cSJeremy L Thompson }
194b0f67a9cSJeremy L Thompson 
195b0f67a9cSJeremy L Thompson /**
196*6c328a79SJeremy L Thompson   @brief Destroy a `CeedBasis` passed as a `CeedObject`
197*6c328a79SJeremy L Thompson 
198*6c328a79SJeremy L Thompson   @param[in,out] basis Address of `CeedBasis` to destroy
199*6c328a79SJeremy L Thompson 
200*6c328a79SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
201*6c328a79SJeremy L Thompson 
202*6c328a79SJeremy L Thompson   @ref Developer
203*6c328a79SJeremy L Thompson **/
CeedBasisDestroy_Object(CeedObject * basis)204*6c328a79SJeremy L Thompson static int CeedBasisDestroy_Object(CeedObject *basis) {
205*6c328a79SJeremy L Thompson   CeedCall(CeedBasisDestroy((CeedBasis *)basis));
206*6c328a79SJeremy L Thompson   return CEED_ERROR_SUCCESS;
207*6c328a79SJeremy L Thompson }
208*6c328a79SJeremy L Thompson 
209*6c328a79SJeremy L Thompson /**
210ea61e9acSJeremy L Thompson   @brief Create the interpolation and gradient matrices for projection from the nodes of `basis_from` to the nodes of `basis_to`.
211ba59ac12SSebastian Grimberg 
21215ad3917SSebastian Grimberg   The interpolation is given by `interp_project = interp_to^+ * interp_from`, where the pseudoinverse `interp_to^+` is given by QR factorization.
213ca94c3ddSJeremy L Thompson   The gradient is given by `grad_project = interp_to^+ * grad_from`, and is only computed for \f$H^1\f$ spaces otherwise it should not be used.
21415ad3917SSebastian Grimberg 
215ba59ac12SSebastian Grimberg   Note: `basis_from` and `basis_to` must have compatible quadrature spaces.
216a76a04e7SJeremy L Thompson 
217ca94c3ddSJeremy L Thompson   @param[in]  basis_from     `CeedBasis` to project from
218ca94c3ddSJeremy L Thompson   @param[in]  basis_to       `CeedBasis` to project to
219ca94c3ddSJeremy L Thompson   @param[out] interp_project Address of the variable where the newly created interpolation matrix will be stored
220ca94c3ddSJeremy L Thompson   @param[out] grad_project   Address of the variable where the newly created gradient matrix will be stored
221a76a04e7SJeremy L Thompson 
222a76a04e7SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
223a76a04e7SJeremy L Thompson 
224a76a04e7SJeremy L Thompson   @ref Developer
225a76a04e7SJeremy L Thompson **/
CeedBasisCreateProjectionMatrices(CeedBasis basis_from,CeedBasis basis_to,CeedScalar ** interp_project,CeedScalar ** grad_project)2262b730f8bSJeremy L Thompson static int CeedBasisCreateProjectionMatrices(CeedBasis basis_from, CeedBasis basis_to, CeedScalar **interp_project, CeedScalar **grad_project) {
227e104ad11SJames Wright   bool    are_both_tensor;
2281c66c397SJeremy L Thompson   CeedInt Q, Q_to, Q_from, P_to, P_from;
2291c66c397SJeremy L Thompson 
230a76a04e7SJeremy L Thompson   // Check for compatible quadrature spaces
2312b730f8bSJeremy L Thompson   CeedCall(CeedBasisGetNumQuadraturePoints(basis_to, &Q_to));
2322b730f8bSJeremy L Thompson   CeedCall(CeedBasisGetNumQuadraturePoints(basis_from, &Q_from));
2339bc66399SJeremy L Thompson   CeedCheck(Q_to == Q_from, CeedBasisReturnCeed(basis_to), CEED_ERROR_DIMENSION,
2343f08121cSJeremy L Thompson             "Bases must have compatible quadrature spaces."
23523622755SJeremy L Thompson             " 'basis_from' has %" CeedInt_FMT " points and 'basis_to' has %" CeedInt_FMT,
2363f08121cSJeremy L Thompson             Q_from, Q_to);
2371c66c397SJeremy L Thompson   Q = Q_to;
238a76a04e7SJeremy L Thompson 
23914556e63SJeremy L Thompson   // Check for matching tensor or non-tensor
240e104ad11SJames Wright   {
241e104ad11SJames Wright     bool is_tensor_to, is_tensor_from;
242e104ad11SJames Wright 
2432b730f8bSJeremy L Thompson     CeedCall(CeedBasisIsTensor(basis_to, &is_tensor_to));
2442b730f8bSJeremy L Thompson     CeedCall(CeedBasisIsTensor(basis_from, &is_tensor_from));
245e104ad11SJames Wright     are_both_tensor = is_tensor_to && is_tensor_from;
246e104ad11SJames Wright   }
247e104ad11SJames Wright   if (are_both_tensor) {
2482b730f8bSJeremy L Thompson     CeedCall(CeedBasisGetNumNodes1D(basis_to, &P_to));
2492b730f8bSJeremy L Thompson     CeedCall(CeedBasisGetNumNodes1D(basis_from, &P_from));
2502b730f8bSJeremy L Thompson     CeedCall(CeedBasisGetNumQuadraturePoints1D(basis_from, &Q));
2516574a04fSJeremy L Thompson   } else {
2522b730f8bSJeremy L Thompson     CeedCall(CeedBasisGetNumNodes(basis_to, &P_to));
2532b730f8bSJeremy L Thompson     CeedCall(CeedBasisGetNumNodes(basis_from, &P_from));
254a76a04e7SJeremy L Thompson   }
255a76a04e7SJeremy L Thompson 
25615ad3917SSebastian Grimberg   // Check for matching FE space
25715ad3917SSebastian Grimberg   CeedFESpace fe_space_to, fe_space_from;
2583f08121cSJeremy L Thompson 
25915ad3917SSebastian Grimberg   CeedCall(CeedBasisGetFESpace(basis_to, &fe_space_to));
26015ad3917SSebastian Grimberg   CeedCall(CeedBasisGetFESpace(basis_from, &fe_space_from));
2619bc66399SJeremy L Thompson   CeedCheck(fe_space_to == fe_space_from, CeedBasisReturnCeed(basis_to), CEED_ERROR_MINOR,
2623f08121cSJeremy L Thompson             "Bases must both be the same FE space type."
2633f08121cSJeremy L Thompson             " 'basis_from' is a %s and 'basis_to' is a %s",
2643f08121cSJeremy L Thompson             CeedFESpaces[fe_space_from], CeedFESpaces[fe_space_to]);
26515ad3917SSebastian Grimberg 
26614556e63SJeremy L Thompson   // Get source matrices
26715ad3917SSebastian Grimberg   CeedInt           dim, q_comp = 1;
2682247a93fSRezgar Shakeri   CeedScalar       *interp_to_inv, *interp_from;
2691c66c397SJeremy L Thompson   const CeedScalar *interp_to_source = NULL, *interp_from_source = NULL, *grad_from_source = NULL;
2701c66c397SJeremy L Thompson 
271b3ed00e5SJames Wright   CeedCall(CeedBasisGetDimension(basis_from, &dim));
272e104ad11SJames Wright   if (are_both_tensor) {
2732b730f8bSJeremy L Thompson     CeedCall(CeedBasisGetInterp1D(basis_to, &interp_to_source));
2742b730f8bSJeremy L Thompson     CeedCall(CeedBasisGetInterp1D(basis_from, &interp_from_source));
275a76a04e7SJeremy L Thompson   } else {
27615ad3917SSebastian Grimberg     CeedCall(CeedBasisGetNumQuadratureComponents(basis_from, CEED_EVAL_INTERP, &q_comp));
2772b730f8bSJeremy L Thompson     CeedCall(CeedBasisGetInterp(basis_to, &interp_to_source));
2782b730f8bSJeremy L Thompson     CeedCall(CeedBasisGetInterp(basis_from, &interp_from_source));
27915ad3917SSebastian Grimberg   }
28015ad3917SSebastian Grimberg   CeedCall(CeedMalloc(Q * P_from * q_comp, &interp_from));
28115ad3917SSebastian Grimberg   CeedCall(CeedCalloc(P_to * P_from, interp_project));
28215ad3917SSebastian Grimberg 
28315ad3917SSebastian Grimberg   // `grad_project = interp_to^+ * grad_from` is computed for the H^1 space case so the
284de05fbb2SSebastian Grimberg   // projection basis will have a gradient operation (allocated even if not H^1 for the
285de05fbb2SSebastian Grimberg   // basis construction later on)
28615ad3917SSebastian Grimberg   if (fe_space_to == CEED_FE_SPACE_H1) {
287e104ad11SJames Wright     if (are_both_tensor) {
28815ad3917SSebastian Grimberg       CeedCall(CeedBasisGetGrad1D(basis_from, &grad_from_source));
28915ad3917SSebastian Grimberg     } else {
2902b730f8bSJeremy L Thompson       CeedCall(CeedBasisGetGrad(basis_from, &grad_from_source));
291a76a04e7SJeremy L Thompson     }
292de05fbb2SSebastian Grimberg   }
293e104ad11SJames Wright   CeedCall(CeedCalloc(P_to * P_from * (are_both_tensor ? 1 : dim), grad_project));
29415ad3917SSebastian Grimberg 
2952247a93fSRezgar Shakeri   // Compute interp_to^+, pseudoinverse of interp_to
2962247a93fSRezgar Shakeri   CeedCall(CeedCalloc(Q * q_comp * P_to, &interp_to_inv));
2979bc66399SJeremy L Thompson   CeedCall(CeedMatrixPseudoinverse(CeedBasisReturnCeed(basis_to), interp_to_source, Q * q_comp, P_to, interp_to_inv));
29814556e63SJeremy L Thompson   // Build matrices
299e104ad11SJames Wright   CeedInt     num_matrices = 1 + (fe_space_to == CEED_FE_SPACE_H1) * (are_both_tensor ? 1 : dim);
30014556e63SJeremy L Thompson   CeedScalar *input_from[num_matrices], *output_project[num_matrices];
3011c66c397SJeremy L Thompson 
30214556e63SJeremy L Thompson   input_from[0]     = (CeedScalar *)interp_from_source;
30314556e63SJeremy L Thompson   output_project[0] = *interp_project;
30414556e63SJeremy L Thompson   for (CeedInt m = 1; m < num_matrices; m++) {
30514556e63SJeremy L Thompson     input_from[m]     = (CeedScalar *)&grad_from_source[(m - 1) * Q * P_from];
30602af4036SJeremy L Thompson     output_project[m] = &((*grad_project)[(m - 1) * P_to * P_from]);
30714556e63SJeremy L Thompson   }
30814556e63SJeremy L Thompson   for (CeedInt m = 0; m < num_matrices; m++) {
3092247a93fSRezgar Shakeri     // output_project = interp_to^+ * interp_from
31015ad3917SSebastian Grimberg     memcpy(interp_from, input_from[m], Q * P_from * q_comp * sizeof(input_from[m][0]));
3119bc66399SJeremy L Thompson     CeedCall(CeedMatrixMatrixMultiply(CeedBasisReturnCeed(basis_to), interp_to_inv, input_from[m], output_project[m], P_to, P_from, Q * q_comp));
3122247a93fSRezgar Shakeri     // Round zero to machine precision
3132247a93fSRezgar Shakeri     for (CeedInt i = 0; i < P_to * P_from; i++) {
3142247a93fSRezgar Shakeri       if (fabs(output_project[m][i]) < 10 * CEED_EPSILON) output_project[m][i] = 0.0;
315a76a04e7SJeremy L Thompson     }
31614556e63SJeremy L Thompson   }
31714556e63SJeremy L Thompson 
31814556e63SJeremy L Thompson   // Cleanup
3192247a93fSRezgar Shakeri   CeedCall(CeedFree(&interp_to_inv));
3202b730f8bSJeremy L Thompson   CeedCall(CeedFree(&interp_from));
321a76a04e7SJeremy L Thompson   return CEED_ERROR_SUCCESS;
322a76a04e7SJeremy L Thompson }
323a76a04e7SJeremy L Thompson 
3240b31fde2SJeremy L Thompson /**
3256ab8e59fSJames Wright   @brief Check input vector dimensions for CeedBasisApply[Add]
3266ab8e59fSJames Wright 
3276ab8e59fSJames Wright   @param[in]  basis     `CeedBasis` to evaluate
3286ab8e59fSJames Wright   @param[in]  num_elem  The number of elements to apply the basis evaluation to;
3296ab8e59fSJames Wright                           the backend will specify the ordering in @ref CeedElemRestrictionCreate()
3306ab8e59fSJames Wright   @param[in]  t_mode    @ref CEED_NOTRANSPOSE to evaluate from nodes to quadrature points;
3316ab8e59fSJames Wright                           @ref CEED_TRANSPOSE to apply the transpose, mapping from quadrature points to nodes
3326ab8e59fSJames Wright   @param[in]  eval_mode @ref CEED_EVAL_NONE to use values directly,
3336ab8e59fSJames Wright                           @ref CEED_EVAL_INTERP to use interpolated values,
3346ab8e59fSJames Wright                           @ref CEED_EVAL_GRAD to use gradients,
3356ab8e59fSJames Wright                           @ref CEED_EVAL_DIV to use divergence,
3366ab8e59fSJames Wright                           @ref CEED_EVAL_CURL to use curl,
3376ab8e59fSJames Wright                           @ref CEED_EVAL_WEIGHT to use quadrature weights
3386ab8e59fSJames Wright   @param[in]  u         Input `CeedVector`
3396ab8e59fSJames Wright   @param[out] v         Output `CeedVector`
3406ab8e59fSJames Wright 
3416ab8e59fSJames Wright   @return An error code: 0 - success, otherwise - failure
3426ab8e59fSJames Wright 
3436ab8e59fSJames Wright   @ref Developer
3446ab8e59fSJames Wright **/
CeedBasisApplyCheckDims(CeedBasis basis,CeedInt num_elem,CeedTransposeMode t_mode,CeedEvalMode eval_mode,CeedVector u,CeedVector v)3456ab8e59fSJames Wright static int CeedBasisApplyCheckDims(CeedBasis basis, CeedInt num_elem, CeedTransposeMode t_mode, CeedEvalMode eval_mode, CeedVector u, CeedVector v) {
3466ab8e59fSJames Wright   CeedInt  dim, num_comp, q_comp, num_nodes, num_qpts;
3476ab8e59fSJames Wright   CeedSize u_length = 0, v_length;
3486ab8e59fSJames Wright 
3496ab8e59fSJames Wright   CeedCall(CeedBasisGetDimension(basis, &dim));
3506ab8e59fSJames Wright   CeedCall(CeedBasisGetNumComponents(basis, &num_comp));
3516ab8e59fSJames Wright   CeedCall(CeedBasisGetNumQuadratureComponents(basis, eval_mode, &q_comp));
3526ab8e59fSJames Wright   CeedCall(CeedBasisGetNumNodes(basis, &num_nodes));
3536ab8e59fSJames Wright   CeedCall(CeedBasisGetNumQuadraturePoints(basis, &num_qpts));
3546ab8e59fSJames Wright   CeedCall(CeedVectorGetLength(v, &v_length));
3556ab8e59fSJames Wright   if (u) CeedCall(CeedVectorGetLength(u, &u_length));
3566ab8e59fSJames Wright 
3576ab8e59fSJames Wright   // Check vector lengths to prevent out of bounds issues
3586ab8e59fSJames Wright   bool has_good_dims = true;
3596ab8e59fSJames Wright   switch (eval_mode) {
3606ab8e59fSJames Wright     case CEED_EVAL_NONE:
3616ab8e59fSJames Wright     case CEED_EVAL_INTERP:
3626ab8e59fSJames Wright     case CEED_EVAL_GRAD:
3636ab8e59fSJames Wright     case CEED_EVAL_DIV:
3646ab8e59fSJames Wright     case CEED_EVAL_CURL:
3656ab8e59fSJames Wright       has_good_dims = ((t_mode == CEED_TRANSPOSE && u_length >= (CeedSize)num_elem * (CeedSize)num_comp * (CeedSize)num_qpts * (CeedSize)q_comp &&
3666ab8e59fSJames Wright                         v_length >= (CeedSize)num_elem * (CeedSize)num_comp * (CeedSize)num_nodes) ||
3676ab8e59fSJames Wright                        (t_mode == CEED_NOTRANSPOSE && v_length >= (CeedSize)num_elem * (CeedSize)num_qpts * (CeedSize)num_comp * (CeedSize)q_comp &&
3686ab8e59fSJames Wright                         u_length >= (CeedSize)num_elem * (CeedSize)num_comp * (CeedSize)num_nodes));
3696ab8e59fSJames Wright       break;
3706ab8e59fSJames Wright     case CEED_EVAL_WEIGHT:
3716ab8e59fSJames Wright       has_good_dims = v_length >= (CeedSize)num_elem * (CeedSize)num_qpts;
3726ab8e59fSJames Wright       break;
3736ab8e59fSJames Wright   }
3746ab8e59fSJames Wright   CeedCheck(has_good_dims, CeedBasisReturnCeed(basis), CEED_ERROR_DIMENSION, "Input/output vectors too short for basis and evaluation mode");
3756ab8e59fSJames Wright   return CEED_ERROR_SUCCESS;
3766ab8e59fSJames Wright }
3776ab8e59fSJames Wright 
3786ab8e59fSJames Wright /**
3790b31fde2SJeremy L Thompson   @brief Check input vector dimensions for CeedBasisApply[Add]AtPoints
3800b31fde2SJeremy L Thompson 
3810b31fde2SJeremy L Thompson   @param[in]  basis      `CeedBasis` to evaluate
3820b31fde2SJeremy L Thompson   @param[in]  num_elem   The number of elements to apply the basis evaluation to;
3830b31fde2SJeremy L Thompson                           the backend will specify the ordering in @ref CeedElemRestrictionCreate()
3840b31fde2SJeremy L Thompson   @param[in]  num_points Array of the number of points to apply the basis evaluation to in each element, size `num_elem`
3850b31fde2SJeremy L Thompson   @param[in]  t_mode     @ref CEED_NOTRANSPOSE to evaluate from nodes to points;
3860b31fde2SJeremy L Thompson                            @ref CEED_TRANSPOSE to apply the transpose, mapping from points to nodes
3870b31fde2SJeremy L Thompson   @param[in]  eval_mode  @ref CEED_EVAL_INTERP to use interpolated values,
3880b31fde2SJeremy L Thompson                            @ref CEED_EVAL_GRAD to use gradients,
3890b31fde2SJeremy L Thompson                            @ref CEED_EVAL_WEIGHT to use quadrature weights
3900b31fde2SJeremy L Thompson   @param[in]  x_ref      `CeedVector` holding reference coordinates of each point
3910b31fde2SJeremy L Thompson   @param[in]  u          Input `CeedVector`, of length `num_nodes * num_comp` for @ref CEED_NOTRANSPOSE
3920b31fde2SJeremy L Thompson   @param[out] v          Output `CeedVector`, of length `num_points * num_q_comp` for @ref CEED_NOTRANSPOSE with @ref CEED_EVAL_INTERP
3930b31fde2SJeremy L Thompson 
3940b31fde2SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
3950b31fde2SJeremy L Thompson 
3960b31fde2SJeremy L Thompson   @ref Developer
3970b31fde2SJeremy L Thompson **/
CeedBasisApplyAtPointsCheckDims(CeedBasis basis,CeedInt num_elem,const CeedInt * num_points,CeedTransposeMode t_mode,CeedEvalMode eval_mode,CeedVector x_ref,CeedVector u,CeedVector v)3980b31fde2SJeremy L Thompson static int CeedBasisApplyAtPointsCheckDims(CeedBasis basis, CeedInt num_elem, const CeedInt *num_points, CeedTransposeMode t_mode,
3990b31fde2SJeremy L Thompson                                            CeedEvalMode eval_mode, CeedVector x_ref, CeedVector u, CeedVector v) {
4000b31fde2SJeremy L Thompson   CeedInt  dim, num_comp, num_q_comp, num_nodes, P_1d = 1, Q_1d = 1, total_num_points = 0;
4010b31fde2SJeremy L Thompson   CeedSize x_length = 0, u_length = 0, v_length;
4020b31fde2SJeremy L Thompson 
4030b31fde2SJeremy L Thompson   CeedCall(CeedBasisGetDimension(basis, &dim));
4040b31fde2SJeremy L Thompson   CeedCall(CeedBasisGetNumNodes1D(basis, &P_1d));
4050b31fde2SJeremy L Thompson   CeedCall(CeedBasisGetNumQuadraturePoints1D(basis, &Q_1d));
4060b31fde2SJeremy L Thompson   CeedCall(CeedBasisGetNumComponents(basis, &num_comp));
4070b31fde2SJeremy L Thompson   CeedCall(CeedBasisGetNumQuadratureComponents(basis, eval_mode, &num_q_comp));
4080b31fde2SJeremy L Thompson   CeedCall(CeedBasisGetNumNodes(basis, &num_nodes));
4090b31fde2SJeremy L Thompson   CeedCall(CeedVectorGetLength(v, &v_length));
4100b31fde2SJeremy L Thompson   if (x_ref != CEED_VECTOR_NONE) CeedCall(CeedVectorGetLength(x_ref, &x_length));
4110b31fde2SJeremy L Thompson   if (u != CEED_VECTOR_NONE) CeedCall(CeedVectorGetLength(u, &u_length));
4120b31fde2SJeremy L Thompson 
4130b31fde2SJeremy L Thompson   // Check compatibility coordinates vector
4140b31fde2SJeremy L Thompson   for (CeedInt i = 0; i < num_elem; i++) total_num_points += num_points[i];
4159bc66399SJeremy L Thompson   CeedCheck((x_length >= (CeedSize)total_num_points * (CeedSize)dim) || (eval_mode == CEED_EVAL_WEIGHT), CeedBasisReturnCeed(basis),
4169bc66399SJeremy L Thompson             CEED_ERROR_DIMENSION,
4170b31fde2SJeremy L Thompson             "Length of reference coordinate vector incompatible with basis dimension and number of points."
4180b31fde2SJeremy L Thompson             " Found reference coordinate vector of length %" CeedSize_FMT ", not of length %" CeedSize_FMT ".",
41919a04db8SJeremy L Thompson             x_length, (CeedSize)total_num_points * (CeedSize)dim);
4200b31fde2SJeremy L Thompson 
4210b31fde2SJeremy L Thompson   // Check CEED_EVAL_WEIGHT only on CEED_NOTRANSPOSE
4229bc66399SJeremy L Thompson   CeedCheck(eval_mode != CEED_EVAL_WEIGHT || t_mode == CEED_NOTRANSPOSE, CeedBasisReturnCeed(basis), CEED_ERROR_UNSUPPORTED,
4230b31fde2SJeremy L Thompson             "CEED_EVAL_WEIGHT only supported with CEED_NOTRANSPOSE");
4240b31fde2SJeremy L Thompson 
4250b31fde2SJeremy L Thompson   // Check vector lengths to prevent out of bounds issues
4260b31fde2SJeremy L Thompson   bool has_good_dims = true;
4270b31fde2SJeremy L Thompson   switch (eval_mode) {
4280b31fde2SJeremy L Thompson     case CEED_EVAL_INTERP:
42919a04db8SJeremy L Thompson       has_good_dims = ((t_mode == CEED_TRANSPOSE && (u_length >= (CeedSize)total_num_points * (CeedSize)num_q_comp ||
43019a04db8SJeremy L Thompson                                                      v_length >= (CeedSize)num_elem * (CeedSize)num_nodes * (CeedSize)num_comp)) ||
43119a04db8SJeremy L Thompson                        (t_mode == CEED_NOTRANSPOSE && (v_length >= (CeedSize)total_num_points * (CeedSize)num_q_comp ||
43219a04db8SJeremy L Thompson                                                        u_length >= (CeedSize)num_elem * (CeedSize)num_nodes * (CeedSize)num_comp)));
4330b31fde2SJeremy L Thompson       break;
4340b31fde2SJeremy L Thompson     case CEED_EVAL_GRAD:
43519a04db8SJeremy L Thompson       has_good_dims = ((t_mode == CEED_TRANSPOSE && (u_length >= (CeedSize)total_num_points * (CeedSize)num_q_comp * (CeedSize)dim ||
43619a04db8SJeremy L Thompson                                                      v_length >= (CeedSize)num_elem * (CeedSize)num_nodes * (CeedSize)num_comp)) ||
43719a04db8SJeremy L Thompson                        (t_mode == CEED_NOTRANSPOSE && (v_length >= (CeedSize)total_num_points * (CeedSize)num_q_comp * (CeedSize)dim ||
43819a04db8SJeremy L Thompson                                                        u_length >= (CeedSize)num_elem * (CeedSize)num_nodes * (CeedSize)num_comp)));
4390b31fde2SJeremy L Thompson       break;
4400b31fde2SJeremy L Thompson     case CEED_EVAL_WEIGHT:
4410b31fde2SJeremy L Thompson       has_good_dims = t_mode == CEED_NOTRANSPOSE && (v_length >= total_num_points);
4420b31fde2SJeremy L Thompson       break;
4430b31fde2SJeremy L Thompson       // LCOV_EXCL_START
4440b31fde2SJeremy L Thompson     case CEED_EVAL_NONE:
4450b31fde2SJeremy L Thompson     case CEED_EVAL_DIV:
4460b31fde2SJeremy L Thompson     case CEED_EVAL_CURL:
4479bc66399SJeremy L Thompson       return CeedError(CeedBasisReturnCeed(basis), CEED_ERROR_UNSUPPORTED, "Evaluation at arbitrary points not supported for %s",
4489bc66399SJeremy L Thompson                        CeedEvalModes[eval_mode]);
4490b31fde2SJeremy L Thompson       // LCOV_EXCL_STOP
4500b31fde2SJeremy L Thompson   }
4519bc66399SJeremy L Thompson   CeedCheck(has_good_dims, CeedBasisReturnCeed(basis), CEED_ERROR_DIMENSION, "Input/output vectors too short for basis and evaluation mode");
4520b31fde2SJeremy L Thompson   return CEED_ERROR_SUCCESS;
4530b31fde2SJeremy L Thompson }
4540b31fde2SJeremy L Thompson 
4550b31fde2SJeremy L Thompson /**
4560b31fde2SJeremy L Thompson   @brief Default implimentation to apply basis evaluation from nodes to arbitrary points
4570b31fde2SJeremy L Thompson 
4580b31fde2SJeremy L Thompson   @param[in]  basis      `CeedBasis` to evaluate
4590b31fde2SJeremy L Thompson   @param[in]  apply_add  Sum result into target vector or overwrite
4600b31fde2SJeremy L Thompson   @param[in]  num_elem   The number of elements to apply the basis evaluation to;
4610b31fde2SJeremy L Thompson                           the backend will specify the ordering in @ref CeedElemRestrictionCreate()
4620b31fde2SJeremy L Thompson   @param[in]  num_points Array of the number of points to apply the basis evaluation to in each element, size `num_elem`
4630b31fde2SJeremy L Thompson   @param[in]  t_mode     @ref CEED_NOTRANSPOSE to evaluate from nodes to points;
4640b31fde2SJeremy L Thompson                            @ref CEED_TRANSPOSE to apply the transpose, mapping from points to nodes
4650b31fde2SJeremy L Thompson   @param[in]  eval_mode  @ref CEED_EVAL_INTERP to use interpolated values,
4660b31fde2SJeremy L Thompson                            @ref CEED_EVAL_GRAD to use gradients,
4670b31fde2SJeremy L Thompson                            @ref CEED_EVAL_WEIGHT to use quadrature weights
4680b31fde2SJeremy L Thompson   @param[in]  x_ref      `CeedVector` holding reference coordinates of each point
4690b31fde2SJeremy L Thompson   @param[in]  u          Input `CeedVector`, of length `num_nodes * num_comp` for @ref CEED_NOTRANSPOSE
4700b31fde2SJeremy L Thompson   @param[out] v          Output `CeedVector`, of length `num_points * num_q_comp` for @ref CEED_NOTRANSPOSE with @ref CEED_EVAL_INTERP
4710b31fde2SJeremy L Thompson 
4720b31fde2SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
4730b31fde2SJeremy L Thompson 
4740b31fde2SJeremy L Thompson   @ref Developer
4750b31fde2SJeremy L Thompson **/
CeedBasisApplyAtPoints_Core(CeedBasis basis,bool apply_add,CeedInt num_elem,const CeedInt * num_points,CeedTransposeMode t_mode,CeedEvalMode eval_mode,CeedVector x_ref,CeedVector u,CeedVector v)4760b31fde2SJeremy L Thompson static int CeedBasisApplyAtPoints_Core(CeedBasis basis, bool apply_add, CeedInt num_elem, const CeedInt *num_points, CeedTransposeMode t_mode,
4770b31fde2SJeremy L Thompson                                        CeedEvalMode eval_mode, CeedVector x_ref, CeedVector u, CeedVector v) {
4780b31fde2SJeremy L Thompson   CeedInt dim, num_comp, P_1d = 1, Q_1d = 1, total_num_points = num_points[0];
4790b31fde2SJeremy L Thompson 
4800b31fde2SJeremy L Thompson   CeedCall(CeedBasisGetDimension(basis, &dim));
4810b31fde2SJeremy L Thompson   // Inserting check because clang-tidy doesn't understand this cannot occur
4829bc66399SJeremy L Thompson   CeedCheck(dim > 0, CeedBasisReturnCeed(basis), CEED_ERROR_UNSUPPORTED, "Malformed CeedBasis, dim > 0 is required");
4830b31fde2SJeremy L Thompson   CeedCall(CeedBasisGetNumNodes1D(basis, &P_1d));
4840b31fde2SJeremy L Thompson   CeedCall(CeedBasisGetNumQuadraturePoints1D(basis, &Q_1d));
4850b31fde2SJeremy L Thompson   CeedCall(CeedBasisGetNumComponents(basis, &num_comp));
4860b31fde2SJeremy L Thompson 
4870b31fde2SJeremy L Thompson   // Default implementation
4880b31fde2SJeremy L Thompson   {
4890b31fde2SJeremy L Thompson     bool is_tensor_basis;
4900b31fde2SJeremy L Thompson 
4910b31fde2SJeremy L Thompson     CeedCall(CeedBasisIsTensor(basis, &is_tensor_basis));
4929bc66399SJeremy L Thompson     CeedCheck(is_tensor_basis, CeedBasisReturnCeed(basis), CEED_ERROR_UNSUPPORTED,
4939bc66399SJeremy L Thompson               "Evaluation at arbitrary points only supported for tensor product bases");
4940b31fde2SJeremy L Thompson   }
4959bc66399SJeremy L Thompson   CeedCheck(num_elem == 1, CeedBasisReturnCeed(basis), CEED_ERROR_UNSUPPORTED,
4969bc66399SJeremy L Thompson             "Evaluation at arbitrary  points only supported for a single element at a time");
4970b31fde2SJeremy L Thompson   if (eval_mode == CEED_EVAL_WEIGHT) {
4980b31fde2SJeremy L Thompson     CeedCall(CeedVectorSetValue(v, 1.0));
4990b31fde2SJeremy L Thompson     return CEED_ERROR_SUCCESS;
5000b31fde2SJeremy L Thompson   }
5010b31fde2SJeremy L Thompson   if (!basis->basis_chebyshev) {
5020b31fde2SJeremy L Thompson     // Build basis mapping from nodes to Chebyshev coefficients
5030b31fde2SJeremy L Thompson     CeedScalar       *chebyshev_interp_1d, *chebyshev_grad_1d, *chebyshev_q_weight_1d;
5040b31fde2SJeremy L Thompson     const CeedScalar *q_ref_1d;
5059bc66399SJeremy L Thompson     Ceed              ceed;
5060b31fde2SJeremy L Thompson 
5070b31fde2SJeremy L Thompson     CeedCall(CeedCalloc(P_1d * Q_1d, &chebyshev_interp_1d));
5080b31fde2SJeremy L Thompson     CeedCall(CeedCalloc(P_1d * Q_1d, &chebyshev_grad_1d));
5090b31fde2SJeremy L Thompson     CeedCall(CeedCalloc(Q_1d, &chebyshev_q_weight_1d));
5100b31fde2SJeremy L Thompson     CeedCall(CeedBasisGetQRef(basis, &q_ref_1d));
5110b31fde2SJeremy L Thompson     CeedCall(CeedBasisGetChebyshevInterp1D(basis, chebyshev_interp_1d));
5120b31fde2SJeremy L Thompson 
5139bc66399SJeremy L Thompson     CeedCall(CeedBasisGetCeed(basis, &ceed));
5140b31fde2SJeremy L Thompson     CeedCall(CeedVectorCreate(ceed, num_comp * CeedIntPow(Q_1d, dim), &basis->vec_chebyshev));
5150b31fde2SJeremy L Thompson     CeedCall(CeedBasisCreateTensorH1(ceed, dim, num_comp, P_1d, Q_1d, chebyshev_interp_1d, chebyshev_grad_1d, q_ref_1d, chebyshev_q_weight_1d,
5160b31fde2SJeremy L Thompson                                      &basis->basis_chebyshev));
5170b31fde2SJeremy L Thompson 
5180b31fde2SJeremy L Thompson     // Cleanup
5190b31fde2SJeremy L Thompson     CeedCall(CeedFree(&chebyshev_interp_1d));
5200b31fde2SJeremy L Thompson     CeedCall(CeedFree(&chebyshev_grad_1d));
5210b31fde2SJeremy L Thompson     CeedCall(CeedFree(&chebyshev_q_weight_1d));
5229bc66399SJeremy L Thompson     CeedCall(CeedDestroy(&ceed));
5230b31fde2SJeremy L Thompson   }
5240b31fde2SJeremy L Thompson 
5250b31fde2SJeremy L Thompson   // Create TensorContract object if needed, such as a basis from the GPU backends
5260b31fde2SJeremy L Thompson   if (!basis->contract) {
5270b31fde2SJeremy L Thompson     Ceed      ceed_ref;
5280b31fde2SJeremy L Thompson     CeedBasis basis_ref = NULL;
5290b31fde2SJeremy L Thompson 
5300b31fde2SJeremy L Thompson     CeedCall(CeedInit("/cpu/self", &ceed_ref));
5310b31fde2SJeremy L Thompson     // Only need matching tensor contraction dimensions, any type of basis will work
5320b31fde2SJeremy L Thompson     CeedCall(CeedBasisCreateTensorH1Lagrange(ceed_ref, dim, num_comp, P_1d, Q_1d, CEED_GAUSS, &basis_ref));
5330b31fde2SJeremy L Thompson     // Note - clang-tidy doesn't know basis_ref->contract must be valid here
5349bc66399SJeremy L Thompson     CeedCheck(basis_ref && basis_ref->contract, CeedBasisReturnCeed(basis), CEED_ERROR_UNSUPPORTED,
5359bc66399SJeremy L Thompson               "Reference CPU ceed failed to create a tensor contraction object");
5360b31fde2SJeremy L Thompson     CeedCall(CeedTensorContractReferenceCopy(basis_ref->contract, &basis->contract));
5370b31fde2SJeremy L Thompson     CeedCall(CeedBasisDestroy(&basis_ref));
5380b31fde2SJeremy L Thompson     CeedCall(CeedDestroy(&ceed_ref));
5390b31fde2SJeremy L Thompson   }
5400b31fde2SJeremy L Thompson 
5410b31fde2SJeremy L Thompson   // Basis evaluation
5420b31fde2SJeremy L Thompson   switch (t_mode) {
5430b31fde2SJeremy L Thompson     case CEED_NOTRANSPOSE: {
5440b31fde2SJeremy L Thompson       // Nodes to arbitrary points
5450b31fde2SJeremy L Thompson       CeedScalar       *v_array;
5460b31fde2SJeremy L Thompson       const CeedScalar *chebyshev_coeffs, *x_array_read;
5470b31fde2SJeremy L Thompson 
5480b31fde2SJeremy L Thompson       // -- Interpolate to Chebyshev coefficients
5490b31fde2SJeremy L Thompson       CeedCall(CeedBasisApply(basis->basis_chebyshev, 1, CEED_NOTRANSPOSE, CEED_EVAL_INTERP, u, basis->vec_chebyshev));
5500b31fde2SJeremy L Thompson 
5510b31fde2SJeremy L Thompson       // -- Evaluate Chebyshev polynomials at arbitrary points
5520b31fde2SJeremy L Thompson       CeedCall(CeedVectorGetArrayRead(basis->vec_chebyshev, CEED_MEM_HOST, &chebyshev_coeffs));
5530b31fde2SJeremy L Thompson       CeedCall(CeedVectorGetArrayRead(x_ref, CEED_MEM_HOST, &x_array_read));
5540b31fde2SJeremy L Thompson       CeedCall(CeedVectorGetArrayWrite(v, CEED_MEM_HOST, &v_array));
5550b31fde2SJeremy L Thompson       switch (eval_mode) {
5560b31fde2SJeremy L Thompson         case CEED_EVAL_INTERP: {
5570b31fde2SJeremy L Thompson           CeedScalar tmp[2][num_comp * CeedIntPow(Q_1d, dim)], chebyshev_x[Q_1d];
5580b31fde2SJeremy L Thompson 
5590b31fde2SJeremy L Thompson           // ---- Values at point
5600b31fde2SJeremy L Thompson           for (CeedInt p = 0; p < total_num_points; p++) {
5610b31fde2SJeremy L Thompson             CeedInt pre = num_comp * CeedIntPow(Q_1d, dim - 1), post = 1;
5620b31fde2SJeremy L Thompson 
5630b31fde2SJeremy L Thompson             for (CeedInt d = 0; d < dim; d++) {
5640b31fde2SJeremy L Thompson               // ------ Tensor contract with current Chebyshev polynomial values
5650b31fde2SJeremy L Thompson               CeedCall(CeedChebyshevPolynomialsAtPoint(x_array_read[d * total_num_points + p], Q_1d, chebyshev_x));
5660b31fde2SJeremy L Thompson               CeedCall(CeedTensorContractApply(basis->contract, pre, Q_1d, post, 1, chebyshev_x, t_mode, false,
5670b31fde2SJeremy L Thompson                                                d == 0 ? chebyshev_coeffs : tmp[d % 2], tmp[(d + 1) % 2]));
5680b31fde2SJeremy L Thompson               pre /= Q_1d;
5690b31fde2SJeremy L Thompson               post *= 1;
5700b31fde2SJeremy L Thompson             }
5710b31fde2SJeremy L Thompson             for (CeedInt c = 0; c < num_comp; c++) v_array[c * total_num_points + p] = tmp[dim % 2][c];
5720b31fde2SJeremy L Thompson           }
5730b31fde2SJeremy L Thompson           break;
5740b31fde2SJeremy L Thompson         }
5750b31fde2SJeremy L Thompson         case CEED_EVAL_GRAD: {
5760b31fde2SJeremy L Thompson           CeedScalar tmp[2][num_comp * CeedIntPow(Q_1d, dim)], chebyshev_x[Q_1d];
5770b31fde2SJeremy L Thompson 
5780b31fde2SJeremy L Thompson           // ---- Values at point
5790b31fde2SJeremy L Thompson           for (CeedInt p = 0; p < total_num_points; p++) {
5800b31fde2SJeremy L Thompson             // Dim**2 contractions, apply grad when pass == dim
5810b31fde2SJeremy L Thompson             for (CeedInt pass = 0; pass < dim; pass++) {
5820b31fde2SJeremy L Thompson               CeedInt pre = num_comp * CeedIntPow(Q_1d, dim - 1), post = 1;
5830b31fde2SJeremy L Thompson 
5840b31fde2SJeremy L Thompson               for (CeedInt d = 0; d < dim; d++) {
5850b31fde2SJeremy L Thompson                 // ------ Tensor contract with current Chebyshev polynomial values
5860b31fde2SJeremy L Thompson                 if (pass == d) CeedCall(CeedChebyshevDerivativeAtPoint(x_array_read[d * total_num_points + p], Q_1d, chebyshev_x));
5870b31fde2SJeremy L Thompson                 else CeedCall(CeedChebyshevPolynomialsAtPoint(x_array_read[d * total_num_points + p], Q_1d, chebyshev_x));
5880b31fde2SJeremy L Thompson                 CeedCall(CeedTensorContractApply(basis->contract, pre, Q_1d, post, 1, chebyshev_x, t_mode, false,
5890b31fde2SJeremy L Thompson                                                  d == 0 ? chebyshev_coeffs : tmp[d % 2], tmp[(d + 1) % 2]));
5900b31fde2SJeremy L Thompson                 pre /= Q_1d;
5910b31fde2SJeremy L Thompson                 post *= 1;
5920b31fde2SJeremy L Thompson               }
5930b31fde2SJeremy L Thompson               for (CeedInt c = 0; c < num_comp; c++) v_array[(pass * num_comp + c) * total_num_points + p] = tmp[dim % 2][c];
5940b31fde2SJeremy L Thompson             }
5950b31fde2SJeremy L Thompson           }
5960b31fde2SJeremy L Thompson           break;
5970b31fde2SJeremy L Thompson         }
5980b31fde2SJeremy L Thompson         default:
5990b31fde2SJeremy L Thompson           // Nothing to do, excluded above
6000b31fde2SJeremy L Thompson           break;
6010b31fde2SJeremy L Thompson       }
6020b31fde2SJeremy L Thompson       CeedCall(CeedVectorRestoreArrayRead(basis->vec_chebyshev, &chebyshev_coeffs));
6030b31fde2SJeremy L Thompson       CeedCall(CeedVectorRestoreArrayRead(x_ref, &x_array_read));
6040b31fde2SJeremy L Thompson       CeedCall(CeedVectorRestoreArray(v, &v_array));
6050b31fde2SJeremy L Thompson       break;
6060b31fde2SJeremy L Thompson     }
6070b31fde2SJeremy L Thompson     case CEED_TRANSPOSE: {
6080b31fde2SJeremy L Thompson       // Note: No switch on e_mode here because only CEED_EVAL_INTERP is supported at this time
6090b31fde2SJeremy L Thompson       // Arbitrary points to nodes
6100b31fde2SJeremy L Thompson       CeedScalar       *chebyshev_coeffs;
6110b31fde2SJeremy L Thompson       const CeedScalar *u_array, *x_array_read;
6120b31fde2SJeremy L Thompson 
6130b31fde2SJeremy L Thompson       // -- Transpose of evaluation of Chebyshev polynomials at arbitrary points
6140b31fde2SJeremy L Thompson       CeedCall(CeedVectorGetArrayWrite(basis->vec_chebyshev, CEED_MEM_HOST, &chebyshev_coeffs));
6150b31fde2SJeremy L Thompson       CeedCall(CeedVectorGetArrayRead(x_ref, CEED_MEM_HOST, &x_array_read));
6160b31fde2SJeremy L Thompson       CeedCall(CeedVectorGetArrayRead(u, CEED_MEM_HOST, &u_array));
6170b31fde2SJeremy L Thompson 
6180b31fde2SJeremy L Thompson       switch (eval_mode) {
6190b31fde2SJeremy L Thompson         case CEED_EVAL_INTERP: {
6200b31fde2SJeremy L Thompson           CeedScalar tmp[2][num_comp * CeedIntPow(Q_1d, dim)], chebyshev_x[Q_1d];
6210b31fde2SJeremy L Thompson 
6220b31fde2SJeremy L Thompson           // ---- Values at point
6230b31fde2SJeremy L Thompson           for (CeedInt p = 0; p < total_num_points; p++) {
6240b31fde2SJeremy L Thompson             CeedInt pre = num_comp * 1, post = 1;
6250b31fde2SJeremy L Thompson 
6260b31fde2SJeremy L Thompson             for (CeedInt c = 0; c < num_comp; c++) tmp[0][c] = u_array[c * total_num_points + p];
6270b31fde2SJeremy L Thompson             for (CeedInt d = 0; d < dim; d++) {
6280b31fde2SJeremy L Thompson               // ------ Tensor contract with current Chebyshev polynomial values
6290b31fde2SJeremy L Thompson               CeedCall(CeedChebyshevPolynomialsAtPoint(x_array_read[d * total_num_points + p], Q_1d, chebyshev_x));
6300b31fde2SJeremy L Thompson               CeedCall(CeedTensorContractApply(basis->contract, pre, 1, post, Q_1d, chebyshev_x, t_mode, p > 0 && d == (dim - 1), tmp[d % 2],
6310b31fde2SJeremy L Thompson                                                d == (dim - 1) ? chebyshev_coeffs : tmp[(d + 1) % 2]));
6320b31fde2SJeremy L Thompson               pre /= 1;
6330b31fde2SJeremy L Thompson               post *= Q_1d;
6340b31fde2SJeremy L Thompson             }
6350b31fde2SJeremy L Thompson           }
6360b31fde2SJeremy L Thompson           break;
6370b31fde2SJeremy L Thompson         }
6380b31fde2SJeremy L Thompson         case CEED_EVAL_GRAD: {
6390b31fde2SJeremy L Thompson           CeedScalar tmp[2][num_comp * CeedIntPow(Q_1d, dim)], chebyshev_x[Q_1d];
6400b31fde2SJeremy L Thompson 
6410b31fde2SJeremy L Thompson           // ---- Values at point
6420b31fde2SJeremy L Thompson           for (CeedInt p = 0; p < total_num_points; p++) {
6430b31fde2SJeremy L Thompson             // Dim**2 contractions, apply grad when pass == dim
6440b31fde2SJeremy L Thompson             for (CeedInt pass = 0; pass < dim; pass++) {
6450b31fde2SJeremy L Thompson               CeedInt pre = num_comp * 1, post = 1;
6460b31fde2SJeremy L Thompson 
6470b31fde2SJeremy L Thompson               for (CeedInt c = 0; c < num_comp; c++) tmp[0][c] = u_array[(pass * num_comp + c) * total_num_points + p];
6480b31fde2SJeremy L Thompson               for (CeedInt d = 0; d < dim; d++) {
6490b31fde2SJeremy L Thompson                 // ------ Tensor contract with current Chebyshev polynomial values
6500b31fde2SJeremy L Thompson                 if (pass == d) CeedCall(CeedChebyshevDerivativeAtPoint(x_array_read[d * total_num_points + p], Q_1d, chebyshev_x));
6510b31fde2SJeremy L Thompson                 else CeedCall(CeedChebyshevPolynomialsAtPoint(x_array_read[d * total_num_points + p], Q_1d, chebyshev_x));
6520b31fde2SJeremy L Thompson                 CeedCall(CeedTensorContractApply(basis->contract, pre, 1, post, Q_1d, chebyshev_x, t_mode,
6530b31fde2SJeremy L Thompson                                                  (p > 0 || (p == 0 && pass > 0)) && d == (dim - 1), tmp[d % 2],
6540b31fde2SJeremy L Thompson                                                  d == (dim - 1) ? chebyshev_coeffs : tmp[(d + 1) % 2]));
6550b31fde2SJeremy L Thompson                 pre /= 1;
6560b31fde2SJeremy L Thompson                 post *= Q_1d;
6570b31fde2SJeremy L Thompson               }
6580b31fde2SJeremy L Thompson             }
6590b31fde2SJeremy L Thompson           }
6600b31fde2SJeremy L Thompson           break;
6610b31fde2SJeremy L Thompson         }
6620b31fde2SJeremy L Thompson         default:
6630b31fde2SJeremy L Thompson           // Nothing to do, excluded above
6640b31fde2SJeremy L Thompson           break;
6650b31fde2SJeremy L Thompson       }
6660b31fde2SJeremy L Thompson       CeedCall(CeedVectorRestoreArray(basis->vec_chebyshev, &chebyshev_coeffs));
6670b31fde2SJeremy L Thompson       CeedCall(CeedVectorRestoreArrayRead(x_ref, &x_array_read));
6680b31fde2SJeremy L Thompson       CeedCall(CeedVectorRestoreArrayRead(u, &u_array));
6690b31fde2SJeremy L Thompson 
6700b31fde2SJeremy L Thompson       // -- Interpolate transpose from Chebyshev coefficients
6710b31fde2SJeremy L Thompson       if (apply_add) CeedCall(CeedBasisApplyAdd(basis->basis_chebyshev, 1, CEED_TRANSPOSE, CEED_EVAL_INTERP, basis->vec_chebyshev, v));
6720b31fde2SJeremy L Thompson       else CeedCall(CeedBasisApply(basis->basis_chebyshev, 1, CEED_TRANSPOSE, CEED_EVAL_INTERP, basis->vec_chebyshev, v));
6730b31fde2SJeremy L Thompson       break;
6740b31fde2SJeremy L Thompson     }
6750b31fde2SJeremy L Thompson   }
6760b31fde2SJeremy L Thompson   return CEED_ERROR_SUCCESS;
6770b31fde2SJeremy L Thompson }
6780b31fde2SJeremy L Thompson 
6797a982d89SJeremy L. Thompson /// @}
6807a982d89SJeremy L. Thompson 
6817a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
6827a982d89SJeremy L. Thompson /// Ceed Backend API
6837a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
6847a982d89SJeremy L. Thompson /// @addtogroup CeedBasisBackend
6857a982d89SJeremy L. Thompson /// @{
6867a982d89SJeremy L. Thompson 
6877a982d89SJeremy L. Thompson /**
688fda26546SJeremy L Thompson   @brief Fallback to a reference implementation for a non tensor-product basis for \f$H^1\f$ discretizations.
689fda26546SJeremy L Thompson     This function may only be called inside of a backend `BasisCreateH1` function.
690fda26546SJeremy L Thompson     This is used by a backend when the specific parameters for a `CeedBasis` exceed the backend's support, such as
691fda26546SJeremy L Thompson     when a `interp` and `grad` matrices require too many bytes to fit into shared memory on a GPU.
692fda26546SJeremy L Thompson 
693fda26546SJeremy L Thompson   @param[in]  ceed      `Ceed` object used to create the `CeedBasis`
694fda26546SJeremy L Thompson   @param[in]  topo      Topology of element, e.g. hypercube, simplex, etc
695fda26546SJeremy L Thompson   @param[in]  num_comp  Number of field components (1 for scalar fields)
696fda26546SJeremy L Thompson   @param[in]  num_nodes Total number of nodes
697fda26546SJeremy L Thompson   @param[in]  num_qpts  Total number of quadrature points
698fda26546SJeremy L Thompson   @param[in]  interp    Row-major (`num_qpts * num_nodes`) matrix expressing the values of nodal basis functions at quadrature points
699fda26546SJeremy L Thompson   @param[in]  grad      Row-major (`dim * num_qpts * num_nodes`) matrix expressing derivatives of nodal basis functions at quadrature points
700fda26546SJeremy L Thompson   @param[in]  q_ref     Array of length `num_qpts * dim` holding the locations of quadrature points on the reference element
701fda26546SJeremy L Thompson   @param[in]  q_weight  Array of length `num_qpts` holding the quadrature weights on the reference element
702fda26546SJeremy L Thompson   @param[out] basis     Newly created `CeedBasis`
703fda26546SJeremy L Thompson 
704fda26546SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
705fda26546SJeremy L Thompson 
706fda26546SJeremy L Thompson   @ref User
707fda26546SJeremy L Thompson **/
CeedBasisCreateH1Fallback(Ceed ceed,CeedElemTopology topo,CeedInt num_comp,CeedInt num_nodes,CeedInt num_qpts,const CeedScalar * interp,const CeedScalar * grad,const CeedScalar * q_ref,const CeedScalar * q_weight,CeedBasis basis)708fda26546SJeremy L Thompson int CeedBasisCreateH1Fallback(Ceed ceed, CeedElemTopology topo, CeedInt num_comp, CeedInt num_nodes, CeedInt num_qpts, const CeedScalar *interp,
709fda26546SJeremy L Thompson                               const CeedScalar *grad, const CeedScalar *q_ref, const CeedScalar *q_weight, CeedBasis basis) {
710fda26546SJeremy L Thompson   CeedInt P = num_nodes, Q = num_qpts, dim = 0;
711fda26546SJeremy L Thompson   Ceed    delegate;
712fda26546SJeremy L Thompson 
713fda26546SJeremy L Thompson   CeedCall(CeedGetObjectDelegate(ceed, &delegate, "Basis"));
714fda26546SJeremy L Thompson   CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement BasisCreateH1");
715fda26546SJeremy L Thompson 
716b0f67a9cSJeremy L Thompson   CeedCall(CeedReferenceCopy(delegate, &(basis)->obj.ceed));
717fda26546SJeremy L Thompson   CeedCall(CeedBasisGetTopologyDimension(topo, &dim));
718fda26546SJeremy L Thompson   CeedCall(delegate->BasisCreateH1(topo, dim, P, Q, interp, grad, q_ref, q_weight, basis));
719fda26546SJeremy L Thompson   CeedCall(CeedDestroy(&delegate));
720fda26546SJeremy L Thompson   return CEED_ERROR_SUCCESS;
721fda26546SJeremy L Thompson }
722fda26546SJeremy L Thompson 
723fda26546SJeremy L Thompson /**
724ca94c3ddSJeremy L Thompson   @brief Return collocated gradient matrix
7257a982d89SJeremy L. Thompson 
726ca94c3ddSJeremy L Thompson   @param[in]  basis         `CeedBasis`
727ca94c3ddSJeremy L Thompson   @param[out] collo_grad_1d Row-major (`Q_1d * Q_1d`) matrix expressing derivatives of basis functions at quadrature points
7287a982d89SJeremy L. Thompson 
7297a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
7307a982d89SJeremy L. Thompson 
7317a982d89SJeremy L. Thompson   @ref Backend
7327a982d89SJeremy L. Thompson **/
CeedBasisGetCollocatedGrad(CeedBasis basis,CeedScalar * collo_grad_1d)733d1d35e2fSjeremylt int CeedBasisGetCollocatedGrad(CeedBasis basis, CeedScalar *collo_grad_1d) {
7347a982d89SJeremy L. Thompson   Ceed              ceed;
7352247a93fSRezgar Shakeri   CeedInt           P_1d, Q_1d;
7362247a93fSRezgar Shakeri   CeedScalar       *interp_1d_pinv;
7371203703bSJeremy L Thompson   const CeedScalar *grad_1d, *interp_1d;
7381203703bSJeremy L Thompson 
739ea61e9acSJeremy L Thompson   // Note: This function is for backend use, so all errors are terminal and we do not need to clean up memory on failure.
7402247a93fSRezgar Shakeri   CeedCall(CeedBasisGetCeed(basis, &ceed));
7412247a93fSRezgar Shakeri   CeedCall(CeedBasisGetNumNodes1D(basis, &P_1d));
7422247a93fSRezgar Shakeri   CeedCall(CeedBasisGetNumQuadraturePoints1D(basis, &Q_1d));
7437a982d89SJeremy L. Thompson 
7442247a93fSRezgar Shakeri   // Compute interp_1d^+, pseudoinverse of interp_1d
7452247a93fSRezgar Shakeri   CeedCall(CeedCalloc(P_1d * Q_1d, &interp_1d_pinv));
7461203703bSJeremy L Thompson   CeedCall(CeedBasisGetInterp1D(basis, &interp_1d));
7471203703bSJeremy L Thompson   CeedCall(CeedMatrixPseudoinverse(ceed, interp_1d, Q_1d, P_1d, interp_1d_pinv));
7481203703bSJeremy L Thompson   CeedCall(CeedBasisGetGrad1D(basis, &grad_1d));
7491203703bSJeremy L Thompson   CeedCall(CeedMatrixMatrixMultiply(ceed, grad_1d, (const CeedScalar *)interp_1d_pinv, collo_grad_1d, Q_1d, Q_1d, P_1d));
7507a982d89SJeremy L. Thompson 
7512247a93fSRezgar Shakeri   CeedCall(CeedFree(&interp_1d_pinv));
7529bc66399SJeremy L Thompson   CeedCall(CeedDestroy(&ceed));
753e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
7547a982d89SJeremy L. Thompson }
7557a982d89SJeremy L. Thompson 
7567a982d89SJeremy L. Thompson /**
757b0cc4569SJeremy L Thompson   @brief Return 1D interpolation matrix to Chebyshev polynomial coefficients on quadrature space
758b0cc4569SJeremy L Thompson 
759b0cc4569SJeremy L Thompson   @param[in]  basis               `CeedBasis`
760b0cc4569SJeremy L Thompson   @param[out] chebyshev_interp_1d Row-major (`P_1d * Q_1d`) matrix interpolating from basis nodes to Chebyshev polynomial coefficients
761b0cc4569SJeremy L Thompson 
762b0cc4569SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
763b0cc4569SJeremy L Thompson 
764b0cc4569SJeremy L Thompson   @ref Backend
765b0cc4569SJeremy L Thompson **/
CeedBasisGetChebyshevInterp1D(CeedBasis basis,CeedScalar * chebyshev_interp_1d)766b0cc4569SJeremy L Thompson int CeedBasisGetChebyshevInterp1D(CeedBasis basis, CeedScalar *chebyshev_interp_1d) {
767b0cc4569SJeremy L Thompson   CeedInt           P_1d, Q_1d;
768b0cc4569SJeremy L Thompson   CeedScalar       *C, *chebyshev_coeffs_1d_inv;
769b0cc4569SJeremy L Thompson   const CeedScalar *interp_1d, *q_ref_1d;
770b0cc4569SJeremy L Thompson   Ceed              ceed;
771b0cc4569SJeremy L Thompson 
772b0cc4569SJeremy L Thompson   CeedCall(CeedBasisGetCeed(basis, &ceed));
773b0cc4569SJeremy L Thompson   CeedCall(CeedBasisGetNumNodes1D(basis, &P_1d));
774b0cc4569SJeremy L Thompson   CeedCall(CeedBasisGetNumQuadraturePoints1D(basis, &Q_1d));
775b0cc4569SJeremy L Thompson 
776b0cc4569SJeremy L Thompson   // Build coefficient matrix
777bd83cbc5SJeremy L Thompson   // -- Note: Clang-tidy needs this check
778bd83cbc5SJeremy L Thompson   CeedCheck((P_1d > 0) && (Q_1d > 0), ceed, CEED_ERROR_INCOMPATIBLE, "CeedBasis dimensions are malformed");
779b0cc4569SJeremy L Thompson   CeedCall(CeedCalloc(Q_1d * Q_1d, &C));
780b0cc4569SJeremy L Thompson   CeedCall(CeedBasisGetQRef(basis, &q_ref_1d));
781b0cc4569SJeremy L Thompson   for (CeedInt i = 0; i < Q_1d; i++) CeedCall(CeedChebyshevPolynomialsAtPoint(q_ref_1d[i], Q_1d, &C[i * Q_1d]));
782b0cc4569SJeremy L Thompson 
783b0cc4569SJeremy L Thompson   // Compute C^+, pseudoinverse of coefficient matrix
784b0cc4569SJeremy L Thompson   CeedCall(CeedCalloc(Q_1d * Q_1d, &chebyshev_coeffs_1d_inv));
785b0cc4569SJeremy L Thompson   CeedCall(CeedMatrixPseudoinverse(ceed, C, Q_1d, Q_1d, chebyshev_coeffs_1d_inv));
786b0cc4569SJeremy L Thompson 
787b0cc4569SJeremy L Thompson   // Build mapping from nodes to Chebyshev coefficients
788b0cc4569SJeremy L Thompson   CeedCall(CeedBasisGetInterp1D(basis, &interp_1d));
789b0cc4569SJeremy L Thompson   CeedCall(CeedMatrixMatrixMultiply(ceed, chebyshev_coeffs_1d_inv, interp_1d, chebyshev_interp_1d, Q_1d, P_1d, Q_1d));
790b0cc4569SJeremy L Thompson 
791b0cc4569SJeremy L Thompson   // Cleanup
792b0cc4569SJeremy L Thompson   CeedCall(CeedFree(&C));
793b0cc4569SJeremy L Thompson   CeedCall(CeedFree(&chebyshev_coeffs_1d_inv));
7949bc66399SJeremy L Thompson   CeedCall(CeedDestroy(&ceed));
795b0cc4569SJeremy L Thompson   return CEED_ERROR_SUCCESS;
796b0cc4569SJeremy L Thompson }
797b0cc4569SJeremy L Thompson 
798b0cc4569SJeremy L Thompson /**
799ca94c3ddSJeremy L Thompson   @brief Get tensor status for given `CeedBasis`
8007a982d89SJeremy L. Thompson 
801ca94c3ddSJeremy L Thompson   @param[in]  basis     `CeedBasis`
802d1d35e2fSjeremylt   @param[out] is_tensor Variable to store tensor status
8037a982d89SJeremy L. Thompson 
8047a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
8057a982d89SJeremy L. Thompson 
8067a982d89SJeremy L. Thompson   @ref Backend
8077a982d89SJeremy L. Thompson **/
CeedBasisIsTensor(CeedBasis basis,bool * is_tensor)808d1d35e2fSjeremylt int CeedBasisIsTensor(CeedBasis basis, bool *is_tensor) {
8096402da51SJeremy L Thompson   *is_tensor = basis->is_tensor_basis;
810e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
8117a982d89SJeremy L. Thompson }
8127a982d89SJeremy L. Thompson 
8137a982d89SJeremy L. Thompson /**
814ca62d558SJeremy L Thompson   @brief Determine if given `CeedBasis` has nodes collocated with quadrature points
815ca62d558SJeremy L Thompson 
816ca62d558SJeremy L Thompson   @param[in]  basis         `CeedBasis`
817aa4b4a9fSJeremy L Thompson   @param[out] is_collocated Variable to store collocated status
818ca62d558SJeremy L Thompson 
819ca62d558SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
820ca62d558SJeremy L Thompson 
821ca62d558SJeremy L Thompson   @ref Backend
822ca62d558SJeremy L Thompson **/
CeedBasisIsCollocated(CeedBasis basis,bool * is_collocated)823ca62d558SJeremy L Thompson int CeedBasisIsCollocated(CeedBasis basis, bool *is_collocated) {
824ca62d558SJeremy L Thompson   if (basis->is_tensor_basis && (basis->Q_1d == basis->P_1d)) {
825ca62d558SJeremy L Thompson     *is_collocated = true;
826ca62d558SJeremy L Thompson 
827ca62d558SJeremy L Thompson     for (CeedInt i = 0; i < basis->P_1d; i++) {
828ca62d558SJeremy L Thompson       *is_collocated = *is_collocated && (fabs(basis->interp_1d[i + basis->P_1d * i] - 1.0) < 10 * CEED_EPSILON);
829ca62d558SJeremy L Thompson       for (CeedInt j = 0; j < basis->Q_1d; j++) {
830ca62d558SJeremy L Thompson         if (j != i) *is_collocated = *is_collocated && (fabs(basis->interp_1d[j + basis->P_1d * i]) < 10 * CEED_EPSILON);
831ca62d558SJeremy L Thompson       }
832ca62d558SJeremy L Thompson     }
833ca62d558SJeremy L Thompson   } else {
834ca62d558SJeremy L Thompson     *is_collocated = false;
835ca62d558SJeremy L Thompson   }
836ca62d558SJeremy L Thompson   return CEED_ERROR_SUCCESS;
837ca62d558SJeremy L Thompson }
838ca62d558SJeremy L Thompson 
839ca62d558SJeremy L Thompson /**
840ca94c3ddSJeremy L Thompson   @brief Get backend data of a `CeedBasis`
8417a982d89SJeremy L. Thompson 
842ca94c3ddSJeremy L Thompson   @param[in]  basis `CeedBasis`
8437a982d89SJeremy L. Thompson   @param[out] data  Variable to store data
8447a982d89SJeremy L. Thompson 
8457a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
8467a982d89SJeremy L. Thompson 
8477a982d89SJeremy L. Thompson   @ref Backend
8487a982d89SJeremy L. Thompson **/
CeedBasisGetData(CeedBasis basis,void * data)849777ff853SJeremy L Thompson int CeedBasisGetData(CeedBasis basis, void *data) {
850777ff853SJeremy L Thompson   *(void **)data = basis->data;
851e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
8527a982d89SJeremy L. Thompson }
8537a982d89SJeremy L. Thompson 
8547a982d89SJeremy L. Thompson /**
855ca94c3ddSJeremy L Thompson   @brief Set backend data of a `CeedBasis`
8567a982d89SJeremy L. Thompson 
857ca94c3ddSJeremy L Thompson   @param[in,out] basis  `CeedBasis`
858ea61e9acSJeremy L Thompson   @param[in]     data   Data to set
8597a982d89SJeremy L. Thompson 
8607a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
8617a982d89SJeremy L. Thompson 
8627a982d89SJeremy L. Thompson   @ref Backend
8637a982d89SJeremy L. Thompson **/
CeedBasisSetData(CeedBasis basis,void * data)864777ff853SJeremy L Thompson int CeedBasisSetData(CeedBasis basis, void *data) {
865777ff853SJeremy L Thompson   basis->data = data;
866e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
8677a982d89SJeremy L. Thompson }
8687a982d89SJeremy L. Thompson 
8697a982d89SJeremy L. Thompson /**
870ca94c3ddSJeremy L Thompson   @brief Increment the reference counter for a `CeedBasis`
87134359f16Sjeremylt 
872ca94c3ddSJeremy L Thompson   @param[in,out] basis `CeedBasis` to increment the reference counter
87334359f16Sjeremylt 
87434359f16Sjeremylt   @return An error code: 0 - success, otherwise - failure
87534359f16Sjeremylt 
87634359f16Sjeremylt   @ref Backend
87734359f16Sjeremylt **/
CeedBasisReference(CeedBasis basis)8789560d06aSjeremylt int CeedBasisReference(CeedBasis basis) {
879b0f67a9cSJeremy L Thompson   CeedCall(CeedObjectReference((CeedObject)basis));
88034359f16Sjeremylt   return CEED_ERROR_SUCCESS;
88134359f16Sjeremylt }
88234359f16Sjeremylt 
88334359f16Sjeremylt /**
884ca94c3ddSJeremy L Thompson   @brief Get number of Q-vector components for given `CeedBasis`
885c4e3f59bSSebastian Grimberg 
886ca94c3ddSJeremy L Thompson   @param[in]  basis     `CeedBasis`
887ca94c3ddSJeremy L Thompson   @param[in]  eval_mode @ref CEED_EVAL_INTERP to use interpolated values,
888ca94c3ddSJeremy L Thompson                           @ref CEED_EVAL_GRAD to use gradients,
889ca94c3ddSJeremy L Thompson                           @ref CEED_EVAL_DIV to use divergence,
890ca94c3ddSJeremy L Thompson                           @ref CEED_EVAL_CURL to use curl
891c4e3f59bSSebastian Grimberg   @param[out] q_comp    Variable to store number of Q-vector components of basis
892c4e3f59bSSebastian Grimberg 
893c4e3f59bSSebastian Grimberg   @return An error code: 0 - success, otherwise - failure
894c4e3f59bSSebastian Grimberg 
895c4e3f59bSSebastian Grimberg   @ref Backend
896c4e3f59bSSebastian Grimberg **/
CeedBasisGetNumQuadratureComponents(CeedBasis basis,CeedEvalMode eval_mode,CeedInt * q_comp)897c4e3f59bSSebastian Grimberg int CeedBasisGetNumQuadratureComponents(CeedBasis basis, CeedEvalMode eval_mode, CeedInt *q_comp) {
8981203703bSJeremy L Thompson   CeedInt dim;
8991203703bSJeremy L Thompson 
9001203703bSJeremy L Thompson   CeedCall(CeedBasisGetDimension(basis, &dim));
901c4e3f59bSSebastian Grimberg   switch (eval_mode) {
9021203703bSJeremy L Thompson     case CEED_EVAL_INTERP: {
9031203703bSJeremy L Thompson       CeedFESpace fe_space;
9041203703bSJeremy L Thompson 
9051203703bSJeremy L Thompson       CeedCall(CeedBasisGetFESpace(basis, &fe_space));
9061203703bSJeremy L Thompson       *q_comp = (fe_space == CEED_FE_SPACE_H1) ? 1 : dim;
9071203703bSJeremy L Thompson     } break;
908c4e3f59bSSebastian Grimberg     case CEED_EVAL_GRAD:
9091203703bSJeremy L Thompson       *q_comp = dim;
910c4e3f59bSSebastian Grimberg       break;
911c4e3f59bSSebastian Grimberg     case CEED_EVAL_DIV:
912c4e3f59bSSebastian Grimberg       *q_comp = 1;
913c4e3f59bSSebastian Grimberg       break;
914c4e3f59bSSebastian Grimberg     case CEED_EVAL_CURL:
9151203703bSJeremy L Thompson       *q_comp = (dim < 3) ? 1 : dim;
916c4e3f59bSSebastian Grimberg       break;
917c4e3f59bSSebastian Grimberg     case CEED_EVAL_NONE:
918c4e3f59bSSebastian Grimberg     case CEED_EVAL_WEIGHT:
919352a5e7cSSebastian Grimberg       *q_comp = 1;
920c4e3f59bSSebastian Grimberg       break;
921c4e3f59bSSebastian Grimberg   }
922c4e3f59bSSebastian Grimberg   return CEED_ERROR_SUCCESS;
923c4e3f59bSSebastian Grimberg }
924c4e3f59bSSebastian Grimberg 
925c4e3f59bSSebastian Grimberg /**
926ca94c3ddSJeremy L Thompson   @brief Estimate number of FLOPs required to apply `CeedBasis` in `t_mode` and `eval_mode`
9276e15d496SJeremy L Thompson 
928ca94c3ddSJeremy L Thompson   @param[in]  basis        `CeedBasis` to estimate FLOPs for
929ea61e9acSJeremy L Thompson   @param[in]  t_mode       Apply basis or transpose
930ca94c3ddSJeremy L Thompson   @param[in]  eval_mode    @ref CeedEvalMode
9313f919cbcSJeremy L Thompson   @param[in]  is_at_points Evaluate the basis at points or quadrature points
9323f919cbcSJeremy L Thompson   @param[in]  num_points   Number of points basis is evaluated at
933ea61e9acSJeremy L Thompson   @param[out] flops        Address of variable to hold FLOPs estimate
9346e15d496SJeremy L Thompson 
9356e15d496SJeremy L Thompson   @ref Backend
9366e15d496SJeremy L Thompson **/
CeedBasisGetFlopsEstimate(CeedBasis basis,CeedTransposeMode t_mode,CeedEvalMode eval_mode,bool is_at_points,CeedInt num_points,CeedSize * flops)9373f919cbcSJeremy L Thompson int CeedBasisGetFlopsEstimate(CeedBasis basis, CeedTransposeMode t_mode, CeedEvalMode eval_mode, bool is_at_points, CeedInt num_points,
9383f919cbcSJeremy L Thompson                               CeedSize *flops) {
9396e15d496SJeremy L Thompson   bool is_tensor;
9406e15d496SJeremy L Thompson 
9412b730f8bSJeremy L Thompson   CeedCall(CeedBasisIsTensor(basis, &is_tensor));
9423f919cbcSJeremy L Thompson   CeedCheck(!is_at_points || is_tensor, CeedBasisReturnCeed(basis), CEED_ERROR_INCOMPATIBLE, "Can only evaluate tensor-product bases at points");
9436e15d496SJeremy L Thompson   if (is_tensor) {
9446e15d496SJeremy L Thompson     CeedInt dim, num_comp, P_1d, Q_1d;
9451c66c397SJeremy L Thompson 
9462b730f8bSJeremy L Thompson     CeedCall(CeedBasisGetDimension(basis, &dim));
9472b730f8bSJeremy L Thompson     CeedCall(CeedBasisGetNumComponents(basis, &num_comp));
9482b730f8bSJeremy L Thompson     CeedCall(CeedBasisGetNumNodes1D(basis, &P_1d));
9492b730f8bSJeremy L Thompson     CeedCall(CeedBasisGetNumQuadraturePoints1D(basis, &Q_1d));
9506e15d496SJeremy L Thompson     if (t_mode == CEED_TRANSPOSE) {
9512b730f8bSJeremy L Thompson       P_1d = Q_1d;
9522b730f8bSJeremy L Thompson       Q_1d = P_1d;
9536e15d496SJeremy L Thompson     }
9546e15d496SJeremy L Thompson     CeedInt tensor_flops = 0, pre = num_comp * CeedIntPow(P_1d, dim - 1), post = 1;
9553f919cbcSJeremy L Thompson 
9566e15d496SJeremy L Thompson     for (CeedInt d = 0; d < dim; d++) {
9576e15d496SJeremy L Thompson       tensor_flops += 2 * pre * P_1d * post * Q_1d;
9586e15d496SJeremy L Thompson       pre /= P_1d;
9596e15d496SJeremy L Thompson       post *= Q_1d;
9606e15d496SJeremy L Thompson     }
9613f919cbcSJeremy L Thompson     if (is_at_points) {
96252780386SJeremy L Thompson       bool is_gpu = false;
96352780386SJeremy L Thompson 
96452780386SJeremy L Thompson       {
96552780386SJeremy L Thompson         CeedMemType mem_type;
96652780386SJeremy L Thompson 
96752780386SJeremy L Thompson         CeedCall(CeedGetPreferredMemType(CeedBasisReturnCeed(basis), &mem_type));
96852780386SJeremy L Thompson         is_gpu = mem_type == CEED_MEM_DEVICE;
96952780386SJeremy L Thompson       }
97052780386SJeremy L Thompson 
9713f919cbcSJeremy L Thompson       CeedInt chebyshev_flops = (Q_1d - 2) * 3 + 1, d_chebyshev_flops = (Q_1d - 2) * 8 + 1;
9723f919cbcSJeremy L Thompson       CeedInt point_tensor_flops = 0, pre = CeedIntPow(Q_1d, dim - 1), post = 1;
9733f919cbcSJeremy L Thompson 
9743f919cbcSJeremy L Thompson       for (CeedInt d = 0; d < dim; d++) {
9753f919cbcSJeremy L Thompson         point_tensor_flops += 2 * pre * Q_1d * post * 1;
9763f919cbcSJeremy L Thompson         pre /= P_1d;
9773f919cbcSJeremy L Thompson         post *= Q_1d;
9783f919cbcSJeremy L Thompson       }
9793f919cbcSJeremy L Thompson 
9803f919cbcSJeremy L Thompson       switch (eval_mode) {
9813f919cbcSJeremy L Thompson         case CEED_EVAL_NONE:
9823f919cbcSJeremy L Thompson           *flops = 0;
9833f919cbcSJeremy L Thompson           break;
984a82cd097SZach Atkins         case CEED_EVAL_INTERP: {
985a82cd097SZach Atkins           *flops = tensor_flops + num_points * num_comp * (point_tensor_flops + (t_mode == CEED_TRANSPOSE ? CeedIntPow(Q_1d, dim) : 0));
986a82cd097SZach Atkins           if (dim == 3 && is_gpu) {
987802d760aSJeremy L Thompson             *flops += num_points * Q_1d *
988802d760aSJeremy L Thompson                       (chebyshev_flops + num_comp * (2 * chebyshev_flops + 2 * Q_1d * Q_1d + (t_mode == CEED_TRANSPOSE ? 2 * Q_1d + 1 : 3 * Q_1d)));
989a82cd097SZach Atkins           } else {
990a82cd097SZach Atkins             *flops += num_points * (is_gpu ? num_comp : 1) * dim * chebyshev_flops;
991a82cd097SZach Atkins           }
9923f919cbcSJeremy L Thompson           break;
993a82cd097SZach Atkins         }
994a82cd097SZach Atkins         case CEED_EVAL_GRAD: {
995a82cd097SZach Atkins           *flops = tensor_flops + num_points * num_comp * (point_tensor_flops + (t_mode == CEED_TRANSPOSE ? CeedIntPow(Q_1d, dim) : 0));
996a82cd097SZach Atkins           if (dim == 3 && is_gpu) {
997802d760aSJeremy L Thompson             CeedInt inner_flops =
998dc7b9553SJeremy L Thompson                 dim * (2 * Q_1d * Q_1d + (t_mode == CEED_TRANSPOSE ? 2 : 3) * Q_1d) + (dim - 1) * (2 * chebyshev_flops + d_chebyshev_flops);
999802d760aSJeremy L Thompson 
100027a8a650SZach Atkins             *flops += num_points * Q_1d * (chebyshev_flops + d_chebyshev_flops + num_comp * (inner_flops + (t_mode == CEED_TRANSPOSE ? 1 : 0)));
1001a82cd097SZach Atkins           } else {
1002a82cd097SZach Atkins             *flops += num_points * (is_gpu ? num_comp : 1) * dim * (d_chebyshev_flops + (dim - 1) * chebyshev_flops);
1003a82cd097SZach Atkins           }
10043f919cbcSJeremy L Thompson           break;
1005a82cd097SZach Atkins         }
10063f919cbcSJeremy L Thompson         case CEED_EVAL_DIV:
10073f919cbcSJeremy L Thompson         case CEED_EVAL_CURL: {
10083f919cbcSJeremy L Thompson           // LCOV_EXCL_START
100952780386SJeremy L Thompson           return CeedError(CeedBasisReturnCeed(basis), CEED_ERROR_INCOMPATIBLE, "Tensor basis evaluation for %s not supported at points",
10103f919cbcSJeremy L Thompson                            CeedEvalModes[eval_mode]);
10113f919cbcSJeremy L Thompson           break;
10123f919cbcSJeremy L Thompson           // LCOV_EXCL_STOP
10133f919cbcSJeremy L Thompson         }
10143f919cbcSJeremy L Thompson         case CEED_EVAL_WEIGHT:
10153f919cbcSJeremy L Thompson           *flops = num_points;
10163f919cbcSJeremy L Thompson           break;
10173f919cbcSJeremy L Thompson       }
10183f919cbcSJeremy L Thompson     } else {
10196e15d496SJeremy L Thompson       switch (eval_mode) {
10202b730f8bSJeremy L Thompson         case CEED_EVAL_NONE:
10212b730f8bSJeremy L Thompson           *flops = 0;
10222b730f8bSJeremy L Thompson           break;
10232b730f8bSJeremy L Thompson         case CEED_EVAL_INTERP:
10242b730f8bSJeremy L Thompson           *flops = tensor_flops;
10252b730f8bSJeremy L Thompson           break;
10262b730f8bSJeremy L Thompson         case CEED_EVAL_GRAD:
10272b730f8bSJeremy L Thompson           *flops = tensor_flops * 2;
10282b730f8bSJeremy L Thompson           break;
10296e15d496SJeremy L Thompson         case CEED_EVAL_DIV:
10301203703bSJeremy L Thompson         case CEED_EVAL_CURL: {
10316574a04fSJeremy L Thompson           // LCOV_EXCL_START
10326e536b99SJeremy L Thompson           return CeedError(CeedBasisReturnCeed(basis), CEED_ERROR_INCOMPATIBLE, "Tensor basis evaluation for %s not supported",
10336e536b99SJeremy L Thompson                            CeedEvalModes[eval_mode]);
10342b730f8bSJeremy L Thompson           break;
10356e15d496SJeremy L Thompson           // LCOV_EXCL_STOP
10361203703bSJeremy L Thompson         }
10372b730f8bSJeremy L Thompson         case CEED_EVAL_WEIGHT:
10382b730f8bSJeremy L Thompson           *flops = dim * CeedIntPow(Q_1d, dim);
10392b730f8bSJeremy L Thompson           break;
10406e15d496SJeremy L Thompson       }
10413f919cbcSJeremy L Thompson     }
10426e15d496SJeremy L Thompson   } else {
1043c4e3f59bSSebastian Grimberg     CeedInt dim, num_comp, q_comp, num_nodes, num_qpts;
10441c66c397SJeremy L Thompson 
10452b730f8bSJeremy L Thompson     CeedCall(CeedBasisGetDimension(basis, &dim));
10462b730f8bSJeremy L Thompson     CeedCall(CeedBasisGetNumComponents(basis, &num_comp));
1047c4e3f59bSSebastian Grimberg     CeedCall(CeedBasisGetNumQuadratureComponents(basis, eval_mode, &q_comp));
10482b730f8bSJeremy L Thompson     CeedCall(CeedBasisGetNumNodes(basis, &num_nodes));
10492b730f8bSJeremy L Thompson     CeedCall(CeedBasisGetNumQuadraturePoints(basis, &num_qpts));
10506e15d496SJeremy L Thompson     switch (eval_mode) {
10512b730f8bSJeremy L Thompson       case CEED_EVAL_NONE:
10522b730f8bSJeremy L Thompson         *flops = 0;
10532b730f8bSJeremy L Thompson         break;
10542b730f8bSJeremy L Thompson       case CEED_EVAL_INTERP:
10552b730f8bSJeremy L Thompson       case CEED_EVAL_GRAD:
10562b730f8bSJeremy L Thompson       case CEED_EVAL_DIV:
10572b730f8bSJeremy L Thompson       case CEED_EVAL_CURL:
1058c4e3f59bSSebastian Grimberg         *flops = num_nodes * num_qpts * num_comp * q_comp;
10592b730f8bSJeremy L Thompson         break;
10602b730f8bSJeremy L Thompson       case CEED_EVAL_WEIGHT:
10612b730f8bSJeremy L Thompson         *flops = 0;
10622b730f8bSJeremy L Thompson         break;
10636e15d496SJeremy L Thompson     }
10646e15d496SJeremy L Thompson   }
10656e15d496SJeremy L Thompson   return CEED_ERROR_SUCCESS;
10666e15d496SJeremy L Thompson }
10676e15d496SJeremy L Thompson 
10686e15d496SJeremy L Thompson /**
1069ca94c3ddSJeremy L Thompson   @brief Get `CeedFESpace` for a `CeedBasis`
1070c4e3f59bSSebastian Grimberg 
1071ca94c3ddSJeremy L Thompson   @param[in]  basis    `CeedBasis`
1072ca94c3ddSJeremy L Thompson   @param[out] fe_space Variable to store `CeedFESpace`
1073c4e3f59bSSebastian Grimberg 
1074c4e3f59bSSebastian Grimberg   @return An error code: 0 - success, otherwise - failure
1075c4e3f59bSSebastian Grimberg 
1076c4e3f59bSSebastian Grimberg   @ref Backend
1077c4e3f59bSSebastian Grimberg **/
CeedBasisGetFESpace(CeedBasis basis,CeedFESpace * fe_space)1078c4e3f59bSSebastian Grimberg int CeedBasisGetFESpace(CeedBasis basis, CeedFESpace *fe_space) {
1079c4e3f59bSSebastian Grimberg   *fe_space = basis->fe_space;
1080c4e3f59bSSebastian Grimberg   return CEED_ERROR_SUCCESS;
1081c4e3f59bSSebastian Grimberg }
1082c4e3f59bSSebastian Grimberg 
1083c4e3f59bSSebastian Grimberg /**
1084ca94c3ddSJeremy L Thompson   @brief Get dimension for given `CeedElemTopology`
10857a982d89SJeremy L. Thompson 
1086ca94c3ddSJeremy L Thompson   @param[in]  topo `CeedElemTopology`
10877a982d89SJeremy L. Thompson   @param[out] dim  Variable to store dimension of topology
10887a982d89SJeremy L. Thompson 
10897a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
10907a982d89SJeremy L. Thompson 
10917a982d89SJeremy L. Thompson   @ref Backend
10927a982d89SJeremy L. Thompson **/
CeedBasisGetTopologyDimension(CeedElemTopology topo,CeedInt * dim)10937a982d89SJeremy L. Thompson int CeedBasisGetTopologyDimension(CeedElemTopology topo, CeedInt *dim) {
10947a982d89SJeremy L. Thompson   *dim = (CeedInt)topo >> 16;
1095e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
10967a982d89SJeremy L. Thompson }
10977a982d89SJeremy L. Thompson 
10987a982d89SJeremy L. Thompson /**
1099ca94c3ddSJeremy L Thompson   @brief Get `CeedTensorContract` of a `CeedBasis`
11007a982d89SJeremy L. Thompson 
1101ca94c3ddSJeremy L Thompson   @param[in]  basis     `CeedBasis`
1102ca94c3ddSJeremy L Thompson   @param[out] contract  Variable to store `CeedTensorContract`
11037a982d89SJeremy L. Thompson 
11047a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
11057a982d89SJeremy L. Thompson 
11067a982d89SJeremy L. Thompson   @ref Backend
11077a982d89SJeremy L. Thompson **/
CeedBasisGetTensorContract(CeedBasis basis,CeedTensorContract * contract)11087a982d89SJeremy L. Thompson int CeedBasisGetTensorContract(CeedBasis basis, CeedTensorContract *contract) {
11097a982d89SJeremy L. Thompson   *contract = basis->contract;
1110e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
11117a982d89SJeremy L. Thompson }
11127a982d89SJeremy L. Thompson 
11137a982d89SJeremy L. Thompson /**
1114ca94c3ddSJeremy L Thompson   @brief Set `CeedTensorContract` of a `CeedBasis`
11157a982d89SJeremy L. Thompson 
1116ca94c3ddSJeremy L Thompson   @param[in,out] basis    `CeedBasis`
1117ca94c3ddSJeremy L Thompson   @param[in]     contract `CeedTensorContract` to set
11187a982d89SJeremy L. Thompson 
11197a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
11207a982d89SJeremy L. Thompson 
11217a982d89SJeremy L. Thompson   @ref Backend
11227a982d89SJeremy L. Thompson **/
CeedBasisSetTensorContract(CeedBasis basis,CeedTensorContract contract)112334359f16Sjeremylt int CeedBasisSetTensorContract(CeedBasis basis, CeedTensorContract contract) {
112434359f16Sjeremylt   basis->contract = contract;
11252b730f8bSJeremy L Thompson   CeedCall(CeedTensorContractReference(contract));
1126e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
11277a982d89SJeremy L. Thompson }
11287a982d89SJeremy L. Thompson 
11297a982d89SJeremy L. Thompson /**
1130ca94c3ddSJeremy L Thompson   @brief Return a reference implementation of matrix multiplication \f$C = A B\f$.
1131ba59ac12SSebastian Grimberg 
1132ca94c3ddSJeremy L Thompson   Note: This is a reference implementation for CPU `CeedScalar` pointers that is not intended for high performance.
11337a982d89SJeremy L. Thompson 
1134ca94c3ddSJeremy L Thompson   @param[in]  ceed  `Ceed` context for error handling
1135ca94c3ddSJeremy L Thompson   @param[in]  mat_A Row-major matrix `A`
1136ca94c3ddSJeremy L Thompson   @param[in]  mat_B Row-major matrix `B`
1137ca94c3ddSJeremy L Thompson   @param[out] mat_C Row-major output matrix `C`
1138ca94c3ddSJeremy L Thompson   @param[in]  m     Number of rows of `C`
1139ca94c3ddSJeremy L Thompson   @param[in]  n     Number of columns of `C`
1140ca94c3ddSJeremy L Thompson   @param[in]  kk    Number of columns of `A`/rows of `B`
11417a982d89SJeremy L. Thompson 
11427a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
11437a982d89SJeremy L. Thompson 
11447a982d89SJeremy L. Thompson   @ref Utility
11457a982d89SJeremy L. Thompson **/
CeedMatrixMatrixMultiply(Ceed ceed,const CeedScalar * mat_A,const CeedScalar * mat_B,CeedScalar * mat_C,CeedInt m,CeedInt n,CeedInt kk)11462b730f8bSJeremy L Thompson int CeedMatrixMatrixMultiply(Ceed ceed, const CeedScalar *mat_A, const CeedScalar *mat_B, CeedScalar *mat_C, CeedInt m, CeedInt n, CeedInt kk) {
11472b730f8bSJeremy L Thompson   for (CeedInt i = 0; i < m; i++) {
11487a982d89SJeremy L. Thompson     for (CeedInt j = 0; j < n; j++) {
11497a982d89SJeremy L. Thompson       CeedScalar sum = 0;
11501c66c397SJeremy L Thompson 
11512b730f8bSJeremy L Thompson       for (CeedInt k = 0; k < kk; k++) sum += mat_A[k + i * kk] * mat_B[j + k * n];
1152d1d35e2fSjeremylt       mat_C[j + i * n] = sum;
11537a982d89SJeremy L. Thompson     }
11542b730f8bSJeremy L Thompson   }
1155e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
11567a982d89SJeremy L. Thompson }
11577a982d89SJeremy L. Thompson 
1158ba59ac12SSebastian Grimberg /**
1159ba59ac12SSebastian Grimberg   @brief Return QR Factorization of a matrix
1160ba59ac12SSebastian Grimberg 
1161ca94c3ddSJeremy L Thompson   @param[in]     ceed `Ceed` context for error handling
1162ba59ac12SSebastian Grimberg   @param[in,out] mat  Row-major matrix to be factorized in place
1163ca94c3ddSJeremy L Thompson   @param[in,out] tau  Vector of length `m` of scaling factors
1164ba59ac12SSebastian Grimberg   @param[in]     m    Number of rows
1165ba59ac12SSebastian Grimberg   @param[in]     n    Number of columns
1166ba59ac12SSebastian Grimberg 
1167ba59ac12SSebastian Grimberg   @return An error code: 0 - success, otherwise - failure
1168ba59ac12SSebastian Grimberg 
1169ba59ac12SSebastian Grimberg   @ref Utility
1170ba59ac12SSebastian Grimberg **/
CeedQRFactorization(Ceed ceed,CeedScalar * mat,CeedScalar * tau,CeedInt m,CeedInt n)1171ba59ac12SSebastian Grimberg int CeedQRFactorization(Ceed ceed, CeedScalar *mat, CeedScalar *tau, CeedInt m, CeedInt n) {
1172ba59ac12SSebastian Grimberg   CeedScalar v[m];
1173ba59ac12SSebastian Grimberg 
1174ba59ac12SSebastian Grimberg   // Check matrix shape
11756574a04fSJeremy L Thompson   CeedCheck(n <= m, ceed, CEED_ERROR_UNSUPPORTED, "Cannot compute QR factorization with n > m");
1176ba59ac12SSebastian Grimberg 
1177ba59ac12SSebastian Grimberg   for (CeedInt i = 0; i < n; i++) {
11781c66c397SJeremy L Thompson     CeedScalar sigma = 0.0;
11791c66c397SJeremy L Thompson 
1180ba59ac12SSebastian Grimberg     if (i >= m - 1) {  // last row of matrix, no reflection needed
1181ba59ac12SSebastian Grimberg       tau[i] = 0.;
1182ba59ac12SSebastian Grimberg       break;
1183ba59ac12SSebastian Grimberg     }
1184ba59ac12SSebastian Grimberg     // Calculate Householder vector, magnitude
1185ba59ac12SSebastian Grimberg     v[i] = mat[i + n * i];
1186ba59ac12SSebastian Grimberg     for (CeedInt j = i + 1; j < m; j++) {
1187ba59ac12SSebastian Grimberg       v[j] = mat[i + n * j];
1188ba59ac12SSebastian Grimberg       sigma += v[j] * v[j];
1189ba59ac12SSebastian Grimberg     }
11901c66c397SJeremy L Thompson     const CeedScalar norm = sqrt(v[i] * v[i] + sigma);  // norm of v[i:m]
11911c66c397SJeremy L Thompson     const CeedScalar R_ii = -copysign(norm, v[i]);
11921c66c397SJeremy L Thompson 
1193ba59ac12SSebastian Grimberg     v[i] -= R_ii;
1194ba59ac12SSebastian Grimberg     // norm of v[i:m] after modification above and scaling below
1195ba59ac12SSebastian Grimberg     //   norm = sqrt(v[i]*v[i] + sigma) / v[i];
1196ba59ac12SSebastian Grimberg     //   tau = 2 / (norm*norm)
1197ba59ac12SSebastian Grimberg     tau[i] = 2 * v[i] * v[i] / (v[i] * v[i] + sigma);
1198ba59ac12SSebastian Grimberg     for (CeedInt j = i + 1; j < m; j++) v[j] /= v[i];
1199ba59ac12SSebastian Grimberg 
1200ba59ac12SSebastian Grimberg     // Apply Householder reflector to lower right panel
1201ba59ac12SSebastian Grimberg     CeedHouseholderReflect(&mat[i * n + i + 1], &v[i], tau[i], m - i, n - i - 1, n, 1);
1202ba59ac12SSebastian Grimberg     // Save v
1203ba59ac12SSebastian Grimberg     mat[i + n * i] = R_ii;
1204ba59ac12SSebastian Grimberg     for (CeedInt j = i + 1; j < m; j++) mat[i + n * j] = v[j];
1205ba59ac12SSebastian Grimberg   }
1206ba59ac12SSebastian Grimberg   return CEED_ERROR_SUCCESS;
1207ba59ac12SSebastian Grimberg }
1208ba59ac12SSebastian Grimberg 
1209ba59ac12SSebastian Grimberg /**
1210ba59ac12SSebastian Grimberg   @brief Apply Householder Q matrix
1211ba59ac12SSebastian Grimberg 
1212ca94c3ddSJeremy L Thompson   Compute `mat_A = mat_Q mat_A`, where `mat_Q` is \f$m \times m\f$ and `mat_A` is \f$m \times n\f$.
1213ba59ac12SSebastian Grimberg 
1214ba59ac12SSebastian Grimberg   @param[in,out] mat_A  Matrix to apply Householder Q to, in place
1215ba59ac12SSebastian Grimberg   @param[in]     mat_Q  Householder Q matrix
1216ba59ac12SSebastian Grimberg   @param[in]     tau    Householder scaling factors
1217ba59ac12SSebastian Grimberg   @param[in]     t_mode Transpose mode for application
1218ca94c3ddSJeremy L Thompson   @param[in]     m      Number of rows in `A`
1219ca94c3ddSJeremy L Thompson   @param[in]     n      Number of columns in `A`
1220ca94c3ddSJeremy L Thompson   @param[in]     k      Number of elementary reflectors in Q, `k < m`
1221ca94c3ddSJeremy L Thompson   @param[in]     row    Row stride in `A`
1222ca94c3ddSJeremy L Thompson   @param[in]     col    Col stride in `A`
1223ba59ac12SSebastian Grimberg 
1224ba59ac12SSebastian Grimberg   @return An error code: 0 - success, otherwise - failure
1225ba59ac12SSebastian Grimberg 
1226c4e3f59bSSebastian Grimberg   @ref Utility
1227ba59ac12SSebastian Grimberg **/
CeedHouseholderApplyQ(CeedScalar * mat_A,const CeedScalar * mat_Q,const CeedScalar * tau,CeedTransposeMode t_mode,CeedInt m,CeedInt n,CeedInt k,CeedInt row,CeedInt col)1228ba59ac12SSebastian Grimberg int CeedHouseholderApplyQ(CeedScalar *mat_A, const CeedScalar *mat_Q, const CeedScalar *tau, CeedTransposeMode t_mode, CeedInt m, CeedInt n,
1229ba59ac12SSebastian Grimberg                           CeedInt k, CeedInt row, CeedInt col) {
1230ba59ac12SSebastian Grimberg   CeedScalar *v;
12311c66c397SJeremy L Thompson 
1232ba59ac12SSebastian Grimberg   CeedCall(CeedMalloc(m, &v));
1233ba59ac12SSebastian Grimberg   for (CeedInt ii = 0; ii < k; ii++) {
1234ba59ac12SSebastian Grimberg     CeedInt i = t_mode == CEED_TRANSPOSE ? ii : k - 1 - ii;
1235ba59ac12SSebastian Grimberg     for (CeedInt j = i + 1; j < m; j++) v[j] = mat_Q[j * k + i];
1236ba59ac12SSebastian Grimberg     // Apply Householder reflector (I - tau v v^T) collo_grad_1d^T
1237ba59ac12SSebastian Grimberg     CeedCall(CeedHouseholderReflect(&mat_A[i * row], &v[i], tau[i], m - i, n, row, col));
1238ba59ac12SSebastian Grimberg   }
1239ba59ac12SSebastian Grimberg   CeedCall(CeedFree(&v));
1240ba59ac12SSebastian Grimberg   return CEED_ERROR_SUCCESS;
1241ba59ac12SSebastian Grimberg }
1242ba59ac12SSebastian Grimberg 
1243ba59ac12SSebastian Grimberg /**
12442247a93fSRezgar Shakeri   @brief Return pseudoinverse of a matrix
12452247a93fSRezgar Shakeri 
12462247a93fSRezgar Shakeri   @param[in]     ceed      Ceed context for error handling
12472247a93fSRezgar Shakeri   @param[in]     mat       Row-major matrix to compute pseudoinverse of
12482247a93fSRezgar Shakeri   @param[in]     m         Number of rows
12492247a93fSRezgar Shakeri   @param[in]     n         Number of columns
12502247a93fSRezgar Shakeri   @param[out]    mat_pinv  Row-major pseudoinverse matrix
12512247a93fSRezgar Shakeri 
12522247a93fSRezgar Shakeri   @return An error code: 0 - success, otherwise - failure
12532247a93fSRezgar Shakeri 
12542247a93fSRezgar Shakeri   @ref Utility
12552247a93fSRezgar Shakeri **/
CeedMatrixPseudoinverse(Ceed ceed,const CeedScalar * mat,CeedInt m,CeedInt n,CeedScalar * mat_pinv)12561203703bSJeremy L Thompson int CeedMatrixPseudoinverse(Ceed ceed, const CeedScalar *mat, CeedInt m, CeedInt n, CeedScalar *mat_pinv) {
12572247a93fSRezgar Shakeri   CeedScalar *tau, *I, *mat_copy;
12582247a93fSRezgar Shakeri 
12592247a93fSRezgar Shakeri   CeedCall(CeedCalloc(m, &tau));
12602247a93fSRezgar Shakeri   CeedCall(CeedCalloc(m * m, &I));
12612247a93fSRezgar Shakeri   CeedCall(CeedCalloc(m * n, &mat_copy));
12622247a93fSRezgar Shakeri   memcpy(mat_copy, mat, m * n * sizeof mat[0]);
12632247a93fSRezgar Shakeri 
12642247a93fSRezgar Shakeri   // QR Factorization, mat = Q R
12652247a93fSRezgar Shakeri   CeedCall(CeedQRFactorization(ceed, mat_copy, tau, m, n));
12662247a93fSRezgar Shakeri 
12672247a93fSRezgar Shakeri   // -- Apply Q^T, I = Q^T * I
12682247a93fSRezgar Shakeri   for (CeedInt i = 0; i < m; i++) I[i * m + i] = 1.0;
12692247a93fSRezgar Shakeri   CeedCall(CeedHouseholderApplyQ(I, mat_copy, tau, CEED_TRANSPOSE, m, m, n, m, 1));
12702247a93fSRezgar Shakeri   // -- Apply R_inv, mat_pinv = R_inv * Q^T
12712247a93fSRezgar Shakeri   for (CeedInt j = 0; j < m; j++) {  // Column j
12722247a93fSRezgar Shakeri     mat_pinv[j + m * (n - 1)] = I[j + m * (n - 1)] / mat_copy[n * n - 1];
12732247a93fSRezgar Shakeri     for (CeedInt i = n - 2; i >= 0; i--) {  // Row i
12742247a93fSRezgar Shakeri       mat_pinv[j + m * i] = I[j + m * i];
12752247a93fSRezgar Shakeri       for (CeedInt k = i + 1; k < n; k++) mat_pinv[j + m * i] -= mat_copy[k + n * i] * mat_pinv[j + m * k];
12762247a93fSRezgar Shakeri       mat_pinv[j + m * i] /= mat_copy[i + n * i];
12772247a93fSRezgar Shakeri     }
12782247a93fSRezgar Shakeri   }
12792247a93fSRezgar Shakeri 
12802247a93fSRezgar Shakeri   // Cleanup
12812247a93fSRezgar Shakeri   CeedCall(CeedFree(&I));
12822247a93fSRezgar Shakeri   CeedCall(CeedFree(&tau));
12832247a93fSRezgar Shakeri   CeedCall(CeedFree(&mat_copy));
12842247a93fSRezgar Shakeri   return CEED_ERROR_SUCCESS;
12852247a93fSRezgar Shakeri }
12862247a93fSRezgar Shakeri 
12872247a93fSRezgar Shakeri /**
1288ba59ac12SSebastian Grimberg   @brief Return symmetric Schur decomposition of the symmetric matrix mat via symmetric QR factorization
1289ba59ac12SSebastian Grimberg 
1290ca94c3ddSJeremy L Thompson   @param[in]     ceed   `Ceed` context for error handling
1291ba59ac12SSebastian Grimberg   @param[in,out] mat    Row-major matrix to be factorized in place
1292ba59ac12SSebastian Grimberg   @param[out]    lambda Vector of length n of eigenvalues
1293ba59ac12SSebastian Grimberg   @param[in]     n      Number of rows/columns
1294ba59ac12SSebastian Grimberg 
1295ba59ac12SSebastian Grimberg   @return An error code: 0 - success, otherwise - failure
1296ba59ac12SSebastian Grimberg 
1297ba59ac12SSebastian Grimberg   @ref Utility
1298ba59ac12SSebastian Grimberg **/
12992c2ea1dbSJeremy L Thompson CeedPragmaOptimizeOff
CeedSymmetricSchurDecomposition(Ceed ceed,CeedScalar * mat,CeedScalar * lambda,CeedInt n)13002c2ea1dbSJeremy L Thompson int CeedSymmetricSchurDecomposition(Ceed ceed, CeedScalar *mat, CeedScalar *lambda, CeedInt n) {
1301ba59ac12SSebastian Grimberg   // Check bounds for clang-tidy
13026574a04fSJeremy L Thompson   CeedCheck(n > 1, ceed, CEED_ERROR_UNSUPPORTED, "Cannot compute symmetric Schur decomposition of scalars");
1303ba59ac12SSebastian Grimberg 
1304ba59ac12SSebastian Grimberg   CeedScalar v[n - 1], tau[n - 1], mat_T[n * n];
1305ba59ac12SSebastian Grimberg 
1306ba59ac12SSebastian Grimberg   // Copy mat to mat_T and set mat to I
1307ba59ac12SSebastian Grimberg   memcpy(mat_T, mat, n * n * sizeof(mat[0]));
1308ba59ac12SSebastian Grimberg   for (CeedInt i = 0; i < n; i++) {
1309ba59ac12SSebastian Grimberg     for (CeedInt j = 0; j < n; j++) mat[j + n * i] = (i == j) ? 1 : 0;
1310ba59ac12SSebastian Grimberg   }
1311ba59ac12SSebastian Grimberg 
1312ba59ac12SSebastian Grimberg   // Reduce to tridiagonal
1313ba59ac12SSebastian Grimberg   for (CeedInt i = 0; i < n - 1; i++) {
1314ba59ac12SSebastian Grimberg     // Calculate Householder vector, magnitude
1315ba59ac12SSebastian Grimberg     CeedScalar sigma = 0.0;
13161c66c397SJeremy L Thompson 
1317ba59ac12SSebastian Grimberg     v[i] = mat_T[i + n * (i + 1)];
1318ba59ac12SSebastian Grimberg     for (CeedInt j = i + 1; j < n - 1; j++) {
1319ba59ac12SSebastian Grimberg       v[j] = mat_T[i + n * (j + 1)];
1320ba59ac12SSebastian Grimberg       sigma += v[j] * v[j];
1321ba59ac12SSebastian Grimberg     }
13221c66c397SJeremy L Thompson     const CeedScalar norm = sqrt(v[i] * v[i] + sigma);  // norm of v[i:n-1]
13231c66c397SJeremy L Thompson     const CeedScalar R_ii = -copysign(norm, v[i]);
13241c66c397SJeremy L Thompson 
1325ba59ac12SSebastian Grimberg     v[i] -= R_ii;
1326ba59ac12SSebastian Grimberg     // norm of v[i:m] after modification above and scaling below
1327ba59ac12SSebastian Grimberg     //   norm = sqrt(v[i]*v[i] + sigma) / v[i];
1328ba59ac12SSebastian Grimberg     //   tau = 2 / (norm*norm)
1329ba59ac12SSebastian Grimberg     tau[i] = i == n - 2 ? 2 : 2 * v[i] * v[i] / (v[i] * v[i] + sigma);
1330ba59ac12SSebastian Grimberg     for (CeedInt j = i + 1; j < n - 1; j++) v[j] /= v[i];
1331ba59ac12SSebastian Grimberg 
1332ba59ac12SSebastian Grimberg     // Update sub and super diagonal
1333ba59ac12SSebastian Grimberg     for (CeedInt j = i + 2; j < n; j++) {
1334ba59ac12SSebastian Grimberg       mat_T[i + n * j] = 0;
1335ba59ac12SSebastian Grimberg       mat_T[j + n * i] = 0;
1336ba59ac12SSebastian Grimberg     }
1337ba59ac12SSebastian Grimberg     // Apply symmetric Householder reflector to lower right panel
1338ba59ac12SSebastian Grimberg     CeedHouseholderReflect(&mat_T[(i + 1) + n * (i + 1)], &v[i], tau[i], n - (i + 1), n - (i + 1), n, 1);
1339ba59ac12SSebastian Grimberg     CeedHouseholderReflect(&mat_T[(i + 1) + n * (i + 1)], &v[i], tau[i], n - (i + 1), n - (i + 1), 1, n);
1340ba59ac12SSebastian Grimberg 
1341ba59ac12SSebastian Grimberg     // Save v
1342ba59ac12SSebastian Grimberg     mat_T[i + n * (i + 1)] = R_ii;
1343ba59ac12SSebastian Grimberg     mat_T[(i + 1) + n * i] = R_ii;
1344ba59ac12SSebastian Grimberg     for (CeedInt j = i + 1; j < n - 1; j++) {
1345ba59ac12SSebastian Grimberg       mat_T[i + n * (j + 1)] = v[j];
1346ba59ac12SSebastian Grimberg     }
1347ba59ac12SSebastian Grimberg   }
1348ba59ac12SSebastian Grimberg   // Backwards accumulation of Q
1349ba59ac12SSebastian Grimberg   for (CeedInt i = n - 2; i >= 0; i--) {
1350ba59ac12SSebastian Grimberg     if (tau[i] > 0.0) {
1351ba59ac12SSebastian Grimberg       v[i] = 1;
1352ba59ac12SSebastian Grimberg       for (CeedInt j = i + 1; j < n - 1; j++) {
1353ba59ac12SSebastian Grimberg         v[j]                   = mat_T[i + n * (j + 1)];
1354ba59ac12SSebastian Grimberg         mat_T[i + n * (j + 1)] = 0;
1355ba59ac12SSebastian Grimberg       }
1356ba59ac12SSebastian Grimberg       CeedHouseholderReflect(&mat[(i + 1) + n * (i + 1)], &v[i], tau[i], n - (i + 1), n - (i + 1), n, 1);
1357ba59ac12SSebastian Grimberg     }
1358ba59ac12SSebastian Grimberg   }
1359ba59ac12SSebastian Grimberg 
1360ba59ac12SSebastian Grimberg   // Reduce sub and super diagonal
1361ba59ac12SSebastian Grimberg   CeedInt    p = 0, q = 0, itr = 0, max_itr = n * n * n * n;
1362ba59ac12SSebastian Grimberg   CeedScalar tol = CEED_EPSILON;
1363ba59ac12SSebastian Grimberg 
1364ba59ac12SSebastian Grimberg   while (itr < max_itr) {
1365ba59ac12SSebastian Grimberg     // Update p, q, size of reduced portions of diagonal
1366ba59ac12SSebastian Grimberg     p = 0;
1367ba59ac12SSebastian Grimberg     q = 0;
1368ba59ac12SSebastian Grimberg     for (CeedInt i = n - 2; i >= 0; i--) {
1369ba59ac12SSebastian Grimberg       if (fabs(mat_T[i + n * (i + 1)]) < tol) q += 1;
1370ba59ac12SSebastian Grimberg       else break;
1371ba59ac12SSebastian Grimberg     }
1372ba59ac12SSebastian Grimberg     for (CeedInt i = 0; i < n - q - 1; i++) {
1373ba59ac12SSebastian Grimberg       if (fabs(mat_T[i + n * (i + 1)]) < tol) p += 1;
1374ba59ac12SSebastian Grimberg       else break;
1375ba59ac12SSebastian Grimberg     }
1376ba59ac12SSebastian Grimberg     if (q == n - 1) break;  // Finished reducing
1377ba59ac12SSebastian Grimberg 
1378ba59ac12SSebastian Grimberg     // Reduce tridiagonal portion
1379ba59ac12SSebastian Grimberg     CeedScalar t_nn = mat_T[(n - 1 - q) + n * (n - 1 - q)], t_nnm1 = mat_T[(n - 2 - q) + n * (n - 1 - q)];
1380ba59ac12SSebastian Grimberg     CeedScalar d  = (mat_T[(n - 2 - q) + n * (n - 2 - q)] - t_nn) / 2;
1381ba59ac12SSebastian Grimberg     CeedScalar mu = t_nn - t_nnm1 * t_nnm1 / (d + copysign(sqrt(d * d + t_nnm1 * t_nnm1), d));
1382ba59ac12SSebastian Grimberg     CeedScalar x  = mat_T[p + n * p] - mu;
1383ba59ac12SSebastian Grimberg     CeedScalar z  = mat_T[p + n * (p + 1)];
13841c66c397SJeremy L Thompson 
1385ba59ac12SSebastian Grimberg     for (CeedInt k = p; k < n - q - 1; k++) {
1386ba59ac12SSebastian Grimberg       // Compute Givens rotation
1387ba59ac12SSebastian Grimberg       CeedScalar c = 1, s = 0;
13881c66c397SJeremy L Thompson 
1389ba59ac12SSebastian Grimberg       if (fabs(z) > tol) {
1390ba59ac12SSebastian Grimberg         if (fabs(z) > fabs(x)) {
13911c66c397SJeremy L Thompson           const CeedScalar tau = -x / z;
13921c66c397SJeremy L Thompson 
13931c66c397SJeremy L Thompson           s = 1 / sqrt(1 + tau * tau);
13941c66c397SJeremy L Thompson           c = s * tau;
1395ba59ac12SSebastian Grimberg         } else {
13961c66c397SJeremy L Thompson           const CeedScalar tau = -z / x;
13971c66c397SJeremy L Thompson 
13981c66c397SJeremy L Thompson           c = 1 / sqrt(1 + tau * tau);
13991c66c397SJeremy L Thompson           s = c * tau;
1400ba59ac12SSebastian Grimberg         }
1401ba59ac12SSebastian Grimberg       }
1402ba59ac12SSebastian Grimberg 
1403ba59ac12SSebastian Grimberg       // Apply Givens rotation to T
1404ba59ac12SSebastian Grimberg       CeedGivensRotation(mat_T, c, s, CEED_NOTRANSPOSE, k, k + 1, n, n);
1405ba59ac12SSebastian Grimberg       CeedGivensRotation(mat_T, c, s, CEED_TRANSPOSE, k, k + 1, n, n);
1406ba59ac12SSebastian Grimberg 
1407ba59ac12SSebastian Grimberg       // Apply Givens rotation to Q
1408ba59ac12SSebastian Grimberg       CeedGivensRotation(mat, c, s, CEED_NOTRANSPOSE, k, k + 1, n, n);
1409ba59ac12SSebastian Grimberg 
1410ba59ac12SSebastian Grimberg       // Update x, z
1411ba59ac12SSebastian Grimberg       if (k < n - q - 2) {
1412ba59ac12SSebastian Grimberg         x = mat_T[k + n * (k + 1)];
1413ba59ac12SSebastian Grimberg         z = mat_T[k + n * (k + 2)];
1414ba59ac12SSebastian Grimberg       }
1415ba59ac12SSebastian Grimberg     }
1416ba59ac12SSebastian Grimberg     itr++;
1417ba59ac12SSebastian Grimberg   }
1418ba59ac12SSebastian Grimberg 
1419ba59ac12SSebastian Grimberg   // Save eigenvalues
1420ba59ac12SSebastian Grimberg   for (CeedInt i = 0; i < n; i++) lambda[i] = mat_T[i + n * i];
1421ba59ac12SSebastian Grimberg 
1422ba59ac12SSebastian Grimberg   // Check convergence
14236574a04fSJeremy L Thompson   CeedCheck(itr < max_itr || q > n, ceed, CEED_ERROR_MINOR, "Symmetric QR failed to converge");
1424ba59ac12SSebastian Grimberg   return CEED_ERROR_SUCCESS;
1425ba59ac12SSebastian Grimberg }
14262c2ea1dbSJeremy L Thompson CeedPragmaOptimizeOn
1427ba59ac12SSebastian Grimberg 
1428ba59ac12SSebastian Grimberg /**
1429ba59ac12SSebastian Grimberg   @brief Return Simultaneous Diagonalization of two matrices.
1430ba59ac12SSebastian Grimberg 
1431ca94c3ddSJeremy L Thompson   This solves the generalized eigenvalue problem `A x = lambda B x`, where `A` and `B` are symmetric and `B` is positive definite.
1432ca94c3ddSJeremy L Thompson   We generate the matrix `X` and vector `Lambda` such that `X^T A X = Lambda` and `X^T B X = I`.
1433ca94c3ddSJeremy L Thompson   This is equivalent to the LAPACK routine 'sygv' with `TYPE = 1`.
1434ba59ac12SSebastian Grimberg 
1435ca94c3ddSJeremy L Thompson   @param[in]  ceed   `Ceed` context for error handling
1436ba59ac12SSebastian Grimberg   @param[in]  mat_A  Row-major matrix to be factorized with eigenvalues
1437ba59ac12SSebastian Grimberg   @param[in]  mat_B  Row-major matrix to be factorized to identity
1438ba59ac12SSebastian Grimberg   @param[out] mat_X  Row-major orthogonal matrix
1439ca94c3ddSJeremy L Thompson   @param[out] lambda Vector of length `n` of generalized eigenvalues
1440ba59ac12SSebastian Grimberg   @param[in]  n      Number of rows/columns
1441ba59ac12SSebastian Grimberg 
1442ba59ac12SSebastian Grimberg   @return An error code: 0 - success, otherwise - failure
1443ba59ac12SSebastian Grimberg 
1444ba59ac12SSebastian Grimberg   @ref Utility
1445ba59ac12SSebastian Grimberg **/
14462c2ea1dbSJeremy L Thompson CeedPragmaOptimizeOff
CeedSimultaneousDiagonalization(Ceed ceed,CeedScalar * mat_A,CeedScalar * mat_B,CeedScalar * mat_X,CeedScalar * lambda,CeedInt n)14472c2ea1dbSJeremy L Thompson int CeedSimultaneousDiagonalization(Ceed ceed, CeedScalar *mat_A, CeedScalar *mat_B, CeedScalar *mat_X, CeedScalar *lambda, CeedInt n) {
1448ba59ac12SSebastian Grimberg   CeedScalar *mat_C, *mat_G, *vec_D;
14491c66c397SJeremy L Thompson 
1450ba59ac12SSebastian Grimberg   CeedCall(CeedCalloc(n * n, &mat_C));
1451ba59ac12SSebastian Grimberg   CeedCall(CeedCalloc(n * n, &mat_G));
1452ba59ac12SSebastian Grimberg   CeedCall(CeedCalloc(n, &vec_D));
1453ba59ac12SSebastian Grimberg 
1454ba59ac12SSebastian Grimberg   // Compute B = G D G^T
1455ba59ac12SSebastian Grimberg   memcpy(mat_G, mat_B, n * n * sizeof(mat_B[0]));
1456ba59ac12SSebastian Grimberg   CeedCall(CeedSymmetricSchurDecomposition(ceed, mat_G, vec_D, n));
1457ba59ac12SSebastian Grimberg 
1458ba59ac12SSebastian Grimberg   // Sort eigenvalues
1459ba59ac12SSebastian Grimberg   for (CeedInt i = n - 1; i >= 0; i--) {
1460ba59ac12SSebastian Grimberg     for (CeedInt j = 0; j < i; j++) {
1461ba59ac12SSebastian Grimberg       if (fabs(vec_D[j]) > fabs(vec_D[j + 1])) {
14621c66c397SJeremy L Thompson         CeedScalarSwap(vec_D[j], vec_D[j + 1]);
14631c66c397SJeremy L Thompson         for (CeedInt k = 0; k < n; k++) CeedScalarSwap(mat_G[k * n + j], mat_G[k * n + j + 1]);
1464ba59ac12SSebastian Grimberg       }
1465ba59ac12SSebastian Grimberg     }
1466ba59ac12SSebastian Grimberg   }
1467ba59ac12SSebastian Grimberg 
1468ba59ac12SSebastian Grimberg   // Compute C = (G D^1/2)^-1 A (G D^1/2)^-T
1469ba59ac12SSebastian Grimberg   //           = D^-1/2 G^T A G D^-1/2
1470ba59ac12SSebastian Grimberg   // -- D = D^-1/2
1471ba59ac12SSebastian Grimberg   for (CeedInt i = 0; i < n; i++) vec_D[i] = 1. / sqrt(vec_D[i]);
1472ba59ac12SSebastian Grimberg   // -- G = G D^-1/2
1473ba59ac12SSebastian Grimberg   // -- C = D^-1/2 G^T
1474ba59ac12SSebastian Grimberg   for (CeedInt i = 0; i < n; i++) {
1475ba59ac12SSebastian Grimberg     for (CeedInt j = 0; j < n; j++) {
1476ba59ac12SSebastian Grimberg       mat_G[i * n + j] *= vec_D[j];
1477ba59ac12SSebastian Grimberg       mat_C[j * n + i] = mat_G[i * n + j];
1478ba59ac12SSebastian Grimberg     }
1479ba59ac12SSebastian Grimberg   }
1480ba59ac12SSebastian Grimberg   // -- X = (D^-1/2 G^T) A
1481ba59ac12SSebastian Grimberg   CeedCall(CeedMatrixMatrixMultiply(ceed, (const CeedScalar *)mat_C, (const CeedScalar *)mat_A, mat_X, n, n, n));
1482ba59ac12SSebastian Grimberg   // -- C = (D^-1/2 G^T A) (G D^-1/2)
1483ba59ac12SSebastian Grimberg   CeedCall(CeedMatrixMatrixMultiply(ceed, (const CeedScalar *)mat_X, (const CeedScalar *)mat_G, mat_C, n, n, n));
1484ba59ac12SSebastian Grimberg 
1485ba59ac12SSebastian Grimberg   // Compute Q^T C Q = lambda
1486ba59ac12SSebastian Grimberg   CeedCall(CeedSymmetricSchurDecomposition(ceed, mat_C, lambda, n));
1487ba59ac12SSebastian Grimberg 
1488ba59ac12SSebastian Grimberg   // Sort eigenvalues
1489ba59ac12SSebastian Grimberg   for (CeedInt i = n - 1; i >= 0; i--) {
1490ba59ac12SSebastian Grimberg     for (CeedInt j = 0; j < i; j++) {
1491ba59ac12SSebastian Grimberg       if (fabs(lambda[j]) > fabs(lambda[j + 1])) {
14921c66c397SJeremy L Thompson         CeedScalarSwap(lambda[j], lambda[j + 1]);
14931c66c397SJeremy L Thompson         for (CeedInt k = 0; k < n; k++) CeedScalarSwap(mat_C[k * n + j], mat_C[k * n + j + 1]);
1494ba59ac12SSebastian Grimberg       }
1495ba59ac12SSebastian Grimberg     }
1496ba59ac12SSebastian Grimberg   }
1497ba59ac12SSebastian Grimberg 
1498ba59ac12SSebastian Grimberg   // Set X = (G D^1/2)^-T Q
1499ba59ac12SSebastian Grimberg   //       = G D^-1/2 Q
1500ba59ac12SSebastian Grimberg   CeedCall(CeedMatrixMatrixMultiply(ceed, (const CeedScalar *)mat_G, (const CeedScalar *)mat_C, mat_X, n, n, n));
1501ba59ac12SSebastian Grimberg 
1502ba59ac12SSebastian Grimberg   // Cleanup
1503ba59ac12SSebastian Grimberg   CeedCall(CeedFree(&mat_C));
1504ba59ac12SSebastian Grimberg   CeedCall(CeedFree(&mat_G));
1505ba59ac12SSebastian Grimberg   CeedCall(CeedFree(&vec_D));
1506ba59ac12SSebastian Grimberg   return CEED_ERROR_SUCCESS;
1507ba59ac12SSebastian Grimberg }
15082c2ea1dbSJeremy L Thompson CeedPragmaOptimizeOn
1509ba59ac12SSebastian Grimberg 
15107a982d89SJeremy L. Thompson /// @}
15117a982d89SJeremy L. Thompson 
15127a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
15137a982d89SJeremy L. Thompson /// CeedBasis Public API
15147a982d89SJeremy L. Thompson /// ----------------------------------------------------------------------------
15157a982d89SJeremy L. Thompson /// @addtogroup CeedBasisUser
1516d7b241e6Sjeremylt /// @{
1517d7b241e6Sjeremylt 
1518b11c1e72Sjeremylt /**
1519ca94c3ddSJeremy L Thompson   @brief Create a tensor-product basis for \f$H^1\f$ discretizations
1520b11c1e72Sjeremylt 
1521ca94c3ddSJeremy L Thompson   @param[in]  ceed        `Ceed` object used to create the `CeedBasis`
1522ea61e9acSJeremy L Thompson   @param[in]  dim         Topological dimension
1523ea61e9acSJeremy L Thompson   @param[in]  num_comp    Number of field components (1 for scalar fields)
1524ea61e9acSJeremy L Thompson   @param[in]  P_1d        Number of nodes in one dimension
1525ea61e9acSJeremy L Thompson   @param[in]  Q_1d        Number of quadrature points in one dimension
1526ca94c3ddSJeremy L Thompson   @param[in]  interp_1d   Row-major (`Q_1d * P_1d`) matrix expressing the values of nodal basis functions at quadrature points
1527ca94c3ddSJeremy L Thompson   @param[in]  grad_1d     Row-major (`Q_1d * P_1d`) matrix expressing derivatives of nodal basis functions at quadrature points
1528ca94c3ddSJeremy L Thompson   @param[in]  q_ref_1d    Array of length `Q_1d` holding the locations of quadrature points on the 1D reference element `[-1, 1]`
1529ca94c3ddSJeremy L Thompson   @param[in]  q_weight_1d Array of length `Q_1d` holding the quadrature weights on the reference element
1530ca94c3ddSJeremy L Thompson   @param[out] basis       Address of the variable where the newly created `CeedBasis` will be stored
1531b11c1e72Sjeremylt 
1532b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
1533dfdf5a53Sjeremylt 
15347a982d89SJeremy L. Thompson   @ref User
1535b11c1e72Sjeremylt **/
CeedBasisCreateTensorH1(Ceed ceed,CeedInt dim,CeedInt num_comp,CeedInt P_1d,CeedInt Q_1d,const CeedScalar * interp_1d,const CeedScalar * grad_1d,const CeedScalar * q_ref_1d,const CeedScalar * q_weight_1d,CeedBasis * basis)15362b730f8bSJeremy L Thompson int CeedBasisCreateTensorH1(Ceed ceed, CeedInt dim, CeedInt num_comp, CeedInt P_1d, CeedInt Q_1d, const CeedScalar *interp_1d,
15372b730f8bSJeremy L Thompson                             const CeedScalar *grad_1d, const CeedScalar *q_ref_1d, const CeedScalar *q_weight_1d, CeedBasis *basis) {
15385fe0d4faSjeremylt   if (!ceed->BasisCreateTensorH1) {
15395fe0d4faSjeremylt     Ceed delegate;
15406574a04fSJeremy L Thompson 
15412b730f8bSJeremy L Thompson     CeedCall(CeedGetObjectDelegate(ceed, &delegate, "Basis"));
15421ef3a2a9SJeremy L Thompson     CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement BasisCreateTensorH1");
15432b730f8bSJeremy L Thompson     CeedCall(CeedBasisCreateTensorH1(delegate, dim, num_comp, P_1d, Q_1d, interp_1d, grad_1d, q_ref_1d, q_weight_1d, basis));
15449bc66399SJeremy L Thompson     CeedCall(CeedDestroy(&delegate));
1545e15f9bd0SJeremy L Thompson     return CEED_ERROR_SUCCESS;
15465fe0d4faSjeremylt   }
1547e15f9bd0SJeremy L Thompson 
1548ca94c3ddSJeremy L Thompson   CeedCheck(dim > 0, ceed, CEED_ERROR_DIMENSION, "CeedBasis dimension must be a positive value");
1549ca94c3ddSJeremy L Thompson   CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "CeedBasis must have at least 1 component");
1550ca94c3ddSJeremy L Thompson   CeedCheck(P_1d > 0, ceed, CEED_ERROR_DIMENSION, "CeedBasis must have at least 1 node");
1551ca94c3ddSJeremy L Thompson   CeedCheck(Q_1d > 0, ceed, CEED_ERROR_DIMENSION, "CeedBasis must have at least 1 quadrature point");
1552227444bfSJeremy L Thompson 
15532b730f8bSJeremy L Thompson   CeedElemTopology topo = dim == 1 ? CEED_TOPOLOGY_LINE : dim == 2 ? CEED_TOPOLOGY_QUAD : CEED_TOPOLOGY_HEX;
1554e15f9bd0SJeremy L Thompson 
15552b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(1, basis));
1556*6c328a79SJeremy L Thompson   CeedCall(CeedObjectCreate(ceed, CeedBasisView_Object, CeedBasisDestroy_Object, &(*basis)->obj));
15576402da51SJeremy L Thompson   (*basis)->is_tensor_basis = true;
1558d7b241e6Sjeremylt   (*basis)->dim             = dim;
1559d99fa3c5SJeremy L Thompson   (*basis)->topo            = topo;
1560d1d35e2fSjeremylt   (*basis)->num_comp        = num_comp;
1561d1d35e2fSjeremylt   (*basis)->P_1d            = P_1d;
1562d1d35e2fSjeremylt   (*basis)->Q_1d            = Q_1d;
1563d1d35e2fSjeremylt   (*basis)->P               = CeedIntPow(P_1d, dim);
1564d1d35e2fSjeremylt   (*basis)->Q               = CeedIntPow(Q_1d, dim);
1565c4e3f59bSSebastian Grimberg   (*basis)->fe_space        = CEED_FE_SPACE_H1;
15662b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(Q_1d, &(*basis)->q_ref_1d));
15672b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(Q_1d, &(*basis)->q_weight_1d));
1568ff3a0f91SJeremy L Thompson   if (q_ref_1d) memcpy((*basis)->q_ref_1d, q_ref_1d, Q_1d * sizeof(q_ref_1d[0]));
15692b730f8bSJeremy L Thompson   if (q_weight_1d) memcpy((*basis)->q_weight_1d, q_weight_1d, Q_1d * sizeof(q_weight_1d[0]));
15702b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(Q_1d * P_1d, &(*basis)->interp_1d));
15712b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(Q_1d * P_1d, &(*basis)->grad_1d));
15722b730f8bSJeremy L Thompson   if (interp_1d) memcpy((*basis)->interp_1d, interp_1d, Q_1d * P_1d * sizeof(interp_1d[0]));
1573ff3a0f91SJeremy L Thompson   if (grad_1d) memcpy((*basis)->grad_1d, grad_1d, Q_1d * P_1d * sizeof(grad_1d[0]));
15742b730f8bSJeremy L Thompson   CeedCall(ceed->BasisCreateTensorH1(dim, P_1d, Q_1d, interp_1d, grad_1d, q_ref_1d, q_weight_1d, *basis));
1575e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1576d7b241e6Sjeremylt }
1577d7b241e6Sjeremylt 
1578b11c1e72Sjeremylt /**
1579ca94c3ddSJeremy L Thompson   @brief Create a tensor-product \f$H^1\f$ Lagrange basis
1580b11c1e72Sjeremylt 
1581ca94c3ddSJeremy L Thompson   @param[in]  ceed      `Ceed` object used to create the `CeedBasis`
1582ea61e9acSJeremy L Thompson   @param[in]  dim       Topological dimension of element
1583ea61e9acSJeremy L Thompson   @param[in]  num_comp  Number of field components (1 for scalar fields)
1584ea61e9acSJeremy L Thompson   @param[in]  P         Number of Gauss-Lobatto nodes in one dimension.
1585ca94c3ddSJeremy L Thompson                           The polynomial degree of the resulting `Q_k` element is `k = P - 1`.
1586ea61e9acSJeremy L Thompson   @param[in]  Q         Number of quadrature points in one dimension.
1587ca94c3ddSJeremy L Thompson   @param[in]  quad_mode Distribution of the `Q` quadrature points (affects order of accuracy for the quadrature)
1588ca94c3ddSJeremy L Thompson   @param[out] basis     Address of the variable where the newly created `CeedBasis` will be stored
1589b11c1e72Sjeremylt 
1590b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
1591dfdf5a53Sjeremylt 
15927a982d89SJeremy L. Thompson   @ref User
1593b11c1e72Sjeremylt **/
CeedBasisCreateTensorH1Lagrange(Ceed ceed,CeedInt dim,CeedInt num_comp,CeedInt P,CeedInt Q,CeedQuadMode quad_mode,CeedBasis * basis)15942b730f8bSJeremy L Thompson int CeedBasisCreateTensorH1Lagrange(Ceed ceed, CeedInt dim, CeedInt num_comp, CeedInt P, CeedInt Q, CeedQuadMode quad_mode, CeedBasis *basis) {
1595d7b241e6Sjeremylt   // Allocate
1596c8c3fa7dSJeremy L Thompson   int        ierr = CEED_ERROR_SUCCESS;
15972b730f8bSJeremy L Thompson   CeedScalar c1, c2, c3, c4, dx, *nodes, *interp_1d, *grad_1d, *q_ref_1d, *q_weight_1d;
15984d537eeaSYohann 
1599ca94c3ddSJeremy L Thompson   CeedCheck(dim > 0, ceed, CEED_ERROR_DIMENSION, "CeedBasis dimension must be a positive value");
1600ca94c3ddSJeremy L Thompson   CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "CeedBasis must have at least 1 component");
1601ca94c3ddSJeremy L Thompson   CeedCheck(P > 0, ceed, CEED_ERROR_DIMENSION, "CeedBasis must have at least 1 node");
1602ca94c3ddSJeremy L Thompson   CeedCheck(Q > 0, ceed, CEED_ERROR_DIMENSION, "CeedBasis must have at least 1 quadrature point");
1603227444bfSJeremy L Thompson 
1604e15f9bd0SJeremy L Thompson   // Get Nodes and Weights
16052b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(P * Q, &interp_1d));
16062b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(P * Q, &grad_1d));
16072b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(P, &nodes));
16082b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(Q, &q_ref_1d));
16092b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(Q, &q_weight_1d));
16102b730f8bSJeremy L Thompson   if (CeedLobattoQuadrature(P, nodes, NULL) != CEED_ERROR_SUCCESS) goto cleanup;
1611d1d35e2fSjeremylt   switch (quad_mode) {
1612d7b241e6Sjeremylt     case CEED_GAUSS:
1613d1d35e2fSjeremylt       ierr = CeedGaussQuadrature(Q, q_ref_1d, q_weight_1d);
1614d7b241e6Sjeremylt       break;
1615d7b241e6Sjeremylt     case CEED_GAUSS_LOBATTO:
1616d1d35e2fSjeremylt       ierr = CeedLobattoQuadrature(Q, q_ref_1d, q_weight_1d);
1617d7b241e6Sjeremylt       break;
1618d7b241e6Sjeremylt   }
16192b730f8bSJeremy L Thompson   if (ierr != CEED_ERROR_SUCCESS) goto cleanup;
1620e15f9bd0SJeremy L Thompson 
1621d7b241e6Sjeremylt   // Build B, D matrix
1622d7b241e6Sjeremylt   // Fornberg, 1998
1623c8c3fa7dSJeremy L Thompson   for (CeedInt i = 0; i < Q; i++) {
1624d7b241e6Sjeremylt     c1                   = 1.0;
1625d1d35e2fSjeremylt     c3                   = nodes[0] - q_ref_1d[i];
1626d1d35e2fSjeremylt     interp_1d[i * P + 0] = 1.0;
1627c8c3fa7dSJeremy L Thompson     for (CeedInt j = 1; j < P; j++) {
1628d7b241e6Sjeremylt       c2 = 1.0;
1629d7b241e6Sjeremylt       c4 = c3;
1630d1d35e2fSjeremylt       c3 = nodes[j] - q_ref_1d[i];
1631c8c3fa7dSJeremy L Thompson       for (CeedInt k = 0; k < j; k++) {
1632d7b241e6Sjeremylt         dx = nodes[j] - nodes[k];
1633d7b241e6Sjeremylt         c2 *= dx;
1634d7b241e6Sjeremylt         if (k == j - 1) {
1635d1d35e2fSjeremylt           grad_1d[i * P + j]   = c1 * (interp_1d[i * P + k] - c4 * grad_1d[i * P + k]) / c2;
1636d1d35e2fSjeremylt           interp_1d[i * P + j] = -c1 * c4 * interp_1d[i * P + k] / c2;
1637d7b241e6Sjeremylt         }
1638d1d35e2fSjeremylt         grad_1d[i * P + k]   = (c3 * grad_1d[i * P + k] - interp_1d[i * P + k]) / dx;
1639d1d35e2fSjeremylt         interp_1d[i * P + k] = c3 * interp_1d[i * P + k] / dx;
1640d7b241e6Sjeremylt       }
1641d7b241e6Sjeremylt       c1 = c2;
1642d7b241e6Sjeremylt     }
1643d7b241e6Sjeremylt   }
16449ac7b42eSJeremy L Thompson   // Pass to CeedBasisCreateTensorH1
16452b730f8bSJeremy L Thompson   CeedCall(CeedBasisCreateTensorH1(ceed, dim, num_comp, P, Q, interp_1d, grad_1d, q_ref_1d, q_weight_1d, basis));
1646e15f9bd0SJeremy L Thompson cleanup:
16472b730f8bSJeremy L Thompson   CeedCall(CeedFree(&interp_1d));
16482b730f8bSJeremy L Thompson   CeedCall(CeedFree(&grad_1d));
16492b730f8bSJeremy L Thompson   CeedCall(CeedFree(&nodes));
16502b730f8bSJeremy L Thompson   CeedCall(CeedFree(&q_ref_1d));
16512b730f8bSJeremy L Thompson   CeedCall(CeedFree(&q_weight_1d));
1652e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1653d7b241e6Sjeremylt }
1654d7b241e6Sjeremylt 
1655b11c1e72Sjeremylt /**
1656ca94c3ddSJeremy L Thompson   @brief Create a non tensor-product basis for \f$H^1\f$ discretizations
1657a8de75f0Sjeremylt 
1658ca94c3ddSJeremy L Thompson   @param[in]  ceed      `Ceed` object used to create the `CeedBasis`
1659e00f3be8SJames Wright   @param[in]  topo      Topology of element, e.g. hypercube, simplex, etc
1660ea61e9acSJeremy L Thompson   @param[in]  num_comp  Number of field components (1 for scalar fields)
1661ea61e9acSJeremy L Thompson   @param[in]  num_nodes Total number of nodes
1662ea61e9acSJeremy L Thompson   @param[in]  num_qpts  Total number of quadrature points
1663ca94c3ddSJeremy L Thompson   @param[in]  interp    Row-major (`num_qpts * num_nodes`) matrix expressing the values of nodal basis functions at quadrature points
1664ca94c3ddSJeremy L Thompson   @param[in]  grad      Row-major (`dim * num_qpts * num_nodes`) matrix expressing derivatives of nodal basis functions at quadrature points
1665fda26546SJeremy L Thompson   @param[in]  q_ref     Array of length `num_qpts * dim` holding the locations of quadrature points on the reference element
1666ca94c3ddSJeremy L Thompson   @param[in]  q_weight  Array of length `num_qpts` holding the quadrature weights on the reference element
1667ca94c3ddSJeremy L Thompson   @param[out] basis     Address of the variable where the newly created `CeedBasis` will be stored
1668a8de75f0Sjeremylt 
1669a8de75f0Sjeremylt   @return An error code: 0 - success, otherwise - failure
1670a8de75f0Sjeremylt 
16717a982d89SJeremy L. Thompson   @ref User
1672a8de75f0Sjeremylt **/
CeedBasisCreateH1(Ceed ceed,CeedElemTopology topo,CeedInt num_comp,CeedInt num_nodes,CeedInt num_qpts,const CeedScalar * interp,const CeedScalar * grad,const CeedScalar * q_ref,const CeedScalar * q_weight,CeedBasis * basis)16732b730f8bSJeremy L Thompson int CeedBasisCreateH1(Ceed ceed, CeedElemTopology topo, CeedInt num_comp, CeedInt num_nodes, CeedInt num_qpts, const CeedScalar *interp,
16742b730f8bSJeremy L Thompson                       const CeedScalar *grad, const CeedScalar *q_ref, const CeedScalar *q_weight, CeedBasis *basis) {
1675d1d35e2fSjeremylt   CeedInt P = num_nodes, Q = num_qpts, dim = 0;
1676a8de75f0Sjeremylt 
16775fe0d4faSjeremylt   if (!ceed->BasisCreateH1) {
16785fe0d4faSjeremylt     Ceed delegate;
16796574a04fSJeremy L Thompson 
16802b730f8bSJeremy L Thompson     CeedCall(CeedGetObjectDelegate(ceed, &delegate, "Basis"));
16811ef3a2a9SJeremy L Thompson     CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement BasisCreateH1");
16822b730f8bSJeremy L Thompson     CeedCall(CeedBasisCreateH1(delegate, topo, num_comp, num_nodes, num_qpts, interp, grad, q_ref, q_weight, basis));
16839bc66399SJeremy L Thompson     CeedCall(CeedDestroy(&delegate));
1684e15f9bd0SJeremy L Thompson     return CEED_ERROR_SUCCESS;
16855fe0d4faSjeremylt   }
16865fe0d4faSjeremylt 
1687ca94c3ddSJeremy L Thompson   CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "CeedBasis must have at least 1 component");
1688ca94c3ddSJeremy L Thompson   CeedCheck(num_nodes > 0, ceed, CEED_ERROR_DIMENSION, "CeedBasis must have at least 1 node");
1689ca94c3ddSJeremy L Thompson   CeedCheck(num_qpts > 0, ceed, CEED_ERROR_DIMENSION, "CeedBasis must have at least 1 quadrature point");
1690227444bfSJeremy L Thompson 
16912b730f8bSJeremy L Thompson   CeedCall(CeedBasisGetTopologyDimension(topo, &dim));
1692a8de75f0Sjeremylt 
1693db002c03SJeremy L Thompson   CeedCall(CeedCalloc(1, basis));
1694*6c328a79SJeremy L Thompson   CeedCall(CeedObjectCreate(ceed, CeedBasisView_Object, CeedBasisDestroy_Object, &(*basis)->obj));
16956402da51SJeremy L Thompson   (*basis)->is_tensor_basis = false;
1696a8de75f0Sjeremylt   (*basis)->dim             = dim;
1697d99fa3c5SJeremy L Thompson   (*basis)->topo            = topo;
1698d1d35e2fSjeremylt   (*basis)->num_comp        = num_comp;
1699a8de75f0Sjeremylt   (*basis)->P               = P;
1700a8de75f0Sjeremylt   (*basis)->Q               = Q;
1701c4e3f59bSSebastian Grimberg   (*basis)->fe_space        = CEED_FE_SPACE_H1;
17022b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(Q * dim, &(*basis)->q_ref_1d));
17032b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(Q, &(*basis)->q_weight_1d));
1704ff3a0f91SJeremy L Thompson   if (q_ref) memcpy((*basis)->q_ref_1d, q_ref, Q * dim * sizeof(q_ref[0]));
1705ff3a0f91SJeremy L Thompson   if (q_weight) memcpy((*basis)->q_weight_1d, q_weight, Q * sizeof(q_weight[0]));
17062b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(Q * P, &(*basis)->interp));
17072b730f8bSJeremy L Thompson   CeedCall(CeedCalloc(dim * Q * P, &(*basis)->grad));
1708ff3a0f91SJeremy L Thompson   if (interp) memcpy((*basis)->interp, interp, Q * P * sizeof(interp[0]));
1709ff3a0f91SJeremy L Thompson   if (grad) memcpy((*basis)->grad, grad, dim * Q * P * sizeof(grad[0]));
17102b730f8bSJeremy L Thompson   CeedCall(ceed->BasisCreateH1(topo, dim, P, Q, interp, grad, q_ref, q_weight, *basis));
1711e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
1712a8de75f0Sjeremylt }
1713a8de75f0Sjeremylt 
1714a8de75f0Sjeremylt /**
1715859c15bbSJames Wright   @brief Create a non tensor-product basis for \f$H(\mathrm{div})\f$ discretizations
171650c301a5SRezgar Shakeri 
1717ca94c3ddSJeremy L Thompson   @param[in]  ceed      `Ceed` object used to create the `CeedBasis`
1718ea61e9acSJeremy L Thompson   @param[in]  topo      Topology of element (`CEED_TOPOLOGY_QUAD`, `CEED_TOPOLOGY_PRISM`, etc.), dimension of which is used in some array sizes below
1719ea61e9acSJeremy L Thompson   @param[in]  num_comp  Number of components (usually 1 for vectors in H(div) bases)
1720ca94c3ddSJeremy L Thompson   @param[in]  num_nodes Total number of nodes (DoFs per element)
1721ea61e9acSJeremy L Thompson   @param[in]  num_qpts  Total number of quadrature points
1722ca94c3ddSJeremy L Thompson   @param[in]  interp    Row-major (`dim * num_qpts * num_nodes`) matrix expressing the values of basis functions at quadrature points
1723ca94c3ddSJeremy L Thompson   @param[in]  div       Row-major (`num_qpts * num_nodes`) matrix expressing divergence of basis functions at quadrature points
1724ca94c3ddSJeremy L Thompson   @param[in]  q_ref     Array of length `num_qpts` * dim holding the locations of quadrature points on the reference element
1725ca94c3ddSJeremy L Thompson   @param[in]  q_weight  Array of length `num_qpts` holding the quadrature weights on the reference element
1726ca94c3ddSJeremy L Thompson   @param[out] basis     Address of the variable where the newly created `CeedBasis` will be stored
172750c301a5SRezgar Shakeri 
172850c301a5SRezgar Shakeri   @return An error code: 0 - success, otherwise - failure
172950c301a5SRezgar Shakeri 
173050c301a5SRezgar Shakeri   @ref User
173150c301a5SRezgar Shakeri **/
CeedBasisCreateHdiv(Ceed ceed,CeedElemTopology topo,CeedInt num_comp,CeedInt num_nodes,CeedInt num_qpts,const CeedScalar * interp,const CeedScalar * div,const CeedScalar * q_ref,const CeedScalar * q_weight,CeedBasis * basis)17322b730f8bSJeremy L Thompson int CeedBasisCreateHdiv(Ceed ceed, CeedElemTopology topo, CeedInt num_comp, CeedInt num_nodes, CeedInt num_qpts, const CeedScalar *interp,
17332b730f8bSJeremy L Thompson                         const CeedScalar *div, const CeedScalar *q_ref, const CeedScalar *q_weight, CeedBasis *basis) {
173450c301a5SRezgar Shakeri   CeedInt Q = num_qpts, P = num_nodes, dim = 0;
1735c4e3f59bSSebastian Grimberg 
173650c301a5SRezgar Shakeri   if (!ceed->BasisCreateHdiv) {
173750c301a5SRezgar Shakeri     Ceed delegate;
17386574a04fSJeremy L Thompson 
17392b730f8bSJeremy L Thompson     CeedCall(CeedGetObjectDelegate(ceed, &delegate, "Basis"));
17406574a04fSJeremy L Thompson     CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement BasisCreateHdiv");
17412b730f8bSJeremy L Thompson     CeedCall(CeedBasisCreateHdiv(delegate, topo, num_comp, num_nodes, num_qpts, interp, div, q_ref, q_weight, basis));
17429bc66399SJeremy L Thompson     CeedCall(CeedDestroy(&delegate));
174350c301a5SRezgar Shakeri     return CEED_ERROR_SUCCESS;
174450c301a5SRezgar Shakeri   }
174550c301a5SRezgar Shakeri 
1746ca94c3ddSJeremy L Thompson   CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "CeedBasis must have at least 1 component");
1747ca94c3ddSJeremy L Thompson   CeedCheck(num_nodes > 0, ceed, CEED_ERROR_DIMENSION, "CeedBasis must have at least 1 node");
1748ca94c3ddSJeremy L Thompson   CeedCheck(num_qpts > 0, ceed, CEED_ERROR_DIMENSION, "CeedBasis must have at least 1 quadrature point");
1749227444bfSJeremy L Thompson 
1750c4e3f59bSSebastian Grimberg   CeedCall(CeedBasisGetTopologyDimension(topo, &dim));
1751c4e3f59bSSebastian Grimberg 
1752db002c03SJeremy L Thompson   CeedCall(CeedCalloc(1, basis));
1753*6c328a79SJeremy L Thompson   CeedCall(CeedObjectCreate(ceed, CeedBasisView_Object, CeedBasisDestroy_Object, &(*basis)->obj));
17546402da51SJeremy L Thompson   (*basis)->is_tensor_basis = false;
175550c301a5SRezgar Shakeri   (*basis)->dim             = dim;
175650c301a5SRezgar Shakeri   (*basis)->topo            = topo;
175750c301a5SRezgar Shakeri   (*basis)->num_comp        = num_comp;
175850c301a5SRezgar Shakeri   (*basis)->P               = P;
175950c301a5SRezgar Shakeri   (*basis)->Q               = Q;
1760c4e3f59bSSebastian Grimberg   (*basis)->fe_space        = CEED_FE_SPACE_HDIV;
17612b730f8bSJeremy L Thompson   CeedCall(CeedMalloc(Q * dim, &(*basis)->q_ref_1d));
17622b730f8bSJeremy L Thompson   CeedCall(CeedMalloc(Q, &(*basis)->q_weight_1d));
176350c301a5SRezgar Shakeri   if (q_ref) memcpy((*basis)->q_ref_1d, q_ref, Q * dim * sizeof(q_ref[0]));
176450c301a5SRezgar Shakeri   if (q_weight) memcpy((*basis)->q_weight_1d, q_weight, Q * sizeof(q_weight[0]));
17652b730f8bSJeremy L Thompson   CeedCall(CeedMalloc(dim * Q * P, &(*basis)->interp));
17662b730f8bSJeremy L Thompson   CeedCall(CeedMalloc(Q * P, &(*basis)->div));
176750c301a5SRezgar Shakeri   if (interp) memcpy((*basis)->interp, interp, dim * Q * P * sizeof(interp[0]));
176850c301a5SRezgar Shakeri   if (div) memcpy((*basis)->div, div, Q * P * sizeof(div[0]));
17692b730f8bSJeremy L Thompson   CeedCall(ceed->BasisCreateHdiv(topo, dim, P, Q, interp, div, q_ref, q_weight, *basis));
177050c301a5SRezgar Shakeri   return CEED_ERROR_SUCCESS;
177150c301a5SRezgar Shakeri }
177250c301a5SRezgar Shakeri 
177350c301a5SRezgar Shakeri /**
17744385fb7fSSebastian Grimberg   @brief Create a non tensor-product basis for \f$H(\mathrm{curl})\f$ discretizations
1775c4e3f59bSSebastian Grimberg 
1776ca94c3ddSJeremy L Thompson   @param[in]  ceed      `Ceed` object used to create the `CeedBasis`
1777c4e3f59bSSebastian Grimberg   @param[in]  topo      Topology of element (`CEED_TOPOLOGY_QUAD`, `CEED_TOPOLOGY_PRISM`, etc.), dimension of which is used in some array sizes below
1778ca94c3ddSJeremy L Thompson   @param[in]  num_comp  Number of components (usually 1 for vectors in \f$H(\mathrm{curl})\f$ bases)
1779ca94c3ddSJeremy L Thompson   @param[in]  num_nodes Total number of nodes (DoFs per element)
1780c4e3f59bSSebastian Grimberg   @param[in]  num_qpts  Total number of quadrature points
1781ca94c3ddSJeremy L Thompson   @param[in]  interp    Row-major (`dim * num_qpts * num_nodes`) matrix expressing the values of basis functions at quadrature points
1782ca94c3ddSJeremy L Thompson   @param[in]  curl      Row-major (`curl_comp * num_qpts * num_nodes`, `curl_comp = 1` if `dim < 3` otherwise `curl_comp = dim`) matrix expressing curl of basis functions at quadrature points
1783ca94c3ddSJeremy L Thompson   @param[in]  q_ref     Array of length `num_qpts * dim` holding the locations of quadrature points on the reference element
1784ca94c3ddSJeremy L Thompson   @param[in]  q_weight  Array of length `num_qpts` holding the quadrature weights on the reference element
1785ca94c3ddSJeremy L Thompson   @param[out] basis     Address of the variable where the newly created `CeedBasis` will be stored
1786c4e3f59bSSebastian Grimberg 
1787c4e3f59bSSebastian Grimberg   @return An error code: 0 - success, otherwise - failure
1788c4e3f59bSSebastian Grimberg 
1789c4e3f59bSSebastian Grimberg   @ref User
1790c4e3f59bSSebastian Grimberg **/
CeedBasisCreateHcurl(Ceed ceed,CeedElemTopology topo,CeedInt num_comp,CeedInt num_nodes,CeedInt num_qpts,const CeedScalar * interp,const CeedScalar * curl,const CeedScalar * q_ref,const CeedScalar * q_weight,CeedBasis * basis)1791c4e3f59bSSebastian Grimberg int CeedBasisCreateHcurl(Ceed ceed, CeedElemTopology topo, CeedInt num_comp, CeedInt num_nodes, CeedInt num_qpts, const CeedScalar *interp,
1792c4e3f59bSSebastian Grimberg                          const CeedScalar *curl, const CeedScalar *q_ref, const CeedScalar *q_weight, CeedBasis *basis) {
1793c4e3f59bSSebastian Grimberg   CeedInt Q = num_qpts, P = num_nodes, dim = 0, curl_comp = 0;
1794c4e3f59bSSebastian Grimberg 
1795d075f50bSSebastian Grimberg   if (!ceed->BasisCreateHcurl) {
1796c4e3f59bSSebastian Grimberg     Ceed delegate;
17976574a04fSJeremy L Thompson 
1798c4e3f59bSSebastian Grimberg     CeedCall(CeedGetObjectDelegate(ceed, &delegate, "Basis"));
17996574a04fSJeremy L Thompson     CeedCheck(delegate, ceed, CEED_ERROR_UNSUPPORTED, "Backend does not implement BasisCreateHcurl");
1800c4e3f59bSSebastian Grimberg     CeedCall(CeedBasisCreateHcurl(delegate, topo, num_comp, num_nodes, num_qpts, interp, curl, q_ref, q_weight, basis));
18019bc66399SJeremy L Thompson     CeedCall(CeedDestroy(&delegate));
1802c4e3f59bSSebastian Grimberg     return CEED_ERROR_SUCCESS;
1803c4e3f59bSSebastian Grimberg   }
1804c4e3f59bSSebastian Grimberg 
1805ca94c3ddSJeremy L Thompson   CeedCheck(num_comp > 0, ceed, CEED_ERROR_DIMENSION, "CeedBasis must have at least 1 component");
1806ca94c3ddSJeremy L Thompson   CeedCheck(num_nodes > 0, ceed, CEED_ERROR_DIMENSION, "CeedBasis must have at least 1 node");
1807ca94c3ddSJeremy L Thompson   CeedCheck(num_qpts > 0, ceed, CEED_ERROR_DIMENSION, "CeedBasis must have at least 1 quadrature point");
1808c4e3f59bSSebastian Grimberg 
1809c4e3f59bSSebastian Grimberg   CeedCall(CeedBasisGetTopologyDimension(topo, &dim));
1810c4e3f59bSSebastian Grimberg   curl_comp = (dim < 3) ? 1 : dim;
1811c4e3f59bSSebastian Grimberg 
1812db002c03SJeremy L Thompson   CeedCall(CeedCalloc(1, basis));
1813*6c328a79SJeremy L Thompson   CeedCall(CeedObjectCreate(ceed, CeedBasisView_Object, CeedBasisDestroy_Object, &(*basis)->obj));
18146402da51SJeremy L Thompson   (*basis)->is_tensor_basis = false;
1815c4e3f59bSSebastian Grimberg   (*basis)->dim             = dim;
1816c4e3f59bSSebastian Grimberg   (*basis)->topo            = topo;
1817c4e3f59bSSebastian Grimberg   (*basis)->num_comp        = num_comp;
1818c4e3f59bSSebastian Grimberg   (*basis)->P               = P;
1819c4e3f59bSSebastian Grimberg   (*basis)->Q               = Q;
1820c4e3f59bSSebastian Grimberg   (*basis)->fe_space        = CEED_FE_SPACE_HCURL;
1821c4e3f59bSSebastian Grimberg   CeedCall(CeedMalloc(Q * dim, &(*basis)->q_ref_1d));
1822c4e3f59bSSebastian Grimberg   CeedCall(CeedMalloc(Q, &(*basis)->q_weight_1d));
1823c4e3f59bSSebastian Grimberg   if (q_ref) memcpy((*basis)->q_ref_1d, q_ref, Q * dim * sizeof(q_ref[0]));
1824c4e3f59bSSebastian Grimberg   if (q_weight) memcpy((*basis)->q_weight_1d, q_weight, Q * sizeof(q_weight[0]));
1825c4e3f59bSSebastian Grimberg   CeedCall(CeedMalloc(dim * Q * P, &(*basis)->interp));
1826c4e3f59bSSebastian Grimberg   CeedCall(CeedMalloc(curl_comp * Q * P, &(*basis)->curl));
1827c4e3f59bSSebastian Grimberg   if (interp) memcpy((*basis)->interp, interp, dim * Q * P * sizeof(interp[0]));
1828c4e3f59bSSebastian Grimberg   if (curl) memcpy((*basis)->curl, curl, curl_comp * Q * P * sizeof(curl[0]));
1829c4e3f59bSSebastian Grimberg   CeedCall(ceed->BasisCreateHcurl(topo, dim, P, Q, interp, curl, q_ref, q_weight, *basis));
1830c4e3f59bSSebastian Grimberg   return CEED_ERROR_SUCCESS;
1831c4e3f59bSSebastian Grimberg }
1832c4e3f59bSSebastian Grimberg 
1833c4e3f59bSSebastian Grimberg /**
1834ca94c3ddSJeremy L Thompson   @brief Create a `CeedBasis` for projection from the nodes of `basis_from` to the nodes of `basis_to`.
1835ba59ac12SSebastian Grimberg 
1836ca94c3ddSJeremy L Thompson   Only @ref CEED_EVAL_INTERP will be valid for the new basis, `basis_project`.
1837ca94c3ddSJeremy L Thompson   For \f$H^1\f$ spaces, @ref CEED_EVAL_GRAD will also be valid.
1838ca94c3ddSJeremy L Thompson   The interpolation is given by `interp_project = interp_to^+ * interp_from`, where the pseudoinverse `interp_to^+` is given by QR factorization.
1839ca94c3ddSJeremy L Thompson   The gradient (for the \f$H^1\f$ case) is given by `grad_project = interp_to^+ * grad_from`.
184015ad3917SSebastian Grimberg 
184115ad3917SSebastian Grimberg   Note: `basis_from` and `basis_to` must have compatible quadrature spaces.
184215ad3917SSebastian Grimberg 
18439fd66db6SSebastian Grimberg   Note: `basis_project` will have the same number of components as `basis_from`, regardless of the number of components that `basis_to` has.
18449fd66db6SSebastian Grimberg         If `basis_from` has 3 components and `basis_to` has 5 components, then `basis_project` will have 3 components.
1845f113e5dcSJeremy L Thompson 
1846e104ad11SJames Wright   Note: If either `basis_from` or `basis_to` are non-tensor, then `basis_project` will also be non-tensor
1847e104ad11SJames Wright 
1848ca94c3ddSJeremy L Thompson   @param[in]  basis_from    `CeedBasis` to prolong from
1849ca94c3ddSJeremy L Thompson   @param[in]  basis_to      `CeedBasis` to prolong to
1850ca94c3ddSJeremy L Thompson   @param[out] basis_project Address of the variable where the newly created `CeedBasis` will be stored
1851f113e5dcSJeremy L Thompson 
1852f113e5dcSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
1853f113e5dcSJeremy L Thompson 
1854f113e5dcSJeremy L Thompson   @ref User
1855f113e5dcSJeremy L Thompson **/
CeedBasisCreateProjection(CeedBasis basis_from,CeedBasis basis_to,CeedBasis * basis_project)18562b730f8bSJeremy L Thompson int CeedBasisCreateProjection(CeedBasis basis_from, CeedBasis basis_to, CeedBasis *basis_project) {
1857f113e5dcSJeremy L Thompson   Ceed        ceed;
1858e104ad11SJames Wright   bool        create_tensor;
18591c66c397SJeremy L Thompson   CeedInt     dim, num_comp;
1860097cc795SJames Wright   CeedScalar *interp_project, *grad_project;
18611c66c397SJeremy L Thompson 
18622b730f8bSJeremy L Thompson   CeedCall(CeedBasisGetCeed(basis_to, &ceed));
1863f113e5dcSJeremy L Thompson 
1864ecc88aebSJeremy L Thompson   // Create projection matrix
18652b730f8bSJeremy L Thompson   CeedCall(CeedBasisCreateProjectionMatrices(basis_from, basis_to, &interp_project, &grad_project));
1866f113e5dcSJeremy L Thompson 
1867f113e5dcSJeremy L Thompson   // Build basis
1868e104ad11SJames Wright   {
1869e104ad11SJames Wright     bool is_tensor_to, is_tensor_from;
1870e104ad11SJames Wright 
1871e104ad11SJames Wright     CeedCall(CeedBasisIsTensor(basis_to, &is_tensor_to));
1872e104ad11SJames Wright     CeedCall(CeedBasisIsTensor(basis_from, &is_tensor_from));
1873e104ad11SJames Wright     create_tensor = is_tensor_from && is_tensor_to;
1874e104ad11SJames Wright   }
18752b730f8bSJeremy L Thompson   CeedCall(CeedBasisGetDimension(basis_to, &dim));
18762b730f8bSJeremy L Thompson   CeedCall(CeedBasisGetNumComponents(basis_from, &num_comp));
1877e104ad11SJames Wright   if (create_tensor) {
1878f113e5dcSJeremy L Thompson     CeedInt P_1d_to, P_1d_from;
18791c66c397SJeremy L Thompson 
18802b730f8bSJeremy L Thompson     CeedCall(CeedBasisGetNumNodes1D(basis_from, &P_1d_from));
18812b730f8bSJeremy L Thompson     CeedCall(CeedBasisGetNumNodes1D(basis_to, &P_1d_to));
1882097cc795SJames Wright     CeedCall(CeedBasisCreateTensorH1(ceed, dim, num_comp, P_1d_from, P_1d_to, interp_project, grad_project, NULL, NULL, basis_project));
1883f113e5dcSJeremy L Thompson   } else {
1884de05fbb2SSebastian Grimberg     // Even if basis_to and basis_from are not H1, the resulting basis is H1 for interpolation to work
1885f113e5dcSJeremy L Thompson     CeedInt          num_nodes_to, num_nodes_from;
18861c66c397SJeremy L Thompson     CeedElemTopology topo;
18871c66c397SJeremy L Thompson 
1888e00f3be8SJames Wright     CeedCall(CeedBasisGetTopology(basis_from, &topo));
18892b730f8bSJeremy L Thompson     CeedCall(CeedBasisGetNumNodes(basis_from, &num_nodes_from));
18902b730f8bSJeremy L Thompson     CeedCall(CeedBasisGetNumNodes(basis_to, &num_nodes_to));
1891097cc795SJames Wright     CeedCall(CeedBasisCreateH1(ceed, topo, num_comp, num_nodes_from, num_nodes_to, interp_project, grad_project, NULL, NULL, basis_project));
1892f113e5dcSJeremy L Thompson   }
1893f113e5dcSJeremy L Thompson 
1894f113e5dcSJeremy L Thompson   // Cleanup
18952b730f8bSJeremy L Thompson   CeedCall(CeedFree(&interp_project));
18962b730f8bSJeremy L Thompson   CeedCall(CeedFree(&grad_project));
18979bc66399SJeremy L Thompson   CeedCall(CeedDestroy(&ceed));
1898f113e5dcSJeremy L Thompson   return CEED_ERROR_SUCCESS;
1899f113e5dcSJeremy L Thompson }
1900f113e5dcSJeremy L Thompson 
1901f113e5dcSJeremy L Thompson /**
1902ca94c3ddSJeremy L Thompson   @brief Copy the pointer to a `CeedBasis`.
19039560d06aSjeremylt 
1904ca94c3ddSJeremy L Thompson   Note: If the value of `*basis_copy` passed into this function is non-`NULL`, then it is assumed that `*basis_copy` is a pointer to a `CeedBasis`.
1905ca94c3ddSJeremy L Thompson         This `CeedBasis` will be destroyed if `*basis_copy` is the only reference to this `CeedBasis`.
1906ea61e9acSJeremy L Thompson 
1907ca94c3ddSJeremy L Thompson   @param[in]     basis      `CeedBasis` to copy reference to
1908ea61e9acSJeremy L Thompson   @param[in,out] basis_copy Variable to store copied reference
19099560d06aSjeremylt 
19109560d06aSjeremylt   @return An error code: 0 - success, otherwise - failure
19119560d06aSjeremylt 
19129560d06aSjeremylt   @ref User
19139560d06aSjeremylt **/
CeedBasisReferenceCopy(CeedBasis basis,CeedBasis * basis_copy)19149560d06aSjeremylt int CeedBasisReferenceCopy(CeedBasis basis, CeedBasis *basis_copy) {
1915356036faSJeremy L Thompson   if (basis != CEED_BASIS_NONE) CeedCall(CeedBasisReference(basis));
19162b730f8bSJeremy L Thompson   CeedCall(CeedBasisDestroy(basis_copy));
19179560d06aSjeremylt   *basis_copy = basis;
19189560d06aSjeremylt   return CEED_ERROR_SUCCESS;
19199560d06aSjeremylt }
19209560d06aSjeremylt 
19219560d06aSjeremylt /**
19224c789ea2SJeremy L Thompson   @brief Set the number of tabs to indent for @ref CeedBasisView() output
19234c789ea2SJeremy L Thompson 
19244c789ea2SJeremy L Thompson   @param[in] basis    `CeedBasis` to set the number of view tabs
19254c789ea2SJeremy L Thompson   @param[in] num_tabs Number of view tabs to set
19264c789ea2SJeremy L Thompson 
19274c789ea2SJeremy L Thompson   @return Error code: 0 - success, otherwise - failure
19284c789ea2SJeremy L Thompson 
19294c789ea2SJeremy L Thompson   @ref User
19304c789ea2SJeremy L Thompson **/
CeedBasisSetNumViewTabs(CeedBasis basis,CeedInt num_tabs)19314c789ea2SJeremy L Thompson int CeedBasisSetNumViewTabs(CeedBasis basis, CeedInt num_tabs) {
1932a299a25bSJeremy L Thompson   CeedCall(CeedObjectSetNumViewTabs((CeedObject)basis, num_tabs));
19334c789ea2SJeremy L Thompson   return CEED_ERROR_SUCCESS;
19344c789ea2SJeremy L Thompson }
19354c789ea2SJeremy L Thompson 
19364c789ea2SJeremy L Thompson /**
1937690992b2SZach Atkins   @brief Get the number of tabs to indent for @ref CeedBasisView() output
1938690992b2SZach Atkins 
1939690992b2SZach Atkins   @param[in]  basis    `CeedBasis` to get the number of view tabs
1940690992b2SZach Atkins   @param[out] num_tabs Number of view tabs
1941690992b2SZach Atkins 
1942690992b2SZach Atkins   @return Error code: 0 - success, otherwise - failure
1943690992b2SZach Atkins 
1944690992b2SZach Atkins   @ref User
1945690992b2SZach Atkins **/
CeedBasisGetNumViewTabs(CeedBasis basis,CeedInt * num_tabs)1946690992b2SZach Atkins int CeedBasisGetNumViewTabs(CeedBasis basis, CeedInt *num_tabs) {
1947a299a25bSJeremy L Thompson   CeedCall(CeedObjectGetNumViewTabs((CeedObject)basis, num_tabs));
1948690992b2SZach Atkins   return CEED_ERROR_SUCCESS;
1949690992b2SZach Atkins }
1950690992b2SZach Atkins 
1951690992b2SZach Atkins /**
1952ca94c3ddSJeremy L Thompson   @brief View a `CeedBasis`
19537a982d89SJeremy L. Thompson 
1954ca94c3ddSJeremy L Thompson   @param[in] basis  `CeedBasis` to view
1955ca94c3ddSJeremy L Thompson   @param[in] stream Stream to view to, e.g., `stdout`
19567a982d89SJeremy L. Thompson 
19577a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
19587a982d89SJeremy L. Thompson 
19597a982d89SJeremy L. Thompson   @ref User
19607a982d89SJeremy L. Thompson **/
CeedBasisView(CeedBasis basis,FILE * stream)19617a982d89SJeremy L. Thompson int CeedBasisView(CeedBasis basis, FILE *stream) {
19621203703bSJeremy L Thompson   bool             is_tensor_basis;
19634c789ea2SJeremy L Thompson   char            *tabs = NULL;
19641203703bSJeremy L Thompson   CeedElemTopology topo;
19651203703bSJeremy L Thompson   CeedFESpace      fe_space;
19661203703bSJeremy L Thompson 
19671203703bSJeremy L Thompson   // Basis data
19681203703bSJeremy L Thompson   CeedCall(CeedBasisIsTensor(basis, &is_tensor_basis));
19691203703bSJeremy L Thompson   CeedCall(CeedBasisGetTopology(basis, &topo));
19701203703bSJeremy L Thompson   CeedCall(CeedBasisGetFESpace(basis, &fe_space));
19712b730f8bSJeremy L Thompson 
19724c789ea2SJeremy L Thompson   {
19734c789ea2SJeremy L Thompson     CeedInt num_tabs = 0;
19744c789ea2SJeremy L Thompson 
19754c789ea2SJeremy L Thompson     CeedCall(CeedBasisGetNumViewTabs(basis, &num_tabs));
19764c789ea2SJeremy L Thompson     CeedCall(CeedCalloc(CEED_TAB_WIDTH * num_tabs + 1, &tabs));
19774c789ea2SJeremy L Thompson     for (CeedInt i = 0; i < CEED_TAB_WIDTH * num_tabs; i++) tabs[i] = ' ';
197850c301a5SRezgar Shakeri   }
19794c789ea2SJeremy L Thompson 
19804c789ea2SJeremy L Thompson   // Print FE space and element topology of the basis
19814c789ea2SJeremy L Thompson   fprintf(stream, "%sCeedBasis in a %s on a %s element\n", tabs, CeedFESpaces[fe_space], CeedElemTopologies[topo]);
19824c789ea2SJeremy L Thompson   if (is_tensor_basis) {
19834c789ea2SJeremy L Thompson     fprintf(stream, "%s  P: %" CeedInt_FMT "\n%s  Q: %" CeedInt_FMT "\n", tabs, basis->P_1d, tabs, basis->Q_1d);
19844c789ea2SJeremy L Thompson   } else {
19854c789ea2SJeremy L Thompson     fprintf(stream, "%s  P: %" CeedInt_FMT "\n%s  Q: %" CeedInt_FMT "\n", tabs, basis->P, tabs, basis->Q);
19864c789ea2SJeremy L Thompson   }
19874c789ea2SJeremy L Thompson   fprintf(stream, "%s  dimension: %" CeedInt_FMT "\n%s  field components: %" CeedInt_FMT "\n", tabs, basis->dim, tabs, basis->num_comp);
1988ea61e9acSJeremy L Thompson   // Print quadrature data, interpolation/gradient/divergence/curl of the basis
19891203703bSJeremy L Thompson   if (is_tensor_basis) {  // tensor basis
19901203703bSJeremy L Thompson     CeedInt           P_1d, Q_1d;
19911203703bSJeremy L Thompson     const CeedScalar *q_ref_1d, *q_weight_1d, *interp_1d, *grad_1d;
19921203703bSJeremy L Thompson 
19931203703bSJeremy L Thompson     CeedCall(CeedBasisGetNumNodes1D(basis, &P_1d));
19941203703bSJeremy L Thompson     CeedCall(CeedBasisGetNumQuadraturePoints1D(basis, &Q_1d));
19951203703bSJeremy L Thompson     CeedCall(CeedBasisGetQRef(basis, &q_ref_1d));
19961203703bSJeremy L Thompson     CeedCall(CeedBasisGetQWeights(basis, &q_weight_1d));
19971203703bSJeremy L Thompson     CeedCall(CeedBasisGetInterp1D(basis, &interp_1d));
19981203703bSJeremy L Thompson     CeedCall(CeedBasisGetGrad1D(basis, &grad_1d));
19991203703bSJeremy L Thompson 
20004c789ea2SJeremy L Thompson     CeedCall(CeedScalarView("qref1d", "\t% 12.8f", 1, Q_1d, q_ref_1d, tabs, stream));
20014c789ea2SJeremy L Thompson     CeedCall(CeedScalarView("qweight1d", "\t% 12.8f", 1, Q_1d, q_weight_1d, tabs, stream));
20024c789ea2SJeremy L Thompson     CeedCall(CeedScalarView("interp1d", "\t% 12.8f", Q_1d, P_1d, interp_1d, tabs, stream));
20034c789ea2SJeremy L Thompson     CeedCall(CeedScalarView("grad1d", "\t% 12.8f", Q_1d, P_1d, grad_1d, tabs, stream));
200450c301a5SRezgar Shakeri   } else {  // non-tensor basis
20051203703bSJeremy L Thompson     CeedInt           P, Q, dim, q_comp;
20061203703bSJeremy L Thompson     const CeedScalar *q_ref, *q_weight, *interp, *grad, *div, *curl;
20071203703bSJeremy L Thompson 
20081203703bSJeremy L Thompson     CeedCall(CeedBasisGetNumNodes(basis, &P));
20091203703bSJeremy L Thompson     CeedCall(CeedBasisGetNumQuadraturePoints(basis, &Q));
20101203703bSJeremy L Thompson     CeedCall(CeedBasisGetDimension(basis, &dim));
20111203703bSJeremy L Thompson     CeedCall(CeedBasisGetQRef(basis, &q_ref));
20121203703bSJeremy L Thompson     CeedCall(CeedBasisGetQWeights(basis, &q_weight));
20131203703bSJeremy L Thompson     CeedCall(CeedBasisGetInterp(basis, &interp));
20141203703bSJeremy L Thompson     CeedCall(CeedBasisGetGrad(basis, &grad));
20151203703bSJeremy L Thompson     CeedCall(CeedBasisGetDiv(basis, &div));
20161203703bSJeremy L Thompson     CeedCall(CeedBasisGetCurl(basis, &curl));
20171203703bSJeremy L Thompson 
20184c789ea2SJeremy L Thompson     CeedCall(CeedScalarView("qref", "\t% 12.8f", 1, Q * dim, q_ref, tabs, stream));
20194c789ea2SJeremy L Thompson     CeedCall(CeedScalarView("qweight", "\t% 12.8f", 1, Q, q_weight, tabs, stream));
2020c4e3f59bSSebastian Grimberg     CeedCall(CeedBasisGetNumQuadratureComponents(basis, CEED_EVAL_INTERP, &q_comp));
20214c789ea2SJeremy L Thompson     CeedCall(CeedScalarView("interp", "\t% 12.8f", q_comp * Q, P, interp, tabs, stream));
20221203703bSJeremy L Thompson     if (grad) {
2023c4e3f59bSSebastian Grimberg       CeedCall(CeedBasisGetNumQuadratureComponents(basis, CEED_EVAL_GRAD, &q_comp));
20244c789ea2SJeremy L Thompson       CeedCall(CeedScalarView("grad", "\t% 12.8f", q_comp * Q, P, grad, tabs, stream));
20257a982d89SJeremy L. Thompson     }
20261203703bSJeremy L Thompson     if (div) {
2027c4e3f59bSSebastian Grimberg       CeedCall(CeedBasisGetNumQuadratureComponents(basis, CEED_EVAL_DIV, &q_comp));
20284c789ea2SJeremy L Thompson       CeedCall(CeedScalarView("div", "\t% 12.8f", q_comp * Q, P, div, tabs, stream));
2029c4e3f59bSSebastian Grimberg     }
20301203703bSJeremy L Thompson     if (curl) {
2031c4e3f59bSSebastian Grimberg       CeedCall(CeedBasisGetNumQuadratureComponents(basis, CEED_EVAL_CURL, &q_comp));
20324c789ea2SJeremy L Thompson       CeedCall(CeedScalarView("curl", "\t% 12.8f", q_comp * Q, P, curl, tabs, stream));
203350c301a5SRezgar Shakeri     }
203450c301a5SRezgar Shakeri   }
20354c789ea2SJeremy L Thompson   CeedCall(CeedFree(&tabs));
2036e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
20377a982d89SJeremy L. Thompson }
20387a982d89SJeremy L. Thompson 
20397a982d89SJeremy L. Thompson /**
2040db2becc9SJeremy L Thompson   @brief Apply basis evaluation from nodes to quadrature points or vice versa
2041db2becc9SJeremy L Thompson 
2042db2becc9SJeremy L Thompson   @param[in]  basis     `CeedBasis` to evaluate
2043db2becc9SJeremy L Thompson   @param[in]  num_elem  The number of elements to apply the basis evaluation to;
2044db2becc9SJeremy L Thompson                           the backend will specify the ordering in @ref CeedElemRestrictionCreate()
2045db2becc9SJeremy L Thompson   @param[in]  t_mode    @ref CEED_NOTRANSPOSE to evaluate from nodes to quadrature points;
2046db2becc9SJeremy L Thompson                           @ref CEED_TRANSPOSE to apply the transpose, mapping from quadrature points to nodes
2047db2becc9SJeremy L Thompson   @param[in]  eval_mode @ref CEED_EVAL_NONE to use values directly,
2048db2becc9SJeremy L Thompson                           @ref CEED_EVAL_INTERP to use interpolated values,
2049db2becc9SJeremy L Thompson                           @ref CEED_EVAL_GRAD to use gradients,
2050db2becc9SJeremy L Thompson                           @ref CEED_EVAL_DIV to use divergence,
2051db2becc9SJeremy L Thompson                           @ref CEED_EVAL_CURL to use curl,
2052db2becc9SJeremy L Thompson                           @ref CEED_EVAL_WEIGHT to use quadrature weights
2053db2becc9SJeremy L Thompson   @param[in]  u         Input `CeedVector`
2054db2becc9SJeremy L Thompson   @param[out] v         Output `CeedVector`
2055db2becc9SJeremy L Thompson 
2056db2becc9SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
2057db2becc9SJeremy L Thompson 
2058db2becc9SJeremy L Thompson   @ref User
2059db2becc9SJeremy L Thompson **/
CeedBasisApply(CeedBasis basis,CeedInt num_elem,CeedTransposeMode t_mode,CeedEvalMode eval_mode,CeedVector u,CeedVector v)2060db2becc9SJeremy L Thompson int CeedBasisApply(CeedBasis basis, CeedInt num_elem, CeedTransposeMode t_mode, CeedEvalMode eval_mode, CeedVector u, CeedVector v) {
2061db2becc9SJeremy L Thompson   CeedCall(CeedBasisApplyCheckDims(basis, num_elem, t_mode, eval_mode, u, v));
2062db2becc9SJeremy L Thompson   CeedCheck(basis->Apply, CeedBasisReturnCeed(basis), CEED_ERROR_UNSUPPORTED, "Backend does not support CeedBasisApply");
20632b730f8bSJeremy L Thompson   CeedCall(basis->Apply(basis, num_elem, t_mode, eval_mode, u, v));
2064e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
20657a982d89SJeremy L. Thompson }
20667a982d89SJeremy L. Thompson 
20677a982d89SJeremy L. Thompson /**
2068db2becc9SJeremy L Thompson   @brief Apply basis evaluation from quadrature points to nodes and sum into target vector
2069db2becc9SJeremy L Thompson 
2070db2becc9SJeremy L Thompson   @param[in]  basis     `CeedBasis` to evaluate
2071db2becc9SJeremy L Thompson   @param[in]  num_elem  The number of elements to apply the basis evaluation to;
2072db2becc9SJeremy L Thompson                           the backend will specify the ordering in @ref CeedElemRestrictionCreate()
2073db2becc9SJeremy L Thompson   @param[in]  t_mode    @ref CEED_TRANSPOSE to apply the transpose, mapping from quadrature points to nodes;
2074db2becc9SJeremy L Thompson                            @ref CEED_NOTRANSPOSE is not valid for `CeedBasisApplyAdd()`
2075db2becc9SJeremy L Thompson   @param[in]  eval_mode @ref CEED_EVAL_NONE to use values directly,
2076db2becc9SJeremy L Thompson                           @ref CEED_EVAL_INTERP to use interpolated values,
2077db2becc9SJeremy L Thompson                           @ref CEED_EVAL_GRAD to use gradients,
2078db2becc9SJeremy L Thompson                           @ref CEED_EVAL_DIV to use divergence,
2079db2becc9SJeremy L Thompson                           @ref CEED_EVAL_CURL to use curl,
2080db2becc9SJeremy L Thompson                           @ref CEED_EVAL_WEIGHT to use quadrature weights
2081db2becc9SJeremy L Thompson   @param[in]  u         Input `CeedVector`
2082db2becc9SJeremy L Thompson   @param[out] v         Output `CeedVector` to sum into
2083db2becc9SJeremy L Thompson 
2084db2becc9SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
2085db2becc9SJeremy L Thompson 
2086db2becc9SJeremy L Thompson   @ref User
2087db2becc9SJeremy L Thompson **/
CeedBasisApplyAdd(CeedBasis basis,CeedInt num_elem,CeedTransposeMode t_mode,CeedEvalMode eval_mode,CeedVector u,CeedVector v)2088db2becc9SJeremy L Thompson int CeedBasisApplyAdd(CeedBasis basis, CeedInt num_elem, CeedTransposeMode t_mode, CeedEvalMode eval_mode, CeedVector u, CeedVector v) {
2089db2becc9SJeremy L Thompson   CeedCheck(t_mode == CEED_TRANSPOSE, CeedBasisReturnCeed(basis), CEED_ERROR_UNSUPPORTED, "CeedBasisApplyAdd only supports CEED_TRANSPOSE");
2090db2becc9SJeremy L Thompson   CeedCall(CeedBasisApplyCheckDims(basis, num_elem, t_mode, eval_mode, u, v));
2091db2becc9SJeremy L Thompson   CeedCheck(basis->ApplyAdd, CeedBasisReturnCeed(basis), CEED_ERROR_UNSUPPORTED, "Backend does not implement CeedBasisApplyAdd");
2092db2becc9SJeremy L Thompson   CeedCall(basis->ApplyAdd(basis, num_elem, t_mode, eval_mode, u, v));
2093db2becc9SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2094db2becc9SJeremy L Thompson }
2095db2becc9SJeremy L Thompson 
2096db2becc9SJeremy L Thompson /**
2097db2becc9SJeremy L Thompson   @brief Apply basis evaluation from nodes to arbitrary points
2098db2becc9SJeremy L Thompson 
2099db2becc9SJeremy L Thompson   @param[in]  basis      `CeedBasis` to evaluate
2100db2becc9SJeremy L Thompson   @param[in]  num_elem   The number of elements to apply the basis evaluation to;
2101db2becc9SJeremy L Thompson                           the backend will specify the ordering in @ref CeedElemRestrictionCreate()
2102db2becc9SJeremy L Thompson   @param[in]  num_points Array of the number of points to apply the basis evaluation to in each element, size `num_elem`
2103db2becc9SJeremy L Thompson   @param[in]  t_mode     @ref CEED_NOTRANSPOSE to evaluate from nodes to points;
2104db2becc9SJeremy L Thompson                            @ref CEED_TRANSPOSE to apply the transpose, mapping from points to nodes
2105db2becc9SJeremy L Thompson   @param[in]  eval_mode  @ref CEED_EVAL_INTERP to use interpolated values,
2106db2becc9SJeremy L Thompson                            @ref CEED_EVAL_GRAD to use gradients,
2107db2becc9SJeremy L Thompson                            @ref CEED_EVAL_WEIGHT to use quadrature weights
2108db2becc9SJeremy L Thompson   @param[in]  x_ref      `CeedVector` holding reference coordinates of each point
2109db2becc9SJeremy L Thompson   @param[in]  u          Input `CeedVector`, of length `num_nodes * num_comp` for @ref CEED_NOTRANSPOSE
2110db2becc9SJeremy L Thompson   @param[out] v          Output `CeedVector`, of length `num_points * num_q_comp` for @ref CEED_NOTRANSPOSE with @ref CEED_EVAL_INTERP
2111db2becc9SJeremy L Thompson 
2112db2becc9SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
2113db2becc9SJeremy L Thompson 
2114db2becc9SJeremy L Thompson   @ref User
2115db2becc9SJeremy L Thompson **/
CeedBasisApplyAtPoints(CeedBasis basis,CeedInt num_elem,const CeedInt * num_points,CeedTransposeMode t_mode,CeedEvalMode eval_mode,CeedVector x_ref,CeedVector u,CeedVector v)2116db2becc9SJeremy L Thompson int CeedBasisApplyAtPoints(CeedBasis basis, CeedInt num_elem, const CeedInt *num_points, CeedTransposeMode t_mode, CeedEvalMode eval_mode,
2117db2becc9SJeremy L Thompson                            CeedVector x_ref, CeedVector u, CeedVector v) {
2118db2becc9SJeremy L Thompson   CeedCall(CeedBasisApplyAtPointsCheckDims(basis, num_elem, num_points, t_mode, eval_mode, x_ref, u, v));
2119db2becc9SJeremy L Thompson   if (basis->ApplyAtPoints) {
2120db2becc9SJeremy L Thompson     CeedCall(basis->ApplyAtPoints(basis, num_elem, num_points, t_mode, eval_mode, x_ref, u, v));
2121db2becc9SJeremy L Thompson   } else {
2122db2becc9SJeremy L Thompson     CeedCall(CeedBasisApplyAtPoints_Core(basis, false, num_elem, num_points, t_mode, eval_mode, x_ref, u, v));
2123db2becc9SJeremy L Thompson   }
2124db2becc9SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2125db2becc9SJeremy L Thompson }
2126db2becc9SJeremy L Thompson 
2127db2becc9SJeremy L Thompson /**
2128db2becc9SJeremy L Thompson   @brief Apply basis evaluation from nodes to arbitrary points and sum into target vector
2129db2becc9SJeremy L Thompson 
2130db2becc9SJeremy L Thompson   @param[in]  basis      `CeedBasis` to evaluate
2131db2becc9SJeremy L Thompson   @param[in]  num_elem   The number of elements to apply the basis evaluation to;
2132db2becc9SJeremy L Thompson                           the backend will specify the ordering in @ref CeedElemRestrictionCreate()
2133db2becc9SJeremy L Thompson   @param[in]  num_points Array of the number of points to apply the basis evaluation to in each element, size `num_elem`
2134db2becc9SJeremy L Thompson   @param[in]  t_mode     @ref CEED_NOTRANSPOSE to evaluate from nodes to points;
2135db2becc9SJeremy L Thompson                            @ref CEED_NOTRANSPOSE is not valid for `CeedBasisApplyAddAtPoints()`
2136db2becc9SJeremy L Thompson   @param[in]  eval_mode  @ref CEED_EVAL_INTERP to use interpolated values,
2137db2becc9SJeremy L Thompson                            @ref CEED_EVAL_GRAD to use gradients,
2138db2becc9SJeremy L Thompson                            @ref CEED_EVAL_WEIGHT to use quadrature weights
2139db2becc9SJeremy L Thompson   @param[in]  x_ref      `CeedVector` holding reference coordinates of each point
2140db2becc9SJeremy L Thompson   @param[in]  u          Input `CeedVector`, of length `num_nodes * num_comp` for @ref CEED_NOTRANSPOSE
2141db2becc9SJeremy L Thompson   @param[out] v          Output `CeedVector`, of length `num_points * num_q_comp` for @ref CEED_NOTRANSPOSE with @ref CEED_EVAL_INTERP
2142db2becc9SJeremy L Thompson 
2143db2becc9SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
2144db2becc9SJeremy L Thompson 
2145db2becc9SJeremy L Thompson   @ref User
2146db2becc9SJeremy L Thompson **/
CeedBasisApplyAddAtPoints(CeedBasis basis,CeedInt num_elem,const CeedInt * num_points,CeedTransposeMode t_mode,CeedEvalMode eval_mode,CeedVector x_ref,CeedVector u,CeedVector v)2147db2becc9SJeremy L Thompson int CeedBasisApplyAddAtPoints(CeedBasis basis, CeedInt num_elem, const CeedInt *num_points, CeedTransposeMode t_mode, CeedEvalMode eval_mode,
2148db2becc9SJeremy L Thompson                               CeedVector x_ref, CeedVector u, CeedVector v) {
2149db2becc9SJeremy L Thompson   CeedCheck(t_mode == CEED_TRANSPOSE, CeedBasisReturnCeed(basis), CEED_ERROR_UNSUPPORTED, "CeedBasisApplyAddAtPoints only supports CEED_TRANSPOSE");
2150db2becc9SJeremy L Thompson   CeedCall(CeedBasisApplyAtPointsCheckDims(basis, num_elem, num_points, t_mode, eval_mode, x_ref, u, v));
2151db2becc9SJeremy L Thompson   if (basis->ApplyAddAtPoints) {
2152db2becc9SJeremy L Thompson     CeedCall(basis->ApplyAddAtPoints(basis, num_elem, num_points, t_mode, eval_mode, x_ref, u, v));
2153db2becc9SJeremy L Thompson   } else {
2154db2becc9SJeremy L Thompson     CeedCall(CeedBasisApplyAtPoints_Core(basis, true, num_elem, num_points, t_mode, eval_mode, x_ref, u, v));
2155db2becc9SJeremy L Thompson   }
2156db2becc9SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2157db2becc9SJeremy L Thompson }
2158db2becc9SJeremy L Thompson 
2159db2becc9SJeremy L Thompson /**
21606e536b99SJeremy L Thompson   @brief Get the `Ceed` associated with a `CeedBasis`
2161b7c9bbdaSJeremy L Thompson 
2162ca94c3ddSJeremy L Thompson   @param[in]  basis `CeedBasis`
2163ca94c3ddSJeremy L Thompson   @param[out] ceed  Variable to store `Ceed`
2164b7c9bbdaSJeremy L Thompson 
2165b7c9bbdaSJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
2166b7c9bbdaSJeremy L Thompson 
2167b7c9bbdaSJeremy L Thompson   @ref Advanced
2168b7c9bbdaSJeremy L Thompson **/
CeedBasisGetCeed(CeedBasis basis,Ceed * ceed)2169b7c9bbdaSJeremy L Thompson int CeedBasisGetCeed(CeedBasis basis, Ceed *ceed) {
2170b0f67a9cSJeremy L Thompson   CeedCall(CeedObjectGetCeed((CeedObject)basis, ceed));
2171b7c9bbdaSJeremy L Thompson   return CEED_ERROR_SUCCESS;
2172b7c9bbdaSJeremy L Thompson }
2173b7c9bbdaSJeremy L Thompson 
2174b7c9bbdaSJeremy L Thompson /**
21756e536b99SJeremy L Thompson   @brief Return the `Ceed` associated with a `CeedBasis`
21766e536b99SJeremy L Thompson 
21776e536b99SJeremy L Thompson   @param[in] basis `CeedBasis`
21786e536b99SJeremy L Thompson 
21796e536b99SJeremy L Thompson   @return `Ceed` associated with the `basis`
21806e536b99SJeremy L Thompson 
21816e536b99SJeremy L Thompson   @ref Advanced
21826e536b99SJeremy L Thompson **/
CeedBasisReturnCeed(CeedBasis basis)2183b0f67a9cSJeremy L Thompson Ceed CeedBasisReturnCeed(CeedBasis basis) { return CeedObjectReturnCeed((CeedObject)basis); }
21846e536b99SJeremy L Thompson 
21856e536b99SJeremy L Thompson /**
2186ca94c3ddSJeremy L Thompson   @brief Get dimension for given `CeedBasis`
21879d007619Sjeremylt 
2188ca94c3ddSJeremy L Thompson   @param[in]  basis `CeedBasis`
21899d007619Sjeremylt   @param[out] dim   Variable to store dimension of basis
21909d007619Sjeremylt 
21919d007619Sjeremylt   @return An error code: 0 - success, otherwise - failure
21929d007619Sjeremylt 
2193b7c9bbdaSJeremy L Thompson   @ref Advanced
21949d007619Sjeremylt **/
CeedBasisGetDimension(CeedBasis basis,CeedInt * dim)21959d007619Sjeremylt int CeedBasisGetDimension(CeedBasis basis, CeedInt *dim) {
21969d007619Sjeremylt   *dim = basis->dim;
2197e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
21989d007619Sjeremylt }
21999d007619Sjeremylt 
22009d007619Sjeremylt /**
2201ca94c3ddSJeremy L Thompson   @brief Get topology for given `CeedBasis`
2202d99fa3c5SJeremy L Thompson 
2203ca94c3ddSJeremy L Thompson   @param[in]  basis `CeedBasis`
2204d99fa3c5SJeremy L Thompson   @param[out] topo  Variable to store topology of basis
2205d99fa3c5SJeremy L Thompson 
2206d99fa3c5SJeremy L Thompson   @return An error code: 0 - success, otherwise - failure
2207d99fa3c5SJeremy L Thompson 
2208b7c9bbdaSJeremy L Thompson   @ref Advanced
2209d99fa3c5SJeremy L Thompson **/
CeedBasisGetTopology(CeedBasis basis,CeedElemTopology * topo)2210d99fa3c5SJeremy L Thompson int CeedBasisGetTopology(CeedBasis basis, CeedElemTopology *topo) {
2211d99fa3c5SJeremy L Thompson   *topo = basis->topo;
2212e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2213d99fa3c5SJeremy L Thompson }
2214d99fa3c5SJeremy L Thompson 
2215d99fa3c5SJeremy L Thompson /**
2216ca94c3ddSJeremy L Thompson   @brief Get number of components for given `CeedBasis`
22179d007619Sjeremylt 
2218ca94c3ddSJeremy L Thompson   @param[in]  basis    `CeedBasis`
2219ca94c3ddSJeremy L Thompson   @param[out] num_comp Variable to store number of components
22209d007619Sjeremylt 
22219d007619Sjeremylt   @return An error code: 0 - success, otherwise - failure
22229d007619Sjeremylt 
2223b7c9bbdaSJeremy L Thompson   @ref Advanced
22249d007619Sjeremylt **/
CeedBasisGetNumComponents(CeedBasis basis,CeedInt * num_comp)2225d1d35e2fSjeremylt int CeedBasisGetNumComponents(CeedBasis basis, CeedInt *num_comp) {
2226d1d35e2fSjeremylt   *num_comp = basis->num_comp;
2227e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
22289d007619Sjeremylt }
22299d007619Sjeremylt 
22309d007619Sjeremylt /**
2231ca94c3ddSJeremy L Thompson   @brief Get total number of nodes (in `dim` dimensions) of a `CeedBasis`
22329d007619Sjeremylt 
2233ca94c3ddSJeremy L Thompson   @param[in]  basis `CeedBasis`
22349d007619Sjeremylt   @param[out] P     Variable to store number of nodes
22359d007619Sjeremylt 
22369d007619Sjeremylt   @return An error code: 0 - success, otherwise - failure
22379d007619Sjeremylt 
22389d007619Sjeremylt   @ref Utility
22399d007619Sjeremylt **/
CeedBasisGetNumNodes(CeedBasis basis,CeedInt * P)22409d007619Sjeremylt int CeedBasisGetNumNodes(CeedBasis basis, CeedInt *P) {
22419d007619Sjeremylt   *P = basis->P;
2242e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
22439d007619Sjeremylt }
22449d007619Sjeremylt 
22459d007619Sjeremylt /**
2246ca94c3ddSJeremy L Thompson   @brief Get total number of nodes (in 1 dimension) of a `CeedBasis`
22479d007619Sjeremylt 
2248ca94c3ddSJeremy L Thompson   @param[in]  basis `CeedBasis`
2249d1d35e2fSjeremylt   @param[out] P_1d  Variable to store number of nodes
22509d007619Sjeremylt 
22519d007619Sjeremylt   @return An error code: 0 - success, otherwise - failure
22529d007619Sjeremylt 
2253b7c9bbdaSJeremy L Thompson   @ref Advanced
22549d007619Sjeremylt **/
CeedBasisGetNumNodes1D(CeedBasis basis,CeedInt * P_1d)2255d1d35e2fSjeremylt int CeedBasisGetNumNodes1D(CeedBasis basis, CeedInt *P_1d) {
22566e536b99SJeremy L Thompson   CeedCheck(basis->is_tensor_basis, CeedBasisReturnCeed(basis), CEED_ERROR_MINOR, "Cannot supply P_1d for non-tensor CeedBasis");
2257d1d35e2fSjeremylt   *P_1d = basis->P_1d;
2258e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
22599d007619Sjeremylt }
22609d007619Sjeremylt 
22619d007619Sjeremylt /**
2262ca94c3ddSJeremy L Thompson   @brief Get total number of quadrature points (in `dim` dimensions) of a `CeedBasis`
22639d007619Sjeremylt 
2264ca94c3ddSJeremy L Thompson   @param[in]  basis `CeedBasis`
22659d007619Sjeremylt   @param[out] Q     Variable to store number of quadrature points
22669d007619Sjeremylt 
22679d007619Sjeremylt   @return An error code: 0 - success, otherwise - failure
22689d007619Sjeremylt 
22699d007619Sjeremylt   @ref Utility
22709d007619Sjeremylt **/
CeedBasisGetNumQuadraturePoints(CeedBasis basis,CeedInt * Q)22719d007619Sjeremylt int CeedBasisGetNumQuadraturePoints(CeedBasis basis, CeedInt *Q) {
22729d007619Sjeremylt   *Q = basis->Q;
2273e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
22749d007619Sjeremylt }
22759d007619Sjeremylt 
22769d007619Sjeremylt /**
2277ca94c3ddSJeremy L Thompson   @brief Get total number of quadrature points (in 1 dimension) of a `CeedBasis`
22789d007619Sjeremylt 
2279ca94c3ddSJeremy L Thompson   @param[in]  basis `CeedBasis`
2280d1d35e2fSjeremylt   @param[out] Q_1d  Variable to store number of quadrature points
22819d007619Sjeremylt 
22829d007619Sjeremylt   @return An error code: 0 - success, otherwise - failure
22839d007619Sjeremylt 
2284b7c9bbdaSJeremy L Thompson   @ref Advanced
22859d007619Sjeremylt **/
CeedBasisGetNumQuadraturePoints1D(CeedBasis basis,CeedInt * Q_1d)2286d1d35e2fSjeremylt int CeedBasisGetNumQuadraturePoints1D(CeedBasis basis, CeedInt *Q_1d) {
22876e536b99SJeremy L Thompson   CeedCheck(basis->is_tensor_basis, CeedBasisReturnCeed(basis), CEED_ERROR_MINOR, "Cannot supply Q_1d for non-tensor CeedBasis");
2288d1d35e2fSjeremylt   *Q_1d = basis->Q_1d;
2289e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
22909d007619Sjeremylt }
22919d007619Sjeremylt 
22929d007619Sjeremylt /**
2293ca94c3ddSJeremy L Thompson   @brief Get reference coordinates of quadrature points (in `dim` dimensions) of a `CeedBasis`
22949d007619Sjeremylt 
2295ca94c3ddSJeremy L Thompson   @param[in]  basis `CeedBasis`
2296d1d35e2fSjeremylt   @param[out] q_ref Variable to store reference coordinates of quadrature points
22979d007619Sjeremylt 
22989d007619Sjeremylt   @return An error code: 0 - success, otherwise - failure
22999d007619Sjeremylt 
2300b7c9bbdaSJeremy L Thompson   @ref Advanced
23019d007619Sjeremylt **/
CeedBasisGetQRef(CeedBasis basis,const CeedScalar ** q_ref)2302d1d35e2fSjeremylt int CeedBasisGetQRef(CeedBasis basis, const CeedScalar **q_ref) {
2303d1d35e2fSjeremylt   *q_ref = basis->q_ref_1d;
2304e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
23059d007619Sjeremylt }
23069d007619Sjeremylt 
23079d007619Sjeremylt /**
2308ca94c3ddSJeremy L Thompson   @brief Get quadrature weights of quadrature points (in `dim` dimensions) of a `CeedBasis`
23099d007619Sjeremylt 
2310ca94c3ddSJeremy L Thompson   @param[in]  basis    `CeedBasis`
2311d1d35e2fSjeremylt   @param[out] q_weight Variable to store quadrature weights
23129d007619Sjeremylt 
23139d007619Sjeremylt   @return An error code: 0 - success, otherwise - failure
23149d007619Sjeremylt 
2315b7c9bbdaSJeremy L Thompson   @ref Advanced
23169d007619Sjeremylt **/
CeedBasisGetQWeights(CeedBasis basis,const CeedScalar ** q_weight)2317d1d35e2fSjeremylt int CeedBasisGetQWeights(CeedBasis basis, const CeedScalar **q_weight) {
2318d1d35e2fSjeremylt   *q_weight = basis->q_weight_1d;
2319e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
23209d007619Sjeremylt }
23219d007619Sjeremylt 
23229d007619Sjeremylt /**
2323ca94c3ddSJeremy L Thompson   @brief Get interpolation matrix of a `CeedBasis`
23249d007619Sjeremylt 
2325ca94c3ddSJeremy L Thompson   @param[in]  basis  `CeedBasis`
23269d007619Sjeremylt   @param[out] interp Variable to store interpolation matrix
23279d007619Sjeremylt 
23289d007619Sjeremylt   @return An error code: 0 - success, otherwise - failure
23299d007619Sjeremylt 
2330b7c9bbdaSJeremy L Thompson   @ref Advanced
23319d007619Sjeremylt **/
CeedBasisGetInterp(CeedBasis basis,const CeedScalar ** interp)23326c58de82SJeremy L Thompson int CeedBasisGetInterp(CeedBasis basis, const CeedScalar **interp) {
23336402da51SJeremy L Thompson   if (!basis->interp && basis->is_tensor_basis) {
23349d007619Sjeremylt     // Allocate
23352b730f8bSJeremy L Thompson     CeedCall(CeedMalloc(basis->Q * basis->P, &basis->interp));
23369d007619Sjeremylt 
23379d007619Sjeremylt     // Initialize
23382b730f8bSJeremy L Thompson     for (CeedInt i = 0; i < basis->Q * basis->P; i++) basis->interp[i] = 1.0;
23399d007619Sjeremylt 
23409d007619Sjeremylt     // Calculate
23412b730f8bSJeremy L Thompson     for (CeedInt d = 0; d < basis->dim; d++) {
23422b730f8bSJeremy L Thompson       for (CeedInt qpt = 0; qpt < basis->Q; qpt++) {
23439d007619Sjeremylt         for (CeedInt node = 0; node < basis->P; node++) {
2344d1d35e2fSjeremylt           CeedInt p = (node / CeedIntPow(basis->P_1d, d)) % basis->P_1d;
2345d1d35e2fSjeremylt           CeedInt q = (qpt / CeedIntPow(basis->Q_1d, d)) % basis->Q_1d;
23461c66c397SJeremy L Thompson 
2347d1d35e2fSjeremylt           basis->interp[qpt * (basis->P) + node] *= basis->interp_1d[q * basis->P_1d + p];
23489d007619Sjeremylt         }
23499d007619Sjeremylt       }
23502b730f8bSJeremy L Thompson     }
23512b730f8bSJeremy L Thompson   }
23529d007619Sjeremylt   *interp = basis->interp;
2353e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
23549d007619Sjeremylt }
23559d007619Sjeremylt 
23569d007619Sjeremylt /**
2357ca94c3ddSJeremy L Thompson   @brief Get 1D interpolation matrix of a tensor product `CeedBasis`
23589d007619Sjeremylt 
2359ca94c3ddSJeremy L Thompson   @param[in]  basis     `CeedBasis`
2360d1d35e2fSjeremylt   @param[out] interp_1d Variable to store interpolation matrix
23619d007619Sjeremylt 
23629d007619Sjeremylt   @return An error code: 0 - success, otherwise - failure
23639d007619Sjeremylt 
23649d007619Sjeremylt   @ref Backend
23659d007619Sjeremylt **/
CeedBasisGetInterp1D(CeedBasis basis,const CeedScalar ** interp_1d)2366d1d35e2fSjeremylt int CeedBasisGetInterp1D(CeedBasis basis, const CeedScalar **interp_1d) {
23671203703bSJeremy L Thompson   bool is_tensor_basis;
23681203703bSJeremy L Thompson 
23691203703bSJeremy L Thompson   CeedCall(CeedBasisIsTensor(basis, &is_tensor_basis));
23706e536b99SJeremy L Thompson   CeedCheck(is_tensor_basis, CeedBasisReturnCeed(basis), CEED_ERROR_MINOR, "CeedBasis is not a tensor product CeedBasis");
2371d1d35e2fSjeremylt   *interp_1d = basis->interp_1d;
2372e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
23739d007619Sjeremylt }
23749d007619Sjeremylt 
23759d007619Sjeremylt /**
2376ca94c3ddSJeremy L Thompson   @brief Get gradient matrix of a `CeedBasis`
23779d007619Sjeremylt 
2378ca94c3ddSJeremy L Thompson   @param[in]  basis `CeedBasis`
23799d007619Sjeremylt   @param[out] grad  Variable to store gradient matrix
23809d007619Sjeremylt 
23819d007619Sjeremylt   @return An error code: 0 - success, otherwise - failure
23829d007619Sjeremylt 
2383b7c9bbdaSJeremy L Thompson   @ref Advanced
23849d007619Sjeremylt **/
CeedBasisGetGrad(CeedBasis basis,const CeedScalar ** grad)23856c58de82SJeremy L Thompson int CeedBasisGetGrad(CeedBasis basis, const CeedScalar **grad) {
23866402da51SJeremy L Thompson   if (!basis->grad && basis->is_tensor_basis) {
23879d007619Sjeremylt     // Allocate
23882b730f8bSJeremy L Thompson     CeedCall(CeedMalloc(basis->dim * basis->Q * basis->P, &basis->grad));
23899d007619Sjeremylt 
23909d007619Sjeremylt     // Initialize
23912b730f8bSJeremy L Thompson     for (CeedInt i = 0; i < basis->dim * basis->Q * basis->P; i++) basis->grad[i] = 1.0;
23929d007619Sjeremylt 
23939d007619Sjeremylt     // Calculate
23942b730f8bSJeremy L Thompson     for (CeedInt d = 0; d < basis->dim; d++) {
23952b730f8bSJeremy L Thompson       for (CeedInt i = 0; i < basis->dim; i++) {
23962b730f8bSJeremy L Thompson         for (CeedInt qpt = 0; qpt < basis->Q; qpt++) {
23979d007619Sjeremylt           for (CeedInt node = 0; node < basis->P; node++) {
2398d1d35e2fSjeremylt             CeedInt p = (node / CeedIntPow(basis->P_1d, d)) % basis->P_1d;
2399d1d35e2fSjeremylt             CeedInt q = (qpt / CeedIntPow(basis->Q_1d, d)) % basis->Q_1d;
24001c66c397SJeremy L Thompson 
24012b730f8bSJeremy L Thompson             if (i == d) basis->grad[(i * basis->Q + qpt) * (basis->P) + node] *= basis->grad_1d[q * basis->P_1d + p];
24022b730f8bSJeremy L Thompson             else basis->grad[(i * basis->Q + qpt) * (basis->P) + node] *= basis->interp_1d[q * basis->P_1d + p];
24032b730f8bSJeremy L Thompson           }
24042b730f8bSJeremy L Thompson         }
24052b730f8bSJeremy L Thompson       }
24069d007619Sjeremylt     }
24079d007619Sjeremylt   }
24089d007619Sjeremylt   *grad = basis->grad;
2409e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
24109d007619Sjeremylt }
24119d007619Sjeremylt 
24129d007619Sjeremylt /**
2413ca94c3ddSJeremy L Thompson   @brief Get 1D gradient matrix of a tensor product `CeedBasis`
24149d007619Sjeremylt 
2415ca94c3ddSJeremy L Thompson   @param[in]  basis   `CeedBasis`
2416d1d35e2fSjeremylt   @param[out] grad_1d Variable to store gradient matrix
24179d007619Sjeremylt 
24189d007619Sjeremylt   @return An error code: 0 - success, otherwise - failure
24199d007619Sjeremylt 
2420b7c9bbdaSJeremy L Thompson   @ref Advanced
24219d007619Sjeremylt **/
CeedBasisGetGrad1D(CeedBasis basis,const CeedScalar ** grad_1d)2422d1d35e2fSjeremylt int CeedBasisGetGrad1D(CeedBasis basis, const CeedScalar **grad_1d) {
24231203703bSJeremy L Thompson   bool is_tensor_basis;
24241203703bSJeremy L Thompson 
24251203703bSJeremy L Thompson   CeedCall(CeedBasisIsTensor(basis, &is_tensor_basis));
24266e536b99SJeremy L Thompson   CeedCheck(is_tensor_basis, CeedBasisReturnCeed(basis), CEED_ERROR_MINOR, "CeedBasis is not a tensor product CeedBasis");
2427d1d35e2fSjeremylt   *grad_1d = basis->grad_1d;
2428e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
24299d007619Sjeremylt }
24309d007619Sjeremylt 
24319d007619Sjeremylt /**
2432ca94c3ddSJeremy L Thompson   @brief Get divergence matrix of a `CeedBasis`
243350c301a5SRezgar Shakeri 
2434ca94c3ddSJeremy L Thompson   @param[in]  basis `CeedBasis`
243550c301a5SRezgar Shakeri   @param[out] div   Variable to store divergence matrix
243650c301a5SRezgar Shakeri 
243750c301a5SRezgar Shakeri   @return An error code: 0 - success, otherwise - failure
243850c301a5SRezgar Shakeri 
243950c301a5SRezgar Shakeri   @ref Advanced
244050c301a5SRezgar Shakeri **/
CeedBasisGetDiv(CeedBasis basis,const CeedScalar ** div)244150c301a5SRezgar Shakeri int CeedBasisGetDiv(CeedBasis basis, const CeedScalar **div) {
244250c301a5SRezgar Shakeri   *div = basis->div;
244350c301a5SRezgar Shakeri   return CEED_ERROR_SUCCESS;
244450c301a5SRezgar Shakeri }
244550c301a5SRezgar Shakeri 
244650c301a5SRezgar Shakeri /**
2447ca94c3ddSJeremy L Thompson   @brief Get curl matrix of a `CeedBasis`
2448c4e3f59bSSebastian Grimberg 
2449ca94c3ddSJeremy L Thompson   @param[in]  basis `CeedBasis`
2450c4e3f59bSSebastian Grimberg   @param[out] curl  Variable to store curl matrix
2451c4e3f59bSSebastian Grimberg 
2452c4e3f59bSSebastian Grimberg   @return An error code: 0 - success, otherwise - failure
2453c4e3f59bSSebastian Grimberg 
2454c4e3f59bSSebastian Grimberg   @ref Advanced
2455c4e3f59bSSebastian Grimberg **/
CeedBasisGetCurl(CeedBasis basis,const CeedScalar ** curl)2456c4e3f59bSSebastian Grimberg int CeedBasisGetCurl(CeedBasis basis, const CeedScalar **curl) {
2457c4e3f59bSSebastian Grimberg   *curl = basis->curl;
2458c4e3f59bSSebastian Grimberg   return CEED_ERROR_SUCCESS;
2459c4e3f59bSSebastian Grimberg }
2460c4e3f59bSSebastian Grimberg 
2461c4e3f59bSSebastian Grimberg /**
2462ca94c3ddSJeremy L Thompson   @brief Destroy a @ref CeedBasis
24637a982d89SJeremy L. Thompson 
2464ca94c3ddSJeremy L Thompson   @param[in,out] basis `CeedBasis` to destroy
24657a982d89SJeremy L. Thompson 
24667a982d89SJeremy L. Thompson   @return An error code: 0 - success, otherwise - failure
24677a982d89SJeremy L. Thompson 
24687a982d89SJeremy L. Thompson   @ref User
24697a982d89SJeremy L. Thompson **/
CeedBasisDestroy(CeedBasis * basis)24707a982d89SJeremy L. Thompson int CeedBasisDestroy(CeedBasis *basis) {
2471b0f67a9cSJeremy L Thompson   if (!*basis || *basis == CEED_BASIS_NONE || CeedObjectDereference((CeedObject)*basis) > 0) {
2472ad6481ceSJeremy L Thompson     *basis = NULL;
2473ad6481ceSJeremy L Thompson     return CEED_ERROR_SUCCESS;
2474ad6481ceSJeremy L Thompson   }
24752b730f8bSJeremy L Thompson   if ((*basis)->Destroy) CeedCall((*basis)->Destroy(*basis));
24769831d45aSJeremy L Thompson   CeedCall(CeedTensorContractDestroy(&(*basis)->contract));
2477c4e3f59bSSebastian Grimberg   CeedCall(CeedFree(&(*basis)->q_ref_1d));
2478c4e3f59bSSebastian Grimberg   CeedCall(CeedFree(&(*basis)->q_weight_1d));
24792b730f8bSJeremy L Thompson   CeedCall(CeedFree(&(*basis)->interp));
24802b730f8bSJeremy L Thompson   CeedCall(CeedFree(&(*basis)->interp_1d));
24812b730f8bSJeremy L Thompson   CeedCall(CeedFree(&(*basis)->grad));
24822b730f8bSJeremy L Thompson   CeedCall(CeedFree(&(*basis)->grad_1d));
2483c4e3f59bSSebastian Grimberg   CeedCall(CeedFree(&(*basis)->div));
2484c4e3f59bSSebastian Grimberg   CeedCall(CeedFree(&(*basis)->curl));
2485c8c3fa7dSJeremy L Thompson   CeedCall(CeedVectorDestroy(&(*basis)->vec_chebyshev));
2486c8c3fa7dSJeremy L Thompson   CeedCall(CeedBasisDestroy(&(*basis)->basis_chebyshev));
2487*6c328a79SJeremy L Thompson   CeedCall(CeedObjectDestroy_Private(&(*basis)->obj));
24882b730f8bSJeremy L Thompson   CeedCall(CeedFree(basis));
2489e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
24907a982d89SJeremy L. Thompson }
24917a982d89SJeremy L. Thompson 
24927a982d89SJeremy L. Thompson /**
2493b11c1e72Sjeremylt   @brief Construct a Gauss-Legendre quadrature
2494b11c1e72Sjeremylt 
2495ca94c3ddSJeremy L Thompson   @param[in]  Q           Number of quadrature points (integrates polynomials of degree `2*Q-1` exactly)
2496ca94c3ddSJeremy L Thompson   @param[out] q_ref_1d    Array of length `Q` to hold the abscissa on `[-1, 1]`
2497ca94c3ddSJeremy L Thompson   @param[out] q_weight_1d Array of length `Q` to hold the weights
2498b11c1e72Sjeremylt 
2499b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
2500dfdf5a53Sjeremylt 
2501dfdf5a53Sjeremylt   @ref Utility
2502b11c1e72Sjeremylt **/
CeedGaussQuadrature(CeedInt Q,CeedScalar * q_ref_1d,CeedScalar * q_weight_1d)25032b730f8bSJeremy L Thompson int CeedGaussQuadrature(CeedInt Q, CeedScalar *q_ref_1d, CeedScalar *q_weight_1d) {
2504d7b241e6Sjeremylt   CeedScalar P0, P1, P2, dP2, xi, wi, PI = 4.0 * atan(1.0);
25051c66c397SJeremy L Thompson 
2506d1d35e2fSjeremylt   // Build q_ref_1d, q_weight_1d
250792ae7e47SJeremy L Thompson   for (CeedInt i = 0; i <= Q / 2; i++) {
2508d7b241e6Sjeremylt     // Guess
2509d7b241e6Sjeremylt     xi = cos(PI * (CeedScalar)(2 * i + 1) / ((CeedScalar)(2 * Q)));
2510d7b241e6Sjeremylt     // Pn(xi)
2511d7b241e6Sjeremylt     P0 = 1.0;
2512d7b241e6Sjeremylt     P1 = xi;
2513d7b241e6Sjeremylt     P2 = 0.0;
251492ae7e47SJeremy L Thompson     for (CeedInt j = 2; j <= Q; j++) {
2515d7b241e6Sjeremylt       P2 = (((CeedScalar)(2 * j - 1)) * xi * P1 - ((CeedScalar)(j - 1)) * P0) / ((CeedScalar)(j));
2516d7b241e6Sjeremylt       P0 = P1;
2517d7b241e6Sjeremylt       P1 = P2;
2518d7b241e6Sjeremylt     }
2519d7b241e6Sjeremylt     // First Newton Step
2520d7b241e6Sjeremylt     dP2 = (xi * P2 - P0) * (CeedScalar)Q / (xi * xi - 1.0);
2521d7b241e6Sjeremylt     xi  = xi - P2 / dP2;
2522d7b241e6Sjeremylt     // Newton to convergence
252392ae7e47SJeremy L Thompson     for (CeedInt k = 0; k < 100 && fabs(P2) > 10 * CEED_EPSILON; k++) {
2524d7b241e6Sjeremylt       P0 = 1.0;
2525d7b241e6Sjeremylt       P1 = xi;
252692ae7e47SJeremy L Thompson       for (CeedInt j = 2; j <= Q; j++) {
2527d7b241e6Sjeremylt         P2 = (((CeedScalar)(2 * j - 1)) * xi * P1 - ((CeedScalar)(j - 1)) * P0) / ((CeedScalar)(j));
2528d7b241e6Sjeremylt         P0 = P1;
2529d7b241e6Sjeremylt         P1 = P2;
2530d7b241e6Sjeremylt       }
2531d7b241e6Sjeremylt       dP2 = (xi * P2 - P0) * (CeedScalar)Q / (xi * xi - 1.0);
2532d7b241e6Sjeremylt       xi  = xi - P2 / dP2;
2533d7b241e6Sjeremylt     }
2534d7b241e6Sjeremylt     // Save xi, wi
2535d7b241e6Sjeremylt     wi                     = 2.0 / ((1.0 - xi * xi) * dP2 * dP2);
2536d1d35e2fSjeremylt     q_weight_1d[i]         = wi;
2537d1d35e2fSjeremylt     q_weight_1d[Q - 1 - i] = wi;
2538d1d35e2fSjeremylt     q_ref_1d[i]            = -xi;
2539d1d35e2fSjeremylt     q_ref_1d[Q - 1 - i]    = xi;
2540d7b241e6Sjeremylt   }
2541e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2542d7b241e6Sjeremylt }
2543d7b241e6Sjeremylt 
2544b11c1e72Sjeremylt /**
2545b11c1e72Sjeremylt   @brief Construct a Gauss-Legendre-Lobatto quadrature
2546b11c1e72Sjeremylt 
2547ca94c3ddSJeremy L Thompson   @param[in]  Q           Number of quadrature points (integrates polynomials of degree `2*Q-3` exactly)
2548ca94c3ddSJeremy L Thompson   @param[out] q_ref_1d    Array of length `Q` to hold the abscissa on `[-1, 1]`
2549ca94c3ddSJeremy L Thompson   @param[out] q_weight_1d Array of length `Q` to hold the weights
2550b11c1e72Sjeremylt 
2551b11c1e72Sjeremylt   @return An error code: 0 - success, otherwise - failure
2552dfdf5a53Sjeremylt 
2553dfdf5a53Sjeremylt   @ref Utility
2554b11c1e72Sjeremylt **/
CeedLobattoQuadrature(CeedInt Q,CeedScalar * q_ref_1d,CeedScalar * q_weight_1d)25552b730f8bSJeremy L Thompson int CeedLobattoQuadrature(CeedInt Q, CeedScalar *q_ref_1d, CeedScalar *q_weight_1d) {
2556d7b241e6Sjeremylt   CeedScalar P0, P1, P2, dP2, d2P2, xi, wi, PI = 4.0 * atan(1.0);
25571c66c397SJeremy L Thompson 
2558d1d35e2fSjeremylt   // Build q_ref_1d, q_weight_1d
2559d7b241e6Sjeremylt   // Set endpoints
25606574a04fSJeremy L Thompson   CeedCheck(Q > 1, NULL, CEED_ERROR_DIMENSION, "Cannot create Lobatto quadrature with Q=%" CeedInt_FMT " < 2 points", Q);
2561d7b241e6Sjeremylt   wi = 2.0 / ((CeedScalar)(Q * (Q - 1)));
2562d1d35e2fSjeremylt   if (q_weight_1d) {
2563d1d35e2fSjeremylt     q_weight_1d[0]     = wi;
2564d1d35e2fSjeremylt     q_weight_1d[Q - 1] = wi;
2565d7b241e6Sjeremylt   }
2566d1d35e2fSjeremylt   q_ref_1d[0]     = -1.0;
2567d1d35e2fSjeremylt   q_ref_1d[Q - 1] = 1.0;
2568d7b241e6Sjeremylt   // Interior
256992ae7e47SJeremy L Thompson   for (CeedInt i = 1; i <= (Q - 1) / 2; i++) {
2570d7b241e6Sjeremylt     // Guess
2571d7b241e6Sjeremylt     xi = cos(PI * (CeedScalar)(i) / (CeedScalar)(Q - 1));
2572d7b241e6Sjeremylt     // Pn(xi)
2573d7b241e6Sjeremylt     P0 = 1.0;
2574d7b241e6Sjeremylt     P1 = xi;
2575d7b241e6Sjeremylt     P2 = 0.0;
257692ae7e47SJeremy L Thompson     for (CeedInt j = 2; j < Q; j++) {
2577d7b241e6Sjeremylt       P2 = (((CeedScalar)(2 * j - 1)) * xi * P1 - ((CeedScalar)(j - 1)) * P0) / ((CeedScalar)(j));
2578d7b241e6Sjeremylt       P0 = P1;
2579d7b241e6Sjeremylt       P1 = P2;
2580d7b241e6Sjeremylt     }
2581d7b241e6Sjeremylt     // First Newton step
2582d7b241e6Sjeremylt     dP2  = (xi * P2 - P0) * (CeedScalar)Q / (xi * xi - 1.0);
2583d7b241e6Sjeremylt     d2P2 = (2 * xi * dP2 - (CeedScalar)(Q * (Q - 1)) * P2) / (1.0 - xi * xi);
2584d7b241e6Sjeremylt     xi   = xi - dP2 / d2P2;
2585d7b241e6Sjeremylt     // Newton to convergence
258692ae7e47SJeremy L Thompson     for (CeedInt k = 0; k < 100 && fabs(dP2) > 10 * CEED_EPSILON; k++) {
2587d7b241e6Sjeremylt       P0 = 1.0;
2588d7b241e6Sjeremylt       P1 = xi;
258992ae7e47SJeremy L Thompson       for (CeedInt j = 2; j < Q; j++) {
2590d7b241e6Sjeremylt         P2 = (((CeedScalar)(2 * j - 1)) * xi * P1 - ((CeedScalar)(j - 1)) * P0) / ((CeedScalar)(j));
2591d7b241e6Sjeremylt         P0 = P1;
2592d7b241e6Sjeremylt         P1 = P2;
2593d7b241e6Sjeremylt       }
2594d7b241e6Sjeremylt       dP2  = (xi * P2 - P0) * (CeedScalar)Q / (xi * xi - 1.0);
2595d7b241e6Sjeremylt       d2P2 = (2 * xi * dP2 - (CeedScalar)(Q * (Q - 1)) * P2) / (1.0 - xi * xi);
2596d7b241e6Sjeremylt       xi   = xi - dP2 / d2P2;
2597d7b241e6Sjeremylt     }
2598d7b241e6Sjeremylt     // Save xi, wi
2599d7b241e6Sjeremylt     wi = 2.0 / (((CeedScalar)(Q * (Q - 1))) * P2 * P2);
2600d1d35e2fSjeremylt     if (q_weight_1d) {
2601d1d35e2fSjeremylt       q_weight_1d[i]         = wi;
2602d1d35e2fSjeremylt       q_weight_1d[Q - 1 - i] = wi;
2603d7b241e6Sjeremylt     }
2604d1d35e2fSjeremylt     q_ref_1d[i]         = -xi;
2605d1d35e2fSjeremylt     q_ref_1d[Q - 1 - i] = xi;
2606d7b241e6Sjeremylt   }
2607e15f9bd0SJeremy L Thompson   return CEED_ERROR_SUCCESS;
2608d7b241e6Sjeremylt }
2609d7b241e6Sjeremylt 
2610d7b241e6Sjeremylt /// @}
2611