My Project: src/c/so3_sampling.c Source File

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
314 int so3_sampling_flmn_size(
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