############################################################################### # # Copyright (c) 2013-2024, Lawrence Livermore National Security, LLC # and other libROM project developers. See the top-level COPYRIGHT # file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) # ############################################################################### # Require CMake version 3.12 or later to expose modern features of # CMake for maintainability. With additional work, it is possible to # rewrite the build system generator for CMake 3.10+, 3.8+, 3.1+, # 3.0+, or 2.8+, with increasing amounts of work as the minimum # required version is decreased. Notably, CMake's find modules export # targets (e.g., FindZLIB.cmake exports the ZLIB::ZLIB IMPORTED # target) as of version 3.1, and CMake supports using the # _ROOT variables to set the prefix search path for # find_package() as of version 3.12. cmake_minimum_required(VERSION 3.12) cmake_policy(SET CMP0074 NEW) # Use _ROOT variables in find_package # Even though this project is a pure C++ library, the C language must be enabled # for MPI and HDF5 dependency checking. The Fortran language must be enabled # for Fortran-C name mangling convention detection. project(libROM VERSION 1.0.0 DESCRIPTION "Model reduction library emphasizing large-scale parallelism" HOMEPAGE_URL "https://github.com/LLNL/libROM" LANGUAGES C CXX Fortran) set(libROM_CMAKE_PATH ${CMAKE_SOURCE_DIR}/cmake) set(libROM_CMAKE_MODULE_PATH ${libROM_CMAKE_PATH}/modules) list(APPEND CMAKE_MODULE_PATH ${libROM_CMAKE_MODULE_PATH}) option(USE_MFEM "Build libROM with MFEM" OFF) option(MFEM_USE_GSLIB "Build libROM with MFEM using GSLIB" OFF) option(BUILD_STATIC "Build libROM as a static library" OFF) option(ENABLE_EXAMPLES "Build examples and regression tests" ON) option(ENABLE_DOCS "Build docs using Doxygen" OFF) option(ENABLE_TESTS "Build unit tests. Requires googletest to be installed" OFF) set(LIBROM_FLAGS "" CACHE STRING "Additional compiler flags used to compile libROM") ## Set a bunch of variables to generate a configure header # Enable assertion checking if debug symbols generated if((CMAKE_BUILD_TYPE STREQUAL "Debug") OR (CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")) set(DEBUG_CHECK_ASSERTIONS "1") set(LIBROM_FLAGS "${LIBROM_FLAGS} -Wall") endif() set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS_INIT} ${LIBROM_FLAGS}" CACHE STRING "" FORCE) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS_INIT} ${LIBROM_FLAGS}" CACHE STRING "" FORCE) if (CMAKE_HOST_APPLE) # Fix linker flags for OSX to use classic linker on XCode 15.0+: # https://developer.apple.com/documentation/xcode-release-notes/xcode-15-release-notes#Linking set(MPI_Fortran_LINK_FLAGS "${MPI_Fortran_LINK_FLAGS} -Wl,-ld_classic") endif() set(CAROM_VERSION_MAJOR "${PROJECT_VERSION_MAJOR}") set(CAROM_VERSION_MINOR "${PROJECT_VERSION_MINOR}") set(CAROM_VERSION_PATCHLEVEL "${PROJECT_VERSION_PATCH}") set(CAROM_PACKAGE ${CMAKE_PROJECT_NAME}) set(CAROM_PACKAGE_NAME ${CMAKE_PROJECT_NAME}) set(CAROM_PACKAGE_STRING "${CMAKE_PROJECT_NAME} ${CMAKE_PROJECT_VERSION}") set(CAROM_PACKAGE_TARNAME ${CMAKE_PROJECT_NAME}) set(CAROM_PACKAGE_URL ${CMAKE_PROJECT_HOMEPAGE_URL}) set(CAROM_PACKAGE_VERSION ${CMAKE_PROJECT_VERSION}) set(CAROM_VERSION ${CMAKE_PROJECT_VERSION}) include(CheckIncludeFiles) check_include_files(dlfcn.h CAROM_HAVE_DLFCN_H) check_include_files(inttypes.h CAROM_HAVE_INTTYPES_H) check_include_files(memory.h CAROM_HAVE_MEMORY_H) check_include_files(stdint.h CAROM_HAVE_STDINT_H) check_include_files(stdlib.h CAROM_HAVE_STDLIB_H) check_include_files(strings.h CAROM_HAVE_STRINGS_H) check_include_files(string.h CAROM_HAVE_STRING_H) check_include_files(sys/stat.h CAROM_HAVE_SYS_STAT_H) check_include_files(sys/types.h CAROM_HAVE_SYS_TYPES_H) check_include_files(unistd.h CAROM_HAVE_UNISTD_H) # Construct an expression consisting of the 24 ANSI C headers set(stdc_header_list "assert.h;complex.h;ctype.h;errno.h;fenv.h;float.h") set(stdc_header_list "${stdc_header_list};inttypes.h;iso646.h;limits.h") set(stdc_header_list "${stdc_header_list};locale.h;math.h;setjmp.h;signal.h") set(stdc_header_list "${stdc_header_list};stdarg.h;stdbool.h;stdint.h") set(stdc_header_list "${stdc_header_list};stddef.h;stdio.h;stdlib.h;string.h") set(stdc_header_list "${stdc_header_list};tgmath.h;time.h;wchar.h;wctype.h") check_include_files("${stdc_header_list}" CAROM_STDC_HEADERS) # List minimum version requirements for dependencies where possible to make # packaging easier later. find_package(HDF5 1.8.0 REQUIRED) find_package(BLAS 3.4.0 REQUIRED) find_package(LAPACK 3.4.0 REQUIRED) # In FindMPI.cmake, "CXX" refers to "the MPI C API [being] usable from C++" find_package(MPI 1.2 REQUIRED) find_package(ZLIB 1.2.3 REQUIRED) if (ENABLE_TESTS) find_package(GTest 1.6.0 REQUIRED) endif() # Define variables for use in generating a configure file set(CAROM_HAVE_BLAS ${BLAS_FOUND}) set(CAROM_HAVE_LAPACK ${LAPACK_FOUND}) set(CAROM_HAVE_HDF5 ${HDF5_FOUND}) if (USE_MFEM) find_library(MFEM mfem "${CMAKE_SOURCE_DIR}/dependencies/mfem" "${MFEM_DIR}/lib") find_library(HYPRE HYPRE "${CMAKE_SOURCE_DIR}/dependencies/hypre/src/hypre/lib" "${HYPRE_DIR}/lib") find_library(PARMETIS parmetis "${CMAKE_SOURCE_DIR}/dependencies/parmetis-4.0.3/build/lib/libparmetis" "${PARMETIS_DIR}/lib") find_library(METIS metis "${CMAKE_SOURCE_DIR}/dependencies/parmetis-4.0.3/build/lib/libmetis" "${METIS_DIR}/lib") find_path(MFEM_INCLUDES mfem.hpp "${CMAKE_SOURCE_DIR}/dependencies/mfem" "${MFEM_DIR}/include") find_path(HYPRE_INCLUDES HYPRE.h "${CMAKE_SOURCE_DIR}/dependencies/hypre/src/hypre/include" "${HYPRE_DIR}/include") find_path(PARMETIS_INCLUDES metis.h "${CMAKE_SOURCE_DIR}/dependencies/parmetis-4.0.3/metis/include" "${PARMETIS_DIR}/metis/include") endif() add_subdirectory(lib) # Use the C++11 standard as an entire feature instead of # enumerating individual compiler features for simplicity target_compile_features(ROM PRIVATE cxx_std_11) if (ENABLE_EXAMPLES) if (USE_MFEM) set(examples poisson_global_rom poisson_local_rom_greedy dg_advection_global_rom dg_advection_local_rom_matrix_interp mixed_nonlinear_diffusion nonlinear_elasticity_global_rom linear_elasticity_global_rom maxwell_global_rom de_parametric_maxwell_greedy maxwell_local_rom_greedy grad_div_global_rom elliptic_eigenproblem_global_rom dg_advection nonlinear_elasticity heat_conduction heat_conduction_dmdc parametric_heat_conduction de_parametric_heat_conduction_greedy de_dg_advection_greedy wave_equation dg_euler local_dw_csv parametric_tw_csv parametric_dw_csv parametric_dmdc_heat_conduction) set(example_directories prom prom prom prom prom prom prom prom prom prom prom prom dmd dmd dmd dmd dmd dmd dmd dmd dmd dmd dmd dmd dmd) list(LENGTH examples len1) math(EXPR len2 "${len1} - 1") foreach(val RANGE ${len2}) list(GET examples ${val} name) list(GET example_directories ${val} example_dir) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/examples/${example_dir}) add_executable(${name} examples/${example_dir}/${name}.cpp) target_link_libraries(${name} PRIVATE ROM ${MPI_C_LINK_FLAGS} ${MPI_C_LIBRARIES} MPI::MPI_C ${MPI_FORTRAN_LINK_FLAGS} ${MPI_FORTRAN_LIBRARIES} MPI::MPI_Fortran) target_include_directories(${name} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${MPI_C_INCLUDE_DIRS}) target_compile_features(${name} PRIVATE cxx_std_11) endforeach() # IN LISTS examples file(COPY examples/data DESTINATION ${CMAKE_BINARY_DIR}/examples) file(COPY examples/merlin DESTINATION ${CMAKE_BINARY_DIR}/examples) file(COPY examples/dmd/heat_conduction_csv.sh DESTINATION ${CMAKE_BINARY_DIR}/examples/dmd) file(COPY examples/dmd/heat_conduction_hdf.sh DESTINATION ${CMAKE_BINARY_DIR}/examples/dmd) endif() set(misc_example_names combine_samples) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/examples/misc) foreach(name IN LISTS misc_example_names) add_executable(${name} examples/misc/${name}.cpp) target_link_libraries(${name} PRIVATE ROM ${MPI_C_LINK_FLAGS} ${MPI_C_LIBRARIES} MPI::MPI_C ${MPI_FORTRAN_LINK_FLAGS} ${MPI_FORTRAN_LIBRARIES} MPI::MPI_Fortran) target_include_directories(${name} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${MPI_C_INCLUDE_DIRS}) target_compile_features(${name} PRIVATE cxx_std_11) endforeach(name) # IN LISTS misc_exmaple_names set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/tests) if (USE_MFEM) set(regression_test_names basisComparator checkError computeSpeedup solutionComparator fileComparator) foreach(name IN LISTS regression_test_names) add_executable(${name} regression_tests/${name}.cpp) target_link_libraries(${name} PRIVATE ROM ${MPI_C_LINK_FLAGS} ${MPI_C_LIBRARIES} MPI::MPI_C ${MPI_FORTRAN_LINK_FLAGS} ${MPI_FORTRAN_LIBRARIES} MPI::MPI_Fortran) target_include_directories(${name} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${MPI_C_INCLUDE_DIRS}) target_compile_features(${name} PRIVATE cxx_std_11) endforeach(name) # IN LISTS regression_test_names endif() endif(ENABLE_EXAMPLES) if (ENABLE_TESTS) enable_testing() add_subdirectory(unit_tests tests) endif() # NOTE(goxberry@gmail.com, oxberry1@llnl.gov): This code snippet # builds the Doxygen documentation, but outputs said documentation to # ${CMAKE_CURRENT_SOURCE_DIR}/docs)... if(${ENABLE_DOCS}) find_package(Doxygen 1.8.5 REQUIRED) set(doxyfile ${CMAKE_CURRENT_SOURCE_DIR}/docs/Doxyfile) add_custom_target( documentation ALL COMMAND ${DOXYGEN_EXECUTABLE} ${doxyfile} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMENT "Generating API documentation with Doxygen" VERBATIM ) add_dependencies(documentation ROM) add_custom_target( doxygen_tagfile COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/rom.tag ${CMAKE_CURRENT_BINARY_DIR}/docs/html/rom.tag) add_dependencies(doxygen_tagfile documentation) endif()