Fixed K computation. Handle fully the Nyquist plane depending on the parity of dimensions.

This commit is contained in:
Guilhem Lavaux 2012-11-10 19:11:34 -05:00
parent cc7996175c
commit 3c0e7ae8f8
2 changed files with 70 additions and 21 deletions

View File

@ -9,14 +9,16 @@ using namespace std;
double spectrum_generator(double k) double spectrum_generator(double k)
{ {
return 1/(0.1+pow(k, 3.0)); if (k==0)
return 0;
return 1/(0.01+pow(k, 3.0));
} }
int main() int main()
{ {
EuclidianFourierTransform_2d<double> dft(128,128,1.0,1.0); EuclidianFourierTransform_2d<double> dft(1024,1024,1.0,1.0);
EuclidianSpectrum_1D<double> spectrum(spectrum_generator); EuclidianSpectrum_1D<double> spectrum(spectrum_generator);
double volume = 128*128; double volume = 1024*1024;
gsl_rng *rng = gsl_rng_alloc(gsl_rng_default); gsl_rng *rng = gsl_rng_alloc(gsl_rng_default);
dft.realSpace().eigen().setRandom(); dft.realSpace().eigen().setRandom();
@ -33,7 +35,7 @@ int main()
dft.fourierSpace() = *m.get(); dft.fourierSpace() = *m.get();
dft.synthesis(); dft.synthesis();
uint32_t dims[2] = { 128, 128 }; uint32_t dims[2] = { 1024, 1024 };
CosmoTool::saveArray("generated_map.nc", dft.realSpace().data(), dims, 2); CosmoTool::saveArray("generated_map.nc", dft.realSpace().data(), dims, 2);
return 0; return 0;

View File

@ -109,19 +109,26 @@ namespace CosmoTool
protected: protected:
typedef boost::shared_ptr<std::complex<T> > ptr_t; typedef boost::shared_ptr<std::complex<T> > ptr_t;
std::vector<double> delta_k; std::vector<double> delta_k;
int m_dim0;
bool even0, alleven;
long plane_size; long plane_size;
public: public:
typedef typename EuclidianFourierMapBase<std::complex<T> >::DimArray DimArray; typedef typename EuclidianFourierMapBase<std::complex<T> >::DimArray DimArray;
EuclidianFourierMapComplex(ptr_t indata, EuclidianFourierMapComplex(ptr_t indata,
int dim0,
const DimArray& indims, const DimArray& indims,
const std::vector<double>& dk) const std::vector<double>& dk)
: EuclidianFourierMapBase<std::complex<T> >(indata, indims), delta_k(dk) : EuclidianFourierMapBase<std::complex<T> >(indata, indims), delta_k(dk), m_dim0(dim0), even0((dim0 % 2)==0)
{ {
assert(dk.size() == indims.size()); assert(dk.size() == indims.size());
plane_size = 1; plane_size = 1;
alleven = true;
for (int q = 1; q < indims.size(); q++) for (int q = 1; q < indims.size(); q++)
plane_size *= indims[q]; {
plane_size *= indims[q];
alleven = alleven && ((indims[q]%2)==0);
}
} }
virtual FourierMap<std::complex<T> > *mimick() const virtual FourierMap<std::complex<T> > *mimick() const
@ -131,6 +138,7 @@ namespace CosmoTool
ptr_t((std::complex<T> *) ptr_t((std::complex<T> *)
fftw_malloc(sizeof(std::complex<T>)*this->size()), fftw_malloc(sizeof(std::complex<T>)*this->size()),
std::ptr_fun(fftw_free)), std::ptr_fun(fftw_free)),
m_dim0,
this->getDims(), this->getDims(),
this->delta_k); this->delta_k);
} }
@ -141,7 +149,9 @@ namespace CosmoTool
const DimArray& dims = this->getDims(); const DimArray& dims = this->getDims();
assert(ik.size() == dims.size()); assert(ik.size() == dims.size());
double k2 = 0; double k2 = 0;
for (int q = 0; q < ik.size(); q++) k2 += CosmoTool::square(ik[0]*delta_k[0]);
for (int q = 1; q < ik.size(); q++)
{ {
int dk = ik[q]; int dk = ik[q];
@ -165,6 +175,9 @@ namespace CosmoTool
return get_K(d); return get_K(d);
} }
bool allDimensionsEven() const { return alleven; }
bool firstDimensionEven() const { return even0; }
virtual std::complex<T> dot_product(const FourierMap<std::complex<T> >& other) const virtual std::complex<T> dot_product(const FourierMap<std::complex<T> >& other) const
throw(std::bad_cast) throw(std::bad_cast)
{ {
@ -175,7 +188,7 @@ namespace CosmoTool
const std::complex<T> *d1 = this->data(); const std::complex<T> *d1 = this->data();
const std::complex<T> *d2 = m2.data(); const std::complex<T> *d2 = m2.data();
const DimArray& dims = this->getDims(); const DimArray& dims = this->getDims();
int N0 = dims[0]; int N0 = dims[0] + (even0 ? 0 : 1);
std::complex<T> result = 0; std::complex<T> result = 0;
for (long q0 = 1; q0 < N0-1; q0++) for (long q0 = 1; q0 < N0-1; q0++)
@ -187,11 +200,14 @@ namespace CosmoTool
result += 2*(conj(d1[idx]) * d2[idx]).real(); result += 2*(conj(d1[idx]) * d2[idx]).real();
} }
} }
for (long p = 0; p < plane_size; p++) if (!even0)
{ {
long q0 = N0*p, q1 = (p+1)*N0-1; for (long p = 0; p < plane_size; p++)
result += conj(d1[q0]) * d2[q0]; {
result += conj(d1[q1]) * d2[q1]; long q0 = N0*p, q1 = (p+1)*N0-1;
result += conj(d1[q0]) * d2[q0];
result += conj(d1[q1]) * d2[q1];
}
} }
return result; return result;
} }
@ -239,7 +255,7 @@ namespace CosmoTool
fourierMap = new EuclidianFourierMapComplex<T>( fourierMap = new EuclidianFourierMapComplex<T>(
boost::shared_ptr<std::complex<T> >((std::complex<T>*)calls::alloc_complex(N), boost::shared_ptr<std::complex<T> >((std::complex<T>*)calls::alloc_complex(N),
std::ptr_fun(calls::free)), std::ptr_fun(calls::free)),
m_dims_hc, dk); dims[0], m_dims_hc, dk);
m_analysis = calls::plan_dft_r2c(dims.size(), &dims[0], m_analysis = calls::plan_dft_r2c(dims.size(), &dims[0],
realMap->data(), (typename calls::complex_type *)fourierMap->data(), realMap->data(), (typename calls::complex_type *)fourierMap->data(),
FFTW_MEASURE); FFTW_MEASURE);
@ -306,6 +322,26 @@ namespace CosmoTool
} }
}; };
template<typename T>
class EuclidianFourierTransform_1d: public EuclidianFourierTransform<T>
{
private:
template<typename T2>
static std::vector<T2> make_1d_vector(T2 a)
{
T2 arr[2] = { a};
return std::vector<T2>(&arr[0],&arr[1]);
}
public:
EuclidianFourierTransform_1d(int Nx, double Lx)
: EuclidianFourierTransform<T>(make_1d_vector<int>(Nx), make_1d_vector<double>(Lx))
{
}
virtual ~EuclidianFourierTransform_1d() {}
};
template<typename T> template<typename T>
class EuclidianFourierTransform_2d: public EuclidianFourierTransform<T> class EuclidianFourierTransform_2d: public EuclidianFourierTransform<T>
{ {
@ -363,6 +399,7 @@ namespace CosmoTool
long idx; long idx;
const DimArray& dims = rand_map.getDims(); const DimArray& dims = rand_map.getDims();
long plane_size; long plane_size;
bool alleven = rand_map.allDimensionsEven();
for (long p = 1; p < m_c.size(); p++) for (long p = 1; p < m_c.size(); p++)
{ {
@ -371,16 +408,18 @@ namespace CosmoTool
gsl_ran_gaussian(rng, A_k)); gsl_ran_gaussian(rng, A_k));
} }
// Generate the mean value // Generate the mean value
d[0] = std::complex<T>(std::sqrt(f(0)), 0); d[0] = std::complex<T>(gsl_ran_gaussian(rng, std::sqrt(f(0))), 0);
if (!rand_map.firstDimensionEven())
return ret_map;
// Correct the Nyquist plane // Correct the Nyquist plane
idx = dims[0]-1; // Stick to the last element of the first dimension idx = dims[0]-1; // Stick to the last element of the first dimension
d[idx] = std::complex<T>(d[idx].real() + d[idx].imag(), 0);
// 1D is special case // 1D is special case
if (dims.size() == 1) if (dims.size() == 1)
{ return ret_map;
d[idx] = std::complex<T>(d[idx].real() + d[idx].imag(), 0);
return ret_map;
}
plane_size = 1; plane_size = 1;
for (int q = 1; q < dims.size(); q++) for (int q = 1; q < dims.size(); q++)
{ {
@ -395,8 +434,16 @@ namespace CosmoTool
assert(q2 < plane_size*dims[0]); assert(q2 < plane_size*dims[0]);
d[q] = conj(d[q2]); d[q] = conj(d[q2]);
} }
long q = dims[0];
d[q] = std::complex<T>(d[q].real() + d[q].imag()); if (alleven)
{
long q = 0;
for (int i = dims.size()-1; i >= 1; i--)
q = dims[i]*q + dims[i]/2;
q += dims[0]-1;
d[q] = std::complex<T>(d[q].real()+d[q].imag(),0);
}
return ret_map; return ret_map;
} }