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

Last change on this file since 3572 was 3572, checked in by cmv, 17 years ago

char* -> const char* pour regler les problemes de deprecated string const... + comparaison unsigned signed + suppression EVOL_PLANCK rz+cmv 07/02/2009

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