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

Last change on this file since 1624 was 1624, checked in by cmv, 24 years ago

On enleve les SetTemp() inutiles cmv 6/8/01

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