alm_powspec_tools.cc

00001 /*
00002  *  This file is part of Healpix_cxx.
00003  *
00004  *  Healpix_cxx is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  Healpix_cxx is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with Healpix_cxx; if not, write to the Free Software
00016  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00017  *
00018  *  For more information about HEALPix, see http://healpix.sourceforge.net
00019  */
00020 
00021 /*
00022  *  Healpix_cxx is being developed at the Max-Planck-Institut fuer Astrophysik
00023  *  and financially supported by the Deutsches Zentrum fuer Luft- und Raumfahrt
00024  *  (DLR).
00025  */
00026 
00027 /*
00028  *  Copyright (C) 2003-2015 Max-Planck-Society
00029  *  Author: Martin Reinecke
00030  */
00031 
00032 #include "alm_powspec_tools.h"
00033 #include "string_utils.h"
00034 #include "alm.h"
00035 #include "planck_rng.h"
00036 #include "powspec.h"
00037 #include "xcomplex.h"
00038 #include "rotmatrix.h"
00039 #include "openmp_support.h"
00040 #include "wigner.h"
00041 #include "lsconstants.h"
00042 
00043 using namespace std;
00044 template<typename T> void create_alm
00045   (const PowSpec &powspec, Alm<xcomplex<T> > &alm, planck_rng &rng)
00046   {
00047   int lmax = alm.Lmax();
00048   int mmax = alm.Mmax();
00049   const double hsqrt2 = 1/sqrt(2.);
00050 
00051   for (int l=0; l<=lmax; ++l)
00052     {
00053     double rms_tt = sqrt(powspec.tt(l));
00054     double zeta1_r = rng.rand_gauss();
00055     alm(l,0) = T(zeta1_r * rms_tt);
00056     for (int m=1; m<=min(l,mmax); ++m)
00057       {
00058       zeta1_r = rng.rand_gauss()*hsqrt2;
00059       double zeta1_i = rng.rand_gauss()*hsqrt2;
00060       alm(l,m) = xcomplex<T>(T(zeta1_r*rms_tt), T(zeta1_i*rms_tt));
00061       }
00062     }
00063   }
00064 
00065 template void create_alm (const PowSpec &powspec,
00066   Alm<xcomplex<float> > &alm, planck_rng &rng);
00067 template void create_alm (const PowSpec &powspec,
00068   Alm<xcomplex<double> > &alm, planck_rng &rng);
00069 
00070 
00071 template<typename T> void create_alm_pol
00072   (const PowSpec &ps,
00073    Alm<xcomplex<T> > &almT,
00074    Alm<xcomplex<T> > &almG,
00075    Alm<xcomplex<T> > &almC,
00076    planck_rng &rng)
00077   {
00078   int lmax = almT.Lmax();
00079   int mmax = almT.Mmax();
00080   const double hsqrt2 = 1/sqrt(2.);
00081 
00082   bool full = ps.Num_specs()==6;
00083 
00084   for (int l=0; l<=lmax; ++l)
00085     {
00086     double rms_tt=0, rms_g1=0, rms_c1=0;
00087     if (ps.tt(l) > 0)
00088       {
00089       rms_tt = sqrt(ps.tt(l));
00090       rms_g1 = ps.tg(l)/rms_tt;
00091       if (full) rms_c1 = ps.tc(l)/rms_tt;
00092       }
00093 
00094     double zeta1_r = rng.rand_gauss();
00095     almT(l,0) = T(zeta1_r * rms_tt);
00096     almG(l,0) = T(zeta1_r * rms_g1);
00097     almC(l,0) = T(zeta1_r * rms_c1);
00098     for (int m=1; m<=min(l,mmax); ++m)
00099       {
00100       zeta1_r = rng.rand_gauss()*hsqrt2;
00101       double zeta1_i = rng.rand_gauss()*hsqrt2;
00102       almT(l,m) = xcomplex<T>(T(zeta1_r*rms_tt), T(zeta1_i*rms_tt));
00103       almG(l,m) = xcomplex<T>(T(zeta1_r*rms_g1), T(zeta1_i*rms_g1));
00104       almC(l,m) = xcomplex<T>(T(zeta1_r*rms_c1), T(zeta1_i*rms_c1));
00105       }
00106     }
00107 
00108   for (int l=0; l<=lmax; ++l)
00109     {
00110     double rms_g2=0, rms_c2=0, rms_c3=0;
00111     if (ps.tt(l) > 0)
00112       {
00113       rms_g2 = ps.gg(l) - (ps.tg(l)/ps.tt(l))*ps.tg(l);
00114       if (rms_g2<=0)
00115         {
00116         planck_assert (abs(rms_g2) <= 1e-8*abs(ps.gg(l)),
00117           "Inconsistent TT, GG and TG spectra at l="+dataToString(l));
00118         rms_g2 = 0;
00119         }
00120       double rms_c1 = full ? (ps.tc(l) / sqrt(ps.tt(l))) : 0.;
00121       if (rms_g2>0)
00122         {
00123         rms_g2 = sqrt(rms_g2);
00124         if (full) rms_c2 = (ps.gc(l) - ps.tc(l) * (ps.tg(l)/ps.tt(l))) / rms_g2;
00125         }
00126       rms_c3 = ps.cc(l) - rms_c1*rms_c1 - rms_c2*rms_c2; 
00127       if (rms_c3<=0)
00128         {
00129         planck_assert (abs(rms_c3) <= 1e-8*abs(ps.cc(l)),
00130           "Inconsistent spectra at l="+dataToString(l));
00131         rms_c3 = 0;
00132         }
00133       rms_c3 = sqrt(rms_c3);
00134       }
00135     double zeta2_r = rng.rand_gauss();
00136     double zeta3_r = rng.rand_gauss();
00137     almG(l,0) += T(zeta2_r*rms_g2);
00138     almC(l,0) += T(zeta3_r*rms_c3 + zeta2_r*rms_c2);
00139 
00140     for (int m=1; m<=min(l,mmax); ++m)
00141       {
00142       zeta2_r = rng.rand_gauss()*hsqrt2;
00143       double zeta2_i = rng.rand_gauss()*hsqrt2;
00144       zeta3_r = rng.rand_gauss()*hsqrt2;
00145       double zeta3_i = rng.rand_gauss()*hsqrt2;
00146 
00147       almG(l,m) += xcomplex<T> (T(zeta2_r*rms_g2),T(zeta2_i*rms_g2));
00148       almC(l,m) += xcomplex<T> (T(zeta3_r*rms_c3),T(zeta3_i*rms_c3))
00149                   +xcomplex<T> (T(zeta2_r*rms_c2),T(zeta2_i*rms_c2));
00150       }
00151     }
00152   }
00153 
00154 template void create_alm_pol
00155   (const PowSpec &powspec,
00156    Alm<xcomplex<float> > &almT,
00157    Alm<xcomplex<float> > &almG,
00158    Alm<xcomplex<float> > &almC,
00159    planck_rng &rng);
00160 template void create_alm_pol
00161   (const PowSpec &powspec,
00162    Alm<xcomplex<double> > &almT,
00163    Alm<xcomplex<double> > &almG,
00164    Alm<xcomplex<double> > &almC,
00165    planck_rng &rng);
00166 
00167 
00168 template<typename T> void extract_crosspowspec
00169   (const Alm<xcomplex<T> > &alm1,
00170    const Alm<xcomplex<T> > &alm2,PowSpec &powspec)
00171   {
00172   planck_assert (alm1.conformable(alm2), "a_lm are not conformable");
00173   arr<double> tt(alm1.Lmax()+1);
00174   for (int l=0; l<=alm1.Lmax(); ++l)
00175     {
00176     tt[l] = alm1(l,0).real()*alm2(l,0).real();
00177     int limit = min(l,alm1.Mmax());
00178     for (int m=1; m<=limit; ++m)
00179       tt[l] += 2 * (alm1(l,m).real()*alm2(l,m).real()
00180                   + alm1(l,m).imag()*alm2(l,m).imag());
00181     tt[l] /= (2*l+1);
00182     }
00183   powspec.Set(tt);
00184   }
00185 
00186 template void extract_crosspowspec
00187   (const Alm<xcomplex<float> > &alm1,
00188    const Alm<xcomplex<float> > &alm2, PowSpec &powspec);
00189 template void extract_crosspowspec
00190   (const Alm<xcomplex<double> > &alm1,
00191    const Alm<xcomplex<double> > &alm2, PowSpec &powspec);
00192 
00193 
00194 template<typename T> void extract_powspec
00195   (const Alm<xcomplex<T> > &alm, PowSpec &powspec)
00196   { extract_crosspowspec (alm,alm,powspec); }
00197 
00198 template void extract_powspec
00199   (const Alm<xcomplex<float> > &alm, PowSpec &powspec);
00200 template void extract_powspec
00201   (const Alm<xcomplex<double> > &alm, PowSpec &powspec);
00202 
00203 namespace {
00204 
00205 template<typename T> void extract_crosspowspec
00206   (const Alm<xcomplex<T> > &almT1,
00207    const Alm<xcomplex<T> > &almG1,
00208    const Alm<xcomplex<T> > &almC1,
00209    const Alm<xcomplex<T> > &almT2,
00210    const Alm<xcomplex<T> > &almG2,
00211    const Alm<xcomplex<T> > &almC2,
00212    PowSpec &powspec)
00213   {
00214   planck_assert (almT1.conformable(almG1) && almT1.conformable(almC1) &&
00215                  almT1.conformable(almT2) && almT1.conformable(almG2) &&
00216                  almT1.conformable(almC2), "a_lm are not conformable");
00217 
00218   int lmax = almT1.Lmax();
00219   arr<double> tt(lmax+1), gg(lmax+1), cc(lmax+1), tg(lmax+1),
00220               tc(lmax+1), gc(lmax+1);
00221   for (int l=0; l<=lmax; ++l)
00222     {
00223     tt[l] = almT1(l,0).real()*almT2(l,0).real();
00224     gg[l] = almG1(l,0).real()*almG2(l,0).real();
00225     cc[l] = almC1(l,0).real()*almC2(l,0).real();
00226     tg[l] = almT1(l,0).real()*almG2(l,0).real();
00227     tc[l] = almT1(l,0).real()*almC2(l,0).real();
00228     gc[l] = almG1(l,0).real()*almC2(l,0).real();
00229     int limit = min(l,almT1.Mmax());
00230     for (int m=1; m<=limit; ++m)
00231       {
00232       tt[l] += 2 * (almT1(l,m).real()*almT2(l,m).real()
00233                   + almT1(l,m).imag()*almT2(l,m).imag());
00234       gg[l] += 2 * (almG1(l,m).real()*almG2(l,m).real()
00235                   + almG1(l,m).imag()*almG2(l,m).imag());
00236       cc[l] += 2 * (almC1(l,m).real()*almC2(l,m).real()
00237                   + almC1(l,m).imag()*almC2(l,m).imag());
00238       tg[l] += 2 * (almT1(l,m).real()*almG2(l,m).real()
00239                   + almT1(l,m).imag()*almG2(l,m).imag());
00240       tc[l] += 2 * (almT1(l,m).real()*almC2(l,m).real()
00241                   + almT1(l,m).imag()*almC2(l,m).imag());
00242       gc[l] += 2 * (almG1(l,m).real()*almC2(l,m).real()
00243                   + almG1(l,m).imag()*almC2(l,m).imag());
00244       }
00245     tt[l] /= (2*l+1);
00246     gg[l] /= (2*l+1);
00247     cc[l] /= (2*l+1);
00248     tg[l] /= (2*l+1);
00249     tc[l] /= (2*l+1);
00250     gc[l] /= (2*l+1);
00251     }
00252   powspec.Set(tt,gg,cc,tg,tc,gc);
00253   }
00254 
00255 } // unnamed namespace
00256 
00257 template<typename T> void extract_powspec
00258   (const Alm<xcomplex<T> > &almT,
00259    const Alm<xcomplex<T> > &almG,
00260    const Alm<xcomplex<T> > &almC,
00261    PowSpec &powspec)
00262   { extract_crosspowspec(almT,almG,almC,almT,almG,almC,powspec); }
00263 
00264 template void extract_powspec
00265   (const Alm<xcomplex<float> > &almT,
00266    const Alm<xcomplex<float> > &almG,
00267    const Alm<xcomplex<float> > &almC,
00268    PowSpec &powspec);
00269 template void extract_powspec
00270   (const Alm<xcomplex<double> > &almT,
00271    const Alm<xcomplex<double> > &almG,
00272    const Alm<xcomplex<double> > &almC,
00273    PowSpec &powspec);
00274 
00275 
00276 template<typename T> void smoothWithGauss
00277   (Alm<xcomplex<T> > &alm, double fwhm)
00278   {
00279   int fct = (fwhm>=0) ? 1 : -1;
00280   double sigma = fwhm*fwhm2sigma;
00281   arr<double> gb(alm.Lmax()+1);
00282   for (int l=0; l<=alm.Lmax(); ++l)
00283     gb[l] = exp(-.5*fct*l*(l+1)*sigma*sigma);
00284   alm.ScaleL(gb);
00285   }
00286 
00287 template void smoothWithGauss
00288   (Alm<xcomplex<float> > &alm, double fwhm);
00289 template void smoothWithGauss
00290   (Alm<xcomplex<double> > &alm, double fwhm);
00291 
00292 
00293 template<typename T> void smoothWithGauss
00294   (Alm<xcomplex<T> > &almT,
00295    Alm<xcomplex<T> > &almG,
00296    Alm<xcomplex<T> > &almC,
00297    double fwhm)
00298   {
00299   int fct = (fwhm>=0) ? 1 : -1;
00300   double sigma = fwhm*fwhm2sigma;
00301   double fact_pol = exp(2*fct*sigma*sigma);
00302   arr<double> gb(almT.Lmax()+1);
00303   for (int l=0; l<=almT.Lmax(); ++l)
00304     gb[l] = exp(-.5*fct*l*(l+1)*sigma*sigma);
00305   almT.ScaleL(gb);
00306   for (int l=0; l<=almT.Lmax(); ++l)
00307     gb[l] *= fact_pol;
00308   almG.ScaleL(gb); almC.ScaleL(gb);
00309   }
00310 
00311 template<typename T> void applyCosineWindow
00312   (Alm<xcomplex<T> > &alm, int lmin, int lmax)
00313   {
00314   planck_assert((lmin>=0)&&(lmax>lmin),"bad lmin/lmax");
00315   arr<double> cw(alm.Lmax()+1);
00316   for (int i=0; i<int(cw.size()); ++i)
00317   if (i<lmin)
00318     cw[i]=1;
00319   else if (i<lmax)
00320     cw[i]=(1+cos(pi*(i-lmin)/double(lmax-lmin)))/2;
00321   else
00322     cw[i]=0;
00323 
00324   alm.ScaleL(cw);
00325   }
00326 
00327 template void applyCosineWindow
00328   (Alm<xcomplex<float> > &alm, int lmin, int lmax);
00329 template void applyCosineWindow
00330   (Alm<xcomplex<double> > &alm, int lmin, int lmax);
00331 
00332 template void smoothWithGauss
00333   (Alm<xcomplex<float> > &almT,
00334    Alm<xcomplex<float> > &almG,
00335    Alm<xcomplex<float> > &almC,
00336    double fwhm);
00337 template void smoothWithGauss
00338   (Alm<xcomplex<double> > &almT,
00339    Alm<xcomplex<double> > &almG,
00340    Alm<xcomplex<double> > &almC,
00341    double fwhm);
00342 
00343 template<typename T> void rotate_alm (Alm<xcomplex<T> > &alm,
00344   double psi, double theta, double phi)
00345   {
00346   planck_assert (alm.Lmax()==alm.Mmax(),
00347     "rotate_alm: lmax must be equal to mmax");
00348   int lmax=alm.Lmax();
00349   arr<xcomplex<double> > exppsi(lmax+1), expphi(lmax+1);
00350   for (int m=0; m<=lmax; ++m)
00351     {
00352     exppsi[m] = dcomplex(cos(psi*m),-sin(psi*m));
00353     expphi[m] = dcomplex(cos(phi*m),-sin(phi*m));
00354     }
00355 
00356   wigner_d_risbo_openmp rec(lmax,theta);
00357 
00358   arr<xcomplex<double> > almtmp(lmax+1);
00359 
00360   for (int l=0; l<=lmax; ++l)
00361     {
00362     const arr2<double> &d(rec.recurse());
00363 
00364     for (int m=0; m<=l; ++m)
00365       almtmp[m] = xcomplex<double>(alm(l,0))*d[l][l+m];
00366 
00367 #pragma omp parallel
00368 {
00369     int64 lo,hi;
00370     openmp_calc_share(0,l+1,lo,hi);
00371 
00372     bool flip = true;
00373     for (int mm=1; mm<=l; ++mm)
00374       {
00375       dcomplex t1 = dcomplex(alm(l,mm))*exppsi[mm];
00376       bool flip2 = ((mm+lo)&1) ? true : false;
00377       for (int m=lo; m<hi; ++m)
00378         {
00379         double d1 = flip2 ? -d[l-mm][l-m] : d[l-mm][l-m];
00380         double d2 = flip  ? -d[l-mm][l+m] : d[l-mm][l+m];
00381         double f1 = d1+d2, f2 = d1-d2;
00382         almtmp[m]+=dcomplex(t1.real()*f1,t1.imag()*f2);
00383         flip2 = !flip2;
00384         }
00385       flip = !flip;
00386       }
00387 }
00388 
00389     for (int m=0; m<=l; ++m)
00390       alm(l,m) = xcomplex<T>(almtmp[m]*expphi[m]);
00391     }
00392   }
00393 
00394 template void rotate_alm (Alm<xcomplex<float> > &alm,
00395   double psi, double theta, double phi);
00396 template void rotate_alm (Alm<xcomplex<double> > &alm,
00397   double psi, double theta, double phi);
00398 
00399 template<typename T> void rotate_alm (Alm<xcomplex<T> > &almT,
00400   Alm<xcomplex<T> > &almG, Alm<xcomplex<T> > &almC,
00401   double psi, double theta, double phi)
00402   {
00403   planck_assert (almT.Lmax()==almT.Mmax(),
00404     "rotate_alm: lmax must be equal to mmax");
00405   planck_assert (almG.conformable(almT) && almC.conformable(almT),
00406     "rotate_alm: a_lm are not conformable");
00407   int lmax=almT.Lmax();
00408   arr<xcomplex<double> > exppsi(lmax+1), expphi(lmax+1);
00409   for (int m=0; m<=lmax; ++m)
00410     {
00411     exppsi[m] = dcomplex(cos(psi*m),-sin(psi*m));
00412     expphi[m] = dcomplex(cos(phi*m),-sin(phi*m));
00413     }
00414 
00415   wigner_d_risbo_openmp rec(lmax,theta);
00416 
00417   arr<xcomplex<double> > almtmpT(lmax+1), almtmpG(lmax+1), almtmpC(lmax+1);
00418 
00419   for (int l=0; l<=lmax; ++l)
00420     {
00421     const arr2<double> &d(rec.recurse());
00422 
00423     for (int m=0; m<=l; ++m)
00424       {
00425       almtmpT[m] = xcomplex<double>(almT(l,0))*d[l][m+l];
00426       almtmpG[m] = xcomplex<double>(almG(l,0))*d[l][m+l];
00427       almtmpC[m] = xcomplex<double>(almC(l,0))*d[l][m+l];
00428       }
00429 
00430 #pragma omp parallel
00431 {
00432     int64 lo,hi;
00433     openmp_calc_share(0,l+1,lo,hi);
00434 
00435     bool flip = true;
00436     for (int mm=1; mm<=l; ++mm)
00437       {
00438       dcomplex t1T = dcomplex(almT(l,mm))*exppsi[mm];
00439       dcomplex t1G = dcomplex(almG(l,mm))*exppsi[mm];
00440       dcomplex t1C = dcomplex(almC(l,mm))*exppsi[mm];
00441       bool flip2 = ((mm+lo)&1) ? true : false;
00442       for (int m=lo; m<hi; ++m)
00443         {
00444         double d1 = flip2 ? -d[l-mm][l-m] : d[l-mm][l-m];
00445         double d2 = flip  ? -d[l-mm][l+m] : d[l-mm][l+m];
00446         double f1 = d1+d2, f2 = d1-d2;
00447         almtmpT[m]+=dcomplex(t1T.real()*f1,t1T.imag()*f2);
00448         almtmpG[m]+=dcomplex(t1G.real()*f1,t1G.imag()*f2);
00449         almtmpC[m]+=dcomplex(t1C.real()*f1,t1C.imag()*f2);
00450         flip2 = !flip2;
00451         }
00452       flip = !flip;
00453       }
00454 }
00455 
00456     for (int m=0; m<=l; ++m)
00457       {
00458       almT(l,m) = xcomplex<T>(almtmpT[m]*expphi[m]);
00459       almG(l,m) = xcomplex<T>(almtmpG[m]*expphi[m]);
00460       almC(l,m) = xcomplex<T>(almtmpC[m]*expphi[m]);
00461       }
00462     }
00463   }
00464 
00465 template void rotate_alm (Alm<xcomplex<float> > &almT,
00466   Alm<xcomplex<float> > &almG, Alm<xcomplex<float> > &almC,
00467   double psi, double theta, double phi);
00468 template void rotate_alm (Alm<xcomplex<double> > &almT,
00469   Alm<xcomplex<double> > &almG, Alm<xcomplex<double> > &almC,
00470   double psi, double theta, double phi);
00471 
00472 
00473 template<typename T> void rotate_alm (Alm<xcomplex<T> > &alm,
00474   const rotmatrix &mat)
00475   {
00476   double a1, a2, a3;
00477   mat.Extract_CPAC_Euler_Angles (a1, a2, a3);
00478   rotate_alm (alm, a3, a2, a1);
00479   }
00480 
00481 template void rotate_alm (Alm<xcomplex<float> > &alm, const rotmatrix &mat);
00482 template void rotate_alm (Alm<xcomplex<double> > &alm, const rotmatrix &mat);
00483 
00484 template<typename T> void rotate_alm (Alm<xcomplex<T> > &almT,
00485   Alm<xcomplex<T> > &almG, Alm<xcomplex<T> > &almC,
00486   const rotmatrix &mat)
00487   {
00488   double a1, a2, a3;
00489   mat.Extract_CPAC_Euler_Angles (a1, a2, a3);
00490   rotate_alm (almT, almG, almC, a3, a2, a1);
00491   }
00492 
00493 template void rotate_alm (Alm<xcomplex<float> > &almT,
00494   Alm<xcomplex<float> > &almG, Alm<xcomplex<float> > &almC,
00495   const rotmatrix &mat);
00496 template void rotate_alm (Alm<xcomplex<double> > &almT,
00497   Alm<xcomplex<double> > &almG, Alm<xcomplex<double> > &almC,
00498   const rotmatrix &mat);

Generated on Thu Oct 8 14:48:52 2015 for Healpix C++