diff --git a/.gitignore b/.gitignore index 5ba184ca..041a66fe 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,21 @@ -ext_lib +# Build directory +build/ + +# Python build products +python/build/ +python/dist/ +python/srwpy.egg-info/ + +# Documentation artifacts docs/source/cookbook docs/build/ + +# Python and C compiled files *.pyc *.o data_example* .idea + +# Compiled libraries *.a *.so diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000..84e0bce6 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,66 @@ +# Minimum cmake version +# Picked 3.12 as this one introduces a proper FindOpenMP +cmake_minimum_required(VERSION 3.12 FATAL_ERROR) + +# Project name +project(SRW) + +cmake_policy(SET CMP0074 NEW) + +# Folder for helper modules (Find*.cmake) +set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) + +# Uncomment for VERBOSE Makefiles. Useful for debugging. +#set(CMAKE_VERBOSE_MAKEFILE ON) + +# Useful debug for Find commands +#set(CMAKE_FIND_DEBUG_MODE ON) + +# Uncomment for install messages +#set(CMAKE_INSTALL_MESSAGE ALWAYS) + +# Uncomment for Debug Build +#set(CMAKE_BUILD_TYPE Debug) +set(CMAKE_BUILD_TYPE Release) + +# Option for OpenMP build, OFF by default. +option(USE_OPENMP "Activate OpenMP build" OFF) + +# Option for C client library to be built or not - See src/clients/CMakeLists.txt +option(BUILD_CLIENT_C "Activate C Client library build" OFF) + +# Option for Python client library to be built or not - See src/clients/CMakeLists.txt +option(BUILD_CLIENT_PYTHON "Activate Python Client library build" OFF) + +# Option for Igor Pro client library to be built or not - See src/clients/CMakeLists.txt +option(BUILD_CLIENT_IGOR "Activate Igor Pro Client library build" OFF) + + +# Temporary path for FFTW in case we need to build it +set(STAGED_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/stage) +message(STATUS "${PROJECT_NAME} staged install: ${STAGED_INSTALL_PREFIX}") + + +if(UNIX) + # Use /lib /bin /include /share folder structure + include(GNUInstallDirs) +else() + if (WIN32) + set(${CMAKE_INSTALL_LIBDIR} "lib") + set(${CMAKE_INSTALL_DATADIR} "share") + set(${CMAKE_INSTALL_INCLUDEDIR} "include") + set(${CMAKE_INSTALL_BINDIR} "bin") + message(STATUS "Setting installation destination on Windows to: ${CMAKE_INSTALL_PREFIX}") + else() + message(FATAL_ERROR "System not UNIX nor WIN32 - not implemented yet") + endif() +endif() + +# Force FFTW to look for STATIC libraries that we need +set(FFTW_USE_STATIC_LIBS ON) + +# External Libraries +add_subdirectory(ext_lib) + +# Main library +add_subdirectory(src) diff --git a/cmake/FindFFTW.cmake b/cmake/FindFFTW.cmake new file mode 100644 index 00000000..9d594247 --- /dev/null +++ b/cmake/FindFFTW.cmake @@ -0,0 +1,336 @@ +# - Find the FFTW library +# +# Original version of this file: +# Copyright (c) 2015, Wenzel Jakob +# https://github.com/wjakob/layerlab/blob/master/cmake/FindFFTW.cmake, commit 4d58bfdc28891b4f9373dfe46239dda5a0b561c6 +# Modifications: +# Copyright (c) 2017, Patrick Bos +# +# Usage: +# find_package(FFTW [REQUIRED] [QUIET] [COMPONENTS component1 ... componentX] ) +# +# It sets the following variables: +# FFTW_FOUND ... true if fftw is found on the system +# FFTW_[component]_LIB_FOUND ... true if the component is found on the system (see components below) +# FFTW_LIBRARIES ... full paths to all found fftw libraries +# FFTW_[component]_LIB ... full path to one of the components (see below) +# FFTW_INCLUDE_DIRS ... fftw include directory paths +# +# The following variables will be checked by the function +# FFTW_USE_STATIC_LIBS ... if true, only static libraries are found, otherwise both static and shared. +# FFTW_ROOT ... if set, the libraries are exclusively searched +# under this path +# +# This package supports the following components: +# FLOAT_LIB +# DOUBLE_LIB +# LONGDOUBLE_LIB +# FLOAT_THREADS_LIB +# DOUBLE_THREADS_LIB +# LONGDOUBLE_THREADS_LIB +# FLOAT_OPENMP_LIB +# DOUBLE_OPENMP_LIB +# LONGDOUBLE_OPENMP_LIB +# + + +if( NOT FFTW_ROOT AND DEFINED ENV{FFTWDIR} ) + set( FFTW_ROOT $ENV{FFTWDIR} ) +endif() + +# Check if we can use PkgConfig +find_package(PkgConfig) + +#Determine from PKG +if( PKG_CONFIG_FOUND AND NOT FFTW_ROOT ) + pkg_check_modules( PKG_FFTW QUIET "fftw3" ) +endif() + +#Check whether to search static or dynamic libs +set( CMAKE_FIND_LIBRARY_SUFFIXES_SAV ${CMAKE_FIND_LIBRARY_SUFFIXES} ) + +if( ${FFTW_USE_STATIC_LIBS} ) + set( CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_STATIC_LIBRARY_SUFFIX} ) +else() + set( CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES_SAV} ) +endif() + +if( FFTW_ROOT ) + # find libs + + find_library( + FFTW_DOUBLE_LIB + NAMES "fftw3" libfftw3-3 + PATHS ${FFTW_ROOT} + PATH_SUFFIXES "lib" "lib64" + NO_DEFAULT_PATH + ) + + find_library( + FFTW_DOUBLE_THREADS_LIB + NAMES "fftw3_threads" + PATHS ${FFTW_ROOT} + PATH_SUFFIXES "lib" "lib64" + NO_DEFAULT_PATH + ) + + find_library( + FFTW_DOUBLE_OPENMP_LIB + NAMES "fftw3_omp" + PATHS ${FFTW_ROOT} + PATH_SUFFIXES "lib" "lib64" + NO_DEFAULT_PATH + ) + + find_library( + FFTW_FLOAT_LIB + NAMES "fftw3f" libfftw3f-3 + PATHS ${FFTW_ROOT} + PATH_SUFFIXES "lib" "lib64" + NO_DEFAULT_PATH + ) + + find_library( + FFTW_FLOAT_THREADS_LIB + NAMES "fftw3f_threads" + PATHS ${FFTW_ROOT} + PATH_SUFFIXES "lib" "lib64" + NO_DEFAULT_PATH + ) + + find_library( + FFTW_FLOAT_OPENMP_LIB + NAMES "fftw3f_omp" + PATHS ${FFTW_ROOT} + PATH_SUFFIXES "lib" "lib64" + NO_DEFAULT_PATH + ) + + find_library( + FFTW_LONGDOUBLE_LIB + NAMES "fftw3l" libfftw3l-3 + PATHS ${FFTW_ROOT} + PATH_SUFFIXES "lib" "lib64" + NO_DEFAULT_PATH + ) + + find_library( + FFTW_LONGDOUBLE_THREADS_LIB + NAMES "fftw3l_threads" + PATHS ${FFTW_ROOT} + PATH_SUFFIXES "lib" "lib64" + NO_DEFAULT_PATH + ) + + find_library( + FFTW_LONGDOUBLE_OPENMP_LIB + NAMES "fftw3l_omp" + PATHS ${FFTW_ROOT} + PATH_SUFFIXES "lib" "lib64" + NO_DEFAULT_PATH + ) + + #find includes + find_path(FFTW_INCLUDE_DIRS + NAMES "fftw3.h" + PATHS ${FFTW_ROOT} + PATH_SUFFIXES "include" + NO_DEFAULT_PATH + ) + +else() + + find_library( + FFTW_DOUBLE_LIB + NAMES "fftw3" + PATHS ${PKG_FFTW_LIBRARY_DIRS} ${LIB_INSTALL_DIR} $ENV{CONDA_PREFIX}/lib + ) + + find_library( + FFTW_DOUBLE_THREADS_LIB + NAMES "fftw3_threads" + PATHS ${PKG_FFTW_LIBRARY_DIRS} ${LIB_INSTALL_DIR} $ENV{CONDA_PREFIX}/lib + ) + + find_library( + FFTW_DOUBLE_OPENMP_LIB + NAMES "fftw3_omp" + PATHS ${PKG_FFTW_LIBRARY_DIRS} ${LIB_INSTALL_DIR} $ENV{CONDA_PREFIX}/lib + ) + + find_library( + FFTW_FLOAT_LIB + NAMES "fftw3f" + PATHS ${PKG_FFTW_LIBRARY_DIRS} ${LIB_INSTALL_DIR} $ENV{CONDA_PREFIX}/lib + ) + + find_library( + FFTW_FLOAT_THREADS_LIB + NAMES "fftw3f_threads" + PATHS ${PKG_FFTW_LIBRARY_DIRS} ${LIB_INSTALL_DIR} $ENV{CONDA_PREFIX}/lib + ) + + find_library( + FFTW_FLOAT_OPENMP_LIB + NAMES "fftw3f_omp" + PATHS ${PKG_FFTW_LIBRARY_DIRS} ${LIB_INSTALL_DIR} $ENV{CONDA_PREFIX}/lib + ) + + find_library( + FFTW_LONGDOUBLE_LIB + NAMES "fftw3l" + PATHS ${PKG_FFTW_LIBRARY_DIRS} ${LIB_INSTALL_DIR} $ENV{CONDA_PREFIX}/lib + ) + + find_library( + FFTW_LONGDOUBLE_THREADS_LIB + NAMES "fftw3l_threads" + PATHS ${PKG_FFTW_LIBRARY_DIRS} ${LIB_INSTALL_DIR} $ENV{CONDA_PREFIX}/lib + ) + + find_library(FFTW_LONGDOUBLE_OPENMP_LIB + NAMES "fftw3l_omp" + PATHS ${PKG_FFTW_LIBRARY_DIRS} ${LIB_INSTALL_DIR} $ENV{CONDA_PREFIX}/lib + ) + + find_path(FFTW_INCLUDE_DIRS + NAMES "fftw3.h" + PATHS ${PKG_FFTW_INCLUDE_DIRS} ${INCLUDE_INSTALL_DIR} $ENV{CONDA_PREFIX}/include + ) + +endif( FFTW_ROOT ) + +#--------------------------------------- components + +if (FFTW_DOUBLE_LIB) + set(FFTW_DOUBLE_LIB_FOUND TRUE) + set(FFTW_LIBRARIES ${FFTW_LIBRARIES} ${FFTW_DOUBLE_LIB}) + add_library(FFTW::Double INTERFACE IMPORTED) + set_target_properties(FFTW::Double + PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${FFTW_INCLUDE_DIRS}" + INTERFACE_LINK_LIBRARIES "${FFTW_DOUBLE_LIB}" + ) +else() + set(FFTW_DOUBLE_LIB_FOUND FALSE) +endif() + +if (FFTW_FLOAT_LIB) + set(FFTW_FLOAT_LIB_FOUND TRUE) + set(FFTW_LIBRARIES ${FFTW_LIBRARIES} ${FFTW_FLOAT_LIB}) + add_library(FFTW::Float INTERFACE IMPORTED) + set_target_properties(FFTW::Float + PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${FFTW_INCLUDE_DIRS}" + INTERFACE_LINK_LIBRARIES "${FFTW_FLOAT_LIB}" + ) +else() + set(FFTW_FLOAT_LIB_FOUND FALSE) +endif() + +if (FFTW_LONGDOUBLE_LIB) + set(FFTW_LONGDOUBLE_LIB_FOUND TRUE) + set(FFTW_LIBRARIES ${FFTW_LIBRARIES} ${FFTW_LONGDOUBLE_LIB}) + add_library(FFTW::LongDouble INTERFACE IMPORTED) + set_target_properties(FFTW::LongDouble + PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${FFTW_INCLUDE_DIRS}" + INTERFACE_LINK_LIBRARIES "${FFTW_LONGDOUBLE_LIB}" + ) +else() + set(FFTW_LONGDOUBLE_LIB_FOUND FALSE) +endif() + +if (FFTW_DOUBLE_THREADS_LIB) + set(FFTW_DOUBLE_THREADS_LIB_FOUND TRUE) + set(FFTW_LIBRARIES ${FFTW_LIBRARIES} ${FFTW_DOUBLE_THREADS_LIB}) + add_library(FFTW::DoubleThreads INTERFACE IMPORTED) + set_target_properties(FFTW::DoubleThreads + PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${FFTW_INCLUDE_DIRS}" + INTERFACE_LINK_LIBRARIES "${FFTW_DOUBLETHREADS_LIB}" + ) +else() + set(FFTW_DOUBLE_THREADS_LIB_FOUND FALSE) +endif() + +if (FFTW_FLOAT_THREADS_LIB) + set(FFTW_FLOAT_THREADS_LIB_FOUND TRUE) + set(FFTW_LIBRARIES ${FFTW_LIBRARIES} ${FFTW_FLOAT_THREADS_LIB}) + add_library(FFTW::FloatThreads INTERFACE IMPORTED) + set_target_properties(FFTW::FloatThreads + PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${FFTW_INCLUDE_DIRS}" + INTERFACE_LINK_LIBRARIES "${FFTW_FLOAT_THREADS_LIB}" + ) +else() + set(FFTW_FLOAT_THREADS_LIB_FOUND FALSE) +endif() + +if (FFTW_LONGDOUBLE_THREADS_LIB) + set(FFTW_LONGDOUBLE_THREADS_LIB_FOUND TRUE) + set(FFTW_LIBRARIES ${FFTW_LIBRARIES} ${FFTW_LONGDOUBLE_THREADS_LIB}) + add_library(FFTW::LongDoubleThreads INTERFACE IMPORTED) + set_target_properties(FFTW::LongDoubleThreads + PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${FFTW_INCLUDE_DIRS}" + INTERFACE_LINK_LIBRARIES "${FFTW_LONGDOUBLE_THREADS_LIB}" + ) +else() + set(FFTW_LONGDOUBLE_THREADS_LIB_FOUND FALSE) +endif() + +if (FFTW_DOUBLE_OPENMP_LIB) + set(FFTW_DOUBLE_OPENMP_LIB_FOUND TRUE) + set(FFTW_LIBRARIES ${FFTW_LIBRARIES} ${FFTW_DOUBLE_OPENMP_LIB}) + add_library(FFTW::DoubleOpenMP INTERFACE IMPORTED) + set_target_properties(FFTW::DoubleOpenMP + PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${FFTW_INCLUDE_DIRS}" + INTERFACE_LINK_LIBRARIES "${FFTW_DOUBLE_OPENMP_LIB}" + ) +else() + set(FFTW_DOUBLE_OPENMP_LIB_FOUND FALSE) +endif() + +if (FFTW_FLOAT_OPENMP_LIB) + set(FFTW_FLOAT_OPENMP_LIB_FOUND TRUE) + set(FFTW_LIBRARIES ${FFTW_LIBRARIES} ${FFTW_FLOAT_OPENMP_LIB}) + add_library(FFTW::FloatOpenMP INTERFACE IMPORTED) + set_target_properties(FFTW::FloatOpenMP + PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${FFTW_INCLUDE_DIRS}" + INTERFACE_LINK_LIBRARIES "${FFTW_FLOAT_OPENMP_LIB}" + ) +else() + set(FFTW_FLOAT_OPENMP_LIB_FOUND FALSE) +endif() + +if (FFTW_LONGDOUBLE_OPENMP_LIB) + set(FFTW_LONGDOUBLE_OPENMP_LIB_FOUND TRUE) + set(FFTW_LIBRARIES ${FFTW_LIBRARIES} ${FFTW_LONGDOUBLE_OPENMP_LIB}) + add_library(FFTW::LongDoubleOpenMP INTERFACE IMPORTED) + set_target_properties(FFTW::LongDoubleOpenMP + PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${FFTW_INCLUDE_DIRS}" + INTERFACE_LINK_LIBRARIES "${FFTW_LONGDOUBLE_OPENMP_LIB}" + ) +else() + set(FFTW_LONGDOUBLE_OPENMP_LIB_FOUND FALSE) +endif() + +#--------------------------------------- end components + +set( CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES_SAV} ) + +include(FindPackageHandleStandardArgs) + +find_package_handle_standard_args(FFTW + REQUIRED_VARS FFTW_INCLUDE_DIRS + HANDLE_COMPONENTS + ) + +mark_as_advanced( + FFTW_INCLUDE_DIRS + FFTW_LIBRARIES + FFTW_FLOAT_LIB + FFTW_DOUBLE_LIB + FFTW_LONGDOUBLE_LIB + FFTW_FLOAT_THREADS_LIB + FFTW_DOUBLE_THREADS_LIB + FFTW_LONGDOUBLE_THREADS_LIB + FFTW_FLOAT_OPENMP_LIB + FFTW_DOUBLE_OPENMP_LIB + FFTW_LONGDOUBLE_OPENMP_LIB + ) diff --git a/cmake/FindFFTW2.cmake b/cmake/FindFFTW2.cmake new file mode 100644 index 00000000..7039d575 --- /dev/null +++ b/cmake/FindFFTW2.cmake @@ -0,0 +1,335 @@ +# - Find the FFTW2 library +# +# Original version of this file: +# Copyright (c) 2015, Wenzel Jakob +# https://github.com/wjakob/layerlab/blob/master/cmake/FindFFTW.cmake, commit 4d58bfdc28891b4f9373dfe46239dda5a0b561c6 +# Modifications: +# Copyright (c) 2017, Patrick Bos +# +# Usage: +# find_package(FFTW [REQUIRED] [QUIET] [COMPONENTS component1 ... componentX] ) +# +# It sets the following variables: +# FFTW2_FOUND ... true if fftw is found on the system +# FFTW_[component]_LIB_FOUND ... true if the component is found on the system (see components below) +# FFTW_LIBRARIES ... full paths to all found fftw libraries +# FFTW_[component]_LIB ... full path to one of the components (see below) +# FFTW_INCLUDE_DIRS ... fftw include directory paths +# +# The following variables will be checked by the function +# FFTW_USE_STATIC_LIBS ... if true, only static libraries are found, otherwise both static and shared. +# FFTW_ROOT ... if set, the libraries are exclusively searched +# under this path +# +# This package supports the following components: +# FLOAT_LIB +# DOUBLE_LIB +# LONGDOUBLE_LIB +# FLOAT_THREADS_LIB +# DOUBLE_THREADS_LIB +# LONGDOUBLE_THREADS_LIB +# FLOAT_OPENMP_LIB +# DOUBLE_OPENMP_LIB +# LONGDOUBLE_OPENMP_LIB +# + +if( NOT FFTW_ROOT AND DEFINED ENV{FFTWDIR} ) + set( FFTW_ROOT $ENV{FFTWDIR} ) +endif() + +# Check if we can use PkgConfig +find_package(PkgConfig) + +#Determine from PKG +if( PKG_CONFIG_FOUND AND NOT FFTW_ROOT ) + pkg_check_modules( PKG_FFTW QUIET "fftw" ) +endif() + +#Check whether to search static or dynamic libs +set( CMAKE_FIND_LIBRARY_SUFFIXES_SAV ${CMAKE_FIND_LIBRARY_SUFFIXES} ) + +if( ${FFTW_USE_STATIC_LIBS} ) + set( CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_STATIC_LIBRARY_SUFFIX} ) +else() + set( CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES_SAV} ) +endif() + +if( FFTW_ROOT ) + # find libs + + find_library( + FFTW_DOUBLE_LIB + NAMES "fftw" libfftw + PATHS ${FFTW_ROOT} + PATH_SUFFIXES "lib" "lib64" + NO_DEFAULT_PATH + ) + + find_library( + FFTW_DOUBLE_THREADS_LIB + NAMES "fftw_threads" + PATHS ${FFTW_ROOT} + PATH_SUFFIXES "lib" "lib64" + NO_DEFAULT_PATH + ) + + find_library( + FFTW_DOUBLE_OPENMP_LIB + NAMES "fftw_omp" + PATHS ${FFTW_ROOT} + PATH_SUFFIXES "lib" "lib64" + NO_DEFAULT_PATH + ) + + find_library( + FFTW_FLOAT_LIB + NAMES "fftwf" libfftwf + PATHS ${FFTW_ROOT} + PATH_SUFFIXES "lib" "lib64" + NO_DEFAULT_PATH + ) + + find_library( + FFTW_FLOAT_THREADS_LIB + NAMES "fftwf_threads" + PATHS ${FFTW_ROOT} + PATH_SUFFIXES "lib" "lib64" + NO_DEFAULT_PATH + ) + + find_library( + FFTW_FLOAT_OPENMP_LIB + NAMES "fftwf_omp" + PATHS ${FFTW_ROOT} + PATH_SUFFIXES "lib" "lib64" + NO_DEFAULT_PATH + ) + + find_library( + FFTW_LONGDOUBLE_LIB + NAMES "fftwl" libfftwl + PATHS ${FFTW_ROOT} + PATH_SUFFIXES "lib" "lib64" + NO_DEFAULT_PATH + ) + + find_library( + FFTW_LONGDOUBLE_THREADS_LIB + NAMES "fftwl_threads" + PATHS ${FFTW_ROOT} + PATH_SUFFIXES "lib" "lib64" + NO_DEFAULT_PATH + ) + + find_library( + FFTW_LONGDOUBLE_OPENMP_LIB + NAMES "fftwl_omp" + PATHS ${FFTW_ROOT} + PATH_SUFFIXES "lib" "lib64" + NO_DEFAULT_PATH + ) + + #find includes + find_path(FFTW_INCLUDE_DIRS + NAMES "fftw.h" + PATHS ${FFTW_ROOT} + PATH_SUFFIXES "include" + NO_DEFAULT_PATH + ) + +else() + + find_library( + FFTW_DOUBLE_LIB + NAMES "fftw" + PATHS ${PKG_FFTW_LIBRARY_DIRS} ${LIB_INSTALL_DIR} $ENV{CONDA_PREFIX}/lib + ) + + find_library( + FFTW_DOUBLE_THREADS_LIB + NAMES "fftw_threads" + PATHS ${PKG_FFTW_LIBRARY_DIRS} ${LIB_INSTALL_DIR} $ENV{CONDA_PREFIX}/lib + ) + + find_library( + FFTW_DOUBLE_OPENMP_LIB + NAMES "fftw_omp" + PATHS ${PKG_FFTW_LIBRARY_DIRS} ${LIB_INSTALL_DIR} $ENV{CONDA_PREFIX}/lib + ) + + find_library( + FFTW_FLOAT_LIB + NAMES "fftwf" + PATHS ${PKG_FFTW_LIBRARY_DIRS} ${LIB_INSTALL_DIR} $ENV{CONDA_PREFIX}/lib + ) + + find_library( + FFTW_FLOAT_THREADS_LIB + NAMES "fftwf_threads" + PATHS ${PKG_FFTW_LIBRARY_DIRS} ${LIB_INSTALL_DIR} $ENV{CONDA_PREFIX}/lib + ) + + find_library( + FFTW_FLOAT_OPENMP_LIB + NAMES "fftwf_omp" + PATHS ${PKG_FFTW_LIBRARY_DIRS} ${LIB_INSTALL_DIR} $ENV{CONDA_PREFIX}/lib + ) + + find_library( + FFTW_LONGDOUBLE_LIB + NAMES "fftwl" + PATHS ${PKG_FFTW_LIBRARY_DIRS} ${LIB_INSTALL_DIR} $ENV{CONDA_PREFIX}/lib + ) + + find_library( + FFTW_LONGDOUBLE_THREADS_LIB + NAMES "fftwl_threads" + PATHS ${PKG_FFTW_LIBRARY_DIRS} ${LIB_INSTALL_DIR} $ENV{CONDA_PREFIX}/lib + ) + + find_library(FFTW_LONGDOUBLE_OPENMP_LIB + NAMES "fftwl_omp" + PATHS ${PKG_FFTW_LIBRARY_DIRS} ${LIB_INSTALL_DIR} $ENV{CONDA_PREFIX}/lib + ) + + find_path(FFTW_INCLUDE_DIRS + NAMES "fftw.h" + PATHS ${PKG_FFTW_INCLUDE_DIRS} ${INCLUDE_INSTALL_DIR} $ENV{CONDA_PREFIX}/include + ) + +endif( FFTW_ROOT ) + +#--------------------------------------- components + +if (FFTW_DOUBLE_LIB) + set(FFTW_DOUBLE_LIB_FOUND TRUE) + set(FFTW_LIBRARIES ${FFTW_LIBRARIES} ${FFTW_DOUBLE_LIB}) + add_library(FFTW::Double INTERFACE IMPORTED) + set_target_properties(FFTW::Double + PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${FFTW_INCLUDE_DIRS}" + INTERFACE_LINK_LIBRARIES "${FFTW_DOUBLE_LIB}" + ) +else() + set(FFTW_DOUBLE_LIB_FOUND FALSE) +endif() + +if (FFTW_FLOAT_LIB) + set(FFTW_FLOAT_LIB_FOUND TRUE) + set(FFTW_LIBRARIES ${FFTW_LIBRARIES} ${FFTW_FLOAT_LIB}) + add_library(FFTW::Float INTERFACE IMPORTED) + set_target_properties(FFTW::Float + PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${FFTW_INCLUDE_DIRS}" + INTERFACE_LINK_LIBRARIES "${FFTW_FLOAT_LIB}" + ) +else() + set(FFTW_FLOAT_LIB_FOUND FALSE) +endif() + +if (FFTW_LONGDOUBLE_LIB) + set(FFTW_LONGDOUBLE_LIB_FOUND TRUE) + set(FFTW_LIBRARIES ${FFTW_LIBRARIES} ${FFTW_LONGDOUBLE_LIB}) + add_library(FFTW::LongDouble INTERFACE IMPORTED) + set_target_properties(FFTW::LongDouble + PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${FFTW_INCLUDE_DIRS}" + INTERFACE_LINK_LIBRARIES "${FFTW_LONGDOUBLE_LIB}" + ) +else() + set(FFTW_LONGDOUBLE_LIB_FOUND FALSE) +endif() + +if (FFTW_DOUBLE_THREADS_LIB) + set(FFTW_DOUBLE_THREADS_LIB_FOUND TRUE) + set(FFTW_LIBRARIES ${FFTW_LIBRARIES} ${FFTW_DOUBLE_THREADS_LIB}) + add_library(FFTW::DoubleThreads INTERFACE IMPORTED) + set_target_properties(FFTW::DoubleThreads + PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${FFTW_INCLUDE_DIRS}" + INTERFACE_LINK_LIBRARIES "${FFTW_DOUBLETHREADS_LIB}" + ) +else() + set(FFTW_DOUBLE_THREADS_LIB_FOUND FALSE) +endif() + +if (FFTW_FLOAT_THREADS_LIB) + set(FFTW_FLOAT_THREADS_LIB_FOUND TRUE) + set(FFTW_LIBRARIES ${FFTW_LIBRARIES} ${FFTW_FLOAT_THREADS_LIB}) + add_library(FFTW::FloatThreads INTERFACE IMPORTED) + set_target_properties(FFTW::FloatThreads + PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${FFTW_INCLUDE_DIRS}" + INTERFACE_LINK_LIBRARIES "${FFTW_FLOAT_THREADS_LIB}" + ) +else() + set(FFTW_FLOAT_THREADS_LIB_FOUND FALSE) +endif() + +if (FFTW_LONGDOUBLE_THREADS_LIB) + set(FFTW_LONGDOUBLE_THREADS_LIB_FOUND TRUE) + set(FFTW_LIBRARIES ${FFTW_LIBRARIES} ${FFTW_LONGDOUBLE_THREADS_LIB}) + add_library(FFTW::LongDoubleThreads INTERFACE IMPORTED) + set_target_properties(FFTW::LongDoubleThreads + PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${FFTW_INCLUDE_DIRS}" + INTERFACE_LINK_LIBRARIES "${FFTW_LONGDOUBLE_THREADS_LIB}" + ) +else() + set(FFTW_LONGDOUBLE_THREADS_LIB_FOUND FALSE) +endif() + +if (FFTW_DOUBLE_OPENMP_LIB) + set(FFTW_DOUBLE_OPENMP_LIB_FOUND TRUE) + set(FFTW_LIBRARIES ${FFTW_LIBRARIES} ${FFTW_DOUBLE_OPENMP_LIB}) + add_library(FFTW::DoubleOpenMP INTERFACE IMPORTED) + set_target_properties(FFTW::DoubleOpenMP + PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${FFTW_INCLUDE_DIRS}" + INTERFACE_LINK_LIBRARIES "${FFTW_DOUBLE_OPENMP_LIB}" + ) +else() + set(FFTW_DOUBLE_OPENMP_LIB_FOUND FALSE) +endif() + +if (FFTW_FLOAT_OPENMP_LIB) + set(FFTW_FLOAT_OPENMP_LIB_FOUND TRUE) + set(FFTW_LIBRARIES ${FFTW_LIBRARIES} ${FFTW_FLOAT_OPENMP_LIB}) + add_library(FFTW::FloatOpenMP INTERFACE IMPORTED) + set_target_properties(FFTW::FloatOpenMP + PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${FFTW_INCLUDE_DIRS}" + INTERFACE_LINK_LIBRARIES "${FFTW_FLOAT_OPENMP_LIB}" + ) +else() + set(FFTW_FLOAT_OPENMP_LIB_FOUND FALSE) +endif() + +if (FFTW_LONGDOUBLE_OPENMP_LIB) + set(FFTW_LONGDOUBLE_OPENMP_LIB_FOUND TRUE) + set(FFTW_LIBRARIES ${FFTW_LIBRARIES} ${FFTW_LONGDOUBLE_OPENMP_LIB}) + add_library(FFTW::LongDoubleOpenMP INTERFACE IMPORTED) + set_target_properties(FFTW::LongDoubleOpenMP + PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${FFTW_INCLUDE_DIRS}" + INTERFACE_LINK_LIBRARIES "${FFTW_LONGDOUBLE_OPENMP_LIB}" + ) +else() + set(FFTW_LONGDOUBLE_OPENMP_LIB_FOUND FALSE) +endif() + +#--------------------------------------- end components + +set( CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES_SAV} ) + +include(FindPackageHandleStandardArgs) + +find_package_handle_standard_args(FFTW2 + REQUIRED_VARS FFTW_INCLUDE_DIRS + HANDLE_COMPONENTS + ) + +mark_as_advanced( + FFTW_INCLUDE_DIRS + FFTW_LIBRARIES + FFTW_FLOAT_LIB + FFTW_DOUBLE_LIB + FFTW_LONGDOUBLE_LIB + FFTW_FLOAT_THREADS_LIB + FFTW_DOUBLE_THREADS_LIB + FFTW_LONGDOUBLE_THREADS_LIB + FFTW_FLOAT_OPENMP_LIB + FFTW_DOUBLE_OPENMP_LIB + FFTW_LONGDOUBLE_OPENMP_LIB + ) diff --git a/docs/source/installation.rst b/docs/source/installation.rst index e4292179..43e990d8 100644 --- a/docs/source/installation.rst +++ b/docs/source/installation.rst @@ -2,30 +2,139 @@ Installation ============ -SRW package consists of a C++ library and client libraries for: +SRW uses leverages the OS portability features of CMake for its build system. +This package consists of a C++ library and client libraries for: - C - Python - Igor PRO +------------ +Dependencies +------------ + +SRW depends on the following external dependencies: + +- CMake >= 3.12 +- C/C++ compiler +- FFTW library (3.x for regular build or 2.x if selecting OpenMP) + +Note: The proper FFTW library will be built as part of the C++ library if not found on the system. + +Optional Dependencies +===================== + +- Python 2.7 or 3.6+ (required for Python client) +- Igor Pro (required for Igor Pro client) +- Igor XOP (required for Igor Pro client) + +--------------- +Build Procedure +--------------- + +As mentioned above, SRW relies on CMake for generation of the files necessary for +building the main SRW and client libraries. + +For users looking for the Python client, the procedure is very straightforward +and does not require source build. Please find the instructions below. + +The Source Build is only recommended for users that need the main SRW library to +link with other code or the C and Igor client libraries. + +Source Build +============ + +Before diving on the details for the source build of SRW library it is important +to first look into the options available via CMake to configure the build and install +of the package. + +CMake Options +^^^^^^^^^^^^^ + +Here are the cmake options along with their usage and description for SRW library. + +====================== ====== =============================================== ========================================================== +Option Type Usage Description +====================== ====== =============================================== ========================================================== +-DUSE_OPENMP (bool) -DUSE_OPENMP= Whether or not to build OpenMP capable library +-DBUILD_CLIENT_C (bool) -DBUILD_CLIENT_C= Whether or not to build the C client library +-DBUILD_CLIENT_PYTHON (bool) -DBUILD_CLIENT_PYTHON= Whether or not to build the Python client library +-DCMAKE_INSTALL_PREFIX (str) -DCMAKE_INSTALL_PREFIX=/home/user/software/SRW The path in which to install the build artifacts +====================== ====== =============================================== ========================================================== + + Linux/macOS Instructions ^^^^^^^^^^^^^^^^^^^^^^^^ -From the SRW root folder run:: +When building cmake-based projects, it is common practice to do so in a folder other than the project root directory. + +As a way to demonstrate how to build and install the SRW library we will simulate a case in which an user wants to +build and install the SRW library (with OpenMP) along with the C client only and have it installed at a specific folder under its home directory. + +Here are the steps:: - $ make all + $ cd SRW # This is the folder in which you have the SRW code + $ mkdir build + $ cd build + $ cmake .. -DUSE_OPENMP=ON -DBUILD_CLIENT_C=ON -DCMAKE_INSTALL_PREFIX=/home/user/my_install_folder/ + $ make + $ make install -This command will build the needed dependencies, the main SRW library and also the Python library to be used. +Windows +^^^^^^^ + +When building cmake-based projects, it is common practice to do so in a folder other than the project root directory. + +As a way to demonstrate how to build and install the SRW library we will simulate a case in which an user wants to +build and install the SRW library (with OpenMP) along with the C client only and have it installed at a specific folder under its C: drive. + +Here are the steps:: -To build SRW with OpenMP support use:: + $ cd SRW # This is the folder in which you have the SRW code + $ mkdir build + $ cd build + $ cmake .. -GNMake Makefiles -DUSE_OPENMP=ON -DBUILD_CLIENT_C=ON -DCMAKE_INSTALL_PREFIX=C:\my_install_folder + $ cmake --build . --config Release --target install - $ MODE=omp make all +Note: For Windows it is necessary to specify the *-G* option to select a build system that does not support multi-configuration builds otherwise it will install +the artifacts in a folder called Release or Debug depending on the *--config* selected. + +Python Client +============= + +When installing the Python client, it will automatically take care of building +the SRW library as part of the process. + +Linux/macOS Instructions +^^^^^^^^^^^^^^^^^^^^^^^^ -After this step is concluded, you can use the Python library by adding the `python` folder to your `PYTHONPATH` variable -or install the `srwpy` package at your Python distribution via the `setup.py` file. +In order to install the regular SRW (non-OpenMP) do:: + + $ cd python + $ python setup.py install + +In order to install the OpenMP capable SRW do:: + + $ cd python + $ MODE=omp python setup.py install Windows ^^^^^^^ -TODO +In order to install the regular SRW (non-OpenMP) do:: + + $ cd python + $ python setup.py install + +In order to install the OpenMP capable SRW do:: + + $ cd python + $ set MODE=omp + $ python setup.py install + + +Igor Pro Client +=============== + +TODO \ No newline at end of file diff --git a/ext_lib/CMakeLists.txt b/ext_lib/CMakeLists.txt new file mode 100644 index 00000000..9eac7156 --- /dev/null +++ b/ext_lib/CMakeLists.txt @@ -0,0 +1,7 @@ +if(USE_OPENMP) + message(STATUS "Looking for FFTW2") + add_subdirectory(fftw) +else() + message(STATUS "Looking for FFTW3") + add_subdirectory(fftw3) +endif() \ No newline at end of file diff --git a/ext_lib/fftw/CMakeLists.txt b/ext_lib/fftw/CMakeLists.txt new file mode 100644 index 00000000..37fbbd8e --- /dev/null +++ b/ext_lib/fftw/CMakeLists.txt @@ -0,0 +1,105 @@ +find_package(FFTW2 QUIET COMPONENTS FLOAT_LIB) + +if(FFTW2_FOUND) + message(STATUS "Found FFTW2F: ${FFTW_FLOAT_LIB}") + + set( + FFTW_DOUBLE_LIB ${FFTW_DOUBLE_LIB} + CACHE PATH "Path to FFTW" + FORCE + ) + +else() + message(STATUS "Suitable FFTW could not be located. Downloading and building!") + + include(ExternalProject) + + if(UNIX) + + ExternalProject_Add(fftw_external + URL + http://www.fftw.org/fftw-2.1.5.tar.gz + URL_HASH + MD5=8d16a84f3ca02a785ef9eb36249ba433 + CMAKE_ARGS -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} + PREFIX ${CMAKE_CURRENT_BINARY_DIR} + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + # This cp line is important. FFTW 2 must be build inplace otherwise + # the make part will generate invalid library... + COMMAND cp -r ${CMAKE_CURRENT_BINARY_DIR}/src/fftw_external/. . + COMMAND ./configure --enable-float --with-pic + COMMAND sed -i.bak -e "s/^CFLAGS = /CFLAGS = -fPIC /" Makefile + COMMAND make -j8 + COMMAND mkdir -p ${STAGED_INSTALL_PREFIX}/lib + COMMAND cp fftw/.libs/libfftw.a ${STAGED_INSTALL_PREFIX}/lib + INSTALL_COMMAND "" + ) + + include(GNUInstallDirs) + + set( + FFTW_ROOT ${STAGED_INSTALL_PREFIX} + CACHE PATH "Path to internally built FFTWConfig.cmake" + FORCE + ) + + set( + FFTW_DOUBLE_LIB ${STAGED_INSTALL_PREFIX}/lib/libfftw.a + CACHE PATH "Path to FFTW" + FORCE + ) + + set( + FFTW_FLOAT_LIB + CACHE PATH "Path to FFTWF" + FORCE + ) + + + # Libraries + add_library(fftw STATIC IMPORTED) + set_property(TARGET fftw PROPERTY IMPORTED_LOCATION ${STAGED_INSTALL_PREFIX}/lib/libfftw.a) + endif() + if(WIN32) + ExternalProject_Add(fftw_external + URL + https://github.com/ochubar/SRW/raw/master/ext_lib/fftw64_f.lib + URL_HASH + MD5=3e34fe1af702ba2af176e83a39021250 + DOWNLOAD_NAME fftwf.lib + DOWNLOAD_DIR ${STAGED_INSTALL_PREFIX}/lib + DOWNLOAD_NO_EXTRACT true + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + ) + + include(GNUInstallDirs) + + set( + FFTW_ROOT ${STAGED_INSTALL_PREFIX} + CACHE PATH "Path to internally built FFTWConfig.cmake" + FORCE + ) + + set( + FFTW_DOUBLE_LIB ${STAGED_INSTALL_PREFIX}/lib/fftwf.lib + CACHE PATH "Path to FFTW" + FORCE + ) + + set( + FFTW_FLOAT_LIB + CACHE PATH "Path to FFTWF" + FORCE + ) + + + # Libraries + add_library(fftw STATIC IMPORTED) + set_property(TARGET fftw PROPERTY IMPORTED_LOCATION ${STAGED_INSTALL_PREFIX}/lib/fftwf.lib) + endif() + add_dependencies(fftw fftw_external) + +endif() diff --git a/ext_lib/fftw3/CMakeLists.txt b/ext_lib/fftw3/CMakeLists.txt new file mode 100644 index 00000000..930b501c --- /dev/null +++ b/ext_lib/fftw3/CMakeLists.txt @@ -0,0 +1,118 @@ +find_package(FFTW QUIET COMPONENTS FLOAT_LIB DOUBLE_LIB) + +if(FFTW_FOUND) + message(STATUS "Found FFTW3: ${FFTW_DOUBLE_LIB}") + message(STATUS "Found FFTW3F: ${FFTW_FLOAT_LIB}") + + set( + FFTW_DOUBLE_LIB ${FFTW_DOUBLE_LIB} + CACHE PATH "Path to FFTW" + FORCE + ) + + set( + FFTW_FLOAT_LIB ${FFTW_FLOAT_LIB} + CACHE PATH "Path to FFTWF" + FORCE + ) + +else() + message(STATUS "Suitable FFTW3 could not be located. Downloading and building!") + include(ExternalProject) + + if(UNIX) + + + ExternalProject_Add(fftw3_external + URL + http://www.fftw.org/fftw-3.3.8.tar.gz + URL_HASH + MD5=8aac833c943d8e90d51b697b27d4384d + PREFIX ${CMAKE_CURRENT_BINARY_DIR} + CONFIGURE_COMMAND "" + BUILD_COMMAND + ${CMAKE_CURRENT_BINARY_DIR}/src/fftw3_external/configure --enable-float --with-pic --prefix=${STAGED_INSTALL_PREFIX} && + make -j8 && + make install && + make clean && + ${CMAKE_CURRENT_BINARY_DIR}/src/fftw3_external/configure --with-pic --prefix=${STAGED_INSTALL_PREFIX} && + make -j8 && + make install + INSTALL_COMMAND "" + PREFIX=${CMAKE_CURRENT_BINARY_DIR} + ) + + include(GNUInstallDirs) + + set( + FFTW_ROOT ${STAGED_INSTALL_PREFIX} + CACHE PATH "Path to internally built FFTW3Config.cmake" + FORCE + ) + + set( + FFTW_DOUBLE_LIB ${STAGED_INSTALL_PREFIX}/lib/libfftw3.a + CACHE PATH "Path to FFTW" + FORCE + ) + + set( + FFTW_FLOAT_LIB ${STAGED_INSTALL_PREFIX}/lib/libfftw3f.a + CACHE PATH "Path to FFTWF" + FORCE + ) + + # Libraries + add_library(fftw3 STATIC IMPORTED) + set_property(TARGET fftw3 PROPERTY IMPORTED_LOCATION ${STAGED_INSTALL_PREFIX}/lib/libfftw3.a) + add_library(fftw3f STATIC IMPORTED) + set_property(TARGET fftw3f PROPERTY IMPORTED_LOCATION ${STAGED_INSTALL_PREFIX}/lib/libfftw3f.a) + endif() + if(WIN32) + ExternalProject_Add(fftw3_external + URL + http://www.fftw.org/fftw-3.3.8.tar.gz + URL_HASH + MD5=8aac833c943d8e90d51b697b27d4384d + PREFIX ${CMAKE_CURRENT_BINARY_DIR} + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + COMMAND cmake ${CMAKE_CURRENT_BINARY_DIR}/src/fftw3_external/ -DBUILD_SHARED_LIBS=OFF -DENABLE_FLOAT=ON -DBUILD_TESTS=OFF -DCMAKE_INSTALL_PREFIX=${STAGED_INSTALL_PREFIX} + COMMAND cmake --build . --config Release --target install + COMMAND cmake ${CMAKE_CURRENT_BINARY_DIR}/src/fftw3_external/ -DBUILD_SHARED_LIBS=OFF -DENABLE_FLOAT=OFF -DBUILD_TESTS=OFF-DCMAKE_INSTALL_PREFIX=${STAGED_INSTALL_PREFIX} + COMMAND cmake --build . --config Release --target install + INSTALL_COMMAND "" + ) + + include(GNUInstallDirs) + + + set( + FFTW_ROOT ${STAGED_INSTALL_PREFIX} + CACHE PATH "Path to internally built FFTW3Config.cmake" + FORCE + ) + + set( + FFTW_DOUBLE_LIB ${STAGED_INSTALL_PREFIX}/lib/fftw3.lib + CACHE PATH "Path to FFTW" + FORCE + ) + + set( + FFTW_FLOAT_LIB ${STAGED_INSTALL_PREFIX}/lib/fftw3f.lib + CACHE PATH "Path to FFTWF" + FORCE + ) + + # Libraries + add_library(fftw3 STATIC IMPORTED) + set_property(TARGET fftw3 PROPERTY IMPORTED_LOCATION ${STAGED_INSTALL_PREFIX}/lib/fftw3.lib) + add_library(fftw3f STATIC IMPORTED) + set_property(TARGET fftw3f PROPERTY IMPORTED_LOCATION ${STAGED_INSTALL_PREFIX}/lib/fftw3f.lib) + endif() + + add_dependencies(fftw3 fftw3_external) + add_dependencies(fftw3f fftw3_external) + +endif() diff --git a/python/setup.py b/python/setup.py index bc4afa2a..1c8669c9 100644 --- a/python/setup.py +++ b/python/setup.py @@ -1,25 +1,69 @@ import os -from setuptools import setup, find_packages, Extension - -ext_kwargs = {'define_macros': [('MAJOR_VERSION', '1'), ('MINOR_VERSION', '0')], - 'include_dirs': [os.path.abspath('../src/lib')], - 'library_dirs': [os.path.abspath('../src'), os.path.abspath('../ext_lib')], - 'sources': [os.path.abspath('../src/clients/python/srwlpy.cpp')]} - -if 'MODE' in os.environ: - sMode = str(os.environ['MODE']) - if sMode == 'omp': - ext_kwargs.update({'libraries': ['srw', 'm', 'fftw'], #OC07022019 - 'extra_link_args': ['-fopenmp'], - 'extra_compile_args': ['-Wno-sign-compare','-Wno-parentheses','-fopenmp','-Wno-write-strings']}) - elif sMode == '0': - ext_kwargs.update({'libraries': ['srw', 'm', 'fftw3f', 'fftw3']}) #OC07022019 - else: - raise Exception("Unknown SRW compilation/linking option") - -srwlpy = Extension('srwlpy', **ext_kwargs) - -setup(name='SRW Python interface', +import re +import sys +import subprocess + +from distutils.version import LooseVersion +from setuptools import setup, Extension, find_packages +from setuptools.command.build_ext import build_ext + + +class CMakeExtension(Extension): + def __init__(self, name, sourcedir='', package_name=''): + Extension.__init__(self, name, sources=[]) + self.sourcedir = os.path.abspath(sourcedir) + self.package_name = package_name + + +class CMakeBuild(build_ext): + def run(self): + try: + out = subprocess.check_output(['cmake', '--version']) + except OSError: + raise RuntimeError( + "CMake must be installed to build the following extensions: " + + ", ".join(e.name for e in self.extensions)) + + cmake_version = LooseVersion(re.search(r'version\s*([\d.]+)', + out.decode()).group(1)) + if cmake_version < '3.12.0': + raise RuntimeError("CMake >= 3.12.0 is required.") + + for ext in self.extensions: + self.build_extension(ext) + + def build_extension(self, ext): + extdir = os.path.abspath( + os.path.dirname(self.get_ext_fullpath(ext.name))) + extdir = os.path.join(extdir, ext.package_name) + cmake_args = [ + '-DBUILD_CLIENT_PYTHON=ON', + '-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=' + extdir, + '-DCMAKE_RUNTIME_OUTPUT_DIRECTORY=' + extdir, + '-DPYTHON_EXECUTABLE=' + sys.executable] + env = os.environ.copy() + if 'MODE' in env: + if env['MODE'] == 'omp': + cmake_args += ['-DUSE_OPENMP=ON'] + if os.name == 'nt': + # We need makefile generator that does not support multi-configuration builds + # otherwise windows will output a Release or Debug folder in which the artifacts + # will be located. + cmake_args.append('-GNMake Makefiles') + + if not os.path.exists(self.build_temp): + os.makedirs(self.build_temp) + print('Using cmake args as: ', cmake_args) + subprocess.check_call(['cmake', ext.sourcedir] + cmake_args, + cwd=self.build_temp, env=env) + subprocess.check_call(['cmake', '--build', '.', '--config', 'Release'], + cwd=self.build_temp) + print() # Add an empty line for cleaner output + +base_dir = os.path.dirname(os.path.realpath(__file__)) +original_src_dir = os.path.join(base_dir, '..') + +setup(name='srwpy', version='1.0', description='This is SRW for Python', author='O. Chubar et al.', @@ -29,4 +73,7 @@ This is SRW for Python. ''', packages=find_packages(exclude=['docs', 'tests']), - ext_modules=[srwlpy]) + zip_safe=False, + ext_modules=[CMakeExtension('srwlpy', original_src_dir, 'srwpy')], + cmdclass=dict(build_ext=CMakeBuild) +) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 00000000..3e0c6b28 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,30 @@ +# OS Dependent configurations +if(UNIX) + if (APPLE) # MacOS + add_definitions(-D__MAC__) + else() # Linux + add_definitions(-DLINUX) + endif() + add_compile_options(-fPIC) +else() # Windows + set(WINDOWS_EXPORT_ALL_SYMBOLS ON) + add_definitions(-DWIN32 -D_WINDOWS -D_USRDLL -D_CRT_SECURE_NO_WARNINGS -DNON_UNIX_STDIO -D__VC__) +endif() + + +message(STATUS "Compiler is: ${CMAKE_C_COMPILER} | ${CMAKE_CXX_COMPILER}") + +if(USE_OPENMP) + find_package(OpenMP REQUIRED) + message(STATUS "OpenMP libomp location: ${OpenMP_libomp_LIBRARY} | Include: ${OpenMP_CXX_INCLUDE_DIRS}") + message(STATUS "OpenMP Flags: C -> ${OpenMP_C_FLAGS} | CXX -> ${OpenMP_CXX_FLAGS}") + set(SRW_DEFINITIONS -D_GNU_SOURCE -D__USE_XOPEN2K8 -DFFTW_ENABLE_FLOAT -D_GM_WITHOUT_BASE -DSRWLIB_STATIC -DNO_TIMER -DANSI_DECLARATORS -DTRILIBRARY -D_WITH_OMP) +else() + set(SRW_DEFINITIONS -D_GNU_SOURCE -D__USE_XOPEN2K8 -DFFTW_ENABLE_FLOAT -D_GM_WITHOUT_BASE -DSRWLIB_STATIC -DNO_TIMER -DANSI_DECLARATORS -DTRILIBRARY -D_FFTW3) +endif() + +add_subdirectory(ext) +add_subdirectory(core) +add_subdirectory(lib) + +add_subdirectory(clients) \ No newline at end of file diff --git a/src/clients/CMakeLists.txt b/src/clients/CMakeLists.txt new file mode 100644 index 00000000..ec94c26d --- /dev/null +++ b/src/clients/CMakeLists.txt @@ -0,0 +1,11 @@ +if(BUILD_CLIENT_C) + add_subdirectory(c) +endif() + +if(BUILD_CLIENT_PYTHON) + add_subdirectory(python) +endif() + +if(BUILD_CLIENT_IGOR) + add_subdirectory(igor) +endif() \ No newline at end of file diff --git a/src/clients/c/CMakeLists.txt b/src/clients/c/CMakeLists.txt new file mode 100644 index 00000000..207924fc --- /dev/null +++ b/src/clients/c/CMakeLists.txt @@ -0,0 +1,13 @@ +set(srw_clients_c_source_files + srwlclient.cpp +) + +add_executable(srwlclient ${srw_clients_c_source_files}) + +target_link_libraries(srwlclient srw) + +target_include_directories(srwlclient PUBLIC + $ +) + +install(TARGETS srwlclient RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) \ No newline at end of file diff --git a/src/clients/python/CMakeLists.txt b/src/clients/python/CMakeLists.txt new file mode 100644 index 00000000..11fbacda --- /dev/null +++ b/src/clients/python/CMakeLists.txt @@ -0,0 +1,43 @@ +# for testing we will need the python interpreter +find_package(PythonInterp REQUIRED) + +# we require python development headers +find_package(PythonLibs ${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR} EXACT REQUIRED) + + +set(srw_clients_python_source_files + srwlpy.cpp +) + +add_library(srwlpy SHARED ${srw_clients_python_source_files}) + +target_include_directories(srwlpy PUBLIC ${PYTHON_INCLUDE_DIRS}) + +target_include_directories(srwlpy PUBLIC $) + +# prevent cmake from creating a "lib" prefix +set_target_properties(srwlpy PROPERTIES PREFIX "") + +if (UNIX) + # Math library is only needed by unix. When using Windows, VS does it for you. + target_link_libraries(srwlpy m ${FFTW_DOUBLE_LIB} ${FFTW_FLOAT_LIB} srw) + + set_target_properties(srwlpy PROPERTIES SUFFIX ".so") + + # The -shared flag is only valid for UNIX systems. + set_target_properties(srwlpy PROPERTIES LINK_FLAGS "-shared") +endif() + +if(APPLE) + # We need the undefined dynamic_lookup to overcome issues with a statically linked + # python. More details here: https://gitlab.kitware.com/vtk/vtk/-/issues/17214 + set_target_properties(srwlpy PROPERTIES LINK_FLAGS "-undefined dynamic_lookup -shared") +endif() + +if(WIN32) + target_link_libraries(srwlpy srw ${PYTHON_LIBRARIES}) + set_target_properties(srwlpy PROPERTIES SUFFIX ".pyd") +endif() + + +install(TARGETS srwlpy LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) \ No newline at end of file diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt new file mode 100644 index 00000000..5dd800c9 --- /dev/null +++ b/src/core/CMakeLists.txt @@ -0,0 +1,59 @@ +set(core_source_files + srclcuti.cpp + srcradint.cpp + srctrjdt.cpp + sremitpr.cpp + srgsnbm.cpp + srgtrjdt.cpp + srisosrc.cpp + srmagcnt.cpp + srmagfld.cpp + srmatsta.cpp + sroptapt.cpp + sroptcnt.cpp + sroptdrf.cpp + sroptel2.cpp + sroptel3.cpp + sroptelm.cpp + sroptfoc.cpp + sroptgrat.cpp + sroptgtr.cpp + sropthck.cpp + sroptcryst.cpp + sroptmat.cpp + sroptpsh.cpp + sroptshp.cpp + sroptsmr.cpp + sroptwgr.cpp + sroptzp.cpp + sroptzps.cpp + srpersto.cpp + srpowden.cpp + srprdint.cpp + srprgind.cpp + srpropme.cpp + srptrjdt.cpp + srradinc.cpp + srradint.cpp + srradmnp.cpp + srradstr.cpp + srremflp.cpp + srsase.cpp + srsend.cpp + srstowig.cpp + srsysuti.cpp + srthckbm.cpp + srthckbm2.cpp + srtrjaux.cpp + srtrjdat.cpp + srtrjdat3d.cpp +) + +add_library(core OBJECT ${core_source_files}) +target_link_libraries(core genesis) +target_compile_definitions(core PRIVATE ${SRW_DEFINITIONS}) + +target_include_directories(core PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) +target_include_directories(core PUBLIC + $ +) \ No newline at end of file diff --git a/src/core/sroptel2.cpp b/src/core/sroptel2.cpp index 42117619..95c21204 100644 --- a/src/core/sroptel2.cpp +++ b/src/core/sroptel2.cpp @@ -182,10 +182,13 @@ int srTGenOptElem::PropagateRadiationMeth_0(srTSRWRadStructAccessData* pRadAcces bool* gridParamWereModif = new bool[neOrig]; //SY: return outside of parallel regions is not allowed - we do it outside - - int* results = new int[neOrig]; - if(results == 0) return MEMORY_ALLOCATION_FAILURE; - for(int ie = 0; ie < neOrig; ie++) results[ie] = 0; + int* single_results = new int[neOrig]; + if(single_results == 0) return MEMORY_ALLOCATION_FAILURE; + int max_threads = omp_get_max_threads(); + int* thread_results = new int[max_threads]; + if(thread_results == 0) return MEMORY_ALLOCATION_FAILURE; + for(int ie = 0; ie < neOrig; ie++) single_results[ie] = 0; + for(int tn = 0; tn < max_threads; tn++) thread_results[tn] = 0; //OC31102018: added by SY (for profiling?) at parallelizing SRW via OpenMP //srwlPrintTime(": PropagateRadiationMeth_0 : before cycle",&start); @@ -201,15 +204,15 @@ int srTGenOptElem::PropagateRadiationMeth_0(srTSRWRadStructAccessData* pRadAcces { int threadNum = omp_get_thread_num(); srTSRWRadStructAccessData *pRadDataSingleE = 0; - results[threadNum] = SetupNewRadStructFromSliceConstE(pRadAccessData, -1, pRadDataSingleE); + thread_results[threadNum] = SetupNewRadStructFromSliceConstE(pRadAccessData, -1, pRadDataSingleE); //allocates new pRadDataSingleE ! - if(!results[threadNum]) + if(!thread_results[threadNum]) { #pragma omp for for(int ie=0; iepBaseRadX, pRadDataSingleE->pBaseRadZ)) continue; + if(single_results[ie] = ExtractRadSliceConstE(pRadAccessData, ie, pRadDataSingleE->pBaseRadX, pRadDataSingleE->pBaseRadZ)) continue; pRadDataSingleE->eStart = pRadAccessData->eStart + ie*pRadAccessData->eStep; long OffsetMom = AmOfMoments*ie; pRadDataSingleE->pMomX = pRadAccessData->pMomX + OffsetMom; @@ -231,7 +234,7 @@ int srTGenOptElem::PropagateRadiationMeth_0(srTSRWRadStructAccessData* pRadAcces if(pPrevRadDataSingleE != 0) { - if(results[ie] = ExtractRadSliceConstE(pRadAccessData, ie, pPrevRadDataSingleE->pBaseRadX, pPrevRadDataSingleE->pBaseRadZ, true)) continue; //OC120908 + if(single_results[ie] = ExtractRadSliceConstE(pRadAccessData, ie, pPrevRadDataSingleE->pBaseRadX, pPrevRadDataSingleE->pBaseRadZ, true)) continue; //OC120908 pPrevRadDataSingleE->eStart = pRadDataSingleE->eStart; pPrevRadDataSingleE->pMomX = pRadDataSingleE->pMomX; pPrevRadDataSingleE->pMomZ = pRadDataSingleE->pMomZ; @@ -239,9 +242,9 @@ int srTGenOptElem::PropagateRadiationMeth_0(srTSRWRadStructAccessData* pRadAcces //if(results[ie] = PropagateRadiationSingleE_Meth_0(pRadDataSingleE, pPrevRadDataSingleE, pBuf)) continue; //OC06092019 //OC01102019 (restored) - if(results[ie] = PropagateRadiationSingleE_Meth_0(pRadDataSingleE, pPrevRadDataSingleE)) continue; //from derived classes + if(single_results[ie] = PropagateRadiationSingleE_Meth_0(pRadDataSingleE, pPrevRadDataSingleE)) continue; //from derived classes - if(results[ie] = UpdateGenRadStructSliceConstE_Meth_0(pRadDataSingleE, ie, pRadAccessData, 1)) continue; + if(single_results[ie] = UpdateGenRadStructSliceConstE_Meth_0(pRadDataSingleE, ie, pRadAccessData, 1)) continue; //the above doesn't change the transverse grid parameters in *pRadAccessData //vRadSlices.push_back(*pRadDataSingleE); //this automatically calls destructor, which can eventually delete "emulated" structs! @@ -259,8 +262,13 @@ int srTGenOptElem::PropagateRadiationMeth_0(srTSRWRadStructAccessData* pRadAcces if(pRadDataSingleE != 0) delete pRadDataSingleE; } - for(int ie = 0; ie < neOrig; ie++) if(results[ie]) return results[ie]; - delete[] results; + // check results, free memory, exit if there was error + result = 0; + for(int ie = 0; ie < neOrig; ie++) if(single_results[ie]) result = single_results[ie]; + for(int tn = 0; tn < max_threads; tn++) if(thread_results[tn]) result = thread_results[tn]; + delete[] single_results; + delete[] thread_results; + if (result) return result; //OC31102018: added by SY (for profiling?) at parallelizing SRW via OpenMP //char str[256]; diff --git a/src/core/sroptelm.cpp b/src/core/sroptelm.cpp index 5bd83e8c..336d5567 100644 --- a/src/core/sroptelm.cpp +++ b/src/core/sroptelm.cpp @@ -1341,14 +1341,16 @@ int srTGenOptElem::SetRadRepres(srTSRWRadStructAccessData* pRadAccessData, char //} #else //OC28102018: modified by SY - //Added by SY (for profiling?) at parallelizing SRW via OpenMP: - //srwlPrintTime("SetRadRepres : setup",&start); - //SY: return outside of parallel regions is not allowed - we do it outside - int* results = new int[pRadAccessData->ne]; - if(results == 0) return MEMORY_ALLOCATION_FAILURE; - for(long ie = 0; ie < pRadAccessData->ne; ie++) results[ie]=0; + int* single_results = new int[pRadAccessData->ne]; + if(single_results == 0) return MEMORY_ALLOCATION_FAILURE; + for(long ie = 0; ie < pRadAccessData->ne; ie++) single_results[ie]=0; + + int max_threads = omp_get_max_threads(); + int* thread_results = new int[max_threads]; + if(thread_results == 0) return MEMORY_ALLOCATION_FAILURE; + for(int tn = 0; tn < max_threads; tn++) thread_results[tn] = 0; //SY: creation (and deletion) of FFTW plans is not thread-safe. Have to do this outside of threads. //(and we don't need to recreate plans for same dimensions anyway) @@ -1372,14 +1374,14 @@ int srTGenOptElem::SetRadRepres(srTSRWRadStructAccessData* pRadAccessData, char //members are changed inside Make2DFFT. CGenMathFFT2DInfo FFT2DInfo_local = FFT2DInfo; - if(results[ie] = ExtractRadSliceConstE(pRadAccessData, ie, AuxEx, AuxEz)) continue; + if(single_results[ie] = ExtractRadSliceConstE(pRadAccessData, ie, AuxEx, AuxEz)) continue; srTDataPtrsForWfrEdgeCorr DataPtrsForWfrEdgeCorr; if(WfrEdgeCorrShouldBeTreated) { if(CoordOrAng == 1) { - if(results[ie] = SetupWfrEdgeCorrData(pRadAccessData, AuxEx, AuxEz, DataPtrsForWfrEdgeCorr)) continue; + if(single_results[ie] = SetupWfrEdgeCorrData(pRadAccessData, AuxEx, AuxEz, DataPtrsForWfrEdgeCorr)) continue; } } @@ -1388,10 +1390,10 @@ int srTGenOptElem::SetRadRepres(srTSRWRadStructAccessData* pRadAccessData, char if(ar_zStartInSlicesE != 0) FFT2DInfo_local.yStart = ar_zStartInSlicesE[ie]; FFT2DInfo_local.pData = AuxEx; - if(results[ie] = FFT2D.Make2DFFT(FFT2DInfo_local, &Plan2DFFT)) continue; + if(single_results[ie] = FFT2D.Make2DFFT(FFT2DInfo_local, &Plan2DFFT)) continue; FFT2DInfo_local.pData = AuxEz; - if(results[ie] = FFT2D.Make2DFFT(FFT2DInfo_local, &Plan2DFFT)) continue; + if(single_results[ie] = FFT2D.Make2DFFT(FFT2DInfo_local, &Plan2DFFT)) continue; if(WfrEdgeCorrShouldBeTreated) { @@ -1404,14 +1406,14 @@ int srTGenOptElem::SetRadRepres(srTSRWRadStructAccessData* pRadAccessData, char } } } - results[ie] = SetupRadSliceConstE(pRadAccessData, ie, AuxEx, AuxEz); + single_results[ie] = SetupRadSliceConstE(pRadAccessData, ie, AuxEx, AuxEz); //SY: save FFT2DInfo from one of FFT2DInfo_local if(ie == 0) FFT2DInfo = FFT2DInfo_local; } // end for } else { - results[omp_get_thread_num()] = MEMORY_ALLOCATION_FAILURE; + thread_results[omp_get_thread_num()] = MEMORY_ALLOCATION_FAILURE; } // end if if(AuxEx != 0) delete[] AuxEx; if(AuxEz != 0) delete[] AuxEz; @@ -1420,16 +1422,16 @@ int srTGenOptElem::SetRadRepres(srTSRWRadStructAccessData* pRadAccessData, char fftwnd_destroy_plan(Plan2DFFT); - for(long ie = 0; ie < pRadAccessData->ne; ie++) if(results[ie]) return results[ie]; - delete[] results; + // check results, free memory, exit if there was error + result = 0; + for(long ie = 0; ie < pRadAccessData->ne; ie++) if(single_results[ie]) result = single_results[ie]; + for(int tn = 0; tn < max_threads; tn++) if(thread_results[tn]) result = thread_results[tn]; + delete[] single_results; + delete[] thread_results; + if (result) return result; #endif } - //Added by SY (for profiling?) at parallelizing SRW via OpenMP: - //char str[256]; - //sprintf(str,"%s %d","::SetRadRepres : cycles:",pRadAccessData->ne); - //srwlPrintTime(str,&start); - pRadAccessData->xStep = FFT2DInfo.xStepTr; pRadAccessData->zStep = FFT2DInfo.yStepTr; pRadAccessData->xStart = FFT2DInfo.xStartTr; diff --git a/src/ext/CMakeLists.txt b/src/ext/CMakeLists.txt new file mode 100644 index 00000000..a9722d07 --- /dev/null +++ b/src/ext/CMakeLists.txt @@ -0,0 +1,3 @@ +add_subdirectory(auxparse) +add_subdirectory(genmath) +add_subdirectory(genesis) \ No newline at end of file diff --git a/src/ext/auxparse/CMakeLists.txt b/src/ext/auxparse/CMakeLists.txt new file mode 100644 index 00000000..19c09e44 --- /dev/null +++ b/src/ext/auxparse/CMakeLists.txt @@ -0,0 +1,8 @@ +set(auxparse_source_files + auxparse.cpp + auxparse.h +) + +add_library(auxparse OBJECT ${auxparse_source_files}) +target_include_directories(auxparse PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) +target_compile_definitions(auxparse PRIVATE ${SRW_DEFINITIONS}) diff --git a/src/ext/genesis/CMakeLists.txt b/src/ext/genesis/CMakeLists.txt new file mode 100644 index 00000000..b522f629 --- /dev/null +++ b/src/ext/genesis/CMakeLists.txt @@ -0,0 +1,32 @@ +set(genesis_source_files + all_com.c + check.c + diagno.c + esource.c + field.c + incoherent.c + initrun.c + input.c + loadbeam.c + loadrad.c + magfield.c + main.c + math.c + mpi.c + output.c + partsim.c + pushp.c + rpos.c + scan.c + source.c + stepz.c + string.c + tdepend.c + timerec.c + track.c +) + +add_library(genesis OBJECT ${genesis_source_files}) +target_link_libraries(genesis genmath) +target_include_directories(genesis PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) +target_compile_definitions(genesis PRIVATE ${SRW_DEFINITIONS}) diff --git a/src/ext/genmath/CMakeLists.txt b/src/ext/genmath/CMakeLists.txt new file mode 100644 index 00000000..41b1e776 --- /dev/null +++ b/src/ext/genmath/CMakeLists.txt @@ -0,0 +1,22 @@ +set(genmath_source_files + gmfft.cpp + gmfft.h + gmfit.cpp + gmfit.h + gminterp.cpp + gminterp.h + gmmeth.cpp + gmmeth.h + gmtrans.cpp + gmtrans.h +) + +add_library(genmath OBJECT ${genmath_source_files}) +target_link_libraries(genmath PUBLIC auxparse) +target_include_directories(genmath PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) + +if(USE_OPENMP) + target_include_directories(genmath PUBLIC ${OpenMP_CXX_INCLUDE_DIRS}) +endif() + +target_compile_definitions(genmath PRIVATE ${SRW_DEFINITIONS}) diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt new file mode 100644 index 00000000..2c17a1c6 --- /dev/null +++ b/src/lib/CMakeLists.txt @@ -0,0 +1,49 @@ +set(srw_lib_source_files + srwlib.cpp + srwlib.h + srerror.cpp + srerror.h +) + +add_library(srw STATIC + ${srw_lib_source_files} + $ + $ + $ + $ +) + + +# Add definitions needed to build SRW +target_compile_definitions(srw PUBLIC ${SRW_DEFINITIONS}) + +# Libraries in which SRW lib depends +target_link_libraries(srw core ${FFTW_DOUBLE_LIB} ${FFTW_FLOAT_LIB}) + +if (UNIX) + # Math library is only needed by unix. When using Windows, VS does it for you. + target_link_libraries(srw m) +endif() + +if (USE_OPENMP) + target_link_libraries(srw OpenMP::OpenMP_CXX) + target_include_directories(srw PUBLIC ${OpenMP_CXX_INCLUDE_DIRS}) +endif() + +target_include_directories(srw PUBLIC + $ +) +target_include_directories(srw PUBLIC + $ +) +target_include_directories(srw PUBLIC + $ +) +target_include_directories(srw PUBLIC + $ +) +target_include_directories(srw PUBLIC + $ +) + +install(TARGETS srw LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) \ No newline at end of file