My Project
so3_sampling.c
Go to the documentation of this file.
1 // S03 package to perform Wigner transform on the rotation group SO(3)
2 // Copyright (C) 2013 Martin Büttner and Jason McEwen
3 // See LICENSE.txt for license details
4 
5 #include <stdlib.h>
6 #include <stdio.h>
7 #include <math.h>
8 #include "so3_error.h"
9 #include "so3_types.h"
10 
11 int so3_sampling_nalpha(const so3_parameters_t *);
12 int so3_sampling_nbeta(const so3_parameters_t *);
13 int so3_sampling_ngamma(const so3_parameters_t *);
14 
15 
16 //============================================================================
17 // Sampling weights
18 //============================================================================
19 
30 complex double so3_sampling_weight(
31  const so3_parameters_t *parameters,
32  int p)
33 {
34  switch (parameters->sampling_scheme)
35  {
36  case SO3_SAMPLING_MW:
37  case SO3_SAMPLING_MW_SS:
38  if (p == 1)
39  return -I * SSHT_PION2;
40  else if (p == -1)
41  return I * SSHT_PION2;
42  else if (p % 2 == 0)
43  return 2.0 / (1.0 - p*p);
44  else
45  return 0.0;
46  default:
47  SO3_ERROR_GENERIC("Invalid sampling scheme.");
48  }
49 }
50 
51 //============================================================================
52 // Sampling relations for all supported sampling schemes
53 //============================================================================
54 
78 int so3_sampling_f_size(const so3_parameters_t *parameters)
79 {
80  int L, N;
81  L = parameters->L;
82  N = parameters->N;
83 
84  return so3_sampling_nalpha(parameters) *
85  so3_sampling_nbeta(parameters) *
86  so3_sampling_ngamma(parameters);
87 }
88 
110 int so3_sampling_n(const so3_parameters_t *parameters)
111 {
112  int L, N;
113  L = parameters->L;
114  N = parameters->N;
115 
116  // Are these actually correct?
117  switch (parameters->sampling_scheme)
118  {
119  case SO3_SAMPLING_MW:
120  return ((2*L-1)*(L-1) + 1)*so3_sampling_ngamma(parameters);
121  case SO3_SAMPLING_MW_SS:
122  return ((2*L)*(L-1) + 2)*so3_sampling_ngamma(parameters);
123  default:
124  SO3_ERROR_GENERIC("Invalid sampling scheme.");
125  }
126 }
127 
128 
140 int so3_sampling_nalpha(const so3_parameters_t *parameters)
141 {
142  int L;
143  L = parameters->L;
144 
145  switch (parameters->sampling_scheme)
146  {
147  case SO3_SAMPLING_MW:
148  return 2*L - 1;
149  case SO3_SAMPLING_MW_SS:
150  return 2*L;
151  default:
152  SO3_ERROR_GENERIC("Invalid sampling scheme.");
153  }
154 }
155 
156 
171 int so3_sampling_nbeta(const so3_parameters_t *parameters)
172 {
173  switch (parameters->sampling_scheme)
174  {
175  case SO3_SAMPLING_MW:
176  return parameters->L;
177  case SO3_SAMPLING_MW_SS:
178  return parameters->L + 1;
179  default:
180  SO3_ERROR_GENERIC("Invalid sampling scheme.");
181  }
182 }
183 
195 int so3_sampling_ngamma(const so3_parameters_t *parameters)
196 {
197  int N;
198  N = parameters->N;
199 
200  if (parameters->steerable)
201  return N;
202  else
203  return 2*N-1;
204 }
205 
206 
222 double so3_sampling_a2alpha(int a, const so3_parameters_t *parameters)
223 {
224  int L;
225  L = parameters->L;
226 
227  switch (parameters->sampling_scheme)
228  {
229  case SO3_SAMPLING_MW:
230  return 2.0 * a * SO3_PI / (2.0*L - 1.0);
231  case SO3_SAMPLING_MW_SS:
232  return 2.0 * a * SO3_PI / (2.0*L);
233  default:
234  SO3_ERROR_GENERIC("Invalid sampling scheme.");
235  }
236 }
237 
238 
254 double so3_sampling_b2beta(int b, const so3_parameters_t *parameters)
255 {
256  int L;
257  L = parameters->L;
258 
259  switch (parameters->sampling_scheme)
260  {
261  case SO3_SAMPLING_MW:
262  return (2.0*b + 1.0) * SO3_PI / (2.0*L - 1.0);
263  case SO3_SAMPLING_MW_SS:
264  return 2.0 * b * SO3_PI / (2.0*L);
265  default:
266  SO3_ERROR_GENERIC("Invalid sampling scheme.");
267  }
268 }
269 
270 
286 double so3_sampling_g2gamma(int g, const so3_parameters_t *parameters)
287 {
288  int N;
289  N = parameters->N;
290 
291  if (parameters->steerable)
292  return g * SO3_PI / N;
293  else
294  return 2.0 * g * SO3_PI / (2.0*N - 1.0);
295 }
296 
297 //============================================================================
298 // Harmonic index relations
299 //============================================================================
300 
315  const so3_parameters_t *parameters
316 ) {
317  int L, N;
318  L = parameters->L;
319  N = parameters->N;
320  switch (parameters->storage)
321  {
322  case SO3_STORAGE_PADDED:
323  if (parameters->reality)
324  return N*L*L;
325  else
326  return (2*N-1)*L*L;
327  case SO3_STORAGE_COMPACT:
328  // Both of these are based on the fact that the sum
329  // over n*n from 1 to N-1 is (N-1)*N*(2*N-1)/6.
330  if (parameters->reality)
331  return N*(6*L*L-(N-1)*(2*N-1))/6;
332  else
333  return (2*N-1)*(3*L*L-N*(N-1))/3;
334  default:
335  SO3_ERROR_GENERIC("Invalid storage method.");
336  }
337 }
338 
367 void so3_sampling_elmn2ind(int *ind, int el, int m, int n, const so3_parameters_t *parameters)
368 {
369  int L, N, offset, absn;
370  L = parameters->L;
371  N = parameters->N;
372 
373  // Most of the formulae here are based on the fact that the sum
374  // over n*n from 1 to N-1 is (N-1)*N*(2*N-1)/6.
375  switch (parameters->storage)
376  {
377  case SO3_STORAGE_PADDED:
378  switch (parameters->n_order)
379  {
380  case SO3_N_ORDER_ZERO_FIRST:
381  offset = ((n < 0) ? -2*n - 1 : 2*n) * L*L;
382  *ind = offset + el*el + el + m;
383  return;
384  case SO3_N_ORDER_NEGATIVE_FIRST:
385  offset = (N-1 + n) * L*L;
386  *ind = offset + el*el + el + m;
387  return;
388  default:
389  SO3_ERROR_GENERIC("Invalid n-order.");
390  }
391  case SO3_STORAGE_COMPACT:
392  switch (parameters->n_order)
393  {
394  case SO3_N_ORDER_ZERO_FIRST:
395  absn = abs(n);
396  if (absn > el)
397  SO3_ERROR_GENERIC("Tried to access component with n > l in compact storage.");
398  // Initialize offset to the total storage that would be needed if N == n
399  offset = (2*absn-1)*(3*L*L - absn*(absn-1))/3;
400  // Advance positive n by another lm-chunk
401  if (n >= 0)
402  offset += L*L - n*n;
403  *ind = offset + el*el - n*n + el + m;
404  return;
405  case SO3_N_ORDER_NEGATIVE_FIRST:
406  absn = abs(n);
407  if (absn > el)
408  SO3_ERROR_GENERIC("Tried to access component with n > l in compact storage.");
409  // Initialize offset as for padded storage, minus the correction necessary for n = 0
410  offset = (N-1 + n) * L*L - (2*N - 1)*(N-1)*N/6;
411  // Now correct the offset for other n due to missing padding
412  if (n <= 0)
413  offset += absn*(2*absn+1)*(absn+1)/6;
414  else
415  offset -= absn*(2*absn-1)*(absn-1)/6;
416  *ind = offset + el*el - n*n + el + m;
417  return;
418  default:
419  SO3_ERROR_GENERIC("Invalid n-order.");
420  }
421  default:
422  SO3_ERROR_GENERIC("Invalid storage method.");
423  }
424 }
425 
453 void so3_sampling_ind2elmn(int *el, int *m, int *n, int ind, const so3_parameters_t *parameters)
454 {
455  int L, N, offset;
456  L = parameters->L;
457  N = parameters->N;
458 
459  switch (parameters->storage)
460  {
461  case SO3_STORAGE_PADDED:
462  switch (parameters->n_order)
463  {
464  case SO3_N_ORDER_ZERO_FIRST:
465  *n = ind/(L*L);
466 
467  if(*n % 2)
468  *n = -(*n+1)/2;
469  else
470  *n /= 2;
471 
472  ind %= L*L;
473 
474  *el = sqrt(ind);
475  *m = ind - (*el)*(*el) - *el;
476  return;
477  case SO3_N_ORDER_NEGATIVE_FIRST:
478  *n = ind/(L*L) - (N-1);
479 
480  ind %= L*L;
481 
482  *el = sqrt(ind);
483  *m = ind - (*el)*(*el) - *el;
484  return;
485  default:
486  SO3_ERROR_GENERIC("Invalid n-order.");
487  }
488  case SO3_STORAGE_COMPACT:
489  switch (parameters->n_order)
490  {
491  case SO3_N_ORDER_ZERO_FIRST:
492  offset = 0;
493  *n = 0;
494  // TODO: Can this loop be replaced by an analytical function
495  // (or two - one for positive and one for negative *n)
496  while(ind + offset >= L*L)
497  {
498  ind -= L*L - offset;
499 
500  if (*n >= 0)
501  {
502  *n = -(*n+1);
503  offset = (*n)*(*n);
504  }
505  else
506  {
507  *n = -(*n);
508  }
509  }
510 
511  ind += offset;
512 
513  *el = sqrt(ind);
514  *m = ind - (*el)*(*el) - *el;
515  return;
516  case SO3_N_ORDER_NEGATIVE_FIRST:
517  *n = -N+1;
518  offset = (*n)*(*n);
519  // TODO: Can this loop be replaced by an analytical function
520  // (or two - one for positive and one for negative *n)
521  while(ind + offset >= L*L)
522  {
523  ind -= L*L - offset;
524 
525  (*n)++;
526  offset = (*n)*(*n);
527  }
528 
529  ind += offset;
530 
531  *el = sqrt(ind);
532  *m = ind - (*el)*(*el) - *el;
533  return;
534  default:
535  SO3_ERROR_GENERIC("Invalid n-order.");
536  }
537  default:
538  SO3_ERROR_GENERIC("Invalid storage method.");
539  }
540 }
541 
569 void so3_sampling_elmn2ind_real(int *ind, int el, int m, int n, const so3_parameters_t *parameters)
570 {
571  int base_ind;
572  so3_parameters_t temp_params;
573 
574  // Need to make a copy, because subroutines always use
575  // NEGATIVE_FIRST storage order.
576  temp_params = *parameters;
577  temp_params.n_order = SO3_N_ORDER_NEGATIVE_FIRST;
578 
579  // TODO: Could be optimized by computing the indices directly.
580  switch(parameters->storage)
581  {
582  case SO3_STORAGE_PADDED:
583  so3_sampling_elmn2ind(&base_ind, 0, 0, 0, &temp_params);
584  so3_sampling_elmn2ind(ind, el, m, n, &temp_params);
585  (*ind) -= base_ind;
586  return;
587  case SO3_STORAGE_COMPACT:
588  so3_sampling_elmn2ind(&base_ind, 0, 0, 0, &temp_params);
589  so3_sampling_elmn2ind(ind, el, m, n, &temp_params);
590  (*ind) -= base_ind;
591  return;
592  default:
593  SO3_ERROR_GENERIC("Invalid storage method.");
594  }
595 }
596 
624 void so3_sampling_ind2elmn_real(int *el, int *m, int *n, int ind, const so3_parameters_t *parameters)
625 {
626  int base_ind;
627  so3_parameters_t temp_params;
628 
629  // Need to make a copy, because subroutines always use
630  // NEG_FIRST storage.
631  temp_params = *parameters;
632  temp_params.n_order = SO3_N_ORDER_NEGATIVE_FIRST;
633 
634  // TODO: Could be optimized by computing the indices directly.
635  switch(parameters->storage)
636  {
637  case SO3_STORAGE_PADDED:
638  so3_sampling_elmn2ind(&base_ind, 0, 0, 0, &temp_params);
639  so3_sampling_ind2elmn(el, m, n, base_ind + ind, &temp_params);
640  return;
641  case SO3_STORAGE_COMPACT:
642  so3_sampling_elmn2ind(&base_ind, 0, 0, 0, &temp_params);
643  so3_sampling_ind2elmn(el, m, n, base_ind + ind, &temp_params);
644  return;
645  default:
646  SO3_ERROR_GENERIC("Invalid storage method.");
647  }
648 }
so3_sampling_f_size
int so3_sampling_f_size(const so3_parameters_t *parameters)
Definition: so3_sampling.c:78
so3_sampling_ngamma
int so3_sampling_ngamma(const so3_parameters_t *)
Definition: so3_sampling.c:195
so3_sampling_g2gamma
double so3_sampling_g2gamma(int g, const so3_parameters_t *parameters)
Definition: so3_sampling.c:286
so3_sampling_a2alpha
double so3_sampling_a2alpha(int a, const so3_parameters_t *parameters)
Definition: so3_sampling.c:222
so3_sampling_ind2elmn
void so3_sampling_ind2elmn(int *el, int *m, int *n, int ind, const so3_parameters_t *parameters)
Definition: so3_sampling.c:453
so3_sampling_elmn2ind_real
void so3_sampling_elmn2ind_real(int *ind, int el, int m, int n, const so3_parameters_t *parameters)
Definition: so3_sampling.c:569
so3_sampling_nalpha
int so3_sampling_nalpha(const so3_parameters_t *)
Definition: so3_sampling.c:140
so3_sampling_b2beta
double so3_sampling_b2beta(int b, const so3_parameters_t *parameters)
Definition: so3_sampling.c:254
so3_sampling_nbeta
int so3_sampling_nbeta(const so3_parameters_t *)
Definition: so3_sampling.c:171
so3_sampling_n
int so3_sampling_n(const so3_parameters_t *parameters)
Definition: so3_sampling.c:110
so3_sampling_flmn_size
int so3_sampling_flmn_size(const so3_parameters_t *parameters)
Definition: so3_sampling.c:314
so3_sampling_weight
complex double so3_sampling_weight(const so3_parameters_t *parameters, int p)
Definition: so3_sampling.c:30
so3_sampling_elmn2ind
void so3_sampling_elmn2ind(int *ind, int el, int m, int n, const so3_parameters_t *parameters)
Definition: so3_sampling.c:367
so3_sampling_ind2elmn_real
void so3_sampling_ind2elmn_real(int *el, int *m, int *n, int ind, const so3_parameters_t *parameters)
Definition: so3_sampling.c:624