@@ -34,6 +34,53 @@ const CeedBasis CEED_BASIS_COLLOCATED = &ceed_basis_collocated;
3434/// @addtogroup CeedBasisDeveloper
3535/// @{
3636
37+ /**
38+ @brief Compute Chebyshev polynomial values at a point
39+
40+ @param[in] x Coordinate to evaluate Chebyshev polynomials at
41+ @param[in] n Number of Chebyshev polynomials to evaluate, n >= 2
42+ @param[out] chebyshev_x Array of Chebyshev polynomial values
43+
44+ @return An error code: 0 - success, otherwise - failure
45+
46+ @ref Developer
47+ **/
48+ static int CeedChebyshevPolynomialsAtPoint (CeedScalar x , CeedInt n , CeedScalar * chebyshev_x ) {
49+ chebyshev_x [0 ] = 1.0 ;
50+ chebyshev_x [1 ] = 2 * x ;
51+ for (CeedInt i = 2 ; i < n ; i ++ ) chebyshev_x [i ] = 2 * x * chebyshev_x [i - 1 ] - chebyshev_x [i - 2 ];
52+
53+ return CEED_ERROR_SUCCESS ;
54+ }
55+
56+ /**
57+ @brief Compute values of the derivative of Chebyshev polynomials at a point
58+
59+ @param[in] x Coordinate to evaluate derivative of Chebyshev polynomials at
60+ @param[in] n Number of Chebyshev polynomials to evaluate, n >= 2
61+ @param[out] chebyshev_x Array of Chebyshev polynomial derivative values
62+
63+ @return An error code: 0 - success, otherwise - failure
64+
65+ @ref Developer
66+ **/
67+ static int CeedChebyshevDerivativeAtPoint (CeedScalar x , CeedInt n , CeedScalar * chebyshev_dx ) {
68+ CeedScalar chebyshev_x [3 ];
69+
70+ chebyshev_x [1 ] = 1.0 ;
71+ chebyshev_x [2 ] = 2 * x ;
72+ chebyshev_dx [0 ] = 0.0 ;
73+ chebyshev_dx [1 ] = 2.0 ;
74+ for (CeedInt i = 2 ; i < n ; i ++ ) {
75+ chebyshev_x [0 ] = chebyshev_x [1 ];
76+ chebyshev_x [1 ] = chebyshev_x [2 ];
77+ chebyshev_x [2 ] = 2 * x * chebyshev_x [1 ] - chebyshev_x [0 ];
78+ chebyshev_dx [i ] = 2 * x * chebyshev_dx [i - 1 ] + 2 * chebyshev_x [1 ] - chebyshev_dx [i - 2 ];
79+ }
80+
81+ return CEED_ERROR_SUCCESS ;
82+ }
83+
3784/**
3885 @brief Compute Householder reflection
3986
@@ -1438,6 +1485,9 @@ int CeedBasisApplyAtPoints(CeedBasis basis, CeedInt num_points, CeedTransposeMod
14381485 (t_mode == CEED_NOTRANSPOSE && (v_length >= num_points * num_q_comp || u_length >= num_nodes * num_comp )));
14391486 break ;
14401487 case CEED_EVAL_GRAD :
1488+ good_dims = ((t_mode == CEED_TRANSPOSE && (u_length >= num_points * num_q_comp * dim || v_length >= num_nodes * num_comp )) ||
1489+ (t_mode == CEED_NOTRANSPOSE && (v_length >= num_points * num_q_comp * dim || u_length >= num_nodes * num_comp )));
1490+ break ;
14411491 case CEED_EVAL_NONE :
14421492 case CEED_EVAL_WEIGHT :
14431493 case CEED_EVAL_DIV :
@@ -1456,6 +1506,8 @@ int CeedBasisApplyAtPoints(CeedBasis basis, CeedInt num_points, CeedTransposeMod
14561506
14571507 // Default implementation
14581508 CeedCheck (basis -> is_tensor_basis , basis -> ceed , CEED_ERROR_UNSUPPORTED , "Evaluation at arbitrary points only supported for tensor product bases" );
1509+ CeedCheck (eval_mode == CEED_EVAL_INTERP || t_mode == CEED_NOTRANSPOSE , basis -> ceed , CEED_ERROR_UNSUPPORTED , "%s evaluation only supported for %s" ,
1510+ CeedEvalModes [eval_mode ], CeedTransposeModes [CEED_NOTRANSPOSE ]);
14591511 if (!basis -> basis_chebyshev ) {
14601512 // Build matrix mapping from quadrature point values to Chebyshev coefficients
14611513 CeedScalar * tau , * C , * I , * chebyshev_coeffs_1d ;
@@ -1466,13 +1518,7 @@ int CeedBasisApplyAtPoints(CeedBasis basis, CeedInt num_points, CeedTransposeMod
14661518 CeedCheck (P_1d > 0 && Q_1d > 0 , basis -> ceed , CEED_ERROR_INCOMPATIBLE , "Basis dimensions are malformed" );
14671519 CeedCall (CeedCalloc (Q_1d * Q_1d , & C ));
14681520 CeedCall (CeedBasisGetQRef (basis , & q_ref_1d ));
1469- for (CeedInt i = 0 ; i < Q_1d ; i ++ ) {
1470- const CeedScalar x = q_ref_1d [i ];
1471-
1472- C [i * Q_1d + 0 ] = 1.0 ;
1473- C [i * Q_1d + 1 ] = 2 * x ;
1474- for (CeedInt j = 2 ; j < Q_1d ; j ++ ) C [i * Q_1d + j ] = 2 * x * C [i * Q_1d + j - 1 ] - C [i * Q_1d + j - 2 ];
1475- }
1521+ for (CeedInt i = 0 ; i < Q_1d ; i ++ ) CeedCall (CeedChebyshevPolynomialsAtPoint (q_ref_1d [i ], Q_1d , & C [i * Q_1d ]));
14761522
14771523 // Inverse of coefficient matrix
14781524 CeedCall (CeedCalloc (Q_1d * Q_1d , & chebyshev_coeffs_1d ));
@@ -1546,36 +1592,61 @@ int CeedBasisApplyAtPoints(CeedBasis basis, CeedInt num_points, CeedTransposeMod
15461592 CeedCall (CeedVectorGetArrayRead (basis -> vec_chebyshev , CEED_MEM_HOST , & chebyshev_coeffs ));
15471593 CeedCall (CeedVectorGetArrayRead (x_ref , CEED_MEM_HOST , & x_array_read ));
15481594 CeedCall (CeedVectorGetArrayWrite (v , CEED_MEM_HOST , & v_array ));
1549- {
1550- CeedScalar tmp [2 ][num_comp * CeedIntPow (Q_1d , dim )], chebyshev_x [Q_1d ];
1551-
1552- // ---- Values at point
1553- for (CeedInt p = 0 ; p < num_points ; p ++ ) {
1554- CeedInt pre = num_comp * CeedIntPow (Q_1d , dim - 1 ), post = 1 ;
1555-
1556- for (CeedInt d = dim - 1 ; d >= 0 ; d -- ) {
1557- // ------ Compute Chebyshev polynomial values
1558- {
1559- const CeedScalar x = x_array_read [p * dim + d ];
1560-
1561- chebyshev_x [0 ] = 1.0 ;
1562- chebyshev_x [1 ] = 2 * x ;
1563- for (CeedInt j = 2 ; j < Q_1d ; j ++ ) chebyshev_x [j ] = 2 * x * chebyshev_x [j - 1 ] - chebyshev_x [j - 2 ];
1595+ switch (eval_mode ) {
1596+ case CEED_EVAL_INTERP : {
1597+ CeedScalar tmp [2 ][num_comp * CeedIntPow (Q_1d , dim )], chebyshev_x [Q_1d ];
1598+
1599+ // ---- Values at point
1600+ for (CeedInt p = 0 ; p < num_points ; p ++ ) {
1601+ CeedInt pre = num_comp * CeedIntPow (Q_1d , dim - 1 ), post = 1 ;
1602+
1603+ // Note: stepping "backwards" through the tensor contractions to agree with the ordering of the Chebyshev coefficients
1604+ for (CeedInt d = dim - 1 ; d >= 0 ; d -- ) {
1605+ // ------ Tensor contract with current Chebyshev polynomial values
1606+ CeedCall (CeedChebyshevPolynomialsAtPoint (x_array_read [p * dim + d ], Q_1d , chebyshev_x ));
1607+ CeedCall (CeedTensorContractApply (basis -> contract , pre , Q_1d , post , 1 , chebyshev_x , t_mode , false,
1608+ d == (dim - 1 ) ? chebyshev_coeffs : tmp [d % 2 ], d == 0 ? & v_array [p * num_comp ] : tmp [(d + 1 ) % 2 ]));
1609+ pre /= Q_1d ;
1610+ post *= 1 ;
15641611 }
1565- // ------ Tensor contract
1566- CeedCall (CeedTensorContractApply (basis -> contract , pre , Q_1d , post , 1 , chebyshev_x , t_mode , false,
1567- d == (dim - 1 ) ? chebyshev_coeffs : tmp [d % 2 ], d == 0 ? & v_array [p * num_comp ] : tmp [(d + 1 ) % 2 ]));
1568- pre /= Q_1d ;
1569- post *= 1 ;
15701612 }
1613+ break ;
15711614 }
1615+ case CEED_EVAL_GRAD : {
1616+ CeedScalar tmp [2 ][num_comp * CeedIntPow (Q_1d , dim )], chebyshev_x [Q_1d ];
1617+
1618+ // ---- Values at point
1619+ for (CeedInt p = 0 ; p < num_points ; p ++ ) {
1620+ // Note: stepping "backwards" through the tensor contractions to agree with the ordering of the Chebyshev coefficients
1621+ // Dim**2 contractions, apply grad when pass == dim
1622+ for (CeedInt pass = dim - 1 ; pass >= 0 ; pass -- ) {
1623+ CeedInt pre = num_comp * CeedIntPow (Q_1d , dim - 1 ), post = 1 ;
1624+
1625+ for (CeedInt d = dim - 1 ; d >= 0 ; d -- ) {
1626+ // ------ Tensor contract with current Chebyshev polynomial values
1627+ if (pass == d ) CeedCall (CeedChebyshevDerivativeAtPoint (x_array_read [p * dim + d ], Q_1d , chebyshev_x ));
1628+ else CeedCall (CeedChebyshevPolynomialsAtPoint (x_array_read [p * dim + d ], Q_1d , chebyshev_x ));
1629+ CeedCall (CeedTensorContractApply (basis -> contract , pre , Q_1d , post , 1 , chebyshev_x , t_mode , false,
1630+ d == (dim - 1 ) ? chebyshev_coeffs : tmp [d % 2 ],
1631+ d == 0 ? & v_array [p * num_comp * dim + pass ] : tmp [(d + 1 ) % 2 ]));
1632+ pre /= Q_1d ;
1633+ post *= 1 ;
1634+ }
1635+ }
1636+ }
1637+ break ;
1638+ }
1639+ default :
1640+ // Nothing to do, this won't occur
1641+ break ;
15721642 }
15731643 CeedCall (CeedVectorRestoreArrayRead (basis -> vec_chebyshev , & chebyshev_coeffs ));
15741644 CeedCall (CeedVectorRestoreArrayRead (x_ref , & x_array_read ));
15751645 CeedCall (CeedVectorRestoreArray (v , & v_array ));
15761646 break ;
15771647 }
15781648 case CEED_TRANSPOSE : {
1649+ // Note: No switch on e_mode here because only CEED_EVAL_INTERP is supported at this time
15791650 // Arbitrary points to nodes
15801651 CeedScalar * chebyshev_coeffs ;
15811652 const CeedScalar * u_array , * x_array_read ;
@@ -1591,16 +1662,10 @@ int CeedBasisApplyAtPoints(CeedBasis basis, CeedInt num_points, CeedTransposeMod
15911662 for (CeedInt p = 0 ; p < num_points ; p ++ ) {
15921663 CeedInt pre = num_comp * 1 , post = 1 ;
15931664
1665+ // Note: stepping "backwards" through the tensor contractions to agree with the ordering of the Chebyshev coefficients
15941666 for (CeedInt d = dim - 1 ; d >= 0 ; d -- ) {
1595- // ------ Compute Chebyshev polynomial values
1596- {
1597- const CeedScalar x = x_array_read [p * dim + d ];
1598-
1599- chebyshev_x [0 ] = 1.0 ;
1600- chebyshev_x [1 ] = 2 * x ;
1601- for (CeedInt j = 2 ; j < Q_1d ; j ++ ) chebyshev_x [j ] = 2 * x * chebyshev_x [j - 1 ] - chebyshev_x [j - 2 ];
1602- }
1603- // ------ Tensor contract
1667+ // ------ Tensor contract with current Chebyshev polynomial values
1668+ CeedCall (CeedChebyshevPolynomialsAtPoint (x_array_read [p * dim + d ], Q_1d , chebyshev_x ));
16041669 CeedCall (CeedTensorContractApply (basis -> contract , pre , 1 , post , Q_1d , chebyshev_x , t_mode , p > 0 && d == 0 ,
16051670 d == (dim - 1 ) ? & u_array [p * num_comp ] : tmp [d % 2 ], d == 0 ? chebyshev_coeffs : tmp [(d + 1 ) % 2 ]));
16061671 pre /= 1 ;
0 commit comments