void cosmobl::reconstruction_fourier_space (const catalogue::Catalogue data, const catalogue::Catalogue random, const cosmology::Cosmology cosmology, const double redshift, const double bias, const double cell_size, const double smoothing_radius, const int interpolation_type)
{
  double ff = cosmology.linear_growth_rate(redshift);
  double beta = ff/bias;
  
  //double rsd_term = 3*ff/(7+3*ff);
  double rsd_term = (ff-beta)/(1+beta);

  data::ScalarField3D density_field = data.density_field(cell_size, interpolation_type, smoothing_radius);
  density_field.FourierTransformField();

  data::VectorField3D displacement_field(density_field.nx(), density_field.ny(), density_field.nz(), density_field.MinX(), density_field.MaxX(), density_field.MinY(), density_field.MaxY(), density_field.MinZ(), density_field.MaxZ()); 

  data::VectorField3D displacement_field_RSD(density_field.nx(), density_field.ny(), density_field.nz(), density_field.MinX(), density_field.MaxX(), density_field.MinY(), density_field.MaxY(), density_field.MinZ(), density_field.MaxZ()); 

  
  // convert the grid to the displacement field (in Fourier space)

  double xfact = 2.*par::pi/(density_field.deltaX()*density_field.nx());
  double yfact = 2.*par::pi/(density_field.deltaY()*density_field.ny());
  double zfact = 2.*par::pi/(density_field.deltaZ()*density_field.nz());

  for (int i=0; i<density_field.nx(); i++) {
    double kx = (i<=density_field.nx()/2) ? xfact*i : -(density_field.nx()-i)*xfact;
    for (int j=0; j<density_field.ny(); j++) {
      double ky =(j<=density_field.ny()/2) ? yfact*j : -(density_field.ny()-j)*yfact;
      for (int k=0; k<density_field.nzFourier(); k++) {
	double kz = zfact*k;
	double kk = pow(kx*kx+ky*ky+kz*kz, 0.5);

	vector<double> gridK = {density_field.ScalarField_FourierSpace_real (i, j, k), density_field.ScalarField_FourierSpace_complex (i, j, k) };

	if (kk!=0){
	  displacement_field.set_VectorField_FourierSpace_real({kx*gridK[1]/(kk*kk)/bias, ky*gridK[1]/(kk*kk)/bias, kz*gridK[1]/(kk*kk)/bias} ,i ,j ,k);

	  displacement_field.set_VectorField_FourierSpace_complex({-kx*gridK[0]/(kk*kk)/bias, -ky*gridK[0]/(kk*kk)/bias, -kz*gridK[0]/(kk*kk)/bias} ,i , j, k);
	}

      }
    }
  }
  
  displacement_field.FourierAntiTransformField();

  
  // apply the RSD correction (in Fourier space)
  
  for (int i=0; i<density_field.nx(); i++)
    for (int j=0; j<density_field.ny(); j++)
      for (int k=0; k<density_field.nz(); k++) {

	double rx = i*density_field.deltaX()+density_field.MinX(), ry = j*density_field.deltaY()+density_field.MinY(), rz = k*density_field.deltaZ()+density_field.MinZ();
	double rr = (sqrt(rx*rx+ry*ry+rz*rz)==0) ? 1 : sqrt(rx*rx+ry*ry+rz*rz);

	vector<double> displ = displacement_field.VectorField(i, j, k);
	double scalar_product = (rr==0) ? 0. : (displ[0]*rx+displ[1]*ry+displ[2]*rz)/rr;

	double displ_x_rsd = displ[0]+rsd_term*scalar_product*rx/rr; 
	double displ_y_rsd = displ[1]+rsd_term*scalar_product*ry/rr; 
	double displ_z_rsd = displ[2]+rsd_term*scalar_product*rz/rr; 

	displacement_field_RSD.set_VectorField({displ_x_rsd, displ_y_rsd, displ_z_rsd}, i, j, k);
      }

  
  // set the displacement

  for (size_t i=0; i<data.nObjects(); i++) {
    int i1 = min(int((data.xx(i)-density_field.MinX())/density_field.deltaX()), density_field.nx()-1);
    int j1 = min(int((data.yy(i)-density_field.MinY())/density_field.deltaY()), density_field.ny()-1);
    int k1 = min(int((data.zz(i)-density_field.MinZ())/density_field.deltaZ()), density_field.nz()-1);

    vector<double> displacement = displacement_field_RSD.VectorField(i1, j1, k1);

    data.catalogue_object(i)->set_x_displacement(displacement[0]);
    data.catalogue_object(i)->set_y_displacement(displacement[1]);
    data.catalogue_object(i)->set_z_displacement(displacement[2]);
  }

  for (size_t i=0; i<random.nObjects(); i++) {
    int i1 = min(int((random.xx(i)-density_field.MinX())/density_field.deltaX()), density_field.nx()-1);
    int j1 = min(int((random.yy(i)-density_field.MinY())/density_field.deltaY()), density_field.ny()-1);
    int k1 = min(int((random.zz(i)-density_field.MinZ())/density_field.deltaZ()), density_field.nz()-1);

    vector<double> displacement = displacement_field_RSD.VectorField(i1, j1, k1);

    random.catalogue_object(i)->set_x_displacement(displacement[0]);
    random.catalogue_object(i)->set_y_displacement(displacement[1]);
    random.catalogue_object(i)->set_z_displacement(displacement[2]);
  }
}