|
| 1 | +From 0144ab834e8b438a7077d3afa1cb2b025540259c Mon Sep 17 00:00:00 2001 |
| 2 | +From: Rui Chen <rui@chenrui.dev> |
| 3 | +Date: Sun, 28 Sep 2025 11:07:37 -0400 |
| 4 | +Subject: [PATCH] Support hypre 3.0 |
| 5 | + |
| 6 | +Signed-off-by: Rui Chen <rui@chenrui.dev> |
| 7 | +--- |
| 8 | + CMakeLists.txt | 10 +-- |
| 9 | + config/cmake/modules/FindHYPRE.cmake | 113 ++++++++++++++++++++++++++- |
| 10 | + linalg/hypre.cpp | 4 +- |
| 11 | + linalg/hypre.hpp | 8 +- |
| 12 | + linalg/hypre_parcsr.cpp | 6 +- |
| 13 | + linalg/hypre_parcsr.hpp | 4 + |
| 14 | + 6 files changed, 129 insertions(+), 16 deletions(-) |
| 15 | + |
| 16 | +diff --git a/CMakeLists.txt b/CMakeLists.txt |
| 17 | +index 64c9a62..45b16bb 100644 |
| 18 | +--- a/CMakeLists.txt |
| 19 | ++++ b/CMakeLists.txt |
| 20 | +@@ -261,6 +261,11 @@ if (MFEM_USE_OPENMP OR MFEM_USE_LEGACY_OPENMP) |
| 21 | + endif() |
| 22 | + endif() |
| 23 | + |
| 24 | ++# Umpire (must be included before hypre, so hypre can use it if needed) |
| 25 | ++if (MFEM_USE_UMPIRE) |
| 26 | ++ find_package(UMPIRE REQUIRED) |
| 27 | ++endif() |
| 28 | ++ |
| 29 | + # MPI -> hypre; PETSc (optional) |
| 30 | + if (MFEM_USE_MPI) |
| 31 | + find_package(MPI REQUIRED) |
| 32 | +@@ -476,11 +481,6 @@ if (MFEM_USE_RAJA) |
| 33 | + find_package(RAJA REQUIRED) |
| 34 | + endif() |
| 35 | + |
| 36 | +-# UMPIRE |
| 37 | +-if (MFEM_USE_UMPIRE) |
| 38 | +- find_package(UMPIRE REQUIRED) |
| 39 | +-endif() |
| 40 | +- |
| 41 | + # GOOGLE-BENCHMARK |
| 42 | + if (MFEM_USE_BENCHMARK) |
| 43 | + find_package(Benchmark REQUIRED) |
| 44 | +diff --git a/config/cmake/modules/FindHYPRE.cmake b/config/cmake/modules/FindHYPRE.cmake |
| 45 | +index d13b623..1df0790 100644 |
| 46 | +--- a/config/cmake/modules/FindHYPRE.cmake |
| 47 | ++++ b/config/cmake/modules/FindHYPRE.cmake |
| 48 | +@@ -9,21 +9,25 @@ |
| 49 | + # terms of the BSD-3 license. We welcome feedback and contributions, see file |
| 50 | + # CONTRIBUTING.md for details. |
| 51 | + |
| 52 | +-# Defines the following variables: |
| 53 | ++# Defines the following variables if fetching of TPLs is disabled (default): |
| 54 | + # - HYPRE_FOUND |
| 55 | + # - HYPRE_LIBRARIES |
| 56 | + # - HYPRE_INCLUDE_DIRS |
| 57 | + # - HYPRE_VERSION |
| 58 | + # - HYPRE_USING_CUDA (internal) |
| 59 | + # - HYPRE_USING_HIP (internal) |
| 60 | ++# otherwise, the following are defined: |
| 61 | ++# - HYPRE (imported library target) |
| 62 | ++# - HYPRE_VERSION (cache variable) |
| 63 | + |
| 64 | +-if (HYPRE_FOUND) |
| 65 | ++if (HYPRE_FOUND OR TARGET HYPRE) |
| 66 | + if (HYPRE_USING_CUDA) |
| 67 | + find_package(CUDAToolkit REQUIRED) |
| 68 | + endif() |
| 69 | + if (HYPRE_USING_HIP) |
| 70 | + find_package(rocsparse REQUIRED) |
| 71 | + find_package(rocrand REQUIRED) |
| 72 | ++ find_package(rocsolver REQUIRED) |
| 73 | + endif() |
| 74 | + if (HYPRE_LIBRARIES AND HYPRE_INCLUDE_DIRS AND HYPRE_VERSION) |
| 75 | + find_package_handle_standard_args(HYPRE |
| 76 | +@@ -33,6 +37,95 @@ if (HYPRE_FOUND) |
| 77 | + endif() |
| 78 | + endif() |
| 79 | + |
| 80 | ++if (HYPRE_FETCH OR FETCH_TPLS) |
| 81 | ++ # Collect all HYPRE_ENABLE variables and pass them to hypre, assuming they are BOOL. |
| 82 | ++ set(HYPRE_CMAKE_OPTIONS "") |
| 83 | ++ get_cmake_property(all_vars VARIABLES) |
| 84 | ++ foreach(var ${all_vars}) |
| 85 | ++ if(var MATCHES "^HYPRE_ENABLE") |
| 86 | ++ list(APPEND HYPRE_CMAKE_OPTIONS "-D${var}:BOOL=${${var}}") |
| 87 | ++ endif() |
| 88 | ++ endforeach() |
| 89 | ++ |
| 90 | ++ set(HYPRE_FETCH_VERSION 2.33.0) |
| 91 | ++ set(HYPRE_FETCH_TAG "v${HYPRE_FETCH_VERSION}" CACHE STRING "Tag, branch, or commit for HYPRE") |
| 92 | ++ add_library(HYPRE STATIC IMPORTED) |
| 93 | ++ # set options and associated dependencies |
| 94 | ++ list(APPEND HYPRE_CMAKE_OPTIONS -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}) |
| 95 | ++ if (MFEM_USE_CUDA) |
| 96 | ++ list(APPEND HYPRE_CMAKE_OPTIONS -DHYPRE_ENABLE_CUDA:BOOL=ON -DCMAKE_CUDA_ARCHITECTURES:STRING=${CMAKE_CUDA_ARCHITECTURES}) |
| 97 | ++ find_package(CUDAToolkit REQUIRED) |
| 98 | ++ target_link_libraries(HYPRE INTERFACE CUDA::cusparse CUDA::curand CUDA::cublas) |
| 99 | ++ elseif (MFEM_USE_HIP) |
| 100 | ++ list(APPEND HYPRE_CMAKE_OPTIONS -DHYPRE_ENABLE_HIP:BOOL=ON) |
| 101 | ++ find_package(rocsparse REQUIRED) |
| 102 | ++ find_package(rocrand REQUIRED) |
| 103 | ++ target_link_libraries(HYPRE INTERFACE rocsparse rocrand) |
| 104 | ++ endif() |
| 105 | ++ if (MFEM_USE_CUDA OR MFEM_USE_HIP) |
| 106 | ++ if (MFEM_USE_UMPIRE) |
| 107 | ++ if (EXISTS ${umpire_DIR}) |
| 108 | ++ list(APPEND HYPRE_CMAKE_OPTIONS -DHYPRE_ENABLE_UMPIRE:BOOL=ON -Dumpire_DIR:PATH=${umpire_DIR}) |
| 109 | ++ else() |
| 110 | ++ message(FATAL_ERROR "MFEM_USE_UMPIRE=ON, however umpire_DIR isn't visible to HYPRE") |
| 111 | ++ endif() |
| 112 | ++ else() |
| 113 | ++ list(APPEND HYPRE_CMAKE_OPTIONS -DHYPRE_ENABLE_UMPIRE:BOOL=OFF) |
| 114 | ++ message(WARNING |
| 115 | ++"================================================================================ |
| 116 | ++ Umpire is disabled while building HYPRE with GPU support. |
| 117 | ++ This is not recommended for performance reasons! |
| 118 | ++ Consider enabling Umpire with -DMFEM_USE_UMPIRE=ON and providing -DUMPIRE_DIR. |
| 119 | ++================================================================================") |
| 120 | ++ endif() |
| 121 | ++ endif() |
| 122 | ++ if (MFEM_USE_SINGLE) |
| 123 | ++ list(APPEND HYPRE_CMAKE_OPTIONS -DHYPRE_ENABLE_SINGLE:BOOL=ON) |
| 124 | ++ endif() |
| 125 | ++ # define external project and create future include directory so it is present |
| 126 | ++ # to pass CMake checks at end of MFEM configuration step |
| 127 | ++ message(STATUS "Will fetch HYPRE ${HYPRE_FETCH_TAG} to be built with ${HYPRE_CMAKE_OPTIONS}") |
| 128 | ++ set(HYPRE_INSTALL ${CMAKE_BINARY_DIR}/fetch/hypre) |
| 129 | ++ include(ExternalProject) |
| 130 | ++ ExternalProject_Add(hypre |
| 131 | ++ GIT_REPOSITORY https://github.com/hypre-space/hypre.git |
| 132 | ++ GIT_TAG ${HYPRE_FETCH_TAG} |
| 133 | ++ GIT_SHALLOW TRUE |
| 134 | ++ GIT_PROGRESS TRUE |
| 135 | ++ UPDATE_DISCONNECTED TRUE |
| 136 | ++ SOURCE_SUBDIR src |
| 137 | ++ PREFIX ${HYPRE_INSTALL} |
| 138 | ++ BUILD_COMMAND ${CMAKE_COMMAND} --build . -- -j${CMAKE_BUILD_PARALLEL_LEVEL} |
| 139 | ++ CMAKE_CACHE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=${HYPRE_INSTALL} -DCMAKE_INSTALL_LIBDIR:PATH=lib ${HYPRE_CMAKE_OPTIONS}) |
| 140 | ++ file(MAKE_DIRECTORY ${HYPRE_INSTALL}/include) |
| 141 | ++ # set imported library target properties |
| 142 | ++ add_dependencies(HYPRE hypre) |
| 143 | ++ set_target_properties(HYPRE PROPERTIES |
| 144 | ++ IMPORTED_LOCATION ${HYPRE_INSTALL}/lib/libHYPRE.a |
| 145 | ++ INTERFACE_INCLUDE_DIRECTORIES ${HYPRE_INSTALL}/include) |
| 146 | ++ # convert HYPRE version to integer |
| 147 | ++ if (HYPRE_FETCH_TAG MATCHES "^v?([0-9]+)\\.([0-9]+)\\.([0-9]+)$") |
| 148 | ++ # Exact release tag X.Y.Z |
| 149 | ++ string(REGEX MATCHALL "[0-9]+" HYPRE_SPLIT_VERSION "${HYPRE_FETCH_TAG}") |
| 150 | ++ elseif (HYPRE_FETCH_VERSION MATCHES "([0-9]+)\\.([0-9]+)(\\.([0-9]+))?") |
| 151 | ++ string(REGEX MATCHALL "[0-9]+" HYPRE_SPLIT_VERSION "${HYPRE_FETCH_VERSION}") |
| 152 | ++ else (NOT DEFINED HYPRE_VERSION) |
| 153 | ++ message(FATAL_ERROR "Unable to find HYPRE release version. Please provide it via -DHYPRE_VERSION") |
| 154 | ++ endif() |
| 155 | ++ if (HYPRE_SPLIT_VERSION AND NOT DEFINED HYPRE_VERSION) |
| 156 | ++ list(GET HYPRE_SPLIT_VERSION 0 HYPRE_MAJOR_VERSION) |
| 157 | ++ list(GET HYPRE_SPLIT_VERSION 1 HYPRE_MINOR_VERSION) |
| 158 | ++ if (HYPRE_SPLIT_VERSION GREATER 2) |
| 159 | ++ list(GET HYPRE_SPLIT_VERSION 2 HYPRE_PATCH_VERSION) |
| 160 | ++ else() |
| 161 | ++ set(HYPRE_PATCH_VERSION 0) |
| 162 | ++ endif() |
| 163 | ++ math(EXPR HYPRE_VERSION "10000*${HYPRE_MAJOR_VERSION} + 100*${HYPRE_MINOR_VERSION} + ${HYPRE_PATCH_VERSION}") |
| 164 | ++ set(HYPRE_VERSION ${HYPRE_VERSION} CACHE STRING "HYPRE version." FORCE) |
| 165 | ++ endif() |
| 166 | ++ return() |
| 167 | ++endif() |
| 168 | ++ |
| 169 | + include(MfemCmakeUtilities) |
| 170 | + mfem_find_package(HYPRE HYPRE HYPRE_DIR "include" "HYPRE.h" "lib" "HYPRE" |
| 171 | + "Paths to headers required by HYPRE." "Libraries required by HYPRE." |
| 172 | +@@ -86,8 +179,9 @@ if (HYPRE_FOUND AND HYPRE_USING_CUDA) |
| 173 | + mfem_culib_set_libraries(CUSPARSE cusparse) |
| 174 | + mfem_culib_set_libraries(CURAND curand) |
| 175 | + mfem_culib_set_libraries(CUBLAS cublas) |
| 176 | ++ mfem_culib_set_libraries(CUSOLVER cusolver) |
| 177 | + list(APPEND HYPRE_LIBRARIES ${CUSPARSE_LIBRARIES} ${CURAND_LIBRARIES} |
| 178 | +- ${CUBLAS_LIBRARIES}) |
| 179 | ++ ${CUBLAS_LIBRARIES} ${CUSOLVER_LIBRARIES}) |
| 180 | + set(HYPRE_LIBRARIES ${HYPRE_LIBRARIES} CACHE STRING |
| 181 | + "HYPRE libraries + dependencies." FORCE) |
| 182 | + message(STATUS "Updated HYPRE_LIBRARIES: ${HYPRE_LIBRARIES}") |
| 183 | +@@ -96,12 +190,23 @@ endif() |
| 184 | + if (HYPRE_FOUND AND HYPRE_USING_HIP) |
| 185 | + find_package(rocsparse REQUIRED) |
| 186 | + find_package(rocrand REQUIRED) |
| 187 | +- list(APPEND HYPRE_LIBRARIES ${rocsparse_LIBRARIES} ${rocrand_LIBRARIES}) |
| 188 | ++ find_package(rocsolver REQUIRED) |
| 189 | ++ list(APPEND HYPRE_LIBRARIES ${rocsparse_LIBRARIES} ${rocrand_LIBRARIES} roc::rocsolver roc::rocblas) |
| 190 | + set(HYPRE_LIBRARIES ${HYPRE_LIBRARIES} CACHE STRING |
| 191 | + "HYPRE libraries + dependencies." FORCE) |
| 192 | + message(STATUS "Updated HYPRE_LIBRARIES: ${HYPRE_LIBRARIES}") |
| 193 | + endif() |
| 194 | + |
| 195 | ++# Hypre+Umpire check |
| 196 | ++if (HYPRE_FOUND AND (HYPRE_USING_CUDA OR HYPRE_USING_HIP) AND NOT MFEM_USE_UMPIRE) |
| 197 | ++ message(WARNING |
| 198 | ++"=============================================================== |
| 199 | ++ Detected GPU-enabled HYPRE build without Umpire support. |
| 200 | ++ This is not recommended for performance reasons! |
| 201 | ++ Consider rebuilding HYPRE with Umpire support. |
| 202 | ++===============================================================") |
| 203 | ++endif() |
| 204 | ++ |
| 205 | + find_package_handle_standard_args(HYPRE |
| 206 | + REQUIRED_VARS HYPRE_LIBRARIES HYPRE_INCLUDE_DIRS HYPRE_VERSION |
| 207 | + ) |
| 208 | +diff --git a/linalg/hypre.cpp b/linalg/hypre.cpp |
| 209 | +index c3f6067..a19c2bb 100644 |
| 210 | +--- a/linalg/hypre.cpp |
| 211 | ++++ b/linalg/hypre.cpp |
| 212 | +@@ -2324,10 +2324,10 @@ void HypreParMatrix::Threshold(real_t threshold) |
| 213 | + ierr += hypre_CSRMatrixDestroy(csr_A); |
| 214 | + } |
| 215 | + |
| 216 | +- /* TODO: GenerateDiagAndOffd() uses an int array of size equal to the number |
| 217 | ++ /* TODO: hypre_GenerateDiagAndOffd() uses an int array of size equal to the number |
| 218 | + of columns in csr_A_wo_z which is the global number of columns in A. This |
| 219 | + does not scale well. */ |
| 220 | +- ierr += GenerateDiagAndOffd(csr_A_wo_z,parcsr_A_ptr, |
| 221 | ++ ierr += hypre_GenerateDiagAndOffd(csr_A_wo_z,parcsr_A_ptr, |
| 222 | + col_start,col_end); |
| 223 | + |
| 224 | + ierr += hypre_CSRMatrixDestroy(csr_A_wo_z); |
| 225 | +diff --git a/linalg/hypre.hpp b/linalg/hypre.hpp |
| 226 | +index efbb0de..93e7c01 100644 |
| 227 | +--- a/linalg/hypre.hpp |
| 228 | ++++ b/linalg/hypre.hpp |
| 229 | +@@ -25,11 +25,11 @@ |
| 230 | + #define HYPRE_TIMING |
| 231 | + |
| 232 | + // hypre header files |
| 233 | +-#include <seq_mv.h> |
| 234 | +-#include <temp_multivector.h> |
| 235 | + #include <_hypre_parcsr_mv.h> |
| 236 | + #include <_hypre_parcsr_ls.h> |
| 237 | + |
| 238 | ++#include <HYPRE_parcsr_ls.h> |
| 239 | ++ |
| 240 | + #ifdef HYPRE_COMPLEX |
| 241 | + #error "MFEM does not work with HYPRE's complex numbers support" |
| 242 | + #endif |
| 243 | +@@ -53,6 +53,10 @@ |
| 244 | + #error "MFEM_USE_HIP=YES is required when HYPRE is built with HIP!" |
| 245 | + #endif |
| 246 | + |
| 247 | ++#if MFEM_HYPRE_VERSION > 21500 |
| 248 | ++#define HYPRE_AssumedPartitionCheck() 1 |
| 249 | ++#endif |
| 250 | ++ |
| 251 | + namespace mfem |
| 252 | + { |
| 253 | + |
| 254 | +diff --git a/linalg/hypre_parcsr.cpp b/linalg/hypre_parcsr.cpp |
| 255 | +index a11eab8..2409e25 100644 |
| 256 | +--- a/linalg/hypre_parcsr.cpp |
| 257 | ++++ b/linalg/hypre_parcsr.cpp |
| 258 | +@@ -1916,9 +1916,9 @@ hypre_ParCSRMatrixAdd(hypre_ParCSRMatrix *A, |
| 259 | + /* FIXME: GenerateDiagAndOffd() uses an int array of size equal to the |
| 260 | + number of columns in csr_C_temp which is the global number of columns |
| 261 | + in A and B. This does not scale well. */ |
| 262 | +- ierr += GenerateDiagAndOffd(csr_C_temp, C, |
| 263 | +- hypre_ParCSRMatrixFirstColDiag(A), |
| 264 | +- hypre_ParCSRMatrixLastColDiag(A)); |
| 265 | ++ ierr += hypre_GenerateDiagAndOffd(csr_C_temp, C, |
| 266 | ++ hypre_ParCSRMatrixFirstColDiag(A), |
| 267 | ++ hypre_ParCSRMatrixLastColDiag(A)); |
| 268 | + |
| 269 | + /* delete CSR version of C */ |
| 270 | + ierr += hypre_CSRMatrixDestroy(csr_C_temp); |
| 271 | +diff --git a/linalg/hypre_parcsr.hpp b/linalg/hypre_parcsr.hpp |
| 272 | +index 4dadd31..07b3217 100644 |
| 273 | +--- a/linalg/hypre_parcsr.hpp |
| 274 | ++++ b/linalg/hypre_parcsr.hpp |
| 275 | +@@ -21,6 +21,10 @@ |
| 276 | + // hypre header files |
| 277 | + #include <_hypre_parcsr_mv.h> |
| 278 | + |
| 279 | ++#if MFEM_HYPRE_VERSION < 30000 |
| 280 | ++#define hypre_GenerateDiagAndOffd GenerateDiagAndOffd |
| 281 | ++#endif |
| 282 | ++ |
| 283 | + // Older hypre versions do not define HYPRE_BigInt and HYPRE_MPI_BIG_INT, so we |
| 284 | + // define them here for backward compatibility. |
| 285 | + #if MFEM_HYPRE_VERSION < 21600 |
| 286 | +-- |
| 287 | +2.51.0 |
| 288 | + |
0 commit comments