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

Last change on this file since 2715 was 2625, checked in by cmv, 21 years ago

juste une petite erreur de frappe dans le blabla... cmv 01/10/04

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