Ewald 1D in 3D: jdu spát
[qpms.git] / qpms / indexing.h
blob59e90eb943e8f9163329365cce236aea9fb0c607
1 /*! \file indexing.h
2 * \brief Various index conversion functions.
3 */
4 #ifndef QPMS_INDEXING_H
5 #define QPMS_INDEXING_H
7 #include "qpms_types.h"
8 #include <math.h>
9 #include "optim.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
19 return sqrt(y+1);
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
42 return sqrt(y);
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) {
72 *t = u & 3;
73 qpms_y_sc_t y_sc = u / 4;
74 qpms_y2mn_sc_p(y_sc, m, n);
75 // Test validity
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
78 return QPMS_SUCCESS;
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) {
85 *t = u & 3;
86 *y = u / 4 - 1;
87 if (QPMS_UNLIKELY(*t == 0 || *t == 3)) return QPMS_ERROR;
88 if (QPMS_UNLIKELY(*y < 0)) return QPMS_ERROR;
89 return QPMS_SUCCESS;
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) {
98 *t = u & 3;
99 *y = u / 4 - 1;
100 if (QPMS_UNLIKELY(*t == 3)) return QPMS_ERROR;
101 if (QPMS_UNLIKELY(*y < 0)) return QPMS_ERROR;
102 return QPMS_SUCCESS;
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);
109 return m;
113 #endif //QPMS_INDEXING_H