
#/*##########################################################################
# Copyright (C) 2001-2013 European Synchrotron Radiation Facility
#
#              PyHST2  
#  European Synchrotron Radiation Facility, Grenoble,France
#
# PyHST2 is  developed at
# the ESRF by the Scientific Software  staff.
# Principal author for PyHST2: Alessandro Mirone.
#
# This program is free software; you can redistribute it and/or modify it 
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option) 
# any later version.
#
# PyHST2 is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# PyHST2; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
# Suite 330, Boston, MA 02111-1307, USA.
#
# PyHST2 follows the dual licensing model of Trolltech's Qt and Riverbank's PyQt
# and cannot be used as a free plugin for a non-free program. 
#
# Please contact the ESRF industrial unit (industry@esrf.fr) if this license 
# is a problem for you.
#############################################################################*/
#/*##########################################################################
# Copyright (C) 2004-2010 European Synchrotron Radiation Facility
#
# This file is part of the PyHST  Toolkit developed at
# the ESRF by the SciSoft  group.
#
# This toolkit is free software; you can redistribute it and/or modify it 
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option) 
# any later version.
#
# PyHST is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# PyHST; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
# Suite 330, Boston, MA 02111-1307, USA.
#
# PyHST follows the dual licensing model of Trolltech's Qt and Riverbank's PyQt
# and cannot be used as a free plugin for a non-free program. 
#
# Please contact the ESRF industrial unit (industry@esrf.fr) if this license 
# is a problem for you.
#############################################################################*/



#include<stdio.h>
#include<string.h>
#include<math.h>
#include<complex>
#include <cuda.h>
#include <cufft.h>

#define CUFFT_SAFE_CALL_EXCEPTION(call, extramsg) {do {	\
       cufftResult err = call;    \
       if( CUFFT_SUCCESS  != err) {   \
	 if(err==   CUFFT_INVALID_PLAN   )				\
	   sprintf(messaggio, "Error in file '%s' in line %i :%s -- %s \n", \
                   __FILE__, __LINE__, "CUFFT_INVALID_PLAN"    ,  extramsg); \
	 if(err==  CUFFT_ALLOC_FAILED   )				\
	   sprintf(messaggio, "Error in file '%s' in line %i :%s -- %s \n", \
                   __FILE__, __LINE__, "CUFFT_ALLOC_FAILED"    ,  extramsg); \
	 if(err==  CUFFT_INVALID_TYPE   )				\
	   sprintf(messaggio, "Error in file '%s' in line %i :%s -- %s \n", \
                   __FILE__, __LINE__,  "CUFFT_INVALID_TYPE"  ,  extramsg); \
	 if(err==  CUFFT_INVALID_VALUE  )				\
	   sprintf(messaggio, "Error in file '%s' in line %i :%s -- %s \n", \
                   __FILE__, __LINE__, "CUFFT_INVALID_VALUE"   ,  extramsg); \
	 if(err==    CUFFT_INTERNAL_ERROR)				\
	   sprintf(messaggio, "Error in file '%s' in line %i :%s -- %s \n", \
                   __FILE__, __LINE__, "CUFFT_INTERNAL_ERROR"   ,  extramsg); \
	 if(err==  CUFFT_EXEC_FAILED )					\
	   sprintf(messaggio, "Error in file '%s' in line %i :%s -- %s \n", \
                   __FILE__, __LINE__, "CUFFT_EXEC_FAILED"     ,  extramsg); \
	 if(err==    CUFFT_SETUP_FAILED )				\
	   sprintf(messaggio, "Error in file '%s' in line %i :%s -- %s \n", \
                   __FILE__, __LINE__, "CUFFT_SETUP_FAILED"   ,  extramsg); \
	 if(err==  CUFFT_INVALID_SIZE)					\
	   sprintf(messaggio, "Error in file '%s' in line %i :%s -- %s \n", \
                   __FILE__, __LINE__, "CUFFT_INVALID_SIZE"   ,  extramsg); \
	 fprintf(stderr, messaggio );					\
	 goto fail;							\
       } } while (0); }

#define CUDA_SAFE_CALL_EXCEPTION(call, extramsg) {do {	\
       cudaError err = call;    \
       if( cudaSuccess != err) {   \
	   sprintf(messaggio, "Error in file '%s' in line %i :%s -- %s \n", \
                   __FILE__, __LINE__,  cudaGetErrorString( err) ,  extramsg); \
           fprintf(stderr, messaggio );     \
	   goto fail;			    \
       } } while (0); }


#define THROWMESSAGE(mes) {						\
    sprintf(messaggio, "Cuda error in file '%s' in line %i : %s.n  , %s \n", \
	    __FILE__, __LINE__,  mes);	\
    fprintf(stderr, messaggio );					\
    goto fail;								\
  }
// -----------------------------------------------------------------------------------------------

using namespace std; 

void callcufft(   int Ny, int Nx,
		  complex<float> *input,
		  complex<float> *output,
		  int direction)  {

  char messaggio[300];

  
  cufftComplex *devPtr=0;

  cufftHandle FFTplan, ifftp=0;
  

  
  CUDA_SAFE_CALL_EXCEPTION( cudaMalloc((void**)&devPtr, sizeof(cufftComplex)* Ny* Nx )
			    , "allocating memory for cufft on device");

  CUDA_SAFE_CALL_EXCEPTION( cudaMemcpy(devPtr  ,input  , 2*sizeof(float) * Ny*Nx , 
				       cudaMemcpyHostToDevice) ," copying data do device");
  
  
  CUFFT_SAFE_CALL_EXCEPTION( cufftPlan2d(&FFTplan, Ny , Nx , CUFFT_C2C ),"creating cufft plan" );
  ifftp=1;


  
  if(direction==1) {
    CUFFT_SAFE_CALL_EXCEPTION( cufftExecC2C(FFTplan, (cufftComplex *)devPtr , 
					    (cufftComplex *)devPtr , CUFFT_FORWARD), "  doing forward cufft" );
  } else if (direction==-1){
    CUFFT_SAFE_CALL_EXCEPTION( cufftExecC2C(FFTplan, (cufftComplex *)devPtr , 
					    (cufftComplex *)devPtr , CUFFT_INVERSE), "  doing inverse cufft" );
  } else {
    THROWMESSAGE(  " direction neither 1 nor -1   "  );
  }
  
  CUDA_SAFE_CALL_EXCEPTION( cudaMemcpy( output , devPtr  , 2*sizeof(float) * Ny*Nx , 
				       cudaMemcpyDeviceToHost) ," copying data from device");

  CUFFT_SAFE_CALL_EXCEPTION (cufftDestroy(FFTplan) , "destroying cufft plan" );
  CUDA_SAFE_CALL_EXCEPTION (cudaFree(devPtr), "destroying cufft plan" );
  return ;

fail :
  
  printf("Shutting down...\n");
  if(ifftp)  cufftDestroy(FFTplan)  ;
  if(devPtr) cudaFree(devPtr) ;

  throw messaggio ;

};

