/* * This file is part of Healpix_cxx. * * Healpix_cxx is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Healpix_cxx is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Healpix_cxx; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * For more information about HEALPix, see http://healpix.jpl.nasa.gov */ /* * Healpix_cxx is being developed at the Max-Planck-Institut fuer Astrophysik * and financially supported by the Deutsches Zentrum fuer Luft- und Raumfahrt * (DLR). */ /* * Copyright (C) 2003-2011 Max-Planck-Society * Author: Martin Reinecke */ #include "alm_powspec_tools.h" #include "alm.h" #include "planck_rng.h" #include "powspec.h" #include "xcomplex.h" #include "rotmatrix.h" #include "openmp_support.h" #include "wigner.h" #include "lsconstants.h" using namespace std; template void create_alm (const PowSpec &powspec, Alm > &alm, planck_rng &rng) { int lmax = alm.Lmax(); int mmax = alm.Mmax(); const double hsqrt2 = 1/sqrt(2.); for (int l=0; l<=lmax; ++l) { double rms_tt = sqrt(powspec.tt(l)); double zeta1_r = rng.rand_gauss(); alm(l,0) = T(zeta1_r * rms_tt); for (int m=1; m<=min(l,mmax); ++m) { zeta1_r = rng.rand_gauss()*hsqrt2; double zeta1_i = rng.rand_gauss()*hsqrt2; alm(l,m).Set (T(zeta1_r*rms_tt), T(zeta1_i*rms_tt)); } } } template void create_alm (const PowSpec &powspec, Alm > &alm, planck_rng &rng); template void create_alm (const PowSpec &powspec, Alm > &alm, planck_rng &rng); template void create_alm_pol (const PowSpec &powspec, Alm > &almT, Alm > &almG, Alm > &almC, planck_rng &rng) { int lmax = almT.Lmax(); int mmax = almT.Mmax(); const double hsqrt2 = 1/sqrt(2.); for (int l=0; l<=lmax; ++l) { double rms_tt=0, rms_g1=0; if (powspec.tt(l) != 0) { rms_tt = sqrt(powspec.tt(l)); rms_g1 = powspec.tg(l)/rms_tt; } double zeta1_r = rng.rand_gauss(); almT(l,0) = T(zeta1_r * rms_tt); almG(l,0) = T(zeta1_r * rms_g1); for (int m=1; m<=min(l,mmax); ++m) { zeta1_r = rng.rand_gauss()*hsqrt2; double zeta1_i = rng.rand_gauss()*hsqrt2; almT(l,m).Set (T(zeta1_r*rms_tt), T(zeta1_i*rms_tt)); almG(l,m).Set (T(zeta1_r*rms_g1), T(zeta1_i*rms_g1)); } } for (int l=0; l<=lmax; ++l) { double rms_g2 = 0; double rms_cc = 0; if (powspec.tt(l) != 0) { rms_g2 = powspec.gg(l) - (powspec.tg(l)/powspec.tt(l))*powspec.tg(l); if (rms_g2 <= 0) { planck_assert (abs(rms_g2) <= 1e-8*abs(powspec.gg(l)), "Inconsistent TT, GG and TG spectra at l="+dataToString(l)); rms_g2 = 0; } rms_g2 = sqrt(rms_g2); rms_cc = sqrt(powspec.cc(l)); } almG(l,0) += T(rng.rand_gauss()*rms_g2); almC(l,0) = T(rng.rand_gauss()*rms_cc); for (int m=1; m<=min(l,mmax); ++m) { double zeta2_r = rng.rand_gauss()*hsqrt2; double zeta2_i = rng.rand_gauss()*hsqrt2; double zeta3_r = rng.rand_gauss()*hsqrt2; double zeta3_i = rng.rand_gauss()*hsqrt2; almG(l,m) += xcomplex (T(zeta2_r*rms_g2),T(zeta2_i*rms_g2)); almC(l,m).Set (T(zeta3_r*rms_cc),T(zeta3_i*rms_cc)); } } } template void create_alm_pol (const PowSpec &powspec, Alm > &almT, Alm > &almG, Alm > &almC, planck_rng &rng); template void create_alm_pol (const PowSpec &powspec, Alm > &almT, Alm > &almG, Alm > &almC, planck_rng &rng); template void extract_crosspowspec (const Alm > &alm1, const Alm > &alm2,PowSpec &powspec) { planck_assert (alm1.conformable(alm2), "a_lm are not conformable"); arr tt(alm1.Lmax()+1); for (int l=0; l<=alm1.Lmax(); ++l) { tt[l] = alm1(l,0).re*alm2(l,0).re; int limit = min(l,alm1.Mmax()); for (int m=1; m<=limit; ++m) tt[l] += 2 * (alm1(l,m).re*alm2(l,m).re + alm1(l,m).im*alm2(l,m).im); tt[l] /= (2*l+1); } powspec.Set(tt); } template void extract_crosspowspec (const Alm > &alm1, const Alm > &alm2, PowSpec &powspec); template void extract_crosspowspec (const Alm > &alm1, const Alm > &alm2, PowSpec &powspec); template void extract_powspec (const Alm > &alm, PowSpec &powspec) { extract_crosspowspec (alm,alm,powspec); } template void extract_powspec (const Alm > &alm, PowSpec &powspec); template void extract_powspec (const Alm > &alm, PowSpec &powspec); namespace { template void extract_crosspowspec (const Alm > &almT1, const Alm > &almG1, const Alm > &almC1, const Alm > &almT2, const Alm > &almG2, const Alm > &almC2, PowSpec &powspec) { planck_assert (almT1.conformable(almG1) && almT1.conformable(almC1) && almT1.conformable(almT2) && almT1.conformable(almG2) && almT1.conformable(almC2), "a_lm are not conformable"); int lmax = almT1.Lmax(); arr tt(lmax+1), gg(lmax+1), cc(lmax+1), tg(lmax+1), tc(lmax+1), gc(lmax+1); for (int l=0; l<=lmax; ++l) { tt[l] = almT1(l,0).re*almT2(l,0).re; gg[l] = almG1(l,0).re*almG2(l,0).re; cc[l] = almC1(l,0).re*almC2(l,0).re; tg[l] = almT1(l,0).re*almG2(l,0).re; tc[l] = almT1(l,0).re*almC2(l,0).re; gc[l] = almG1(l,0).re*almC2(l,0).re; int limit = min(l,almT1.Mmax()); for (int m=1; m<=limit; ++m) { tt[l] += 2 * (almT1(l,m).re*almT2(l,m).re + almT1(l,m).im*almT2(l,m).im); gg[l] += 2 * (almG1(l,m).re*almG2(l,m).re + almG1(l,m).im*almG2(l,m).im); cc[l] += 2 * (almC1(l,m).re*almC2(l,m).re + almC1(l,m).im*almC2(l,m).im); tg[l] += 2 * (almT1(l,m).re*almG2(l,m).re + almT1(l,m).im*almG2(l,m).im); tc[l] += 2 * (almT1(l,m).re*almC2(l,m).re + almT1(l,m).im*almC2(l,m).im); gc[l] += 2 * (almG1(l,m).re*almC2(l,m).re + almG1(l,m).im*almC2(l,m).im); } tt[l] /= (2*l+1); gg[l] /= (2*l+1); cc[l] /= (2*l+1); tg[l] /= (2*l+1); tc[l] /= (2*l+1); gc[l] /= (2*l+1); } powspec.Set(tt,gg,cc,tg,tc,gc); } } // unnamed namespace template void extract_powspec (const Alm > &almT, const Alm > &almG, const Alm > &almC, PowSpec &powspec) { extract_crosspowspec(almT,almG,almC,almT,almG,almC,powspec); } template void extract_powspec (const Alm > &almT, const Alm > &almG, const Alm > &almC, PowSpec &powspec); template void extract_powspec (const Alm > &almT, const Alm > &almG, const Alm > &almC, PowSpec &powspec); template void smoothWithGauss (Alm > &alm, double fwhm) { int fct = (fwhm>=0) ? 1 : -1; double sigma = fwhm*fwhm2sigma; arr gb(alm.Lmax()+1); for (int l=0; l<=alm.Lmax(); ++l) gb[l] = exp(-.5*fct*l*(l+1)*sigma*sigma); alm.ScaleL(gb); } template void smoothWithGauss (Alm > &alm, double fwhm); template void smoothWithGauss (Alm > &alm, double fwhm); template void smoothWithGauss (Alm > &almT, Alm > &almG, Alm > &almC, double fwhm) { int fct = (fwhm>=0) ? 1 : -1; double sigma = fwhm*fwhm2sigma; double fact_pol = exp(2*fct*sigma*sigma); arr gb(almT.Lmax()+1); for (int l=0; l<=almT.Lmax(); ++l) gb[l] = exp(-.5*fct*l*(l+1)*sigma*sigma); almT.ScaleL(gb); for (int l=0; l<=almT.Lmax(); ++l) gb[l] *= fact_pol; almG.ScaleL(gb); almC.ScaleL(gb); } template void smoothWithGauss (Alm > &almT, Alm > &almG, Alm > &almC, double fwhm); template void smoothWithGauss (Alm > &almT, Alm > &almG, Alm > &almC, double fwhm); template void rotate_alm (Alm > &alm, double psi, double theta, double phi) { planck_assert (alm.Lmax()==alm.Mmax(), "rotate_alm: lmax must be equal to mmax"); int lmax=alm.Lmax(); arr > exppsi(lmax+1), expphi(lmax+1); for (int m=0; m<=lmax; ++m) { exppsi[m].Set (cos(psi*m),-sin(psi*m)); expphi[m].Set (cos(phi*m),-sin(phi*m)); } wigner_d_risbo_openmp rec(lmax,theta); arr > almtmp(lmax+1); for (int l=0; l<=lmax; ++l) { const arr2 &d(rec.recurse()); for (int m=0; m<=l; ++m) almtmp[m] = xcomplex(alm(l,0))*d[l][l+m]; #pragma omp parallel { int64 lo,hi; openmp_calc_share(0,l+1,lo,hi); bool flip = true; for (int mm=1; mm<=l; ++mm) { xcomplex t1 = xcomplex(alm(l,mm))*exppsi[mm]; bool flip2 = ((mm+lo)&1) ? true : false; for (int m=lo; m(almtmp[m]*expphi[m]); } } template void rotate_alm (Alm > &alm, double psi, double theta, double phi); template void rotate_alm (Alm > &alm, double psi, double theta, double phi); template void rotate_alm (Alm > &almT, Alm > &almG, Alm > &almC, double psi, double theta, double phi) { planck_assert (almT.Lmax()==almT.Mmax(), "rotate_alm: lmax must be equal to mmax"); planck_assert (almG.conformable(almT) && almC.conformable(almT), "rotate_alm: a_lm are not conformable"); int lmax=almT.Lmax(); arr > exppsi(lmax+1), expphi(lmax+1); for (int m=0; m<=lmax; ++m) { exppsi[m].Set (cos(psi*m),-sin(psi*m)); expphi[m].Set (cos(phi*m),-sin(phi*m)); } wigner_d_risbo_openmp rec(lmax,theta); arr > almtmpT(lmax+1), almtmpG(lmax+1), almtmpC(lmax+1); for (int l=0; l<=lmax; ++l) { const arr2 &d(rec.recurse()); for (int m=0; m<=l; ++m) { almtmpT[m] = xcomplex(almT(l,0))*d[l][m+l]; almtmpG[m] = xcomplex(almG(l,0))*d[l][m+l]; almtmpC[m] = xcomplex(almC(l,0))*d[l][m+l]; } #pragma omp parallel { int64 lo,hi; openmp_calc_share(0,l+1,lo,hi); bool flip = true; for (int mm=1; mm<=l; ++mm) { xcomplex t1T = xcomplex(almT(l,mm))*exppsi[mm]; xcomplex t1G = xcomplex(almG(l,mm))*exppsi[mm]; xcomplex t1C = xcomplex(almC(l,mm))*exppsi[mm]; bool flip2 = ((mm+lo)&1) ? true : false; for (int m=lo; m(almtmpT[m]*expphi[m]); almG(l,m) = xcomplex(almtmpG[m]*expphi[m]); almC(l,m) = xcomplex(almtmpC[m]*expphi[m]); } } } template void rotate_alm (Alm > &almT, Alm > &almG, Alm > &almC, double psi, double theta, double phi); template void rotate_alm (Alm > &almT, Alm > &almG, Alm > &almC, double psi, double theta, double phi); template void rotate_alm (Alm > &alm, const rotmatrix &mat) { double a1, a2, a3; mat.Extract_CPAC_Euler_Angles (a1, a2, a3); rotate_alm (alm, a3, a2, a1); } template void rotate_alm (Alm > &alm, const rotmatrix &mat); template void rotate_alm (Alm > &alm, const rotmatrix &mat); template void rotate_alm (Alm > &almT, Alm > &almG, Alm > &almC, const rotmatrix &mat) { double a1, a2, a3; mat.Extract_CPAC_Euler_Angles (a1, a2, a3); rotate_alm (almT, almG, almC, a3, a2, a1); } template void rotate_alm (Alm > &almT, Alm > &almG, Alm > &almC, const rotmatrix &mat); template void rotate_alm (Alm > &almT, Alm > &almG, Alm > &almC, const rotmatrix &mat);