2 * \brief Various index conversion functions.
4 #ifndef QPMS_INDEXING_H
5 #define QPMS_INDEXING_H
7 #include "qpms_types.h"
13 static inline qpms_y_t
qpms_mn2y(qpms_m_t m
, qpms_l_t n
) {
14 return n
* (n
+ 1) + m
- 1;
17 static inline qpms_lm_t
qpms_y2n(qpms_y_t y
) {
18 //return (sqrt(5+y)-2)/2; // the cast will truncate the fractional part, which is what we want
22 static inline qpms_m_t
qpms_yn2m(qpms_y_t y
, qpms_l_t n
) {
23 return y
-qpms_mn2y(0,n
);
26 static inline void qpms_y2mn_p(qpms_y_t y
, qpms_m_t
*m
, qpms_l_t
*n
){
27 *m
=qpms_yn2m(y
,*n
=qpms_y2n(y
));
30 static inline qpms_y_t
qpms_lMax2nelem(qpms_l_t lmax
){
31 return lmax
* ((qpms_y_t
)lmax
+ 2);
34 // Scalar versions: they have a place for the 0, 0 term in the beginning
36 static inline qpms_y_t
qpms_mn2y_sc(qpms_m_t m
, qpms_l_t n
) {
37 return n
* (n
+ 1) + m
;
40 static inline qpms_lm_t
qpms_y2n_sc(qpms_y_t y
) {
41 //return (sqrt(5+y)-2)/2; // the cast will truncate the fractional part, which is what we want
45 static inline qpms_m_t
qpms_yn2m_sc(qpms_y_t y
, qpms_l_t n
) {
46 return y
-qpms_mn2y_sc(0,n
);
49 static inline void qpms_y2mn_sc_p(qpms_y_t y
, qpms_m_t
*m
, qpms_l_t
*n
){
50 *m
=qpms_yn2m_sc(y
,*n
=qpms_y2n_sc(y
));
53 static inline qpms_y_t
qpms_lMax2nelem_sc(qpms_l_t lmax
){
54 return lmax
* ((qpms_y_t
)lmax
+ 2) + 1;
57 // TODO maybe enable crashing / validity control by macro definitions...
59 /// Conversion from VSWF type, order and degree to universal index.
60 static inline qpms_uvswfi_t
qpms_tmn2uvswfi(
61 qpms_vswf_type_t t
, qpms_m_t m
, qpms_l_t n
) {
62 return t
+ 4 * qpms_mn2y_sc(m
, n
);
65 /// Constant denoting the l=0, m=0 longitudinal spherical vector wave.
66 static const qpms_uvswfi_t QPMS_UI_L00
= 0;
68 /// Conversion from universal VSWF index u to type, order and degree.
69 /** Returns a non-zero value if the u value is invalid. */
70 static inline qpms_errno_t
qpms_uvswfi2tmn(qpms_uvswfi_t u
,
71 qpms_vswf_type_t
*t
, qpms_m_t
*m
, qpms_l_t
*n
) {
73 qpms_y_sc_t y_sc
= u
/ 4;
74 qpms_y2mn_sc_p(y_sc
, m
, n
);
76 if (QPMS_UNLIKELY(*t
== 3)) return QPMS_ERROR
; // VSWF type code invalid, TODO WARN
77 if (QPMS_UNLIKELY(*t
&& !y_sc
)) return QPMS_ERROR
; // l == 0 for transversal wave, TODO WARN
81 /// Conversion from universal VSWF index u to type and the traditional layout index (\a l > 0).
82 /** Does *not* allow for longitudinal waves. */
83 static inline qpms_errno_t
qpms_uvswfi2ty(qpms_uvswfi_t u
,
84 qpms_vswf_type_t
*t
, qpms_y_t
*y
) {
87 if (QPMS_UNLIKELY(*t
== 0 || *t
== 3)) return QPMS_ERROR
;
88 if (QPMS_UNLIKELY(*y
< 0)) return QPMS_ERROR
;
92 /// Conversion from universal VSWF index u to type and the traditional (vector) layout index.
93 /** *Does* allow for longitudinal waves, but returns an error if l == 0.
94 * (The only legit VSWF with l = 0 is the longitudinal one; u == 0.)
96 static inline qpms_errno_t
qpms_uvswfi2ty_l(qpms_uvswfi_t u
,
97 qpms_vswf_type_t
*t
, qpms_y_t
*y
) {
100 if (QPMS_UNLIKELY(*t
== 3)) return QPMS_ERROR
;
101 if (QPMS_UNLIKELY(*y
< 0)) return QPMS_ERROR
;
105 /// Extract degree \a m from an universal VSWF index \a u.
106 static inline qpms_m_t
qpms_uvswfi2m(qpms_uvswfi_t u
) {
107 qpms_vswf_type_t t
; qpms_m_t m
; qpms_l_t n
;
108 qpms_uvswfi2tmn(u
, &t
,&m
,&n
);
113 #endif //QPMS_INDEXING_H