// Demonstration that inverse real FFT is giving incorrect results. // // June 25, 2018 // HIP version: 1.5.18151 // rocfft version 0.8.1 // // Can be compiled with: // // hipcc -o rocfft_real_inverse rocfft_real_inverse.cpp -I/opt/rocmfft/include -L/opt/rocfft/lib -lrocfft // #include #include #include #include "rocfft/rocfft.h" #include #include // Parameters const int width = 12; // innermost const int height = 4; // Derived_parameters. const int N = width * height; const int hermitian_width = width/2 + 1; const int N_hermitian = hermitian_width * height; #define FFT_SAFE(x) { \ rocfft_status status = x; \ if ( status != rocfft_status_success ) { \ std::cerr << "Error " << status << std::endl; \ exit(-1); \ }} // ------------------------------------------------------------------------- void inverse_real_fft( float* in, float* out ) { // Create rocFFT plan rocfft_plan inverse_plan = nullptr; size_t length[2] = { width, height }; FFT_SAFE( rocfft_plan_create( &inverse_plan, rocfft_placement_notinplace, rocfft_transform_type_real_inverse, rocfft_precision_single, 2, length, 1, nullptr ) ); size_t device_workspace_size; rocfft_plan_get_work_buffer_size( inverse_plan, &device_workspace_size ); char* device_workspace = nullptr; rocfft_execution_info info = nullptr; hipMalloc(&device_workspace, device_workspace_size); rocfft_execution_info_create(&info); rocfft_execution_info_set_work_buffer(info, device_workspace, device_workspace_size); // Create HIP device buffer for K-space data (input to inverse FFT) float *d_in; hipMalloc( &d_in, 2*sizeof(float)*N_hermitian ); // Create HIP device buffer for real-space data (output to inverse FFT) float *d_out; hipMalloc( &d_out, sizeof(float)*N ); // Copy data to device hipMemcpy( d_in, in, 2*sizeof(float)*N_hermitian, hipMemcpyHostToDevice ); // Execute inverse plan FFT_SAFE( rocfft_execute( inverse_plan, (void**)&d_in, (void**)&d_out, info) ); // Wait for execution to finish hipDeviceSynchronize(); // Copy data back to host hipMemcpy( out, d_out, sizeof(float)*N, hipMemcpyDeviceToHost ); // Clean-up hipFree( device_workspace ); hipFree( d_out ); hipFree( d_in ); FFT_SAFE( rocfft_execution_info_destroy(info) ); FFT_SAFE( rocfft_plan_destroy(inverse_plan) ); } // ------------------------------------------------------------------------- void forward_real_fft( float* in, float* out ) { // Create rocFFT plan rocfft_plan forward_plan = nullptr; size_t length[2] = { width, height }; FFT_SAFE( rocfft_plan_create( &forward_plan, rocfft_placement_notinplace, rocfft_transform_type_real_forward, rocfft_precision_single, 2, length, 1, nullptr ) ); size_t device_workspace_size; rocfft_plan_get_work_buffer_size( forward_plan, &device_workspace_size ); char* device_workspace = nullptr; rocfft_execution_info info = nullptr; hipMalloc(&device_workspace, device_workspace_size); rocfft_execution_info_create(&info); rocfft_execution_info_set_work_buffer(info, device_workspace, device_workspace_size); // Create HIP device buffer for real-space data (input to forward FFT) float *d_in; hipMalloc( &d_in, sizeof(float)*N ); // Create HIP device buffer K-space data (output to forward FFT) float *d_out; hipMalloc( &d_out, 2*sizeof(float)*N_hermitian ); // Copy data to device hipMemcpy( d_in, in, sizeof(float)*N, hipMemcpyHostToDevice ); // Execute forward plan FFT_SAFE( rocfft_execute( forward_plan, (void**)&d_in, (void**)&d_out, info) ); // Wait for execution to finish hipDeviceSynchronize(); // Copy data back to host hipMemcpy( out, d_out, 2*sizeof(float)*N_hermitian, hipMemcpyDeviceToHost ); // Clean-up hipFree( device_workspace ); hipFree( d_out ); hipFree( d_in ); FFT_SAFE( rocfft_execution_info_destroy(info) ); FFT_SAFE( rocfft_plan_destroy(forward_plan) ); } // ------------------------------------------------------------------------- void inverse_complex_fft( float* in, float* out ) { // Create rocFFT plan rocfft_plan inverse_plan = nullptr; size_t length[2] = { width, height }; FFT_SAFE( rocfft_plan_create( &inverse_plan, rocfft_placement_notinplace, rocfft_transform_type_complex_inverse, rocfft_precision_single, 2, length, 1, nullptr ) ); size_t device_workspace_size; rocfft_plan_get_work_buffer_size( inverse_plan, &device_workspace_size ); char* device_workspace = nullptr; rocfft_execution_info info = nullptr; hipMalloc(&device_workspace, device_workspace_size); rocfft_execution_info_create(&info); rocfft_execution_info_set_work_buffer(info, device_workspace, device_workspace_size); // Create HIP device buffer for K-space data (input to inverse FFT) float *d_in; hipMalloc( &d_in, 2*sizeof(float)*N ); // Create HIP device buffer for real-space data (output to inverse FFT) float *d_out; hipMalloc( &d_out, 2*sizeof(float)*N ); // Copy data to device hipMemcpy( d_in, in, 2*sizeof(float)*N, hipMemcpyHostToDevice ); // Execute inverse plan FFT_SAFE( rocfft_execute( inverse_plan, (void**)&d_in, (void**)&d_out, info) ); // Wait for execution to finish hipDeviceSynchronize(); // Copy data to back to host hipMemcpy( out, d_out, 2*sizeof(float)*N, hipMemcpyDeviceToHost ); // Clean-up hipFree( device_workspace ); hipFree( d_out ); hipFree( d_in ); FFT_SAFE( rocfft_execution_info_destroy(info) ); FFT_SAFE( rocfft_plan_destroy(inverse_plan) ); } // ------------------------------------------------------------------------- // Utility function to print maximum amplitude (over both arrays), // and the maximum difference (amplitude) between the arrays. void compare_complex_to_real( float* c, float* r, int count ) { float max_amplitude = 0; float max_difference = 0; for ( int i=0; i