int getLoc(GEOLOCATE_REC *g,double range,double dop, /* Inputs.*/ double *latitude,double *phi,double *earthRadius) /*Outputs.*/ { int err; double yaw=0,look=0; vector target; err = getLookYaw(g,range,dop,&look,&yaw); if (err) return err; getDoppler(g,look,yaw,NULL,NULL,&target,NULL); cart2sph(target,earthRadius,latitude,phi); return 0; }
void exafmm_kernel::M2M(std::vector<real>& CiM, const std::vector<real>& CjM, const std::array<real, NDIM>& dist, const integer N) { std::vector<real> Ynm(FMM_P * FMM_P); std::vector<real> M_r(N), M_i(N); real rho, theta, phi; cart2sph(rho, theta, phi, dist); evalMultipole(rho, theta, -phi, Ynm); for (integer j = 0; j != FMM_P; ++j) { for (integer k = 0; k <= j; ++k) { const integer jkp = j * j + j + k; const integer jkm = j * j + j - k; #pragma vector aligned #pragma simd for (integer i = 0; i != N; ++i) { M_r[i] = M_i[i] = real(0.0); } for (integer n = 0; n <= j; ++n) { for (integer m = std::max(n - j + k, -n); m <= std::min(j - n + k, +n); ++m) { const integer nn = n * n + n; const integer nj = (j - n) * (j - n) + j - n; const integer jnkm = nj + k - m; const integer jnpkm = nj + std::abs(k - m); const integer jnmkm = nj - std::abs(k - m); const integer nmp = nn + std::abs(m); const integer nmm = nn - std::abs(m); const auto Mj_r = CjM.data() + N * jnpkm; const auto Mj_i = CjM.data() + N * jnmkm; const real tmp = Anm[nmp] * Anm[jnkm] / Anm[jkp]* ODDEVEN((std::abs(k) - std::abs(m) - std::abs(k - m)) / 2 + n); const real sgn_km = SGN(k-m); const real Y_r = tmp * Ynm[nmp]; const real Y_i = SGN(m) * tmp * Ynm[nmm]; #pragma vector aligned #pragma simd for (integer i = 0; i != N; ++i) { COMPLEX_MULT_ADD(M_r[i], M_i[i], Y_r, Y_i, Mj_r[i], sgn_km * Mj_i[i]); } } } auto Mi_r = CiM.data() + N * jkp; auto Mi_i = CiM.data() + N * jkm; #pragma vector aligned #pragma simd for (integer i = 0; i != N; ++i) { Mi_r[i] += M_r[i]; Mi_i[i] += (jkm == jkp) ? 0.0 : M_i[i]; } } } }
void exafmm_kernel::L2L(std::vector<real>& CiL, const std::vector<real>& CjL, const std::array<real, NDIM>& dist, const integer N) { std::vector<real> Ynm(FMM_P * FMM_P); real rho, theta, phi; std::vector<real> L_r(N), L_i(N); cart2sph(rho, theta, phi, dist); evalMultipole(rho, theta, phi, Ynm); for (integer j = 0; j != FMM_P; ++j) { for (integer k = 0; k <= j; ++k) { integer jkp = j * j + j + k; integer jkm = j * j + j - k; #pragma vector aligned #pragma simd for (integer i = 0; i != N; ++i) { L_r[i] = L_i[i] = 0.0; } for (integer n = j; n != FMM_P; ++n) { for (integer m = j - n + k; m <= n - j + k; ++m) { const integer nn = n * n + n; const integer nj = (n - j) * ((n - j) + 1); const integer npm = nn + std::abs(m); const integer nmm = nn - std::abs(m); const integer jnpkm = nj + std::abs(m - k); const integer jnmkm = nj - std::abs(m - k); const auto Lj_r = CjL.data() + N * npm; const auto Lj_i = CjL.data() + N * nmm; const real sgn = SGN(m); real tmp = std::pow(-real(1.0), real(std::abs(m) - std::abs(k) - std::abs(m - k)) / 2) * Anm[jnpkm] * Anm[jkp] / Anm[npm]; const real Y_r = Ynm[jnpkm] * tmp; const real Y_i = SGN(m-k) * Ynm[jnmkm] * tmp; #pragma vector aligned #pragma simd for (integer i = 0; i != N; ++i) { COMPLEX_MULT_ADD(L_r[i], L_i[i], Y_r, Y_i, Lj_r[i], sgn * Lj_i[i]); } } } auto Li_r = CiL.data() + N * jkp; auto Li_i = CiL.data() + N * jkm; #pragma vector aligned #pragma simd for (integer i = 0; i != N; ++i) { Li_r[i] = L_r[i]; Li_i[i] = (k == 0) ? L_r[i] : L_i[i]; } } } }
void scan_to_latlon(meta_parameters *meta, double x, double y, double z, double *lat_d, double *lon, double *height) { double qlat, qlon; double lat,radius; vector pos; meta_projection *proj = meta->projection; if (z != 0.0) { // height correction applies directly to y (range direction) double line, samp; line = (y-proj->startY)/proj->perY - meta->general->start_line; samp = (x-proj->startX)/proj->perX - meta->general->start_sample; double sr = meta_get_slant(meta,line,samp); double er = proj->param.atct.rlocal; double ht = meta_get_sat_height(meta,line,samp); double cos_ang = (sr*sr + er*er - ht*ht)/(2.0*sr*er); if (cos_ang > 1) cos_ang = 1; if (cos_ang < -1) cos_ang = -1; double incid = PI-acos(cos_ang); x += z*tan(PI/2-incid); } if (meta->sar->look_direction=='R') qlat = -x/proj->param.atct.rlocal; /* Right looking sar */ else qlat = x/proj->param.atct.rlocal; /* Left looking sar */ qlon = y/(proj->param.atct.rlocal*cos(qlat)); sph2cart(proj->param.atct.rlocal, qlat, qlon, &pos); rotate_z(&pos,-proj->param.atct.alpha3); rotate_y(&pos,-proj->param.atct.alpha2); rotate_z(&pos,-proj->param.atct.alpha1); cart2sph(pos,&radius,&lat,lon); *lon *= R2D; lat *= R2D; *lat_d = atand(tand(lat) / (1-ecc2(proj->re_minor,proj->re_major))); *height = z; // FIXME: Do we need to correct the height at all? }
static void ll_ac(meta_projection *proj, char look_dir, double lat_r, double lon, double *c1, double *c2) { double qlat, qlon; double lat,radius; vector pos; lat = atan(tan(lat_r)*(1 - ecc2(proj->re_minor,proj->re_major))); sph2cart(proj->param.atct.rlocal,lat,lon,&pos); rotate_z(&pos,proj->param.atct.alpha1); rotate_y(&pos,proj->param.atct.alpha2); rotate_z(&pos,proj->param.atct.alpha3); cart2sph(pos,&radius,&qlat,&qlon); *c1 = qlon*proj->param.atct.rlocal*cos(qlat); if (look_dir=='R') *c2 = -1.0*qlat*proj->param.atct.rlocal; /* right looking */ else *c2 = qlat * proj->param.atct.rlocal; /* left looking */ }
/** * Create expansions for D_ij / G_i (Tornberg & Greengard */ void P2M(const source_type& source, const charge_type& charge, const point_type& center, multipole_type& M) const { complex Ynm[4*P*P], YnmTheta[4*P*P]; // modifications needed here point_type dist = static_cast<point_type>(source) - center; real rho, alpha, beta; cart2sph(rho,alpha,beta,dist); evalMultipole(rho,alpha,-beta,Ynm,YnmTheta); real g0 = charge[0], g1 = charge[1], g2 = charge[2]; real n0 = charge[3], n1 = charge[4], n2 = charge[5]; for (int n=0; n!=P; ++n) { for (int m=0; m<=n; ++m) { const int nm = n * (n + 1) + m; const int nms = n * (n + 1) / 2 + m; complex brh = (double)n/rho*Ynm[nm]; // d(rho) complex bal = YnmTheta[nm]; // d(alpha) complex bbe = -complex(0,1.)*(double)m*Ynm[nm]; // d(beta) complex bxd = sin(alpha)*cos(beta)*brh + cos(alpha)*cos(beta)/rho*bal - sin(beta)/rho/sin(alpha)*bbe; // dx complex byd = sin(alpha)*sin(beta)*brh + cos(alpha)*sin(beta)/rho*bal + cos(beta)/rho/sin(alpha)*bbe; // dy complex bzd = cos(alpha)*brh - sin(alpha)/rho*bal; // dz // which order should these be in? real rdotn = bxd*n0 + byd*n1 + bzd*n2; real rdotg = bxd*g0 + byd*g1 + bzd*g2; M[0][nms] += (rdotn * g0 + rdotg * n0); M[1][nms] += (rdotn * g1 + rdotg * n1); M[2][nms] += (rdotn * g2 + rdotg * n2); real xdotg = source[0]*g0 + source[1]*g1 + source[2]*g2; real ndotx = n0*source[0] + n1*source[1] + n2*source[2]; M[3][nms] += rdotn * xdotg + rdotg * ndotx; } } }
static int get_target_latlon(stateVector *st, double look, double *tlat, double *tlon) { // satellite height, from the state vector double ht = vecMagnitude(st->pos); // earth radius, calculate from WGS84 values, and approx latitude double re = 6378137.0; double rp = 6356752.31414; double lat = asin(st->pos.z/ht); double er = re*rp/sqrt(rp*rp*cos(lat)*cos(lat)+re*re*sin(lat)*sin(lat)); // calculate slant range by law of cosines // (where we know two sides, but not the angle between them) double D = er*er - ht*ht*sin(look)*sin(look); if (D < 0) return 0; // can't see the Earth from here double sr1 = ht*cos(look) + sqrt(D); double sr2 = ht*cos(look) - sqrt(D); double sr = sr1>sr2 ? sr2 : sr1; // target position, first in inertial coords, then convert to lat/lon vector target; get_target_position(st, look, 0, sr, &target); double glat; // geocentric cart2sph(target,&er,&glat,tlon); // tlon should be -180,180 // tlat needs to be geodetic // both should be degrees *tlon *= R2D; if (*tlon < -180.) *tlon += 360.; *tlat = R2D*atan(tan(glat)*re*re/(rp*rp)); return 1; }
/** * Create expansions for S_ij / F_i (Tornberg & Greengard */ void P2M(const source_type& source, const charge_type& charge, const point_type& center, multipole_type& M) const { complex Ynm[4*P*P], YnmTheta[4*P*P]; // modifications needed here point_type dist = static_cast<point_type>(source) - center; real rho, alpha, beta; cart2sph(rho,alpha,beta,dist); evalMultipole(rho,alpha,-beta,Ynm,YnmTheta); real f0 = charge[0], f1 = charge[1], f2 = charge[2]; real fdotx = f0*source[0] + f1*source[1] + f2*source[2]; for (int n=0; n!=P; ++n) { for (int m=0; m<=n; ++m) { const int nm = n * (n + 1) + m; const int nms = n * (n + 1) / 2 + m; M[0][nms] += f0 * Ynm[nm]; M[1][nms] += f1 * Ynm[nm]; M[2][nms] += f2 * Ynm[nm]; M[3][nms] += fdotx * Ynm[nm]; } } }
/** Kernel L2P operation * r += Op(L, t) where L is the local expansion and r is the result * * @param[in] L The local expansion * @param[in] center The center of the box with the local expansion * @param[in] target The target of this L2P operation * @param[in] result The result to accumulate into * @pre L includes the influence of all sources outside its box */ void L2P(const local_type& L, const point_type& center, const target_type& target, result_type& result) const { complex Ynm[4*P*P], YnmTheta[4*P*P]; point_type dist = target - center; point_type gradient[4]; // = {0.,0.,0.,0.}; gradient[0] = point_type(0.); gradient[1] = point_type(0.); gradient[2] = point_type(0.); gradient[3] = point_type(0.); point_type cartesian(0); real r, theta, phi; cart2sph(r,theta,phi,dist); evalMultipole(r,theta,phi,Ynm,YnmTheta); #ifdef STRESSLET double scale = 1./6; #else double scale = 1.; #endif for( int n=0; n!=P; ++n ) { int nm = n * n + n; int nms = n * (n + 1) / 2; result[0] += scale*std::real(L[0][nms] * Ynm[nm]); result[1] += scale*std::real(L[1][nms] * Ynm[nm]); result[2] += scale*std::real(L[2][nms] * Ynm[nm]); real factor = 1. / r * n; gradient[0][0] += std::real(L[0][nms] * Ynm[nm]) * factor; gradient[0][1] += std::real(L[0][nms] * YnmTheta[nm]); gradient[1][0] += std::real(L[1][nms] * Ynm[nm]) * factor; gradient[1][1] += std::real(L[1][nms] * YnmTheta[nm]); gradient[2][0] += std::real(L[2][nms] * Ynm[nm]) * factor; gradient[2][1] += std::real(L[2][nms] * YnmTheta[nm]); gradient[3][0] += std::real(L[3][nms] * Ynm[nm]) * factor; gradient[3][1] += std::real(L[3][nms] * YnmTheta[nm]); for( int m=1; m<=n; ++m ) { nm = n * n + n + m; nms = n * (n + 1) / 2 + m; result[0] += scale * 2 * std::real(L[0][nms] * Ynm[nm]); result[1] += scale * 2 * std::real(L[1][nms] * Ynm[nm]); result[2] += scale * 2 * std::real(L[2][nms] * Ynm[nm]); gradient[0][0] += 2 * std::real(L[0][nms] * Ynm[nm]) * factor; gradient[0][1] += 2 * std::real(L[0][nms] * YnmTheta[nm]); gradient[0][2] += 2 * std::real(L[0][nms] * Ynm[nm] * CI) * m; gradient[1][0] += 2 * std::real(L[1][nms] * Ynm[nm]) * factor; gradient[1][1] += 2 * std::real(L[1][nms] * YnmTheta[nm]); gradient[1][2] += 2 * std::real(L[1][nms] * Ynm[nm] * CI) * m; gradient[2][0] += 2 * std::real(L[2][nms] * Ynm[nm]) * factor; gradient[2][1] += 2 * std::real(L[2][nms] * YnmTheta[nm]); gradient[2][2] += 2 * std::real(L[2][nms] * Ynm[nm] * CI) * m; gradient[3][0] += 2 * std::real(L[3][nms] * Ynm[nm]) * factor; gradient[3][1] += 2 * std::real(L[3][nms] * YnmTheta[nm]); gradient[3][2] += 2 * std::real(L[3][nms] * Ynm[nm] * CI) * m; } } sph2cart(r,theta,phi,gradient[0],cartesian); cartesian *= -target[0]; gradient[0] = cartesian; sph2cart(r,theta,phi,gradient[1],cartesian); cartesian *= -target[1]; gradient[1] = cartesian; sph2cart(r,theta,phi,gradient[2],cartesian); cartesian *= -target[2]; gradient[2] = cartesian; sph2cart(r,theta,phi,gradient[3],cartesian); gradient[3] = cartesian; result[0] += scale*(gradient[0][0]+gradient[1][0]+gradient[2][0]+gradient[3][0]); result[1] += scale*(gradient[0][1]+gradient[1][1]+gradient[2][1]+gradient[3][1]); result[2] += scale*(gradient[0][2]+gradient[1][2]+gradient[2][2]+gradient[3][2]); }
// m2p void FmmKernel::m2p(int numBoxIndex, int numLevel) { int ii,i,ij,jj,jb,j,n,nm,nms,m; vec3<int> boxIndex3D; vec3<float> boxCenter; vec3<double> accel,dist; double boxSize,r,theta,phi,rn,accelR,accelTheta,accelPhi; double xx,yy,s2,fact,pn,p,p1,p2; double YnmReal[numExpansion2],YnmRealTheta[numExpansion2]; std::complex<double> MnmVector[numCoefficients]; std::complex<double> rr,rtheta,rphi,I(0.0,1.0),eim; boxSize = rootBoxSize/(1 << numLevel); for( ii=0; ii<numBoxIndex; ii++ ) { for( i=particleOffset[0][ii]; i<=particleOffset[1][ii]; i++ ) { for( ij=0; ij<numInteraction[ii]; ij++ ) { jj = interactionList[ii][ij]; jb = jj+levelOffset[numLevel-1]; for( j=0; j<numCoefficients; j++ ) MnmVector[j] = Mnm[jb][j]; tree.unmorton(boxIndexFull[jb],boxIndex3D); boxCenter.x = boxMin.x+(boxIndex3D.x+0.5)*boxSize; boxCenter.y = boxMin.y+(boxIndex3D.y+0.5)*boxSize; boxCenter.z = boxMin.z+(boxIndex3D.z+0.5)*boxSize; dist.x = bodyPos[i].x-boxCenter.x; dist.y = bodyPos[i].y-boxCenter.y; dist.z = bodyPos[i].z-boxCenter.z; cart2sph(r,theta,phi,dist.x,dist.y,dist.z); xx = cos(theta); yy = sin(theta); s2 = sqrt((1-xx)*(1+xx)); fact = 1; pn = 1; for( m=0; m<numExpansions; m++ ) { p = pn; nm = m*m+2*m; YnmReal[nm] = factorial[nm]*p; p1 = p; p = xx*(2*m+1)*p; YnmRealTheta[nm] = factorial[nm]*(p-(m+1)*xx*p1)/yy; for( n=m+1; n<numExpansions; n++ ) { nm = n*n+n+m; YnmReal[nm] = factorial[nm]*p; p2 = p1; p1 = p; p = (xx*(2*n+1)*p1-(n+m)*p2)/(n-m+1); YnmRealTheta[nm] = factorial[nm]*((n-m+1)*p-(n+1)*xx*p1)/yy; } pn = -pn*fact*s2; fact += 2; } accelR = 0; accelTheta = 0; accelPhi = 0; rn = 1/r; for( n=0; n<numExpansions; n++ ) { rn /= r; nm = n*n+n; nms = n*(n+1)/2; rr = -(n+1)*rn*YnmReal[nm]; rtheta = rn*r*YnmRealTheta[nm]; accelR += real(rr*MnmVector[nms]); accelTheta += real(rtheta*MnmVector[nms]); for( m=1; m<=n; m++ ) { nm = n*n+n+m; nms = n*(n+1)/2+m; eim = exp(m*phi*I); rr = -(n+1)*rn*YnmReal[nm]*eim; rtheta = rn*r*YnmRealTheta[nm]*eim; rphi = m*rn*r*YnmReal[nm]*eim*I; accelR += 2*real(rr*MnmVector[nms]); accelTheta += 2*real(rtheta*MnmVector[nms]); accelPhi += 2*real(rphi*MnmVector[nms]); } } accel.x = sin(theta)*cos(phi)*accelR+cos(theta)*cos(phi)/r*accelTheta-sin(phi)/r/sin(theta)*accelPhi; accel.y = sin(theta)*sin(phi)*accelR+cos(theta)*sin(phi)/r*accelTheta+cos(phi)/r/sin(theta)*accelPhi; accel.z = cos(theta)*accelR-sin(theta)/r*accelTheta; bodyAccel[i].x += inv4PI*accel.x; bodyAccel[i].y += inv4PI*accel.y; bodyAccel[i].z += inv4PI*accel.z; } } } }
// precalculate M2L translation matrix and Wigner rotation matrix void FmmKernel::precalc() { int n,m,nm,nabsm,j,k,nk,npn,nmn,npm,nmm,nmk,i,nmk1,nm1k,nmk2; vec3<int> boxIndex3D; vec3<double> dist; double anmk[2][numExpansion4]; double Dnmd[numExpansion4]; double fnma,fnpa,pn,p,p1,p2,anmd,anmkd,rho,alpha,beta,sc,ank,ek; std::complex<double> expBeta[numExpansion2],I(0.0,1.0); int jk,jkn,jnk; double fnmm,fnpm,fad; for( n=0; n<2*numExpansions; n++ ) { for( m=-n; m<=n; m++ ) { nm = n*n+n+m; nabsm = abs(m); fnmm = 1.0; for( i=1; i<=n-m; i++ ) fnmm *= i; fnpm = 1.0; for( i=1; i<=n+m; i++ ) fnpm *= i; fnma = 1.0; for( i=1; i<=n-nabsm; i++ ) fnma *= i; fnpa = 1.0; for( i=1; i<=n+nabsm; i++ ) fnpa *= i; factorial[nm] = sqrt(fnma/fnpa); fad = sqrt(fnmm*fnpm); anm[nm] = pow(-1.0,n)/fad; } } for( j=0; j<numExpansions; j++) { for( k=-j; k<=j; k++ ){ jk = j*j+j+k; for( n=abs(k); n<numExpansions; n++ ) { nk = n*n+n+k; jkn = jk*numExpansion2+nk; jnk = (j+n)*(j+n)+j+n; Anm[jkn] = pow(-1.0,j+k)*anm[nk]*anm[jk]/anm[jnk]; } } } pn = 1; for( m=0; m<2*numExpansions; m++ ) { p = pn; npn = m*m+2*m; nmn = m*m; Ynm[npn] = factorial[npn]*p; Ynm[nmn] = conj(Ynm[npn]); p1 = p; p = (2*m+1)*p; for( n=m+1; n<2*numExpansions; n++ ) { npm = n*n+n+m; nmm = n*n+n-m; Ynm[npm] = factorial[npm]*p; Ynm[nmm] = conj(Ynm[npm]); p2 = p1; p1 = p; p = ((2*n+1)*p1-(n+m)*p2)/(n-m+1); } pn = 0; } for( n=0; n<numExpansions; n++ ) { for( m=1; m<=n; m++ ) { anmd = n*(n+1)-m*(m-1); for( k=1-m; k<m; k++ ) { nmk = (4*n*n*n+6*n*n+5*n)/3+m*(2*n+1)+k; anmkd = ((double) (n*(n+1)-k*(k+1)))/(n*(n+1)-m*(m-1)); anmk[0][nmk] = -(m+k)/sqrt(anmd); anmk[1][nmk] = sqrt(anmkd); } } } for( i=0; i<numRelativeBox; i++ ) { tree.unmorton(i,boxIndex3D); dist.x = boxIndex3D.x-3; dist.y = boxIndex3D.y-3; dist.z = boxIndex3D.z-3; cart2sph(rho,alpha,beta,dist.x,dist.y,dist.z); sc = sin(alpha)/(1+cos(alpha)); for( n=0; n<4*numExpansions-3; n++ ) { expBeta[n] = exp((n-2*numExpansions+2)*beta*I); } for( n=0; n<numExpansions; n++ ) { nmk = (4*n*n*n+6*n*n+5*n)/3+n*(2*n+1)+n; Dnmd[nmk] = pow(cos(alpha*0.5),2*n); for( k=n; k>=1-n; k-- ) { nmk = (4*n*n*n+6*n*n+5*n)/3+n*(2*n+1)+k; nmk1 = (4*n*n*n+6*n*n+5*n)/3+n*(2*n+1)+k-1; ank = ((double) n+k)/(n-k+1); Dnmd[nmk1] = sqrt(ank)*tan(alpha*0.5)*Dnmd[nmk]; } for( m=n; m>=1; m-- ) { for( k=m-1; k>=1-m; k-- ){ nmk = (4*n*n*n+6*n*n+5*n)/3+m*(2*n+1)+k; nmk1 = (4*n*n*n+6*n*n+5*n)/3+m*(2*n+1)+k+1; nm1k = (4*n*n*n+6*n*n+5*n)/3+(m-1)*(2*n+1)+k; Dnmd[nm1k] = anmk[1][nmk]*Dnmd[nmk1]+anmk[0][nmk]*sc*Dnmd[nmk]; } } } for( n=1; n<numExpansions; n++ ) { for( m=0; m<=n; m++ ) { for( k=-m; k<=-1; k++ ) { ek = pow(-1.0,k); nmk = (4*n*n*n+6*n*n+5*n)/3+m*(2*n+1)+k; nmk1 = (4*n*n*n+6*n*n+5*n)/3-k*(2*n+1)-m; Dnmd[nmk] = ek*Dnmd[nmk]; Dnmd[nmk1] = pow(-1.0,m+k)*Dnmd[nmk]; } for( k=0; k<=m; k++ ) { nmk = (4*n*n*n+6*n*n+5*n)/3+m*(2*n+1)+k; nmk1 = (4*n*n*n+6*n*n+5*n)/3+k*(2*n+1)+m; nmk2 = (4*n*n*n+6*n*n+5*n)/3-k*(2*n+1)-m; Dnmd[nmk1] = pow(-1.0,m+k)*Dnmd[nmk]; Dnmd[nmk2] = Dnmd[nmk1]; } } } for( n=0; n<numExpansions; n++ ) { for( m=0; m<=n; m++ ) { for( k=-n; k<=n; k++ ) { nmk = (4*n*n*n+6*n*n+5*n)/3+m*(2*n+1)+k; nk = n*(n+1)+k; Dnm[i][m][nk] = Dnmd[nmk]*expBeta[k+m+2*numExpansions-2]; } } } alpha = -alpha; beta = -beta; sc = sin(alpha)/(1+cos(alpha)); for( n=0; n<4*numExpansions-3; n++ ) { expBeta[n] = exp((n-2*numExpansions+2)*beta*I); } for( n=0; n<numExpansions; n++ ) { nmk = (4*n*n*n+6*n*n+5*n)/3+n*(2*n+1)+n; Dnmd[nmk] = pow(cos(alpha*0.5),2*n); for( k=n; k>=1-n; k-- ) { nmk = (4*n*n*n+6*n*n+5*n)/3+n*(2*n+1)+k; nmk1 = (4*n*n*n+6*n*n+5*n)/3+n*(2*n+1)+k-1; ank = ((double) n+k)/(n-k+1); Dnmd[nmk1] = sqrt(ank)*tan(alpha*0.5)*Dnmd[nmk]; } for( m=n; m>=1; m-- ) { for( k=m-1; k>=1-m; k-- ) { nmk = (4*n*n*n+6*n*n+5*n)/3+m*(2*n+1)+k; nmk1 = (4*n*n*n+6*n*n+5*n)/3+m*(2*n+1)+k+1; nm1k = (4*n*n*n+6*n*n+5*n)/3+(m-1)*(2*n+1)+k; Dnmd[nm1k] = anmk[1][nmk]*Dnmd[nmk1]+anmk[0][nmk]*sc*Dnmd[nmk]; } } } for( n=1; n<numExpansions; n++ ) { for( m=0; m<=n; m++ ) { for( k=-m; k<=-1; k++ ) { ek = pow(-1.0,k); nmk = (4*n*n*n+6*n*n+5*n)/3+m*(2*n+1)+k; nmk1 = (4*n*n*n+6*n*n+5*n)/3-k*(2*n+1)-m; Dnmd[nmk] = ek*Dnmd[nmk]; Dnmd[nmk1] = pow(-1.0,m+k)*Dnmd[nmk]; } for( k=0; k<=m; k++ ) { nmk = (4*n*n*n+6*n*n+5*n)/3+m*(2*n+1)+k; nmk1 = (4*n*n*n+6*n*n+5*n)/3+k*(2*n+1)+m; nmk2 = (4*n*n*n+6*n*n+5*n)/3-k*(2*n+1)-m; Dnmd[nmk1] = pow(-1.0,m+k)*Dnmd[nmk]; Dnmd[nmk2] = Dnmd[nmk1]; } } } for( n=0; n<numExpansions; n++ ) { for( m=0; m<=n; m++ ) { for( k=-n; k<=n; k++ ) { nmk = (4*n*n*n+6*n*n+5*n)/3+m*(2*n+1)+k; nk = n*(n+1)+k; Dnm[i+numRelativeBox][m][nk] = Dnmd[nmk]*expBeta[k+m+2*numExpansions-2]; } } } } for( j=0; j<numBoxIndexTotal; j++ ) { for( i=0; i<numCoefficients; i++ ) { Mnm[j][i] = 0; } } }
// p2m void FmmKernel::p2m(int numBoxIndex) { int jj,j,n,m,nm,nms; vec3<int> boxIndex3D; vec3<float> boxCenter; vec3<double> dist; double boxSize,rho,alpha,beta; double xx,s2,fact,pn,p,p1,p2,rhom,rhon; double YnmReal[numExpansion2]; std::complex<double> MnmVector[numCoefficients],I(0.0,1.0),eim; boxSize = rootBoxSize/(1 << maxLevel); for( jj=0; jj<numBoxIndex; jj++ ) { tree.unmorton(boxIndexFull[jj],boxIndex3D); boxCenter.x = boxMin.x+(boxIndex3D.x+0.5)*boxSize; boxCenter.y = boxMin.y+(boxIndex3D.y+0.5)*boxSize; boxCenter.z = boxMin.z+(boxIndex3D.z+0.5)*boxSize; for( j=0; j<numCoefficients; j++ ) { MnmVector[j] = 0; } for( j=particleOffset[0][jj]; j<=particleOffset[1][jj]; j++ ) { dist.x = bodyPos[j].x-boxCenter.x; dist.y = bodyPos[j].y-boxCenter.y; dist.z = bodyPos[j].z-boxCenter.z; cart2sph(rho,alpha,beta,dist.x,dist.y,dist.z); xx = cos(alpha); s2 = sqrt((1-xx)*(1+xx)); fact = 1; pn = 1; rhom = 1; for( m=0; m<numExpansions; m++ ) { p = pn; nm = m*m+2*m; YnmReal[nm] = rhom*factorial[nm]*p; p1 = p; p = xx*(2*m+1)*p; rhom *= rho; rhon = rhom; for( n=m+1; n<numExpansions; n++ ) { nm = n*n+n+m; YnmReal[nm] = rhon*factorial[nm]*p; p2 = p1; p1 = p; p = (xx*(2*n+1)*p1-(n+m)*p2)/(n-m+1); rhon *=rho; } pn = -pn*fact*s2; fact += 2; } for( n=0; n<numExpansions; n++ ) { for( m=0; m<=n; m++ ) { nm = n*n+n+m; nms = n*(n+1)/2+m; eim = exp(-m*beta*I); MnmVector[nms] += ((std::complex<double>) bodyPos[j].w)*YnmReal[nm]*eim; } } } for( j=0; j<numCoefficients; j++ ) { Mnm[jj][j] = MnmVector[j]; } } }
FE_TMPL std::complex<float> FE_SYS::_I(int n,int m,glm::vec3 x){ glm::vec3 s = cart2sph(x); return std::pow(std::complex<float>(0,-1),-std::abs(m)) * _A(n,m) * std::pow(s.x,n) * _Y(n,m,s.y,s.z); }
void get_sources(ParamCoLoRe *par) { ////// // Uses the gaussian matter density field to obtain a // poisson sampling of point sources (returns an integer array // with the number of sources in each cell). int ii,nthr; lint *np_tot_thr; #ifdef _HAVE_OMP nthr=omp_get_max_threads(); #else //_HAVE_OMP nthr=1; #endif //_HAVE_OMP np_tot_thr=my_calloc(nthr,sizeof(lint)); print_info("*** Getting point sources\n"); if(NodeThis==0) timer(0); print_info("Poisson-sampling\n"); #ifdef _HAVE_OMP #pragma omp parallel default(none) \ shared(par,np_tot_thr,IThread0) #endif //_HAVE_OMP { lint iz; #ifdef _HAVE_OMP int ithr=omp_get_thread_num(); #else //_HAVE_OMP int ithr=0; #endif //_HAVE_OMP double dx=par->l_box/par->n_grid; double cell_vol=dx*dx*dx; int ngx=2*(par->n_grid/2+1); unsigned int seed_thr=par->seed_rng+IThread0+ithr; gsl_rng *rng_thr=init_rng(seed_thr); #ifdef _HAVE_OMP #pragma omp for schedule(static) #endif //_HAVE_OMP for(iz=0;iz<par->nz_here;iz++) { int iy; lint indexz=iz*((lint)(ngx*par->n_grid)); double z0=(iz+par->iz0_here+0.5)*dx-par->pos_obs[2]; for(iy=0;iy<par->n_grid;iy++) { int ix; lint indexy=iy*ngx; double y0=(iy+0.5)*dx-par->pos_obs[1]; for(ix=0;ix<par->n_grid;ix++) { int npp=0; double dz_rsd=0; lint index=ix+indexy+indexz; double x0=(ix+0.5)*dx-par->pos_obs[1]; double r=sqrt(x0*x0+y0*y0+z0*z0); double redshift=z_of_r(par,r); double ndens=ndens_of_z(par,redshift); if(ndens>0) { double bias=bias_of_z(par,redshift); double gfb=dgrowth_of_r(par,r)*bias; double lambda=ndens*cell_vol* exp(gfb*(par->grid_dens[index]-0.5*gfb*par->sigma2_gauss)); npp=rng_poisson(lambda,rng_thr); dz_rsd=par->grid_rvel[index]*vgrowth_of_r(par,r); } par->grid_rvel[index]=dz_rsd; par->nsources[index]=npp; np_tot_thr[ithr]+=npp; } } }//end omp for end_rng(rng_thr); }//end omp parallel if(NodeThis==0) timer(2); par->nsources_this=0; for(ii=0;ii<nthr;ii++) par->nsources_this+=np_tot_thr[ii]; par->nsources_total=0; #ifdef _HAVE_MPI MPI_Allreduce(&(par->nsources_this),&(par->nsources_total),1,LINT_MPI,MPI_SUM,MPI_COMM_WORLD); #else //_HAVE_MPI par->nsources_total=par->nsources_this; #endif //_HAVE_MPI print_info(" There will be %ld particles in total\n",(long)(par->nsources_total)); //#ifdef _DEBUG // printf("Node %d has %ld particles\n",NodeThis,(long)(par->nsources_this)); //#endif //_DEBUG for(ii=nthr-1;ii>0;ii--) { int jj; lint nh=0; for(jj=0;jj<ii;jj++) nh+=np_tot_thr[jj]; np_tot_thr[ii]=nh; } np_tot_thr[0]=0; //np_tot_thr now contains the id of the first particle in the thread #ifdef _SPREC fftwf_free(par->grid_dens_f); #else //_SPREC fftw_free(par->grid_dens_f); #endif //_SPREC par->grid_dens_f=NULL; par->gals=my_malloc(par->nsources_this*sizeof(Gal)); if(NodeThis==0) timer(0); print_info("Assigning coordinates\n"); #ifdef _HAVE_OMP #pragma omp parallel default(none) \ shared(par,IThread0,np_tot_thr) #endif //_HAVE_OMP { lint iz; #ifdef _HAVE_OMP int ithr=omp_get_thread_num(); #else //_HAVE_OMP int ithr=0; #endif //_HAVE_OMP double dx=par->l_box/par->n_grid; int ngx=2*(par->n_grid/2+1); unsigned int seed_thr=par->seed_rng+IThread0+ithr; gsl_rng *rng_thr=init_rng(seed_thr); #ifdef _HAVE_OMP #pragma omp for schedule(static) #endif //_HAVE_OMP for(iz=0;iz<par->nz_here;iz++) { int iy; lint indexz=iz*((lint)(ngx*par->n_grid)); double z0=(iz+par->iz0_here)*dx-par->pos_obs[2]; for(iy=0;iy<par->n_grid;iy++) { int ix; lint indexy=iy*ngx; double y0=iy*dx-par->pos_obs[1]; for(ix=0;ix<par->n_grid;ix++) { double x0=ix*dx-par->pos_obs[1]; lint index=ix+indexy+indexz; int npp=par->nsources[index]; if(npp>0) { int ip; double dz_rsd=par->grid_rvel[index]; for(ip=0;ip<npp;ip++) { double cth,phi,r; lint pid=np_tot_thr[ithr]; double x=x0+dx*rng_01(rng_thr); double y=y0+dx*rng_01(rng_thr); double z=z0+dx*rng_01(rng_thr); cart2sph(x,y,z,&r,&cth,&phi); par->gals[pid].ra=RTOD*phi; par->gals[pid].dec=90-RTOD*acos(cth); par->gals[pid].z0=z_of_r(par,r); par->gals[pid].dz_rsd=dz_rsd; np_tot_thr[ithr]++; } } } } }//end omp for end_rng(rng_thr); }//end omp parallel if(NodeThis==0) timer(2); free(np_tot_thr); print_info("\n"); }