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) = 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 }
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);