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

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

1/ passage en sa_size_t (au lieu de int) dans Alm<T> et Bm<T>
2/ Ajout des methodes optimisees (statiques) pour calcul transforme Ylm
ds LambdaLMBuilder et utilisation ds SphericalTransformServer

Reza , 1/06/2006

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