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

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

Modif cosmetique - suppression warning compil CC, Reza 14/11/2000

File size: 39.2 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 r_8 phi0;
460 r_8 theta;
461 map.GetThetaSlice(ith,theta,phi0,pixNumber ,data);
462 for (int i=0;i< nmmax+1;i++)
463 {
464 phase(i)=0;
465 }
466 double cth = cos(theta);
467
468 //part of the sky out of the symetric cut
469 bool keep_it = (abs(cth) >= cos_theta_cut);
470
471 if (keep_it)
472 {
473 // tableau datain a supprimer
474 // TVector<complex<T> > datain(pixNumber.NElts());
475 // for(int kk=0; kk<nph; kk++) datain(kk)=complex<T>(data(kk),(T)0.);
476
477 // phase = CFromFourierAnalysis(nmmax,datain,phi0);
478 phase = CFromFourierAnalysis(nmmax,data,phi0);
479
480 }
481
482 /*-----------------------------------------------------------------------
483 computes the a_lm by integrating over theta
484 lambda_lm(theta) * phas_m(theta)
485 for each m and l
486 -----------------------------------------------------------------------*/
487 // LambdaBuilder lb(theta,nlmax,nmmax);
488 LambdaLMBuilder lb(theta,nlmax,nmmax);
489 r_8 domega=map.PixSolAngle(map.PixIndexSph(theta,phi0));
490 for (int m = 0; m <= nmmax; m++)
491 {
492 alm(m,m) += (T)lb.lamlm(m,m) * phase(m) * (T)domega; //m,m even
493 for (int l = m+1; l<= nlmax; l++)
494 {
495 alm(l,m) += (T)lb.lamlm(l,m) * phase(m)*(T)domega;
496 }
497 }
498 }
499 return alm;
500}
501 /*! \fn TVector< complex<T> > SOPHYA::SphericalTransformServer::CFromFourierAnalysis(int_4 nmmax, const TVector<complex<T> >datain, r_8 phi0) const
502
503\return a vector with mmax elements which are sums :
504\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.
505 */
506template<class T>
507TVector< complex<T> > SphericalTransformServer<T>::CFromFourierAnalysis(int_4 nmmax, const TVector<complex<T> >datain, r_8 phi0) const
508{
509 /*=======================================================================
510 integrates (data * phi-dependence-of-Ylm) over phi
511 --> function of m can be computed by FFT
512
513 datain est modifie
514 =======================================================================*/
515 int_4 nph=datain.NElts();
516 if (nph <= 0)
517 {
518 throw PException("bizarre : vecteur datain de longueur nulle (CFromFourierAnalysis)");
519 }
520 TVector<complex<T> > transformedData(nph);
521 fftIntfPtr_-> FFTForward(datain, transformedData);
522
523 //dataout.ReSize(nmmax+1);
524 TVector< complex<T> > dataout(nmmax+1);
525 // dataout.SetTemp(true);
526
527 int im_max=min(nph,nmmax+1);
528 int i;
529 for (i=0;i< dataout.NElts();i++) dataout(i)=complex<T>((T)0.,(T)0.);
530 for (i=0;i<im_max;i++) dataout(i)=transformedData(i);
531
532
533 // for (int i = 0;i <im_max;i++){
534 // dataout(i)*= (complex<T>)(complex<double>(cos(-i*phi0),sin(-i*phi0)));
535 // }
536 for (int kk=nph; kk<dataout.NElts(); kk++) dataout(kk)=dataout(kk%nph);
537 for (i = 0;i <dataout.NElts();i++){
538 dataout(i)*= (complex<T>)(complex<double>(cos(-i*phi0),sin(-i*phi0)));
539 }
540 return dataout;
541}
542
543//&&&&&&&&& nouvelle version
544/* \fn TVector< complex<T> > SOPHYA::SphericalTransformServer::CFromFourierAnalysis(int_4 nmmax, const TVector<T> datain, r_8 phi0) const
545
546same as previous one, but with a "datain" which is real (not complex) */
547template<class T>
548TVector< complex<T> > SphericalTransformServer<T>::CFromFourierAnalysis(int_4 nmmax, const TVector<T> datain, r_8 phi0) const
549{
550 //=======================================================================
551 // integrates (data * phi-dependence-of-Ylm) over phi
552 // --> function of m can be computed by FFT
553 // ! with 0<= m <= npoints/2 (: Nyquist)
554 // ! because the data is real the negative m are the conjugate of the
555 // ! positive ones
556
557 // datain est modifie
558 //
559 // =======================================================================
560 int_4 nph=datain.NElts();
561 if (nph <= 0)
562 {
563 throw PException("bizarre : vecteur datain de longueur nulle (CFromFourierAnalysis)");
564 }
565 TVector<complex<T> > transformedData;
566 // a remodifier
567 //FFTPackServer ffts;
568 //ffts.setNormalize(false);
569 //ffts.FFTForward(datain, transformedData);
570
571 fftIntfPtr_-> FFTForward(datain, transformedData);
572 //
573
574 //dataout.ReSize(nmmax+1);
575 TVector< complex<T> > dataout(nmmax+1);
576 // dataout.SetTemp(true);
577
578 // on transfere le resultat de la fft dans dataout.
579 // on s'assure que ca ne depasse pas la taille de dataout
580 int sizeOfTransformToGet = min(transformedData.NElts(),nmmax+1);
581 // int im_max=min(transformedData.NElts()-1,nmmax);
582 int i;
583 for (i=0;i<sizeOfTransformToGet;i++) dataout(i)=transformedData(i);
584
585
586 // si dataout n'est pas plein, on complete jusqu'a nph valeurs (a moins
587 // que dataout ne soit plein avant d'atteindre nph)
588 if (sizeOfTransformToGet == (transformedData.NElts()))
589 {
590 for (i=transformedData.NElts(); i<min(nph,dataout.NElts()); i++)
591 {
592
593 // dataout(i) = conj(dataout(2*sizeOfTransformToGet-i-2) );
594 dataout(i) = conj(dataout(nph-i) );
595 }
596 // on conplete, si necessaire, par periodicite
597 for (int kk=nph; kk<dataout.NElts(); kk++)
598 {
599 dataout(kk)=dataout(kk%nph);
600 }
601 }
602 for (i = 0;i <dataout.NElts();i++){
603 dataout(i)*= (complex<T>)(complex<double>(cos(-i*phi0),sin(-i*phi0)));
604 }
605 return dataout;
606}
607
608 /*! \fn void SOPHYA::SphericalTransformServer::GenerateFromAlm(SphericalMap<T>& mapq,
609 SphericalMap<T>& mapu,
610 int_4 pixelSizeIndex,
611 const Alm<T>& alme,
612 const Alm<T>& almb) const
613
614synthesis of a polarization map from Alm coefficients. The spheres mapq and mapu contain respectively the Stokes parameters. */
615template<class T>
616void SphericalTransformServer<T>::GenerateFromAlm(SphericalMap<T>& mapq,
617 SphericalMap<T>& mapu,
618 int_4 pixelSizeIndex,
619 const Alm<T>& alme,
620 const Alm<T>& almb) const
621{
622 /*=======================================================================
623 computes a map form its alm for the HEALPIX pixelisation
624 map(theta,phi) = sum_l_m a_lm Y_lm(theta,phi)
625 = sum_m {e^(i*m*phi) sum_l a_lm*lambda_lm(theta)}
626
627 where Y_lm(theta,phi) = lambda(theta) * e^(i*m*phi)
628
629 * the recurrence of Ylm is the standard one (cf Num Rec)
630 * the sum over m is done by FFT
631
632 =======================================================================*/
633 int_4 nlmax=alme.Lmax();
634 if (nlmax != almb.Lmax())
635 {
636 cout << " SphericalTransformServer: les deux tableaux alm n'ont pas la meme taille" << endl;
637 throw SzMismatchError("SphericalTransformServer: les deux tableaux alm n'ont pas la meme taille");
638 }
639 int_4 nmmax=nlmax;
640 int_4 nsmax=0;
641 mapq.Resize(pixelSizeIndex);
642 mapu.Resize(pixelSizeIndex);
643 char* sphere_type=mapq.TypeOfMap();
644 if (strncmp(sphere_type,mapu.TypeOfMap(),4) != 0)
645 {
646 cout << " SphericalTransformServer: les deux spheres ne sont pas de meme type" << endl;
647 cout << " type 1 " << sphere_type << endl;
648 cout << " type 2 " << mapu.TypeOfMap() << endl;
649 throw SzMismatchError("SphericalTransformServer: les deux spheres ne sont pas de meme type");
650
651 }
652 if (strncmp(sphere_type,"RING",4) == 0)
653 {
654 nsmax=mapq.SizeIndex();
655 }
656 else
657 // pour une sphere Gorski le nombre de pixels est 12*nsmax**2
658 // on calcule une quantite equivalente a nsmax pour la sphere-theta-phi
659 // en vue de l'application du critere Healpix : nlmax<=3*nsmax-1
660 // c'est approximatif ; a raffiner.
661 if (strncmp(sphere_type,"TETAFI",6) == 0)
662 {
663 nsmax=(int_4)sqrt(mapq.NbPixels()/12.);
664 }
665 else
666 {
667 cout << " unknown type of sphere : " << sphere_type << endl;
668 throw IOExc(" unknown type of sphere ");
669 }
670 cout << "GenerateFromAlm: the spheres are of type : " << sphere_type << endl;
671 cout << "GenerateFromAlm: size indices (nside) of spheres= " << nsmax << endl;
672 cout << "GenerateFromAlm: nlmax (from Alm) = " << nlmax << endl;
673 if (nlmax>3*nsmax-1)
674 {
675 cout << "GenerateFromAlm: nlmax should be <= 3*nside-1" << endl;
676 if (strncmp(sphere_type,"TETAFI",6) == 0)
677 {
678 cout << " (for this criterium, nsmax is computed as sqrt(nbPixels/12))" << endl;
679 }
680 }
681 if (alme.Lmax()!=almb.Lmax())
682 {
683 cout << "GenerateFromAlm: arrays Alme and Almb have not the same size ? " << endl;
684 throw SzMismatchError("SphericalTransformServer: arrays Alme and Almb have not the same size ? ");
685 }
686 mapFromWX(nlmax, nmmax, mapq, mapu, alme, almb);
687 // mapFromPM(nlmax, nmmax, mapq, mapu, alme, almb);
688}
689
690
691 /*! \fn void SOPHYA::SphericalTransformServer::DecomposeToAlm(const SphericalMap<T>& mapq,
692 const SphericalMap<T>& mapu,
693 Alm<T>& alme,
694 Alm<T>& almb,
695 int_4 nlmax,
696 r_8 cos_theta_cut) const
697
698analysis of a polarization map into Alm coefficients.
699
700 The spheres \c mapq and \c mapu contain respectively the Stokes parameters.
701
702 \c a2lme and \c a2lmb will receive respectively electric and magnetic Alm's
703 nlmax : maximum value of the l index
704
705 \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.
706 */
707template<class T>
708void SphericalTransformServer<T>::DecomposeToAlm(const SphericalMap<T>& mapq,
709 const SphericalMap<T>& mapu,
710 Alm<T>& alme,
711 Alm<T>& almb,
712 int_4 nlmax,
713 r_8 cos_theta_cut) const
714{
715 int_4 nmmax = nlmax;
716 // resize et remise a zero
717 alme.ReSizeToLmax(nlmax);
718 almb.ReSizeToLmax(nlmax);
719
720
721 TVector<T> dataq;
722 TVector<T> datau;
723 TVector<int_4> pixNumber;
724
725 char* sphere_type=mapq.TypeOfMap();
726 if (strncmp(sphere_type,mapu.TypeOfMap(),4) != 0)
727 {
728 cout << " SphericalTransformServer: les deux spheres ne sont pas de meme type" << endl;
729 cout << " type 1 " << sphere_type << endl;
730 cout << " type 2 " << mapu.TypeOfMap() << endl;
731 throw SzMismatchError("SphericalTransformServer: les deux spheres ne sont pas de meme type");
732
733 }
734 if (mapq.NbPixels()!=mapu.NbPixels())
735 {
736 cout << " DecomposeToAlm: map Q and map U have not same size ?" << endl;
737 throw SzMismatchError("SphericalTransformServer::DecomposeToAlm: map Q and map U have not same size ");
738 }
739 for (int_4 ith = 0; ith < mapq.NbThetaSlices(); ith++)
740 {
741 r_8 phi0;
742 r_8 theta;
743 mapq.GetThetaSlice(ith,theta,phi0, pixNumber,dataq);
744 mapu.GetThetaSlice(ith,theta,phi0, pixNumber,datau);
745 if (dataq.NElts() != datau.NElts() )
746 {
747 throw SzMismatchError("the spheres have not the same pixelization");
748 }
749 r_8 domega=mapq.PixSolAngle(mapq.PixIndexSph(theta,phi0));
750 double cth = cos(theta);
751 //part of the sky out of the symetric cut
752 bool keep_it = (abs(cth) >= cos_theta_cut);
753 if (keep_it)
754 {
755 // almFromPM(pixNumber.NElts(), nlmax, nmmax, phi0, domega, theta, dataq, datau, alme, almb);
756 almFromWX(nlmax, nmmax, phi0, domega, theta, dataq, datau, alme, almb);
757 }
758 }
759}
760
761
762 /*! \fn void SOPHYA::SphericalTransformServer::almFromWX(int_4 nlmax, int_4 nmmax,
763 r_8 phi0, r_8 domega,
764 r_8 theta,
765 const TVector<T>& dataq,
766 const TVector<T>& datau,
767 Alm<T>& alme,
768 Alm<T>& almb) const
769
770Compute polarized Alm's as :
771\f[
772a_{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)}
773\f]
774\f[
775a_{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)}
776\f]
777
778where \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.
779
780\f$\omega_{pix}\f$ are solid angle of each pixel.
781
782dataq, datau : Stokes parameters.
783
784 */
785template<class T>
786void SphericalTransformServer<T>::almFromWX(int_4 nlmax, int_4 nmmax,
787 r_8 phi0, r_8 domega,
788 r_8 theta,
789 const TVector<T>& dataq,
790 const TVector<T>& datau,
791 Alm<T>& alme,
792 Alm<T>& almb) const
793{
794 TVector< complex<T> > phaseq(nmmax+1);
795 TVector< complex<T> > phaseu(nmmax+1);
796 // TVector<complex<T> > datain(nph);
797 for (int i=0;i< nmmax+1;i++)
798 {
799 phaseq(i)=0;
800 phaseu(i)=0;
801 }
802 // for(int kk=0; kk<nph; kk++) datain(kk)=complex<T>(dataq(kk),0.);
803
804 // phaseq = CFromFourierAnalysis(nmmax,datain,phi0);
805 phaseq = CFromFourierAnalysis(nmmax,dataq,phi0);
806
807 // for(int kk=0; kk<nph; kk++) datain(kk)=complex<T>(datau(kk),0.);
808
809 // phaseu= CFromFourierAnalysis(nlmax,nmmax,datain,phi0);
810 phaseu= CFromFourierAnalysis(nmmax,datau,phi0);
811
812 LambdaWXBuilder lwxb(theta,nlmax,nmmax);
813
814 r_8 sqr2inv=1/Rac2;
815 for (int m = 0; m <= nmmax; m++)
816 {
817 r_8 lambda_w=0.;
818 r_8 lambda_x=0.;
819 lwxb.lam_wx(m, m, lambda_w, lambda_x);
820 complex<T> zi_lam_x((T)0., (T)lambda_x);
821 alme(m,m) += ( (T)(lambda_w)*phaseq(m)-zi_lam_x*phaseu(m) )*(T)(domega*sqr2inv);
822 almb(m,m) += ( (T)(lambda_w)*phaseu(m)+zi_lam_x*phaseq(m) )*(T)(domega*sqr2inv);
823
824 for (int l = m+1; l<= nlmax; l++)
825 {
826 lwxb.lam_wx(l, m, lambda_w, lambda_x);
827 zi_lam_x = complex<T>((T)0., (T)lambda_x);
828 alme(l,m) += ( (T)(lambda_w)*phaseq(m)-zi_lam_x*phaseu(m) )*(T)(domega*sqr2inv);
829 almb(l,m) += ( (T)(lambda_w)*phaseu(m)+zi_lam_x*phaseq(m) )*(T)(domega*sqr2inv);
830 }
831 }
832}
833
834
835 /*! \fn void SOPHYA::SphericalTransformServer::almFromPM(int_4 nph, int_4 nlmax,
836 int_4 nmmax,
837 r_8 phi0, r_8 domega,
838 r_8 theta,
839 const TVector<T>& dataq,
840 const TVector<T>& datau,
841 Alm<T>& alme,
842 Alm<T>& almb) const
843
844Compute polarized Alm's as :
845\f[
846a_{lm}^E=-\frac{1}{2}\sum_{slices}{\omega_{pix}\left(\,_{+}\lambda_l^m\tilde{P^+}+\,_{-}\lambda_l^m\tilde{P^-}\right)}
847\f]
848\f[
849a_{lm}^B=\frac{i}{2}\sum_{slices}{\omega_{pix}\left(\,_{+}\lambda_l^m\tilde{P^+}-\,_{-}\lambda_l^m\tilde{P^-}\right)}
850\f]
851
852where \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$ .
853
854\f$\omega_{pix}\f$ are solid angle of each pixel.
855
856dataq, datau : Stokes parameters.
857
858 */
859template<class T>
860void SphericalTransformServer<T>::almFromPM(int_4 nph, int_4 nlmax,
861 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{
869 TVector< complex<T> > phasep(nmmax+1);
870 TVector< complex<T> > phasem(nmmax+1);
871 TVector<complex<T> > datain(nph);
872 for (int i=0;i< nmmax+1;i++)
873 {
874 phasep(i)=0;
875 phasem(i)=0;
876 }
877 int kk;
878 for(kk=0; kk<nph; kk++) datain(kk)=complex<T>(dataq(kk),datau(kk));
879
880 phasep = CFromFourierAnalysis(nmmax,datain,phi0);
881
882 for(kk=0; kk<nph; kk++) datain(kk)=complex<T>(dataq(kk),-datau(kk));
883 phasem = CFromFourierAnalysis(nmmax,datain,phi0);
884 LambdaPMBuilder lpmb(theta,nlmax,nmmax);
885
886 for (int m = 0; m <= nmmax; m++)
887 {
888 r_8 lambda_p=0.;
889 r_8 lambda_m=0.;
890 complex<T> im((T)0.,(T)1.);
891 lpmb.lam_pm(m, m, lambda_p, lambda_m);
892
893 alme(m,m) += -( (T)(lambda_p)*phasep(m) + (T)(lambda_m)*phasem(m) )*(T)(domega*0.5);
894 almb(m,m) += im*( (T)(lambda_p)*phasep(m) - (T)(lambda_m)*phasem(m) )*(T)(domega*0.5);
895 for (int l = m+1; l<= nlmax; l++)
896 {
897 lpmb.lam_pm(l, m, lambda_p, lambda_m);
898 alme(l,m) += -( (T)(lambda_p)*phasep(m) + (T)(lambda_m)*phasem(m) )*(T)(domega*0.5);
899 almb(l,m) += im* ( (T)(lambda_p)*phasep(m) - (T)(lambda_m)*phasem(m) )*(T)(domega*0.5);
900 }
901 }
902}
903
904
905/*! \fn void SOPHYA::SphericalTransformServer::mapFromWX(int_4 nlmax, int_4 nmmax,
906 SphericalMap<T>& mapq,
907 SphericalMap<T>& mapu,
908 const Alm<T>& alme,
909 const Alm<T>& almb) const
910
911synthesis of Stokes parameters following formulae :
912
913\f[
914Q=\sum_{m=-mmax}^{mmax}b_m^qe^{im\varphi}
915\f]
916\f[
917U=\sum_{m=-mmax}^{mmax}b_m^ue^{im\varphi}
918\f]
919
920computed by FFT (method fourierSynthesisFromB called by the present one)
921
922with :
923
924\f[
925b_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) }
926\f]
927\f[
928b_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) }
929\f]
930 */
931template<class T>
932void SphericalTransformServer<T>::mapFromWX(int_4 nlmax, int_4 nmmax,
933 SphericalMap<T>& mapq,
934 SphericalMap<T>& mapu,
935 const Alm<T>& alme,
936 const Alm<T>& almb) const
937{
938 Bm<complex<T> > b_m_theta_q(nmmax);
939 Bm<complex<T> > b_m_theta_u(nmmax);
940
941 for (int_4 ith = 0; ith < mapq.NbThetaSlices();ith++)
942 {
943 int_4 nph;
944 r_8 phi0;
945 r_8 theta;
946 TVector<int_4> pixNumber;
947 TVector<T> datan;
948
949 mapq.GetThetaSlice(ith,theta,phi0, pixNumber,datan);
950 nph = pixNumber.NElts();
951 // -----------------------------------------------------
952 // for each theta, and each m, computes
953 // b(m,theta) = sum_over_l>m (lambda_l_m(theta) * a_l_m)
954 // ------------------------------------------------------
955 LambdaWXBuilder lwxb(theta,nlmax,nmmax);
956 // LambdaPMBuilder lpmb(theta,nlmax,nmmax);
957 r_8 sqr2inv=1/Rac2;
958 int m;
959 for (m = 0; m <= nmmax; m++)
960 {
961 r_8 lambda_w=0.;
962 r_8 lambda_x=0.;
963 lwxb.lam_wx(m, m, lambda_w, lambda_x);
964 complex<T> zi_lam_x((T)0., (T)lambda_x);
965
966 b_m_theta_q(m) = ( (T)(lambda_w) * alme(m,m) - zi_lam_x * almb(m,m))*(T)sqr2inv ;
967 b_m_theta_u(m) = ( (T)(lambda_w) * almb(m,m) + zi_lam_x * alme(m,m))*(T)sqr2inv;
968
969
970 for (int l = m+1; l<= nlmax; l++)
971 {
972
973 lwxb.lam_wx(l, m, lambda_w, lambda_x);
974 zi_lam_x= complex<T>((T)0., (T)lambda_x);
975
976 b_m_theta_q(m) += ((T)(lambda_w)*alme(l,m)-zi_lam_x *almb(l,m))*(T)sqr2inv;
977 b_m_theta_u(m) += ((T)(lambda_w)*almb(l,m)+zi_lam_x *alme(l,m))*(T)sqr2inv;
978
979 }
980 }
981 // obtains the negative m of b(m,theta) (= complex conjugate)
982 for (m=1;m<=nmmax;m++)
983 {
984 b_m_theta_q(-m) = conj(b_m_theta_q(m));
985 b_m_theta_u(-m) = conj(b_m_theta_u(m));
986 }
987
988 // TVector<complex<T> > Tempq = fourierSynthesisFromB(b_m_theta_q,nph,phi0);
989 // TVector<complex<T> > Tempu = fourierSynthesisFromB(b_m_theta_u,nph,phi0);
990 TVector<T> Tempq = RfourierSynthesisFromB(b_m_theta_q,nph,phi0);
991 TVector<T> Tempu = RfourierSynthesisFromB(b_m_theta_u,nph,phi0);
992 for (int i=0;i< nph;i++)
993 {
994 // mapq(pixNumber(i))=Tempq(i).real();
995 // mapu(pixNumber(i))=Tempu(i).real();
996 mapq(pixNumber(i))=Tempq(i);
997 mapu(pixNumber(i))=Tempu(i);
998
999 }
1000 }
1001}
1002/*! \fn void SOPHYA::SphericalTransformServer::mapFromPM(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 polarizations following formulae :
1009
1010\f[
1011P^+ = \sum_{m=-mmax}^{mmax} {b_m^+e^{im\varphi} }
1012\f]
1013\f[
1014P^- = \sum_{m=-mmax}^{mmax} {b_m^-e^{im\varphi} }
1015\f]
1016
1017computed by FFT (method fourierSynthesisFromB called by the present one)
1018
1019with :
1020
1021\f[
1022b_m^+=-\sum_{l=|m|}^{lmax}{\,_{+}\lambda_l^m \left( a_{lm}^E+ia_{lm}^B \right) }
1023\f]
1024\f[
1025b_m^-=-\sum_{l=|m|}^{lmax}{\,_{+}\lambda_l^m \left( a_{lm}^E-ia_{lm}^B \right) }
1026\f]
1027 */
1028template<class T>
1029void SphericalTransformServer<T>::mapFromPM(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_p(nmmax);
1036 Bm<complex<T> > b_m_theta_m(nmmax);
1037 for (int_4 ith = 0; ith < mapq.NbThetaSlices();ith++)
1038 {
1039 int_4 nph;
1040 r_8 phi0;
1041 r_8 theta;
1042 TVector<int_4> pixNumber;
1043 TVector<T> datan;
1044
1045 mapq.GetThetaSlice(ith,theta,phi0, pixNumber,datan);
1046 nph = pixNumber.NElts();
1047
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
1053 LambdaPMBuilder lpmb(theta,nlmax,nmmax);
1054 int m;
1055 for (m = 0; m <= nmmax; m++)
1056 {
1057 r_8 lambda_p=0.;
1058 r_8 lambda_m=0.;
1059 lpmb.lam_pm(m, m, lambda_p, lambda_m);
1060 complex<T> im((T)0.,(T)1.);
1061
1062 b_m_theta_p(m) = (T)(lambda_p )* (-alme(m,m) - im * almb(m,m));
1063 b_m_theta_m(m) = (T)(lambda_m) * (-alme(m,m) + im * almb(m,m));
1064
1065
1066 for (int l = m+1; l<= nlmax; l++)
1067 {
1068 lpmb.lam_pm(l, m, lambda_p, lambda_m);
1069 b_m_theta_p(m) += (T)(lambda_p)*(-alme(l,m)-im *almb(l,m));
1070 b_m_theta_m(m) += (T)(lambda_m)*(-alme(l,m)+im *almb(l,m));
1071 }
1072 }
1073
1074 // obtains the negative m of b(m,theta) (= complex conjugate)
1075 for (m=1;m<=nmmax;m++)
1076 {
1077 b_m_theta_p(-m) = conj(b_m_theta_m(m));
1078 b_m_theta_m(-m) = conj(b_m_theta_p(m));
1079 }
1080
1081 TVector<complex<T> > Tempp = fourierSynthesisFromB(b_m_theta_p,nph,phi0);
1082 TVector<complex<T> > Tempm = fourierSynthesisFromB(b_m_theta_m,nph,phi0);
1083
1084 for (int i=0;i< nph;i++)
1085 {
1086 mapq(pixNumber(i))=0.5*(Tempp(i)+Tempm(i)).real();
1087 mapu(pixNumber(i))=0.5*(Tempp(i)-Tempm(i)).imag();
1088 }
1089 }
1090}
1091
1092
1093 /*! \fn void SOPHYA::SphericalTransformServer::GenerateFromCl(SphericalMap<T>& sphq,
1094 SphericalMap<T>& sphu,
1095 int_4 pixelSizeIndex,
1096 const TVector<T>& Cle,
1097 const TVector<T>& Clb,
1098 const r_8 fwhm) const
1099
1100synthesis of a polarization map from power spectra electric-Cl and magnetic-Cl (Alm's are generated randomly, following a gaussian distribution).
1101 \param fwhm FWHM in arcmin for random generation of Alm's (eg. 5)
1102*/
1103template<class T>
1104void SphericalTransformServer<T>::GenerateFromCl(SphericalMap<T>& sphq,
1105 SphericalMap<T>& sphu,
1106 int_4 pixelSizeIndex,
1107 const TVector<T>& Cle,
1108 const TVector<T>& Clb,
1109 const r_8 fwhm) const
1110{
1111 if (Cle.NElts() != Clb.NElts())
1112 {
1113 cout << " SphericalTransformServer: les deux tableaux Cl n'ont pas la meme taille" << endl;
1114 throw SzMismatchError("SphericalTransformServer::GenerateFromCl : two Cl arrays have not same size");
1115 }
1116
1117 // Alm<T> a2lme,a2lmb;
1118 // almFromCl(a2lme, Cle, fwhm);
1119 // almFromCl(a2lmb, Clb, fwhm);
1120 // Alm<T> a2lme = almFromCl(Cle, fwhm);
1121 // Alm<T> a2lmb = almFromCl(Clb, fwhm);
1122 Alm<T> a2lme(Cle, fwhm);
1123 Alm<T> a2lmb(Clb, fwhm);
1124
1125 GenerateFromAlm(sphq,sphu,pixelSizeIndex,a2lme,a2lmb);
1126}
1127 /*! \fn void SOPHYA::SphericalTransformServer::GenerateFromCl(SphericalMap<T>& sph,
1128 int_4 pixelSizeIndex,
1129 const TVector<T>& Cl,
1130 const r_8 fwhm) const
1131
1132synthesis of a temperature map from power spectrum Cl (Alm's are generated randomly, following a gaussian distribution). */
1133template<class T>
1134void SphericalTransformServer<T>::GenerateFromCl(SphericalMap<T>& sph,
1135 int_4 pixelSizeIndex,
1136 const TVector<T>& Cl,
1137 const r_8 fwhm) const
1138{
1139
1140 Alm<T> alm(Cl, fwhm);
1141 GenerateFromAlm(sph,pixelSizeIndex, alm );
1142}
1143
1144
1145
1146/*! \fn TVector<T> SOPHYA::SphericalTransformServer::DecomposeToCl(const SphericalMap<T>& sph, int_4 nlmax, r_8 cos_theta_cut) const
1147
1148\return power spectrum from analysis of a temperature map.
1149
1150 \param<nlmax> : maximum value of the l index
1151
1152 \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.
1153 */
1154template <class T>
1155TVector<T> SphericalTransformServer<T>::DecomposeToCl(const SphericalMap<T>& sph, int_4 nlmax, r_8 cos_theta_cut) const
1156{
1157 Alm<T> alm=DecomposeToAlm( sph, nlmax, cos_theta_cut);
1158 // power spectrum
1159 return alm.powerSpectrum();
1160}
1161
1162#ifdef __CXX_PRAGMA_TEMPLATES__
1163#pragma define_template SphericalTransformServer<r_8>
1164#pragma define_template SphericalTransformServer<r_4>
1165#endif
1166#if defined(ANSI_TEMPLATES) || defined(GNU_TEMPLATES)
1167template class SphericalTransformServer<r_8>;
1168template class SphericalTransformServer<r_4>;
1169#endif
Note: See TracBrowser for help on using the repository browser.