| [658] | 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,
 | 
|---|
 | 13 |              SphericalMap<double>& map,
 | 
|---|
 | 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;
 | 
|---|
 | 44 |     double theta,thetas;
 | 
|---|
 | 45 |     Vector phin, datan,datas;
 | 
|---|
 | 46 |     TVector<double> phis;
 | 
|---|
 | 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,
 | 
|---|
 | 107 |               int nph, Vector& dataout, double phi0,
 | 
|---|
 | 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 | }
 | 
|---|