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

Last change on this file since 3508 was 3508, checked in by ansari, 17 years ago

Ajout mineur de commentaire/doc , Reza 08/08/2008

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