// Transform to a single k point: std::complex<double> XTable::kval(double kx, double ky) const { check_array(); // Don't evaluate if k not in fundamental period kx*=_dx; ky*=_dx; #ifdef FFT_DEBUG if (std::abs(kx) > M_PI || std::abs(ky) > M_PI) throw FFTOutofRange("XTable::kval() args out of range"); #endif std::complex<double> I(0.,1.); std::complex<double> dxphase=std::exp(-I*kx); std::complex<double> dyphase=std::exp(-I*ky); std::complex<double> phase(1.,0.); std::complex<double> z; std::complex<double> sum=0.; const double* zptr=_array.get(); std::complex<double> yphase=std::exp(I*(ky*_N/2)); for (int iy=0; iy< _N; iy++) { phase = yphase; phase *= std::exp(I*(kx*_N/2)); for (int ix=0; ix< _N ; ix++) { sum += phase* (*(zptr++)); phase *= dxphase; } yphase *= dyphase; } sum *= _dx*_dx; return sum; }
// Transform to a single k point: DComplex xTable::kval(double kx, double ky) const { // check this: don't evaluate if x not in fundamental period: kx*=dx; ky*=dx; if (kx > 2*PI || ky > 2*PI) throw FFTOutofRange(); DComplex I(0.,1.); DComplex dxphase=exp(-I*kx); DComplex dyphase=exp(-I*ky); DComplex phase(1.,0.); DComplex z; DComplex sum=0.; double *zptr=array; DComplex yphase=exp(I*(ky*N/2)); for (int i=0; i< N; i++) { phase = yphase; phase *= exp(I*(kx*N/2)); for (int j=0; j< N ; j++) { sum += phase* (*(zptr++)); phase *= dxphase; } yphase *= dyphase; } sum *= dx*dx*scaleby; return sum; }
size_t xTable::index(int i, int j) const { // origin will be in center. i += N/2; j += N/2; if (i<0 || i>=N || j<0 || j>=N) throw FFTOutofRange() ; return i*N+j; }
size_t kTable::index(int i, int j) const { // adjust for xTable with origin in center. if (i<-N/2 || i>N/2 || j<-N/2 || j>N/2) throw FFTOutofRange() ; if (j<0) { j=-j; i=-i; //need the conjugate in this case } if (i<0) i+=N; return i*(N/2+1)+j; }
// Transform to a single x point: // assumes (x,y) in physical units double KTable::xval(double x, double y) const { check_array(); x*=_dk; y*=_dk; // Don't evaluate if x not in fundamental period +-PI/dk: #ifdef FFT_DEBUG if (std::abs(x) > M_PI || std::abs(y) > M_PI) throw FFTOutofRange(" (x,y) too big in xval()"); #endif std::complex<double> I(0.,1.); std::complex<double> dxphase=std::exp(I*x); std::complex<double> dyphase=std::exp(I*y); std::complex<double> phase(1.,0.); std::complex<double> z; double sum=0.; // y DC terms first: const std::complex<double>* zptr=_array.get(); // Do the positive y frequencies std::complex<double> yphase=1.; for (int iy=0; iy< _N/2; iy++) { phase = yphase; z= *(zptr++); sum += (phase*z).real(); //x DC term for (int ix=1; ix< _N/2 ; ix++) { phase *= dxphase; z= *(zptr++); sum += (phase*z).real() * 2.; } phase *= dxphase; //ix=N/2 has no mirror: z= *(zptr++); sum += (phase*z).real(); yphase *= dyphase; } // wrap to the negative ky's yphase = std::exp(I*(y*(-_N/2))); for (int iy=-_N/2; iy< 0; iy++) { phase = yphase; z= *(zptr++); sum += (phase*z).real(); // x DC term for (int ix=1; ix< _N/2 ; ix++) { phase *= dxphase; z= *(zptr++); sum += (phase*z).real() * 2.; } phase *= dxphase; //ix=N/2 has no mirror: z= *(zptr++); sum += (phase*z).real(); yphase *= dyphase; } sum *= _dk*_dk/(4.*M_PI*M_PI); //inverse xform has 2pi in it. return sum; }
// Transform to a single x point: double kTable::xval(double x, double y) const { // ??? check this: don't evaluate if x not in fundamental period: x*=dk; y*=dk; if (x > 2*PI || y > 2*PI) throw FFTOutofRange(); DComplex I(0.,1.); DComplex dxphase=exp(I*x); DComplex dyphase=exp(I*y); DComplex phase(1.,0.); DComplex z; double sum=0.; // y DC terms first: DComplex *zptr=array; // Do the positive y frequencies DComplex yphase=1.; for (int i=0; i< N/2; i++) { phase = yphase; z= *(zptr++); sum += (phase*z).real(); //x DC term for (int j=1; j< N/2 ; j++) { phase *= dxphase; z= *(zptr++); sum += (phase*z).real() * 2.; } phase *= dxphase; //j=N/2 has no mirror: z= *(zptr++); sum += (phase*z).real(); yphase *= dyphase; } // wrap to the negative ky's yphase = exp(I*(y*(-N/2))); for (int i=-N/2; i< 0; i++) { phase = yphase; z= *(zptr++); sum += (phase*z).real() * 2.; for (int j=1; j< N/2 ; j++) { phase *= dxphase; z= *(zptr++); sum += (phase*z).real() * 2.; } phase *= dxphase; //j=N/2 has no mirror: z= *(zptr++); sum += (phase*z).real(); yphase *= dyphase; } sum *= dk*dk*scaleby/(4.*PI*PI); //inverse xform has 2pi in it. return sum; }
// Translate the PSF to be for source at (x0,y0); void KTable::translate(double x0, double y0) { clearCache(); // invalidate any stored interpolations check_array(); // convert to phases: x0*=_dk; y0*=_dk; // too big will just be wrapping around: #ifdef FFT_DEBUG if (x0 > M_PI || y0 > M_PI) throw FFTOutofRange("(x0,y0) too big in translate()"); #endif std::complex<double> I(0.,1.); std::complex<double> dxphase=std::exp(std::complex<double>(0.,-x0)); std::complex<double> dyphase=std::exp(std::complex<double>(0.,-y0)); std::complex<double> phase(1.,0.); std::complex<double> yphase=1.; std::complex<double> z; std::complex<double>* zptr=_array.get(); for (int iy=0; iy< _N/2; iy++) { phase = yphase; for (int ix=0; ix<= _N/2 ; ix++) { z = *zptr; *zptr = phase * z; phase *= dxphase; zptr++; } yphase *= dyphase; } // wrap to the negative ky's yphase = std::exp(I*((_N/2)*y0)); for (int iy=-_N/2; iy< 0; iy++) { phase = yphase; for (int ix=0; ix<= _N/2 ; ix++) { z = *zptr; *zptr = phase* z; phase *= dxphase; zptr++; } yphase *= dyphase; } }
void // Translate the PSF to be for source at (x0,y0); // ??need a sign flip here? kTable::Translate(double x0, double y0) { // convert to phases: x0*=dk; y0*=dk; // too big will just be wrapping around: if (x0 > PI || y0 > PI) throw FFTOutofRange(); DComplex I(0.,1.); DComplex dxphase=exp(DComplex(0.,x0)); DComplex dyphase=exp(DComplex(0.,y0)); DComplex phase(1.,0.); DComplex yphase=1.; DComplex z; DComplex *zptr=array; for (int i=0; i< N/2; i++) { phase = yphase; for (int j=0; j<= N/2 ; j++) { z = *zptr; *zptr = phase * z; phase *= dxphase; zptr++; } yphase *= dyphase; } // wrap to the negative ky's yphase = exp(I*((-N/2)*y0)); for (int i=-N/2; i< 0; i++) { phase = yphase; for (int j=0; j<= N/2 ; j++) { z = *zptr; *zptr = phase* z; phase *= dxphase; zptr++; } yphase *= dyphase; } return; }