[468] | 1 | #include <math.h>
|
---|
| 2 | #include "syngen.h"
|
---|
| 3 | #include "lambuilder.h"
|
---|
| 4 | #include "fftserver.h"
|
---|
| 5 |
|
---|
| 6 | extern "C" {
|
---|
| 7 | void fft_gpd_(long double* ,int& ,int& ,int& ,int& ,long double*);
|
---|
| 8 | float gasdev2_(int& idum);
|
---|
| 9 | }
|
---|
| 10 |
|
---|
| 11 | void alm2mapgen(const int nsmax,const int nlmax,const int nmmax,
|
---|
| 12 | const vector< vector< complex<double> > >&alm,
|
---|
[532] | 13 | SphericalMap<double>& map,
|
---|
[468] | 14 | vector< complex<long double> > b_north,
|
---|
| 15 | vector< complex<long double> > b_south,
|
---|
| 16 | vector< complex<long double> > bw,
|
---|
| 17 | vector< complex<long double> > data,
|
---|
| 18 | vector< complex<long double> > work){
|
---|
| 19 | /*=======================================================================
|
---|
| 20 | computes a map form its alm for the HEALPIX pixelisation
|
---|
| 21 | map(theta,phi) = sum_l_m a_lm Y_lm(theta,phi)
|
---|
| 22 | = sum_m {e^(i*m*phi) sum_l a_lm*lambda_lm(theta)}
|
---|
| 23 |
|
---|
| 24 | where Y_lm(theta,phi) = lambda(theta) * e^(i*m*phi)
|
---|
| 25 |
|
---|
| 26 | * the recurrence of Ylm is the standard one (cf Num Rec)
|
---|
| 27 | * the sum over m is done by FFT
|
---|
| 28 |
|
---|
| 29 | =======================================================================*/
|
---|
| 30 |
|
---|
| 31 | // map.resize(12*nsmax*nsmax);
|
---|
| 32 | b_north.resize(2*nmmax+1); //index m corresponds to nmmax+m
|
---|
| 33 | b_south.resize(2*nmmax+1);
|
---|
| 34 | bw.resize(4*nsmax);
|
---|
| 35 | data.resize(4*nsmax);
|
---|
| 36 | work.resize(4*nsmax);
|
---|
| 37 |
|
---|
| 38 |
|
---|
| 39 | /* INTEGER l, indl */
|
---|
| 40 |
|
---|
| 41 | for (int ith = 0; ith <= (map.NbThetaSlices()+1)/2-1;ith++){
|
---|
| 42 | int nph;
|
---|
| 43 | double phi0;
|
---|
[532] | 44 | double theta,thetas;
|
---|
| 45 | Vector phin, datan,datas;
|
---|
| 46 | TVector<double> phis;
|
---|
[468] | 47 | map.GetThetaSlice(map.NbThetaSlices()-ith-1,thetas,phis,datas);
|
---|
| 48 | map.GetThetaSlice(ith,theta,phin,datan);
|
---|
| 49 | nph = phin.NElts();
|
---|
| 50 | phi0 = phin(0);
|
---|
| 51 | double cth = cos(theta);
|
---|
| 52 |
|
---|
| 53 | /* -----------------------------------------------------
|
---|
| 54 | for each theta, and each m, computes
|
---|
| 55 | b(m,theta) = sum_over_l>m (lambda_l_m(theta) * a_l_m)
|
---|
| 56 | ------------------------------------------------------
|
---|
| 57 | lambda_mm tends to go down when m increases (risk of underflow)
|
---|
| 58 | lambda_lm tends to go up when l increases (risk of overflow)*/
|
---|
| 59 | // lambda_0_0 * big number --> to avoid underflow
|
---|
| 60 | LambdaBuilder lb(acos(cth),nlmax,nmmax);
|
---|
| 61 | for (int m = 0; m <= nmmax; m++){
|
---|
| 62 | complex<double> b_n = lb.lamlm(m,m) * alm[m][m];
|
---|
| 63 | complex<double> b_s = lb.lamlm(m,m) * alm[m][m]; //m,m even
|
---|
| 64 | for (int l = m+1; l<= nlmax; l++){
|
---|
| 65 | b_n += lb.lamlm(l,m)*alm[l][m];
|
---|
| 66 | b_s += lb.lamlm(l,m,-1)*alm[l][m];
|
---|
| 67 | }
|
---|
| 68 | b_north[m+nmmax] = b_n;
|
---|
| 69 | b_south[m+nmmax] = b_s;
|
---|
| 70 | }
|
---|
| 71 |
|
---|
| 72 | // obtains the negative m of b(m,theta) (= complex conjugate)
|
---|
| 73 |
|
---|
| 74 | for (int m=-nmmax;m<=-1;m++){
|
---|
| 75 | //compiler doesn't have conj()
|
---|
| 76 | complex<long double>
|
---|
| 77 | shit(b_north[-m+nmmax].real(),-b_north[-m+nmmax].imag());
|
---|
| 78 | complex<long double>
|
---|
| 79 | shit2(b_south[-m+nmmax].real(),-b_south[-m+nmmax].imag());
|
---|
| 80 | b_north[m+nmmax] = shit;
|
---|
| 81 | b_south[m+nmmax] = shit2;
|
---|
| 82 | }
|
---|
| 83 | /* ---------------------------------------------------------------
|
---|
| 84 | sum_m b(m,theta)*exp(i*m*phi) -> f(phi,theta)
|
---|
| 85 | ---------------------------------------------------------------*/
|
---|
| 86 | /*cout <<"gen ";
|
---|
| 87 | for (int i=0;i<2*nmmax+1;i++){
|
---|
| 88 | cout << b_north[i]<<" ";}
|
---|
| 89 | cout<<endl;*/
|
---|
| 90 |
|
---|
| 91 | syn_phasgen(nsmax,nlmax,nmmax,b_north,nph,datan,phi0,bw); // north hemisph. + equator
|
---|
| 92 | if (ith != map.NbThetaSlices()/2){
|
---|
| 93 | syn_phasgen(nsmax,nlmax,nmmax,b_south,nph,datas,phi0,bw); // south hemisph. w/o equat
|
---|
| 94 | for (int i=0;i< nph;i++){
|
---|
| 95 | map.PixVal(map.PixIndexSph(thetas,phis(i)))=datas(2*i);
|
---|
| 96 | }
|
---|
| 97 | }
|
---|
| 98 | //cout <<"gen "<<datan<<endl;
|
---|
| 99 | for (int i=0;i< nph;i++){
|
---|
| 100 | map.PixVal(map.PixIndexSph(theta,phin(i)))=datan(2*i);
|
---|
| 101 | }
|
---|
| 102 | }
|
---|
| 103 | }
|
---|
| 104 |
|
---|
| 105 | void syn_phasgen(const int nsmax,const int nlmax,const int nmmax,
|
---|
| 106 | const vector< complex<long double> >& datain,
|
---|
[514] | 107 | int nph, Vector& dataout, double phi0,
|
---|
[468] | 108 | vector< complex<long double> >& bw){
|
---|
| 109 |
|
---|
| 110 | /*=======================================================================
|
---|
| 111 | dataout(j) = sum_m datain(m) * exp(i*m*phi(j))
|
---|
| 112 | with phi(j) = j*2pi/nph + kphi0*pi/nph and kphi0 =0 or 1
|
---|
| 113 |
|
---|
| 114 | as the set of frequencies {m} is larger than nph,
|
---|
| 115 | we wrap frequencies within {0..nph-1}
|
---|
| 116 | ie m = k*nph + m' with m' in {0..nph-1}
|
---|
| 117 | then
|
---|
| 118 | noting bw(m') = exp(i*m'*phi0)
|
---|
| 119 | * sum_k (datain(k*nph+m') exp(i*k*pi*kphi0))
|
---|
| 120 | with bw(nph-m') = CONJ(bw(m')) (if datain(-m) = CONJ(datain(m)))
|
---|
| 121 | dataout(j) = sum_m' [ bw(m') exp (i*j*m'*2pi/nph) ]
|
---|
| 122 | = Fourier Transform of bw
|
---|
| 123 | is real
|
---|
| 124 |
|
---|
| 125 | NB nph is not necessarily a power of 2
|
---|
| 126 |
|
---|
| 127 | =======================================================================*/
|
---|
| 128 |
|
---|
| 129 | int ksign = 1;
|
---|
| 130 | //long double * data = new long double[nph*2];
|
---|
| 131 | complex<double>* data = new complex<double>[nph];
|
---|
| 132 | long double * work = new long double[nph*2];
|
---|
| 133 |
|
---|
| 134 | int iw;
|
---|
| 135 | for (iw=0;iw<nph;iw++){bw[iw]=0;}
|
---|
| 136 |
|
---|
| 137 | long double shit=phi0*nph;
|
---|
| 138 | //try complex<long double> since generally this will not be an int
|
---|
| 139 | //int kshift = (int) pow(-1,shit);
|
---|
| 140 | //cout<<shit<<" "<<phi0*nph/M_PI<<" "<<kshift<<endl;
|
---|
| 141 | // int kshift = (int) pow(-1,kphi0);// ! either 1 or -1
|
---|
| 142 | // all frequencies [-m,m] are wrapped in [0,nph-1]
|
---|
| 143 | for (int i=1;i<=2*nmmax+1;i++){
|
---|
| 144 | int m=i-nmmax-1; //in -nmmax, nmmax
|
---|
| 145 | iw=((m % nph) +nph) % nph; //between 0 and nph = m'
|
---|
| 146 | int k=(m-iw)/nph; //number of 'turns'
|
---|
| 147 | // cout <<(complex<long double>)pow(kshift,k)<<" ";
|
---|
| 148 | // bw[iw]+=datain[i-1]* (complex<long double>)(pow(kshift,k));//complex number
|
---|
| 149 | bw[iw]+=datain[i-1]* complex<long double>(cos(shit*k),sin(shit*k));//complex number
|
---|
| 150 | }
|
---|
| 151 |
|
---|
| 152 |
|
---|
| 153 | // applies the shift in position <-> phase factor in Fourier space
|
---|
| 154 | for (int iw=1;iw<=nph;iw++){
|
---|
| 155 | int m=ksign*(iw-1);
|
---|
| 156 | complex<long double> shit(cos(m*phi0),sin(m*phi0));
|
---|
| 157 | data[iw-1]=bw[iw-1]*shit;
|
---|
| 158 | // data[2*(iw-1)]=(bw[iw-1]*shit).real();
|
---|
| 159 | //data[2*(iw-1)+1]=(bw[iw-1]*shit).imag();
|
---|
| 160 | }
|
---|
| 161 |
|
---|
| 162 | //FFTVector inv((double*) data,nph,true);
|
---|
| 163 | //FFTVector outv=FFTServer::solve(inv,1);
|
---|
| 164 | //outv.Vreal(dataout);
|
---|
| 165 |
|
---|
| 166 | FFTServer fft;
|
---|
| 167 | fft.fftf(nph, data);
|
---|
| 168 | dataout.Realloc(2*nph);
|
---|
| 169 | for (int i=0;i<nph;i++) {
|
---|
| 170 | dataout(2*i)=data[i].real();dataout(2*i+1)=data[i].imag();
|
---|
| 171 | }
|
---|
| 172 | delete[] data;
|
---|
| 173 | delete[] work;
|
---|
| 174 |
|
---|
| 175 | /*
|
---|
| 176 | int dum0=1;
|
---|
| 177 | int dum1=1;
|
---|
| 178 |
|
---|
| 179 | fft_gpd_(data,nph,dum0,ksign,dum1,work); // complex to complex
|
---|
| 180 |
|
---|
| 181 | for (int iw=0;iw<nph;iw++){dataout(iw) = data[2*iw];}*/
|
---|
| 182 | }
|
---|
| 183 |
|
---|
| 184 | void create_almgen(const int nsmax,const int nlmax,const int nmmax,
|
---|
| 185 | vector< vector< complex<double> > >& alm,
|
---|
| 186 | vector<float>& cls_tt,int& iseed,const float fwhm,
|
---|
| 187 | vector<float> lread){
|
---|
| 188 |
|
---|
| 189 |
|
---|
| 190 | /*=======================================================================
|
---|
| 191 | creates the a_lm from the power spectrum,
|
---|
| 192 | assuming they are gaussian and complex
|
---|
| 193 | with a variance given by C(l)
|
---|
| 194 |
|
---|
| 195 | the input file should contain : l and C(l) with *consecutive* l's
|
---|
| 196 | (missing C(l) are put to 0.)
|
---|
| 197 |
|
---|
| 198 | because the map is real we have : a_l-m = (-)^m conjug(a_lm)
|
---|
| 199 | so we actually compute them only for m >= 0
|
---|
| 200 |
|
---|
| 201 | modifie G. Le Meur (13/01/98) :
|
---|
| 202 | on ne lit plus les C(l) sur un fichier. Le tableau est entre en argument
|
---|
| 203 | (cls_tt). Ce tableau doit contenir les valeur de C(l) par ordre
|
---|
| 204 | SEQUENTIEL de l (de l=0 a l=nlmax)
|
---|
| 205 | =======================================================================*/
|
---|
| 206 | /* CHARACTER*128 filename
|
---|
| 207 |
|
---|
| 208 | integer unit,n_l,j,il,im
|
---|
| 209 | real fs,quadrupole,xxxtmp,correct
|
---|
| 210 | real fs_tt
|
---|
| 211 | real zeta1_r, zeta1_i
|
---|
| 212 | LOGICAL ok
|
---|
| 213 | character*20 string_quad
|
---|
| 214 |
|
---|
| 215 | real*4 prefact(0:2)
|
---|
| 216 | logical prefact_bool
|
---|
| 217 |
|
---|
| 218 | integer lneffct
|
---|
| 219 | real gasdev2
|
---|
| 220 | external lneffct, gasdev2
|
---|
| 221 |
|
---|
| 222 | c-----------------------------------------------------------------------*/
|
---|
| 223 | alm.resize(nlmax+1);
|
---|
| 224 | for (int i=0; i< (signed) alm.size();i++){
|
---|
| 225 | alm[i].resize(nmmax+1);
|
---|
| 226 | }
|
---|
| 227 | //cout << "cing createalm"<<endl;
|
---|
| 228 | iseed = -abs(iseed);
|
---|
| 229 | if (iseed == 0){iseed=-1;}
|
---|
| 230 | int idum = iseed;
|
---|
| 231 |
|
---|
| 232 | float sig_smooth = fwhm/sqrt(8.*log(2.))/(60.*180.)* M_PI;
|
---|
| 233 |
|
---|
| 234 | for (int i=0;i<nlmax+1;i++){lread[i]=0;}
|
---|
| 235 |
|
---|
| 236 | for (int i=0;i <= nlmax;i++){lread[i] = i;}
|
---|
| 237 |
|
---|
| 238 | int n_l = nlmax+1;
|
---|
| 239 |
|
---|
| 240 | cout<<lread[0]<<" <= l <= "<<lread[n_l-1]<<endl;
|
---|
| 241 |
|
---|
| 242 | // --- smoothes the initial power spectrum ---
|
---|
| 243 |
|
---|
| 244 | for (int i=0;i<n_l;i++){
|
---|
| 245 | int l= (int) lread[i];
|
---|
| 246 | float gauss=exp(-l*(l+1.)*sig_smooth*sig_smooth);
|
---|
| 247 | cls_tt[i]*=gauss;
|
---|
| 248 | }
|
---|
| 249 |
|
---|
| 250 |
|
---|
| 251 | // --- generates randomly the alm according to their power spectrum ---
|
---|
| 252 | float hsqrt2 = 1.0 / sqrt(2.0);
|
---|
| 253 |
|
---|
| 254 | for (int i=0;i<n_l;i++){
|
---|
| 255 | int l=(int) lread[i];
|
---|
| 256 | float rms_tt=sqrt(cls_tt[i]);
|
---|
| 257 | // ------ m = 0 ------
|
---|
| 258 | complex<float> zeta1(gasdev2_(idum));
|
---|
| 259 | //cout << "c2 "<<idum << " "<<zeta1 <<endl;
|
---|
| 260 | alm[l][0] = zeta1 * rms_tt;
|
---|
| 261 |
|
---|
| 262 | //------ m > 0 ------
|
---|
| 263 | for (int m=1;m<=l;m++){
|
---|
| 264 | complex<float> shit1(hsqrt2);
|
---|
| 265 | // cout << "c "<<idum << endl;
|
---|
| 266 | complex<float> shit2(gasdev2_(idum),gasdev2_(idum));
|
---|
| 267 | zeta1=shit1*shit2;
|
---|
| 268 | alm[l][m]=rms_tt*zeta1;
|
---|
| 269 | }
|
---|
| 270 | }
|
---|
| 271 | }
|
---|