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

Last change on this file since 1218 was 1218, checked in by ansari, 25 years ago

doc dans .cc

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