00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
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).Set (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 &powspec,
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 for (int l=0; l<=lmax; ++l)
00083 {
00084 double rms_tt=0, rms_g1=0;
00085 if (powspec.tt(l) != 0)
00086 {
00087 rms_tt = sqrt(powspec.tt(l));
00088 rms_g1 = powspec.tg(l)/rms_tt;
00089 }
00090
00091 double zeta1_r = rng.rand_gauss();
00092 almT(l,0) = T(zeta1_r * rms_tt);
00093 almG(l,0) = T(zeta1_r * rms_g1);
00094 for (int m=1; m<=min(l,mmax); ++m)
00095 {
00096 zeta1_r = rng.rand_gauss()*hsqrt2;
00097 double zeta1_i = rng.rand_gauss()*hsqrt2;
00098 almT(l,m).Set (T(zeta1_r*rms_tt), T(zeta1_i*rms_tt));
00099 almG(l,m).Set (T(zeta1_r*rms_g1), T(zeta1_i*rms_g1));
00100 }
00101 }
00102
00103 for (int l=0; l<=lmax; ++l)
00104 {
00105 double rms_g2 = 0;
00106 double rms_cc = 0;
00107 if (powspec.tt(l) != 0)
00108 {
00109 rms_g2 = powspec.gg(l) - (powspec.tg(l)/powspec.tt(l))*powspec.tg(l);
00110 if (rms_g2 <= 0)
00111 {
00112 planck_assert (abs(rms_g2) <= 1e-8*abs(powspec.gg(l)),
00113 "Inconsistent TT, GG and TG spectra at l="+dataToString(l));
00114 rms_g2 = 0;
00115 }
00116 rms_g2 = sqrt(rms_g2);
00117 rms_cc = sqrt(powspec.cc(l));
00118 }
00119 almG(l,0) += T(rng.rand_gauss()*rms_g2);
00120 almC(l,0) = T(rng.rand_gauss()*rms_cc);
00121
00122 for (int m=1; m<=min(l,mmax); ++m)
00123 {
00124 double zeta2_r = rng.rand_gauss()*hsqrt2;
00125 double zeta2_i = rng.rand_gauss()*hsqrt2;
00126 double zeta3_r = rng.rand_gauss()*hsqrt2;
00127 double zeta3_i = rng.rand_gauss()*hsqrt2;
00128
00129 almG(l,m) += xcomplex<T> (T(zeta2_r*rms_g2),T(zeta2_i*rms_g2));
00130 almC(l,m).Set (T(zeta3_r*rms_cc),T(zeta3_i*rms_cc));
00131 }
00132 }
00133 }
00134
00135 template void create_alm_pol
00136 (const PowSpec &powspec,
00137 Alm<xcomplex<float> > &almT,
00138 Alm<xcomplex<float> > &almG,
00139 Alm<xcomplex<float> > &almC,
00140 planck_rng &rng);
00141 template void create_alm_pol
00142 (const PowSpec &powspec,
00143 Alm<xcomplex<double> > &almT,
00144 Alm<xcomplex<double> > &almG,
00145 Alm<xcomplex<double> > &almC,
00146 planck_rng &rng);
00147
00148
00149 template<typename T> void extract_crosspowspec
00150 (const Alm<xcomplex<T> > &alm1,
00151 const Alm<xcomplex<T> > &alm2,PowSpec &powspec)
00152 {
00153 planck_assert (alm1.conformable(alm2), "a_lm are not conformable");
00154 arr<double> tt(alm1.Lmax()+1);
00155 for (int l=0; l<=alm1.Lmax(); ++l)
00156 {
00157 tt[l] = alm1(l,0).re*alm2(l,0).re;
00158 int limit = min(l,alm1.Mmax());
00159 for (int m=1; m<=limit; ++m)
00160 tt[l] += 2 * (alm1(l,m).re*alm2(l,m).re + alm1(l,m).im*alm2(l,m).im);
00161 tt[l] /= (2*l+1);
00162 }
00163 powspec.Set(tt);
00164 }
00165
00166 template void extract_crosspowspec
00167 (const Alm<xcomplex<float> > &alm1,
00168 const Alm<xcomplex<float> > &alm2, PowSpec &powspec);
00169 template void extract_crosspowspec
00170 (const Alm<xcomplex<double> > &alm1,
00171 const Alm<xcomplex<double> > &alm2, PowSpec &powspec);
00172
00173
00174 template<typename T> void extract_powspec
00175 (const Alm<xcomplex<T> > &alm, PowSpec &powspec)
00176 { extract_crosspowspec (alm,alm,powspec); }
00177
00178 template void extract_powspec
00179 (const Alm<xcomplex<float> > &alm, PowSpec &powspec);
00180 template void extract_powspec
00181 (const Alm<xcomplex<double> > &alm, PowSpec &powspec);
00182
00183 namespace {
00184
00185 template<typename T> void extract_crosspowspec
00186 (const Alm<xcomplex<T> > &almT1,
00187 const Alm<xcomplex<T> > &almG1,
00188 const Alm<xcomplex<T> > &almC1,
00189 const Alm<xcomplex<T> > &almT2,
00190 const Alm<xcomplex<T> > &almG2,
00191 const Alm<xcomplex<T> > &almC2,
00192 PowSpec &powspec)
00193 {
00194 planck_assert (almT1.conformable(almG1) && almT1.conformable(almC1) &&
00195 almT1.conformable(almT2) && almT1.conformable(almG2) &&
00196 almT1.conformable(almC2), "a_lm are not conformable");
00197
00198 int lmax = almT1.Lmax();
00199 arr<double> tt(lmax+1), gg(lmax+1), cc(lmax+1), tg(lmax+1),
00200 tc(lmax+1), gc(lmax+1);
00201 for (int l=0; l<=lmax; ++l)
00202 {
00203 tt[l] = almT1(l,0).re*almT2(l,0).re;
00204 gg[l] = almG1(l,0).re*almG2(l,0).re;
00205 cc[l] = almC1(l,0).re*almC2(l,0).re;
00206 tg[l] = almT1(l,0).re*almG2(l,0).re;
00207 tc[l] = almT1(l,0).re*almC2(l,0).re;
00208 gc[l] = almG1(l,0).re*almC2(l,0).re;
00209 int limit = min(l,almT1.Mmax());
00210 for (int m=1; m<=limit; ++m)
00211 {
00212 tt[l] += 2 * (almT1(l,m).re*almT2(l,m).re + almT1(l,m).im*almT2(l,m).im);
00213 gg[l] += 2 * (almG1(l,m).re*almG2(l,m).re + almG1(l,m).im*almG2(l,m).im);
00214 cc[l] += 2 * (almC1(l,m).re*almC2(l,m).re + almC1(l,m).im*almC2(l,m).im);
00215 tg[l] += 2 * (almT1(l,m).re*almG2(l,m).re + almT1(l,m).im*almG2(l,m).im);
00216 tc[l] += 2 * (almT1(l,m).re*almC2(l,m).re + almT1(l,m).im*almC2(l,m).im);
00217 gc[l] += 2 * (almG1(l,m).re*almC2(l,m).re + almG1(l,m).im*almC2(l,m).im);
00218 }
00219 tt[l] /= (2*l+1);
00220 gg[l] /= (2*l+1);
00221 cc[l] /= (2*l+1);
00222 tg[l] /= (2*l+1);
00223 tc[l] /= (2*l+1);
00224 gc[l] /= (2*l+1);
00225 }
00226 powspec.Set(tt,gg,cc,tg,tc,gc);
00227 }
00228
00229 }
00230
00231 template<typename T> void extract_powspec
00232 (const Alm<xcomplex<T> > &almT,
00233 const Alm<xcomplex<T> > &almG,
00234 const Alm<xcomplex<T> > &almC,
00235 PowSpec &powspec)
00236 { extract_crosspowspec(almT,almG,almC,almT,almG,almC,powspec); }
00237
00238 template void extract_powspec
00239 (const Alm<xcomplex<float> > &almT,
00240 const Alm<xcomplex<float> > &almG,
00241 const Alm<xcomplex<float> > &almC,
00242 PowSpec &powspec);
00243 template void extract_powspec
00244 (const Alm<xcomplex<double> > &almT,
00245 const Alm<xcomplex<double> > &almG,
00246 const Alm<xcomplex<double> > &almC,
00247 PowSpec &powspec);
00248
00249
00250 template<typename T> void smoothWithGauss
00251 (Alm<xcomplex<T> > &alm, double fwhm)
00252 {
00253 int fct = (fwhm>=0) ? 1 : -1;
00254 double sigma = fwhm*fwhm2sigma;
00255 arr<double> gb(alm.Lmax()+1);
00256 for (int l=0; l<=alm.Lmax(); ++l)
00257 gb[l] = exp(-.5*fct*l*(l+1)*sigma*sigma);
00258 alm.ScaleL(gb);
00259 }
00260
00261 template void smoothWithGauss
00262 (Alm<xcomplex<float> > &alm, double fwhm);
00263 template void smoothWithGauss
00264 (Alm<xcomplex<double> > &alm, double fwhm);
00265
00266
00267 template<typename T> void smoothWithGauss
00268 (Alm<xcomplex<T> > &almT,
00269 Alm<xcomplex<T> > &almG,
00270 Alm<xcomplex<T> > &almC,
00271 double fwhm)
00272 {
00273 int fct = (fwhm>=0) ? 1 : -1;
00274 double sigma = fwhm*fwhm2sigma;
00275 double fact_pol = exp(2*fct*sigma*sigma);
00276 arr<double> gb(almT.Lmax()+1);
00277 for (int l=0; l<=almT.Lmax(); ++l)
00278 gb[l] = exp(-.5*fct*l*(l+1)*sigma*sigma);
00279 almT.ScaleL(gb);
00280 for (int l=0; l<=almT.Lmax(); ++l)
00281 gb[l] *= fact_pol;
00282 almG.ScaleL(gb); almC.ScaleL(gb);
00283 }
00284
00285 template void smoothWithGauss
00286 (Alm<xcomplex<float> > &almT,
00287 Alm<xcomplex<float> > &almG,
00288 Alm<xcomplex<float> > &almC,
00289 double fwhm);
00290 template void smoothWithGauss
00291 (Alm<xcomplex<double> > &almT,
00292 Alm<xcomplex<double> > &almG,
00293 Alm<xcomplex<double> > &almC,
00294 double fwhm);
00295
00296 template<typename T> void rotate_alm (Alm<xcomplex<T> > &alm,
00297 double psi, double theta, double phi)
00298 {
00299 planck_assert (alm.Lmax()==alm.Mmax(),
00300 "rotate_alm: lmax must be equal to mmax");
00301 int lmax=alm.Lmax();
00302 arr<xcomplex<double> > exppsi(lmax+1), expphi(lmax+1);
00303 for (int m=0; m<=lmax; ++m)
00304 {
00305 exppsi[m].Set (cos(psi*m),-sin(psi*m));
00306 expphi[m].Set (cos(phi*m),-sin(phi*m));
00307 }
00308
00309 wigner_d_risbo_openmp rec(lmax,theta);
00310
00311 arr<xcomplex<double> > almtmp(lmax+1);
00312
00313 for (int l=0; l<=lmax; ++l)
00314 {
00315 const arr2<double> &d(rec.recurse());
00316
00317 for (int m=0; m<=l; ++m)
00318 almtmp[m] = xcomplex<double>(alm(l,0))*d[l][l+m];
00319
00320 #pragma omp parallel
00321 {
00322 int64 lo,hi;
00323 openmp_calc_share(0,l+1,lo,hi);
00324
00325 bool flip = true;
00326 for (int mm=1; mm<=l; ++mm)
00327 {
00328 xcomplex<double> t1 = xcomplex<double>(alm(l,mm))*exppsi[mm];
00329 bool flip2 = ((mm+lo)&1) ? true : false;
00330 for (int m=lo; m<hi; ++m)
00331 {
00332 double d1 = flip2 ? -d[l-mm][l-m] : d[l-mm][l-m];
00333 double d2 = flip ? -d[l-mm][l+m] : d[l-mm][l+m];
00334 double f1 = d1+d2, f2 = d1-d2;
00335 almtmp[m].re += t1.re*f1; almtmp[m].im += t1.im*f2;
00336 flip2 = !flip2;
00337 }
00338 flip = !flip;
00339 }
00340 }
00341
00342 for (int m=0; m<=l; ++m)
00343 alm(l,m) = xcomplex<T>(almtmp[m]*expphi[m]);
00344 }
00345 }
00346
00347 template void rotate_alm (Alm<xcomplex<float> > &alm,
00348 double psi, double theta, double phi);
00349 template void rotate_alm (Alm<xcomplex<double> > &alm,
00350 double psi, double theta, double phi);
00351
00352 template<typename T> void rotate_alm (Alm<xcomplex<T> > &almT,
00353 Alm<xcomplex<T> > &almG, Alm<xcomplex<T> > &almC,
00354 double psi, double theta, double phi)
00355 {
00356 planck_assert (almT.Lmax()==almT.Mmax(),
00357 "rotate_alm: lmax must be equal to mmax");
00358 planck_assert (almG.conformable(almT) && almC.conformable(almT),
00359 "rotate_alm: a_lm are not conformable");
00360 int lmax=almT.Lmax();
00361 arr<xcomplex<double> > exppsi(lmax+1), expphi(lmax+1);
00362 for (int m=0; m<=lmax; ++m)
00363 {
00364 exppsi[m].Set (cos(psi*m),-sin(psi*m));
00365 expphi[m].Set (cos(phi*m),-sin(phi*m));
00366 }
00367
00368 wigner_d_risbo_openmp rec(lmax,theta);
00369
00370 arr<xcomplex<double> > almtmpT(lmax+1), almtmpG(lmax+1), almtmpC(lmax+1);
00371
00372 for (int l=0; l<=lmax; ++l)
00373 {
00374 const arr2<double> &d(rec.recurse());
00375
00376 for (int m=0; m<=l; ++m)
00377 {
00378 almtmpT[m] = xcomplex<double>(almT(l,0))*d[l][m+l];
00379 almtmpG[m] = xcomplex<double>(almG(l,0))*d[l][m+l];
00380 almtmpC[m] = xcomplex<double>(almC(l,0))*d[l][m+l];
00381 }
00382
00383 #pragma omp parallel
00384 {
00385 int64 lo,hi;
00386 openmp_calc_share(0,l+1,lo,hi);
00387
00388 bool flip = true;
00389 for (int mm=1; mm<=l; ++mm)
00390 {
00391 xcomplex<double> t1T = xcomplex<double>(almT(l,mm))*exppsi[mm];
00392 xcomplex<double> t1G = xcomplex<double>(almG(l,mm))*exppsi[mm];
00393 xcomplex<double> t1C = xcomplex<double>(almC(l,mm))*exppsi[mm];
00394 bool flip2 = ((mm+lo)&1) ? true : false;
00395 for (int m=lo; m<hi; ++m)
00396 {
00397 double d1 = flip2 ? -d[l-mm][l-m] : d[l-mm][l-m];
00398 double d2 = flip ? -d[l-mm][l+m] : d[l-mm][l+m];
00399 double f1 = d1+d2, f2 = d1-d2;
00400 almtmpT[m].re += t1T.re*f1; almtmpT[m].im += t1T.im*f2;
00401 almtmpG[m].re += t1G.re*f1; almtmpG[m].im += t1G.im*f2;
00402 almtmpC[m].re += t1C.re*f1; almtmpC[m].im += t1C.im*f2;
00403 flip2 = !flip2;
00404 }
00405 flip = !flip;
00406 }
00407 }
00408
00409 for (int m=0; m<=l; ++m)
00410 {
00411 almT(l,m) = xcomplex<T>(almtmpT[m]*expphi[m]);
00412 almG(l,m) = xcomplex<T>(almtmpG[m]*expphi[m]);
00413 almC(l,m) = xcomplex<T>(almtmpC[m]*expphi[m]);
00414 }
00415 }
00416 }
00417
00418 template void rotate_alm (Alm<xcomplex<float> > &almT,
00419 Alm<xcomplex<float> > &almG, Alm<xcomplex<float> > &almC,
00420 double psi, double theta, double phi);
00421 template void rotate_alm (Alm<xcomplex<double> > &almT,
00422 Alm<xcomplex<double> > &almG, Alm<xcomplex<double> > &almC,
00423 double psi, double theta, double phi);
00424
00425
00426 template<typename T> void rotate_alm (Alm<xcomplex<T> > &alm,
00427 const rotmatrix &mat)
00428 {
00429 double a1, a2, a3;
00430 mat.Extract_CPAC_Euler_Angles (a1, a2, a3);
00431 rotate_alm (alm, a3, a2, a1);
00432 }
00433
00434 template void rotate_alm (Alm<xcomplex<float> > &alm, const rotmatrix &mat);
00435 template void rotate_alm (Alm<xcomplex<double> > &alm, const rotmatrix &mat);
00436
00437 template<typename T> void rotate_alm (Alm<xcomplex<T> > &almT,
00438 Alm<xcomplex<T> > &almG, Alm<xcomplex<T> > &almC,
00439 const rotmatrix &mat)
00440 {
00441 double a1, a2, a3;
00442 mat.Extract_CPAC_Euler_Angles (a1, a2, a3);
00443 rotate_alm (almT, almG, almC, a3, a2, a1);
00444 }
00445
00446 template void rotate_alm (Alm<xcomplex<float> > &almT,
00447 Alm<xcomplex<float> > &almG, Alm<xcomplex<float> > &almC,
00448 const rotmatrix &mat);
00449 template void rotate_alm (Alm<xcomplex<double> > &almT,
00450 Alm<xcomplex<double> > &almG, Alm<xcomplex<double> > &almC,
00451 const rotmatrix &mat);