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

Last change on this file since 2991 was 2991, checked in by ansari, 19 years ago

Corrections dans SphericalTransformServer:

  • gestion taille tableau sortie + imag(f_nyquist) dans RfourierSynthesisFromB
  • Utilisation RfourierSynthesisFromB (TF cmplx->reel) pour synthese

depuis alm, pour tout type de carte

  • Optimisation acces aux pixels avec la methode GetThetaSliceDataPtr()

Reza , 23 Juin 2006

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