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

Last change on this file since 1683 was 1683, checked in by lemeur, 24 years ago

methode iterative pour analyse harmonique

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