diff --git a/CMakeLists.txt b/CMakeLists.txt index e4b337d..11c1fbf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,479 +1,349 @@ -project(MESS C CXX) -cmake_minimum_required(VERSION 3.16) - +# ============================================================================= +# Project Definition +# ============================================================================= +cmake_minimum_required(VERSION 3.22) +project(MESS LANGUAGES C CXX Fortran) + +# ============================================================================= +# Modern CMake Practices & Project-Wide Settings +# ============================================================================= +# Set C++ standard for all targets in the project set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") -set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}") +set(CMAKE_CXX_EXTENSIONS OFF) -# Options for automatic dependency handling -option(AUTO_DOWNLOAD_DEPENDENCIES "Automatically download and build missing dependencies" ON) -option(USE_SYSTEM_LIBS "Try to use system libraries before downloading" ON) +# Use a dedicated folder for external projects to keep the build directory clean +set(EXTERNAL_INSTALL_LOCATION ${CMAKE_BINARY_DIR}/_deps) -# Directory for downloaded and built dependencies -set(EXTERNAL_INSTALL_LOCATION ${CMAKE_BINARY_DIR}/external) +# Include required modules +include(FetchContent) include(ExternalProject) -# External library URLs and versions -set(OPENBLAS_GIT_URL "https://github.com/OpenMathLib/OpenBLAS.git") -set(OPENBLAS_VERSION "v0.3.21") -set(SLATEC_URL "https://www.netlib.org/slatec/slatec_src.tgz") -set(GSL_URL "https://ftp.gnu.org/gnu/gsl/gsl-2.7.tar.gz") -set(QD_URL "https://www.davidhbailey.com/dhbsoftware/qd-2.3.23.tar.gz") -set(QD_SHA256 "b3eaf41ce413ec08f348ee73e606bd3ff9203e411c377c3c0467f89acf69ee26") - -# Check for direct SLATEC build -if(USE_DIRECT_SLATEC) - message(STATUS "Using direct SLATEC build") - if(EXISTS "${CMAKE_SOURCE_DIR}/external/lib/libslatec.a") - set(SLATEC "${CMAKE_SOURCE_DIR}/external/lib/libslatec.a") - message(STATUS "Found direct SLATEC: ${SLATEC}") - else() - message(WARNING "Direct SLATEC build enabled but library not found. Please run ./slatec_direct.sh first.") - message(STATUS "Falling back to regular SLATEC build") - set(USE_DIRECT_SLATEC OFF) - endif() +# ============================================================================= +# Project Options +# ============================================================================= +option(USE_MKL "Use Intel MKL instead of OpenBLAS" OFF) +option(USE_INT64 "Use 64-bit integers for BLAS/LAPACK (ILP64 interface)" OFF) +option(USE_CONDA_LIBS "Use libraries from conda environment" OFF) +# option(USE_DIRECT_CBLAS "Use direct CBLAS instead of GSL's wrapper" OFF) # This option was unused. + +# ============================================================================= +# Build Configuration +# ============================================================================= +# Set default build type to Release if not specified +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE) endif() -# Function to conditionally download and build a dependency -function(handle_dependency name) - if(NOT ${name}_FOUND AND AUTO_DOWNLOAD_DEPENDENCIES) - message(STATUS "Will download and build ${name}") - set(${name}_FOUND TRUE PARENT_SCOPE) - set(${name}_DOWNLOADED TRUE PARENT_SCOPE) - endif() -endfunction() - -# Find BLAS and LAPACK -if(USE_SYSTEM_LIBS) - find_package(BLAS QUIET) - find_package(LAPACK QUIET) -else() - set(BLAS_FOUND FALSE) - set(LAPACK_FOUND FALSE) -endif() - -# If BLAS/LAPACK not found, use OpenBLAS which provides both -if((NOT BLAS_FOUND OR NOT LAPACK_FOUND) AND AUTO_DOWNLOAD_DEPENDENCIES) - message(STATUS "BLAS or LAPACK not found. Will download and build OpenBLAS.") - set(BLAS_FOUND TRUE) - set(LAPACK_FOUND TRUE) - - ExternalProject_Add( - openblas - GIT_REPOSITORY ${OPENBLAS_GIT_URL} - GIT_TAG ${OPENBLAS_VERSION} - CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${EXTERNAL_INSTALL_LOCATION} -DCMAKE_C_FLAGS="-Wno-misleading-indentation" - BUILD_COMMAND $(MAKE) - INSTALL_COMMAND $(MAKE) PREFIX=${EXTERNAL_INSTALL_LOCATION} install - ) +# Print build configuration +message(STATUS "==========================================") +message(STATUS "MESS Build Configuration") +message(STATUS "==========================================") +message(STATUS "Build Type: ${CMAKE_BUILD_TYPE}") +message(STATUS "C++ Standard: ${CMAKE_CXX_STANDARD}") +message(STATUS "USE_MKL: ${USE_MKL}") +message(STATUS "USE_INT64: ${USE_INT64}") +message(STATUS "USE_CONDA_LIBS: ${USE_CONDA_LIBS}") +message(STATUS "==========================================") + +# ============================================================================= +# Find Dependencies (BLAS, LAPACK, GSL, MPI, etc.) +# ============================================================================= +include(FetchContent) + +# --- BLAS / LAPACK Configuration --- +message(STATUS "Configuring BLAS and LAPACK...") + +if(USE_CONDA_LIBS) + message(STATUS "Using conda environment libraries") + set(CONDA_LIB_PATH "/home/keceli/miniconda3/envs/kmess-env/lib") - set(BLAS_LIBRARIES ${EXTERNAL_INSTALL_LOCATION}/lib/libopenblas.so) - set(LAPACK_LIBRARIES ${EXTERNAL_INSTALL_LOCATION}/lib/libopenblas.so) - set(OPENBLAS_DOWNLOADED TRUE) -else() - message(STATUS "Found BLAS: ${BLAS_LIBRARIES}") - message(STATUS "Found LAPACK: ${LAPACK_LIBRARIES}") -endif() - -# Find Fortran compilation capabilities -# This tells CMake to enable Fortran language for our project -enable_language(Fortran OPTIONAL) - -# Find SLATEC -if(USE_SYSTEM_LIBS) - find_library(SLATEC NAMES slatec libslatec QUIET) -endif() - -if(NOT SLATEC AND AUTO_DOWNLOAD_DEPENDENCIES) - message(STATUS "SLATEC not found. Will download and build it.") - - # Create SLATEC wrapper file content for missing C interfaces - file(WRITE ${CMAKE_BINARY_DIR}/slatec_wrapper.f " -! Explicit wrapper for SLATEC functions that need C-compatible interfaces - subroutine davint(x, y, n, xlo, xup, ans, ierr) - implicit none - integer n, ierr - double precision x(n), y(n), xlo, xup, ans - call davint_(x, y, n, xlo, xup, ans, ierr) - return - end - - subroutine ddeabm(f, neq, t, y, tout, info, rtol, atol, idid, - & rwork, lrw, iwork, liw, rpar, ipar) - external f - integer neq, info(*), idid, lrw, iwork(*), liw - double precision t, y(*), tout, rtol(*), atol(*), rwork(*) - integer ipar(*) - double precision rpar(*) - call ddeabm_(f, neq, t, y, tout, info, rtol, atol, idid, - & rwork, lrw, iwork, liw, rpar, ipar) - return - end - - subroutine dbint4(x, y, n, ibcl, ibcr, fbcl, fbcr, kntopt, t, nc, - & bc, ws, lws, ierr) - integer n, ibcl, ibcr, kntopt, nc, lws, ierr - double precision x(*), y(*), fbcl, fbcr, t(*), bc(*), ws(*) - call dbint4_(x, y, n, ibcl, ibcr, fbcl, fbcr, kntopt, t, nc, - & bc, ws, lws, ierr) - return - end - - function dbvalu(t, a, n, k, ideriv, x, inbv, work) - integer n, k, ideriv, inbv - double precision t(*), a(*), x, work(*), dbvalu - dbvalu = dbvalu_(t, a, n, k, ideriv, x, inbv, work) - return - end -") - - # Create build script for SLATEC - file(WRITE ${CMAKE_BINARY_DIR}/build_slatec.sh "#!/bin/sh -set -e -# Use gfortran as default Fortran compiler if not specified -FC=${CMAKE_Fortran_COMPILER} -if [ -z \"$FC\" ]; then - FC=gfortran -fi -FFLAGS='-O2 -fPIC -fdefault-real-8 -fdefault-double-8 -std=legacy' -AR=ar - -echo 'Compiling SLATEC modules...' -for f in *.f; do - echo \"Compiling $f...\" - $FC $FFLAGS -c $f || exit 1 -done - -echo 'Creating library...' -$AR rcs libslatec.a *.o -echo 'Build complete' -") - - # Set up SLATEC build with more detailed configuration for reproducibility - set(SLATEC_SOURCE_DIR ${CMAKE_BINARY_DIR}/slatec_src) - set(SLATEC_BUILD_DIR ${CMAKE_BINARY_DIR}/slatec_build) - - include(ExternalProject) - ExternalProject_Add( - slatec_external - URL ${SLATEC_URL} - DOWNLOAD_DIR ${CMAKE_BINARY_DIR}/downloads - SOURCE_DIR ${SLATEC_SOURCE_DIR} - BINARY_DIR ${SLATEC_BUILD_DIR} - # Configure step - create a simpler setup - CONFIGURE_COMMAND ${CMAKE_COMMAND} -E copy_directory ${SLATEC_SOURCE_DIR} ${SLATEC_BUILD_DIR} - # Copy wrapper file - COMMAND ${CMAKE_COMMAND} -E copy_if_different - ${CMAKE_BINARY_DIR}/slatec_wrapper.f ${SLATEC_BUILD_DIR}/ - # Copy build script - COMMAND ${CMAKE_COMMAND} -E copy_if_different - ${CMAKE_BINARY_DIR}/build_slatec.sh ${SLATEC_BUILD_DIR}/ - # Make build script executable - COMMAND chmod +x ${SLATEC_BUILD_DIR}/build_slatec.sh - # Build step - run the build script - BUILD_COMMAND ${SLATEC_BUILD_DIR}/build_slatec.sh - # Install step - copy built library - INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_if_different - ${SLATEC_BUILD_DIR}/libslatec.a ${EXTERNAL_INSTALL_LOCATION}/lib/libslatec.a - # Disable updates - UPDATE_COMMAND "" - # Logging - LOG_DOWNLOAD ON - LOG_CONFIGURE ON - LOG_BUILD ON - LOG_INSTALL ON - ) - - set(SLATEC ${EXTERNAL_INSTALL_LOCATION}/lib/libslatec.a) - set(SLATEC_DOWNLOADED TRUE) -else() - message(STATUS "Found SLATEC: ${SLATEC}") -endif() - -# Find Fortran libraries needed for SLATEC -# Try to find Intel Fortran runtime -find_library(IFORT_LIBRARY NAMES - ifcore ifport ifcoremt ifportmt - PATHS - /opt/aurora/24.347.0/oneapi/compiler/latest/lib - /opt/aurora/24.347.0/oneapi/compiler/latest/lib/intel64 - /opt/intel/oneapi/compiler/latest/lib - /opt/intel/oneapi/compiler/latest/lib/intel64 -) - -if(IFORT_LIBRARY) - message(STATUS "Found Intel Fortran runtime: ${IFORT_LIBRARY}") - set(FORTRAN_LIBRARIES ${IFORT_LIBRARY}) + if(USE_MKL) + message(STATUS "Using Intel MKL from conda") + # Use explicit MKL libraries to ensure proper 64-bit integer support + if(USE_INT64) + set(BLAS_LIBRARIES + ${CONDA_LIB_PATH}/libmkl_intel_ilp64.so + ${CONDA_LIB_PATH}/libmkl_gnu_thread.so + ${CONDA_LIB_PATH}/libmkl_core.so + m + dl + gomp + ) + set(LAPACK_LIBRARIES ${BLAS_LIBRARIES}) + message(STATUS " - Using 64-bit integers (ILP64)") + else() + set(BLAS_LIBRARIES + ${CONDA_LIB_PATH}/libmkl_intel_lp64.so + ${CONDA_LIB_PATH}/libmkl_gnu_thread.so + ${CONDA_LIB_PATH}/libmkl_core.so + m + dl + gomp + ) + set(LAPACK_LIBRARIES ${BLAS_LIBRARIES}) + message(STATUS " - Using 32-bit integers (LP64)") + endif() + else() + message(STATUS "Using OpenBLAS from conda") + set(BLAS_LIBRARIES ${CONDA_LIB_PATH}/libopenblas.so) + set(LAPACK_LIBRARIES ${CONDA_LIB_PATH}/libopenblas.so) + if(USE_INT64) + message(STATUS " - Using 64-bit integers (ILP64)") + else() + message(STATUS " - Using 32-bit integers (LP64)") + endif() + endif() +elseif(USE_MKL) + message(STATUS "Using Intel MKL") + if(USE_INT64) + set(BLAS_LIBRARIES + /opt/intel/oneapi/mkl/latest/lib/intel64/libmkl_intel_ilp64.so + /opt/intel/oneapi/mkl/latest/lib/intel64/libmkl_gnu_thread.so + /opt/intel/oneapi/mkl/latest/lib/intel64/libmkl_core.so + m + dl + gomp + ) + set(LAPACK_LIBRARIES ${BLAS_LIBRARIES}) + message(STATUS " - Using 64-bit integers (ILP64)") + else() + set(BLAS_LIBRARIES + /opt/intel/oneapi/mkl/latest/lib/intel64/libmkl_intel_lp64.so + /opt/intel/oneapi/mkl/latest/lib/intel64/libmkl_gnu_thread.so + /opt/intel/oneapi/mkl/latest/lib/intel64/libmkl_core.so + m + dl + gomp + ) + set(LAPACK_LIBRARIES ${BLAS_LIBRARIES}) + message(STATUS " - Using 32-bit integers (LP64)") + endif() else() - message(WARNING "Intel Fortran runtime not found, will try gfortran") - # Fall back to gfortran if Intel runtime not found - find_library(GFORTRAN_LIBRARY NAMES - gfortran libgfortran libgfortran.so.5 libgfortran.so.4 libgfortran.so.3 - PATHS - /usr/lib - /usr/lib64 - /usr/lib/gcc - /usr/local/lib - /usr/local/lib64 - /usr/lib/x86_64-linux-gnu - /lib/x86_64-linux-gnu - PATH_SUFFIXES gcc/x86_64-linux-gnu/10 gcc/x86_64-linux-gnu/9 gcc/x86_64-linux-gnu/8 gcc/x86_64-linux-gnu/7 - ) - if(GFORTRAN_LIBRARY) - message(STATUS "Found gfortran: ${GFORTRAN_LIBRARY}") - set(FORTRAN_LIBRARIES ${GFORTRAN_LIBRARY}) + message(STATUS "Using OpenBLAS") + set(BLAS_LIBRARIES /usr/lib/x86_64-linux-gnu/libopenblas.so) + set(LAPACK_LIBRARIES /usr/lib/x86_64-linux-gnu/libopenblas.so) + if(USE_INT64) + message(STATUS " - Using 64-bit integers (ILP64)") else() - message(FATAL_ERROR "No Fortran runtime found") + message(STATUS " - Using 32-bit integers (LP64)") endif() endif() -# Find optional quadmath library (often needed with gfortran) -find_library(QUADMATH_LIBRARY NAMES quadmath) -if(QUADMATH_LIBRARY) - message(STATUS "Found quadmath: ${QUADMATH_LIBRARY}") - list(APPEND FORTRAN_LIBRARIES ${QUADMATH_LIBRARY}) -endif() +message(STATUS "BLAS Libraries: ${BLAS_LIBRARIES}") +message(STATUS "LAPACK Libraries: ${LAPACK_LIBRARIES}") -# Set up link libraries for SLATEC -set(FORTRAN_LIBRARIES ${FORTRAN_LIBRARIES}) -# Find GSL -if(USE_SYSTEM_LIBS) +# --- GSL (GNU Scientific Library) --- +# First, try to find an installed version. If not found, download and build it. +if(USE_CONDA_LIBS) + message(STATUS "Using GSL from conda environment") + set(GSL_INCLUDE_DIRS "/home/keceli/miniconda3/envs/kmess-env/include") + set(GSL_LIBRARIES "/home/keceli/miniconda3/envs/kmess-env/lib/libgsl.so") + set(GSL_DOWNLOADED TRUE) +else() find_package(GSL QUIET) -endif() + if(NOT GSL_FOUND) + message(STATUS "GSL not found. Building from source...") + if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.24") + FetchContent_Declare( + gsl_external + URL "https://ftp.gnu.org/gnu/gsl/gsl-2.8.tar.gz" + URL_HASH SHA256=6a99eeed15632c6354895b1dd542ed5a855c0f15d9ad1326c6fe2b2c9e423190 + DOWNLOAD_EXTRACT_TIMESTAMP TRUE + ) + else() + FetchContent_Declare( + gsl_external + URL "https://ftp.gnu.org/gnu/gsl/gsl-2.8.tar.gz" + URL_HASH SHA256=6a99eeed15632c6354895b1dd542ed5a855c0f15d9ad1326c6fe2b2c9e423190 + ) + endif() + FetchContent_MakeAvailable(gsl_external) + + # Configure GSL with internal CBLAS (more reliable for CI) + set(GSL_CONFIGURE_OPTIONS + "--prefix=${EXTERNAL_INSTALL_LOCATION}" + "--disable-shared" + "--enable-static" + "--with-cblas=internal" + ) -if(NOT GSL_FOUND AND AUTO_DOWNLOAD_DEPENDENCIES) - message(STATUS "GSL not found. Will download and build it.") ExternalProject_Add( - gsl_external - URL ${GSL_URL} - CONFIGURE_COMMAND /configure --prefix=${EXTERNAL_INSTALL_LOCATION} - BUILD_COMMAND make - INSTALL_COMMAND make install + gsl_project + SOURCE_DIR ${gsl_external_SOURCE_DIR} + BINARY_DIR ${gsl_external_BINARY_DIR} + CONFIGURE_COMMAND /configure ${GSL_CONFIGURE_OPTIONS} + BUILD_COMMAND $(MAKE) + INSTALL_COMMAND $(MAKE) install + LOG_CONFIGURE TRUE + LOG_BUILD TRUE + LOG_INSTALL TRUE ) + set(GSL_INCLUDE_DIRS ${EXTERNAL_INSTALL_LOCATION}/include) - set(GSL_LIBRARIES ${EXTERNAL_INSTALL_LOCATION}/lib/libgsl.so) - include_directories(${GSL_INCLUDE_DIRS}) + set(GSL_LIBRARIES ${EXTERNAL_INSTALL_LOCATION}/lib/libgsl.a) set(GSL_DOWNLOADED TRUE) - set(GSL_FOUND TRUE) else() message(STATUS "Found GSL: ${GSL_LIBRARIES}") endif() - -# Find QD -if(USE_SYSTEM_LIBS) - find_library(QD NAMES qd libqd libqd.a QUIET) endif() -if(NOT QD AND AUTO_DOWNLOAD_DEPENDENCIES) - message(STATUS "QD not found. Will download and build it.") - ExternalProject_Add( - qd_external - URL ${QD_URL} - URL_HASH SHA256=${QD_SHA256} - CONFIGURE_COMMAND /configure --prefix=${EXTERNAL_INSTALL_LOCATION} - BUILD_COMMAND make - INSTALL_COMMAND make install - ) - set(QD ${EXTERNAL_INSTALL_LOCATION}/lib/libqd.a) - set(QD_DOWNLOADED TRUE) + +# --- SLATEC (Common Mathematical Library) --- +# First, try to find an installed version. If not found, download and build it. +find_library(SLATEC_LIBRARY NAMES slatec libslatec) +if(NOT SLATEC_LIBRARY) + message(STATUS "SLATEC not found. Building from source...") + if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.24") + FetchContent_Declare( + slatec_external + URL "http://www.netlib.org/slatec/slatec_src.tgz" + URL_HASH SHA1=6100817113c115778eddec5811065be818157554 + DOWNLOAD_EXTRACT_TIMESTAMP TRUE + ) + else() + FetchContent_Declare( + slatec_external + URL "http://www.netlib.org/slatec/slatec_src.tgz" + URL_HASH SHA1=6100817113c115778eddec5811065be818157554 + ) + endif() + FetchContent_Populate(slatec_external) + + # Glob all Fortran sources from the downloaded content + file(GLOB SLATEC_SOURCES "${slatec_external_SOURCE_DIR}/*.f") + + # Create a static library from the SLATEC sources + add_library(slatec_lib STATIC ${SLATEC_SOURCES}) + + # Set Fortran compiler flags for SLATEC (Fortran 77 compatibility) + target_compile_options(slatec_lib PRIVATE + -std=legacy + -fPIC + -O2 + -w # Suppress warnings for old Fortran code + ) + + # Link Fortran runtime + target_link_libraries(slatec_lib PRIVATE gfortran) + + set(SLATEC_LIBRARIES slatec_lib) + set(SLATEC_DOWNLOADED TRUE) else() - message(STATUS "Found QD: ${QD}") + message(STATUS "Found SLATEC: ${SLATEC_LIBRARY}") + set(SLATEC_LIBRARIES ${SLATEC_LIBRARY}) endif() -# Create a list of dependencies we need to add -set(DEPENDENCIES_TARGETS "") -if(DEFINED OPENBLAS_DOWNLOADED) - list(APPEND DEPENDENCIES_TARGETS openblas) -endif() -if(DEFINED SLATEC_DOWNLOADED) - list(APPEND DEPENDENCIES_TARGETS slatec_external) -endif() -if(DEFINED GSL_DOWNLOADED) - list(APPEND DEPENDENCIES_TARGETS gsl_external) -endif() -if(DEFINED QD_DOWNLOADED) - list(APPEND DEPENDENCIES_TARGETS qd_external) -endif() -# Set up include directories for downloaded libraries -include_directories(${EXTERNAL_INSTALL_LOCATION}/include) -link_directories(${EXTERNAL_INSTALL_LOCATION}/lib) - -# Define the library -add_library(messlibs - ${PROJECT_SOURCE_DIR}/src/libmess/atom.cc - ${PROJECT_SOURCE_DIR}/src/libmess/io.cc - ${PROJECT_SOURCE_DIR}/src/libmess/limits.cc - ${PROJECT_SOURCE_DIR}/src/libmess/math.cc - ${PROJECT_SOURCE_DIR}/src/libmess/symmetry.cc - ${PROJECT_SOURCE_DIR}/src/libmess/d3.cc - ${PROJECT_SOURCE_DIR}/src/libmess/key.cc - ${PROJECT_SOURCE_DIR}/src/libmess/mess.cc - ${PROJECT_SOURCE_DIR}/src/libmess/multindex.cc - ${PROJECT_SOURCE_DIR}/src/libmess/units.cc - ${PROJECT_SOURCE_DIR}/src/libmess/graph_common.cc - ${PROJECT_SOURCE_DIR}/src/libmess/lapack.cc - ${PROJECT_SOURCE_DIR}/src/libmess/mpack.cc - # ${PROJECT_SOURCE_DIR}/src/libmess/mpack_dd.cc - ${PROJECT_SOURCE_DIR}/src/libmess/permutation.cc - ${PROJECT_SOURCE_DIR}/src/libmess/graph_omp.cc - ${PROJECT_SOURCE_DIR}/src/libmess/linpack.cc - ${PROJECT_SOURCE_DIR}/src/libmess/model.cc - ${PROJECT_SOURCE_DIR}/src/libmess/slatec.cc - ${PROJECT_SOURCE_DIR}/src/libmess/crossrate.cc - ${PROJECT_SOURCE_DIR}/src/libmess/random.cc - ${PROJECT_SOURCE_DIR}/src/libmess/read.cc - ${PROJECT_SOURCE_DIR}/src/libmess/divsur.cc - ${PROJECT_SOURCE_DIR}/src/libmess/dynamic.cc - ${PROJECT_SOURCE_DIR}/src/libmess/structure.cc - ${PROJECT_SOURCE_DIR}/src/libmess/configuration.cc - ${PROJECT_SOURCE_DIR}/src/libmess/dynlib.cc - ${PROJECT_SOURCE_DIR}/src/libmess/monom.cc - ${PROJECT_SOURCE_DIR}/src/libmess/logical.cc - ${PROJECT_SOURCE_DIR}/src/libmess/potential.cc - ${PROJECT_SOURCE_DIR}/src/libmess/system.cc - ${PROJECT_SOURCE_DIR}/src/libmess/trajectory.cc) - -# Add dependency on external libraries if needed -if(DEPENDENCIES_TARGETS) - add_dependencies(messlibs ${DEPENDENCIES_TARGETS}) +# --- Other Optional Libraries --- +find_library(QD_LIBRARIES NAMES qd libqd) +find_package(MPI QUIET) + +# ============================================================================= +# Library Target (messlibs) +# ============================================================================= +set(MESS_SOURCES + src/libmess/atom.cc + src/libmess/configuration.cc + src/libmess/crossrate.cc + src/libmess/d3.cc + src/libmess/divsur.cc + src/libmess/dynamic.cc + src/libmess/dynlib.cc + src/libmess/graph_common.cc + src/libmess/graph_omp.cc + src/libmess/io.cc + src/libmess/key.cc + src/libmess/lapack.cc + src/libmess/limits.cc + src/libmess/linpack.cc + src/libmess/logical.cc + src/libmess/math.cc + src/libmess/mess.cc + src/libmess/model.cc + src/libmess/monom.cc + src/libmess/mpack.cc + src/libmess/multindex.cc + src/libmess/permutation.cc + src/libmess/potential.cc + src/libmess/random.cc + src/libmess/read.cc + src/libmess/slatec.cc + src/libmess/structure.cc + src/libmess/symmetry.cc + src/libmess/system.cc + src/libmess/trajectory.cc + src/libmess/units.cc +) + +add_library(messlibs STATIC ${MESS_SOURCES}) + +# Add dependencies if they were built from source +if(GSL_DOWNLOADED AND NOT USE_CONDA_LIBS) + add_dependencies(messlibs gsl_project) endif() -# Set Fortran-compatible flags for C/C++ code -set_target_properties(messlibs PROPERTIES - COMPILE_FLAGS "-fPIC -fno-strict-aliasing" +# --- Target Properties: Include Directories --- +target_include_directories(messlibs PUBLIC + $ + $ + $ + ${GSL_INCLUDE_DIRS} ) -# Set up executables -add_executable(mess ${PROJECT_SOURCE_DIR}/src/mess_driver.cc) -add_executable(mess-v2 ${PROJECT_SOURCE_DIR}/src/mess_test.cc) -add_executable(messpf ${PROJECT_SOURCE_DIR}/src/partition_function.cc) -add_executable(messabs ${PROJECT_SOURCE_DIR}/src/abstraction.cc) -add_executable(messsym ${PROJECT_SOURCE_DIR}/src/symmetry_number.cc) - -# Link libraries -target_link_libraries(mess - messlibs - ${BLAS_LIBRARIES} - ${LAPACK_LIBRARIES} - ${GSL_LIBRARIES} - ${QD} - -Wl,--start-group # Use link groups to handle circular dependencies - ${SLATEC} - ${FORTRAN_LIBRARIES} - -lm # Math library - -Wl,--end-group - ${CMAKE_DL_LIBS} -) -target_link_libraries(mess-v2 - messlibs - ${BLAS_LIBRARIES} - ${LAPACK_LIBRARIES} - ${GSL_LIBRARIES} - ${QD} - -Wl,--start-group - ${SLATEC} - ${FORTRAN_LIBRARIES} - -lm - -Wl,--end-group - ${CMAKE_DL_LIBS} -) -target_link_libraries(messpf - messlibs - ${BLAS_LIBRARIES} - ${LAPACK_LIBRARIES} - ${GSL_LIBRARIES} - ${QD} - -Wl,--start-group - ${SLATEC} - ${FORTRAN_LIBRARIES} - -lm - -Wl,--end-group - ${CMAKE_DL_LIBS} -) -target_link_libraries(messabs - messlibs - ${BLAS_LIBRARIES} - ${LAPACK_LIBRARIES} - ${GSL_LIBRARIES} - ${QD} - -Wl,--start-group - ${SLATEC} - ${FORTRAN_LIBRARIES} - -lm - -Wl,--end-group - ${CMAKE_DL_LIBS} -) -target_link_libraries(messsym - messlibs - ${BLAS_LIBRARIES} - ${LAPACK_LIBRARIES} +# --- Target Properties: Compile Definitions --- +if(USE_INT64) + target_compile_definitions(messlibs PUBLIC -DUSE_INT64) +else() + target_compile_definitions(messlibs PUBLIC -DUSE_32BIT_INTEGERS) +endif() + +# --- Target Properties: Link Libraries --- +target_link_libraries(messlibs PUBLIC + ${LAPACK_LIBRARIES} # LAPACK depends on BLAS, so this is often sufficient ${GSL_LIBRARIES} - ${QD} - -Wl,--start-group - ${SLATEC} - ${FORTRAN_LIBRARIES} - -lm - -Wl,--end-group - ${CMAKE_DL_LIBS} + ${SLATEC_LIBRARIES} + m dl # Common system libraries ) -install(TARGETS mess DESTINATION bin) -install(TARGETS mess-v2 DESTINATION bin) -install(TARGETS messpf DESTINATION bin) -install(TARGETS messabs DESTINATION bin) -install(TARGETS messsym DESTINATION bin) - -# Create a direct wrapper for missing SLATEC functions -file(WRITE ${CMAKE_BINARY_DIR}/slatec_wrapper.f " - subroutine davint(x, y, n, xlo, xup, ans, ierr) - implicit none - integer n, ierr - double precision x(n), y(n), xlo, xup, ans - call davint_(x, y, n, xlo, xup, ans, ierr) - return - end - - subroutine ddeabm(f, neq, t, y, tout, info, rtol, atol, idid, - & rwork, lrw, iwork, liw, rpar, ipar) - external f - integer neq, info(*), idid, lrw, iwork(*), liw - double precision t, y(*), tout, rtol(*), atol(*), rwork(*) - integer ipar(*) - double precision rpar(*) - call ddeabm_(f, neq, t, y, tout, info, rtol, atol, idid, - & rwork, lrw, iwork, liw, rpar, ipar) - return - end - - subroutine dbint4(x, y, n, ibcl, ibcr, fbcl, fbcr, kntopt, t, nc, - & bc, ws, lws, ierr) - integer n, ibcl, ibcr, kntopt, nc, lws, ierr - double precision x(*), y(*), fbcl, fbcr, t(*), bc(*), ws(*) - call dbint4_(x, y, n, ibcl, ibcr, fbcl, fbcr, kntopt, t, nc, - & bc, ws, lws, ierr) - return - end - - function dbvalu(t, a, n, k, ideriv, x, inbv, work) - integer n, k, ideriv, inbv - double precision t(*), a(*), x, work(*), dbvalu - dbvalu = dbvalu_(t, a, n, k, ideriv, x, inbv, work) - return - end -") - -# Compile the SLATEC wrapper -add_custom_command( - OUTPUT ${CMAKE_BINARY_DIR}/slatec_wrapper.o - COMMAND gfortran -c -O2 -fPIC ${CMAKE_BINARY_DIR}/slatec_wrapper.f -o ${CMAKE_BINARY_DIR}/slatec_wrapper.o - DEPENDS ${CMAKE_BINARY_DIR}/slatec_wrapper.f - COMMENT "Compiling SLATEC wrapper" -) +# --- Conditionally link optional libraries --- +if(QD_LIBRARIES) + message(STATUS "Found and linking QD library: ${QD_LIBRARIES}") + target_link_libraries(messlibs PUBLIC ${QD_LIBRARIES}) +else() + message(STATUS "Optional QD library not found, skipping.") +endif() + +# --- Handle MPI --- +if(MPI_FOUND) + message(STATUS "MPI found, adding communication sources and linking.") + target_sources(messlibs PRIVATE + src/libmess/comm.cc + src/libmess/auto_comm.cc + src/libmess/new_comm.cc + ) + target_include_directories(messlibs PUBLIC ${MPI_CXX_INCLUDE_PATH}) + target_link_libraries(messlibs PUBLIC MPI::MPI_CXX) +endif() + -# Create a custom target for the wrapper -add_custom_target(slatec_wrapper DEPENDS ${CMAKE_BINARY_DIR}/slatec_wrapper.o) -add_dependencies(messlibs slatec_wrapper) +# ============================================================================= +# Executable Targets +# ============================================================================= +add_executable(mess src/mess_driver.cc) +add_executable(mess-v2 src/mess_test.cc) +add_executable(messpf src/partition_function.cc) +add_executable(messsym src/gumbo.cc) + +# Link all standard executables to the main library +target_link_libraries(mess messlibs) +target_link_libraries(mess-v2 messlibs) +target_link_libraries(messpf messlibs) +target_link_libraries(messsym messlibs) + +# Handle MPI executable separately +if(MPI_FOUND) + add_executable(messabs src/mess_mpi.cc) + target_link_libraries(messabs messlibs) +endif() \ No newline at end of file diff --git a/src/libmess/comm.cc b/src/libmess/comm.cc index 3f3a949..782f415 100644 --- a/src/libmess/comm.cc +++ b/src/libmess/comm.cc @@ -1,9 +1,9 @@ -#include "comm.hh" - //#undef INT #include +#include "comm.hh" + void Comm::send_rate_data(const std::map, double>& data) { int itemp; diff --git a/src/libmess/lapack.cc b/src/libmess/lapack.cc index 65f1f78..81d1e63 100644 --- a/src/libmess/lapack.cc +++ b/src/libmess/lapack.cc @@ -273,21 +273,8 @@ Lapack::Matrix Lapack::Matrix::operator* (Matrix m) const Matrix res(size1(), m.size2()); - int_t n = size1() * m.size2(); - -#pragma omp parallel for default(shared) schedule(static) - - for(int_t k = 0; k < n; ++k) { - // - int_t i = k / m.size2(); - - int_t j = k % m.size2(); - - res(i, j) = vdot(row(i), (ConstSlice)m.column(j)); - } - - //dgemm_('N', 'N', size1(), m.size2(), size2(), 1., - //*this, size1(), m, m.size1(), 0., res, size1()); + dgemm_('N', 'N', size1(), m.size2(), size2(), 1., + *this, size1(), m, m.size1(), 0., res, size1()); return res; } @@ -319,13 +306,7 @@ Lapack::Vector Lapack::Matrix::operator* (const double* v) const Vector res(size1()); -#pragma omp parallel for default(shared) schedule(static) - - for(int_t i = 0; i < size1(); ++i) - // - res[i] = vdot(row(i), v); - - //dgemv_('N', size1(), size2(), 1., *this, size1(), v, 1, 0., res, 1); + dgemv_('N', size1(), size2(), 1., *this, size1(), v, 1, 0., res, 1); return res; } @@ -335,13 +316,7 @@ Lapack::Vector Lapack::operator* (const double* v, Matrix m) Vector res(m.size2()); -#pragma omp parallel for default(shared) schedule(static) - - for(int_t i = 0; i < m.size2(); ++i) - // - res[i] = vdot(m.column(i), v); - - //dgemv_('T', m.size1(), m.size2(), 1., m, m.size1(), v, 1, 0., res, 1); + dgemv_('T', m.size1(), m.size2(), 1., m, m.size1(), v, 1, 0., res, 1); return res; } diff --git a/src/libmess/lapack.hh b/src/libmess/lapack.hh index 263354d..f98f246 100644 --- a/src/libmess/lapack.hh +++ b/src/libmess/lapack.hh @@ -25,7 +25,11 @@ namespace Lapack { +#ifdef USE_INT64 typedef int64_t int_t; +#else + typedef int32_t int_t; +#endif typedef std::complex complex; diff --git a/src/libmess/mess.cc b/src/libmess/mess.cc index 2ff70c5..fb31515 100644 --- a/src/libmess/mess.cc +++ b/src/libmess/mess.cc @@ -6654,14 +6654,12 @@ void MasterEquation::Well::_set_crm_basis () std::vector nfac; - if(with_crm_basis) { - // - _crm_basis.resize(size(), crm_size()); + // Always initialize CRM basis when this function is called + _crm_basis.resize(size(), crm_size()); - _crm_basis = 0.; + _crm_basis = 0.; - nfac.resize(crm_size()); - } + nfac.resize(crm_size()); _weight = 0.; @@ -6673,37 +6671,35 @@ void MasterEquation::Well::_set_crm_basis () _boltzman_sqrt[i] = std::sqrt(dtemp); - if(with_crm_basis) { + if(i) { // - if(i) { - // - itemp = i - 1; - - _crm_basis(i, itemp) = - _weight; - - nfac[itemp] = std::sqrt((_weight / dtemp + 1.) * _weight); - } + itemp = i - 1; - for(int r = i; r < crm_size(); ++r) - // - _crm_basis(i, r) = dtemp; + _crm_basis(i, itemp) = - _weight; + + nfac[itemp] = std::sqrt((_weight / dtemp + 1.) * _weight); } + + for(int r = i; r < crm_size(); ++r) + // + _crm_basis(i, r) = dtemp; _weight += dtemp; } - if(with_crm_basis) + for(int r = 0; r < crm_size(); ++r) { // - for(int r = 0; r < crm_size(); ++r) { + itemp = r + 2; + + for(int i = 0; i < itemp; ++i) // - itemp = r + 2; - - for(int i = 0; i < itemp; ++i) - // - _crm_basis(i, r) /= nfac[r]; - } + _crm_basis(i, r) /= nfac[r]; + } _weight_sqrt = std::sqrt(_weight); + + // Set the CRM basis flag to indicate initialization is complete + with_crm_basis = 1; } MasterEquation::Well::Well (const Model::Well& model) diff --git a/src/mess_mpi.cc b/src/mess_mpi.cc index 5eacfdc..6d83d55 100644 --- a/src/mess_mpi.cc +++ b/src/mess_mpi.cc @@ -20,6 +20,9 @@ #include #include +//#undef INT +#include + #include "libmess/mess.hh" #include "libmess/key.hh" #include "libmess/units.hh" @@ -29,9 +32,6 @@ #include "libmess/mpack.hh" #include "libmess/limits.hh" -//#undef INT -#include - int main (int argc, char* argv []) { const char funame [] = "master_equation: ";