[
  {
    "path": "CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 2.6)\r\nenable_testing()\r\nproject(simple_fft)\r\n\r\nset(UNIT_TESTS simple_fft_unit_tests)\r\nset(BENCHMARK_TESTS simple_fft_benchmark_tests)\r\n\r\nset(HEADERS\r\n        include/simple_fft/fft.h\r\n        include/simple_fft/fft.hpp\r\n        include/simple_fft/fft_impl.hpp\r\n        include/simple_fft/fft_settings.h\r\n        include/simple_fft/check_fft.hpp\r\n        include/simple_fft/copy_array.hpp\r\n        include/simple_fft/error_handling.hpp\r\n   )\r\n\r\nset(HEADERS_UNIT_TESTS\r\n        ${HEADERS}\r\n        unit-tests/test_fft.h\r\n        unit-tests/test_fft.hpp\r\n    )\r\n    \r\nset(SOURCES_UNIT_TESTS\r\n        unit-tests/unit_tests_main.cpp\r\n        unit-tests/test_fft.cpp\r\n        unit-tests/test_with_std_vectors.cpp\r\n        unit-tests/test_with_native_cpp_pointer_based_arrays.cpp\r\n   )\r\n\r\nset(HEADERS_BENCHMARK_TESTS\r\n        ${HEADERS}\r\n        benchmark-tests/benchmark_tests_fftw3.h\r\n        unit-tests/test_fft.cpp\r\n    )\r\n\r\nset(SOURCES_BENCHMARK_TESTS\r\n        benchmark-tests/benchmark_tests_fftw3.cpp\r\n        benchmark-tests/benchmark_tests_main.cpp\r\n    )\r\n   \r\n# Boost section\r\nfind_package(Boost QUIET)\r\nif(Boost_FOUND)\r\n    message(STATUS \"Boost package was found\")\r\n    add_definitions(\"-DHAS_BOOST_PACKAGE\")\r\n    include_directories(SYSTEM \"${Boost_INCLUDE_DIRS} ${SYSTEM}\")\r\n    message(STATUS \"Checking for multi_array and ublas availability...\")\r\n\r\n    find_file(BOOST_MULTI_ARRAY_FILE boost/multi_array.hpp)\r\n    if(BOOST_MULTI_ARRAY_FILE)\r\n        message(STATUS \"boost::multi_array headers were found, building a test\")\r\n        add_definitions(\"-DHAS_BOOST_MULTI_ARRAY\")\r\n        set(SOURCES_UNIT_TESTS \"${SOURCES_UNIT_TESTS}\" unit-tests/test_with_boost_multiarray.cpp)\r\n    else()\r\n        message(STATUS \"boost::multi_array headers were not found, not building a test\")\r\n    endif()\r\n\r\n    find_file(BOOST_UBLAS_FILE boost/numeric/ublas/matrix.hpp)\r\n    if(BOOST_UBLAS_FILE)\r\n        message(STATUS \"boost::numeric::ublas headers were found, building a test\")\r\n        add_definitions(\"-DHAS_BOOST_UBLAS\")\r\n        set(SOURCES_UNIT_TESTS \"${SOURCES_UNIT_TESTS}\" unit-tests/test_with_boost_ublas_vector_matrix.cpp)\r\n    else()\r\n        message(STATUS \"boost::numeric::ublas headers were not found, not building a test\")\r\n    endif()\r\nelse()\r\n    message(STATUS \"Boost package was not found, not building tests with either \")\r\n    message(STATUS \"boost::multi_array or boost::numeric::ublas\")\r\nendif()\r\n\r\n# marray\r\nfind_path(MARRAY_DIR marray/marray.hxx)\r\nif(MARRAY_DIR)\r\n    include_directories(SYSTEM \"${MARRAY_DIR} ${SYSTEM}\")\r\n    message(STATUS \"marray header was found, building a test\")\r\n    add_definitions(\"-DHAS_MARRAY\")\r\n    set(SOURCES_UNIT_TESTS \"${SOURCES_UNIT_TESTS}\" unit-tests/test_with_marray.cpp)\r\nelse()\r\n    message(STATUS \"marray headers was not found, not building a test\")\r\nendif()\r\n\r\n# Eigen\r\nfind_file(EIGEN_FILE eigen3/Eigen/Eigen)\r\nif(EIGEN_FILE)\r\n    find_path(EIGEN_DIR eigen3/Eigen/Eigen)\r\n    if(EIGEN_DIR)\r\n        include_directories(SYSTEM \"${EIGEN_DIR} ${SYSTEM}\")\r\n        message(STATUS \"Eigen headers were found, building a test\")\r\n        add_definitions(\"-DHAS_EIGEN\")\r\n        set(SOURCES_UNIT_TESTS \"${SOURCES_UNIT_TESTS}\" unit-tests/test_with_eigen_vector_matrix.cpp)\r\n    else()\r\n        message(STATUS \"Eigen headers were not found, not building a test\")\r\n    endif()\r\nelse()\r\n    message(STATUS \"Eigen headers were not found, not building a test\")\r\nendif()\r\n\r\n# Armadillo\r\nfind_path(ARMADILLO_INCLUDEFILE_DIR armadillo)\r\nif(ARMADILLO_INCLUDEFILE_DIR)\r\n    include_directories(SYSTEM \"${ARMADILLO_INCLUDEFILE_DIR} ${SYSTEM}\")\r\n    message(STATUS \"Armadillo include file was found, looking for library...\")\r\n\r\n    find_library(ARMADILLO_LIB OPTIONAL\r\n                 NAMES\r\n                 libarmadillo.so armadillo.lib libarmadillo.dll\r\n                 )\r\n    if(ARMADILLO_LIB)\r\n        add_definitions(\"-DHAS_ARMADILLO\")\r\n        set(SOURCES_UNIT_TESTS \"${SOURCES_UNIT_TESTS}\" unit-tests/test_with_armadillo_matrix_and_row.cpp)\r\n        message(STATUS \"Armadillo library was found, building a test\")\r\n    else()\r\n        message(STATUS \"Armadillo library was not found, not building a test\")\r\n    endif()\r\nelse()\r\n    message(STATUS \"Armadillo include file was not found, not building a test\")\r\nendif()\r\n\r\n# Blitz++\r\nfind_file(BLITZ_FILE blitz/blitz.h)\r\nif(BLITZ_FILE)\r\n    find_path(BLITZ_DIR blitz/blitz.h)\r\n    if(BLITZ_DIR)\r\n        include_directories(SYSTEM \"${BLITZ_DIR} ${SYSTEM}\")\r\n        message(STATUS \"Blitz++ headers were found, building a test\")\r\n        add_definitions(\"-DHAS_BLITZ\")\r\n        set(SOURCES_UNIT_TESTS \"${SOURCES_UNIT_TESTS}\" unit-tests/test_with_blitz.cpp)\r\n    else()\r\n        message(STATUS \"Blitz++ headers were not found, not building a test\")\r\n    endif()\r\nelse()\r\n    message(STATUS \"Blitz++ headers were not found, not building a test\")\r\nendif()\r\n\r\n# STLSoft\r\nfind_file(STLSOFT_FILE stlsoft/containers/fixed_array.hpp)\r\nif(STLSOFT_FILE)\r\n    find_path(STLSOFT_DIR stlsoft/containers/fixed_array.hpp)\r\n    if(STLSOFT_DIR)\r\n        include_directories(SYSTEM \"${STLSOFT_DIR} ${SYSTEM}\")\r\n        message(STATUS \"STLSoft headers were found, building a test\")\r\n        add_definitions(\"-DHAS_STLSOFT\")\r\n        set(SOURCES_UNIT_TESTS \"${SOURCES_UNIT_TESTS}\" unit-tests/test_with_stlsoft.cpp)\r\n    else()\r\n        message(STATUS \"STLSoft headers were not found, not building a test\")\r\n    endif()\r\nelse()\r\n    message(STATUS \"STLSoft headers were not found, not building a test\")\r\nendif()\r\n\r\n# fftw library for benchmark test\r\nfind_path(FFTW_INCLUDEFILE_DIR NAMES fftw3.h fftw)\r\nif(FFTW_INCLUDEFILE_DIR)\r\n    find_file(FFTW_INCLUDEFILE_NO_H fftw)\r\n    if(FFTW_INCLUDEFILE_NO_H)\r\n        add_definitions(\"-D_FFTW_INCLUDEFILE_NO_H\")\r\n    endif()\r\n    include_directories(SYSTEM \"${FFTW_INCLUDEFILE_DIR} ${SYSTEM}\")\r\n    message(STATUS \"fftw include file was found, looking for library...\")\r\n\r\n    find_library(FFTW_LIB_OPENMP OPTIONAL\r\n                 NAMES\r\n                 libfftw3_omp.so\r\n                 )\r\n\r\n    find_library(FFTW_LIB OPTIONAL\r\n                 NAMES\r\n                 libfftw3.so libfftw-3.3.lib libfftw3-3.dll\r\n                 )\r\n    if(FFTW_LIB)\r\n        add_definitions(\"-DHAS_FFTW3\")\r\n        message(STATUS \"FFTW library was found, will build a benchmark test\")\r\n        if(FFTW_LIB_OPENMP)\r\n            message(STATUS \"OpenMP version of fftw3 was found and will be used\")\r\n        endif()\r\n    else()\r\n        message(STATUS \"FFTW library was not found, won't build a benchmark test\")\r\n    endif()\r\nelse()\r\n    message(STATUS \"FFTW include file was not found, won't build a benchmark test\")\r\nendif()\r\n\r\nadd_executable(${UNIT_TESTS} ${HEADERS_UNIT_TESTS} ${SOURCES_UNIT_TESTS})\r\nadd_executable(${BENCHMARK_TESTS} ${HEADERS_BENCHMARK_TESTS} ${SOURCES_BENCHMARK_TESTS})\r\n\r\nif(FFTW_LIB)\r\n    target_link_libraries(${BENCHMARK_TESTS} ${FFTW_LIB})\r\n    if(FFTW_LIB_OPENMP)\r\n        target_link_libraries(${BENCHMARK_TESTS} ${FFTW_LIB_OPENMP})\r\n    endif()\r\nendif()\r\n\r\nif(${CMAKE_CXX_COMPILER_ID} MATCHES \"Clang\")\r\n    if(${CMAKE_BUILD_TYPE} MATCHES \"Debug\")\r\n        set(CMAKE_CXX_FLAGS \"-Wno-unknown-pragmas -Wno-unused-parameter ${CMAKE_CXX_FLAGS}\")\r\n        set(CMAKE_CXX_FLAGS \"-Werror -Wextra -pedantic -pedantic-errors ${CMAKE_CXX_FLAGS}\")\r\n    else() # \"Release\"\r\n        set(CMAKE_CXX_FLAGS \"-mcmodel=medium -fstrict-aliasing -Wstrict-aliasing ${CMAKE_CXX_FLAGS}\")\r\n        set(CMAKE_CXX_FLAGS \"-O3 -fkeep-inline-functions -fno-stack-protector ${CMAKE_CXX_FLAGS}\")\r\n    endif()\r\nelse() # not clang\r\n    find_package(OpenMP QUIET)\r\n    if(OPENMP_FOUND)\r\n        message(STATUS \"OpenMP found.\")\r\n        set(CMAKE_C_FLAGS \"${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}\")\r\n        set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}\")\r\n        set(CMAKE_EXE_LINKER_FLAGS \"${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}\")\r\n        add_definitions(-D__USE_OPENMP)\r\n    else()\r\n        message(STATUS \"OpenMP not found, parallelization for FFT and tests will be disabled\")\r\n    endif() # OpenMP\r\n\r\n    if(${CMAKE_CXX_COMPILER_ID} STREQUAL \"GNU\")\r\n        set(CMAKE_CXX_FLAGS \"-fopenmp -lgomp -Wno-unused-parameter -fstrict-aliasing ${CMAKE_CXX_FLAGS}\")\r\n        if(${CMAKE_BUILD_TYPE} MATCHES \"Debug\")\r\n            set(CMAKE_CXX_FLAGS \"-Wall -Wextra -Wshadow -Werror -ansi -pedantic-errors ${CMAKE_CXX_FLAGS}\")\r\n            set(CMAKE_CXX_FLAGS \"-Wno-long-long -Wuninitialized -Wstrict-aliasing ${CMAKE_CXX_FLAGS}\")\r\n            set(CMAKE_CXX_FLAGS \"-Winit-self -Wno-missing-declarations -Woverloaded-virtual ${CMAKE_CXX_FLAGS}\")\r\n            set(CMAKE_CXX_FLAGS \"-Weffc++ -Wcast-align -Wcast-qual -Wpointer-arith ${CMAKE_CXX_FLAGS}\")\r\n            set(CMAKE_CXX_FLAGS \"-Wformat=2 -Wnon-virtual-dtor ${CMAKE_CXX_FLAGS}\")\r\n        else() # \"Release\"\r\n            set(CMAKE_CXX_FLAGS \"-O3 -march=native -mtune=native -ffast-math ${CMAKE_CXX_FLAGS}\")\r\n        endif()\r\n    elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL \"Intel\")\r\n        if(OPENMP_FOUND)\r\n            set(CMAKE_CXX_FLAGS \"-openmp -parallel ${CMAKE_CXX_FLAGS}\")\r\n            find_library(omp5_lib REQUIRED\r\n                         NAMES\r\n                         libiomp5.so\r\n                         )\r\n            set(LIBS ${LIBS} ${omp5_lib})\r\n            target_link_libraries(${UNIT_TESTS} ${omp5_lib})\r\n            target_link_libraries(${BENCHMARK_TESTS} ${omp5_lib})\r\n        endif() # OpenMP\r\n        if(${CMAKE_BUILD_TYPE} MATCHES \"Debug\")\r\n            set(CMAKE_CXX_FLAGS \"-debug -Wall -Werror -Winline -Wdeprecated -Wno-missing-prototypes ${CMAKE_CXX_FLAGS}\")\r\n            set(CMAKE_CXX_FLAGS \"-Wcomment -Wdeprecated -Wformat-security -Wmain -Wno-missing-declarations ${CMAKE_CXX_FLAGS}\")\r\n            set(CMAKE_CXX_FLAGS \"-Woverflow -Wpointer-arith -Woverloaded-virtual -Wpointer-arith ${CMAKE_CXX_FLAGS}\")\r\n            set(CMAKE_CXX_FLAGS \"-Wreturn-type -Wstrict-prototypes -Wtrigraphs -Wuninitialized ${CMAKE_CXX_FLAGS}\")\r\n            set(CMAKE_CXX_FLAGS \"-Wunknown-pragmas -Wno-unused-function -Wno-unused-variable ${CMAKE_CXX_FLAGS}\")\r\n        else() # \"Release\"\r\n            set(CMAKE_CXX_FLAGS \"-O3 -march=core-avx-i ${CMAKE_CXX_FLAGS}\")\r\n        endif()\r\n    elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL \"MSVC\" OR\r\n           ${CMAKE_CXX_COMPILER_ID} STREQUAL \"MSVC10\" OR\r\n           ${CMAKE_CXX_COMPILER_ID} STREQUAL \"MSVC80\" OR\r\n           ${CMAKE_CXX_COMPILER_ID} STREQUAL \"MSVC90\")\r\n        set(CMAKE_CXX_FLAGS \"/D_SCL_SECURE_NO_WARNINGS /D_CRT_SECURE_NO_WARNINGS ${CMAKE_CXX_FLAGS}\")\r\n        set(CMAKE_CXX_FLAGS \"/wd4100 /wd4503 ${CMAKE_CXX_FLAGS}\")\r\n        if(OPENMP_FOUND)\r\n            set(CMAKE_CXX_FLAGS \"/openmp ${CMAKE_CXX_FLAGS}\")\r\n        endif()\r\n    else()\r\n        message(FATAL_ERROR \"Unsupported tool chain.\")\r\n    endif()\r\nendif()\r\n"
  },
  {
    "path": "LICENSE.md",
    "content": "Copyright (c) 2013-2020 Dmitry Ivanov\n\nThe MIT License (MIT)\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "Simple-FFT\n==========\n\n**Header-only C++ library implementing fast Fourier transform of 1D, 2D and 3D data.**\n\n### What's this\n\nSimple FFT is a C++ library implementing fast Fourier transform. The implemented FFT is a radix-2 Cooley-Turkey algorithm. This algorithm can't handle transform of data which size is not a power of 2. It is not the most optimal known FFT algorithm.\n\nThe library is header-only, you don't need to build anything, just include the files in your project. The user-level interface is simple and reminds the one typically found in mathematical software.\n\nThe library is distributed under MIT license\n\n#### Why one more FFT library? Does it have any benefits compared to existing libraries?\n\nWhy do humans create things even though they already have something similar? Because they are not satisfied with what they have. So was my impression with existing libraries implementing fast Fourier transforms. My desires were:\n * Free & open-source library\n * License allowing to use the library in both open and closed-source software.\n * Convenient API somewhat similar to the one found in typical mathematical software.\n * Limited size and dependencies, ideally no dependencies (handy for multiple supported platforms and compilers).\n * As long as my arrays are not going to be huge, I don't need the fastest FFT in the galaxy, I'd be quite happy with some algorithm getting the job done.\n * Having said that my arrays are not too large, I still want minimal or no overhead for copying the data to objects of types used in the library.\n\nThe last statement deserves some explanation: many popular libraries performing FFT use their own data types, sometimes even their own containers. If you already have the data of your own type/container, you are going to either manually transform (e.g. copy) the data or try to cast pointers. Both ways are not elegant.\n\nI didn't find the solution corresponding to the whole wishlist of mine. So I decided to create my own simple library. I've already mentioned some of disadvantages of such approach:\n * Not the fastest algorithm known nowadays.\n * Can't handle data which size is not a power of 2.\n\nThe advantages of Simple FFT behind some well-known and widely used libraries are:\n * Tiny size - just some header files.\n * No need to build it and link a library to your project.\n * Can handle 1D, 2D and 3D arrays, extendable for larger dimensions.\n * Designed to support any _reasonable_ multidimensional array/container type one can imagine.\n\nAgain, the last statement needs some details to be revealed: C++ natively supports multidimensional arrays via pointers and also via \"std vector of std vectors\" approach. However, there are a lot of libraries with their own implementations of multidimensional arrays. I wanted to create a library which in theory can use _any_ type of multidimensional array without data copying or pointer casting. It is not possible to guarantee that my library will work with every multidimensional array type you can imagine but there is only a limited number of restrictions for used types.\n\n#### How the API is convenient? How to actually use the library?\n\nBy convenience of API I mean the interface somewhat similar to that found in mathematical software like Mathcad, Matlab, Octave, Scilab etc. The simplest API you can think of is something like `A = FFT(B)`. It is not very easy to efficiently implement in C++ (well, without move semantic of C++11 at least) because with such interface you are going to return the result of B transform by value which means data copying i.e. overhead (unless return by value optimization is employed). So in C++ it is better to return the result by reference. The function can also return boolean which would indicate whether the transform was successful or not. So the simplest interface would look like\n\n```c++\n b = FFT(A,B); // FFT from A to B\n```\n\nBut FFT algorithm requires the knowledge of shape and dimensionality of used arrays. Most multidimensional array implementations can provide this information but they do it in different ways and I wanted something very generic. So I decided to create functions with the same name but different signature depending on the number of dimensions:\n\n```c++\n b = FFT(A,B,n); // FFT from A to B where A and B are 1D arrays with n elements\n b = FFT(A,B,n,m); // FFT from A to B where A and B are matrices (2D arrays) with n rows and m columns\n b = FFT(A,B,n,m,l); // FFT from A to B where A and B are 3D arrays with n rows, m columns and l depth number;\n```\n\nOne more thing: if the returned value is false then some error has happened. In order to protect user from debugging into 3rdparty library to figure out what happened I decided to return error description as C-style string (because some people don't use `std::string`). So the interface became looking like this:\n\n```c++\n const char * error = NULL; // error description\n b = FFT(A,B,n,error); // FFT from A to B where A and B are 1D arrays with n elements\n b = FFT(A,B,n,m,error); // FFT from A to B where A and B are matrices (2D arrays) with n rows and m columns\n b = FFT(A,B,n,m,l,error); // FFT from A to B where A and B are 3D arrays with n rows, m columns and l depth number;\n```\n\nBut how about the inverse transform? The flag can be used to tell the forward transform from inverse but I thought that different function names would be easier: FFT for forward transform and IFFT for inverse transform:\n\n```c++\n const char * error = NULL; // error description\n b = FFT(A,B,n,error); // forward FFT from A to B where A and B are 1D arrays with n elements\n b = FFT(A,B,n,m,error); // forward FFT from A to B where A and B are matrices (2D arrays) with n rows and m columns\n b = FFT(A,B,n,m,l,error); // forward FFT from A to B where A and B are 3D arrays with n rows, m columns and l depth number;\n b = IFFT(B,A,n,error); // inverse FFT from B to A where A and B are 1D arrays with n elements\n b = IFFT(B,A,n,m,error); // inverse FFT from B to A where A and B are matrices (2D arrays) with n rows and m columns\n b = IFFT(B,A,n,m,l,error); // inverse FFT from B to A where A and B are 3D arrays with n rows, m columns and l depth number;\n```\n\nBeyond that there are only two settings:\n* User needs to define two types called `real_type` and `complex_type`. These are needed by design to avoid extra problems with template instantiation\n* User needs to define macro `__USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR` if the multidimensional array type you want to use accesses elements via `operator[]` (for example, if it is native C++ multidimensional array or `boost::multi_array` or something similar). Otherwise the library will attempt to use `operator()` for element access.\n\nThat's the whole explanation of API.\n\n#### How does it work with multiple libraries implementing matrices and multidimensional arrays in C++ without being aware of those?\n\nWell, the common generic technique of C++ was used - templates. I also added two `typedef`ed types (`real_type` and `complex_type`) to avoid overcomplication of code. But it's not all about templates - I also tried to implement the most generic element access I could imagine. After a bit of thinking I realized that in terms of interface different libraries implementing multidimensional arrays commonly differ only by their element access operator - some implementations use `operator[]` and others - `operator()`. So I splitted every code section using element access operator into two code blocks - the one with `operator[]` and the one with `operator()`. The switch between them is controlled by macro `__USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR` - if it's defined, `operator[]` is used, if not - `operator()`. User can define this macro in some translation units and not define/undef in other ones - just like I did with unit-tests.\n\n#### Are there any examples or, even better, tests?\nI wrote some tests illustrating how to use SimpleFFT library along with some well-known C++ libraries implementing multidimensional arrays. They can also serve as examples (probably, a bit overcomplicated). The tests are based on the following checks:\n* after each forward of inverse FFT [Parseval's theorem](https://en.wikipedia.org/wiki/Parseval%27s_theorem) must be satisfied for input and output data\n* after each sequence of FFT and IFFT the energy conservation law must be satisfied\n* after each sequence of FFT and IFFT the result should be the very same as initial input; so I decided to measure the largest discrepancy between the result and input and calculate the relative error there. If it is small enough (less than 0.01%), this test is considered passed.\n\nI also implemented a simple benchmark test comparing the execution time of multiple loops of Simple FFT and fftw3. The results for Linux with three compilers can be found in the \"benchmark-tests\" folder. As expected, fftw3 is much faster.\n\n#### There are multiple files here, which I should use?\nThere are only two files of interest for library user:\n* `/include/simple_fft/fft_settings.h`\n* `/include/simple_fft/fft.h`\n\nThe first one is supposed to contain `typedef`s for `real_type` and `complex_type` and, if needed, the define of `__USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR` macro. This stuff can also be done somewhere else. The second file is what's actually needed to calculate FFT and IFFT: it contains only API declarations and includes some of other files.\n"
  },
  {
    "path": "benchmark-tests/benchmark_tests_fftw3.cpp",
    "content": "#include \"../include/simple_fft/fft_settings.h\"\r\n\r\n#ifndef __USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR\r\n#define __USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR\r\n#endif\r\n\r\n#include \"benchmark_tests_fftw3.h\"\r\n#include \"../unit-tests/test_fft.hpp\"\r\n#include <vector>\r\n#include <complex>\r\n#include <ctime>\r\n#include <iostream>\r\n#include <iomanip>\r\n#include <fftw3.h>\r\n\r\nnamespace simple_fft {\r\nnamespace fft_test {\r\n\r\nbool BenchmarkTestAgainstFFTW3()\r\n{\r\n    bool res;\r\n    const char * err_str = NULL;\r\n    const int numFFTLoops1D = 10000;\r\n    const int numFFTLoops2D = 500;\r\n    const int numFFTLoops3D = 15;\r\n\r\n    using namespace pulse_params;\r\n\r\n    std::vector<real_type> t, x, y;\r\n    makeGridsForPulse3D(t, x, y);\r\n\r\n    // typedefing vectors\r\n    typedef std::vector<real_type> RealArray1D;\r\n    typedef std::vector<complex_type> ComplexArray1D;\r\n    typedef std::vector<std::vector<real_type> > RealArray2D;\r\n    typedef std::vector<std::vector<complex_type> > ComplexArray2D;\r\n    typedef std::vector<std::vector<std::vector<real_type> > > RealArray3D;\r\n    typedef std::vector<std::vector<std::vector<complex_type> > > ComplexArray3D;\r\n\r\n    // 1D fields and spectrum\r\n    RealArray1D E1_real(nt);\r\n    ComplexArray1D E1_complex(nt), G1(nt);\r\n\r\n    // 2D fields and spectrum\r\n    RealArray2D E2_real(nt);\r\n    ComplexArray2D E2_complex(nt), G2(nt);\r\n\r\n    int grid_size_t = static_cast<int>(nt);\r\n\r\n#ifndef __clang__\r\n#ifdef __USE_OPENMP\r\n#pragma omp parallel for\r\n#endif\r\n#endif\r\n    for(int i = 0; i < grid_size_t; ++i) {\r\n        E2_real[i].resize(nx);\r\n        E2_complex[i].resize(nx);\r\n        G2[i].resize(nx);\r\n    }\r\n\r\n    // 3D fields and spectrum\r\n    RealArray3D E3_real(nt);\r\n    ComplexArray3D E3_complex(nt), G3(nt);\r\n\r\n    int grid_size_x = static_cast<int>(nx);\r\n\r\n#ifndef __clang__\r\n#ifdef __USE_OPENMP\r\n#pragma omp parallel for\r\n#endif\r\n#endif\r\n    for(int i = 0; i < grid_size_t; ++i) {\r\n        E3_real[i].resize(nx);\r\n        E3_complex[i].resize(nx);\r\n        G3[i].resize(nx);\r\n        for(int j = 0; j < grid_size_x; ++j) {\r\n            E3_real[i][j].resize(ny);\r\n            E3_complex[i][j].resize(ny);\r\n            G3[i][j].resize(ny);\r\n        }\r\n    }\r\n\r\n    CMakeInitialPulses3D<RealArray1D,RealArray2D,RealArray3D,true>::makeInitialPulses(E1_real, E2_real, E3_real);\r\n    CMakeInitialPulses3D<ComplexArray1D,ComplexArray2D,ComplexArray3D,false>::makeInitialPulses(E1_complex, E2_complex, E3_complex);\r\n\r\n    // Measure the execution time of Simple FFT\r\n    // 1) 1D Simple FFT for real data\r\n    clock_t beginTime = clock();\r\n    for(int i = 0; i < numFFTLoops1D; ++i) {\r\n        res = FFT(E1_real, G1, nt, err_str);\r\n        if (!res) {\r\n            std::cout << \"Simple FFT 1D real failed: \" << err_str << std::endl;\r\n            return false;\r\n        }\r\n    }\r\n    std::cout << \"Simple 1D FFT for real data: execution time for \"\r\n              << numFFTLoops1D << \" loops: \" << std::setprecision(20)\r\n              << real_type(clock() - beginTime)/CLOCKS_PER_SEC << std::endl;\r\n    // 2) 1D Simple FFT for complex data\r\n    beginTime = clock();\r\n    for(int i = 0; i < numFFTLoops1D; ++i) {\r\n        res = FFT(E1_complex, G1, nt, err_str);\r\n        if (!res) {\r\n            std::cout << \"Simple FFT 1D complex failed: \" << err_str << std::endl;\r\n            return false;\r\n        }\r\n    }\r\n    std::cout << \"Simple 1D FFT for complex data: execution time for \"\r\n              << numFFTLoops1D << \" loops: \" << std::setprecision(20)\r\n              << real_type(clock() - beginTime)/CLOCKS_PER_SEC << std::endl;\r\n    // 3) 2D Simple FFT for real data\r\n    beginTime = clock();\r\n    for(int i = 0; i < numFFTLoops2D; ++i) {\r\n        res = FFT(E2_real, G2, nt, nx, err_str);\r\n        if (!res) {\r\n            std::cout << \"Simple FFT 2D real failed: \" << err_str << std::endl;\r\n            return false;\r\n        }\r\n    }\r\n    std::cout << \"Simple 2D FFT for real data: execution time for \"\r\n              << numFFTLoops2D << \" loops: \" << std::setprecision(20)\r\n              << real_type(clock() - beginTime)/CLOCKS_PER_SEC << std::endl;\r\n    // 4) 2D Simple FFT for complex data\r\n    beginTime = clock();\r\n    for(int i = 0; i < numFFTLoops2D; ++i) {\r\n        res = FFT(E2_complex, G2, nt, nx, err_str);\r\n        if (!res) {\r\n            std::cout << \"Simple FFT 2D complex failed: \" << err_str << std::endl;\r\n            return false;\r\n        }\r\n    }\r\n    std::cout << \"Simple 2D FFT for complex data: execution time for \"\r\n              << numFFTLoops2D << \" loops: \" << std::setprecision(20)\r\n              << real_type(clock() - beginTime)/CLOCKS_PER_SEC << std::endl;\r\n    // 5) 3D Simple FFT for real data\r\n    beginTime = clock();\r\n    for(int i = 0; i < numFFTLoops3D; ++i) {\r\n        res = FFT(E3_real, G3, nt, nx, ny, err_str);\r\n        if (!res) {\r\n            std::cout << \"Simple FFT 3D real failed: \" << err_str << std::endl;\r\n            return false;\r\n        }\r\n    }\r\n    std::cout << \"Simple 3D FFT for real data: execution time for \"\r\n              << numFFTLoops3D << \" loops: \" << std::setprecision(20)\r\n              << real_type(clock() - beginTime)/CLOCKS_PER_SEC << std::endl;\r\n    // 6) 3D Simple FFT for complex data\r\n    beginTime = clock();\r\n    for(int i = 0; i < numFFTLoops3D; ++i) {\r\n        res = FFT(E3_complex, G3, nt, nx, ny, err_str);\r\n        if (!res) {\r\n            std::cout << \"Simple FFT 3D complex failed: \" << err_str << std::endl;\r\n            return false;\r\n        }\r\n    }\r\n    std::cout << \"Simple 3D FFT for complex data: execution time for \"\r\n              << numFFTLoops3D << \" loops: \" << std::setprecision(20)\r\n              << real_type(clock() - beginTime)/CLOCKS_PER_SEC << std::endl;\r\n\r\n\r\n    // Measure the execution time for FFTW3\r\n    // 1) FFTW 1D for real data\r\n    fftw_plan fftwPlan = fftw_plan_dft_r2c_1d(nt, &E1_real[0],\r\n                                              reinterpret_cast<fftw_complex*>(&G1[0]),\r\n                                              FFTW_MEASURE);\r\n    beginTime = clock();\r\n    for(int i = 0; i < numFFTLoops1D; ++i) {\r\n        fftw_execute(fftwPlan);\r\n    }\r\n    std::cout << \"FFTW3 1D FFT for real data: execution time for \"\r\n              << numFFTLoops1D << \" loops: \" << std::setprecision(20)\r\n              << real_type(clock() - beginTime)/CLOCKS_PER_SEC << std::endl;\r\n    fftw_destroy_plan(fftwPlan);\r\n    // 2) FFTW 1D for complex data\r\n    fftwPlan = fftw_plan_dft_1d(nt, reinterpret_cast<fftw_complex*>(&E1_complex[0]),\r\n                                reinterpret_cast<fftw_complex*>(&G1[0]),\r\n                                FFTW_FORWARD, FFTW_MEASURE);\r\n    beginTime = clock();\r\n    for(int i = 0; i < numFFTLoops1D; ++i) {\r\n        fftw_execute(fftwPlan);\r\n    }\r\n    std::cout << \"FFTW3 1D FFT for complex data: execution time for \"\r\n              << numFFTLoops1D << \" loops: \" << std::setprecision(20)\r\n              << real_type(clock() - beginTime)/CLOCKS_PER_SEC << std::endl;\r\n    fftw_destroy_plan(fftwPlan);\r\n    // 3) FFTW 2D for real data\r\n    // NOTE: I can't pass my data to FFTW in its original form, it causes runtime errors,\r\n    //       so I'm allocating another buffer array and copying my data twice -\r\n    //       before and after the FFT. And yes, I'm including the time it takes\r\n    //       into the measurement because I'm measuring the time to get the job done,\r\n    //       not the time of some function being running.\r\n    beginTime = clock();\r\n    real_type*    twoDimRealArray = (real_type*)(fftw_malloc(nt*nx*sizeof(real_type)));\r\n    fftw_complex* twoDimComplexArray = (fftw_complex*)(fftw_malloc(nt*nx*sizeof(fftw_complex)));\r\n    for(size_t i = 0; i < nt; ++i) {\r\n        for(size_t j = 0; j < nx; ++j) {\r\n            *(twoDimRealArray + i * nx + j) = E2_real[i][j];\r\n        }\r\n    }\r\n    fftwPlan = fftw_plan_dft_r2c_2d(nt, nx, twoDimRealArray, twoDimComplexArray,\r\n                                    FFTW_MEASURE);\r\n    for(int i = 0; i < numFFTLoops2D; ++i) {\r\n        fftw_execute(fftwPlan);\r\n    }\r\n    for(size_t i = 0; i < nt; ++i) {\r\n        for(size_t j = 0; j < nx; ++j) {\r\n            G2[i][j] = complex_type((*(twoDimComplexArray + i*nx + j))[0],\r\n                                    (*(twoDimComplexArray + i*nx + j))[1]);\r\n        }\r\n    }\r\n    std::cout << \"FFTW 2D FFT for real data: execution time for \"\r\n              << numFFTLoops2D << \" loops: \" << std::setprecision(20)\r\n              << real_type(clock() - beginTime)/CLOCKS_PER_SEC << std::endl;\r\n    fftw_destroy_plan(fftwPlan);\r\n    // 4) FFTW 2D for complex data\r\n    beginTime = clock();\r\n    twoDimComplexArray = (fftw_complex*)(fftw_malloc(nt*nx*sizeof(fftw_complex)));\r\n    fftw_complex* twoDimComplexArraySpectrum = (fftw_complex*)(fftw_malloc(nt*nx*sizeof(fftw_complex)));\r\n    for(size_t i = 0; i < nt; ++i) {\r\n        for(size_t j = 0; j < nx; ++j) {\r\n            *(twoDimComplexArray + i * nx + j)[0] = std::real(E2_complex[i][j]);\r\n            *(twoDimComplexArray + i * nx + j)[1] = std::imag(E2_complex[i][j]);\r\n        }\r\n    }\r\n    fftwPlan = fftw_plan_dft_2d(nt, nx, twoDimComplexArray, twoDimComplexArraySpectrum,\r\n                                FFTW_FORWARD, FFTW_MEASURE);\r\n    for(int i = 0; i < numFFTLoops2D; ++i) {\r\n        fftw_execute(fftwPlan);\r\n    }\r\n    for(size_t i = 0; i < nt; ++i) {\r\n        for(size_t j = 0; j < nx; ++j) {\r\n            G2[i][j] = complex_type((*(twoDimComplexArraySpectrum + i*nx + j))[0],\r\n                                    (*(twoDimComplexArraySpectrum + i*nx + j))[1]);\r\n        }\r\n    }\r\n    std::cout << \"FFTW 2D FFT for complex data: execution time for \"\r\n              << numFFTLoops2D << \" loops: \" << std::setprecision(20)\r\n              << real_type(clock() - beginTime)/CLOCKS_PER_SEC << std::endl;\r\n    fftw_destroy_plan(fftwPlan);\r\n    // 5) FFTW 3D for real data\r\n    beginTime = clock();\r\n    real_type*    threeDimRealArray = (real_type*)(fftw_malloc(nt*nx*ny*sizeof(real_type)));\r\n    fftw_complex* threeDimComplexArray = (fftw_complex*)(fftw_malloc(nt*nx*ny*sizeof(fftw_complex)));\r\n    for(size_t i = 0; i < nt; ++i) {\r\n        for(size_t j = 0; j < nx; ++j) {\r\n            for(size_t k = 0; k < ny; ++k) {\r\n                *(threeDimRealArray + i * nx * ny + j * ny + k) = E3_real[i][j][k];\r\n            }\r\n        }\r\n    }\r\n    fftwPlan = fftw_plan_dft_r2c_3d(nt, nx, ny, threeDimRealArray, threeDimComplexArray,\r\n                                    FFTW_MEASURE);\r\n    for(int i = 0; i < numFFTLoops3D; ++i) {\r\n        fftw_execute(fftwPlan);\r\n    }\r\n    for(size_t i = 0; i < nt; ++i) {\r\n        for(size_t j = 0; j < nx; ++j) {\r\n            for(size_t k = 0; k < ny; ++k) {\r\n                E3_real[i][j][k] = *(threeDimRealArray + i * nx * ny + j * ny + k);\r\n                G3[i][j][k] = complex_type((*(threeDimComplexArray + i * nx * ny + j * ny + k))[0],\r\n                                           (*(threeDimComplexArray + i * nx * ny + j * ny + k))[1]);\r\n            }\r\n        }\r\n    }\r\n    std::cout << \"FFTW 3D FFT for real data: execution time for \"\r\n              << numFFTLoops3D << \" loops: \" << std::setprecision(20)\r\n              << real_type(clock() - beginTime)/CLOCKS_PER_SEC << std::endl;\r\n    fftw_destroy_plan(fftwPlan);\r\n    // 6) FFTW 3D for complex data\r\n    beginTime = clock();\r\n    threeDimComplexArray = (fftw_complex*)(fftw_malloc(nt*nx*ny*sizeof(fftw_complex)));\r\n    fftw_complex* threeDimComplexArraySpectrum = (fftw_complex*)(fftw_malloc(nt*nx*ny*sizeof(fftw_complex)));\r\n    for(size_t i = 0; i < nt; ++i) {\r\n        for(size_t j = 0; j < nx; ++j) {\r\n            for(size_t k = 0; k < ny; ++k) {\r\n                *(threeDimComplexArray + i * nx * ny + j * ny + k)[0] = std::real(E3_complex[i][j][k]);\r\n                *(threeDimComplexArray + i * nx * ny + j * ny + k)[1] = std::imag(E3_complex[i][j][k]);\r\n            }\r\n        }\r\n    }\r\n    fftwPlan = fftw_plan_dft_3d(nt, nx, ny, threeDimComplexArray, threeDimComplexArraySpectrum,\r\n                                FFTW_FORWARD, FFTW_MEASURE);\r\n    for(int i = 0; i < numFFTLoops3D; ++i) {\r\n        fftw_execute(fftwPlan);\r\n    }\r\n    for(size_t i = 0; i < nt; ++i) {\r\n        for(size_t j = 0; j < nx; ++j) {\r\n            for(size_t k = 0; k < ny; ++k) {\r\n                G3[i][j][k] = complex_type((*(threeDimComplexArraySpectrum + i * nx * ny + j * ny + k))[0],\r\n                                           (*(threeDimComplexArraySpectrum + i * nx * ny + j * ny + k))[1]);\r\n            }\r\n        }\r\n    }\r\n    std::cout << \"FFTW 3D FFT for complex data: execution time for \"\r\n              << numFFTLoops3D << \" loops: \" << std::setprecision(20)\r\n              << real_type(clock() - beginTime)/CLOCKS_PER_SEC << std::endl;\r\n    fftw_destroy_plan(fftwPlan);\r\n\r\n    return true;\r\n\r\n}\r\n\r\n} // namespace fft_test\r\n} // namespace simple_fft\r\n"
  },
  {
    "path": "benchmark-tests/benchmark_tests_fftw3.h",
    "content": "#ifndef __SIMPLE_FFT__BENCHMARK_TESTS_FFTW3_H\r\n#define __SIMPLE_FFT__BENCHMARK_TESTS_FFTW3_H\r\n\r\nnamespace simple_fft {\r\nnamespace fft_test {\r\n\r\nbool BenchmarkTestAgainstFFTW3();\r\n\r\n}\r\n}\r\n\r\n#endif // __SIMPLE_FFT__BENCHMARK_TESTS_FFTW3_H\r\n"
  },
  {
    "path": "benchmark-tests/benchmark_tests_main.cpp",
    "content": "#include \"benchmark_tests_fftw3.h\"\r\n\r\nint main()\r\n{\r\n    using namespace simple_fft;\r\n    using namespace fft_test;\r\n\r\n#ifdef HAS_FFTW3\r\n    if(!BenchmarkTestAgainstFFTW3()) {\r\n        return false;\r\n    }\r\n#endif\r\n\r\n    return 0;\r\n}\r\n"
  },
  {
    "path": "benchmark-tests/results_Linux_Mint_14_x86_64_Intel_Core_i5_10_Gb_RAM/benchmark_test_multiple_transforms_GCC_release.txt",
    "content": "FFT test: creating real 1D pulse.\nDone.\nFFT test: creating real 2D pulse.\nDone.\nFFT test: creating real 3D pulse.\nDone.\nFFT test: creating real 1D pulse.\nDone.\nFFT test: creating real 2D pulse.\nDone.\nFFT test: creating real 3D pulse.\nDone.\nSimple 1D FFT for real data: execution time for 10000 loops: 0.16999999999999998446\nSimple 1D FFT for complex data: execution time for 10000 loops: 0.22000000000000000111\nSimple 2D FFT for real data: execution time for 500 loops: 3.1199999999999996625\nSimple 2D FFT for complex data: execution time for 500 loops: 2.8699999999999996625\nSimple 3D FFT for real data: execution time for 15 loops: 11.509999999999999787\nSimple 3D FFT for complex data: execution time for 15 loops: 10.779999999999999361\nFFTW3 1D FFT for real data: execution time for 10000 loops: 0.010000000000000000208\nFFTW3 1D FFT for complex data: execution time for 10000 loops: 0\nFFTW 2D FFT for real data: execution time for 500 loops: 0.040000000000000000833\nFFTW 2D FFT for complex data: execution time for 500 loops: 0.080000000000000001665\nFFTW 3D FFT for real data: execution time for 15 loops: 0.48999999999999999112\nFFTW 3D FFT for complex data: execution time for 15 loops: 0.96999999999999997335\n"
  },
  {
    "path": "benchmark-tests/results_Linux_Mint_14_x86_64_Intel_Core_i5_10_Gb_RAM/benchmark_test_multiple_transforms_ICC_release.txt",
    "content": "FFT test: creating real 1D pulse.\nDone.\nFFT test: creating real 2D pulse.\nDone.\nFFT test: creating real 3D pulse.\nDone.\nFFT test: creating real 1D pulse.\nDone.\nFFT test: creating real 2D pulse.\nDone.\nFFT test: creating real 3D pulse.\nDone.\nSimple 1D FFT for real data: execution time for 10000 loops: 0.20999999999999999223\nSimple 1D FFT for complex data: execution time for 10000 loops: 0.14999999999999999445\nSimple 2D FFT for real data: execution time for 500 loops: 2.6400000000000001243\nSimple 2D FFT for complex data: execution time for 500 loops: 2.7999999999999998224\nSimple 3D FFT for real data: execution time for 15 loops: 10.359999999999999432\nSimple 3D FFT for complex data: execution time for 15 loops: 10.419999999999999929\nFFTW3 1D FFT for real data: execution time for 10000 loops: 0\nFFTW3 1D FFT for complex data: execution time for 10000 loops: 0.010000000000000000208\nFFTW 2D FFT for real data: execution time for 500 loops: 0.26000000000000000888\nFFTW 2D FFT for complex data: execution time for 500 loops: 0.46000000000000001998\nFFTW 3D FFT for real data: execution time for 15 loops: 0.56999999999999995115\nFFTW 3D FFT for complex data: execution time for 15 loops: 0.95999999999999996447\n"
  },
  {
    "path": "benchmark-tests/results_Linux_Mint_14_x86_64_Intel_Core_i5_10_Gb_RAM/benchmark_test_multiple_transforms_clang_release.txt",
    "content": "FFT test: creating real 1D pulse.\nDone.\nFFT test: creating real 2D pulse.\nDone.\nFFT test: creating real 3D pulse.\nDone.\nFFT test: creating real 1D pulse.\nDone.\nFFT test: creating real 2D pulse.\nDone.\nFFT test: creating real 3D pulse.\nDone.\nSimple 1D FFT for real data: execution time for 10000 loops: 0.020000000000000000416\nSimple 1D FFT for complex data: execution time for 10000 loops: 0.02999999999999999889\nSimple 2D FFT for real data: execution time for 500 loops: 0.46000000000000001998\nSimple 2D FFT for complex data: execution time for 500 loops: 0.46999999999999997335\nSimple 3D FFT for real data: execution time for 15 loops: 1.7299999999999999822\nSimple 3D FFT for complex data: execution time for 15 loops: 1.7399999999999999911\nFFTW3 1D FFT for real data: execution time for 10000 loops: 0.010000000000000000208\nFFTW3 1D FFT for complex data: execution time for 10000 loops: 0\nFFTW 2D FFT for real data: execution time for 500 loops: 0.040000000000000000833\nFFTW 2D FFT for complex data: execution time for 500 loops: 0.080000000000000001665\nFFTW 3D FFT for real data: execution time for 15 loops: 0.48999999999999999112\nFFTW 3D FFT for complex data: execution time for 15 loops: 0.98999999999999999112\n"
  },
  {
    "path": "benchmark-tests/results_Linux_Mint_14_x86_64_Intel_Core_i5_10_Gb_RAM/benchmark_test_single_transform_GCC_release.txt",
    "content": "FFT test: creating real 1D pulse.\nDone.\nFFT test: creating real 2D pulse.\nDone.\nFFT test: creating real 3D pulse.\nDone.\nFFT test: creating real 1D pulse.\nDone.\nFFT test: creating real 2D pulse.\nDone.\nFFT test: creating real 3D pulse.\nDone.\nSimple 1D FFT for real data: execution time for 1 loops: 0\nSimple 1D FFT for complex data: execution time for 1 loops: 0\nSimple 2D FFT for real data: execution time for 1 loops: 0.010000000000000000208\nSimple 2D FFT for complex data: execution time for 1 loops: 0.020000000000000000416\nSimple 3D FFT for real data: execution time for 1 loops: 0.71999999999999997335\nSimple 3D FFT for complex data: execution time for 1 loops: 0.65999999999999992006\nFFTW3 1D FFT for real data: execution time for 1 loops: 0\nFFTW3 1D FFT for complex data: execution time for 1 loops: 0\nFFTW 2D FFT for real data: execution time for 1 loops: 0.010000000000000000208\nFFTW 2D FFT for complex data: execution time for 1 loops: 0.02999999999999999889\nFFTW 3D FFT for real data: execution time for 1 loops: 0.35999999999999998668\nFFTW 3D FFT for complex data: execution time for 1 loops: 0.71999999999999997335\n"
  },
  {
    "path": "benchmark-tests/results_Linux_Mint_14_x86_64_Intel_Core_i5_10_Gb_RAM/benchmark_test_single_transform_ICC_release.txt",
    "content": "FFT test: creating real 1D pulse.\nDone.\nFFT test: creating real 2D pulse.\nDone.\nFFT test: creating real 3D pulse.\nDone.\nFFT test: creating real 1D pulse.\nDone.\nFFT test: creating real 2D pulse.\nDone.\nFFT test: creating real 3D pulse.\nDone.\nSimple 1D FFT for real data: execution time for 1 loops: 0\nSimple 1D FFT for complex data: execution time for 1 loops: 0\nSimple 2D FFT for real data: execution time for 1 loops: 0.010000000000000000208\nSimple 2D FFT for complex data: execution time for 1 loops: 0\nSimple 3D FFT for real data: execution time for 1 loops: 0.60999999999999998668\nSimple 3D FFT for complex data: execution time for 1 loops: 0.64000000000000001332\nFFTW3 1D FFT for real data: execution time for 1 loops: 0\nFFTW3 1D FFT for complex data: execution time for 1 loops: 0\nFFTW 2D FFT for real data: execution time for 1 loops: 0.050000000000000002776\nFFTW 2D FFT for complex data: execution time for 1 loops: 0.11999999999999999556\nFFTW 3D FFT for real data: execution time for 1 loops: 1.0900000000000000799\nFFTW 3D FFT for complex data: execution time for 1 loops: 0.75\n"
  },
  {
    "path": "benchmark-tests/results_Linux_Mint_14_x86_64_Intel_Core_i5_10_Gb_RAM/benchmark_test_single_transform_clang_release.txt",
    "content": "FFT test: creating real 1D pulse.\nDone.\nFFT test: creating real 2D pulse.\nDone.\nFFT test: creating real 3D pulse.\nDone.\nFFT test: creating real 1D pulse.\nDone.\nFFT test: creating real 2D pulse.\nDone.\nFFT test: creating real 3D pulse.\nDone.\nSimple 1D FFT for real data: execution time for 1 loops: 0\nSimple 1D FFT for complex data: execution time for 1 loops: 0\nSimple 2D FFT for real data: execution time for 1 loops: 0.010000000000000000208\nSimple 2D FFT for complex data: execution time for 1 loops: 0\nSimple 3D FFT for real data: execution time for 1 loops: 0.11000000000000000056\nSimple 3D FFT for complex data: execution time for 1 loops: 0.10000000000000000555\nFFTW3 1D FFT for real data: execution time for 1 loops: 0\nFFTW3 1D FFT for complex data: execution time for 1 loops: 0\nFFTW 2D FFT for real data: execution time for 1 loops: 0.020000000000000000416\nFFTW 2D FFT for complex data: execution time for 1 loops: 0.02999999999999999889\nFFTW 3D FFT for real data: execution time for 1 loops: 0.3499999999999999778\nFFTW 3D FFT for complex data: execution time for 1 loops: 0.73999999999999999112\n"
  },
  {
    "path": "include/simple_fft/check_fft.hpp",
    "content": "/**\n * Copyright (c) 2013-2020 Dmitry Ivanov\n *\n * This file is a part of Simple-FFT project and is distributed under the terms\n * of MIT license: https://opensource.org/licenses/MIT\n */\n\n#ifndef __SIMPLE_FFT__CHECK_FFT_HPP__\n#define __SIMPLE_FFT__CHECK_FFT_HPP__\n\n#include \"fft_settings.h\"\n#include \"error_handling.hpp\"\n#include \"copy_array.hpp\"\n#include <cstddef>\n#include <cmath>\n#include <numeric>\n\nusing std::size_t;\n\nnamespace simple_fft {\nnamespace check_fft_private {\n\nenum CheckMode\n{\n    CHECK_FFT_PARSEVAL,\n    CHECK_FFT_ENERGY,\n    CHECK_FFT_EQUALITY\n};\n\ntemplate <class TArray1D, class TComplexArray1D>\nvoid getMaxAbsoluteAndRelativeErrorNorms(const TArray1D & array1,\n                                         const TComplexArray1D & array2, const size_t size,\n                                         real_type & max_absolute_error_norm,\n                                         real_type & max_relative_error_norm)\n{\n    using std::abs;\n\n    real_type current_error;\n\n    // NOTE: no parallelization here, it is a completely sequential loop!\n    for(size_t i = 0; i < size; ++i) {\n#ifdef __USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR\n        current_error = abs(array1[i] - array2[i]);\n#else\n        current_error = abs(array1(i) - array2(i));\n#endif\n        if (current_error > max_absolute_error_norm) {\n            max_absolute_error_norm = current_error;\n#ifdef __USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR\n            if (abs(array1[i]) > abs(array2[i])) {\n                max_relative_error_norm = (abs(array1[i]) > 1e-20\n                                           ? max_absolute_error_norm / abs(array1[i])\n                                           : 0.0);\n            }\n            else {\n                max_relative_error_norm = (abs(array2[i]) > 1e-20\n                                           ? max_absolute_error_norm / abs(array2[i])\n                                           : 0.0);\n            }\n#else\n            if (abs(array1(i)) > abs(array2(i))) {\n                max_relative_error_norm = (abs(array1(i)) > 1e-20\n                                           ? max_absolute_error_norm / abs(array1(i))\n                                           : 0.0);\n            }\n            else {\n                max_relative_error_norm = (abs(array2(i)) > 1e-20\n                                           ? max_absolute_error_norm / abs(array2(i))\n                                           : 0.0);\n            }\n#endif\n        }\n    }\n}\n\ntemplate <class TArray2D, class TComplexArray2D>\nvoid getMaxAbsoluteAndRelativeErrorNorms(const TArray2D & array1,\n                                         const TComplexArray2D & array2,\n                                         const size_t size1, const size_t size2,\n                                         real_type & max_absolute_error_norm,\n                                         real_type & max_relative_error_norm)\n{\n    using std::abs;\n\n    real_type current_error;\n\n    // NOTE: no parallelization here, it is a completely sequential loop!\n    for(int i = 0; i < static_cast<int>(size1); ++i) {\n        for(int j = 0; j < static_cast<int>(size2); ++j) {\n#ifdef __USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR\n            current_error = abs(array1[i][j] - array2[i][j]);\n#else\n            current_error = abs(array1(i,j) - array2(i,j));\n#endif\n            if (current_error > max_absolute_error_norm) {\n                max_absolute_error_norm = current_error;\n#ifdef __USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR\n                if (abs(array1[i][j]) > abs(array2[i][j])) {\n                    max_relative_error_norm = (abs(array1[i][j]) > 1e-20\n                                               ? max_absolute_error_norm / abs(array1[i][j])\n                                               : 0.0);\n                }\n                else {\n                    max_relative_error_norm = (abs(array2[i][j]) > 1e-20\n                                               ? max_absolute_error_norm / abs(array2[i][j])\n                                               : 0.0);\n                }\n#else\n                if (abs(array1(i,j)) > abs(array2(i,j))) {\n                    max_relative_error_norm = (abs(array1(i,j)) > 1e-20\n                                               ? max_absolute_error_norm / abs(array1(i,j))\n                                               : 0.0);\n                }\n                else {\n                    max_relative_error_norm = (abs(array2(i,j)) > 1e-20\n                                               ? max_absolute_error_norm / abs(array2(i,j))\n                                               : 0.0);\n                }\n#endif\n            }\n        }\n    }\n}\n\ntemplate <class TArray3D, class TComplexArray3D>\nvoid getMaxAbsoluteAndRelativeErrorNorms(const TArray3D & array1, const TComplexArray3D & array2,\n                                         const size_t size1, const size_t size2,\n                                         const size_t size3, real_type & max_absolute_error_norm,\n                                         real_type & max_relative_error_norm)\n{\n    using std::abs;\n\n    real_type current_error;\n\n    // NOTE: no parallelization here, it is a completely sequential loop!\n    for(int i = 0; i < static_cast<int>(size1); ++i) {\n        for(int j = 0; j < static_cast<int>(size2); ++j) {\n            for(int k = 0; k < static_cast<int>(size3); ++k) {\n#ifdef __USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR\n                current_error = abs(array1[i][j][k] - array2[i][j][k]);\n#else\n                current_error = abs(array1(i,j,k) - array2(i,j,k));\n#endif\n                if (current_error > max_absolute_error_norm) {\n                    max_absolute_error_norm = current_error;\n#ifdef __USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR\n                    if (abs(array1[i][j][k]) > abs(array2[i][j][k])) {\n                        max_relative_error_norm = (abs(array1[i][j][k]) > 1e-20\n                                                   ? max_absolute_error_norm / abs(array1[i][j][k])\n                                                   : 0.0);\n                    }\n                    else {\n                        max_relative_error_norm = (abs(array2[i][j][k]) > 1e-20\n                                                   ? max_absolute_error_norm / abs(array2[i][j][k])\n                                                   : 0.0);\n                    }\n#else\n                    if (abs(array1(i,j,k)) > abs(array2(i,j,k))) {\n                        max_relative_error_norm = (abs(array1(i,j,k)) > 1e-20\n                                                   ? max_absolute_error_norm / abs(array1(i,j,k))\n                                                   : 0.0);\n                    }\n                    else {\n                        max_relative_error_norm = (abs(array2(i,j,k)) > 1e-20\n                                                   ? max_absolute_error_norm / abs(array2(i,j,k))\n                                                   : 0.0);\n                    }\n#endif\n                }\n            }\n        }\n    }\n}\n\ntemplate <class TArray1D>\nreal_type squareAbsAccumulate(const TArray1D & array, const size_t size,\n                              const real_type init)\n{\n    int size_signed = static_cast<int>(size);\n    real_type sum = init;\n\n    using std::abs;\n\n#ifndef __clang__\n#ifdef __USE_OPENMP\n#pragma omp parallel for reduction(+:sum)\n#endif\n#endif\n    for(int i = 0; i < size_signed; ++i) {\n#ifdef __USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR\n        sum += abs(array[i] * array[i]);\n#else\n        sum += abs(array(i) * array(i));\n#endif\n    }\n\n    return sum;\n}\n\ntemplate <class TArray2D>\nreal_type squareAbsAccumulate(const TArray2D & array, const size_t size1,\n                              const size_t size2, const real_type init)\n{\n    int size1_signed = static_cast<int>(size1);\n    int size2_signed = static_cast<int>(size2);\n    real_type sum = init;\n\n    using std::abs;\n\n#ifndef __clang__\n#ifdef __USE_OPENMP\n#pragma omp parallel for reduction(+:sum)\n#endif\n#endif\n    for(int i = 0; i < size1_signed; ++i) {\n        for(int j = 0; j < size2_signed; ++j) {\n#ifdef __USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR\n            sum += abs(array[i][j] * array[i][j]);\n#else\n            sum += abs(array(i,j) * array(i,j));\n#endif\n        }\n    }\n\n    return sum;\n}\n\ntemplate <class TArray3D>\nreal_type squareAbsAccumulate(const TArray3D & array, const size_t size1,\n                              const size_t size2, const size_t size3,\n                              const real_type init)\n{\n    int size1_signed = static_cast<int>(size1);\n    int size2_signed = static_cast<int>(size2);\n    int size3_signed = static_cast<int>(size3);\n    real_type sum = init;\n\n    using std::abs;\n\n#ifndef __clang__\n#ifdef __USE_OPENMP\n#pragma omp parallel for reduction(+:sum)\n#endif\n#endif\n    for(int i = 0; i < size1_signed; ++i) {\n        for(int j = 0; j < size2_signed; ++j) {\n            for(int k = 0; k < size3_signed; ++k) {\n#ifdef __USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR\n                sum += abs(array[i][j][k] * array[i][j][k]);\n#else\n                sum += abs(array(i,j,k) * array(i,j,k));\n#endif\n            }\n        }\n    }\n\n    return sum;\n}\n\n// Generic template for CCheckFFT struct followed by its explicit specializations\n// for certain numbers of dimensions. TArray can be either of real or complex type.\n// The technique is similar to the one applied for CFFT struct.\ntemplate <class TArray, class TComplexArray, int NumDims>\nstruct CCheckFFT\n{};\n\ntemplate <class TArray1D, class TComplexArray1D>\nstruct CCheckFFT<TArray1D,TComplexArray1D,1>\n{\n    static bool check_fft(const TArray1D & data_before,\n                          const TComplexArray1D & data_after,\n                          const size_t size, const real_type relative_tolerance,\n                          real_type & discrepancy, const CheckMode check_mode,\n                          const char *& error_description)\n    {\n        using namespace error_handling;\n\n        if(0 == size) {\n            GetErrorDescription(EC_NUM_OF_ELEMS_IS_ZERO, error_description);\n            return false;\n        }\n\n        if ( (CHECK_FFT_PARSEVAL != check_mode) &&\n             (CHECK_FFT_ENERGY   != check_mode) &&\n             (CHECK_FFT_EQUALITY != check_mode) )\n        {\n            GetErrorDescription(EC_WRONG_CHECK_FFT_MODE, error_description);\n            return false;\n        }\n\n        if (CHECK_FFT_EQUALITY != check_mode)\n        {\n            real_type sum_before = squareAbsAccumulate<TArray1D>(data_before, size, 0.0);\n            real_type sum_after  = squareAbsAccumulate<TComplexArray1D>(data_after, size, 0.0);\n\n            if (CHECK_FFT_PARSEVAL == check_mode) {\n                sum_after /= size;\n            }\n\n            using std::abs;\n\n            discrepancy = abs(sum_before - sum_after);\n\n            if (discrepancy / ((sum_before < 1e-20) ? (sum_before + 1e-20) : sum_before) > relative_tolerance) {\n                GetErrorDescription(EC_RELATIVE_ERROR_TOO_LARGE, error_description);\n                return false;\n            }\n            else {\n                return true;\n            }\n        }\n        else {\n            real_type relative_error;\n            getMaxAbsoluteAndRelativeErrorNorms(data_before, data_after, size,\n                                                discrepancy, relative_error);\n            if (relative_error < relative_tolerance) {\n                return true;\n            }\n            else {\n                GetErrorDescription(EC_RELATIVE_ERROR_TOO_LARGE, error_description);\n                return false;\n            }\n        }\n    }\n};\n\ntemplate <class TArray2D, class TComplexArray2D>\nstruct CCheckFFT<TArray2D,TComplexArray2D,2>\n{\n    static bool check_fft(const TArray2D & data_before,\n                          const TComplexArray2D & data_after,\n                          const size_t size1, const size_t size2,\n                          const real_type relative_tolerance, real_type & discrepancy,\n                          const CheckMode check_mode, const char *& error_description)\n    {\n        using namespace error_handling;\n\n        if( (0 == size1) || (0 == size2) ) {\n            GetErrorDescription(EC_NUM_OF_ELEMS_IS_ZERO, error_description);\n            return false;\n        }\n\n        if ( (CHECK_FFT_PARSEVAL != check_mode) &&\n             (CHECK_FFT_ENERGY   != check_mode) &&\n             (CHECK_FFT_EQUALITY != check_mode) )\n        {\n            GetErrorDescription(EC_WRONG_CHECK_FFT_MODE, error_description);\n            return false;\n        }\n\n        if (CHECK_FFT_EQUALITY != check_mode)\n        {\n            real_type sum_before = squareAbsAccumulate<TArray2D>(data_before, size1, size2, 0.0);\n            real_type sum_after  = squareAbsAccumulate<TComplexArray2D>(data_after, size1, size2, 0.0);\n\n            if (CHECK_FFT_PARSEVAL == check_mode) {\n                sum_after /= size1 * size2;\n            }\n\n            using std::abs;\n\n            discrepancy = abs(sum_before - sum_after);\n\n            if (discrepancy / ((sum_before < 1e-20) ? (sum_before + 1e-20) : sum_before) > relative_tolerance) {\n                GetErrorDescription(EC_RELATIVE_ERROR_TOO_LARGE, error_description);\n                return false;\n            }\n            else {\n                return true;\n            }\n        }\n        else {\n            real_type relative_error;\n            getMaxAbsoluteAndRelativeErrorNorms(data_before, data_after, size1,\n                                                size2, discrepancy, relative_error);\n            if (relative_error < relative_tolerance) {\n                return true;\n            }\n            else {\n                GetErrorDescription(EC_RELATIVE_ERROR_TOO_LARGE, error_description);\n                return false;\n            }\n        }\n    }\n};\n\ntemplate <class TArray3D, class TComplexArray3D>\nstruct CCheckFFT<TArray3D,TComplexArray3D,3>\n{\n    static bool check_fft(const TArray3D & data_before,\n                          const TComplexArray3D & data_after,\n                          const size_t size1, const size_t size2, const size_t size3,\n                          const real_type relative_tolerance, real_type & discrepancy,\n                          const CheckMode check_mode, const char *& error_description)\n    {\n        using namespace error_handling;\n\n        if( (0 == size1) || (0 == size2) || (0 == size3) ) {\n            GetErrorDescription(EC_NUM_OF_ELEMS_IS_ZERO, error_description);\n            return false;\n        }\n\n        if ( (CHECK_FFT_PARSEVAL != check_mode) &&\n             (CHECK_FFT_ENERGY   != check_mode) &&\n             (CHECK_FFT_EQUALITY != check_mode) )\n        {\n            GetErrorDescription(EC_WRONG_CHECK_FFT_MODE, error_description);\n            return false;\n        }\n\n        if (CHECK_FFT_EQUALITY != check_mode)\n        {\n            real_type sum_before = squareAbsAccumulate<TArray3D>(data_before, size1, size2, size3, 0.0);\n            real_type sum_after  = squareAbsAccumulate<TComplexArray3D>(data_after, size1, size2, size3, 0.0);\n\n            if (CHECK_FFT_PARSEVAL == check_mode) {\n                sum_after /= size1 * size2 * size3;\n            }\n\n            using std::abs;\n\n            discrepancy = abs(sum_before - sum_after);\n\n            if (discrepancy / ((sum_before < 1e-20) ? (sum_before + 1e-20) : sum_before) > relative_tolerance) {\n                GetErrorDescription(EC_RELATIVE_ERROR_TOO_LARGE, error_description);\n                return false;\n            }\n            else {\n                return true;\n            }\n        }\n        else {\n            real_type relative_error;\n            getMaxAbsoluteAndRelativeErrorNorms(data_before, data_after, size1,\n                                                size2, size3, discrepancy, relative_error);\n            if (relative_error < relative_tolerance) {\n                return true;\n            }\n            else {\n                GetErrorDescription(EC_RELATIVE_ERROR_TOO_LARGE, error_description);\n                return false;\n            }\n        }\n    }\n};\n\n} // namespace check_fft_private\n\nnamespace check_fft {\n\ntemplate <class TArray1D, class TComplexArray1D>\nbool checkParsevalTheorem(const TArray1D & data_before_FFT,\n                          const TComplexArray1D & data_after_FFT,\n                          const size_t size, const real_type relative_tolerance,\n                          real_type & discrepancy, const char *& error_description)\n{\n    return check_fft_private::CCheckFFT<TArray1D,TComplexArray1D,1>::check_fft(data_before_FFT,\n                                             data_after_FFT, size, relative_tolerance,\n                                             discrepancy, check_fft_private::CHECK_FFT_PARSEVAL,\n                                             error_description);\n}\n\ntemplate <class TArray2D, class TComplexArray2D>\nbool checkParsevalTheorem(const TArray2D & data_before_FFT,\n                          const TComplexArray2D & data_after_FFT,\n                          const size_t size1, const size_t size2,\n                          const real_type relative_tolerance,\n                          real_type & discrepancy, const char *& error_description)\n{\n    return check_fft_private::CCheckFFT<TArray2D,TComplexArray2D,2>::check_fft(data_before_FFT,\n                                             data_after_FFT, size1, size2, relative_tolerance,\n                                             discrepancy, check_fft_private::CHECK_FFT_PARSEVAL,\n                                             error_description);\n}\n\ntemplate <class TArray3D, class TComplexArray3D>\nbool checkParsevalTheorem(const TArray3D & data_before_FFT,\n                          const TComplexArray3D & data_after_FFT,\n                          const size_t size1, const size_t size2, const size_t size3,\n                          const real_type relative_tolerance, real_type & discrepancy,\n                          const char *& error_description)\n{\n    return check_fft_private::CCheckFFT<TArray3D,TComplexArray3D,3>::check_fft(data_before_FFT,\n                                                  data_after_FFT, size1, size2, size3,\n                                                  relative_tolerance, discrepancy,\n                                                  check_fft_private::CHECK_FFT_PARSEVAL,\n                                                  error_description);\n}\n\ntemplate <class TArray1D, class TComplexArray1D>\nbool checkEnergyConservation(const TArray1D & data_before_FFT,\n                             const TComplexArray1D & data_after_FFT_and_IFFT,\n                             const size_t size, const real_type relative_tolerance,\n                             real_type & discrepancy, const char *& error_description)\n{\n    return check_fft_private::CCheckFFT<TArray1D,TComplexArray1D,1>::check_fft(data_before_FFT,\n                                    data_after_FFT_and_IFFT, size, relative_tolerance,\n                                    discrepancy, check_fft_private::CHECK_FFT_ENERGY,\n                                    error_description);\n}\n\ntemplate <class TArray2D, class TComplexArray2D>\nbool checkEnergyConservation(const TArray2D & data_before_FFT,\n                             const TComplexArray2D & data_after_FFT_and_IFFT,\n                             const size_t size1, const size_t size2,\n                             const real_type relative_tolerance,\n                             real_type & discrepancy, const char *& error_description)\n{\n    return check_fft_private::CCheckFFT<TArray2D,TComplexArray2D,2>::check_fft(data_before_FFT,\n                                                data_after_FFT_and_IFFT, size1, size2,\n                                                relative_tolerance, discrepancy,\n                                                check_fft_private::CHECK_FFT_ENERGY,\n                                                error_description);\n}\n\ntemplate <class TArray3D, class TComplexArray3D>\nbool checkEnergyConservation(const TArray3D & data_before_FFT,\n                             const TComplexArray3D & data_after_FFT_and_IFFT,\n                             const size_t size1, const size_t size2, const size_t size3,\n                             const real_type relative_tolerance, real_type & discrepancy,\n                             const char *& error_description)\n{\n    return check_fft_private::CCheckFFT<TArray3D,TComplexArray3D,3>::check_fft(data_before_FFT,\n                                                data_after_FFT_and_IFFT, size1, size2,\n                                                size3, relative_tolerance, discrepancy,\n                                                check_fft_private::CHECK_FFT_ENERGY,\n                                                error_description);\n}\n\ntemplate <class TArray1D, class TComplexArray1D>\nbool checkEquality(const TArray1D & data_before_FFT,\n                   const TComplexArray1D & data_after_FFT_and_IFFT,\n                   const size_t size, const real_type relative_tolerance,\n                   real_type & discrepancy, const char *& error_description)\n{\n    return check_fft_private::CCheckFFT<TArray1D,TComplexArray1D,1>::check_fft(data_before_FFT,\n                                             data_after_FFT_and_IFFT, size, relative_tolerance,\n                                             discrepancy, check_fft_private::CHECK_FFT_EQUALITY,\n                                             error_description);\n}\n\ntemplate <class TArray2D, class TComplexArray2D>\nbool checkEquality(const TArray2D & data_before_FFT,\n                   const TComplexArray2D & data_after_FFT_and_IFFT, const size_t size1,\n                   const size_t size2, const real_type relative_tolerance,\n                   real_type & discrepancy, const char *& error_description)\n{\n    return check_fft_private::CCheckFFT<TArray2D,TComplexArray2D,2>::check_fft(data_before_FFT,\n                                                         data_after_FFT_and_IFFT, size1, size2,\n                                                         relative_tolerance, discrepancy,\n                                                         check_fft_private::CHECK_FFT_EQUALITY,\n                                                         error_description);\n}\n\ntemplate <class TArray3D, class TComplexArray3D>\nbool checkEquality(const TArray3D & data_before_FFT,\n                   const TComplexArray3D & data_after_FFT_and_IFFT, const size_t size1,\n                   const size_t size2, const size_t size3, const real_type relative_tolerance,\n                   real_type & discrepancy, const char *& error_description)\n{\n    return check_fft_private::CCheckFFT<TArray3D,TComplexArray3D,3>::check_fft(data_before_FFT,\n                                                         data_after_FFT_and_IFFT, size1, size2,\n                                                         size3, relative_tolerance, discrepancy,\n                                                         check_fft_private::CHECK_FFT_EQUALITY,\n                                                         error_description);\n}\n\n} // namespace check_fft\n} // namespace simple_fft\n\n#endif // __SIMPLE_FFT__CHECK_FFT_HPP__\n"
  },
  {
    "path": "include/simple_fft/copy_array.hpp",
    "content": "/**\r\n * Copyright (c) 2013-2020 Dmitry Ivanov\r\n *\r\n * This file is a part of Simple-FFT project and is distributed under the terms\r\n * of MIT license: https://opensource.org/licenses/MIT\r\n */\r\n\r\n#ifndef __SIMPLE_FFT__COPY_ARRAY_HPP\r\n#define __SIMPLE_FFT__COPY_ARRAY_HPP\r\n\r\n#include \"fft_settings.h\"\r\n#include \"error_handling.hpp\"\r\n#include <cstddef>\r\n\r\nusing std::size_t;\r\n\r\nnamespace simple_fft {\r\nnamespace copy_array {\r\n\r\ntemplate <class TComplexArray1D>\r\nvoid copyArray(const TComplexArray1D & data_from, TComplexArray1D & data_to,\r\n               const size_t size)\r\n{\r\n    int size_signed = static_cast<int>(size);\r\n\r\n#ifndef __clang__\r\n#ifdef __USE_OPENMP\r\n#pragma omp parallel for\r\n#endif\r\n#endif\r\n    for(int i = 0; i < size_signed; ++i) {\r\n#ifdef __USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR\r\n        data_to[i] = data_from[i];\r\n#else\r\n        data_to(i) = data_from(i);\r\n#endif\r\n    }\r\n}\r\n\r\ntemplate <class TComplexArray1D, class TRealArray1D>\r\nvoid copyArray(const TRealArray1D & data_from, TComplexArray1D & data_to,\r\n               const size_t size)\r\n{\r\n    int size_signed = static_cast<int>(size);\r\n\r\n    // NOTE: user's complex type should have constructor like\r\n    // \"complex(real, imag)\", where each of real and imag has\r\n    // real type.\r\n\r\n#ifndef __clang__\r\n#ifdef __USE_OPENMP\r\n#pragma omp parallel for\r\n#endif\r\n#endif\r\n    for(int i = 0; i < size_signed; ++i) {\r\n#ifdef __USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR\r\n        data_to[i] = complex_type(data_from[i], 0.0);\r\n#else\r\n        data_to(i) = complex_type(data_from(i), 0.0);\r\n#endif\r\n    }\r\n}\r\n\r\ntemplate <class TComplexArray2D>\r\nvoid copyArray(const TComplexArray2D & data_from, TComplexArray2D & data_to,\r\n               const size_t size1, const size_t size2)\r\n{\r\n    int size1_signed = static_cast<int>(size1);\r\n    int size2_signed = static_cast<int>(size2);\r\n\r\n#ifndef __clang__\r\n#ifdef __USE_OPENMP\r\n#pragma omp parallel for\r\n#endif\r\n#endif\r\n    for(int i = 0; i < size1_signed; ++i) {\r\n        for(int j = 0; j < size2_signed; ++j) {\r\n#ifdef __USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR\r\n            data_to[i][j] = data_from[i][j];\r\n#else\r\n            data_to(i,j) = data_from(i,j);\r\n#endif\r\n        }\r\n    }\r\n}\r\n\r\ntemplate <class TComplexArray2D, class TRealArray2D>\r\nvoid copyArray(const TRealArray2D & data_from, TComplexArray2D & data_to,\r\n               const size_t size1, const size_t size2)\r\n{\r\n    int size1_signed = static_cast<int>(size1);\r\n    int size2_signed = static_cast<int>(size2);\r\n\r\n    // NOTE: user's complex type should have constructor like\r\n    // \"complex(real, imag)\", where each of real and imag has\r\n    // real type.\r\n\r\n#ifndef __clang__\r\n#ifdef __USE_OPENMP\r\n#pragma omp parallel for\r\n#endif\r\n#endif\r\n    for(int i = 0; i < size1_signed; ++i) {\r\n        for(int j = 0; j < size2_signed; ++j) {\r\n#ifdef __USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR\r\n            data_to[i][j] = complex_type(data_from[i][j], 0.0);\r\n#else\r\n            data_to(i,j) = complex_type(data_from(i,j), 0.0);\r\n#endif\r\n        }\r\n    }\r\n}\r\n\r\ntemplate <class TComplexArray3D>\r\nvoid copyArray(const TComplexArray3D & data_from, TComplexArray3D & data_to,\r\n               const size_t size1, const size_t size2, const size_t size3)\r\n{\r\n    int size1_signed = static_cast<int>(size1);\r\n    int size2_signed = static_cast<int>(size2);\r\n    int size3_signed = static_cast<int>(size3);\r\n\r\n#ifndef __clang__\r\n#ifdef __USE_OPENMP\r\n#pragma omp parallel for\r\n#endif\r\n#endif\r\n    for(int i = 0; i < size1_signed; ++i) {\r\n        for(int j = 0; j < size2_signed; ++j) {\r\n            for(int k = 0; k < size3_signed; ++k) {\r\n#ifdef __USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR\r\n                data_to[i][j][k] = data_from[i][j][k];\r\n#else\r\n                data_to(i,j,k) = data_from(i,j,k);\r\n#endif\r\n            }\r\n        }\r\n    }\r\n}\r\n\r\ntemplate <class TComplexArray3D, class TRealArray3D>\r\nvoid copyArray(const TRealArray3D & data_from, TComplexArray3D & data_to,\r\n               const size_t size1, const size_t size2, const size_t size3)\r\n{\r\n    int size1_signed = static_cast<int>(size1);\r\n    int size2_signed = static_cast<int>(size2);\r\n    int size3_signed = static_cast<int>(size3);\r\n\r\n    // NOTE: user's complex type should have constructor like\r\n    // \"complex(real, imag)\", where each of real and imag has\r\n    // real type.\r\n\r\n#ifndef __clang__\r\n#ifdef __USE_OPENMP\r\n#pragma omp parallel for\r\n#endif\r\n#endif\r\n    for(int i = 0; i < size1_signed; ++i) {\r\n        for(int j = 0; j < size2_signed; ++j) {\r\n            for(int k = 0; k < size3_signed; ++k) {\r\n#ifdef __USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR\r\n                data_to[i][j][k] = complex_type(data_from[i][j][k], 0.0);\r\n#else\r\n                data_to(i,j,k) = complex_type(data_from(i,j,k), 0.0);\r\n#endif\r\n            }\r\n        }\r\n    }\r\n}\r\n\r\n} // namespace copy_array\r\n} // namespace simple_fft\r\n\r\n#endif // __SIMPLE_FFT__COPY_ARRAY_HPP\r\n"
  },
  {
    "path": "include/simple_fft/error_handling.hpp",
    "content": "/**\r\n * Copyright (c) 2013-2020 Dmitry Ivanov\r\n *\r\n * This file is a part of Simple-FFT project and is distributed under the terms\r\n * of MIT license: https://opensource.org/licenses/MIT\r\n */\r\n\r\n#ifndef __SIMPLE_FFT__ERROR_HANDLING_HPP\r\n#define __SIMPLE_FFT__ERROR_HANDLING_HPP\r\n\r\nnamespace simple_fft {\r\nnamespace error_handling {\r\n\r\nenum EC_SimpleFFT\r\n{\r\n    EC_SUCCESS = 0,\r\n    EC_UNSUPPORTED_DIMENSIONALITY,\r\n    EC_WRONG_FFT_DIRECTION,\r\n    EC_ONE_OF_DIMS_ISNT_POWER_OF_TWO,\r\n    EC_NUM_OF_ELEMS_IS_ZERO,\r\n    EC_WRONG_CHECK_FFT_MODE,\r\n    EC_RELATIVE_ERROR_TOO_LARGE\r\n};\r\n\r\ninline void GetErrorDescription(const EC_SimpleFFT error_code,\r\n                                const char *& error_description)\r\n{\r\n    switch(error_code)\r\n    {\r\n    case EC_SUCCESS:\r\n        error_description = \"Calculation was successful!\";\r\n        break;\r\n    case EC_UNSUPPORTED_DIMENSIONALITY:\r\n        error_description = \"Unsupported dimensionality: currently only 1D, 2D \"\r\n                            \"and 3D arrays are supported\";\r\n        break;\r\n    case EC_WRONG_FFT_DIRECTION:\r\n        error_description = \"Wrong direction for FFT was specified\";\r\n        break;\r\n    case EC_ONE_OF_DIMS_ISNT_POWER_OF_TWO:\r\n        error_description = \"Unsupported dimensionality: one of dimensions is not \"\r\n                            \"a power of 2\";\r\n        break;\r\n    case EC_NUM_OF_ELEMS_IS_ZERO:\r\n        error_description = \"Number of elements for FFT or IFFT is zero!\";\r\n        break;\r\n    case EC_WRONG_CHECK_FFT_MODE:\r\n        error_description = \"Wrong check FFT mode was specified (should be either \"\r\n                            \"Parseval theorem or energy conservation check\";\r\n        break;\r\n    case EC_RELATIVE_ERROR_TOO_LARGE:\r\n        error_description = \"Relative error returned by FFT test exceeds specified \"\r\n                            \"relative tolerance\";\r\n        break;\r\n    default:\r\n        error_description = \"Unknown error\";\r\n        break;\r\n    }\r\n}\r\n\r\n} // namespace error_handling\r\n} // namespace simple_fft\r\n\r\n#endif // __SIMPLE_FFT__ERROR_HANDLING_HPP\r\n"
  },
  {
    "path": "include/simple_fft/fft.h",
    "content": "/**\n * Copyright (c) 2013-2020 Dmitry Ivanov\n *\n * This file is a part of Simple-FFT project and is distributed under the terms\n * of MIT license: https://opensource.org/licenses/MIT\n */\n\n#ifndef __SIMPLE_FFT__FFT_H__\n#define __SIMPLE_FFT__FFT_H__\n\n#include <cstddef>\n\nusing std::size_t;\n\n/// The public API\nnamespace simple_fft {\n\n/// FFT and IFFT functions\n\n// in-place, complex, forward\ntemplate <class TComplexArray1D>\nbool FFT(TComplexArray1D & data, const size_t size, const char *& error_description);\n\ntemplate <class TComplexArray2D>\nbool FFT(TComplexArray2D & data, const size_t size1, const size_t size2,\n         const char *& error_description);\n\ntemplate <class TComplexArray3D>\nbool FFT(TComplexArray3D & data, const size_t size1, const size_t size2, const size_t size3,\n         const char *& error_description);\n\n// in-place, complex, inverse\ntemplate <class TComplexArray1D>\nbool IFFT(TComplexArray1D & data, const size_t size, const char *& error_description);\n\ntemplate <class TComplexArray2D>\nbool IFFT(TComplexArray2D & data, const size_t size1, const size_t size2,\n          const char *& error_description);\n\ntemplate <class TComplexArray3D>\nbool IFFT(TComplexArray3D & data, const size_t size1, const size_t size2, const size_t size3,\n          const char *& error_description);\n\n// not-in-place, complex, forward\ntemplate <class TComplexArray1D>\nbool FFT(const TComplexArray1D & data_in, TComplexArray1D & data_out,\n         const size_t size, const char *& error_description);\n\ntemplate <class TComplexArray2D>\nbool FFT(const TComplexArray2D & data_in, TComplexArray2D & data_out,\n         const size_t size1, const size_t size2, const char *& error_description);\n\ntemplate <class TComplexArray3D>\nbool FFT(const TComplexArray3D & data_in, TComplexArray3D & data_out,\n         const size_t size1, const size_t size2, const size_t size3,\n         const char *& error_description);\n\n// not-in-place, complex, inverse\ntemplate <class TComplexArray1D>\nbool IFFT(const TComplexArray1D & data_in, TComplexArray1D & data_out,\n          const size_t size, const char *& error_description);\n\ntemplate <class TComplexArray2D>\nbool IFFT(const TComplexArray2D & data_in, TComplexArray2D & data_out,\n          const size_t size1, const size_t size2, const char *& error_description);\n\ntemplate <class TComplexArray3D>\nbool IFFT(const TComplexArray3D & data_in, TComplexArray3D & data_out,\n          const size_t size1, const size_t size2, const size_t size3,\n          const char *& error_description);\n\n// not-in-place, real, forward\ntemplate <class TRealArray1D, class TComplexArray1D>\nbool FFT(const TRealArray1D & data_in, TComplexArray1D & data_out,\n         const size_t size, const char *& error_description);\n\ntemplate <class TRealArray2D, class TComplexArray2D>\nbool FFT(const TRealArray2D & data_in, TComplexArray2D & data_out,\n         const size_t size1, const size_t size2, const char *& error_description);\n\ntemplate <class TRealArray3D, class TComplexArray3D>\nbool FFT(const TRealArray3D & data_in, TComplexArray3D & data_out,\n         const size_t size1, const size_t size2, const size_t size3,\n         const char *& error_description);\n\n// NOTE: There is no inverse transform from complex spectrum to real signal\n// because round-off errors during computation of inverse FFT lead to the appearance\n// of signal imaginary components even though they are small by absolute value.\n// These can be ignored but the author of this file thinks adding such an function\n// would be wrong methodogically: looking at complex result, you can estimate\n// the value of spurious imaginary part. Otherwise you may never know that IFFT\n// provides too large imaginary values due to too small grid size, for example.\n\n} // namespace simple_fft\n\n#endif // __SIMPLE_FFT__FFT_H__\n\n#include \"fft.hpp\"\n"
  },
  {
    "path": "include/simple_fft/fft.hpp",
    "content": "/**\r\n * Copyright (c) 2013-2020 Dmitry Ivanov\r\n *\r\n * This file is a part of Simple-FFT project and is distributed under the terms\r\n * of MIT license: https://opensource.org/licenses/MIT\r\n */\r\n\r\n#ifndef __SIMPLE_FFT__FFT_HPP__\r\n#define __SIMPLE_FFT__FFT_HPP__\r\n\r\n#include \"copy_array.hpp\"\r\n#include \"fft_impl.hpp\"\r\n\r\nnamespace simple_fft {\r\n\r\n// in-place, complex, forward\r\ntemplate <class TComplexArray1D>\r\nbool FFT(TComplexArray1D & data, const size_t size, const char *& error_description)\r\n{\r\n    return impl::CFFT<TComplexArray1D,1>::FFT_inplace(data, size, impl::FFT_FORWARD,\r\n                                                      error_description);\r\n}\r\n\r\ntemplate <class TComplexArray2D>\r\nbool FFT(TComplexArray2D & data, const size_t size1, const size_t size2,\r\n         const char *& error_description)\r\n{\r\n    return impl::CFFT<TComplexArray2D,2>::FFT_inplace(data, size1, size2, impl::FFT_FORWARD,\r\n                                                      error_description);\r\n}\r\n\r\ntemplate <class TComplexArray3D>\r\nbool FFT(TComplexArray3D & data, const size_t size1, const size_t size2, const size_t size3,\r\n         const char *& error_description)\r\n{\r\n    return impl::CFFT<TComplexArray3D,3>::FFT_inplace(data, size1, size2, size3,\r\n                                                      impl::FFT_FORWARD,\r\n                                                      error_description);\r\n}\r\n\r\n// in-place, complex, inverse\r\ntemplate <class TComplexArray1D>\r\nbool IFFT(TComplexArray1D & data, const size_t size, const char *& error_description)\r\n{\r\n    return impl::CFFT<TComplexArray1D,1>::FFT_inplace(data, size, impl::FFT_BACKWARD,\r\n                                                      error_description);\r\n}\r\n\r\ntemplate <class TComplexArray2D>\r\nbool IFFT(TComplexArray2D & data, const size_t size1, const size_t size2,\r\n          const char *& error_description)\r\n{\r\n    return impl::CFFT<TComplexArray2D,2>::FFT_inplace(data, size1, size2, impl::FFT_BACKWARD,\r\n                                                      error_description);\r\n}\r\n\r\ntemplate <class TComplexArray3D>\r\nbool IFFT(TComplexArray3D & data, const size_t size1, const size_t size2, const size_t size3,\r\n          const char *& error_description)\r\n{\r\n    return impl::CFFT<TComplexArray3D,3>::FFT_inplace(data, size1, size2, size3,\r\n                                                      impl::FFT_BACKWARD,\r\n                                                      error_description);\r\n}\r\n\r\n// not-in-place, complex, forward\r\ntemplate <class TComplexArray1D>\r\nbool FFT(const TComplexArray1D & data_in, TComplexArray1D & data_out,\r\n         const size_t size, const char *& error_description)\r\n{\r\n    copy_array::copyArray(data_in, data_out, size);\r\n    return impl::CFFT<TComplexArray1D,1>::FFT_inplace(data_out, size, impl::FFT_FORWARD,\r\n                                                      error_description);\r\n}\r\n\r\ntemplate <class TComplexArray2D>\r\nbool FFT(const TComplexArray2D & data_in, TComplexArray2D & data_out,\r\n         const size_t size1, const size_t size2, const char *& error_description)\r\n{\r\n    copy_array::copyArray(data_in, data_out, size1, size2);\r\n    return impl::CFFT<TComplexArray2D,2>::FFT_inplace(data_out, size1, size2,\r\n                                                      impl::FFT_FORWARD,\r\n                                                      error_description);\r\n}\r\n\r\ntemplate <class TComplexArray3D>\r\nbool FFT(const TComplexArray3D & data_in, TComplexArray3D & data_out,\r\n         const size_t size1, const size_t size2, const size_t size3,\r\n         const char *& error_description)\r\n{\r\n    copy_array::copyArray(data_in, data_out, size1, size2, size3);\r\n    return impl::CFFT<TComplexArray3D,3>::FFT_inplace(data_out, size1, size2, size3,\r\n                                                      impl::FFT_FORWARD,\r\n                                                      error_description);\r\n}\r\n\r\n// not-in-place, complex, inverse\r\ntemplate <class TComplexArray1D>\r\nbool IFFT(const TComplexArray1D & data_in, TComplexArray1D & data_out,\r\n          const size_t size, const char *& error_description)\r\n{\r\n    copy_array::copyArray(data_in, data_out, size);\r\n    return impl::CFFT<TComplexArray1D,1>::FFT_inplace(data_out, size, impl::FFT_BACKWARD,\r\n                                                      error_description);\r\n}\r\n\r\ntemplate <class TComplexArray2D>\r\nbool IFFT(const TComplexArray2D & data_in, TComplexArray2D & data_out,\r\n          const size_t size1, const size_t size2, const char *& error_description)\r\n{\r\n    copy_array::copyArray(data_in, data_out, size1, size2);\r\n    return impl::CFFT<TComplexArray2D,2>::FFT_inplace(data_out, size1, size2,\r\n                                                      impl::FFT_BACKWARD,\r\n                                                      error_description);\r\n}\r\n\r\ntemplate <class TComplexArray3D>\r\nbool IFFT(const TComplexArray3D & data_in, TComplexArray3D & data_out,\r\n          const size_t size1, const size_t size2, const size_t size3,\r\n          const char *& error_description)\r\n{\r\n    copy_array::copyArray(data_in, data_out, size1, size2, size3);\r\n    return impl::CFFT<TComplexArray3D,3>::FFT_inplace(data_out, size1, size2, size3,\r\n                                                      impl::FFT_BACKWARD,\r\n                                                      error_description);\r\n}\r\n\r\n// not-in-place, real, forward\r\ntemplate <class TRealArray1D, class TComplexArray1D>\r\nbool FFT(const TRealArray1D & data_in, TComplexArray1D & data_out,\r\n         const size_t size, const char *& error_description)\r\n{\r\n    copy_array::copyArray(data_in, data_out, size);\r\n    return impl::CFFT<TComplexArray1D,1>::FFT_inplace(data_out, size,\r\n                                                      impl::FFT_FORWARD,\r\n                                                      error_description);\r\n}\r\n\r\ntemplate <class TRealArray2D, class TComplexArray2D>\r\nbool FFT(const TRealArray2D & data_in, TComplexArray2D & data_out,\r\n         const size_t size1, const size_t size2, const char *& error_description)\r\n{\r\n    copy_array::copyArray(data_in, data_out, size1, size2);\r\n    return impl::CFFT<TComplexArray2D,2>::FFT_inplace(data_out, size1, size2,\r\n                                                      impl::FFT_FORWARD,\r\n                                                      error_description);\r\n}\r\n\r\ntemplate <class TRealArray3D, class TComplexArray3D>\r\nbool FFT(const TRealArray3D & data_in, TComplexArray3D & data_out,\r\n         const size_t size1, const size_t size2, const size_t size3,\r\n         const char *& error_description)\r\n{\r\n    copy_array::copyArray(data_in, data_out, size1, size2, size3);\r\n    return impl::CFFT<TComplexArray3D,3>::FFT_inplace(data_out, size1, size2, size3,\r\n                                                      impl::FFT_FORWARD,\r\n                                                      error_description);\r\n}\r\n\r\n} // simple_fft\r\n\r\n#endif // __SIMPLE_FFT__FFT_HPP__\r\n"
  },
  {
    "path": "include/simple_fft/fft_impl.hpp",
    "content": "/**\n * Copyright (c) 2013-2020 Dmitry Ivanov\n *\n * This file is a part of Simple-FFT project and is distributed under the terms\n * of MIT license: https://opensource.org/licenses/MIT\n */\n\n#ifndef __SIMPLE_FFT__FFT_IMPL_HPP__\n#define __SIMPLE_FFT__FFT_IMPL_HPP__\n\n#include \"fft_settings.h\"\n#include \"error_handling.hpp\"\n#include <cstddef>\n#include <math.h>\n#include <vector>\n\nusing std::size_t;\n\n#ifndef M_PI\n#define M_PI 3.1415926535897932\n#endif\n\nnamespace simple_fft {\nnamespace impl {\n\nenum FFT_direction\n{\n    FFT_FORWARD = 0,\n    FFT_BACKWARD\n};\n\n// checking whether the size of array dimension is power of 2\n// via \"complement and compare\" method\ninline bool isPowerOfTwo(const size_t num)\n{\n    return num && (!(num & (num - 1)));\n}\n\ninline bool checkNumElements(const size_t num_elements, const char *& error_description)\n{\n    using namespace error_handling;\n\n    if (!isPowerOfTwo(num_elements)) {\n        GetErrorDescription(EC_ONE_OF_DIMS_ISNT_POWER_OF_TWO, error_description);\n        return false;\n    }\n\n    return true;\n}\n\ntemplate <class TComplexArray1D>\ninline void scaleValues(TComplexArray1D & data, const size_t num_elements)\n{\n    real_type mult = 1.0 / num_elements;\n    int num_elements_signed = static_cast<int>(num_elements);\n\n#ifndef __clang__\n#ifdef __USE_OPENMP\n#pragma omp parallel for\n#endif\n#endif\n    for(int i = 0; i < num_elements_signed; ++i) {\n#ifdef __USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR\n        data[i] *= mult;\n#else\n        data(i) *= mult;\n#endif\n    }\n}\n\n// NOTE: explicit template specialization for the case of std::vector<complex_type>\n// because it is used in 2D and 3D FFT for both array classes with square and round\n// brackets of element access operator; I need to guarantee that sub-FFT 1D will\n// use square brackets for element access operator anyway. It is pretty ugly\n// to duplicate the code but I haven't found more elegant solution.\ntemplate <>\ninline void scaleValues<std::vector<complex_type> >(std::vector<complex_type> & data,\n                                                    const size_t num_elements)\n{\n    real_type mult = 1.0 / num_elements;\n    int num_elements_signed = static_cast<int>(num_elements);\n\n#ifndef __clang__\n#ifdef __USE_OPENMP\n#pragma omp parallel for\n#endif\n#endif\n    for(int i = 0; i < num_elements_signed; ++i) {\n        data[i] *= mult;\n    }\n}\n\ntemplate <class TComplexArray1D>\ninline void bufferExchangeHelper(TComplexArray1D & data, const size_t index_from,\n                                 const size_t index_to, complex_type & buf)\n{\n#ifdef __USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR\n    buf = data[index_from];\n    data[index_from] = data[index_to];\n    data[index_to]= buf;\n#else\n    buf = data(index_from);\n    data(index_from) = data(index_to);\n    data(index_to)= buf;\n#endif\n}\n\n// NOTE: explicit template specialization for the case of std::vector<complex_type>\n// because it is used in 2D and 3D FFT for both array classes with square and round\n// brackets of element access operator; I need to guarantee that sub-FFT 1D will\n// use square brackets for element access operator anyway. It is pretty ugly\n// to duplicate the code but I haven't found more elegant solution.\ntemplate <>\ninline void bufferExchangeHelper<std::vector<complex_type> >(std::vector<complex_type> & data,\n                                                             const size_t index_from,\n                                                             const size_t index_to,\n                                                             complex_type & buf)\n{\n    buf = data[index_from];\n    data[index_from] = data[index_to];\n    data[index_to]= buf;\n}\n\ntemplate <class TComplexArray1D>\nvoid rearrangeData(TComplexArray1D & data, const size_t num_elements)\n{\n    complex_type buf;\n\n    size_t target_index = 0;\n    size_t bit_mask;\n\n    for (size_t i = 0; i < num_elements; ++i)\n    {\n        if (target_index > i)\n        {\n            bufferExchangeHelper(data, target_index, i, buf);\n        }\n\n        // Initialize the bit mask\n        bit_mask = num_elements;\n\n        // While bit is 1\n        while (target_index & (bit_mask >>= 1)) // bit_mask = bit_mask >> 1\n        {\n            // Drop bit:\n            // & is bitwise AND,\n            // ~ is bitwise NOT\n            target_index &= ~bit_mask; // target_index = target_index & (~bit_mask)\n        }\n\n        // | is bitwise OR\n        target_index |= bit_mask; // target_index = target_index | bit_mask\n    }\n}\n\ntemplate <class TComplexArray1D>\ninline void fftTransformHelper(TComplexArray1D & data, const size_t match,\n                               const size_t k, complex_type & product,\n                               const complex_type factor)\n{\n#ifdef __USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR\n    product = data[match] * factor;\n    data[match] = data[k] - product;\n    data[k] += product;\n#else\n    product = data(match) * factor;\n    data(match) = data(k) - product;\n    data(k) += product;\n#endif\n}\n\n// NOTE: explicit template specialization for the case of std::vector<complex_type>\n// because it is used in 2D and 3D FFT for both array classes with square and round\n// brackets of element access operator; I need to guarantee that sub-FFT 1D will\n// use square brackets for element access operator anyway. It is pretty ugly\n// to duplicate the code but I haven't found more elegant solution.\ntemplate <>\ninline void fftTransformHelper<std::vector<complex_type> >(std::vector<complex_type> & data,\n                                                           const size_t match,\n                                                           const size_t k,\n                                                           complex_type & product,\n                                                           const complex_type factor)\n{\n    product = data[match] * factor;\n    data[match] = data[k] - product;\n    data[k] += product;\n}\n\ntemplate <class TComplexArray1D>\nbool makeTransform(TComplexArray1D & data, const size_t num_elements,\n                   const FFT_direction fft_direction, const char *& error_description)\n{\n    using namespace error_handling;\n    using std::sin;\n\n    double local_pi;\n    switch(fft_direction)\n    {\n    case(FFT_FORWARD):\n        local_pi = -M_PI;\n        break;\n    case(FFT_BACKWARD):\n        local_pi = M_PI;\n        break;\n    default:\n        GetErrorDescription(EC_WRONG_FFT_DIRECTION, error_description);\n        return false;\n    }\n\n    // declare variables to cycle the bits of initial signal\n    size_t next, match;\n    real_type sine;\n    real_type delta;\n    complex_type mult, factor, product;\n\n    // NOTE: user's complex type should have constructor like\n    // \"complex(real, imag)\", where each of real and imag has\n    // real type.\n\n    // cycle for all bit positions of initial signal\n    for (size_t i = 1; i < num_elements; i <<= 1)\n    {\n        next = i << 1;  // getting the next bit\n        delta = local_pi / i;    // angle increasing\n        sine = sin(0.5 * delta);    // supplementary sin\n        // multiplier for trigonometric recurrence\n        mult = complex_type(-2.0 * sine * sine, sin(delta));\n        factor = 1.0;   // start transform factor\n\n        for (size_t j = 0; j < i; ++j) // iterations through groups\n                                       // with different transform factors\n        {\n            for (size_t k = j; k < num_elements; k += next) // iterations through\n                                                            // pairs within group\n            {\n                match = k + i;\n                fftTransformHelper(data, match, k, product, factor);\n            }\n            factor = mult * factor + factor;\n        }\n    }\n\n    return true;\n}\n\n// Generic template for complex FFT followed by its explicit specializations\ntemplate <class TComplexArray, int NumDims>\nstruct CFFT\n{};\n\n// 1D FFT:\ntemplate <class TComplexArray1D>\nstruct CFFT<TComplexArray1D,1>\n{\n    // NOTE: passing by pointer is needed to avoid using element access operator\n    static bool FFT_inplace(TComplexArray1D & data, const size_t size,\n                            const FFT_direction fft_direction,\n                            const char *& error_description)\n    {\n        if(!checkNumElements(size, error_description)) {\n            return false;\n        }\n\n        rearrangeData(data, size);\n\n        if(!makeTransform(data, size, fft_direction, error_description)) {\n            return false;\n        }\n\n        if (FFT_BACKWARD == fft_direction) {\n            scaleValues(data, size);\n        }\n\n        return true;\n    }\n};\n\n// 2D FFT\ntemplate <class TComplexArray2D>\nstruct CFFT<TComplexArray2D,2>\n{\n    static bool FFT_inplace(TComplexArray2D & data, const size_t size1, const size_t size2,\n                            const FFT_direction fft_direction, const char *& error_description)\n    {\n        int n_rows = static_cast<int>(size1);\n        int n_cols = static_cast<int>(size2);\n\n        // fft for columns\n        std::vector<complex_type> subarray(n_rows); // each column has n_rows elements\n\n        for(int j = 0; j < n_cols; ++j)\n        {\n#ifndef __clang__\n#ifdef __USE_OPENMP\n#pragma omp parallel for\n#endif\n#endif\n            for(int i = 0; i < n_rows; ++i) {\n#ifdef __USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR\n                subarray[i] = data[i][j];\n#else\n                subarray[i] = data(i,j);\n#endif\n            }\n\n            if(!CFFT<std::vector<complex_type>,1>::FFT_inplace(subarray, size1,\n                                                               fft_direction,\n                                                               error_description))\n            {\n                return false;\n            }\n\n#ifndef __clang__\n#ifdef __USE_OPENMP\n#pragma omp parallel for\n#endif\n#endif\n            for(int i = 0; i < n_rows; ++i) {\n#ifdef __USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR\n                data[i][j] = subarray[i];\n#else\n                data(i,j) = subarray[i];\n#endif\n            }\n        }\n\n        // fft for rows\n        subarray.resize(n_cols); // each row has n_cols elements\n\n        for(int i = 0; i < n_rows; ++i)\n        {\n#ifndef __clang__\n#ifdef __USE_OPENMP\n#pragma omp parallel for\n#endif\n#endif\n            for(int j = 0; j < n_cols; ++j) {\n#ifdef __USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR\n                subarray[j] = data[i][j];\n#else\n                subarray[j] = data(i,j);\n#endif\n            }\n\n            if(!CFFT<std::vector<complex_type>,1>::FFT_inplace(subarray, size2,\n                                                               fft_direction,\n                                                               error_description))\n            {\n                return false;\n            }\n\n#ifndef __clang__\n#ifdef __USE_OPENMP\n#pragma omp parallel for\n#endif\n#endif\n            for(int j = 0; j < n_cols; ++j) {\n#ifdef __USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR\n                data[i][j] = subarray[j];\n#else\n                data(i,j) = subarray[j];\n#endif\n            }\n        }\n\n        return true;\n    }\n};\n\n// 3D FFT\ntemplate <class TComplexArray3D>\nstruct CFFT<TComplexArray3D,3>\n{\n    static bool FFT_inplace(TComplexArray3D & data, const size_t size1, const size_t size2,\n                            const size_t size3, const FFT_direction fft_direction,\n                            const char *& error_description)\n    {\n        int n_rows  = static_cast<int>(size1);\n        int n_cols  = static_cast<int>(size2);\n        int n_depth = static_cast<int>(size3);\n\n        std::vector<complex_type> subarray(n_rows); // for fft for columns: each column has n_rows elements\n\n        for(int k = 0; k < n_depth; ++k) // for all depth layers\n        {\n            // fft for columns\n            for(int j = 0; j < n_cols; ++j)\n            {\n#ifndef __clang__\n#ifdef __USE_OPENMP\n#pragma omp parallel for\n#endif\n#endif\n                for(int i = 0; i < n_rows; ++i) {\n#ifdef __USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR\n                    subarray[i] = data[i][j][k];\n#else\n                    subarray[i] = data(i,j,k);\n#endif\n                }\n\n                if(!CFFT<std::vector<complex_type>,1>::FFT_inplace(subarray, size1,\n                                                                   fft_direction,\n                                                                   error_description))\n                {\n                    return false;\n                }\n\n#ifndef __clang__\n#ifdef __USE_OPENMP\n#pragma omp parallel for\n#endif\n#endif\n                for(int i = 0; i < n_rows; ++i) {\n#ifdef __USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR\n                    data[i][j][k] = subarray[i];\n#else\n                    data(i,j,k) = subarray[i];\n#endif\n                }\n            }\n        }\n\n        subarray.resize(n_cols); // for fft for rows: each row has n_cols elements\n\n        for(int k = 0; k < n_depth; ++k) // for all depth layers\n        {\n            // fft for rows\n            for(int i = 0; i < n_rows; ++i)\n            {\n#ifndef __clang__\n#ifdef __USE_OPENMP\n#pragma omp parallel for\n#endif\n#endif\n                for(int j = 0; j < n_cols; ++j) {\n#ifdef __USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR\n                    subarray[j] = data[i][j][k];\n#else\n                    subarray[j] = data(i,j,k);\n#endif\n                }\n\n                if(!CFFT<std::vector<complex_type>,1>::FFT_inplace(subarray, size2,\n                                                                   fft_direction,\n                                                                   error_description))\n                {\n                    return false;\n                }\n\n#ifndef __clang__\n#ifdef __USE_OPENMP\n#pragma omp parallel for\n#endif\n#endif\n                for(int j = 0; j < n_cols; ++j) {\n#ifdef __USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR\n                    data[i][j][k] = subarray[j];\n#else\n                    data(i,j,k) = subarray[j];\n#endif\n                }\n            }\n        }\n\n        // fft for depth\n        subarray.resize(n_depth); // each depth strip contains n_depth elements\n\n        for(int i = 0; i < n_rows; ++i) // for all rows layers\n        {\n            for(int j = 0; j < n_cols; ++j) // for all cols layers\n            {\n#ifndef __clang__\n#ifdef __USE_OPENMP\n#pragma omp parallel for\n#endif\n#endif\n                for(int k = 0; k < n_depth; ++k) {\n#ifdef __USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR\n                    subarray[k] = data[i][j][k];\n#else\n                    subarray[k] = data(i,j,k);\n#endif\n                }\n\n                if(!CFFT<std::vector<complex_type>,1>::FFT_inplace(subarray, size3,\n                                                                   fft_direction,\n                                                                   error_description))\n                {\n                    return false;\n                }\n\n#ifndef __clang__\n#ifdef __USE_OPENMP\n#pragma omp parallel for\n#endif\n#endif\n                for(int k = 0; k < n_depth; ++k) {\n#ifdef __USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR\n                    data[i][j][k] = subarray[k];\n#else\n                    data(i,j,k) = subarray[k];\n#endif\n                }\n            }\n        }\n\n        return true;\n    }\n};\n\n} // namespace impl\n} // namespace simple_fft\n\n#endif // __SIMPLE_FFT__FFT_IMPL_HPP__\n"
  },
  {
    "path": "include/simple_fft/fft_settings.h",
    "content": "/**\r\n * Copyright (c) 2013-2020 Dmitry Ivanov\r\n *\r\n * This file is a part of Simple-FFT project and is distributed under the terms\r\n * of MIT license: https://opensource.org/licenses/MIT\r\n */\r\n\r\n// In this file you can alter some settings of the library:\r\n// 1) Specify the desired real and complex types by typedef'ing real_type and complex_type.\r\n//    By default real_type is double and complex_type is std::complex<real_type>.\r\n// 2) If the array class uses square brackets for element access operator, define\r\n//    the macro __USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR\r\n\r\n#ifndef __SIMPLE_FFT__FFT_SETTINGS_H__\r\n#define __SIMPLE_FFT__FFT_SETTINGS_H__\r\n\r\n#include <complex>\r\n\r\ntypedef double real_type;\r\ntypedef std::complex<real_type> complex_type;\r\n\r\n//#ifndef __USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR\r\n//#define __USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR\r\n//#endif\r\n\r\n#endif // __SIMPLE_FFT__FFT_SETTINGS_H__\r\n"
  },
  {
    "path": "unit-tests/test_fft.cpp",
    "content": "#include \"test_fft.h\"\n#include \"../include/simple_fft/fft_settings.h\"\n\nnamespace simple_fft {\nnamespace fft_test {\n\nvoid makeGrid1D(const real_type grid_min, const real_type grid_max,\n                const int n_grid_points, std::vector<real_type> & grid)\n{\n    grid.resize(n_grid_points);\n\n    real_type grid_length = grid_max - grid_min;\n    size_t n_intervals = n_grid_points - 1;\n\n#ifndef __clang__\n#ifdef __USE_OPENMP\n#pragma omp parallel for\n#endif\n#endif\n    for(int i = 0; i < n_grid_points; ++i) {\n        grid[i] = grid_min + grid_length * i / n_intervals;\n    }\n}\n\nvoid makeGridsForPulse(std::vector<real_type> & t, std::vector<real_type> & x)\n{\n    using namespace pulse_params;\n\n    // Time grid parameters\n    const real_type tmin_norm = -8 * t0 * w0;   // normalized min time value\n    const real_type tmax_norm =  8 * t0 * w0;   // normalized max time value\n\n    // Transverse spatial x grid parameters\n    const real_type xmin = -50 * x0;\n    const real_type xmax =  50 * x0;\n\n    makeGrid1D(tmin_norm, tmax_norm, nt, t);\n    makeGrid1D(xmin, xmax, nx, x);\n}\n\nvoid makeGridsForPulse3D(std::vector<real_type> & t, std::vector<real_type> & x,\n                         std::vector<real_type> & y)\n{\n    makeGridsForPulse(t, x);\n\n    using namespace pulse_params;\n\n    // Transverse spatial y grid parameters\n    const real_type ymin = -50 * y0;\n    const real_type ymax =  50 * y0;\n\n    makeGrid1D(ymin, ymax, ny, y);\n}\n\n} // namespace fft_test\n} // namespace simple_fft\n"
  },
  {
    "path": "unit-tests/test_fft.h",
    "content": "/*\n * 1D, 2D and 3D electromagnetic fields of femtosecond laser pulses and\n * the respective spectra are considered for testing of FFT functions. This\n * file and test_fft.hpp contain respectively declaration and implementation of\n * common structs and functions used to test FFT with particular types of\n * multidimensional arrays\n */\n\n#ifndef __SIMPLE_FFT__UNIT_TESTS__TEST_FFT_H__\n#define __SIMPLE_FFT__UNIT_TESTS__TEST_FFT_H__\n\n#include \"../include/simple_fft/fft_settings.h\"\n#include <math.h>\n#include <vector>\n\nnamespace simple_fft {\nnamespace fft_test {\n\nenum\n{\n    SUCCESS = 0,\n    FAILURE = 1\n};\n\nnamespace pulse_params\n{\n#ifndef M_PI\n#define M_PI 3.1415926535897932\n#endif\n\n    // Femtosecond laser pulse parameters\n    const real_type c = 3e10;            // lightspeed in vacuum, [cm/sec]\n    const real_type t0 = 4e-15;          // pulse time duration, [sec]\n    const real_type lambda0 = 780e-7;    // pulse central wavelength, [cm]\n    const real_type x0 = 20 * lambda0;   // pulse spatial x size, [cm]\n    const real_type y0 = 20 * lambda0;   // pulse spatial y size, [cm]\n    const real_type w0 = 2.0 * M_PI * c / lambda0;  // pulse central frequency, [n.u.]\n\n    // Grids sizes\n    const size_t nt = 128, nx = 128, ny = 64;\n\n} // namespace pulse_params\n\nvoid makeGrid1D(const real_type grid_min, const real_type grid_max,\n                const int n_grid_points, std::vector<real_type> & grid);\n\nvoid makeGridsForPulse(std::vector<real_type> & t, std::vector<real_type> & x);\n\nvoid makeGridsForPulse3D(std::vector<real_type> & t, std::vector<real_type> & x,\n                         std::vector<real_type> & y);\n\ntemplate <class TArray1D, class TArray2D, bool real_initial_signal>\nstruct CMakeInitialPulses\n{\n    static void makeInitialPulses(TArray1D & pulse1D, TArray2D & pulse2D);\n};\n\ntemplate <class TArray1D, class TArray2D, class TArray3D, bool real_initial_signal>\nstruct CMakeInitialPulses3D\n{\n    static void makeInitialPulses(TArray1D & pulse1D, TArray2D & pulse2D,\n                                  TArray3D & pulse3D);\n};\n\ntemplate <class TField1D, class TComplexArray1D, class TField2D, class TComplexArray2D>\nstruct CTestFFT\n{\n    static int testFFT(const TField1D & initial_field_1D,\n                       const TField2D & initial_field_2D,\n                       TComplexArray1D & spectrum_1D,\n                       TComplexArray1D & restored_field_1D,\n                       TComplexArray2D & spectrum_2D,\n                       TComplexArray2D & restored_field_2D,\n                       const std::vector<real_type> & t,\n                       const std::vector<real_type> & x);\n};\n\ntemplate <class TField1D, class TComplexArray1D, class TField2D, class TComplexArray2D,\n          class TField3D, class TComplexArray3D>\nstruct CTestFFT3D\n{\n    static int testFFT(const TField1D & initial_field_1D,\n                       const TField2D & initial_field_2D,\n                       const TField3D & initial_field_3D,\n                       TComplexArray1D & spectrum_1D,\n                       TComplexArray1D & restored_field_1D,\n                       TComplexArray2D & spectrum_2D,\n                       TComplexArray2D & restored_field_2D,\n                       TComplexArray3D & spectrum_3D,\n                       TComplexArray3D & restored_field_3D,\n                       const std::vector<real_type> & t,\n                       const std::vector<real_type> & x,\n                       const std::vector<real_type> & y);\n};\n\ntemplate <class TRealArray1D, class TComplexArray1D, class TRealArray2D, class TComplexArray2D>\nbool commonPartsForTests(TRealArray1D & E1_real, TRealArray2D & E2_real,\n                         TComplexArray1D & E1_complex, TComplexArray2D & E2_complex,\n                         TComplexArray1D & G1, TComplexArray2D & G2,\n                         TComplexArray1D & E1_restored, TComplexArray2D & E2_restored,\n                         const std::vector<real_type> & t, const std::vector<real_type> & x);\n\ntemplate <class TRealArray1D, class TComplexArray1D, class TRealArray2D,\n          class TComplexArray2D, class TRealArray3D, class TComplexArray3D>\nbool commonPartsForTests3D(TRealArray1D & E1_real, TRealArray2D & E2_real, TRealArray3D & E3_real,\n                           TComplexArray1D & E1_complex, TComplexArray2D & E2_complex,\n                           TComplexArray3D & E3_complex, TComplexArray1D & G1,\n                           TComplexArray2D & G2, TComplexArray3D & G3,\n                           TComplexArray1D & E1_restored, TComplexArray2D & E2_restored,\n                           TComplexArray3D & E3_restored, const std::vector<real_type> & t,\n                           const std::vector<real_type> & x, const std::vector<real_type> & y);\n\n// Declarations for functions used for FFT tests with different array types\n\n// Native C++ arrays\nint testNativeArraysFFT();\nint testStdVectorsFFT();\n\n// Boost multiarray and/or matrix from ublas:\n#ifdef HAS_BOOST_PACKAGE\n#ifdef HAS_BOOST_MULTI_ARRAY\nint testBoostMultiArray();\n#endif // HAS_BOOST_MULTI_ARRAY\n\n#ifdef HAS_BOOST_UBLAS\nint testBoostUblas(); // only vector and matrix\n#endif // HAS_BOOST_UBLAS\n\n#endif // HAS_BOOST_PACKAGE\n\n// Eigen 3x library\n#ifdef HAS_EIGEN\nint testEigen();\n#endif\n\n// marray\n#ifdef HAS_MARRAY\nint testMarray();\n#endif\n\n// Armadillo C++\n#ifdef HAS_ARMADILLO\nint testArmadillo();\n#endif\n\n// Blitz++\n#ifdef HAS_BLITZ\nint testBlitz();\n#endif\n\n#ifdef HAS_STLSOFT\nint testStlSoft();\n#endif\n\n} // namespace fft_test\n} // namespace simple_fft\n\n#endif // __SIMPLE_FFT__UNIT_TESTS__TEST_FFT_H__\n\n#include \"test_fft.hpp\"\n"
  },
  {
    "path": "unit-tests/test_fft.hpp",
    "content": "#ifndef __SIMPLE_FFT__UNIT_TESTS__TEST_FFT_HPP__\r\n#define __SIMPLE_FFT__UNIT_TESTS__TEST_FFT_HPP__\r\n\r\n#include \"test_fft.h\"\r\n#include \"../include/simple_fft/fft.h\"\r\n#include \"../include/simple_fft/check_fft.hpp\"\r\n#include <iostream>\r\n#include <iomanip>\r\n\r\nnamespace simple_fft {\r\nnamespace fft_test {\r\n\r\n// Make initial real_type pulses - explicit template specialization of struct\r\ntemplate  <class TArray1D, class TArray2D>\r\nstruct CMakeInitialPulses<TArray1D,TArray2D,true>\r\n{\r\n    static void makeInitialPulses(TArray1D & pulse1D, TArray2D & pulse2D)\r\n    {\r\n        using namespace pulse_params;\r\n\r\n        std::vector<real_type> t, x;\r\n        makeGridsForPulse(t, x);\r\n\r\n        const int nt = t.size();\r\n        const int nx = x.size();\r\n\r\n        std::cout << \"FFT test: creating real 1D pulse.\" << std::endl;\r\n\r\n#ifndef __clang__\r\n#ifdef __USE_OPENMP\r\n#pragma omp parallel for\r\n#endif\r\n#endif\r\n        for(int i = 0; i < nt; ++i) {\r\n#ifdef __USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR\r\n            pulse1D[i] = std::exp(-2 * std::pow(t[i] / (w0 * t0), 2)) * sin(t[i]);\r\n#else\r\n            pulse1D(i) = std::exp(-2 * std::pow(t[i] / (w0 * t0), 2)) * sin(t[i]);\r\n#endif\r\n        }\r\n\r\n        std::cout << \"Done.\" << std::endl;\r\n\r\n        std::cout << \"FFT test: creating real 2D pulse.\" << std::endl;\r\n\r\n#ifndef __clang__\r\n#ifdef __USE_OPENMP\r\n#pragma omp parallel for\r\n#endif\r\n#endif\r\n        for(int i = 0; i < nt; ++i) {\r\n            for(int j = 0; j < nx; ++j) {\r\n#ifdef __USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR\r\n                pulse2D[i][j] = std::exp(-2 * std::pow(x[j] / x0, 2)) *\r\n                                std::exp(-2 * std::pow(t[i] / (w0 * t0), 2)) * sin(t[i]);\r\n#else\r\n                pulse2D(i,j) = std::exp(-2 * std::pow(x[j] / x0, 2)) *\r\n                               std::exp(-2 * std::pow(t[i] / (w0 * t0), 2)) * sin(t[i]);\r\n#endif\r\n            }\r\n        }\r\n\r\n        std::cout << \"Done.\" << std::endl;\r\n    }\r\n};\r\n\r\ntemplate  <class TArray1D, class TArray2D>\r\nstruct CMakeInitialPulses<TArray1D,TArray2D,false>\r\n{\r\n    static void makeInitialPulses(TArray1D & pulse1D, TArray2D & pulse2D)\r\n    {\r\n        using namespace pulse_params;\r\n\r\n        std::vector<real_type> t, x;\r\n        makeGridsForPulse(t, x);\r\n\r\n        const int nt = t.size();\r\n        const int nx = x.size();\r\n\r\n        std::cout << \"FFT test: creating real 1D pulse.\" << std::endl;\r\n\r\n#ifndef __clang__\r\n#ifdef __USE_OPENMP\r\n#pragma omp parallel for\r\n#endif\r\n#endif\r\n        for(int i = 0; i < nt; ++i) {\r\n#ifdef __USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR\r\n            pulse1D[i] = complex_type(std::exp(-2 * std::pow(t[i] / (w0 * t0), 2)) * sin(t[i]), 0.0);\r\n#else\r\n            pulse1D(i) = complex_type(std::exp(-2 * std::pow(t[i] / (w0 * t0), 2)) * sin(t[i]), 0.0);\r\n#endif\r\n        }\r\n\r\n        std::cout << \"Done.\" << std::endl;\r\n\r\n        std::cout << \"FFT test: creating real 2D pulse.\" << std::endl;\r\n\r\n#ifndef __clang__\r\n#ifdef __USE_OPENMP\r\n#pragma omp parallel for\r\n#endif\r\n#endif\r\n        for(int i = 0; i < nt; ++i) {\r\n            for(int j = 0; j < nx; ++j) {\r\n#ifdef __USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR\r\n                pulse2D[i][j] = complex_type(std::exp(-2 * std::pow(x[j] / x0, 2)) *\r\n                                             std::exp(-2 * std::pow(t[i] / (w0 * t0), 2)) *\r\n                                             sin(t[i]), 0.0);\r\n#else\r\n                pulse2D(i,j) = complex_type(std::exp(-2 * std::pow(x[j] / x0, 2)) *\r\n                                            std::exp(-2 * std::pow(t[i] / (w0 * t0), 2)) *\r\n                                            sin(t[i]), 0.0);\r\n#endif\r\n            }\r\n        }\r\n\r\n        std::cout << \"Done.\" << std::endl;\r\n    }\r\n};\r\n\r\n// Make initial real_type pulses - explicit template specialization of struct\r\ntemplate <class TArray1D, class TArray2D, class TArray3D>\r\nstruct CMakeInitialPulses3D<TArray1D,TArray2D,TArray3D,true>\r\n{\r\n    static void makeInitialPulses(TArray1D & pulse1D, TArray2D & pulse2D, TArray3D & pulse3D)\r\n    {\r\n        using namespace pulse_params;\r\n\r\n        std::vector<real_type> t, x, y;\r\n        makeGridsForPulse3D(t, x, y);\r\n\r\n        const int nt = t.size();\r\n        const int nx = x.size();\r\n        const int ny = y.size();\r\n\r\n        CMakeInitialPulses<TArray1D,TArray2D,true>::makeInitialPulses(pulse1D, pulse2D);\r\n\r\n        std::cout << \"FFT test: creating real 3D pulse.\" << std::endl;\r\n\r\n#ifndef __clang__\r\n#ifdef __USE_OPENMP\r\n#pragma omp parallel for\r\n#endif\r\n#endif\r\n        for(int i = 0; i < nt; ++i) {\r\n            for(int j = 0; j < nx; ++j) {\r\n                for(int k = 0; k < ny; ++k) {\r\n#ifdef __USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR\r\n                    pulse3D[i][j][k] = std::exp(-2 * std::pow(x[j] / x0, 2)) *\r\n                                       std::exp(-2 * std::pow(y[k] / y0, 2)) *\r\n                                       std::exp(-2 * std::pow(t[i] / (w0 * t0), 2)) *\r\n                                       sin(t[i]);\r\n#else\r\n                    pulse3D(i,j,k) = std::exp(-2 * std::pow(x[j] / x0, 2)) *\r\n                                     std::exp(-2 * std::pow(y[k] / y0, 2)) *\r\n                                     std::exp(-2 * std::pow(t[i] / (w0 * t0), 2)) *\r\n                                     sin(t[i]);\r\n#endif\r\n                }\r\n            }\r\n        }\r\n\r\n        std::cout << \"Done.\" << std::endl;\r\n    }\r\n};\r\n\r\n// Make initial complex_type pulses - explicit template specialization of struct\r\ntemplate <class TArray1D, class TArray2D, class TArray3D>\r\nstruct CMakeInitialPulses3D<TArray1D,TArray2D,TArray3D,false>\r\n{\r\n    static void makeInitialPulses(TArray1D & pulse1D, TArray2D & pulse2D, TArray3D & pulse3D)\r\n    {\r\n        using namespace pulse_params;\r\n\r\n        std::vector<real_type> t, x, y;\r\n        makeGridsForPulse3D(t, x, y);\r\n\r\n        const int nt = t.size();\r\n        const int nx = x.size();\r\n        const int ny = y.size();\r\n\r\n        CMakeInitialPulses<TArray1D,TArray2D,false>::makeInitialPulses(pulse1D, pulse2D);\r\n\r\n        std::cout << \"FFT test: creating real 3D pulse.\" << std::endl;\r\n\r\n#ifndef __clang__\r\n#ifdef __USE_OPENMP\r\n#pragma omp parallel for\r\n#endif\r\n#endif\r\n        for(int i = 0; i < nt; ++i) {\r\n            for(int j = 0; j < nx; ++j) {\r\n                for(int k = 0; k < ny; ++k) {\r\n#ifdef __USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR\r\n                    pulse3D[i][j][k] = complex_type(std::exp(-2 * std::pow(x[j] / x0, 2)) *\r\n                                                    std::exp(-2 * std::pow(y[k] / y0, 2)) *\r\n                                                    std::exp(-2 * std::pow(t[i] / (w0 * t0), 2)) *\r\n                                                    sin(t[i]), 0.0);\r\n#else\r\n                    pulse3D(i,j,k) = complex_type(std::exp(-2 * std::pow(x[j] / x0, 2)) *\r\n                                                  std::exp(-2 * std::pow(y[k] / y0, 2)) *\r\n                                                  std::exp(-2 * std::pow(t[i] / (w0 * t0), 2)) *\r\n                                                  sin(t[i]), 0.0);\r\n#endif\r\n                }\r\n            }\r\n        }\r\n\r\n        std::cout << \"Done.\" << std::endl;\r\n    }\r\n};\r\n\r\ntemplate <class TField1D, class TComplexArray1D, class TField2D, class TComplexArray2D>\r\nint CTestFFT<TField1D,TComplexArray1D,TField2D,TComplexArray2D>::testFFT(const TField1D & initial_field_1D,\r\n                                                                         const TField2D & initial_field_2D,\r\n                                                                         TComplexArray1D & spectrum_1D,\r\n                                                                         TComplexArray1D & restored_field_1D,\r\n                                                                         TComplexArray2D & spectrum_2D,\r\n                                                                         TComplexArray2D & restored_field_2D,\r\n                                                                         const std::vector<real_type> & t,\r\n                                                                         const std::vector<real_type> & x)\r\n{\r\n#ifndef M_PI\r\n#define M_PI 3.1415926535897932\r\n#endif\r\n\r\n    bool res;\r\n    const char * error_description = 0;\r\n    const real_type relative_tolerance = 1e-4;\r\n    real_type discrepancy;\r\n\r\n    std::cout << std::setprecision(20);\r\n\r\n    int grid_size_t = static_cast<int>(t.size());\r\n    int grid_size_x = static_cast<int>(x.size());\r\n\r\n    // Testing 1D complex FFT and IFFT\r\n    std::cout << \"FFT test: testing 1D forward FFT.\" << std::endl;\r\n\r\n    res = simple_fft::FFT(initial_field_1D, spectrum_1D, static_cast<size_t>(grid_size_t),\r\n                          error_description);\r\n    if (!res) {\r\n        std::cout << \"FFT test: 1D forward FFT returned with error! Error description: \"\r\n                  << error_description << std::endl;\r\n        return FAILURE;\r\n    }\r\n\r\n    std::cout << \"Done.\" << std::endl;\r\n    std::cout << \"FFT test: checking 1D Parseval theorem with relative tolerance = \"\r\n              << relative_tolerance <<  std::endl;\r\n\r\n    res = simple_fft::check_fft::checkParsevalTheorem(initial_field_1D, spectrum_1D,\r\n                                                      static_cast<size_t>(grid_size_t),\r\n                                                      relative_tolerance, discrepancy,\r\n                                                      error_description);\r\n    if (!res) {\r\n        std::cout << \"FFT test: checking 1D Parseval theorem returned with error! \"\r\n                  << \"Error description: \" << error_description << \", discrepancy = \"\r\n                  << discrepancy << std::endl;\r\n        return FAILURE;\r\n    }\r\n\r\n    std::cout << \"FFT test: checking 1D Parseval theorem completed successfully, \"\r\n              << \"discrepancy = \" << discrepancy << std::endl;\r\n\r\n    std::cout << \"FFT test: testing 1D inverse FFT.\" << std::endl;\r\n\r\n    res = simple_fft::IFFT(spectrum_1D, restored_field_1D, static_cast<size_t>(grid_size_t),\r\n                           error_description);\r\n    if (!res) {\r\n        std::cout << \"FFT test: 1D inverse FFT returned with error! \"\r\n                  << \"Error description: \" << error_description << std::endl;\r\n        return FAILURE;\r\n    }\r\n\r\n    std::cout << \"Done.\" << std::endl;\r\n    std::cout << \"FFT test: checking 1D energy conservation law with relative tolerance = \"\r\n              << relative_tolerance << std::endl;\r\n\r\n    res = simple_fft::check_fft::checkEnergyConservation(initial_field_1D, restored_field_1D,\r\n                                                         static_cast<size_t>(grid_size_t),\r\n                                                         relative_tolerance, discrepancy,\r\n                                                         error_description);\r\n    if (!res) {\r\n        std::cout << \"FFT test: checking 1D energy conservation law returned with error! \"\r\n                  << \"Error description: \" << error_description\r\n                  << \", discrepancy = \" << discrepancy << std::endl;\r\n        return FAILURE;\r\n    }\r\n\r\n    std::cout << \"FFT test: checking 1D energy conservation law completed successfully, \"\r\n              << \"discrepancy = \" << discrepancy << std::endl;\r\n\r\n    std::cout << \"FFT test: checking equality of 1D arrays after FFT and IFFT with \"\r\n              << \"relative tolerance = \" << relative_tolerance << std::endl;\r\n\r\n    discrepancy = 0.0;\r\n    res = simple_fft::check_fft::checkEquality(initial_field_1D, restored_field_1D,\r\n                                               static_cast<size_t>(grid_size_t),\r\n                                               relative_tolerance, discrepancy,\r\n                                               error_description);\r\n    if (!res) {\r\n        std::cout << \"FFT test: checking 1D equality test returned with error! \"\r\n                  << \"Error description: \" << error_description\r\n                  << \", discrepancy = \" << discrepancy << std::endl;\r\n        return FAILURE;\r\n    }\r\n\r\n    std::cout << \"FFT test: checking equality of 1D arrays after FFT and IFFT completed \"\r\n              << \"successfully, discrepancy = \" << discrepancy << std::endl;\r\n\r\n    // Testing 2D FFT and IFFT\r\n    std::cout << \"Testing 2D forward FFT.\" << std::endl;\r\n\r\n    res = simple_fft::FFT(initial_field_2D, spectrum_2D, static_cast<size_t>(grid_size_t),\r\n                          static_cast<size_t>(grid_size_x), error_description);\r\n    if (!res) {\r\n        std::cout << \"FFT test: forward 2D FFT returned with error! Error description: \"\r\n                  << error_description << std::endl;\r\n        return FAILURE;\r\n    }\r\n\r\n    std::cout << \"Done.\" << std::endl;\r\n    std::cout << \"FFT test: checking 2D Parseval theorem with relative tolerance = \"\r\n              << relative_tolerance << std::endl;\r\n\r\n    res = simple_fft::check_fft::checkParsevalTheorem(initial_field_2D, spectrum_2D,\r\n                                                      static_cast<size_t>(grid_size_t),\r\n                                                      static_cast<size_t>(grid_size_x),\r\n                                                      relative_tolerance, discrepancy,\r\n                                                      error_description);\r\n    if (!res) {\r\n        std::cout << \"FFT test: checking 2D Parseval theorem returned with error! \"\r\n                  << \"Error description: \" << error_description\r\n                  << \", discrepancy = \" << discrepancy << std::endl;\r\n        return FAILURE;\r\n    }\r\n\r\n    std::cout << \"FFT test: checking 2D Parseval theorem completed successfully, \"\r\n              << \"discrepancy = \" << discrepancy << std::endl;\r\n    std::cout << \"FFT test: testing inverse 2D FFT.\" << std::endl;\r\n\r\n    res = simple_fft::IFFT(spectrum_2D, restored_field_2D, static_cast<size_t>(grid_size_t),\r\n                           static_cast<size_t>(grid_size_x), error_description);\r\n    if (!res) {\r\n        std::cout << \"FFT test: inverse 2D FFT returned with error! Error description: \"\r\n                  << error_description << std::endl;\r\n        return FAILURE;\r\n    }\r\n\r\n    std::cout << \"Done.\" << std::endl;\r\n    std::cout << \"FFT test: checking 2D energy conservation law with relative tolerance = \"\r\n              << relative_tolerance << std::endl;\r\n\r\n    res = simple_fft::check_fft::checkEnergyConservation(initial_field_2D, restored_field_2D,\r\n                                                         static_cast<size_t>(grid_size_t),\r\n                                                         static_cast<size_t>(grid_size_x),\r\n                                                         relative_tolerance, discrepancy,\r\n                                                         error_description);\r\n    if (!res) {\r\n        std::cout << \"FFT test: checking 2D energy conservation law returned with error! \"\r\n                  << \"Error description: \" << error_description\r\n                  << \", discrepancy = \" << discrepancy << std::endl;\r\n        return FAILURE;\r\n    }\r\n\r\n    std::cout << \"FFT test: checking 2D energy conservation law completed successfully, \"\r\n                  << \"discrepancy = \" << discrepancy << std::endl;\r\n\r\n    std::cout << \"FFT test: checking equality of 2D arrays after FFT and IFFT with \"\r\n              << \"relative tolerance = \" << relative_tolerance << std::endl;\r\n\r\n    discrepancy = 0.0;\r\n    res = simple_fft::check_fft::checkEquality(initial_field_2D, restored_field_2D,\r\n                                               static_cast<size_t>(grid_size_t),\r\n                                               static_cast<size_t>(grid_size_x),\r\n                                               relative_tolerance, discrepancy,\r\n                                               error_description);\r\n    if (!res) {\r\n        std::cout << \"FFT test: checking 2D equality test returned with error! \"\r\n                  << \"Error description: \" << error_description\r\n                  << \", discrepancy = \" << discrepancy << std::endl;\r\n        return FAILURE;\r\n    }\r\n\r\n    std::cout << \"FFT test: checking equality of 2D arrays after FFT and IFFT completed \"\r\n              << \"successfully, discrepancy = \" << discrepancy << std::endl;\r\n\r\n    std::cout << \"FFT test: 1D and 2D FFT and IFFT tests completed successfully!\"\r\n              << std::endl;\r\n\r\n    return SUCCESS;\r\n}\r\n\r\ntemplate <class TField1D, class TComplexArray1D, class TField2D, class TComplexArray2D,\r\n          class TField3D, class TComplexArray3D>\r\nint CTestFFT3D<TField1D,TComplexArray1D,TField2D,TComplexArray2D,TField3D,\r\n               TComplexArray3D>::testFFT(const TField1D & initial_field_1D,\r\n                                         const TField2D & initial_field_2D,\r\n                                         const TField3D & initial_field_3D,\r\n                                         TComplexArray1D & spectrum_1D,\r\n                                         TComplexArray1D & restored_field_1D,\r\n                                         TComplexArray2D & spectrum_2D,\r\n                                         TComplexArray2D & restored_field_2D,\r\n                                         TComplexArray3D & spectrum_3D,\r\n                                         TComplexArray3D & restored_field_3D,\r\n                                         const std::vector<real_type> & t,\r\n                                         const std::vector<real_type> & x,\r\n                                         const std::vector<real_type> & y)\r\n{\r\n#ifndef M_PI\r\n#define M_PI 3.1415926535897932\r\n#endif\r\n    int res2D;\r\n    bool res;\r\n    const char * error_description = 0;\r\n    const real_type relative_tolerance = 1e-4;\r\n    real_type discrepancy;\r\n\r\n    std::cout << std::setprecision(20);\r\n\r\n    int grid_size_t = static_cast<int>(t.size());\r\n    int grid_size_x = static_cast<int>(x.size());\r\n    int grid_size_y = static_cast<int>(y.size());\r\n\r\n    // Test 1D and 2D FFT and IFFT\r\n    res2D = CTestFFT<TField1D,TComplexArray1D,TField2D,TComplexArray2D>::testFFT(initial_field_1D,\r\n                                    initial_field_2D, spectrum_1D, restored_field_1D, spectrum_2D,\r\n                                    restored_field_2D, t, x);\r\n    if (res2D != SUCCESS) {\r\n        return res2D;\r\n    }\r\n\r\n    // Test 3D FFT and IFFT\r\n    std::cout << \"Testing 3D forward FFT.\" << std::endl;\r\n\r\n    res = simple_fft::FFT(initial_field_3D, spectrum_3D, static_cast<size_t>(grid_size_t),\r\n                          static_cast<size_t>(grid_size_x), static_cast<size_t>(grid_size_y),\r\n                          error_description);\r\n    if (!res) {\r\n        std::cout << \"FFT test: forward 3D FFT returned with error! Error description: \"\r\n                  << error_description << std::endl;\r\n        return res; \r\n    }\r\n\r\n    std::cout << \"Done.\" << std::endl;\r\n    std::cout << \"FFT test: checking 3D Parseval theorem with relative tolerance = \"\r\n              << relative_tolerance << std::endl;\r\n\r\n    res = simple_fft::check_fft::checkParsevalTheorem(initial_field_3D, spectrum_3D,\r\n                                                      static_cast<size_t>(grid_size_t),\r\n                                                      static_cast<size_t>(grid_size_x),\r\n                                                      static_cast<size_t>(grid_size_y),\r\n                                                      relative_tolerance, discrepancy,\r\n                                                      error_description);\r\n    if (!res) {\r\n        std::cout << \"FFT test: checking 3D Parseval theorem returned with error! \"\r\n                  << \"Error description: \" << error_description\r\n                  << \", discrepancy = \" << discrepancy << std::endl;\r\n        return FAILURE;\r\n    }\r\n\r\n    std::cout << \"FFT test: checking 3D Parseval theorem completed successfully, \"\r\n              << \"discrepancy = \" << discrepancy << std::endl;\r\n    std::cout << \"FFT test: testing inverse 3D FFT.\" << std::endl;\r\n\r\n    res = simple_fft::IFFT(spectrum_3D, restored_field_3D, static_cast<size_t>(grid_size_t),\r\n                           static_cast<size_t>(grid_size_x), static_cast<size_t>(grid_size_y),\r\n                           error_description);\r\n    if (!res) {\r\n        std::cout << \"FFT test: inverse 3D FFT returned with error! \"\r\n                  << \"Error description: \" << error_description << std::endl;\r\n        return FAILURE;\r\n    }\r\n\r\n    std::cout << \"Done.\" << std::endl;\r\n    std::cout << \"FFT test: checking 3D energy conservation law wih relative tolerance = \"\r\n              << relative_tolerance << std::endl;\r\n\r\n    res = simple_fft::check_fft::checkEnergyConservation(initial_field_3D, restored_field_3D,\r\n                                                         static_cast<size_t>(grid_size_t),\r\n                                                         static_cast<size_t>(grid_size_x),\r\n                                                         static_cast<size_t>(grid_size_y),\r\n                                                         relative_tolerance, discrepancy,\r\n                                                         error_description);\r\n    if (!res) {\r\n        std::cout << \"FFT test: checking energy conservation law returned with error! \"\r\n                  << \"Error description: \" << error_description << std::endl;\r\n        return FAILURE;\r\n    }\r\n\r\n    std::cout << \"FFT test: checking 3D energy conservation law completed successfully, \"\r\n              << \"discrepancy = \" << discrepancy << std::endl;\r\n    \r\n    std::cout << \"FFT test: checking equality of 3D arrays after FFT and IFFT with \"\r\n              << \"relative tolerance = \" << relative_tolerance << std::endl;\r\n\r\n    discrepancy = 0.0;\r\n    res = simple_fft::check_fft::checkEquality(initial_field_3D, restored_field_3D,\r\n                                               static_cast<size_t>(grid_size_t),\r\n                                               static_cast<size_t>(grid_size_x),\r\n                                               static_cast<size_t>(grid_size_y),\r\n                                               relative_tolerance, discrepancy,\r\n                                               error_description);\r\n    if (!res) {\r\n        std::cout << \"FFT test: checking 3D equality test returned with error! \"\r\n                  << \"Error description: \" << error_description\r\n                  << \", discrepancy = \" << discrepancy << std::endl;\r\n        return FAILURE;\r\n    }\r\n\r\n    std::cout << \"FFT test: checking equality of 3D arrays after FFT and IFFT completed \"\r\n              << \"successfully, discrepancy = \" << discrepancy << std::endl;\r\n\r\n    std::cout << \"FFT test: 1D, 2D and 3D FFT and IFFT tests completed successfully!\"\r\n              << std::endl;\r\n\r\n    return SUCCESS;\r\n}\r\n\r\ntemplate <class TRealArray1D, class TComplexArray1D, class TRealArray2D, class TComplexArray2D>\r\nbool commonPartsForTests(TRealArray1D & E1_real, TRealArray2D & E2_real,\r\n                         TComplexArray1D & E1_complex, TComplexArray2D & E2_complex,\r\n                         TComplexArray1D & G1, TComplexArray2D & G2,\r\n                         TComplexArray1D & E1_restored, TComplexArray2D & E2_restored,\r\n                         const std::vector<real_type> & t, const std::vector<real_type> & x)\r\n{\r\n    // Make pulses\r\n    CMakeInitialPulses<TRealArray1D,TRealArray2D,true>::makeInitialPulses(E1_real, E2_real);\r\n    CMakeInitialPulses<TComplexArray1D,TComplexArray2D,false>::makeInitialPulses(E1_complex,\r\n                                                                                 E2_complex);\r\n\r\n    // call FFT tests\r\n    // 1) with real initial signals\r\n    int res = CTestFFT<TRealArray1D,TComplexArray1D,\r\n                       TRealArray2D,TComplexArray2D>::testFFT(E1_real, E2_real,\r\n                                                              G1, E1_restored,\r\n                                                              G2, E2_restored,\r\n                                                              t, x);\r\n    if (res != SUCCESS) {\r\n        return false;\r\n    }\r\n    else {\r\n        std::cout << \"FFT tests for real initial signal completed successfully!\"\r\n                  << std::endl;\r\n    }\r\n\r\n    // 2) with complex initial signals\r\n    res = CTestFFT<TComplexArray1D,TComplexArray1D,\r\n                   TComplexArray2D,TComplexArray2D>::testFFT(E1_complex, E2_complex,\r\n                                                             G1, E1_restored,\r\n                                                             G2, E2_restored,\r\n                                                             t, x);\r\n    if (res != SUCCESS) {\r\n        return false;\r\n    }\r\n    else {\r\n        std::cout << \"FFT tests for complex initial signal completed successfully!\"\r\n                  << std::endl;\r\n    }\r\n\r\n    return true;\r\n}\r\n\r\ntemplate <class TRealArray1D, class TComplexArray1D, class TRealArray2D,\r\n          class TComplexArray2D, class TRealArray3D, class TComplexArray3D>\r\nbool commonPartsForTests3D(TRealArray1D & E1_real, TRealArray2D & E2_real,\r\n                           TRealArray3D & E3_real, TComplexArray1D & E1_complex,\r\n                           TComplexArray2D & E2_complex, TComplexArray3D & E3_complex,\r\n                           TComplexArray1D & G1, TComplexArray2D & G2, TComplexArray3D & G3,\r\n                           TComplexArray1D & E1_restored, TComplexArray2D & E2_restored,\r\n                           TComplexArray3D & E3_restored, const std::vector<real_type> & t,\r\n                           const std::vector<real_type> & x, const std::vector<real_type> & y)\r\n{\r\n    // Make pulses\r\n    CMakeInitialPulses3D<TRealArray1D,TRealArray2D,\r\n                         TRealArray3D,true>::makeInitialPulses(E1_real, E2_real, E3_real);\r\n    CMakeInitialPulses3D<TComplexArray1D,TComplexArray2D,\r\n                         TComplexArray3D,false>::makeInitialPulses(E1_complex,\r\n                                                                   E2_complex,\r\n                                                                   E3_complex);\r\n\r\n    // Call FFT tests\r\n    // 1) With real initial signals\r\n    int res = CTestFFT3D<TRealArray1D,TComplexArray1D,\r\n                         TRealArray2D,TComplexArray2D,\r\n                         TRealArray3D,TComplexArray3D>::testFFT(E1_real, E2_real,\r\n                                                                E3_real, G1,\r\n                                                                E1_restored, G2,\r\n                                                                E2_restored, G3,\r\n                                                                E3_restored, t, x, y);\r\n    if (res != SUCCESS) {\r\n        return false;\r\n    }\r\n    else {\r\n        std::cout << \"FFT tests for real initial signal completed successfully!\"\r\n                  << std::endl;\r\n    }\r\n    // 2) With complex initial signals\r\n    res = CTestFFT3D<TComplexArray1D,TComplexArray1D,\r\n                     TComplexArray2D,TComplexArray2D,\r\n                     TComplexArray3D,TComplexArray3D>::testFFT(E1_complex, E2_complex,\r\n                                                               E3_complex, G1, E1_restored,\r\n                                                               G2, E2_restored, G3,\r\n                                                               E3_restored, t, x, y);\r\n    if (res != SUCCESS) {\r\n        return false;\r\n    }\r\n    else {\r\n        std::cout << \"FFT tests for complex initial signal completed successfully!\"\r\n                  << std::endl;\r\n    }\r\n\r\n    return true;\r\n}\r\n\r\n} // namespace fft_test\r\n} // namespace simple_fft\r\n\r\n#endif // __SIMPLE_FFT__UNIT_TESTS__TEST_FFT_HPP__\r\n"
  },
  {
    "path": "unit-tests/test_with_armadillo_matrix_and_row.cpp",
    "content": "#include \"../include/simple_fft/fft_settings.h\"\n\n#ifdef __USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR\n#undef __USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR\n#endif\n\n#include \"../include/simple_fft/fft.h\"\n#include \"test_fft.h\"\n#include <iostream>\n#include <armadillo>\n\nusing namespace arma;\n\nnamespace simple_fft {\nnamespace fft_test {\n\nint testArmadillo()\n{\n    std::cout << \"Testing FFT algorithms with Armadillo C++\" << std::endl;\n\n    using namespace pulse_params;\n\n    std::vector<real_type> t, x;\n    makeGridsForPulse(t, x);\n\n    // typedefing arrays\n    typedef Row<real_type> RealArray1D;\n    typedef Row<complex_type> ComplexArray1D;\n    typedef Mat<real_type> RealArray2D;\n    typedef Mat<complex_type> ComplexArray2D;\n\n    // 1D fields and spectrum\n    RealArray1D E1_real(nt);\n    ComplexArray1D E1_complex(nt), G1(nt), E1_restored(nt);\n\n    // 2D fields and spectrum\n    RealArray2D E2_real(nt, nx);\n    ComplexArray2D E2_complex(nt, nx), G2(nt, nx), E2_restored(nt, nx);\n\n    if (!commonPartsForTests(E1_real, E2_real, E1_complex, E2_complex, G1, G2,\n                             E1_restored, E2_restored, t, x))\n    {\n        std::cout << \"Tests of FFT algorithms with Armadillo C++ matrix and row \"\n                  << \"returned with errors!\" << std::endl;\n        return FAILURE;\n    }\n\n    std::cout << \"Tests of FFT with Armadillo C++ matrix and row completed successfully!\"\n              << std::endl;\n    return SUCCESS;\n}\n\n} // namespace fft_test\n} // namespace simple_fft\n"
  },
  {
    "path": "unit-tests/test_with_blitz.cpp",
    "content": "#include \"../include/simple_fft/fft_settings.h\"\n\n#ifdef __USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR\n#undef __USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR\n#endif\n\n#include \"../include/simple_fft/fft.h\"\n#include \"test_fft.h\"\n#include <iostream>\n#include <blitz/array.h>\n\nnamespace simple_fft {\nnamespace fft_test {\n\nint testBlitz()\n{\n    std::cout << \"Testing FFT algorithms with blitz\" << std::endl;\n\n    using namespace pulse_params;\n\n    std::vector<real_type> t, x, y;\n    makeGridsForPulse3D(t, x, y);\n\n    // typedefing arrays\n    typedef blitz::Array<real_type,int(1)> RealArray1D;\n    typedef blitz::Array<complex_type,int(1)> ComplexArray1D;\n    typedef blitz::Array<real_type,int(2)> RealArray2D;\n    typedef blitz::Array<complex_type,int(2)> ComplexArray2D;\n    typedef blitz::Array<real_type,int(3)> RealArray3D;\n    typedef blitz::Array<complex_type,int(3)> ComplexArray3D;\n\n    // 1D fields and spectrum\n    RealArray1D E1_real(nt);\n    ComplexArray1D E1_complex(nt), G1(nt), E1_restored(nt);\n\n    // 2D fields and spectrum,\n    RealArray2D E2_real(nt,nx);\n    ComplexArray2D E2_complex(nt,nx), G2(nt,nx), E2_restored(nt,nx);\n\n    // 3D fields and spectrum\n    RealArray3D E3_real(nt,nx,ny);\n    ComplexArray3D E3_complex(nt,nx,ny), G3(nt,nx,ny), E3_restored(nt,nx,ny);\n\n    if (!commonPartsForTests3D(E1_real, E2_real, E3_real, E1_complex, E2_complex,\n                               E3_complex, G1, G2, G3, E1_restored, E2_restored,\n                               E3_restored, t, x, y))\n    {\n        std::cout << \"Tests of FFT with blitz++ arrays returned with errors!\" << std::endl;\n        return FAILURE;\n    }\n\n    std::cout << \"Tests of FFT with blitz++ arrays completed successfully!\" << std::endl;\n    return SUCCESS;\n}\n\n} // namespace fft_test\n} // namespace simple_fft\n"
  },
  {
    "path": "unit-tests/test_with_boost_multiarray.cpp",
    "content": "#include \"../include/simple_fft/fft_settings.h\"\n\n// boost::multi_aray uses square brackets for indices\n#ifndef __USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR\n#define __USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR\n#endif\n\n#include \"../include/simple_fft/fft.h\"\n#include \"test_fft.h\"\n#include <iostream>\n#include <boost/multi_array.hpp>\n\nnamespace simple_fft {\nnamespace fft_test {\n\nint testBoostMultiArray()\n{\n    std::cout << \"Testing FFT algorithms with boost::multi_array\" << std::endl;\n\n    using namespace pulse_params;\n\n    std::vector<real_type> t, x, y;\n    makeGridsForPulse3D(t, x, y);\n\n    // typedefing arrays\n    typedef boost::multi_array<real_type,1> RealArray1D;\n    typedef boost::multi_array<complex_type,1> ComplexArray1D;\n    typedef boost::multi_array<real_type,2> RealArray2D;\n    typedef boost::multi_array<complex_type,2> ComplexArray2D;\n    typedef boost::multi_array<real_type,3> RealArray3D;\n    typedef boost::multi_array<complex_type,3> ComplexArray3D;\n\n    // 1D fields and spectrum\n    RealArray1D E1_real(boost::extents[nt]);\n    ComplexArray1D E1_complex(boost::extents[nt]), G1(boost::extents[nt]),\n                   E1_restored(boost::extents[nt]);\n\n    // 2D fields and spectrum\n    RealArray2D E2_real(boost::extents[nt][nx]);\n    ComplexArray2D E2_complex(boost::extents[nt][nx]), G2(boost::extents[nt][nx]),\n                   E2_restored(boost::extents[nt][nx]);\n\n    // 3D fields and spectrum\n    RealArray3D E3_real(boost::extents[nt][nx][ny]);\n    ComplexArray3D E3_complex(boost::extents[nt][nx][ny]), G3(boost::extents[nt][nx][ny]),\n                   E3_restored(boost::extents[nt][nx][ny]);\n\n    if (!commonPartsForTests3D(E1_real, E2_real, E3_real, E1_complex, E2_complex,\n                               E3_complex, G1, G2, G3, E1_restored, E2_restored,\n                               E3_restored, t, x, y))\n    {\n        std::cout << \"Tests of FFT with boost::multi_array returned with errors!\"\n                  << std::endl;\n        return FAILURE;\n    }\n\n    std::cout << \"Tests of FFT with boost::multi_array completed successfully!\" << std::endl;\n    return SUCCESS;\n}\n\n} // namespace fft_test\n} // namespace simple_fft\n"
  },
  {
    "path": "unit-tests/test_with_boost_ublas_vector_matrix.cpp",
    "content": "#include\"../include/simple_fft/fft_settings.h\"\n\n#ifdef __USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR\n#undef __USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR\n#endif\n\n#include \"../include/simple_fft/fft.h\"\n#include \"test_fft.h\"\n#include <iostream>\n#include <boost/numeric/ublas/vector.hpp>\n#include <boost/numeric/ublas/matrix.hpp>\n\nnamespace simple_fft {\nnamespace fft_test {\n\nint testBoostUblas()\n{\n    std::cout << \"Testing FFT algorithms with boost::numerics::ublas vector and matrix\"\n              << std::endl;\n\n    using namespace pulse_params;\n\n    std::vector<real_type> t, x;\n    makeGridsForPulse(t, x);\n\n    // typedefing arrays\n    typedef boost::numeric::ublas::vector<real_type> RealArray1D;\n    typedef boost::numeric::ublas::vector<complex_type> ComplexArray1D;\n    typedef boost::numeric::ublas::matrix<real_type> RealArray2D;\n    typedef boost::numeric::ublas::matrix<complex_type> ComplexArray2D;\n\n    // 1D fields and spectrum\n    RealArray1D E1_real(nt);\n    ComplexArray1D E1_complex(nt), G1(nt), E1_restored(nt);\n\n    // 2D fields and spectrum\n    RealArray2D E2_real(nt, nx);\n    ComplexArray2D E2_complex(nt, nx), G2(nt, nx), E2_restored(nt, nx);\n\n    if (!commonPartsForTests(E1_real, E2_real, E1_complex, E2_complex,\n                             G1, G2, E1_restored, E2_restored, t, x))\n    {\n        std::cout << \"Tests of FFT with boost::numeric::ublas vector and matrix \"\n                  << \"returned with errors!\" << std::endl;\n        return FAILURE;\n    }\n\n    std::cout << \"Tests of FFT with boost::numeric::ublas vector and matrix \"\n              << \"completed successfully!\" << std::endl;\n    return SUCCESS;\n\n}\n\n} // namespace fft_test\n} // namespace simple_fft\n"
  },
  {
    "path": "unit-tests/test_with_eigen_vector_matrix.cpp",
    "content": "#include \"../include/simple_fft/fft_settings.h\"\n\n#ifdef __USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR\n#undef __USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR\n#endif\n\n#include \"../include/simple_fft/fft.h\"\n#include \"test_fft.h\"\n#include <iostream>\n#include <eigen3/Eigen/Eigen>\n\nnamespace simple_fft {\nnamespace fft_test {\n\nint testEigen()\n{\n    std::cout << \"Testing FFT algorithms with Eigen 3.x vector and matrix\"\n              << std::endl;\n\n    using namespace pulse_params;\n\n    std::vector<real_type> t, x;\n    makeGridsForPulse(t, x);\n\n    // typedefing arrays\n    typedef Eigen::Matrix<real_type, Eigen::Dynamic, 1> RealArray1D;\n    typedef Eigen::Matrix<complex_type, Eigen::Dynamic, 1> ComplexArray1D;\n    typedef Eigen::Matrix<real_type, Eigen::Dynamic, Eigen::Dynamic> RealArray2D;\n    typedef Eigen::Matrix<complex_type, Eigen::Dynamic, Eigen::Dynamic> ComplexArray2D;\n\n    // 1D fields and spectrum\n    RealArray1D E1_real(nt);\n    ComplexArray1D E1_complex(nt), G1(nt), E1_restored(nt);\n\n    // 2D fields and spectrum\n    RealArray2D E2_real(nt, nx);\n    ComplexArray2D E2_complex(nt, nx), G2(nt, nx), E2_restored(nt, nx);\n\n    if (!commonPartsForTests(E1_real, E2_real, E1_complex, E2_complex,\n                             G1, G2, E1_restored, E2_restored, t, x))\n    {\n        std::cout << \"Tests of FFT with Eigen 3.x vector and matrix \"\n                  << \"returned with errors!\" << std::endl;\n        return FAILURE;\n    }\n\n    std::cout << \"Tests of FFT with Eigen 3.x vector and matrix \"\n              << \"completed successfully!\" << std::endl;\n    return SUCCESS;\n}\n\n} // namespace fft_test\n} // namespace simple_fft\n"
  },
  {
    "path": "unit-tests/test_with_marray.cpp",
    "content": "#include \"../include/simple_fft/fft_settings.h\"\n\n#ifdef __USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR\n#undef __USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR\n#endif\n\n#include \"../include/simple_fft/fft.h\"\n#include \"test_fft.h\"\n#include <iostream>\n#include <marray/marray.hxx>\n\nnamespace simple_fft {\nnamespace fft_test {\n\nint testMarray()\n{\n    std::cout << \"Testing FFT algorithms with marray\" << std::endl;\n\n    using namespace pulse_params;\n\n    std::vector<real_type> t, x, y;\n    makeGridsForPulse3D(t, x, y);\n\n    // typedefing arrays\n    typedef marray::Vector<real_type> RealArray1D;\n    typedef marray::Vector<complex_type> ComplexArray1D;\n    typedef marray::Matrix<real_type> RealArray2D;\n    typedef marray::Matrix<complex_type> ComplexArray2D;\n    typedef marray::Marray<real_type> RealArray3D;\n    typedef marray::Marray<complex_type> ComplexArray3D;\n\n    // 1D fields and spectrum\n    RealArray1D E1_real(marray::SkipInitialization, nt);\n    ComplexArray1D E1_complex(marray::SkipInitialization, nt),\n                   G1(marray::SkipInitialization, nt),\n                   E1_restored(marray::SkipInitialization, nt);\n\n    // 2D fields and spectrum\n    RealArray2D E2_real(marray::SkipInitialization, nt, nx);\n    ComplexArray2D E2_complex(marray::SkipInitialization, nt, nx),\n                   G2(marray::SkipInitialization, nt, nx),\n                   E2_restored(marray::SkipInitialization, nt, nx);\n\n    // 3D fields and spectrum\n    size_t shape3d[] = {nt, nx, ny};\n    RealArray3D E3_real(marray::SkipInitialization, shape3d, shape3d + 3);\n    ComplexArray3D E3_complex(marray::SkipInitialization, shape3d, shape3d + 3),\n                   G3(marray::SkipInitialization, shape3d, shape3d + 3),\n                   E3_restored(marray::SkipInitialization, shape3d, shape3d + 3);\n\n    if (!commonPartsForTests3D(E1_real, E2_real, E3_real, E1_complex, E2_complex,\n                               E3_complex, G1, G2, G3, E1_restored, E2_restored,\n                               E3_restored, t, x, y))\n    {\n        std::cout << \"Tests of FFT with marray returned with errors!\" << std::endl;\n        return FAILURE;\n    }\n\n    std::cout << \"Tests of FFT with marray completed successfully!\" << std::endl;\n    return SUCCESS;\n}\n\n} // namespace fft_test\n} // namespace simple_fft\n"
  },
  {
    "path": "unit-tests/test_with_native_cpp_pointer_based_arrays.cpp",
    "content": "#include \"../include/simple_fft/fft_settings.h\"\n\n// Native C++ arrays use square brackets for element access operator\n#ifndef __USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR\n#define __USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR\n#endif\n\n#include \"../include/simple_fft/fft.h\"\n#include \"test_fft.h\"\n#include <iostream>\n\nnamespace simple_fft {\nnamespace fft_test {\n\nint testNativeArraysFFT()\n{\n    std::cout << \"Testing FFT algorithms with native C++ arrays on heap using \"\n              << \"pointers to operate them\" << std::endl;\n\n    using namespace pulse_params;\n\n    std::vector<real_type> t, x, y;\n    makeGridsForPulse3D(t, x, y);\n\n    // typedefing arrays\n    typedef real_type* RealArray1D;\n    typedef complex_type* ComplexArray1D;\n    typedef real_type** RealArray2D;\n    typedef complex_type** ComplexArray2D;\n    typedef real_type*** RealArray3D;\n    typedef complex_type*** ComplexArray3D;\n\n    // 1D fields and spectrum\n    RealArray1D E1_real = new real_type[nt];\n    ComplexArray1D E1_complex = new complex_type[nt];\n    ComplexArray1D G1 = new complex_type[nt];\n    ComplexArray1D E1_restored = new complex_type[nt];\n\n    // 2D fields and spectrum\n    RealArray2D E2_real = new RealArray1D[nt];\n    for(size_t i = 0; i < nt; ++i) {\n        E2_real[i] = new real_type[nx];\n    }\n\n    ComplexArray2D E2_complex = new ComplexArray1D[nt];\n    for(size_t i = 0; i < nt; ++i) {\n        E2_complex[i] = new complex_type[nx];\n    }\n\n    ComplexArray2D G2 = new ComplexArray1D[nt];\n    for(size_t i = 0; i < nt; ++i) {\n        G2[i] = new complex_type[nx];\n    }\n\n    ComplexArray2D E2_restored = new ComplexArray1D[nt];\n    for(size_t i = 0; i < nt; ++i) {\n        E2_restored[i] = new complex_type[nx];\n    }\n\n    // 3D fields and spectrum\n    RealArray3D E3_real = new RealArray2D[nt];\n    for(size_t i = 0; i < nt; ++i) {\n        E3_real[i] = new RealArray1D[nx];\n        for(size_t j = 0; j < nx; ++j) {\n            E3_real[i][j] = new real_type[ny];\n        }\n    }\n\n    ComplexArray3D E3_complex = new ComplexArray2D[nt];\n    for(size_t i = 0; i < nt; ++i) {\n        E3_complex[i] = new ComplexArray1D[nx];\n        for(size_t j = 0; j < nx; ++j) {\n            E3_complex[i][j] = new complex_type[ny];\n        }\n    }\n\n    ComplexArray3D G3 = new ComplexArray2D[nt];\n    for(size_t i = 0; i < nt; ++i) {\n        G3[i] = new ComplexArray1D[nx];\n        for(size_t j = 0; j < nx; ++j) {\n            G3[i][j] = new complex_type[ny];\n        }\n    }\n\n    ComplexArray3D E3_restored = new ComplexArray2D[nt];\n    for(size_t i = 0; i < nt; ++i) {\n        E3_restored[i] = new ComplexArray1D[nx];\n        for(size_t j = 0; j < nx; ++j) {\n            E3_restored[i][j] = new complex_type[ny];\n        }\n    }\n\n    if (!commonPartsForTests3D(E1_real, E2_real, E3_real, E1_complex, E2_complex,\n                               E3_complex, G1, G2, G3, E1_restored, E2_restored,\n                               E3_restored, t, x, y))\n    {\n        std::cout << \"Tests of FFT with native C++ pointer-based arrays on heap \"\n                  << \"returned with errors!\" << std::endl;\n        return FAILURE;\n    }\n\n    // free 3D arrays\n    for(size_t j = 0; j < nx; ++j) {\n        for(size_t i = 0; i < nt; ++i) {\n            delete[] E3_restored[i];\n            E3_restored[i] = NULL;\n\n            delete[] G3[i];\n            G3[i] = NULL;\n\n            delete[] E3_complex[i];\n            E3_complex[i] = NULL;\n\n            delete[] E3_real[i];\n            E3_real[i] = NULL;\n        }\n\n        delete[] E3_restored[j];\n        E3_restored[j] = NULL;\n\n        delete[] G3[j];\n        G3[j] = NULL;\n\n        delete[] E3_complex[j];\n        E3_complex[j] = NULL;\n\n        delete[] E3_real[j];\n        E3_real[j] = 0;\n    }\n\n    delete[] E3_restored;\n    delete[] G3;\n    delete[] E3_complex;\n    delete[] E3_real;\n\n    // free 2D arrays\n    for(size_t i = 0; i < nt; ++i) {\n        delete[] E2_restored[i];\n        E2_restored[i] = NULL;\n\n        delete[] G2[i];\n        G2[i] = NULL;\n\n        delete[] E2_complex[i];\n        E2_complex[i] = NULL;\n\n        delete[] E2_real[i];\n        E2_real[i] = NULL;\n    }\n\n    delete[] E2_restored;\n    delete[] G2;\n    delete[] E2_complex;\n    delete[] E2_real;\n\n    // free 1D arrays\n    delete[] E1_restored;\n    delete[] G1;\n    delete[] E1_complex;\n    delete[] E1_real;\n\n    std::cout << \"Tests of FFT for native C++ pointer-based arrays on heap \"\n              << \"completed successfully!\" << std::endl;\n    return SUCCESS;\n}\n\n} // namespace fft_test\n} // namespace simple_fft\n"
  },
  {
    "path": "unit-tests/test_with_std_vectors.cpp",
    "content": "#include \"../include/simple_fft/fft_settings.h\"\n\n// STL vectors use square brackets for element access operator\n#ifndef __USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR\n#define __USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR\n#endif\n\n#include \"../include/simple_fft/fft.h\"\n#include \"test_fft.h\"\n#include <iostream>\n\nnamespace simple_fft {\nnamespace fft_test {\n\nint testStdVectorsFFT()\n{\n    std::cout << \"Testing FFT algorithms with std::vectors and vectors of vectors \"\n              << \"as used array types\" << std::endl;\n\n    using namespace pulse_params;\n\n    std::vector<real_type> t, x, y;\n    makeGridsForPulse3D(t, x, y);\n\n    // typedefing vectors\n    typedef std::vector<real_type> RealArray1D;\n    typedef std::vector<complex_type> ComplexArray1D;\n    typedef std::vector<std::vector<real_type> > RealArray2D;\n    typedef std::vector<std::vector<complex_type> > ComplexArray2D;\n    typedef std::vector<std::vector<std::vector<real_type> > > RealArray3D;\n    typedef std::vector<std::vector<std::vector<complex_type> > > ComplexArray3D;\n\n    // 1D fields and spectrum\n    RealArray1D E1_real(nt);\n    ComplexArray1D E1_complex(nt), G1(nt), E1_restored(nt);\n\n    // 2D fields and spectrum\n    RealArray2D E2_real(nt);\n    ComplexArray2D E2_complex(nt), G2(nt), E2_restored(nt);\n\n    int grid_size_t = static_cast<int>(nt);\n\n#ifndef __clang__\n#ifdef __USE_OPENMP\n#pragma omp parallel for\n#endif\n#endif\n    for(int i = 0; i < grid_size_t; ++i) {\n        E2_real[i].resize(nx);\n        E2_complex[i].resize(nx);\n        G2[i].resize(nx);\n        E2_restored[i].resize(nx);\n    }\n\n    // 3D fields and spectrum\n    RealArray3D E3_real(nt);\n    ComplexArray3D E3_complex(nt), G3(nt), E3_restored(nt);\n\n    int grid_size_x = static_cast<int>(nx);\n\n#ifndef __clang__\n#ifdef __USE_OPENMP\n#pragma omp parallel for\n#endif\n#endif\n    for(int i = 0; i < grid_size_t; ++i) {\n        E3_real[i].resize(nx);\n        E3_complex[i].resize(nx);\n        G3[i].resize(nx);\n        E3_restored[i].resize(nx);\n        for(int j = 0; j < grid_size_x; ++j) {\n            E3_real[i][j].resize(ny);\n            E3_complex[i][j].resize(ny);\n            G3[i][j].resize(ny);\n            E3_restored[i][j].resize(ny);\n        }\n    }\n\n    if (!commonPartsForTests3D(E1_real, E2_real, E3_real, E1_complex, E2_complex,\n                               E3_complex, G1, G2, G3, E1_restored, E2_restored,\n                               E3_restored, t, x, y))\n    {\n        std::cout << \"Tests of FFT with std vectors returned with errors!\"\n                  << std::endl;\n        return FAILURE;\n    }\n\n    std::cout << \"Tests of FFT with std vectors completed successfully!\" << std::endl;\n    return SUCCESS;\n}\n\n} // namespace fft_test\n} // namespace simple_fft\n"
  },
  {
    "path": "unit-tests/test_with_stlsoft.cpp",
    "content": "#include \"../include/simple_fft/fft_settings.h\"\n\n#ifdef __USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR\n#undef __USE_SQUARE_BRACKETS_FOR_ELEMENT_ACCESS_OPERATOR\n#endif\n\n#include \"../include/simple_fft/fft.h\"\n#include \"test_fft.h\"\n#include <iostream>\n#include <stlsoft/containers/fixed_array.hpp>\n\nnamespace simple_fft {\nnamespace fft_test {\n\nint testStlSoft()\n{\n    std::cout << \"Testing FFT algorithms with STLSoft fixed arrays\" << std::endl;\n\n    using namespace pulse_params;\n\n    std::vector<real_type> t, x, y;\n    makeGridsForPulse3D(t, x, y);\n\n    // typedefing arrays\n    typedef stlsoft::fixed_array_1d<real_type> RealArray1D;\n    typedef stlsoft::fixed_array_1d<complex_type> ComplexArray1D;\n    typedef stlsoft::fixed_array_2d<real_type> RealArray2D;\n    typedef stlsoft::fixed_array_2d<complex_type> ComplexArray2D;\n    typedef stlsoft::fixed_array_3d<real_type> RealArray3D;\n    typedef stlsoft::fixed_array_3d<complex_type> ComplexArray3D;\n\n    // 1D fields and spectrum\n    RealArray1D E1_real(nt);\n    ComplexArray1D E1_complex(nt), G1(nt), E1_restored(nt);\n\n    // 2D fields and spectrum\n    RealArray2D E2_real(nt,nx);\n    ComplexArray2D E2_complex(nt,nx), G2(nt,nx), E2_restored(nt,nx);\n\n    // 3D fields and spectrum\n    RealArray3D E3_real(nt,nx,ny);\n    ComplexArray3D E3_complex(nt,nx,ny), G3(nt,nx,ny), E3_restored(nt,nx,ny);\n\n    if (!commonPartsForTests3D(E1_real, E2_real, E3_real, E1_complex, E2_complex,\n                               E3_complex, G1, G2, G3, E1_restored, E2_restored,\n                               E3_restored, t, x, y))\n    {\n        std::cout << \"Tests of FFT with STLSoft fixed_arrays returned with errors!\" << std::endl;\n        return FAILURE;\n    }\n\n    std::cout << \"Tests of FFT with STLSoft fixed_arrays completed successfully!\" << std::endl;\n    return SUCCESS;\n}\n\n} // namespace fft_test\n} // namespace simple_fft\n"
  },
  {
    "path": "unit-tests/unit_tests_main.cpp",
    "content": "#include \"test_fft.h\"\r\n#include <iostream>\r\n\r\n#ifdef __USE_OPENMP\r\n#include <omp.h>\r\n#endif\r\n\r\nusing namespace simple_fft::fft_test;\r\n\r\nint main()\r\n{\r\n#ifdef __USE_OPENMP\r\n    omp_set_dynamic(0);\r\n    omp_set_num_threads(1);\r\n#endif\r\n\r\n    int res;\r\n\r\n    res = testStdVectorsFFT();\r\n    if (res != 0) {\r\n        return res;\r\n    }\r\n\r\n    res = testNativeArraysFFT();\r\n    if (res != 0) {\r\n        return res;\r\n    }\r\n\r\n#ifdef HAS_BOOST_PACKAGE\r\n\r\n#ifdef HAS_BOOST_MULTI_ARRAY\r\n    res = testBoostMultiArray();\r\n    if (res != 0) {\r\n        return res;\r\n    }\r\n#endif // HAS_BOOST_MULTI_ARRAY\r\n\r\n#ifdef HAS_BOOST_UBLAS\r\n    res = testBoostUblas();\r\n    if (res != 0) {\r\n        return res;\r\n    }\r\n#endif // HAS_BOOST_UBLAS\r\n\r\n#endif // HAS_BOOST_PACKAGE\r\n\r\n#ifdef HAS_EIGEN\r\n    res = testEigen();\r\n    if (res != 0) {\r\n        return res;\r\n    }\r\n#endif // HAS_EIGEN\r\n\r\n#ifdef HAS_MARRAY\r\n    res = testMarray();\r\n    if (res != 0) {\r\n        return res;\r\n    }\r\n#endif // HAS_MARRAY\r\n\r\n#ifdef HAS_ARMADILLO\r\n    res = testArmadillo();\r\n    if (res != 0) {\r\n        return res;\r\n    }\r\n#endif // HAS_ARMADILLO\r\n\r\n#ifdef HAS_BLITZ\r\n    res = testBlitz();\r\n    if (res != 0) {\r\n        return res;\r\n    }\r\n#endif // HAS_BLITZ\r\n\r\n#ifdef HAS_STLSOFT\r\n    res = testStlSoft();\r\n    if (res != 0) {\r\n        return res;\r\n    }\r\n#endif // HAS_STLSOFT\r\n\r\n    return 0;\r\n}\r\n"
  }
]