├── .github └── workflows │ └── ci.yml ├── .gitignore ├── CMakeLists.txt ├── Docker.md ├── Dockerfile ├── LICENSE ├── README.md ├── cmake ├── FindBLACS.cmake ├── FindLAPACK.cmake ├── FindMETIS.cmake ├── FindMUMPS.cmake ├── FindSCALAPACK.cmake ├── FindScotch.cmake └── options.cmake └── src ├── CMakeLists.txt ├── blacs_demo.f90 ├── input_simpletest_real ├── metis.f90 ├── pardiso_basic.f90 ├── scalapack_demo.f90 ├── test_mpi.f90 └── test_mumps.f90 /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | 3 | env: 4 | HOMEBREW_NO_INSTALL_CLEANUP: 1 5 | 6 | on: 7 | push: 8 | paths: 9 | - "**.f90" 10 | - "**.F90" 11 | - "**/CMakeLists.txt" 12 | - "**.cmake" 13 | - ".github/workflows/ci.yml" 14 | 15 | 16 | jobs: 17 | 18 | core: 19 | 20 | strategy: 21 | matrix: 22 | img: [ 23 | { os: ubuntu-latest, cmd: sudo apt update && sudo apt install --no-install-recommends libopenmpi-dev openmpi-bin liblapack-dev libscalapack-mpi-dev libmumps-dev libparmetis-dev }, 24 | { os: macos-latest, cmd: brew install scalapack open-mpi metis && brew reinstall gcc} 25 | ] 26 | 27 | runs-on: ${{ matrix.img.os }} 28 | 29 | steps: 30 | 31 | - uses: actions/checkout@v3 32 | 33 | - name: Install packages 34 | run: ${{ matrix.img.cmd }} 35 | 36 | - run: cmake -B build 37 | - run: cmake --build build 38 | - run: ctest --test-dir build -V 39 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | 3 | # Prerequisites 4 | *.d 5 | 6 | # Compiled Object files 7 | *.slo 8 | *.lo 9 | *.o 10 | *.obj 11 | 12 | # Precompiled Headers 13 | *.gch 14 | *.pch 15 | 16 | # Compiled Dynamic libraries 17 | *.so 18 | *.dylib 19 | *.dll 20 | 21 | # Fortran module files 22 | *.mod 23 | *.smod 24 | 25 | # Compiled Static libraries 26 | *.lai 27 | *.la 28 | *.a 29 | *.lib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.13...3.25) 2 | 3 | project(SparseExamples 4 | LANGUAGES C Fortran 5 | ) 6 | 7 | enable_testing() 8 | 9 | set(arith "d") 10 | 11 | include(cmake/options.cmake) 12 | 13 | find_package(MPI COMPONENTS C Fortran REQUIRED) 14 | find_package(LAPACK REQUIRED) 15 | find_package(SCALAPACK REQUIRED) 16 | find_package(MUMPS) 17 | find_package(METIS) 18 | 19 | add_subdirectory(src) 20 | -------------------------------------------------------------------------------- /Docker.md: -------------------------------------------------------------------------------- 1 | # Docker 2 | 3 | In a directory with the [Dockerfile](./Dockerfile) 4 | 5 | ```sh 6 | docker build -t sp-fortran . 7 | docker run -it sp-fortran 8 | cd sparse-fortran 9 | ``` 10 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM continuumio/miniconda3:latest 2 | RUN /opt/conda/bin/conda install compilers mpich-mpifort mkl mkl-include mumps-mpi blas=*=mkl cmake make git -c defaults -c conda-forge -y 3 | RUN /opt/conda/bin/conda clean --all --force-pkgs-dirs --yes 4 | RUN /opt/conda/bin/git clone --depth=1 https://github.com/scivision/sparse-fortran 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Michael Hirsch, Ph.D. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Sparse Fortran libraries 2 | 3 | ![Actions Status](https://github.com/scivision/sparse-fortran/workflows/ci/badge.svg) 4 | 5 | Examples using BLACS, SCALAPACK, MUMPS, PARDISO for solving sparse arrays in Fortran. 6 | 7 | For Linux, MUMPS can be easily obtained: 8 | 9 | * Ubuntu / Debian: `apt install libmumps-dev` 10 | * CentOS: `apt install mumps-devel` 11 | 12 | ```sh 13 | cmake -B build 14 | cmake --build build 15 | ``` 16 | 17 | The simple examples included test the parallel functionality of MUMPS. 18 | -------------------------------------------------------------------------------- /cmake/FindBLACS.cmake: -------------------------------------------------------------------------------- 1 | # Distributed under the OSI-approved BSD 3-Clause License. See accompanying 2 | # file Copyright.txt or https://cmake.org/licensing for details. 3 | 4 | #[=======================================================================[.rst: 5 | 6 | FindBLACS 7 | --------- 8 | 9 | by Michael Hirsch, Ph.D. www.scivision.dev 10 | 11 | Finds BLACS libraries for MKL, OpenMPI and MPICH. 12 | Intel MKL relies on having environment variable MKLROOT set, typically by sourcing 13 | mklvars.sh beforehand. 14 | Intended to work with Intel MKL at least through version 2021. 15 | 16 | This module does NOT find LAPACK. 17 | 18 | Parameters 19 | ^^^^^^^^^^ 20 | 21 | ``MKL`` 22 | Intel MKL for MSVC, ICL, ICC, GCC and PGCC. Working with IntelMPI (default Window, Linux), MPICH (default Mac) or OpenMPI (Linux only). 23 | 24 | ``OpenMPI`` 25 | OpenMPI interface 26 | 27 | ``MPICH`` 28 | MPICH interface 29 | 30 | 31 | Result Variables 32 | ^^^^^^^^^^^^^^^^ 33 | 34 | ``BLACS_FOUND`` 35 | BLACS libraries were found 36 | ``BLACS__FOUND`` 37 | BLACS specified was found 38 | ``BLACS_LIBRARIES`` 39 | BLACS library files 40 | ``BLACS_INCLUDE_DIRS`` 41 | BLACS include directories 42 | 43 | 44 | References 45 | ^^^^^^^^^^ 46 | 47 | * Pkg-Config and MKL: https://software.intel.com/en-us/articles/intel-math-kernel-library-intel-mkl-and-pkg-config-tool 48 | * MKL for Windows: https://software.intel.com/en-us/mkl-windows-developer-guide-static-libraries-in-the-lib-intel64-win-directory 49 | * MKL Windows directories: https://software.intel.com/en-us/mkl-windows-developer-guide-high-level-directory-structure 50 | * MKL link-line advisor: https://software.intel.com/en-us/articles/intel-mkl-link-line-advisor 51 | #]=======================================================================] 52 | 53 | set(BLACS_LIBRARY) # don't endlessly append 54 | 55 | #===== functions 56 | 57 | function(blacs_mkl) 58 | 59 | set(_mkl_libs ${ARGV}) 60 | 61 | foreach(s ${_mkl_libs}) 62 | find_library(BLACS_${s}_LIBRARY 63 | NAMES ${s} 64 | PATHS 65 | ${MKLROOT} 66 | ENV I_MPI_ROOT 67 | ENV TBBROOT 68 | ../tbb/lib/intel64/gcc4.7 69 | ../tbb/lib/intel64/vc_mt 70 | ../compiler/lib/intel64 71 | PATH_SUFFIXES 72 | lib lib/intel64 lib/intel64_win 73 | intel64/lib/release 74 | lib/intel64/gcc4.7 75 | lib/intel64/vc_mt 76 | HINTS ${MKL_LIBRARY_DIRS} ${MKL_LIBDIR} 77 | NO_DEFAULT_PATH) 78 | if(NOT BLACS_${s}_LIBRARY) 79 | return() 80 | endif() 81 | 82 | list(APPEND BLACS_LIBRARY ${BLACS_${s}_LIBRARY}) 83 | endforeach() 84 | 85 | 86 | find_path(BLACS_INCLUDE_DIR 87 | NAMES mkl_blacs.h 88 | PATHS 89 | ${MKLROOT} 90 | ENV I_MPI_ROOT 91 | ENV TBBROOT 92 | PATH_SUFFIXES 93 | include 94 | include/intel64/lp64 95 | HINTS ${MKL_INCLUDE_DIRS}) 96 | 97 | if(NOT BLACS_INCLUDE_DIR) 98 | return() 99 | endif() 100 | 101 | list(APPEND BLACS_INCLUDE_DIR ${MKL_INCLUDE_DIRS}) 102 | 103 | set(BLACS_MKL_FOUND true PARENT_SCOPE) 104 | set(BLACS_LIBRARY ${BLACS_LIBRARY} PARENT_SCOPE) 105 | set(BLACS_INCLUDE_DIR ${BLACS_INCLUDE_DIR} PARENT_SCOPE) 106 | 107 | endfunction(blacs_mkl) 108 | 109 | 110 | function(nonmkl) 111 | 112 | if(MPICH IN_LIST BLACS_FIND_COMPONENTS) 113 | 114 | find_library(BLACS_LIBRARY 115 | NAMES blacs-mpich blacs-mpich2 116 | NAMES_PER_DIR) 117 | if(BLACS_LIBRARY) 118 | set(BLACS_MPICH_FOUND true PARENT_SCOPE) 119 | endif() 120 | 121 | elseif(LAM IN_LIST BLACS_FIND_COMPONENTS) 122 | 123 | find_library(BLACS_LIBRARY 124 | NAMES blacs-lam) 125 | if(BLACS_LIBRARY) 126 | set(BLACS_LAM_FOUND true PARENT_SCOPE) 127 | endif() 128 | 129 | elseif(PVM IN_LIST BLACS_FIND_COMPONENTS) 130 | 131 | find_library(BLACS_LIBRARY 132 | NAMES blacs-pvm) 133 | if(BLACS_LIBRARY) 134 | set(BLACS_PVM_FOUND true PARENT_SCOPE) 135 | endif() 136 | 137 | elseif(OpenMPI IN_LIST BLACS_FIND_COMPONENTS) 138 | 139 | find_library(BLACS_INIT 140 | NAMES blacsF77init blacsF77init-openmpi 141 | NAMES_PER_DIR) 142 | if(BLACS_INIT) 143 | list(APPEND BLACS_LIBRARY ${BLACS_INIT}) 144 | endif() 145 | 146 | find_library(BLACS_CINIT 147 | NAMES blacsCinit blacsCinit-openmpi 148 | NAMES_PER_DIR) 149 | if(BLACS_CINIT) 150 | list(APPEND BLACS_LIBRARY ${BLACS_CINIT}) 151 | endif() 152 | 153 | # this is the only lib that scalapack/blacs/src provides 154 | find_library(BLACS_LIB 155 | NAMES blacs blacs-mpi blacs-openmpi 156 | NAMES_PER_DIR) 157 | if(BLACS_LIB) 158 | list(APPEND BLACS_LIBRARY ${BLACS_LIB}) 159 | endif() 160 | 161 | if(BLACS_LIBRARY) 162 | set(BLACS_OpenMPI_FOUND true PARENT_SCOPE) 163 | endif() 164 | 165 | endif() 166 | 167 | set(BLACS_LIBRARY ${BLACS_LIBRARY} PARENT_SCOPE) 168 | 169 | endfunction(nonmkl) 170 | 171 | # === main 172 | 173 | if(NOT (OpenMPI IN_LIST BLACS_FIND_COMPONENTS 174 | OR MPICH IN_LIST BLACS_FIND_COMPONENTS 175 | OR MKL IN_LIST BLACS_FIND_COMPONENTS)) 176 | if(DEFINED ENV{MKLROOT}) 177 | list(APPEND BLACS_FIND_COMPONENTS MKL) 178 | if(APPLE) 179 | list(APPEND BLACS_FIND_COMPONENTS MPICH) 180 | endif() 181 | else() 182 | list(APPEND BLACS_FIND_COMPONENTS OpenMPI) 183 | endif() 184 | endif() 185 | 186 | find_package(PkgConfig) 187 | 188 | set(BLACS_INCLUDE_DIR) 189 | 190 | if(MKL IN_LIST BLACS_FIND_COMPONENTS) 191 | # we have to sanitize MKLROOT if it has Windows backslashes (\) otherwise it will break at build time 192 | # double-quotes are necessary per CMake to_cmake_path docs. 193 | file(TO_CMAKE_PATH "$ENV{MKLROOT}" MKLROOT) 194 | 195 | list(APPEND CMAKE_PREFIX_PATH ${MKLROOT}/tools/pkgconfig) 196 | 197 | if(BUILD_SHARED_LIBS) 198 | set(_mkltype dynamic) 199 | else() 200 | set(_mkltype static) 201 | endif() 202 | 203 | pkg_check_modules(MKL mkl-${_mkltype}-lp64-iomp) 204 | 205 | if(OpenMPI IN_LIST BLACS_FIND_COMPONENTS) 206 | blacs_mkl(mkl_blacs_openmpi_lp64) 207 | set(BLACS_OpenMPI_FOUND ${BLACS_MKL_FOUND}) 208 | elseif(MPICH IN_LIST BLACS_FIND_COMPONENTS) 209 | if(APPLE) 210 | blacs_mkl(mkl_blacs_mpich_lp64) 211 | elseif(WIN32) 212 | blacs_mkl(mkl_blacs_mpich2_lp64.lib mpi.lib fmpich2.lib) 213 | else() # MPICH linux is just like IntelMPI 214 | blacs_mkl(mkl_blacs_intelmpi_lp64) 215 | endif() 216 | set(BLACS_MPICH_FOUND ${BLACS_MKL_FOUND}) 217 | else() 218 | blacs_mkl(mkl_blacs_intelmpi_lp64) 219 | endif() 220 | 221 | else(MKL IN_LIST BLACS_FIND_COMPONENTS) 222 | 223 | nonmkl() 224 | 225 | endif(MKL IN_LIST BLACS_FIND_COMPONENTS) 226 | 227 | include(FindPackageHandleStandardArgs) 228 | find_package_handle_standard_args(BLACS 229 | REQUIRED_VARS BLACS_LIBRARY 230 | HANDLE_COMPONENTS) 231 | 232 | if(BLACS_FOUND) 233 | # need if _FOUND guard to allow project to autobuild; can't overwrite imported target even if bad 234 | set(BLACS_INCLUDE_DIRS ${BLACS_INCLUDE_DIR}) 235 | set(BLACS_LIBRARIES ${BLACS_LIBRARY}) 236 | 237 | if(NOT TARGET BLACS::BLACS) 238 | add_library(BLACS::BLACS INTERFACE IMPORTED) 239 | set_target_properties(BLACS::BLACS PROPERTIES 240 | INTERFACE_LINK_LIBRARIES "${BLACS_LIBRARY}" 241 | INTERFACE_INCLUDE_DIRECTORIES "${BLACS_INCLUDE_DIR}" 242 | ) 243 | endif() 244 | endif(BLACS_FOUND) 245 | 246 | mark_as_advanced(BLACS_LIBRARY BLACS_INCLUDE_DIR) 247 | -------------------------------------------------------------------------------- /cmake/FindLAPACK.cmake: -------------------------------------------------------------------------------- 1 | # Distributed under the OSI-approved BSD 3-Clause License. See accompanying 2 | # file Copyright.txt or https://cmake.org/licensing for details. 3 | 4 | #[=======================================================================[.rst: 5 | 6 | FindLapack 7 | ---------- 8 | 9 | * Michael Hirsch, Ph.D. www.scivision.dev 10 | * David Eklund 11 | 12 | Let Michael know if there are more MKL / Lapack / compiler combination you want. 13 | Refer to https://software.intel.com/en-us/articles/intel-mkl-link-line-advisor 14 | 15 | Finds LAPACK libraries for C / C++ / Fortran. 16 | Works with Netlib Lapack / LapackE, Atlas and Intel MKL. 17 | Intel MKL relies on having environment variable MKLROOT set, typically by sourcing 18 | mklvars.sh beforehand. 19 | 20 | Why not the FindLapack.cmake built into CMake? It has a lot of old code for 21 | infrequently used Lapack libraries and is unreliable for me. 22 | 23 | Tested on Linux, MacOS and Windows with: 24 | * GCC / Gfortran 25 | * Clang / Flang 26 | * Intel (icc, ifort) 27 | * Cray 28 | 29 | 30 | Parameters 31 | ^^^^^^^^^^ 32 | 33 | COMPONENTS default to Netlib LAPACK / LapackE, otherwise: 34 | 35 | ``MKL`` 36 | Intel MKL for MSVC, ICL, ICC, GCC and PGCC -- sequential by default, or add TBB or MPI as well 37 | ``OpenMP`` 38 | Intel MPI with OpenMP threading addition to MKL 39 | ``TBB`` 40 | Intel MPI + TBB for MKL 41 | ``MKL64`` 42 | MKL only: 64-bit integers (default is 32-bit integers) 43 | 44 | ``LAPACKE`` 45 | Netlib LapackE for C / C++ 46 | ``Netlib`` 47 | Netlib Lapack for Fortran 48 | ``OpenBLAS`` 49 | OpenBLAS Lapack for Fortran 50 | 51 | ``LAPACK95`` 52 | get Lapack95 interfaces for MKL or Netlib (must also specify one of MKL, Netlib) 53 | 54 | 55 | Result Variables 56 | ^^^^^^^^^^^^^^^^ 57 | 58 | ``LAPACK_FOUND`` 59 | Lapack libraries were found 60 | ``LAPACK__FOUND`` 61 | LAPACK specified was found 62 | ``LAPACK_LIBRARIES`` 63 | Lapack library files (including BLAS 64 | ``LAPACK_INCLUDE_DIRS`` 65 | Lapack include directories (for C/C++) 66 | 67 | 68 | References 69 | ^^^^^^^^^^ 70 | 71 | * Pkg-Config and MKL: https://software.intel.com/en-us/articles/intel-math-kernel-library-intel-mkl-and-pkg-config-tool 72 | * MKL for Windows: https://software.intel.com/en-us/mkl-windows-developer-guide-static-libraries-in-the-lib-intel64-win-directory 73 | * MKL Windows directories: https://software.intel.com/en-us/mkl-windows-developer-guide-high-level-directory-structure 74 | * Atlas http://math-atlas.sourceforge.net/errata.html#LINK 75 | * MKL LAPACKE (C, C++): https://software.intel.com/en-us/mkl-linux-developer-guide-calling-lapack-blas-and-cblas-routines-from-c-c-language-environments 76 | #]=======================================================================] 77 | 78 | include(CheckFortranSourceCompiles) 79 | 80 | # clear to avoid endless appending on subsequent calls 81 | set(LAPACK_LIBRARY) 82 | unset(LAPACK_INCLUDE_DIR) 83 | 84 | # ===== functions ========== 85 | 86 | function(atlas_libs) 87 | 88 | find_library(ATLAS_LIB 89 | NAMES atlas 90 | PATH_SUFFIXES atlas 91 | DOC "ATLAS library" 92 | ) 93 | 94 | find_library(LAPACK_ATLAS 95 | NAMES ptlapack lapack_atlas lapack 96 | NAMES_PER_DIR 97 | PATH_SUFFIXES atlas 98 | DOC "LAPACK ATLAS library" 99 | ) 100 | 101 | find_library(BLAS_LIBRARY 102 | NAMES ptf77blas f77blas blas 103 | NAMES_PER_DIR 104 | PATH_SUFFIXES atlas 105 | DOC "BLAS ATLAS library" 106 | ) 107 | 108 | # === C === 109 | find_library(BLAS_C_ATLAS 110 | NAMES ptcblas cblas 111 | NAMES_PER_DIR 112 | PATH_SUFFIXES atlas 113 | DOC "BLAS C ATLAS library" 114 | ) 115 | 116 | find_path(LAPACK_INCLUDE_DIR 117 | NAMES cblas-atlas.h cblas.h clapack.h 118 | DOC "ATLAS headers" 119 | ) 120 | 121 | #=========== 122 | if(LAPACK_ATLAS AND BLAS_C_ATLAS AND BLAS_LIBRARY AND ATLAS_LIB) 123 | set(LAPACK_Atlas_FOUND true PARENT_SCOPE) 124 | set(LAPACK_LIBRARY ${LAPACK_ATLAS} ${BLAS_C_ATLAS} ${BLAS_LIBRARY} ${ATLAS_LIB}) 125 | list(APPEND LAPACK_LIBRARY ${CMAKE_THREAD_LIBS_INIT}) 126 | endif() 127 | 128 | set(LAPACK_LIBRARY ${LAPACK_LIBRARY} PARENT_SCOPE) 129 | 130 | endfunction(atlas_libs) 131 | 132 | #======================= 133 | 134 | function(netlib_libs) 135 | 136 | if(LAPACK95 IN_LIST LAPACK_FIND_COMPONENTS) 137 | find_path(LAPACK95_INCLUDE_DIR 138 | NAMES f95_lapack.mod 139 | HINTS ${LAPACK95_ROOT} ENV LAPACK95_ROOT 140 | PATH_SUFFIXES include 141 | DOC "LAPACK95 Fortran module" 142 | ) 143 | 144 | find_library(LAPACK95_LIBRARY 145 | NAMES lapack95 146 | HINTS ${LAPACK95_ROOT} ENV LAPACK95_ROOT 147 | DOC "LAPACK95 library" 148 | ) 149 | 150 | if(NOT (LAPACK95_LIBRARY AND LAPACK95_INCLUDE_DIR)) 151 | return() 152 | endif() 153 | 154 | set(LAPACK95_LIBRARY ${LAPACK95_LIBRARY} PARENT_SCOPE) 155 | set(LAPACK_LAPACK95_FOUND true PARENT_SCOPE) 156 | endif(LAPACK95 IN_LIST LAPACK_FIND_COMPONENTS) 157 | 158 | find_library(LAPACK_LIBRARY 159 | NAMES lapack 160 | PATH_SUFFIXES lapack lapack/lib 161 | DOC "LAPACK library" 162 | ) 163 | if(NOT LAPACK_LIBRARY) 164 | return() 165 | endif() 166 | 167 | if(LAPACKE IN_LIST LAPACK_FIND_COMPONENTS) 168 | 169 | find_library(LAPACKE_LIBRARY 170 | NAMES lapacke 171 | PATH_SUFFIXES lapack lapack/lib 172 | ) 173 | 174 | # lapack/include for Homebrew 175 | find_path(LAPACKE_INCLUDE_DIR 176 | NAMES lapacke.h 177 | PATH_SUFFIXES lapack lapack/include 178 | ) 179 | if(NOT (LAPACKE_LIBRARY AND LAPACKE_INCLUDE_DIR)) 180 | return() 181 | endif() 182 | 183 | set(LAPACK_LAPACKE_FOUND true PARENT_SCOPE) 184 | list(APPEND LAPACK_INCLUDE_DIR ${LAPACKE_INCLUDE_DIR}) 185 | list(APPEND LAPACK_LIBRARY ${LAPACKE_LIBRARY}) 186 | mark_as_advanced(LAPACKE_LIBRARY LAPACKE_INCLUDE_DIR) 187 | endif(LAPACKE IN_LIST LAPACK_FIND_COMPONENTS) 188 | 189 | # Netlib on Cygwin and others 190 | 191 | find_library(BLAS_LIBRARY 192 | NAMES refblas blas 193 | NAMES_PER_DIR 194 | PATH_SUFFIXES lapack lapack/lib blas 195 | DOC "BLAS library" 196 | ) 197 | 198 | if(NOT BLAS_LIBRARY) 199 | return() 200 | endif() 201 | 202 | list(APPEND LAPACK_LIBRARY ${BLAS_LIBRARY}) 203 | set(LAPACK_Netlib_FOUND true PARENT_SCOPE) 204 | 205 | list(APPEND LAPACK_LIBRARY ${CMAKE_THREAD_LIBS_INIT}) 206 | 207 | set(LAPACK_LIBRARY ${LAPACK_LIBRARY} PARENT_SCOPE) 208 | 209 | endfunction(netlib_libs) 210 | 211 | #=============================== 212 | function(openblas_libs) 213 | 214 | find_library(LAPACK_LIBRARY 215 | NAMES lapack 216 | PATH_SUFFIXES openblas 217 | DOC "LAPACK library" 218 | ) 219 | 220 | find_library(BLAS_LIBRARY 221 | NAMES openblas blas 222 | NAMES_PER_DIR 223 | PATH_SUFFIXES openblas 224 | DOC "BLAS library" 225 | ) 226 | 227 | find_path(LAPACK_INCLUDE_DIR 228 | NAMES cblas-openblas.h cblas.h f77blas.h openblas_config.h 229 | ) 230 | 231 | if(NOT (LAPACK_LIBRARY AND BLAS_LIBRARY)) 232 | return() 233 | endif() 234 | 235 | list(APPEND LAPACK_LIBRARY ${BLAS_LIBRARY}) 236 | set(LAPACK_OpenBLAS_FOUND true PARENT_SCOPE) 237 | 238 | list(APPEND LAPACK_LIBRARY ${CMAKE_THREAD_LIBS_INIT}) 239 | 240 | set(LAPACK_LIBRARY ${LAPACK_LIBRARY} PARENT_SCOPE) 241 | 242 | endfunction(openblas_libs) 243 | 244 | #=============================== 245 | 246 | function(find_mkl_libs) 247 | # https://software.intel.com/en-us/articles/intel-mkl-link-line-advisor 248 | 249 | set(_mkl_libs ${ARGV}) 250 | if(CMAKE_SYSTEM_NAME STREQUAL "Linux" AND 251 | CMAKE_Fortran_COMPILER_ID STREQUAL "GNU" 252 | ) 253 | list(INSERT _mkl_libs 0 mkl_gf_${_mkl_bitflag}lp64) 254 | else() 255 | if(WIN32 AND BUILD_SHARED_LIBS) 256 | list(INSERT _mkl_libs 0 mkl_intel_${_mkl_bitflag}lp64_dll) 257 | else() 258 | list(INSERT _mkl_libs 0 mkl_intel_${_mkl_bitflag}lp64) 259 | endif() 260 | endif() 261 | 262 | foreach(s ${_mkl_libs}) 263 | find_library(LAPACK_${s}_LIBRARY 264 | NAMES ${s} 265 | PATHS ${MKLROOT}/lib ${MKLROOT}/lib/intel64 ${oneapi_libdir} 266 | NO_DEFAULT_PATH 267 | DOC "Intel MKL ${s} library" 268 | ) 269 | # ${MKLROOT}/[lib[/intel64]]: general MKL libraries 270 | # oneapi_libdir: openmp library 271 | 272 | if(NOT LAPACK_${s}_LIBRARY) 273 | return() 274 | endif() 275 | 276 | list(APPEND LAPACK_LIBRARY ${LAPACK_${s}_LIBRARY}) 277 | endforeach() 278 | 279 | find_path(LAPACK_INCLUDE_DIR 280 | NAMES mkl_lapack.h 281 | HINTS ${MKLROOT} 282 | PATH_SUFFIXES include 283 | NO_DEFAULT_PATH 284 | DOC "Intel MKL header" 285 | ) 286 | 287 | if(NOT LAPACK_INCLUDE_DIR) 288 | return() 289 | endif() 290 | 291 | set(LAPACK_LIBRARY ${LAPACK_LIBRARY} PARENT_SCOPE) 292 | 293 | endfunction(find_mkl_libs) 294 | 295 | # ========== main program 296 | 297 | set(lapack_cray false) 298 | if(DEFINED ENV{CRAYPE_VERSION}) 299 | set(lapack_cray true) 300 | endif() 301 | 302 | if(NOT (lapack_cray 303 | OR OpenBLAS IN_LIST LAPACK_FIND_COMPONENTS 304 | OR Netlib IN_LIST LAPACK_FIND_COMPONENTS 305 | OR Atlas IN_LIST LAPACK_FIND_COMPONENTS 306 | OR MKL IN_LIST LAPACK_FIND_COMPONENTS)) 307 | if(DEFINED ENV{MKLROOT}) 308 | list(APPEND LAPACK_FIND_COMPONENTS MKL) 309 | else() 310 | list(APPEND LAPACK_FIND_COMPONENTS Netlib) 311 | endif() 312 | endif() 313 | 314 | find_package(Threads) 315 | 316 | # ==== generic MKL variables ==== 317 | 318 | if(MKL IN_LIST LAPACK_FIND_COMPONENTS OR MKL64 IN_LIST LAPACK_FIND_COMPONENTS) 319 | # we have to sanitize MKLROOT if it has Windows backslashes (\) otherwise it will break at build time 320 | # double-quotes are necessary per CMake to_cmake_path docs. 321 | file(TO_CMAKE_PATH "$ENV{MKLROOT}" MKLROOT) 322 | 323 | file(TO_CMAKE_PATH "$ENV{ONEAPI_ROOT}" ONEAPI_ROOT) 324 | # oneapi_libdir is where iomp5 is located 325 | set(oneapi_libdir ${ONEAPI_ROOT}/compiler/latest/) 326 | if(WIN32) 327 | string(APPEND oneapi_libdir "windows/compiler/lib/intel64_win") 328 | elseif(APPLE) 329 | string(APPEND oneapi_libdir "mac/compiler/lib") 330 | elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux") 331 | string(APPEND oneapi_libdir "linux/compiler/lib/intel64_lin") 332 | endif() 333 | 334 | if(MKL64 IN_LIST LAPACK_FIND_COMPONENTS) 335 | set(_mkl_bitflag i) 336 | else() 337 | set(_mkl_bitflag) 338 | endif() 339 | 340 | set(_mkl_libs) 341 | if(LAPACK95 IN_LIST LAPACK_FIND_COMPONENTS) 342 | find_mkl_libs(mkl_blas95_${_mkl_bitflag}lp64 mkl_lapack95_${_mkl_bitflag}lp64) 343 | if(LAPACK_LIBRARY) 344 | set(LAPACK95_LIBRARY ${LAPACK_LIBRARY}) 345 | set(LAPACK_LIBRARY) 346 | set(LAPACK95_INCLUDE_DIR ${LAPACK_INCLUDE_DIR}) 347 | set(LAPACK_LAPACK95_FOUND true) 348 | endif() 349 | endif() 350 | 351 | set(_tbb) 352 | if(TBB IN_LIST LAPACK_FIND_COMPONENTS) 353 | list(APPEND _mkl_libs mkl_tbb_thread mkl_core) 354 | set(_tbb tbb stdc++) 355 | elseif(OpenMP IN_LIST LAPACK_FIND_COMPONENTS) 356 | if(WIN32) 357 | set(_mp libiomp5md) 358 | else() 359 | set(_mp iomp5) 360 | endif() 361 | if(WIN32 AND BUILD_SHARED_LIBS) 362 | list(APPEND _mkl_libs mkl_intel_thread_dll mkl_core_dll ${_mp}) 363 | else() 364 | list(APPEND _mkl_libs mkl_intel_thread mkl_core ${_mp}) 365 | endif() 366 | else() 367 | if(WIN32 AND BUILD_SHARED_LIBS) 368 | list(APPEND _mkl_libs mkl_sequential_dll mkl_core_dll) 369 | else() 370 | list(APPEND _mkl_libs mkl_sequential mkl_core) 371 | endif() 372 | endif() 373 | 374 | find_mkl_libs(${_mkl_libs}) 375 | 376 | if(LAPACK_LIBRARY) 377 | 378 | if(NOT WIN32) 379 | list(APPEND LAPACK_LIBRARY ${_tbb} ${CMAKE_THREAD_LIBS_INIT} ${CMAKE_DL_LIBS} m) 380 | endif() 381 | 382 | set(LAPACK_MKL_FOUND true) 383 | 384 | if(MKL64 IN_LIST LAPACK_FIND_COMPONENTS) 385 | set(LAPACK_MKL64_FOUND true) 386 | endif() 387 | 388 | if(OpenMP IN_LIST LAPACK_FIND_COMPONENTS) 389 | set(LAPACK_OpenMP_FOUND true) 390 | endif() 391 | 392 | if(TBB IN_LIST LAPACK_FIND_COMPONENTS) 393 | set(LAPACK_TBB_FOUND true) 394 | endif() 395 | endif() 396 | 397 | elseif(Atlas IN_LIST LAPACK_FIND_COMPONENTS) 398 | atlas_libs() 399 | elseif(Netlib IN_LIST LAPACK_FIND_COMPONENTS) 400 | netlib_libs() 401 | elseif(OpenBLAS IN_LIST LAPACK_FIND_COMPONENTS) 402 | openblas_libs() 403 | elseif(lapack_cray) 404 | # LAPACK is implicitly part of Cray PE LibSci, use Cray compiler wrapper. 405 | endif() 406 | 407 | # -- verify library works 408 | 409 | function(lapack_check) 410 | 411 | get_property(enabled_langs GLOBAL PROPERTY ENABLED_LANGUAGES) 412 | if(NOT Fortran IN_LIST enabled_langs) 413 | set(LAPACK_links true PARENT_SCOPE) 414 | return() 415 | endif() 416 | 417 | set(CMAKE_REQUIRED_FLAGS) 418 | set(CMAKE_REQUIRED_LINK_OPTIONS) 419 | set(CMAKE_REQUIRED_INCLUDES) 420 | set(CMAKE_REQUIRED_LIBRARIES ${LAPACK_LIBRARY}) 421 | 422 | check_fortran_source_compiles( 423 | "program check_lapack 424 | use, intrinsic :: iso_fortran_env, only : real32 425 | implicit none 426 | real(real32), external :: snrm2 427 | print *, snrm2(1, [0._real32], 1) 428 | end program" 429 | LAPACK_s_FOUND 430 | SRC_EXT f90 431 | ) 432 | 433 | check_fortran_source_compiles( 434 | "program check_lapack 435 | use, intrinsic :: iso_fortran_env, only : real64 436 | implicit none 437 | real(real64), external :: dnrm2 438 | print *, dnrm2(1, [0._real64], 1) 439 | end program" 440 | LAPACK_d_FOUND 441 | SRC_EXT f90 442 | ) 443 | 444 | if(LAPACK_s_FOUND OR LAPACK_d_FOUND) 445 | set(LAPACK_links true PARENT_SCOPE) 446 | endif() 447 | 448 | endfunction(lapack_check) 449 | 450 | # --- Check that Scalapack links 451 | 452 | if(lapack_cray OR LAPACK_LIBRARY) 453 | lapack_check() 454 | endif() 455 | 456 | 457 | include(FindPackageHandleStandardArgs) 458 | 459 | if(lapack_cray) 460 | find_package_handle_standard_args(LAPACK HANDLE_COMPONENTS 461 | REQUIRED_VARS LAPACK_links 462 | ) 463 | else() 464 | find_package_handle_standard_args(LAPACK HANDLE_COMPONENTS 465 | REQUIRED_VARS LAPACK_LIBRARY LAPACK_links 466 | ) 467 | endif() 468 | 469 | 470 | set(BLAS_LIBRARIES ${BLAS_LIBRARY}) 471 | set(LAPACK_LIBRARIES ${LAPACK_LIBRARY}) 472 | set(LAPACK_INCLUDE_DIRS ${LAPACK_INCLUDE_DIR}) 473 | 474 | if(LAPACK_FOUND) 475 | # need if _FOUND guard as can't overwrite imported target even if bad 476 | if(NOT TARGET BLAS::BLAS) 477 | add_library(BLAS::BLAS INTERFACE IMPORTED) 478 | set_property(TARGET BLAS::BLAS PROPERTY INTERFACE_LINK_LIBRARIES "${BLAS_LIBRARY}") 479 | endif() 480 | 481 | if(NOT TARGET LAPACK::LAPACK) 482 | add_library(LAPACK::LAPACK INTERFACE IMPORTED) 483 | set_property(TARGET LAPACK::LAPACK PROPERTY INTERFACE_LINK_LIBRARIES "${LAPACK_LIBRARY}") 484 | set_property(TARGET LAPACK::LAPACK PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${LAPACK_INCLUDE_DIR}") 485 | endif() 486 | 487 | if(LAPACK_LAPACK95_FOUND) 488 | set(LAPACK95_LIBRARIES ${LAPACK95_LIBRARY}) 489 | set(LAPACK95_INCLUDE_DIRS ${LAPACK95_INCLUDE_DIR}) 490 | 491 | if(NOT TARGET LAPACK::LAPACK95) 492 | add_library(LAPACK::LAPACK95 INTERFACE IMPORTED) 493 | set_property(TARGET LAPACK::LAPACK95 PROPERTY INTERFACE_LINK_LIBRARIES "${LAPACK95_LIBRARY}") 494 | set_property(TARGET LAPACK::LAPACK95 PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${LAPACK95_INCLUDE_DIR}") 495 | endif() 496 | endif() 497 | endif() 498 | 499 | mark_as_advanced(LAPACK_LIBRARY LAPACK_INCLUDE_DIR) 500 | -------------------------------------------------------------------------------- /cmake/FindMETIS.cmake: -------------------------------------------------------------------------------- 1 | # Distributed under the OSI-approved BSD 3-Clause License. See accompanying 2 | # file Copyright.txt or https://cmake.org/licensing for details. 3 | 4 | #[=======================================================================[.rst: 5 | FindMETIS 6 | ------- 7 | Michael Hirsch, Ph.D. 8 | 9 | Finds the METIS library. 10 | NOTE: If libparmetis used, libmetis must also be linked. 11 | 12 | Imported Targets 13 | ^^^^^^^^^^^^^^^^ 14 | 15 | METIS::METIS 16 | 17 | Result Variables 18 | ^^^^^^^^^^^^^^^^ 19 | 20 | METIS_LIBRARIES 21 | libraries to be linked 22 | 23 | METIS_INCLUDE_DIRS 24 | dirs to be included 25 | 26 | #]=======================================================================] 27 | 28 | 29 | if(parallel IN_LIST METIS_FIND_COMPONENTS) 30 | find_library(PARMETIS_LIBRARY 31 | NAMES parmetis 32 | PATH_SUFFIXES METIS libmetis) 33 | if(PARMETIS_LIBRARY) 34 | set(METIS_parallel_FOUND true) 35 | endif() 36 | endif() 37 | 38 | find_library(METIS_LIBRARY 39 | NAMES metis 40 | PATH_SUFFIXES METIS libmetis) 41 | 42 | if(parallel IN_LIST METIS_FIND_COMPONENTS) 43 | set(metis_inc parmetis.h) 44 | else() 45 | set(metis_inc metis.h) 46 | endif() 47 | 48 | find_path(METIS_INCLUDE_DIR 49 | NAMES ${metis_inc} 50 | PATH_SUFFIXES METIS openmpi-x86_64 mpich-x86_64) 51 | 52 | include(FindPackageHandleStandardArgs) 53 | find_package_handle_standard_args(METIS 54 | REQUIRED_VARS METIS_LIBRARY METIS_INCLUDE_DIR 55 | HANDLE_COMPONENTS) 56 | 57 | if(METIS_FOUND) 58 | 59 | set(METIS_LIBRARIES ${PARMETIS_LIBRARY} ${METIS_LIBRARY}) 60 | set(METIS_INCLUDE_DIRS ${METIS_INCLUDE_DIR}) 61 | 62 | if(NOT TARGET METIS::METIS) 63 | add_library(METIS::METIS INTERFACE IMPORTED) 64 | set_property(TARGET METIS::METIS PROPERTY INTERFACE_LINK_LIBRARIES "${METIS_LIBRARIES}") 65 | set_property(TARGET METIS::METIS PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${METIS_INCLUDE_DIR}") 66 | endif() 67 | endif(METIS_FOUND) 68 | 69 | mark_as_advanced(METIS_INCLUDE_DIR METIS_LIBRARY PARMETIS_LIBRARY) 70 | -------------------------------------------------------------------------------- /cmake/FindMUMPS.cmake: -------------------------------------------------------------------------------- 1 | # Distributed under the OSI-approved BSD 3-Clause License. See accompanying 2 | # file Copyright.txt or https://cmake.org/licensing for details. 3 | 4 | #[=======================================================================[.rst: 5 | FindMUMPS 6 | --------- 7 | 8 | Finds the MUMPS library. 9 | Note that MUMPS generally requires SCALAPACK and LAPACK as well. 10 | PORD is always used, in addition to the optional Scotch + METIS. 11 | 12 | COMPONENTS 13 | s d c z list one or more. Default is "s d" 14 | 15 | Result Variables 16 | ^^^^^^^^^^^^^^^^ 17 | 18 | MUMPS_LIBRARIES 19 | libraries to be linked 20 | 21 | MUMPS_INCLUDE_DIRS 22 | dirs to be included 23 | 24 | MUMPS_HAVE_OPENMP 25 | MUMPS is using OpenMP and thus user programs must link OpenMP as well. 26 | 27 | MUMPS_HAVE_Scotch 28 | MUMPS is using Scotch/METIS and thus user programs must link Scotch/METIS as well. 29 | 30 | #]=======================================================================] 31 | 32 | set(MUMPS_LIBRARY) # don't endlessly append 33 | set(CMAKE_REQUIRED_FLAGS) 34 | 35 | include(CheckFortranSourceCompiles) 36 | 37 | # --- functions 38 | 39 | function(mumps_openmp_check) 40 | 41 | # MUMPS doesn't set any distinct symbols or procedures if OpenMP was linked, 42 | # so we do this indirect test to see if MUMPS needs OpenMP to link. 43 | 44 | find_package(OpenMP COMPONENTS C Fortran) 45 | if(OpenMP_FOUND) 46 | list(APPEND CMAKE_REQUIRED_FLAGS ${OpenMP_Fortran_FLAGS} ${OpenMP_C_FLAGS}) 47 | list(APPEND CMAKE_REQUIRED_INCLUDES ${OpenMP_Fortran_INCLUDE_DIRS} ${OpenMP_C_INCLUDE_DIRS}) 48 | list(APPEND CMAKE_REQUIRED_LIBRARIES ${OpenMP_Fortran_LIBRARIES} ${OpenMP_C_LIBRARIES}) 49 | endif() 50 | 51 | check_fortran_source_compiles( 52 | "program test_omp 53 | implicit none 54 | external :: mumps_ana_omp_return, MUMPS_ICOPY_32TO64_64C 55 | call mumps_ana_omp_return() 56 | call MUMPS_ICOPY_32TO64_64C() 57 | end program" 58 | MUMPS_HAVE_OPENMP 59 | SRC_EXT f90 60 | ) 61 | 62 | endfunction(mumps_openmp_check) 63 | 64 | 65 | function(mumps_scotch_check) 66 | 67 | # check if Scotch linked 68 | find_package(Scotch COMPONENTS ESMUMPS) 69 | # METIS is required when using Scotch 70 | if(Scotch_FOUND) 71 | find_package(METIS) 72 | endif() 73 | 74 | if(NOT METIS_FOUND) 75 | return() 76 | endif() 77 | 78 | list(APPEND CMAKE_REQUIRED_INCLUDES ${Scotch_INCLUDE_DIRS} ${METIS_INCLUDE_DIRS}) 79 | list(APPEND CMAKE_REQUIRED_LIBRARIES ${Scotch_LIBRARIES} ${METIS_LIBRARIES}) 80 | 81 | check_fortran_source_compiles( 82 | "program test_scotch 83 | implicit none 84 | external :: mumps_scotch 85 | call mumps_scotch() 86 | end program" 87 | MUMPS_HAVE_Scotch 88 | SRC_EXT f90 89 | ) 90 | 91 | endfunction(mumps_scotch_check) 92 | 93 | 94 | function(mumps_check) 95 | 96 | if(NOT (MUMPS_LIBRARY AND MUMPS_INCLUDE_DIR)) 97 | message(VERBOSE "MUMPS: skip checks as not found") 98 | return() 99 | endif() 100 | 101 | 102 | find_package(SCALAPACK) 103 | 104 | if(NOT (MPI_C_FOUND AND MPI_Fortran_FOUND)) 105 | # factory FindMPI re-searches, slowing down configure, especialy when many subprojects use MPI 106 | find_package(MPI COMPONENTS C Fortran) 107 | endif() 108 | 109 | find_package(LAPACK) 110 | 111 | set(CMAKE_REQUIRED_INCLUDES ${MUMPS_INCLUDE_DIR} ${SCALAPACK_INCLUDE_DIRS} ${LAPACK_INCLUDE_DIRS} ${MPI_Fortran_INCLUDE_DIRS} ${MPI_C_INCLUDE_DIRS}) 112 | set(CMAKE_REQUIRED_LIBRARIES ${MUMPS_LIBRARY} ${SCALAPACK_LIBRARIES} ${LAPACK_LIBRARIES} ${MPI_Fortran_LIBRARIES} ${MPI_C_LIBRARIES}) 113 | 114 | mumps_openmp_check() 115 | 116 | mumps_scotch_check() 117 | 118 | 119 | foreach(c IN LISTS MUMPS_FIND_COMPONENTS) 120 | if(NOT c IN_LIST mumps_ariths) 121 | continue() 122 | endif() 123 | 124 | check_fortran_source_compiles( 125 | "program test_mumps 126 | implicit none 127 | include '${c}mumps_struc.h' 128 | external :: ${c}mumps 129 | type(${c}mumps_struc) :: mumps_par 130 | end program" 131 | MUMPS_${c}_links 132 | SRC_EXT f90 133 | ) 134 | 135 | if(NOT MUMPS_${c}_links) 136 | continue() 137 | endif() 138 | 139 | set(MUMPS_${c}_FOUND true PARENT_SCOPE) 140 | endforeach() 141 | 142 | set(MUMPS_links true PARENT_SCOPE) 143 | 144 | endfunction(mumps_check) 145 | 146 | 147 | function(mumps_libs) 148 | 149 | # NOTE: NO_DEFAULT_PATH disables CMP0074 MUMPS_ROOT and PATH_SUFFIXES, so we manually specify: 150 | # HINTS ${MUMPS_ROOT} ENV MUMPS_ROOT 151 | # PATH_SUFFIXES ... 152 | # to allow MKL using user-built MUMPS with `cmake -DMUMPS_ROOT=~/lib_intel/mumps` 153 | 154 | if(DEFINED ENV{MKLROOT}) 155 | find_path(MUMPS_INCLUDE_DIR 156 | NAMES mumps_compat.h 157 | NO_DEFAULT_PATH 158 | HINTS ${MUMPS_ROOT} ENV MUMPS_ROOT ${CMAKE_PREFIX_PATH} ENV CMAKE_PREFIX_PATH 159 | PATH_SUFFIXES include 160 | DOC "MUMPS common header" 161 | ) 162 | else() 163 | find_path(MUMPS_INCLUDE_DIR 164 | NAMES mumps_compat.h 165 | PATH_SUFFIXES MUMPS openmpi-x86_64 mpich-x86_64 166 | DOC "MUMPS common header" 167 | ) 168 | endif() 169 | if(NOT MUMPS_INCLUDE_DIR) 170 | return() 171 | endif() 172 | 173 | # get Mumps version 174 | find_file(mumps_conf 175 | NAMES smumps_c.h dmumps_c.h 176 | HINTS ${MUMPS_INCLUDE_DIR} 177 | NO_DEFAULT_PATH 178 | DOC "MUMPS configuration header" 179 | ) 180 | 181 | if(mumps_conf) 182 | file(STRINGS ${mumps_conf} _def 183 | REGEX "^[ \t]*#[ \t]*define[ \t]+MUMPS_VERSION[ \t]+" ) 184 | 185 | if("${_def}" MATCHES "MUMPS_VERSION[ \t]+\"([0-9]+\\.[0-9]+\\.[0-9]+)?\"") 186 | set(MUMPS_VERSION "${CMAKE_MATCH_1}" PARENT_SCOPE) 187 | endif() 188 | endif() 189 | 190 | # --- Mumps Common --- 191 | if(DEFINED ENV{MKLROOT}) 192 | find_library(MUMPS_COMMON 193 | NAMES mumps_common 194 | NO_DEFAULT_PATH 195 | HINTS ${MUMPS_ROOT} ENV MUMPS_ROOT ${CMAKE_PREFIX_PATH} ENV CMAKE_PREFIX_PATH 196 | PATH_SUFFIXES lib 197 | DOC "MUMPS MPI common libraries" 198 | ) 199 | else() 200 | find_library(MUMPS_COMMON 201 | NAMES mumps_common mumps_common_mpi mumpso_common mumps_common_shm 202 | NAMES_PER_DIR 203 | PATH_SUFFIXES openmpi/lib mpich/lib 204 | DOC "MUMPS common libraries" 205 | ) 206 | endif() 207 | 208 | if(NOT MUMPS_COMMON) 209 | return() 210 | endif() 211 | 212 | # --- Pord --- 213 | 214 | if(DEFINED ENV{MKLROOT}) 215 | find_library(PORD 216 | NAMES pord 217 | NO_DEFAULT_PATH 218 | HINTS ${MUMPS_ROOT} ENV MUMPS_ROOT ${CMAKE_PREFIX_PATH} ENV CMAKE_PREFIX_PATH 219 | PATH_SUFFIXES lib 220 | DOC "simplest MUMPS ordering library" 221 | ) 222 | else() 223 | find_library(PORD 224 | NAMES pord mumps_pord 225 | NAMES_PER_DIR 226 | PATH_SUFFIXES openmpi/lib mpich/lib 227 | DOC "simplest MUMPS ordering library" 228 | ) 229 | endif() 230 | if(NOT PORD) 231 | return() 232 | endif() 233 | 234 | foreach(c IN LISTS MUMPS_FIND_COMPONENTS) 235 | if(NOT "${c}" IN_LIST mumps_ariths) 236 | continue() 237 | endif() 238 | 239 | if(DEFINED ENV{MKLROOT}) 240 | find_library(MUMPS_${c}_lib 241 | NAMES ${c}mumps 242 | NO_DEFAULT_PATH 243 | HINTS ${MUMPS_ROOT} ENV MUMPS_ROOT ${CMAKE_PREFIX_PATH} ENV CMAKE_PREFIX_PATH 244 | PATH_SUFFIXES lib 245 | DOC "MUMPS precision-specific" 246 | ) 247 | else() 248 | find_library(MUMPS_${c}_lib 249 | NAMES ${c}mumps ${c}mumps_mpi 250 | NAMES_PER_DIR 251 | PATH_SUFFIXES openmpi/lib mpich/lib 252 | DOC "MUMPS precision-specific" 253 | ) 254 | endif() 255 | 256 | if(NOT MUMPS_${c}_lib) 257 | continue() 258 | endif() 259 | 260 | list(APPEND MUMPS_LIBRARY ${MUMPS_${c}_lib}) 261 | endforeach() 262 | 263 | set(MUMPS_LIBRARY ${MUMPS_LIBRARY} ${MUMPS_COMMON} ${PORD} PARENT_SCOPE) 264 | 265 | endfunction(mumps_libs) 266 | 267 | # --- main 268 | 269 | # need to have at least one arith precision component 270 | set(mumps_ariths s d c z) 271 | 272 | set(mumps_need_default true) 273 | foreach(c IN LISTS MUMPS_FIND_COMPONENTS) 274 | if(c IN_LIST mumps_ariths) 275 | set(mumps_need_default false) 276 | break() 277 | endif() 278 | endforeach() 279 | if(mumps_need_default) 280 | list(APPEND MUMPS_FIND_COMPONENTS s d) 281 | endif() 282 | 283 | mumps_libs() 284 | 285 | mumps_check() 286 | 287 | # --- finalize 288 | 289 | set(CMAKE_REQUIRED_FLAGS) 290 | set(CMAKE_REQUIRED_INCLUDES) 291 | set(CMAKE_REQUIRED_LIBRARIES) 292 | 293 | include(FindPackageHandleStandardArgs) 294 | find_package_handle_standard_args(MUMPS 295 | REQUIRED_VARS MUMPS_LIBRARY MUMPS_INCLUDE_DIR MUMPS_links 296 | VERSION_VAR MUMPS_VERSION 297 | HANDLE_COMPONENTS 298 | ) 299 | 300 | if(MUMPS_FOUND) 301 | # need if _FOUND guard as can't overwrite imported target even if bad 302 | set(MUMPS_LIBRARIES ${MUMPS_LIBRARY}) 303 | set(MUMPS_INCLUDE_DIRS ${MUMPS_INCLUDE_DIR}) 304 | 305 | if(NOT TARGET MUMPS::MUMPS) 306 | add_library(MUMPS::MUMPS INTERFACE IMPORTED) 307 | set_property(TARGET MUMPS::MUMPS PROPERTY INTERFACE_LINK_LIBRARIES "${MUMPS_LIBRARY};SCALAPACK::SCALAPACK;LAPACK::LAPACK;${MPI_Fortran_LIBRARIES};MPI::MPI_C") 308 | set_property(TARGET MUMPS::MUMPS PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${MUMPS_INCLUDE_DIR};${MPI_Fortran_INCLUDE_DIRS}") 309 | endif() 310 | 311 | endif(MUMPS_FOUND) 312 | 313 | mark_as_advanced(MUMPS_INCLUDE_DIR MUMPS_LIBRARY) 314 | -------------------------------------------------------------------------------- /cmake/FindSCALAPACK.cmake: -------------------------------------------------------------------------------- 1 | # Distributed under the OSI-approved BSD 3-Clause License. See accompanying 2 | # file Copyright.txt or https://cmake.org/licensing for details. 3 | 4 | #[=======================================================================[.rst: 5 | 6 | FindSCALAPACK 7 | ------------- 8 | 9 | by Michael Hirsch, Ph.D. www.scivision.dev 10 | 11 | Finds SCALAPACK libraries for MKL, OpenMPI and MPICH. 12 | Intel MKL relies on having environment variable MKLROOT set, typically by sourcing 13 | mklvars.sh beforehand. 14 | 15 | This module does NOT find LAPACK. 16 | 17 | Parameters 18 | ^^^^^^^^^^ 19 | 20 | ``MKL`` 21 | Intel MKL for MSVC, oneAPI, GCC. 22 | Working with IntelMPI (default Window, Linux), MPICH (default Mac) or OpenMPI (Linux only). 23 | 24 | ``MKL64`` 25 | MKL only: 64-bit integers (default is 32-bit integers) 26 | 27 | Result Variables 28 | ^^^^^^^^^^^^^^^^ 29 | 30 | ``SCALAPACK_FOUND`` 31 | SCALapack libraries were found 32 | ``SCALAPACK__FOUND`` 33 | SCALAPACK specified was found 34 | ``SCALAPACK_LIBRARIES`` 35 | SCALapack library files 36 | ``SCALAPACK_INCLUDE_DIRS`` 37 | SCALapack include directories 38 | 39 | 40 | References 41 | ^^^^^^^^^^ 42 | 43 | * Pkg-Config and MKL: https://software.intel.com/en-us/articles/intel-math-kernel-library-intel-mkl-and-pkg-config-tool 44 | * MKL for Windows: https://software.intel.com/en-us/mkl-windows-developer-guide-static-libraries-in-the-lib-intel64-win-directory 45 | * MKL Windows directories: https://software.intel.com/en-us/mkl-windows-developer-guide-high-level-directory-structure 46 | * MKL link-line advisor: https://software.intel.com/en-us/articles/intel-mkl-link-line-advisor 47 | #]=======================================================================] 48 | 49 | include(CheckFortranSourceCompiles) 50 | 51 | set(SCALAPACK_LIBRARY) # avoids appending to prior FindScalapack 52 | 53 | #===== functions 54 | 55 | function(scalapack_check) 56 | 57 | find_package(MPI COMPONENTS C Fortran) 58 | if(NOT LAPACK_FOUND) 59 | # otherwise can cause 32-bit lapack when 64-bit wanted 60 | find_package(LAPACK) 61 | endif() 62 | if(NOT (MPI_Fortran_FOUND AND LAPACK_FOUND)) 63 | return() 64 | endif() 65 | 66 | 67 | set(CMAKE_REQUIRED_FLAGS) 68 | set(CMAKE_REQUIRED_LINK_OPTIONS) 69 | set(CMAKE_REQUIRED_INCLUDES ${SCALAPACK_INCLUDE_DIR}) 70 | set(CMAKE_REQUIRED_LIBRARIES ${SCALAPACK_LIBRARY}) 71 | if(BLACS_LIBRARY) 72 | list(APPEND CMAKE_REQUIRED_LIBRARIES ${BLACS_LIBRARY}) 73 | endif() 74 | list(APPEND CMAKE_REQUIRED_LIBRARIES LAPACK::LAPACK MPI::MPI_Fortran) 75 | 76 | # MPI needed for ifort 77 | 78 | check_fortran_source_compiles( 79 | "program test 80 | use, intrinsic :: iso_fortran_env, only : real64 81 | implicit none 82 | real(real64), external :: pdlamch 83 | integer :: ictxt 84 | print *, pdlamch(ictxt, 'E') 85 | end program" 86 | SCALAPACK_d_FOUND 87 | SRC_EXT f90 88 | ) 89 | 90 | check_fortran_source_compiles( 91 | "program test 92 | use, intrinsic :: iso_fortran_env, only : real32 93 | implicit none 94 | real(real32), external :: pslamch 95 | integer :: ictxt 96 | print *, pslamch(ictxt, 'E') 97 | end program" 98 | SCALAPACK_s_FOUND 99 | SRC_EXT f90 100 | ) 101 | 102 | if(SCALAPACK_s_FOUND OR SCALAPACK_d_FOUND) 103 | set(SCALAPACK_links true PARENT_SCOPE) 104 | endif() 105 | 106 | endfunction(scalapack_check) 107 | 108 | 109 | function(scalapack_mkl scalapack_name blacs_name) 110 | 111 | find_library(SCALAPACK_LIBRARY 112 | NAMES ${scalapack_name} 113 | HINTS ${MKLROOT} 114 | PATH_SUFFIXES lib lib/intel64 115 | NO_DEFAULT_PATH 116 | ) 117 | 118 | find_library(BLACS_LIBRARY 119 | NAMES ${blacs_name} 120 | HINTS ${MKLROOT} 121 | PATH_SUFFIXES lib lib/intel64 122 | NO_DEFAULT_PATH 123 | ) 124 | 125 | find_path(SCALAPACK_INCLUDE_DIR 126 | NAMES mkl_scalapack.h 127 | HINTS ${MKLROOT} 128 | PATH_SUFFIXES include 129 | NO_DEFAULT_PATH 130 | ) 131 | 132 | # pc_mkl_INCLUDE_DIRS on Windows injects breaking garbage 133 | 134 | if(SCALAPACK_LIBRARY AND BLACS_LIBRARY AND SCALAPACK_INCLUDE_DIR) 135 | set(SCALAPACK_MKL_FOUND true) 136 | endif() 137 | 138 | if(MKL64 IN_LIST SCALAPACK_FIND_COMPONENTS) 139 | set(SCALAPACK_MKL64_FOUND ${SCALAPACK_MKL_FOUND}) 140 | 141 | if(DEFINED ENV{I_MPI_ROOT}) 142 | file(TO_CMAKE_PATH "$ENV{I_MPI_ROOT}" I_MPI_ROOT) 143 | 144 | if(MSVC) 145 | set(CMAKE_FIND_LIBRARY_PREFIXES lib) 146 | endif() 147 | 148 | find_library(SCALAPACK_MPI_LIB64 149 | NAMES mpi_ilp64 150 | HINTS ${I_MPI_ROOT} 151 | NO_DEFAULT_PATH 152 | PATH_SUFFIXES lib lib/release 153 | ) 154 | 155 | if(NOT SCALAPACK_MPI_LIB64) 156 | set(SCALAPACK_MKL64_FOUND false) 157 | endif() 158 | endif() 159 | endif() 160 | 161 | set(SCALAPACK_MKL_FOUND ${SCALAPACK_MKL_FOUND} PARENT_SCOPE) 162 | set(SCALAPACK_MKL64_FOUND ${SCALAPACK_MKL64_FOUND} PARENT_SCOPE) 163 | 164 | endfunction(scalapack_mkl) 165 | 166 | # === main 167 | 168 | set(scalapack_cray false) 169 | if(DEFINED ENV{CRAYPE_VERSION}) 170 | set(scalapack_cray true) 171 | endif() 172 | 173 | if(NOT scalapack_cray) 174 | if(NOT MKL IN_LIST SCALAPACK_FIND_COMPONENTS AND DEFINED ENV{MKLROOT}) 175 | list(APPEND SCALAPACK_FIND_COMPONENTS MKL) 176 | endif() 177 | endif() 178 | 179 | if(MKL IN_LIST SCALAPACK_FIND_COMPONENTS OR MKL64 IN_LIST SCALAPACK_FIND_COMPONENTS) 180 | # we have to sanitize MKLROOT if it has Windows backslashes (\) otherwise it will break at build time 181 | # double-quotes are necessary per CMake to_cmake_path docs. 182 | file(TO_CMAKE_PATH "$ENV{MKLROOT}" MKLROOT) 183 | 184 | if(MKL64 IN_LIST SCALAPACK_FIND_COMPONENTS) 185 | set(_mkl_bitflag i) 186 | else() 187 | set(_mkl_bitflag) 188 | endif() 189 | 190 | # find MKL MPI binding 191 | if(WIN32) 192 | if(BUILD_SHARED_LIBS) 193 | scalapack_mkl(mkl_scalapack_${_mkl_bitflag}lp64_dll mkl_blacs_${_mkl_bitflag}lp64_dll) 194 | else() 195 | scalapack_mkl(mkl_scalapack_${_mkl_bitflag}lp64 mkl_blacs_intelmpi_${_mkl_bitflag}lp64) 196 | endif() 197 | elseif(APPLE) 198 | scalapack_mkl(mkl_scalapack_${_mkl_bitflag}lp64 mkl_blacs_mpich_${_mkl_bitflag}lp64) 199 | else() 200 | scalapack_mkl(mkl_scalapack_${_mkl_bitflag}lp64 mkl_blacs_intelmpi_${_mkl_bitflag}lp64) 201 | endif() 202 | 203 | elseif(scalapack_cray) 204 | # Cray PE has Scalapack build into LibSci. Use Cray compiler wrapper. 205 | else() 206 | 207 | find_library(SCALAPACK_LIBRARY 208 | NAMES scalapack scalapack-openmpi scalapack-mpich 209 | NAMES_PER_DIR 210 | PATH_SUFFIXES openmpi/lib mpich/lib 211 | ) 212 | 213 | # some systems have libblacs as a separate file, instead of being subsumed in libscalapack. 214 | get_filename_component(BLACS_ROOT ${SCALAPACK_LIBRARY} DIRECTORY) 215 | 216 | find_library(BLACS_LIBRARY 217 | NAMES blacs 218 | NO_DEFAULT_PATH 219 | HINTS ${BLACS_ROOT} 220 | ) 221 | 222 | endif() 223 | 224 | # --- Check that Scalapack links 225 | 226 | if(scalapack_cray OR SCALAPACK_LIBRARY) 227 | scalapack_check() 228 | endif() 229 | 230 | # --- Finalize 231 | 232 | include(FindPackageHandleStandardArgs) 233 | 234 | if(scalapack_cray) 235 | find_package_handle_standard_args(SCALAPACK HANDLE_COMPONENTS 236 | REQUIRED_VARS SCALAPACK_links 237 | ) 238 | else() 239 | find_package_handle_standard_args(SCALAPACK HANDLE_COMPONENTS 240 | REQUIRED_VARS SCALAPACK_LIBRARY SCALAPACK_links 241 | ) 242 | endif() 243 | 244 | if(SCALAPACK_FOUND) 245 | # need if _FOUND guard as can't overwrite imported target even if bad 246 | set(SCALAPACK_LIBRARIES ${SCALAPACK_LIBRARY}) 247 | if(BLACS_LIBRARY) 248 | list(APPEND SCALAPACK_LIBRARIES ${BLACS_LIBRARY}) 249 | endif() 250 | if(SCALAPACK_MPI_LIB64) 251 | list(APPEND SCALAPACK_LIBRARIES ${SCALAPACK_MPI_LIB64}) 252 | endif() 253 | 254 | set(SCALAPACK_INCLUDE_DIRS ${SCALAPACK_INCLUDE_DIR}) 255 | 256 | if(NOT TARGET SCALAPACK::SCALAPACK) 257 | add_library(SCALAPACK::SCALAPACK INTERFACE IMPORTED) 258 | set_property(TARGET SCALAPACK::SCALAPACK PROPERTY INTERFACE_LINK_LIBRARIES "${SCALAPACK_LIBRARIES}") 259 | set_property(TARGET SCALAPACK::SCALAPACK PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${SCALAPACK_INCLUDE_DIR}") 260 | endif() 261 | endif() 262 | 263 | mark_as_advanced(SCALAPACK_LIBRARY SCALAPACK_INCLUDE_DIR) 264 | -------------------------------------------------------------------------------- /cmake/FindScotch.cmake: -------------------------------------------------------------------------------- 1 | ### 2 | # 3 | # @copyright (c) 2009-2014 The University of Tennessee and The University 4 | # of Tennessee Research Foundation. 5 | # All rights reserved. 6 | # @copyright (c) 2012-2014 Inria. All rights reserved. 7 | # @copyright (c) 2012-2014 Bordeaux INP, CNRS (LaBRI UMR 5800), Inria, Univ. Bordeaux. All rights reserved. 8 | # 9 | ### 10 | # 11 | # - Find Scotch include dirs and libraries 12 | # Use this module by invoking find_package with the form: 13 | # find_package(Scotch 14 | # [REQUIRED] # Fail with error if scotch is not found 15 | # [COMPONENTS ...] # dependencies 16 | # ) 17 | # 18 | # COMPONENTS: 19 | # 20 | # * ESMUMPS: detect Scotch esmumps interface 21 | # * parallel: detect parallel (MPI) Scotch 22 | # 23 | # This module finds headers and scotch library. 24 | # Results are reported in variables: 25 | # Scotch_FOUND - True if headers and requested libraries were found 26 | # Scotch_INCLUDE_DIRS - scotch include directories 27 | # Scotch_LIBRARIES - scotch component libraries to be linked 28 | # 29 | # Imported Targets 30 | # ^^^^^^^^^^^^^^^^ 31 | # 32 | # Scotch::Scotch 33 | # 34 | #============================================================================= 35 | # Copyright 2012-2013 Inria 36 | # Copyright 2012-2013 Emmanuel Agullo 37 | # Copyright 2012-2013 Mathieu Faverge 38 | # Copyright 2012 Cedric Castagnede 39 | # Copyright 2013 Florent Pruvost 40 | # (C) 2018 Michael Hirsch 41 | # 42 | # Distributed under the OSI-approved BSD License (the "License"); 43 | # see accompanying file MORSE-Copyright.txt for details. 44 | # 45 | # This software is distributed WITHOUT ANY WARRANTY; without even the 46 | # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 47 | # See the License for more information. 48 | #============================================================================= 49 | 50 | set(Scotch_LIBRARIES) 51 | 52 | find_path(Scotch_INCLUDE_DIR 53 | NAMES scotch.h 54 | PATH_SUFFIXES scotch openmpi openmpi-x86_64 mpich-x86_64 55 | ) 56 | 57 | # need plain scotch when using ptscotch 58 | set(scotch_names scotch scotcherr) 59 | if(ESMUMPS IN_LIST Scotch_FIND_COMPONENTS) 60 | list(INSERT scotch_names 0 esmumps) 61 | endif() 62 | 63 | if(parallel IN_LIST Scotch_FIND_COMPONENTS) 64 | list(INSERT scotch_names 0 ptscotch ptscotcherr) 65 | if(ESMUMPS IN_LIST Scotch_FIND_COMPONENTS) 66 | list(INSERT scotch_names 0 ptesmumps) 67 | endif() 68 | endif() 69 | 70 | foreach(l IN LISTS scotch_names) 71 | find_library(Scotch_${l}_LIBRARY 72 | NAMES ${l} 73 | PATH_SUFFIXES openmpi/lib mpich/lib 74 | ) 75 | 76 | list(APPEND Scotch_LIBRARIES ${Scotch_${l}_LIBRARY}) 77 | mark_as_advanced(Scotch_${l}_LIBRARY) 78 | endforeach() 79 | 80 | if(parallel IN_LIST Scotch_FIND_COMPONENTS) 81 | if(Scotch_ptesmumps_LIBRARY AND Scotch_ptscotch_LIBRARY) 82 | set(Scotch_ESMUMPS_FOUND true) 83 | set(Scotch_parallel_FOUND true) 84 | endif() 85 | elseif(Scotch_esmumps_LIBRARY) 86 | set(Scotch_ESMUMPS_FOUND true) 87 | endif() 88 | 89 | include(FindPackageHandleStandardArgs) 90 | find_package_handle_standard_args(Scotch 91 | REQUIRED_VARS Scotch_LIBRARIES Scotch_INCLUDE_DIR 92 | HANDLE_COMPONENTS 93 | ) 94 | 95 | if(Scotch_FOUND) 96 | set(Scotch_INCLUDE_DIRS ${Scotch_INCLUDE_DIR}) 97 | 98 | if(NOT TARGET Scotch::Scotch) 99 | add_library(Scotch::Scotch INTERFACE IMPORTED) 100 | set_property(TARGET Scotch::Scotch PROPERTY INTERFACE_LINK_LIBRARIES "${Scotch_LIBRARIES}") 101 | set_property(TARGET Scotch::Scotch PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${Scotch_INCLUDE_DIR}") 102 | endif() 103 | endif(Scotch_FOUND) 104 | 105 | mark_as_advanced(Scotch_INCLUDE_DIR) 106 | -------------------------------------------------------------------------------- /cmake/options.cmake: -------------------------------------------------------------------------------- 1 | set(CMAKE_TLS_VERIFY true) 2 | 3 | 4 | list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}) 5 | 6 | # Rpath options necessary for shared library install to work correctly in user projects 7 | set(CMAKE_INSTALL_NAME_DIR ${CMAKE_INSTALL_PREFIX}/lib) 8 | set(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/lib) 9 | set(CMAKE_INSTALL_RPATH_USE_LINK_PATH true) 10 | 11 | # Necessary for shared library with Visual Studio / Windows oneAPI 12 | set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS true) 13 | 14 | 15 | if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) 16 | # will not take effect without FORCE 17 | # CMAKE_BINARY_DIR for use from FetchContent 18 | set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR} CACHE PATH "Install top-level directory" FORCE) 19 | endif() 20 | 21 | 22 | # --- auto-ignore build directory 23 | if(NOT EXISTS ${PROJECT_BINARY_DIR}/.gitignore) 24 | file(WRITE ${PROJECT_BINARY_DIR}/.gitignore "*") 25 | endif() 26 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | if(METIS_FOUND) 2 | add_executable(metis_demo metis.f90) 3 | target_link_libraries(metis_demo PRIVATE METIS::METIS) 4 | add_test(NAME Metis COMMAND metis_demo) 5 | endif() 6 | 7 | if(MUMPS_FOUND) 8 | add_executable(testmumps test_mumps.f90) 9 | target_link_libraries(testmumps PRIVATE MUMPS::MUMPS SCALAPACK::SCALAPACK LAPACK::LAPACK MPI::MPI_Fortran) 10 | 11 | add_test(NAME MUMPS 12 | COMMAND ${MPIEXEC_EXECUTABLE} ${MPIEXEC_NUMPROC_FLAG} ${MPIEXEC_MAX_NUMPROCS} 13 | $ ${CMAKE_CURRENT_SOURCE_DIR}/input_simpletest_real 14 | ) 15 | endif() 16 | 17 | if("d" IN_LIST arith) 18 | add_executable(blacs_demo blacs_demo.f90) 19 | target_link_libraries(blacs_demo PRIVATE SCALAPACK::SCALAPACK LAPACK::LAPACK MPI::MPI_Fortran) 20 | add_test(NAME BLACS 21 | COMMAND ${MPIEXEC_EXECUTABLE} ${MPIEXEC_NUMPROC_FLAG} ${MPIEXEC_MAX_NUMPROCS} $ 22 | ) 23 | 24 | add_executable(scalapack_demo scalapack_demo.f90) 25 | target_link_libraries(scalapack_demo PRIVATE SCALAPACK::SCALAPACK LAPACK::LAPACK MPI::MPI_Fortran) 26 | add_test(NAME Scalapack 27 | COMMAND ${MPIEXEC_EXECUTABLE} ${MPIEXEC_NUMPROC_FLAG} ${MPIEXEC_MAX_NUMPROCS} $ 28 | ) 29 | endif() 30 | 31 | get_property(_test_names DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY TESTS) 32 | 33 | set_tests_properties(${_test_names} PROPERTIES 34 | RESOURCE_LOCK cpu_mpi 35 | TIMEOUT 15 36 | ) 37 | 38 | if(WIN32 AND CMAKE_VERSION VERSION_GREATER_EQUAL 3.22) 39 | get_target_property(lib SCALAPACK::SCALAPACK INTERFACE_LINK_LIBRARIES) 40 | if(lib) 41 | list(GET lib 0 lib) 42 | cmake_path(GET lib PARENT_PATH libdir) 43 | cmake_path(SET dlldir NORMALIZE ${libdir}/../bin) 44 | if(IS_DIRECTORY ${dlldir}) 45 | set_tests_properties(${_test_names} PROPERTIES 46 | ENVIRONMENT_MODIFICATION PATH=path_list_append:${dlldir} 47 | ) 48 | endif() 49 | endif() 50 | endif() 51 | 52 | 53 | # --- pardiso 54 | 55 | include(CheckSourceCompiles) 56 | 57 | set(CMAKE_REQUIRED_INCLUDES ${SCALAPACK_INCLUDE_DIRS}) 58 | set(CMAKE_REQUIRED_LIBRARIES ${SCALPACK_LIBRARIES} ${LAPACK_LIBRARIES}) 59 | 60 | check_source_compiles(Fortran 61 | "program par 62 | implicit none (type, external) 63 | external :: pardisoinit, pardiso 64 | 65 | call pardisoinit() 66 | end program" 67 | HAVE_PARDISO 68 | ) 69 | 70 | if(HAVE_PARDISO) 71 | add_executable(pardiso_basic pardiso_basic.f90) 72 | target_link_libraries(pardiso_basic PRIVATE SCALAPACK::SCALAPACK LAPACK::LAPACK) 73 | add_test(NAME pardisoBasic COMMAND pardiso_basic) 74 | endif() 75 | -------------------------------------------------------------------------------- /src/blacs_demo.f90: -------------------------------------------------------------------------------- 1 | program blacs_demo 2 | !! minimal Blacs demo 3 | use, intrinsic :: iso_fortran_env, only : real64 4 | implicit none (type, external) 5 | 6 | integer :: ictxt, myid, nprocs, mycol, myrow, npcol, nprow 7 | real(real64) :: eps 8 | real(real64), external :: dlamch 9 | external :: blacs_pinfo, blacs_get, blacs_gridinit, blacs_gridinfo, blacs_gridexit, blacs_exit 10 | 11 | !! arbitrary test parameters 12 | npcol = 2 13 | nprow = 2 14 | 15 | call blacs_pinfo(myid, nprocs) 16 | call blacs_get(-1, 0, ictxt) 17 | call blacs_gridinit(ictxt, 'C', nprocs, 1) 18 | 19 | call blacs_gridinfo(ictxt, nprow, npcol, myrow, mycol) 20 | 21 | eps = dlamch('E') 22 | 23 | if(myrow == mycol) print '(A, F10.6)', "OK: BLACS Fortran eps=", eps 24 | 25 | call blacs_gridexit(ictxt) 26 | call blacs_exit(0) 27 | 28 | end program 29 | -------------------------------------------------------------------------------- /src/input_simpletest_real: -------------------------------------------------------------------------------- 1 | 5 :N 2 | 12 :NZ 3 | 1 2 3.0 4 | 2 3 -3.0 5 | 4 3 2.0 6 | 5 5 1.0 7 | 2 1 3.0 8 | 1 1 2.0 9 | 5 2 4.0 10 | 3 4 2.0 11 | 2 5 6.0 12 | 3 2 -1.0 13 | 1 3 4.0 14 | 3 3 1.0 :values 15 | 20.0 16 | 24.0 17 | 9.0 18 | 6.0 19 | 13.0 :RHS 20 | -------------------------------------------------------------------------------- /src/metis.f90: -------------------------------------------------------------------------------- 1 | !! https://people.math.sc.edu/Burkardt/f_src/metis_test/metis_test.f90 2 | ! GNU LGPL license. Author: John Burkardt 3 | 4 | program test_metis 5 | 6 | implicit none (type, external) 7 | 8 | integer, parameter :: nvtxs=6, nedges=7, ncon=1, nparts =2 9 | integer :: xadj(nvtxs+1), adjncy(2*nedges), part(nvtxs), j, objval, refpart(nvtxs), adjwgt(2*nedges) 10 | integer :: options(40) 11 | integer, dimension(nvtxs) :: vwgt, vsize 12 | real :: tpwgts(nparts*ncon), ubvec(ncon) 13 | 14 | external :: METIS_SetDefaultOptions, METIS_PartGraphKway 15 | 16 | call METIS_SetDefaultOptions(options) 17 | 18 | options = 0 19 | options(7) = 10 20 | options(8) = 1 21 | options(16) = 1 22 | options(17) = 30 23 | 24 | ubvec = 1.001 25 | tpwgts = 0.5 26 | 27 | vwgt = 1 28 | vsize = 1 29 | adjwgt = 1 30 | 31 | xadj=[0, 2, 5, 7, 9, 12, 14] 32 | adjncy=[1,3,0,4,2,1,5,0,4,3,1,5,4,2] 33 | 34 | call METIS_PartGraphKway(nvtxs, ncon, xadj, adjncy, vwgt, vsize, adjwgt, nparts, tpwgts, ubvec, options, objval, part) 35 | 36 | print '(15I3)', part 37 | 38 | refpart = [1,1,0,1,0,0] 39 | 40 | if(any(part /= refpart)) error stop 'metis failed to order' 41 | 42 | end program 43 | -------------------------------------------------------------------------------- /src/pardiso_basic.f90: -------------------------------------------------------------------------------- 1 | program pardiso_basic 2 | !! https://software.intel.com/en-us/mkl-developer-reference-fortran-intel-mkl-pardiso-parameters-in-tabular-form 3 | 4 | use, intrinsic :: iso_fortran_env, only: int64, dp=>real64, stderr=>error_unit 5 | 6 | implicit none (type, external) 7 | 8 | integer(int64) :: pt(64) 9 | integer :: maxfct, mnum, mtype, phase, n, nrhs, error, msglvl 10 | integer :: iparm(64) 11 | integer :: ia(9), ja(18) 12 | real(dp) :: dparm (64), a(18), b(8), x(8), y(8) 13 | integer :: i, j, idum, solver 14 | real(dp) :: waltime1, waltime2, ddum, normb, normr 15 | 16 | external :: pardisoinit, pardiso 17 | 18 | pt = 0 19 | iparm = 0 20 | 21 | !! example 22 | maxfct = 1 23 | mnum = 1 24 | n = 8 25 | nrhs = 1 26 | mtype = -2 ! real, symmetric, indefinite 27 | solver = 10 ! use sparse direct method 28 | msglvl = 1 29 | 30 | 31 | !! sparse example matrix 32 | ia = [1,5,8,10,12,15,17,18,19] 33 | 34 | ja = [& 35 | 1, 3, 6, 7, & 36 | 2, 3, 5, & 37 | 3, 8, & 38 | 4, 7, & 39 | 5, 6, 7, & 40 | 6, 8, & 41 | 7, & 42 | 8] 43 | 44 | a = [& 45 | 7._dp, 1._dp, 2._dp, 7._dp, & 46 | -4._dp, 8._dp, 2._dp, & 47 | 1._dp, 5._dp, & 48 | 7._dp, 9._dp, & 49 | 5._dp, -1._dp, 5._dp, & 50 | 0._dp, 5._dp, & 51 | 11._dp, & 52 | 5._dp] 53 | 54 | !! example rhs 55 | do i = 1, n 56 | b(i) = i 57 | end do 58 | 59 | ! ------------------------------------- 60 | !! https://software.intel.com/en-us/mkl-developer-reference-fortran-pardiso 61 | 62 | !! initialize pardiso 63 | call pardisoinit(pt, mtype, iparm) 64 | 65 | !! analysis 66 | phase = 11 67 | call pardiso(pt, maxfct, mnum, mtype, phase, n, a, ia, ja, & 68 | idum, nrhs, iparm, msglvl, ddum, ddum, error, dparm) 69 | 70 | if (error /= 0) then 71 | write(stderr,*) 'ERROR: pardiso reordering: code ',error 72 | error stop 73 | endif 74 | 75 | !! factorization 76 | phase = 22 77 | call pardiso(pt, maxfct, mnum, mtype, phase, n, a, ia, ja, & 78 | idum, nrhs, iparm, msglvl, ddum, ddum, error, dparm) 79 | 80 | if (error /= 0) then 81 | write(stderr,*) 'ERROR: pardiso factoring: code ',error 82 | error stop 83 | endif 84 | 85 | if (iparm(33) == 1) print *,'log(determinant) = ',dparm 86 | 87 | !! deallocate internal memory 88 | phase = -1 89 | call pardiso(pt, maxfct, mnum, mtype, phase, n, a, ia, ja, & 90 | idum, nrhs, iparm, msglvl, ddum, ddum, error, dparm) 91 | 92 | end program 93 | -------------------------------------------------------------------------------- /src/scalapack_demo.f90: -------------------------------------------------------------------------------- 1 | ! minimal Scalapack demo 2 | program test_scalapack 3 | 4 | use, intrinsic :: iso_fortran_env, only : real64 5 | 6 | implicit none (type, external) 7 | 8 | integer :: ictxt, myid, nprocs, mycol, myrow, npcol, nprow 9 | real(real64) :: eps 10 | 11 | real(real64), external :: pdlamch 12 | external :: blacs_pinfo, blacs_get, blacs_gridinit, blacs_gridinfo, blacs_gridexit, blacs_exit 13 | 14 | ! arbitrary test parameters 15 | npcol = 2 16 | nprow = 2 17 | 18 | call blacs_pinfo(myid, nprocs) 19 | call blacs_get(-1, 0, ictxt) 20 | call blacs_gridinit(ictxt, "C", nprocs, 1) 21 | 22 | call blacs_gridinfo(ictxt, nprow, npcol, myrow, mycol) 23 | 24 | eps = pdlamch(ictxt, 'E') 25 | 26 | if(myrow == mycol) print '(A, F10.6)', "OK: Scalapack Fortran eps=", eps 27 | 28 | call blacs_gridexit(ictxt) 29 | call blacs_exit(0) 30 | 31 | end program 32 | -------------------------------------------------------------------------------- /src/test_mpi.f90: -------------------------------------------------------------------------------- 1 | program mpiTypes 2 | use, intrinsic :: iso_fortran_env 3 | use mpi 4 | 5 | implicit none 6 | 7 | integer :: ierr, mrank, msize, vlen 8 | character(MPI_MAX_LIBRARY_VERSION_STRING) :: version ! allocatable not ok 9 | 10 | print *,compiler_version() 11 | 12 | call MPI_INIT(ierr) 13 | call MPI_COMM_RANK(MPI_COMM_WORLD, mrank, ierr) 14 | call MPI_COMM_SIZE(MPI_COMM_WORLD, msize, ierr) 15 | call MPI_GET_LIBRARY_VERSION(version, vlen, ierr) 16 | 17 | call MPI_FINALIZE() 18 | 19 | print '(A,I3,A,I3,A)', 'Image ', mrank, ' / ', msize, ':',version 20 | 21 | print '(A25,A7)','type','value' 22 | print '(A25,I4)','mpi_real',mpi_real 23 | print '(A25,I4)','mpi_real8',mpi_real8 24 | 25 | end program 26 | -------------------------------------------------------------------------------- /src/test_mumps.f90: -------------------------------------------------------------------------------- 1 | program test_mumps 2 | !! Based on MUMPS manual Sec 11.1 3 | use mpi, only: mpi_init, mpi_comm_world 4 | use, intrinsic :: iso_fortran_env, only: stderr=>error_unit, stdout=>output_unit, i64=>int64 5 | 6 | IMPLICIT NONE (type, external) 7 | 8 | external :: mpi_finalize, dmumps 9 | 10 | INCLUDE 'dmumps_struc.h' 11 | TYPE (DMUMPS_STRUC) :: mumps_par 12 | 13 | integer :: ierr 14 | 15 | CALL MPI_INIT(ierr) 16 | if (ierr /= 0) error stop 'mpi init error' 17 | !> Define a communicator for the package. 18 | mumps_par%COMM = MPI_COMM_WORLD !mpi_val 19 | 20 | !> Initialize an instance of the package for L U factorization (sym = 0, with working host) 21 | mumps_par%SYM = 0 22 | !! A is unsymmetric Sec. 5.2.1 page 24 23 | 24 | mumps_par%PAR = 1 25 | !! use host to compute too Sec 5.1.3 page 23 26 | 27 | mumps_par%JOB = -1 28 | !! Initializes all variables, set job parameters first. Sec 5.1, page 22 29 | 30 | !> set verbosities AFTER %JOB call or they get reset! 31 | mumps_par%ICNTL(1) = stderr 32 | !! error msg stream 33 | 34 | mumps_par%ICNTL(2) = stdout 35 | !! warning msg stream 36 | 37 | mumps_par%ICNTL(4) = 1 38 | !! only error messags 39 | 40 | call simple_test(mumps_par) 41 | 42 | CALL MPI_FINALIZE(ierr) 43 | 44 | contains 45 | 46 | 47 | subroutine simple_test(mumps_par) 48 | 49 | TYPE (DMUMPS_STRUC), intent(inout) :: mumps_par 50 | 51 | call mumps_run(mumps_par) 52 | !! update MUMPS with user parameters 53 | 54 | 55 | call read_input(mumps_par) 56 | !! Define problem on the host (processor 0) 57 | 58 | !> Call package for solution 59 | mumps_par%JOB = 6 60 | call mumps_run(mumps_par) 61 | 62 | !> Solution has been assembled on the host 63 | IF ( mumps_par%MYID == 0 ) THEN 64 | print *, ' Solution is ' 65 | print '(5F7.3)', mumps_par%RHS 66 | 67 | !> Deallocate user data 68 | DEALLOCATE( mumps_par%IRN ) 69 | DEALLOCATE( mumps_par%JCN ) 70 | DEALLOCATE( mumps_par%A ) 71 | DEALLOCATE( mumps_par%RHS ) 72 | END IF 73 | 74 | !> Destroy the instance (deallocate internal data structures) 75 | mumps_par%JOB = -2 76 | call mumps_run(mumps_par) 77 | 78 | end subroutine simple_test 79 | 80 | 81 | subroutine read_input(mumps_par) 82 | 83 | type(dmumps_struc), intent(inout) :: mumps_par 84 | integer :: i, u 85 | INTEGER(i64) :: I8 86 | character(2048) :: argv 87 | 88 | IF ( mumps_par%MYID == 0 ) THEN 89 | 90 | call get_command_argument(1,argv,status=i) 91 | if(i/=0) error stop 'please specify filename with mumps test data' 92 | 93 | open(newunit=u, file=argv, form='formatted', status='old', action='read') 94 | READ(u,*) mumps_par%N 95 | READ(u,*) mumps_par%NNZ 96 | ALLOCATE( mumps_par%IRN ( mumps_par%NNZ ) ) 97 | ALLOCATE( mumps_par%JCN ( mumps_par%NNZ ) ) 98 | ALLOCATE( mumps_par%A( mumps_par%NNZ ) ) 99 | ALLOCATE( mumps_par%RHS ( mumps_par%N ) ) 100 | DO I8 = 1, mumps_par%NNZ 101 | READ(u,*) mumps_par%IRN(I8),mumps_par%JCN(I8), mumps_par%A(I8) 102 | END DO 103 | DO I = 1, mumps_par%N 104 | READ(u,*) mumps_par%RHS(I) 105 | END DO 106 | close(u) 107 | 108 | END IF 109 | 110 | end subroutine read_input 111 | 112 | 113 | subroutine mumps_run(mumps_par) 114 | 115 | type(dmumps_struc), intent(inout) :: mumps_par 116 | 117 | CALL DMUMPS(mumps_par) 118 | 119 | IF(mumps_par%INFOG(1) < 0) THEN 120 | WRITE(stderr,*) "ERROR: " 121 | write(stderr,'(A,I6,A,I9)')" mumps_par%INFOG(1)= ", mumps_par%INFOG(1), " mumps_par%INFOG(2)= ", mumps_par%INFOG(2) 122 | error stop 123 | elseiF(mumps_par%INFOG(1) > 0) THEN 124 | WRITE(stderr,*) "WARNING: " 125 | write(stderr,'(A,I6,A,I9)')" mumps_par%INFOG(1)= ", mumps_par%INFOG(1), " mumps_par%INFOG(2)= ", mumps_par%INFOG(2) 126 | END IF 127 | 128 | end subroutine mumps_run 129 | 130 | end program 131 | --------------------------------------------------------------------------------