source: Sophya/trunk/SophyaLib/Samba/sphericaltransformserver.cc@ 2984

Last change on this file since 2984 was 2984, checked in by ansari, 19 years ago

Remplacement appel a RfourierSynthesisFromB (TF reel) par fourierSynthesisFromB (TF complexe) pour corriger pb transforme Ylm sur HEALPix (zones polar cap) , Reza 21/6/2006

File size: 46.3 KB
Line 
1#include "sopnamsp.h"
2#include "machdefs.h"
3#include <iostream>
4#include <math.h>
5#include <complex>
6#include "sphericaltransformserver.h"
7#include "tvector.h"
8#include "nbrandom.h"
9#include "nbmath.h"
10#include "timing.h"
11//#include "spherehealpix.h"
12
13
14/*!
15 \ingroup Samba
16 \class SOPHYA::SphericalTransformServer
17
18 \brief Analysis/synthesis in spherical harmonics server.
19
20 Class for performing analysis and synthesis of sky maps using spin-0 or spin-2 spherical harmonics.
21
22Maps must be SOPHYA SphericalMaps (SphereHEALPix or SphereThetaPhi or SphereECP).
23
24Temperature and polarization (Stokes parameters) can be developped on spherical harmonics :
25\f[
26\frac{\Delta T}{T}(\hat{n})=\sum_{lm}a_{lm}^TY_l^m(\hat{n})
27\f]
28\f[
29Q(\hat{n})=\frac{1}{\sqrt{2}}\sum_{lm}N_l\left(a_{lm}^EW_{lm}(\hat{n})+a_{lm}^BX_{lm}(\hat{n})\right)
30\f]
31\f[
32U(\hat{n})=-\frac{1}{\sqrt{2}}\sum_{lm}N_l\left(a_{lm}^EX_{lm}(\hat{n})-a_{lm}^BW_{lm}(\hat{n})\right)
33\f]
34\f[
35\left(Q \pm iU\right)(\hat{n})=\sum_{lm}a_{\pm 2lm}\, _{\pm 2}Y_l^m(\hat{n})
36\f]
37
38\f[
39Y_l^m(\hat{n})=\lambda_l^m(\theta)e^{im\phi}
40\f]
41\f[
42_{\pm}Y_l^m(\hat{n})=_{\pm}\lambda_l^m(\theta)e^{im\phi}
43\f]
44\f[
45W_{lm}(\hat{n})=\frac{1}{N_l}\,_{w}\lambda_l^m(\theta)e^{im\phi}
46\f]
47\f[
48X_{lm}(\hat{n})=\frac{-i}{N_l}\,_{x}\lambda_l^m(\theta)e^{im\phi}
49\f]
50
51(see LambdaLMBuilder, LambdaPMBuilder, LambdaWXBuilder classes)
52
53power spectra :
54
55\f[
56C_l^T=\frac{1}{2l+1}\sum_{m=0}^{+ \infty }\left|a_{lm}^T\right|^2=\langle\left|a_{lm}^T\right|^2\rangle
57\f]
58\f[
59C_l^E=\frac{1}{2l+1}\sum_{m=0}^{+\infty}\left|a_{lm}^E\right|^2=\langle\left|a_{lm}^E\right|^2\rangle
60\f]
61\f[
62C_l^B=\frac{1}{2l+1}\sum_{m=0}^{+\infty}\left|a_{lm}^B\right|^2=\langle\left|a_{lm}^B\right|^2\rangle
63\f]
64
65\arg
66\b Synthesis : Get temperature and polarization maps from \f$a_{lm}\f$ coefficients or from power spectra, (methods GenerateFrom...).
67
68\b Temperature:
69\f[
70\frac{\Delta T}{T}(\hat{n})=\sum_{lm}a_{lm}^TY_l^m(\hat{n}) = \sum_{-\infty}^{+\infty}b_m(\theta)e^{im\phi}
71\f]
72
73with
74\f[
75b_m(\theta)=\sum_{l=\left|m\right|}^{+\infty}a_{lm}^T\lambda_l^m(\theta)
76\f]
77
78\b Polarisation
79\f[
80Q \pm iU = \sum_{-\infty}^{+\infty}b_m^{\pm}(\theta)e^{im\phi}
81\f]
82
83where :
84\f[
85b_m^{\pm}(\theta) = \sum_{l=\left|m\right|}^{+\infty}a_{\pm 2lm}\,_{\pm}\lambda_l^m(\theta)
86\f]
87
88or :
89\f[
90Q = \sum_{-\infty}^{+\infty}b_m^{Q}(\theta)e^{im\phi}
91\f]
92\f[
93U = \sum_{-\infty}^{+\infty}b_m^{U}(\theta)e^{im\phi}
94\f]
95
96where:
97\f[
98b_m^{Q}(\theta) = \frac{1}{\sqrt{2}}\sum_{l=\left|m\right|}^{+\infty}\left(a_{lm}^E\,_{w}\lambda_l^m(\theta)-ia_{lm}^B\,_{x}\lambda_l^m(\theta)\right)
99\f]
100\f[
101b_m^{U}(\theta) = \frac{1}{\sqrt{2}}\sum_{l=\left|m\right|}^{+\infty}\left(ia_{lm}^E\,_{x}\lambda_l^m(\theta)+a_{lm}^B\,_{w}\lambda_l^m(\theta)\right)
102\f]
103
104Since the pixelization provides "slices" with constant \f$\theta\f$ and \f$\phi\f$ equally distributed on \f$2\pi\f$ \f$\frac{\Delta T}{T}\f$, \f$Q\f$,\f$U\f$ can be computed by FFT.
105
106
107\arg
108\b Analysis : Get \f$a_{lm}\f$ coefficients or power spectra from temperature and polarization maps (methods DecomposeTo...).
109
110\b Temperature:
111\f[
112a_{lm}^T=\int\frac{\Delta T}{T}(\hat{n})Y_l^{m*}(\hat{n})d\hat{n}
113\f]
114
115approximated as :
116\f[
117a_{lm}^T=\sum_{\theta_k}\omega_kC_m(\theta_k)\lambda_l^m(\theta_k)
118\f]
119where :
120\f[
121C_m (\theta _k)=\sum_{\phi _{k\prime}}\frac{\Delta T}{T}(\theta _k,\phi_{k\prime})e^{-im\phi _{k\prime}}
122\f]
123Since the pixelization provides "slices" with constant \f$\theta\f$ and \f$\phi\f$ equally distributed on \f$2\pi\f$ (\f$\omega_k\f$ is the solid angle of each pixel of the slice \f$\theta_k\f$) \f$C_m\f$ can be computed by FFT.
124
125\b polarisation:
126
127\f[
128a_{\pm 2lm}=\sum_{\theta_k}\omega_kC_m^{\pm}(\theta_k)\,_{\pm}\lambda_l^m(\theta_k)
129\f]
130where :
131\f[
132C_m^{\pm} (\theta _k)=\sum_{\phi _{k\prime}}\left(Q \pm iU\right)(\theta _k,\phi_{k\prime})e^{-im\phi _{k\prime}}
133\f]
134or :
135
136\f[
137a_{lm}^E=\frac{1}{\sqrt{2}}\sum_{\theta_k}\omega_k\left(C_m^{Q}(\theta_k)\,_{w}\lambda_l^m(\theta_k)-iC_m^{U}(\theta_k)\,_{x}\lambda_l^m(\theta_k)\right)
138\f]
139\f[
140a_{lm}^B=\frac{1}{\sqrt{2}}\sum_{\theta_k}\omega_k\left(iC_m^{Q}(\theta_k)\,_{x}\lambda_l^m(\theta_k)+C_m^{U}(\theta_k)\,_{w}\lambda_l^m(\theta_k)\right)
141\f]
142
143where :
144\f[
145C_m^{Q} (\theta _k)=\sum_{\phi _{k\prime}}Q(\theta _k,\phi_{k\prime})e^{-im\phi _{k\prime}}
146\f]
147\f[
148C_m^{U} (\theta _k)=\sum_{\phi _{k\prime}}U(\theta _k,\phi_{k\prime})e^{-im\phi _{k\prime}}
149\f]
150
151 */
152
153 /*! \fn void SOPHYA::SphericalTransformServer::GenerateFromAlm( SphericalMap<T>& map, int_4 pixelSizeIndex, const Alm<T>& alm) const
154
155 synthesis of a temperature map from Alm coefficients
156*/
157template<class T>
158void SphericalTransformServer<T>::GenerateFromAlm( SphericalMap<T>& map, int_4 pixelSizeIndex, const Alm<T>& alm) const
159{
160 /*=======================================================================
161 computes a map from its alm for the HEALPIX pixelisation
162 map(theta,phi) = sum_l_m a_lm Y_lm(theta,phi)
163 = sum_m {e^(i*m*phi) sum_l a_lm*lambda_lm(theta)}
164
165 where Y_lm(theta,phi) = lambda(theta) * e^(i*m*phi)
166
167 * the recurrence of Ylm is the standard one (cf Num Rec)
168 * the sum over m is done by FFT
169
170 =======================================================================*/
171 int_4 nlmax=alm.Lmax();
172 int_4 nmmax=nlmax;
173 int_4 nsmax=0;
174 // le Resize est suppose mettre a zero
175 map.Resize(pixelSizeIndex);
176 string sphere_type=map.TypeOfMap();
177 int premiereTranche = 0;
178 int derniereTranche = map.NbThetaSlices()-1;
179
180 Bm<complex<T> > b_m_theta(nmmax);
181
182
183
184 // pour chaque tranche en theta
185 for (int_4 ith = premiereTranche; ith <= derniereTranche;ith++)
186 {
187 int_4 nph;
188 r_8 phi0;
189 r_8 theta;
190 TVector<int_4> pixNumber;
191 TVector<T> datan;
192
193 map.GetThetaSlice(ith,theta,phi0, pixNumber,datan);
194 nph = pixNumber.NElts();
195 if (nph < 2) continue; // On laisse tomber les tranches avec un point
196 // -----------------------------------------------------
197 // for each theta, and each m, computes
198 // b(m,theta) = sum_over_l>m (lambda_l_m(theta) * a_l_m)
199 // ------------------------------------------------------
200 // ===> Optimisation Reza, Mai 2006
201 /*--- Le bout de code suivant est remplace par l'appel a la nouvelle fonction
202 qui calcule la somme au vol
203 LambdaLMBuilder lb(theta,nlmax,nmmax);
204 // somme sur m de 0 a l'infini
205 for (int_4 m = 0; m <= nmmax; m++)
206 {
207 b_m_theta(m) = (T)( lb.lamlm(m,m) ) * alm(m,m);
208 for (int l = m+1; l<= nlmax; l++)
209 {
210 b_m_theta(m) += (T)( lb.lamlm(l,m) ) * alm(l,m);
211 }
212 }
213 ------- Fin version PRE-Mai2006 */
214 LambdaLMBuilder::ComputeBmFrAlm(theta,nlmax,nmmax, alm, b_m_theta);
215 //Fin Optimisation Reza, Mai 2006 <====
216
217 // obtains the negative m of b(m,theta) (= complex conjugate)
218
219 for (int_4 m=1;m<=nmmax;m++)
220 {
221 b_m_theta(-m) = conj(b_m_theta(m));
222 }
223 // ---------------------------------------------------------------
224 // sum_m b(m,theta)*exp(i*m*phi) -> f(phi,theta)
225 // ---------------------------------------------------------------*/
226
227 /* ----- Reza, Juin 2006 :
228 En verifiant la difference entre deux cartes
229 cl -> map -> alm -> map2 et mapdiff = map-map2
230 je me suis apercu qu'il y avait des differences importantes - dans les
231 deux zones 'polar cap' de HEALPix - apres avoir pas mal chercher, il semble
232 que la routine RfourierSynthesisFromB en soit responsable
233 Je fais donc tout passer dans fourierSynthesisFromB
234 if ( (sphere_type == "RING") || (sphere_type == "NESTED") ) {
235 TVector<T> Temp = RfourierSynthesisFromB(b_m_theta,nph,phi0);
236 for (int i=0;i< nph;i++) map(pixNumber(i))=Temp(i);
237 }
238 else
239 */
240 // pour des pixelisations quelconques (autres que HEALPix
241 // nph n'est pas toujours pair
242 // ca fait des problemes pour les transformees de Fourier
243 // car le server de TF ajuste la longueur du vecteur reel
244 // en sortie de TF, bref, la securite veut qu'on prenne une
245 // TF complexe
246 {
247 TVector<complex<T> > Temp = fourierSynthesisFromB(b_m_theta,nph,phi0);
248 for (int i=0;i< nph;i++) map(pixNumber(i))=Temp(i).real();
249 }
250 }
251}
252
253
254
255 /*! \fn TVector< complex<T> > SOPHYA::SphericalTransformServer::fourierSynthesisFromB(const Bm<complex<T> >& b_m, int_4 nph, r_8 phi0) const
256
257\return a vector with nph elements which are sums :\f$\sum_{m=-mmax}^{mmax}b_m(\theta)e^{im\varphi}\f$ for nph values of \f$\varphi\f$ regularly distributed in \f$[0,\pi]\f$ ( calculated by FFT)
258
259 The object b_m (\f$b_m\f$) of the class Bm is a special vector which index goes from -mmax to mmax.
260 */
261template<class T>
262TVector< complex<T> > SphericalTransformServer<T>::fourierSynthesisFromB(const Bm<complex<T> >& b_m, int_4 nph, r_8 phi0) const
263{
264 /*=======================================================================
265 dataout(j) = sum_m datain(m) * exp(i*m*phi(j))
266 with phi(j) = j*2pi/nph + kphi0*pi/nph and kphi0 =0 or 1
267
268 as the set of frequencies {m} is larger than nph,
269 we wrap frequencies within {0..nph-1}
270 ie m = k*nph + m' with m' in {0..nph-1}
271 then
272 noting bw(m') = exp(i*m'*phi0)
273 * sum_k (datain(k*nph+m') exp(i*k*pi*kphi0))
274 with bw(nph-m') = CONJ(bw(m')) (if datain(-m) = CONJ(datain(m)))
275 dataout(j) = sum_m' [ bw(m') exp (i*j*m'*2pi/nph) ]
276 = Fourier Transform of bw
277 is real
278
279 NB nph is not necessarily a power of 2
280
281=======================================================================*/
282 //**********************************************************************
283 // pour une valeur de phi (indexee par j) la temperature est la transformee
284 // de Fourier de bm (somme sur m de -nmax a +nmmax de bm*exp(i*m*phi)).
285 // on demande nph (nombre de pixels sur la tranche) valeurs de transformees, pour nph valeurs de phi, regulierement reparties sur 2*pi. On a:
286 // DT/T(j) = sum_m b(m) * exp(i*m*phi(j))
287 // sommation de -infini a +infini, en fait limitee a -nmamx, +nmmax
288 // On pose m=k*nph + m', avec m' compris entre 0 et nph-1. Alors :
289 // DT/T(j) = somme_k somme_m' b(k*nph + m')*exp(i*(k*nph + m')*phi(j))
290 // somme_k : de -infini a +infini
291 // somme_m' : de 0 a nph-1
292 // On echange les sommations :
293 // DT/T(j) = somme_m' (exp(i*m'*phi(j)) somme_k b(k*nph + m')*exp(i*(k*nph*phi(j))
294 // mais phi(j) est un multiple entier de 2*pi/nph, la seconde exponentielle
295 // vaut 1.
296 // Il reste a calculer les transformees de Fourier de somme_m' b(k*nph + m')
297 // si phi0 n'est pas nul, il y a juste un decalage a faire.
298 //**********************************************************************
299
300 TVector< complex<T> > bw(nph);
301 TVector< complex<T> > dataout(nph);
302 TVector< complex<T> > data(nph);
303
304
305 for (int kk=0; kk<bw.NElts(); kk++) bw(kk)=(T)0.;
306 int m;
307 for (m=-b_m.Mmax();m<=-1;m++)
308 {
309 int maux=m;
310 while (maux<0) maux+=nph;
311 int iw=maux%nph;
312 double aux=(m-iw)*phi0;
313 bw(iw) += b_m(m) * complex<T>( (T)cos(aux),(T)sin(aux) ) ;
314 }
315 for (m=0;m<=b_m.Mmax();m++)
316 {
317 // int iw=((m % nph) +nph) % nph; //between 0 and nph = m'
318 int iw=m%nph;
319 double aux=(m-iw)*phi0;
320 bw(iw)+=b_m(m) * complex<T>( (T)cos(aux),(T)sin(aux) );
321 }
322
323 // applies the shift in position <-> phase factor in Fourier space
324 for (int mprime=0; mprime < nph; mprime++)
325 {
326 complex<double> aux(cos(mprime*phi0),sin(mprime*phi0));
327 data(mprime)=bw(mprime)*
328 (complex<T>)(complex<double>(cos(mprime*phi0),sin(mprime*phi0)));
329 }
330
331 //sortie.ReSize(nph);
332 TVector< complex<T> > sortie(nph);
333
334 fftIntfPtr_-> FFTBackward(data, sortie);
335
336 return sortie;
337}
338
339//********************************************
340/*! \fn TVector<T> SOPHYA::SphericalTransformServer::RfourierSynthesisFromB(const Bm<complex<T> >& b_m, int_4 nph, r_8 phi0) const
341
342same as fourierSynthesisFromB, but return a real vector, taking into account the fact that b(-m) is conjugate of b(m) */
343template<class T>
344TVector<T> SphericalTransformServer<T>::RfourierSynthesisFromB(const Bm<complex<T> >& b_m, int_4 nph, r_8 phi0) const
345{
346 /*=======================================================================
347 dataout(j) = sum_m datain(m) * exp(i*m*phi(j))
348 with phi(j) = j*2pi/nph + kphi0*pi/nph and kphi0 =0 or 1
349
350 as the set of frequencies {m} is larger than nph,
351 we wrap frequencies within {0..nph-1}
352 ie m = k*nph + m' with m' in {0..nph-1}
353 then
354 noting bw(m') = exp(i*m'*phi0)
355 * sum_k (datain(k*nph+m') exp(i*k*pi*kphi0))
356 with bw(nph-m') = CONJ(bw(m')) (if datain(-m) = CONJ(datain(m)))
357 dataout(j) = sum_m' [ bw(m') exp (i*j*m'*2pi/nph) ]
358 = Fourier Transform of bw
359 is real
360
361 NB nph is not necessarily a power of 2
362
363=======================================================================*/
364 //**********************************************************************
365 // pour une valeur de phi (indexee par j) la temperature est la transformee
366 // de Fourier de bm (somme sur m de -nmax a +nmmax de bm*exp(i*m*phi)).
367 // on demande nph (nombre de pixels sur la tranche) valeurs de transformees, pour nph valeurs de phi, regulierement reparties sur 2*pi. On a:
368 // DT/T(j) = sum_m b(m) * exp(i*m*phi(j))
369 // sommation de -infini a +infini, en fait limitee a -nmamx, +nmmax
370 // On pose m=k*nph + m', avec m' compris entre 0 et nph-1. Alors :
371 // DT/T(j) = somme_k somme_m' b(k*nph + m')*exp(i*(k*nph + m')*phi(j))
372 // somme_k : de -infini a +infini
373 // somme_m' : de 0 a nph-1
374 // On echange les sommations :
375 // DT/T(j) = somme_m' (exp(i*m'*phi(j)) somme_k b(k*nph + m')*exp(i*(k*nph*phi(j))
376 // mais phi(j) est un multiple entier de 2*pi/nph, la seconde exponentielle
377 // vaut 1.
378 // Il reste a calculer les transformees de Fourier de somme_k b(k*nph + m')
379 // si phi0 n'est pas nul, il y a juste un decalage a faire.
380 //**********************************************************************
381 TVector< complex<T> > bw(nph);
382 TVector< complex<T> > dataout(nph);
383 TVector< complex<T> > data(nph/2+1);
384
385
386 for (int kk=0; kk<bw.NElts(); kk++) bw(kk)=(T)0.;
387 int m;
388 for (m=-b_m.Mmax();m<=-1;m++)
389 {
390 int maux=m;
391 while (maux<0) maux+=nph;
392 int iw=maux%nph;
393 double aux=(m-iw)*phi0;
394 bw(iw) += b_m(m) * complex<T>( (T)cos(aux),(T)sin(aux) ) ;
395 }
396 for (m=0;m<=b_m.Mmax();m++)
397 {
398 // int iw=((m % nph) +nph) % nph; //between 0 and nph = m'
399 int iw=m%nph;
400 double aux=(m-iw)*phi0;
401 bw(iw)+=b_m(m) * complex<T>( (T)cos(aux),(T)sin(aux) );
402 }
403
404 // applies the shift in position <-> phase factor in Fourier space
405 // cout << " TF : nph= " << nph << " vec. entree " << data.Size() << endl;
406 for (int mprime=0; mprime <= nph/2; mprime++)
407 {
408 complex<double> aux(cos(mprime*phi0),sin(mprime*phi0));
409 data(mprime)=bw(mprime)*
410 (complex<T>)(complex<double>(cos(mprime*phi0),sin(mprime*phi0)));
411 }
412
413 TVector<T> sortie;
414 fftIntfPtr_-> FFTBackward(data, sortie);
415
416 return sortie;
417}
418//*******************************************
419
420 /*! \fn Alm<T> SOPHYA::SphericalTransformServer::DecomposeToAlm(const SphericalMap<T>& map, int_4 nlmax, r_8 cos_theta_cut) const
421
422\return the Alm coefficients from analysis of a temperature map.
423
424 \param<nlmax> : maximum value of the l index
425
426 \param<cos_theta_cut> : cosinus of the symmetric cut EULER angle theta : cos_theta_cut=0 means no cut ; cos_theta_cut=1 all the sphere is cut.
427
428 */
429template<class T>
430void SphericalTransformServer<T>::DecomposeToAlm(const SphericalMap<T>& map, Alm<T>& alm, int_4 nlmax, r_8 cos_theta_cut) const
431{
432 DecomposeToAlm(const_cast< SphericalMap<T>& >(map), alm, nlmax, cos_theta_cut, 0);
433}
434//*******************************************
435
436 /*! \fn Alm<T> SOPHYA::SphericalTransformServer::DecomposeToAlm(const SphericalMap<T>& map, int_4 nlmax, r_8 cos_theta_cut, int iterationOrder) const
437
438\return the Alm coefficients from analysis of a temperature map. THE MAP CAN BE MODIFIED (if iterationOrder >0)
439
440 \param<nlmax> : maximum value of the l index
441
442 \param<cos_theta_cut> : cosinus of the symmetric cut EULER angle theta : cos_theta_cut=0 means no cut ; cos_theta_cut=1 all the sphere is cut.
443
444\param<iterationOrder> : 1,2,3,4.... order of an iterative analysis. (Default : 0 -> standard analysis). If iterationOrder is not null, the method works with SphereHEALPix but NOT WITH SphereThetaPhi maps ! */
445template<class T>
446void SphericalTransformServer<T>::DecomposeToAlm(SphericalMap<T>& map, Alm<T>& alm, int_4 nlmax, r_8 cos_theta_cut, int iterationOrder) const
447{
448 int_4 nmmax = nlmax;
449 // PrtTim("appel carteVersAlm");
450 carteVersAlm(map, nlmax, cos_theta_cut, alm);
451 // PrtTim("retour carteVersAlm");
452 if (iterationOrder > 0)
453 {
454 TVector<int_4> fact(iterationOrder+2);
455 fact(0) = 1;
456 int k;
457 for (k=1; k <= iterationOrder+1; k++)
458 {
459 fact(k) = fact(k-1)*k;
460 }
461 Alm<T> alm2(alm);
462 T Tzero = (T)0.;
463 complex<T> complexZero = complex<T>(Tzero, Tzero);
464 alm = complexZero;
465 int signe = 1;
466 int nbIteration = iterationOrder+1;
467 for (k=1; k <= nbIteration; k++)
468 {
469 T facMult = (T)(0.5*signe*fact(iterationOrder)*(2*nbIteration-k)/(fact(k)*fact(nbIteration-k)));
470 for (int m = 0; m <= nmmax; m++)
471 {
472 for (int l = m; l<= nlmax; l++)
473 {
474 alm(l,m) += facMult*alm2(l,m);
475 }
476 }
477 if (k == nbIteration) break;
478 signe = -signe;
479 for (int k=0; k< map.NbPixels(); k++) map(k) = (T)0.;
480 // synthetize a map from the estimated alm
481 // PrtTim("appel GenerateFromAlm");
482 GenerateFromAlm( map, map.SizeIndex(), alm2);
483 // PrtTim("retour GenerateFromAlm");
484 alm2 = complexZero;
485 // analyse the new map
486 // PrtTim("appel carteVersAlm");
487 carteVersAlm(map, nlmax, cos_theta_cut, alm2);
488 // PrtTim("retour carteVersAlm");
489 }
490 }
491}
492
493template<class T>
494 void SphericalTransformServer<T>::carteVersAlm(const SphericalMap<T>& map, int_4 nlmax, r_8 cos_theta_cut, Alm<T>& alm) const
495{
496
497 /*-----------------------------------------------------------------------
498 computes the integral in phi : phas_m(theta)
499 for each parallele from north to south pole
500 -----------------------------------------------------------------------*/
501 TVector<T> data;
502 TVector<int_4> pixNumber;
503 int_4 nmmax = nlmax;
504 TVector< complex<T> > phase(nmmax+1);
505
506 alm.ReSizeToLmax(nlmax);
507 for (int_4 ith = 0; ith < map.NbThetaSlices(); ith++)
508 {
509 r_8 phi0;
510 r_8 theta;
511 // PrtTim("debut 1ere tranche ");
512 map.GetThetaSlice(ith,theta,phi0,pixNumber ,data);
513 phase = complex<T>((T)0.,(T)0.);
514 double cth = cos(theta);
515
516 //part of the sky out of the symetric cut
517 bool keep_it = (fabs(cth) >= cos_theta_cut);
518
519 // PrtTim("fin 1ere tranche ");
520
521 if (keep_it)
522 {
523 // phase = CFromFourierAnalysis(nmmax,data,phi0);
524 // PrtTim("avant Fourier ");
525 CFromFourierAnalysis(nmmax,data,phase, phi0);
526 // PrtTim("apres Fourier ");
527
528 }
529
530// ---------------------------------------------------------------------
531// computes the a_lm by integrating over theta
532// lambda_lm(theta) * phas_m(theta)
533// for each m and l
534// -----------------------------------------------------------------------
535
536 // ===> Optimisation Reza, Mai 2006
537 /*--- Le bout de code suivant est remplace par l'appel a la nouvelle fonction
538 qui calcule la somme au vol
539 // PrtTim("avant instanciation LM ");
540 LambdaLMBuilder lb(theta,nlmax,nmmax);
541 // PrtTim("apres instanciation LM ");
542 r_8 domega=map.PixSolAngle(map.PixIndexSph(theta,phi0));
543
544 // PrtTim("avant mise a jour Alm ");
545 complex<T> fi;
546 T facteur;
547 int index;
548 for (int m = 0; m <= nmmax; m++)
549 {
550 fi = phase(m);
551 for (int l = m; l<= nlmax; l++)
552 {
553 index = alm.indexOfElement(l,m);
554 // facteur = (T)(lb.lamlm(l,m) * domega);
555 facteur = (T)(lb.lamlm(index) * domega);
556 // alm(l,m) += facteur * fi ;
557 alm(index) += facteur * fi ;
558 }
559 }
560 ------- Fin version PRE-Mai2006 */
561 r_8 domega=map.PixSolAngle(map.PixIndexSph(theta,phi0));
562 phase *= complex<T>((T)domega, 0.);
563 LambdaLMBuilder::ComputeAlmFrPhase(theta,nlmax,nmmax, phase, alm);
564 //Fin Optimisation Reza, Mai 2006 <====
565
566
567
568 //
569 //
570 // PrtTim("apres mise a jour Alm ");
571 }
572}
573 /*! \fn TVector< complex<T> > SOPHYA::SphericalTransformServer::CFromFourierAnalysis(int_4 nmmax, const TVector<complex<T> >datain, r_8 phi0) const
574
575\return a vector with mmax elements which are sums :
576\f$\sum_{k=0}^{nphi}datain(\theta,\varphi_k)e^{im\varphi_k}\f$ for (mmax+1) values of \f$m\f$ from 0 to mmax.
577 */
578template<class T>
579TVector< complex<T> > SphericalTransformServer<T>::CFromFourierAnalysis(int_4 nmmax, const TVector<complex<T> >datain, r_8 phi0) const
580{
581 /*=======================================================================
582 integrates (data * phi-dependence-of-Ylm) over phi
583 --> function of m can be computed by FFT
584
585 datain est modifie
586 =======================================================================*/
587 int_4 nph=datain.NElts();
588 if (nph <= 0)
589 {
590 throw PException("bizarre : vecteur datain de longueur nulle (CFromFourierAnalysis)");
591 }
592 TVector<complex<T> > transformedData(nph);
593 fftIntfPtr_-> FFTForward(datain, transformedData);
594
595 TVector< complex<T> > dataout(nmmax+1);
596
597 int im_max=min(nph,nmmax+1);
598 int i;
599 dataout = complex<T>((T)0.,(T)0.);
600 // for (i=0;i< dataout.NElts();i++) dataout(i)=complex<T>((T)0.,(T)0.);
601 for (i=0;i<im_max;i++) dataout(i)=transformedData(i);
602
603
604 for (int kk=nph; kk<dataout.NElts(); kk++) dataout(kk)=dataout(kk%nph);
605 for (i = 0;i <dataout.NElts();i++){
606 dataout(i)*= (complex<T>)(complex<double>(cos(-i*phi0),sin(-i*phi0)));
607 }
608 return dataout;
609}
610
611//&&&&&&&&& nouvelle version
612/* \fn TVector< complex<T> > SOPHYA::SphericalTransformServer::CFromFourierAnalysis(int_4 nmmax, const TVector<T> datain, r_8 phi0) const
613
614same as previous one, but with a "datain" which is real (not complex) */
615template<class T>
616void SphericalTransformServer<T>::CFromFourierAnalysis(int_4 nmmax, const TVector<T> datain, TVector< complex<T> >& dataout, r_8 phi0) const
617{
618 //=======================================================================
619 // integrates (data * phi-dependence-of-Ylm) over phi
620 // --> function of m can be computed by FFT
621 // ! with 0<= m <= npoints/2 (: Nyquist)
622 // ! because the data is real the negative m are the conjugate of the
623 // ! positive ones
624
625 // datain est modifie
626 //
627 // =======================================================================
628 int_4 nph=datain.NElts();
629 if (nph <= 0)
630 {
631 throw PException("bizarre : vecteur datain de longueur nulle (CFromFourierAnalysis)");
632 }
633 // if (nph%2 != 0 )
634 // {
635 // throw PException("SphericalTransformServer<T>::CFromFourierAnalysis : longueur de datain impair ?");
636 // }
637 TVector<complex<T> > transformedData;
638
639 // la taille du vecteur complexe retourne est nph/2+1 (si la taille
640 // du vecteur reel entre est nph)
641 // cout << " longueur de datain = " << nph << endl;
642 fftIntfPtr_-> FFTForward(datain, transformedData);
643 // cout << " taille de la transformee " << transformedData.Size() << endl;
644 // TVector< complex<T> > dataout(nmmax+1);
645 dataout.ReSize(nmmax+1);
646
647 // on transfere le resultat de la fft dans dataout.
648
649 int maxFreqAccessiblesParFFT = min(nph/2,nmmax);
650 int i;
651 for (i=0;i<=maxFreqAccessiblesParFFT;i++) dataout(i)=transformedData(i);
652
653
654 // si dataout n'est pas plein, on complete jusqu'a nph+1 valeurs (a moins
655 // que dataout ne soit plein avant d'atteindre nph)
656 if (maxFreqAccessiblesParFFT != nmmax )
657 {
658 int maxMfft = min(nph,nmmax);
659 for (i=maxFreqAccessiblesParFFT+1; i<=maxMfft; i++)
660 {
661 dataout(i) = conj(dataout(nph-i) );
662 }
663 // on conplete, si necessaire, par periodicite
664 if ( maxMfft != nmmax )
665 {
666 for (int kk=nph+1; kk <= nmmax; kk++)
667 {
668 dataout(kk)=dataout(kk%nph);
669 }
670 }
671 }
672 for (i = 0;i <dataout.NElts();i++)
673 {
674 dataout(i)*= (complex<T>)(complex<double>(cos(-i*phi0),sin(-i*phi0)));
675 }
676 // return dataout;
677}
678
679 /*! \fn void SOPHYA::SphericalTransformServer::GenerateFromAlm(SphericalMap<T>& mapq,
680 SphericalMap<T>& mapu,
681 int_4 pixelSizeIndex,
682 const Alm<T>& alme,
683 const Alm<T>& almb) const
684
685synthesis of a polarization map from Alm coefficients. The spheres mapq and mapu contain respectively the Stokes parameters. */
686template<class T>
687void SphericalTransformServer<T>::GenerateFromAlm(SphericalMap<T>& mapq,
688 SphericalMap<T>& mapu,
689 int_4 pixelSizeIndex,
690 const Alm<T>& alme,
691 const Alm<T>& almb) const
692{
693 /*=======================================================================
694 computes a map form its alm for the HEALPIX pixelisation
695 map(theta,phi) = sum_l_m a_lm Y_lm(theta,phi)
696 = sum_m {e^(i*m*phi) sum_l a_lm*lambda_lm(theta)}
697
698 where Y_lm(theta,phi) = lambda(theta) * e^(i*m*phi)
699
700 * the recurrence of Ylm is the standard one (cf Num Rec)
701 * the sum over m is done by FFT
702
703 =======================================================================*/
704 int_4 nlmax=alme.Lmax();
705 if (nlmax != almb.Lmax())
706 {
707 cout << " SphericalTransformServer: les deux tableaux alm n'ont pas la meme taille" << endl;
708 throw SzMismatchError("SphericalTransformServer: les deux tableaux alm n'ont pas la meme taille");
709 }
710 int_4 nmmax=nlmax;
711 int_4 nsmax=0;
712 mapq.Resize(pixelSizeIndex);
713 mapu.Resize(pixelSizeIndex);
714 string sphere_type=mapq.TypeOfMap();
715 if (sphere_type != mapu.TypeOfMap())
716 {
717 cout << " SphericalTransformServer: les deux spheres ne sont pas de meme type" << endl;
718 cout << " type 1 " << sphere_type << endl;
719 cout << " type 2 " << mapu.TypeOfMap() << endl;
720 throw SzMismatchError("SphericalTransformServer: les deux spheres ne sont pas de meme type");
721
722 }
723 bool healpix = true;
724 if (sphere_type.substr(0,4) == "RING")
725 {
726 nsmax=mapq.SizeIndex();
727 }
728 else
729 // pour une sphere Gorski le nombre de pixels est 12*nsmax**2
730 // on calcule une quantite equivalente a nsmax pour la sphere-theta-phi
731 // en vue de l'application du critere Healpix : nlmax<=3*nsmax-1
732 // c'est approximatif ; a raffiner.
733 healpix = false;
734 if (sphere_type.substr(0,6) == "TETAFI")
735 {
736 nsmax=(int_4)sqrt(mapq.NbPixels()/12.);
737 }
738 else
739 {
740 cout << " unknown type of sphere : " << sphere_type << endl;
741 throw IOExc(" unknown type of sphere ");
742 }
743 cout << "GenerateFromAlm: the spheres are of type : " << sphere_type << endl;
744 cout << "GenerateFromAlm: size indices (nside) of spheres= " << nsmax << endl;
745 cout << "GenerateFromAlm: nlmax (from Alm) = " << nlmax << endl;
746 if (nlmax>3*nsmax-1)
747 {
748 cout << "GenerateFromAlm: nlmax should be <= 3*nside-1" << endl;
749 if (sphere_type.substr(0,6) == "TETAFI")
750 {
751 cout << " (for this criterium, nsmax is computed as sqrt(nbPixels/12))" << endl;
752 }
753 }
754 if (alme.Lmax()!=almb.Lmax())
755 {
756 cout << "GenerateFromAlm: arrays Alme and Almb have not the same size ? " << endl;
757 throw SzMismatchError("SphericalTransformServer: arrays Alme and Almb have not the same size ? ");
758 }
759 mapFromWX(nlmax, nmmax, mapq, mapu, alme, almb, healpix);
760 // mapFromPM(nlmax, nmmax, mapq, mapu, alme, almb);
761}
762 /*! \fn void SOPHYA::SphericalTransformServer::DecomposeToAlm(const SphericalMap<T>& mapq,
763 const SphericalMap<T>& mapu,
764 Alm<T>& alme,
765 Alm<T>& almb,
766 int_4 nlmax,
767 r_8 cos_theta_cut) const
768
769analysis of a polarization map into Alm coefficients.
770
771 The spheres \c mapq and \c mapu contain respectively the Stokes parameters.
772
773 \c a2lme and \c a2lmb will receive respectively electric and magnetic Alm's
774 nlmax : maximum value of the l index
775
776 \c cos_theta_cut : cosinus of the symmetric cut EULER angle theta : cos_theta_cut=0 means no cut ; cos_theta_cut=1 all the sphere is cut.
777
778
779 */
780template<class T>
781void SphericalTransformServer<T>::DecomposeToAlm(const SphericalMap<T>& mapq,
782 const SphericalMap<T>& mapu,
783 Alm<T>& alme,
784 Alm<T>& almb,
785 int_4 nlmax,
786 r_8 cos_theta_cut) const
787{
788 DecomposeToAlm(const_cast< SphericalMap<T>& >(mapq), const_cast< SphericalMap<T>& >(mapu), alme, almb, nlmax, cos_theta_cut);
789}
790
791 /*! \fn void SOPHYA::SphericalTransformServer::DecomposeToAlm(const SphericalMap<T>& mapq,
792 const SphericalMap<T>& mapu,
793 Alm<T>& alme,
794 Alm<T>& almb,
795 int_4 nlmax,
796 r_8 cos_theta_cut,
797 int iterationOrder) const
798
799analysis of a polarization map into Alm coefficients.
800
801 The spheres \c mapq and \c mapu contain respectively the Stokes parameters.
802
803 \c a2lme and \c a2lmb will receive respectively electric and magnetic Alm's
804 nlmax : maximum value of the l index
805
806 \c cos_theta_cut : cosinus of the symmetric cut EULER angle theta : cos_theta_cut=0 means no cut ; cos_theta_cut=1 all the sphere is cut.
807
808\param<iterationOrder> : 1,2,3,4.... order of an iterative analysis. (Default : 0 -> standard analysis). If iterationOrder is not null, the method works with SphereHEALPix but NOT WITH SphereThetaPhi maps !
809
810THE INPUT MAPS CAN BE MODIFIED (only if iterationOrder >0)
811
812 */
813template<class T>
814void SphericalTransformServer<T>::DecomposeToAlm(SphericalMap<T>& mapq,
815 SphericalMap<T>& mapu,
816 Alm<T>& alme,
817 Alm<T>& almb,
818 int_4 nlmax,
819 r_8 cos_theta_cut,
820 int iterationOrder) const
821{
822 int_4 nmmax = nlmax;
823 carteVersAlm(mapq, mapu, alme, almb, nlmax, cos_theta_cut);
824 if (iterationOrder > 0)
825 {
826 TVector<int_4> fact(iterationOrder+2);
827 fact(0) = 1;
828 int k;
829 for (k=1; k <= iterationOrder+1; k++)
830 {
831 fact(k) = fact(k-1)*k;
832 }
833 Alm<T> alme2(alme);
834 Alm<T> almb2(almb);
835 T Tzero = (T)0.;
836 complex<T> complexZero = complex<T>(Tzero, Tzero);
837 alme = complexZero;
838 almb = complexZero;
839 int signe = 1;
840 int nbIteration = iterationOrder+1;
841 for (k=1; k <= nbIteration; k++)
842 {
843 T facMult = (T)(0.5*signe*fact(iterationOrder)*(2*nbIteration-k)/(fact(k)*fact(nbIteration-k)));
844 for (int m = 0; m <= nmmax; m++)
845 {
846 for (int l = m; l<= nlmax; l++)
847 {
848 alme(l,m) += facMult*alme2(l,m);
849 almb(l,m) += facMult*almb2(l,m);
850 }
851 }
852 if (k == nbIteration) break;
853 signe = -signe;
854 for (int k=0; k< mapq.NbPixels(); k++)
855 {
856 mapq(k) = (T)0.;
857 mapu(k) = (T)0.;
858 }
859 // synthetize a map from the estimated alm
860 GenerateFromAlm(mapq,mapu,mapq.SizeIndex(),alme2,almb2);
861 alme2 = complexZero;
862 almb2 = complexZero;
863 // analyse the new map
864 carteVersAlm(mapq, mapu, alme2, almb2, nlmax, cos_theta_cut);
865 }
866 }
867}
868
869template<class T>
870void SphericalTransformServer<T>::carteVersAlm(const SphericalMap<T>& mapq,
871 const SphericalMap<T>& mapu,
872 Alm<T>& alme,
873 Alm<T>& almb,
874 int_4 nlmax,
875 r_8 cos_theta_cut) const
876{
877 int_4 nmmax = nlmax;
878 // resize et remise a zero
879 alme.ReSizeToLmax(nlmax);
880 almb.ReSizeToLmax(nlmax);
881
882
883 TVector<T> dataq;
884 TVector<T> datau;
885 TVector<int_4> pixNumber;
886
887 string sphere_type=mapq.TypeOfMap();
888 if (sphere_type != mapu.TypeOfMap())
889 {
890 cout << " SphericalTransformServer: les deux spheres ne sont pas de meme type" << endl;
891 cout << " type 1 " << sphere_type << endl;
892 cout << " type 2 " << mapu.TypeOfMap() << endl;
893 throw SzMismatchError("SphericalTransformServer: les deux spheres ne sont pas de meme type");
894
895 }
896 if (mapq.NbPixels()!=mapu.NbPixels())
897 {
898 cout << " DecomposeToAlm: map Q and map U have not same size ?" << endl;
899 throw SzMismatchError("SphericalTransformServer::DecomposeToAlm: map Q and map U have not same size ");
900 }
901 for (int_4 ith = 0; ith < mapq.NbThetaSlices(); ith++)
902 {
903 r_8 phi0;
904 r_8 theta;
905 mapq.GetThetaSlice(ith,theta,phi0, pixNumber,dataq);
906 mapu.GetThetaSlice(ith,theta,phi0, pixNumber,datau);
907 if (dataq.NElts() != datau.NElts() )
908 {
909 throw SzMismatchError("the spheres have not the same pixelization");
910 }
911 r_8 domega=mapq.PixSolAngle(mapq.PixIndexSph(theta,phi0));
912 double cth = cos(theta);
913 //part of the sky out of the symetric cut
914 bool keep_it = (fabs(cth) >= cos_theta_cut);
915 if (keep_it)
916 {
917 // almFromPM(pixNumber.NElts(), nlmax, nmmax, phi0, domega, theta, dataq, datau, alme, almb);
918 almFromWX(nlmax, nmmax, phi0, domega, theta, dataq, datau, alme, almb);
919 }
920 }
921}
922
923
924 /*! \fn void SOPHYA::SphericalTransformServer::almFromWX(int_4 nlmax, int_4 nmmax,
925 r_8 phi0, r_8 domega,
926 r_8 theta,
927 const TVector<T>& dataq,
928 const TVector<T>& datau,
929 Alm<T>& alme,
930 Alm<T>& almb) const
931
932Compute polarized Alm's as :
933\f[
934a_{lm}^E=\frac{1}{\sqrt{2}}\sum_{slices}{\omega_{pix}\left(\,_{w}\lambda_l^m\tilde{Q}-i\,_{x}\lambda_l^m\tilde{U}\right)}
935\f]
936\f[
937a_{lm}^B=\frac{1}{\sqrt{2}}\sum_{slices}{\omega_{pix}\left(i\,_{x}\lambda_l^m\tilde{Q}+\,_{w}\lambda_l^m\tilde{U}\right)}
938\f]
939
940where \f$\tilde{Q}\f$ and \f$\tilde{U}\f$ are C-coefficients computed by FFT (method CFromFourierAnalysis, called by present method) from the Stokes parameters.
941
942\f$\omega_{pix}\f$ are solid angle of each pixel.
943
944dataq, datau : Stokes parameters.
945
946 */
947template<class T>
948void SphericalTransformServer<T>::almFromWX(int_4 nlmax, int_4 nmmax,
949 r_8 phi0, r_8 domega,
950 r_8 theta,
951 const TVector<T>& dataq,
952 const TVector<T>& datau,
953 Alm<T>& alme,
954 Alm<T>& almb) const
955{
956 TVector< complex<T> > phaseq(nmmax+1);
957 TVector< complex<T> > phaseu(nmmax+1);
958 // TVector<complex<T> > datain(nph);
959 for (int i=0;i< nmmax+1;i++)
960 {
961 phaseq(i)=0;
962 phaseu(i)=0;
963 }
964 // for(int kk=0; kk<nph; kk++) datain(kk)=complex<T>(dataq(kk),0.);
965
966 // phaseq = CFromFourierAnalysis(nmmax,dataq,phi0);
967 CFromFourierAnalysis(nmmax,dataq,phaseq, phi0);
968
969 // phaseu= CFromFourierAnalysis(nmmax,datau,phi0);
970 CFromFourierAnalysis(nmmax,datau,phaseu, phi0);
971
972 LambdaWXBuilder lwxb(theta,nlmax,nmmax);
973
974 r_8 sqr2inv=1/Rac2;
975 for (int m = 0; m <= nmmax; m++)
976 {
977 r_8 lambda_w=0.;
978 r_8 lambda_x=0.;
979 lwxb.lam_wx(m, m, lambda_w, lambda_x);
980 complex<T> zi_lam_x((T)0., (T)lambda_x);
981 alme(m,m) += ( (T)(lambda_w)*phaseq(m)-zi_lam_x*phaseu(m) )*(T)(domega*sqr2inv);
982 almb(m,m) += ( (T)(lambda_w)*phaseu(m)+zi_lam_x*phaseq(m) )*(T)(domega*sqr2inv);
983
984 for (int l = m+1; l<= nlmax; l++)
985 {
986 lwxb.lam_wx(l, m, lambda_w, lambda_x);
987 zi_lam_x = complex<T>((T)0., (T)lambda_x);
988 alme(l,m) += ( (T)(lambda_w)*phaseq(m)-zi_lam_x*phaseu(m) )*(T)(domega*sqr2inv);
989 almb(l,m) += ( (T)(lambda_w)*phaseu(m)+zi_lam_x*phaseq(m) )*(T)(domega*sqr2inv);
990 }
991 }
992}
993
994
995 /*! \fn void SOPHYA::SphericalTransformServer::almFromPM(int_4 nph, int_4 nlmax,
996 int_4 nmmax,
997 r_8 phi0, r_8 domega,
998 r_8 theta,
999 const TVector<T>& dataq,
1000 const TVector<T>& datau,
1001 Alm<T>& alme,
1002 Alm<T>& almb) const
1003
1004Compute polarized Alm's as :
1005\f[
1006a_{lm}^E=-\frac{1}{2}\sum_{slices}{\omega_{pix}\left(\,_{+}\lambda_l^m\tilde{P^+}+\,_{-}\lambda_l^m\tilde{P^-}\right)}
1007\f]
1008\f[
1009a_{lm}^B=\frac{i}{2}\sum_{slices}{\omega_{pix}\left(\,_{+}\lambda_l^m\tilde{P^+}-\,_{-}\lambda_l^m\tilde{P^-}\right)}
1010\f]
1011
1012where \f$\tilde{P^{\pm}}=\tilde{Q}\pm\tilde{U}\f$ computed by FFT (method CFromFourierAnalysis, called by present method) from the Stokes parameters,\f$Q\f$ and \f$U\f$ .
1013
1014\f$\omega_{pix}\f$ are solid angle of each pixel.
1015
1016dataq, datau : Stokes parameters.
1017
1018 */
1019template<class T>
1020void SphericalTransformServer<T>::almFromPM(int_4 nph, int_4 nlmax,
1021 int_4 nmmax,
1022 r_8 phi0, r_8 domega,
1023 r_8 theta,
1024 const TVector<T>& dataq,
1025 const TVector<T>& datau,
1026 Alm<T>& alme,
1027 Alm<T>& almb) const
1028{
1029 TVector< complex<T> > phasep(nmmax+1);
1030 TVector< complex<T> > phasem(nmmax+1);
1031 TVector<complex<T> > datain(nph);
1032 for (int i=0;i< nmmax+1;i++)
1033 {
1034 phasep(i)=0;
1035 phasem(i)=0;
1036 }
1037 int kk;
1038 for(kk=0; kk<nph; kk++) datain(kk)=complex<T>(dataq(kk),datau(kk));
1039
1040 phasep = CFromFourierAnalysis(nmmax,datain,phi0);
1041
1042 for(kk=0; kk<nph; kk++) datain(kk)=complex<T>(dataq(kk),-datau(kk));
1043 phasem = CFromFourierAnalysis(nmmax,datain,phi0);
1044 LambdaPMBuilder lpmb(theta,nlmax,nmmax);
1045
1046 for (int m = 0; m <= nmmax; m++)
1047 {
1048 r_8 lambda_p=0.;
1049 r_8 lambda_m=0.;
1050 complex<T> im((T)0.,(T)1.);
1051 lpmb.lam_pm(m, m, lambda_p, lambda_m);
1052
1053 alme(m,m) += -( (T)(lambda_p)*phasep(m) + (T)(lambda_m)*phasem(m) )*(T)(domega*0.5);
1054 almb(m,m) += im*( (T)(lambda_p)*phasep(m) - (T)(lambda_m)*phasem(m) )*(T)(domega*0.5);
1055 for (int l = m+1; l<= nlmax; l++)
1056 {
1057 lpmb.lam_pm(l, m, lambda_p, lambda_m);
1058 alme(l,m) += -( (T)(lambda_p)*phasep(m) + (T)(lambda_m)*phasem(m) )*(T)(domega*0.5);
1059 almb(l,m) += im* ( (T)(lambda_p)*phasep(m) - (T)(lambda_m)*phasem(m) )*(T)(domega*0.5);
1060 }
1061 }
1062}
1063
1064
1065/*! \fn void SOPHYA::SphericalTransformServer::mapFromWX(int_4 nlmax, int_4 nmmax,
1066 SphericalMap<T>& mapq,
1067 SphericalMap<T>& mapu,
1068 const Alm<T>& alme,
1069 const Alm<T>& almb, bool healpix) const
1070
1071synthesis of Stokes parameters following formulae :
1072
1073\f[
1074Q=\sum_{m=-mmax}^{mmax}b_m^qe^{im\varphi}
1075\f]
1076\f[
1077U=\sum_{m=-mmax}^{mmax}b_m^ue^{im\varphi}
1078\f]
1079
1080computed by FFT (method fourierSynthesisFromB called by the present one)
1081
1082with :
1083
1084\f[
1085b_m^q=-\frac{1}{\sqrt{2}}\sum_{l=|m|}^{lmax}{\left(\,_{w}\lambda_l^ma_{lm}^E-i\,_{x}\lambda_l^ma_{lm}^B\right) }
1086\f]
1087\f[
1088b_m^u=\frac{1}{\sqrt{2}}\sum_{l=|m|}^{lmax}{\left(i\,_{x}\lambda_l^ma_{lm}^E+\,_{w}\lambda_l^ma_{lm}^B\right) }
1089\f]
1090 */
1091template<class T>
1092void SphericalTransformServer<T>::mapFromWX(int_4 nlmax, int_4 nmmax,
1093 SphericalMap<T>& mapq,
1094 SphericalMap<T>& mapu,
1095 const Alm<T>& alme,
1096 const Alm<T>& almb, bool healpix) const
1097{
1098 int i;
1099
1100 Bm<complex<T> > b_m_theta_q(nmmax);
1101 Bm<complex<T> > b_m_theta_u(nmmax);
1102
1103 for (int_4 ith = 0; ith < mapq.NbThetaSlices();ith++)
1104 {
1105 int_4 nph;
1106 r_8 phi0;
1107 r_8 theta;
1108 TVector<int_4> pixNumber;
1109 TVector<T> datan;
1110
1111 mapq.GetThetaSlice(ith,theta,phi0, pixNumber,datan);
1112 nph = pixNumber.NElts();
1113 // -----------------------------------------------------
1114 // for each theta, and each m, computes
1115 // b(m,theta) = sum_over_l>m (lambda_l_m(theta) * a_l_m)
1116 // ------------------------------------------------------
1117 LambdaWXBuilder lwxb(theta,nlmax,nmmax);
1118 // LambdaPMBuilder lpmb(theta,nlmax,nmmax);
1119 r_8 sqr2inv=1/Rac2;
1120 int m;
1121 for (m = 0; m <= nmmax; m++)
1122 {
1123 r_8 lambda_w=0.;
1124 r_8 lambda_x=0.;
1125 lwxb.lam_wx(m, m, lambda_w, lambda_x);
1126 complex<T> zi_lam_x((T)0., (T)lambda_x);
1127
1128 b_m_theta_q(m) = ( (T)(lambda_w) * alme(m,m) - zi_lam_x * almb(m,m))*(T)sqr2inv ;
1129 b_m_theta_u(m) = ( (T)(lambda_w) * almb(m,m) + zi_lam_x * alme(m,m))*(T)sqr2inv;
1130
1131
1132 for (int l = m+1; l<= nlmax; l++)
1133 {
1134
1135 lwxb.lam_wx(l, m, lambda_w, lambda_x);
1136 zi_lam_x= complex<T>((T)0., (T)lambda_x);
1137
1138 b_m_theta_q(m) += ((T)(lambda_w)*alme(l,m)-zi_lam_x *almb(l,m))*(T)sqr2inv;
1139 b_m_theta_u(m) += ((T)(lambda_w)*almb(l,m)+zi_lam_x *alme(l,m))*(T)sqr2inv;
1140
1141 }
1142 }
1143 // obtains the negative m of b(m,theta) (= complex conjugate)
1144 for (m=1;m<=nmmax;m++)
1145 {
1146 b_m_theta_q(-m) = conj(b_m_theta_q(m));
1147 b_m_theta_u(-m) = conj(b_m_theta_u(m));
1148 }
1149 if (healpix)
1150 {
1151 TVector<T> Tempq = RfourierSynthesisFromB(b_m_theta_q,nph,phi0);
1152 TVector<T> Tempu = RfourierSynthesisFromB(b_m_theta_u,nph,phi0);
1153 for (i=0;i< nph;i++)
1154 {
1155 mapq(pixNumber(i))=Tempq(i);
1156 mapu(pixNumber(i))=Tempu(i);
1157 }
1158 }
1159 else
1160 // pour des pixelisations quelconques (autres que HEALPix
1161 // nph n'est pas toujours pair
1162 // ca fait des problemes pour les transformees de Fourier
1163 // car le server de TF ajuste la longueur du vecteur reel
1164 // en sortie de TF, bref, la securite veut qu'on prenne une
1165 // TF complexe
1166 {
1167 TVector<complex<T> > Tempq = fourierSynthesisFromB(b_m_theta_q,nph,phi0);
1168 TVector<complex<T> > Tempu = fourierSynthesisFromB(b_m_theta_u,nph,phi0);
1169 for (i=0;i< nph;i++)
1170 {
1171 mapq(pixNumber(i))=Tempq(i).real();
1172 mapu(pixNumber(i))=Tempu(i).real();
1173 }
1174 }
1175 }
1176}
1177/*! \fn void SOPHYA::SphericalTransformServer::mapFromPM(int_4 nlmax, int_4 nmmax,
1178 SphericalMap<T>& mapq,
1179 SphericalMap<T>& mapu,
1180 const Alm<T>& alme,
1181 const Alm<T>& almb) const
1182
1183synthesis of polarizations following formulae :
1184
1185\f[
1186P^+ = \sum_{m=-mmax}^{mmax} {b_m^+e^{im\varphi} }
1187\f]
1188\f[
1189P^- = \sum_{m=-mmax}^{mmax} {b_m^-e^{im\varphi} }
1190\f]
1191
1192computed by FFT (method fourierSynthesisFromB called by the present one)
1193
1194with :
1195
1196\f[
1197b_m^+=-\sum_{l=|m|}^{lmax}{\,_{+}\lambda_l^m \left( a_{lm}^E+ia_{lm}^B \right) }
1198\f]
1199\f[
1200b_m^-=-\sum_{l=|m|}^{lmax}{\,_{+}\lambda_l^m \left( a_{lm}^E-ia_{lm}^B \right) }
1201\f]
1202 */
1203template<class T>
1204void SphericalTransformServer<T>::mapFromPM(int_4 nlmax, int_4 nmmax,
1205 SphericalMap<T>& mapq,
1206 SphericalMap<T>& mapu,
1207 const Alm<T>& alme,
1208 const Alm<T>& almb) const
1209{
1210 Bm<complex<T> > b_m_theta_p(nmmax);
1211 Bm<complex<T> > b_m_theta_m(nmmax);
1212 for (int_4 ith = 0; ith < mapq.NbThetaSlices();ith++)
1213 {
1214 int_4 nph;
1215 r_8 phi0;
1216 r_8 theta;
1217 TVector<int_4> pixNumber;
1218 TVector<T> datan;
1219
1220 mapq.GetThetaSlice(ith,theta,phi0, pixNumber,datan);
1221 nph = pixNumber.NElts();
1222
1223 // -----------------------------------------------------
1224 // for each theta, and each m, computes
1225 // b(m,theta) = sum_over_l>m (lambda_l_m(theta) * a_l_m)
1226 //------------------------------------------------------
1227
1228 LambdaPMBuilder lpmb(theta,nlmax,nmmax);
1229 int m;
1230 for (m = 0; m <= nmmax; m++)
1231 {
1232 r_8 lambda_p=0.;
1233 r_8 lambda_m=0.;
1234 lpmb.lam_pm(m, m, lambda_p, lambda_m);
1235 complex<T> im((T)0.,(T)1.);
1236
1237 b_m_theta_p(m) = (T)(lambda_p )* (-alme(m,m) - im * almb(m,m));
1238 b_m_theta_m(m) = (T)(lambda_m) * (-alme(m,m) + im * almb(m,m));
1239
1240
1241 for (int l = m+1; l<= nlmax; l++)
1242 {
1243 lpmb.lam_pm(l, m, lambda_p, lambda_m);
1244 b_m_theta_p(m) += (T)(lambda_p)*(-alme(l,m)-im *almb(l,m));
1245 b_m_theta_m(m) += (T)(lambda_m)*(-alme(l,m)+im *almb(l,m));
1246 }
1247 }
1248
1249 // obtains the negative m of b(m,theta) (= complex conjugate)
1250 for (m=1;m<=nmmax;m++)
1251 {
1252 b_m_theta_p(-m) = conj(b_m_theta_m(m));
1253 b_m_theta_m(-m) = conj(b_m_theta_p(m));
1254 }
1255
1256 TVector<complex<T> > Tempp = fourierSynthesisFromB(b_m_theta_p,nph,phi0);
1257 TVector<complex<T> > Tempm = fourierSynthesisFromB(b_m_theta_m,nph,phi0);
1258
1259 for (int i=0;i< nph;i++)
1260 {
1261 mapq(pixNumber(i))=0.5*(Tempp(i)+Tempm(i)).real();
1262 mapu(pixNumber(i))=0.5*(Tempp(i)-Tempm(i)).imag();
1263 }
1264 }
1265}
1266
1267
1268 /*! \fn void SOPHYA::SphericalTransformServer::GenerateFromCl(SphericalMap<T>& sphq,
1269 SphericalMap<T>& sphu,
1270 int_4 pixelSizeIndex,
1271 const TVector<T>& Cle,
1272 const TVector<T>& Clb,
1273 const r_8 fwhm) const
1274
1275synthesis of a polarization map from power spectra electric-Cl and magnetic-Cl (Alm's are generated randomly, following a gaussian distribution).
1276 \param fwhm FWHM in arcmin for random generation of Alm's (eg. 5)
1277*/
1278template<class T>
1279void SphericalTransformServer<T>::GenerateFromCl(SphericalMap<T>& sphq,
1280 SphericalMap<T>& sphu,
1281 int_4 pixelSizeIndex,
1282 const TVector<T>& Cle,
1283 const TVector<T>& Clb,
1284 const r_8 fwhm) const
1285{
1286 if (Cle.NElts() != Clb.NElts())
1287 {
1288 cout << " SphericalTransformServer: les deux tableaux Cl n'ont pas la meme taille" << endl;
1289 throw SzMismatchError("SphericalTransformServer::GenerateFromCl : two Cl arrays have not same size");
1290 }
1291
1292 // Alm<T> a2lme,a2lmb;
1293 // almFromCl(a2lme, Cle, fwhm);
1294 // almFromCl(a2lmb, Clb, fwhm);
1295 // Alm<T> a2lme = almFromCl(Cle, fwhm);
1296 // Alm<T> a2lmb = almFromCl(Clb, fwhm);
1297 Alm<T> a2lme(Cle, fwhm);
1298 Alm<T> a2lmb(Clb, fwhm);
1299
1300 GenerateFromAlm(sphq,sphu,pixelSizeIndex,a2lme,a2lmb);
1301}
1302 /*! \fn void SOPHYA::SphericalTransformServer::GenerateFromCl(SphericalMap<T>& sph,
1303 int_4 pixelSizeIndex,
1304 const TVector<T>& Cl,
1305 const r_8 fwhm) const
1306
1307synthesis of a temperature map from power spectrum Cl (Alm's are generated randomly, following a gaussian distribution). */
1308template<class T>
1309void SphericalTransformServer<T>::GenerateFromCl(SphericalMap<T>& sph,
1310 int_4 pixelSizeIndex,
1311 const TVector<T>& Cl,
1312 const r_8 fwhm) const
1313{
1314
1315 Alm<T> alm(Cl, fwhm);
1316 GenerateFromAlm(sph,pixelSizeIndex, alm );
1317}
1318
1319
1320
1321/*! \fn TVector<T> SOPHYA::SphericalTransformServer::DecomposeToCl(SphericalMap<T>& sph, int_4 nlmax, r_8 cos_theta_cut, int iterationOrder) const
1322
1323\return power spectrum from analysis of a temperature map. THE MAP CAN BE MODIFIED (if iterationOrder >0)
1324
1325 \param<nlmax> : maximum value of the l index
1326
1327 \param<cos_theta_cut> : cosinus of the symmetric cut EULER angle theta : cos_theta_cut=0 means no cut ; cos_theta_cut=1 all the sphere is cut.
1328
1329\param<iterationOrder> : 1,2,3,4.... order of an iterative analysis. If iterationOrder is not null, the method works with SphereHEALPix but NOT WITH SphereThetaPhi maps !
1330
1331 */
1332template <class T>
1333TVector<T> SphericalTransformServer<T>::DecomposeToCl(SphericalMap<T>& sph, int_4 nlmax, r_8 cos_theta_cut, int iterationOrder) const
1334{
1335 Alm<T> alm;
1336 DecomposeToAlm( sph, alm, nlmax, cos_theta_cut, iterationOrder);
1337 // power spectrum
1338 return alm.powerSpectrum();
1339}
1340
1341
1342/*! \fn TVector<T> SOPHYA::SphericalTransformServer::DecomposeToCl(const SphericalMap<T>& sph, int_4 nlmax, r_8 cos_theta_cut) const
1343
1344\return power spectrum from analysis of a temperature map.
1345
1346 \param<nlmax> : maximum value of the l index
1347
1348 \param<cos_theta_cut> : cosinus of the symmetric cut EULER angle theta : cos_theta_cut=0 means no cut ; cos_theta_cut=1 all the sphere is cut.
1349
1350
1351 */
1352
1353
1354template <class T>
1355TVector<T> SphericalTransformServer<T>::DecomposeToCl(const SphericalMap<T>& sph, int_4 nlmax, r_8 cos_theta_cut) const
1356{
1357 Alm<T> alm;
1358 DecomposeToAlm( sph, alm, nlmax, cos_theta_cut);
1359 // power spectrum
1360 return alm.powerSpectrum();
1361}
1362
1363#ifdef __CXX_PRAGMA_TEMPLATES__
1364#pragma define_template SphericalTransformServer<r_8>
1365#pragma define_template SphericalTransformServer<r_4>
1366#endif
1367#if defined(ANSI_TEMPLATES) || defined(GNU_TEMPLATES)
1368template class SOPHYA::SphericalTransformServer<r_8>;
1369template class SOPHYA::SphericalTransformServer<r_4>;
1370#endif
Note: See TracBrowser for help on using the repository browser.