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

Last change on this file since 3510 was 3510, checked in by ansari, 17 years ago

Nettoyage alm.h .cc , utilisation RandomGenerator par Alm<T> et SphericalTransformServer , Reza 08/08/2008

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