# CMake script for finding MKL for Elmer (dynamic linking, Fortran)
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)

IF (WITH_MPI)
  SET(SCALAPACK_NEEDED TRUE)
ELSE()
  SET(SCALAPACK_NEEDED FALSE)
ENDIF()
IF (WITH_OpenMP)
  SET(THREADS_NEEDED TRUE)
ELSE()
  SET(THREADS_NEEDED FALSE)
ENDIF()


# If MKL_LIBRARIES libraries are already defined, do nothing
IF(MKL_BLAS_LIBRARIES AND MKL_LAPACK_LIBRARIES
    AND MKL_Fortran_FLAGS)
  
  IF(NOT SCALAPACK_NEEDED OR 
         (SCALAPACK_NEEDED AND MKL_SCALAPACK_LIBRARIES))
    SET(MKL_FOUND TRUE)
    RETURN()
  ENDIF()
ENDIF()
SET(MKL_FOUND FALSE)

IF (NOT UNIX)
  IF (NOT MKL_FIND_QUIETLY)
    MESSAGE(STATUS "Manually specify:" "MKL_BLAS_LIBRARIES " 
      "MKL_LAPACK_LIBRARIES "
      "MKL_Fortran_FLAGS")
    IF(SCALAPACK_NEEDED)
      MESSAGE(STATUS "Manually specify:" "MKL_SCALAPACK_LIBRARIES")
    ENDIF()
    MESSAGE(FATAL_ERROR "Finding MKL libraries for Elmer not yet implemented for other platforms than Linux.")
  ELSE()
    SET(MKL_FOUND FALSE)
    RETURN()
  ENDIF()
ENDIF()

SET(MKLINCLUDE
  "$ENV{MKLROOT}/include"
  "${MKLROOT}/include"
  "$ENV{MKL_ROOT}/include"
  "${MKL_ROOT}/include"
  INTERNAL
  )

IF (CMAKE_SIZEOF_VOID_P MATCHES 8)
  SET(MKL_SUFFIX "_lp64")
  # 64-bit libraries
  SET(MKLLIB
    "$ENV{MKLROOT}/lib/intel64"
    "${MKLROOT}/lib/intel64"
    "$ENV{MKL_ROOT}/lib/intel64"
    "${MKL_ROOT}/lib/intel64"
    INTERNAL
    )
ELSE()
  SET(MKL_SUFFIX "")
  # 32-bit libraries
  SET(MKLLIB
    "$ENV{MKLROOT}/lib/ia32"
    "${MKLROOT}/lib/ia32"
    "$ENV{MKL_ROOT}/lib/ia32"
    "${MKL_ROOT}/lib/ia32"
    INTERNAL
    )
ENDIF()

# Set library names and compiler arguments
IF(${CMAKE_Fortran_COMPILER_ID} MATCHES "GNU")
  SET(MKL_BASENAME "gf")
  SET(MKL_THR_BASENAME "gnu")
  SET(MKL_Fortran_FLAGS "-Wl,--no-as-needed" CACHE STRING "MKL Fortran flags")
ELSEIF(${CMAKE_Fortran_COMPILER_ID} MATCHES "Intel")
 # Core libraries
 SET(MKL_BASENAME "intel")
 SET(MKL_THR_BASENAME "intel")
 SET(MKL_Fortran_FLAGS "" CACHE STRING "MKL Fortran flags")
ELSEIF(${CMAKE_Fortran_COMPILER_ID} MATCHES "PGI")
   # Core libraries
 SET(MKL_BASENAME "intel")
 SET(MKL_THR_BASENAME "pgi")
 SET(MKL_Fortran_FLAGS "" CACHE STRING "MKL Fortran flags")
ELSE()
  MESSAGE(FATAL_ERROR "Finding MKL libraries not implemented for 
                ${CMAKE_Fortran_COMPILER_ID}")
ENDIF()

# From MKL link line advisor
#GNU, seq  -Wl,--no-as-needed -L${MKLROOT}/lib/intel64 -lmkl_gf_lp64 -lmkl_core -lmkl_sequential -lpthread -lm
#GNU, mt  -Wl,--no-as-needed -L${MKLROOT}/lib/intel64 -lmkl_gf_lp64 -lmkl_core -lmkl_gnu_thread -ldl -lpthread -lm
#Intel, seq -L${MKLROOT}/lib/intel64 -lmkl_intel_lp64 -lmkl_core -lmkl_sequential -lpthread -lm
#Intel, mt -L${MKLROOT}/lib/intel64 -lmkl_intel_lp64 -lmkl_core -lmkl_intel_thread -lpthread -lm

# Core library
SET(MKL_CORE_LIB_NAME "mkl_core" INTERNAL)
SET(MKL_NUM_LIB_NAME "mkl_${MKL_BASENAME}${MKL_SUFFIX}" INTERNAL)
# Threading library
IF (THREADS_NEEDED)
  SET(MKL_THREAD_LIB_NAME "mkl_${MKL_THR_BASENAME}_thread" INTERNAL)
ELSE()
  SET(MKL_THREAD_LIB_NAME "mkl_sequential" INTERNAL)
ENDIF()
SET(MKL_PTHREAD_LIB_NAME "pthread" INTERNAL)
SET(MKL_M_LIB_NAME "m" INTERNAL)

# Find MKL include path
FIND_PATH(MKL_INCLUDE_DIR 
  mkl.h 
  HINTS 
  ${MKLINCLUDE}
  )

# Find MKL core, BLAS and LAPACK libraries
FIND_LIBRARY(MKL_CORE_LIB ${MKL_CORE_LIB_NAME} HINTS ${MKLLIB})
FIND_LIBRARY(MKL_NUM_LIB ${MKL_NUM_LIB_NAME} HINTS ${MKLLIB})
FIND_LIBRARY(MKL_THREAD_LIB ${MKL_THREAD_LIB_NAME} HINTS ${MKLLIB})
FIND_LIBRARY(MKL_PTHREAD_LIB ${MKL_PTHREAD_LIB_NAME} HINTS ${MKLLIB})
FIND_LIBRARY(MKL_M_LIB ${MKL_M_LIB_NAME} HINTS ${MKLLIB})

IF (MKL_INCLUDE_DIR AND MKL_CORE_LIB AND 
    MKL_NUM_LIB AND MKL_THREAD_LIB AND 
    MKL_PTHREAD_LIB AND MKL_M_LIB)
  UNSET(MKL_FAILMSG)
  # SET(MKL_FOUND TRUE)
  SET(MKL_BLAS_LIBRARIES ${MKL_NUM_LIB} 
                         ${MKL_THREAD_LIB}
			 ${MKL_CORE_LIB} 
                         ${MKL_PTHREAD_LIB}
                         ${MKL_M_LIB}  CACHE FILEPATH "MKL BLAS")
  SET(MKL_BLAS_LIBRARIES_FOUND TRUE)
  SET(MKL_LAPACK_LIBRARIES ${MKL_NUM_LIB} 
                           ${MKL_THREAD_LIB}
			   ${MKL_CORE_LIB} 
                           ${MKL_PTHREAD_LIB}
                           ${MKL_M_LIB}  CACHE FILEPATH "MKL LAPACK")
  SET(MKL_LAPACK_LIBRARIES_FOUND TRUE)
ELSE()
  SET(MKL_FAILMSG "MKL core libraries not found.")
ENDIF()

# Find BLACS and Scalapack
SET(MKL_CPARDISO_FOUND FALSE)
IF (SCALAPACK_NEEDED AND NOT MKL_FAILMSG)
  # From MKL link line advisor (for Intel MPI)
  # GNU, seq:  -Wl,--no-as-needed -L${MKLROOT}/lib/intel64 -lmkl_scalapack_lp64 -lmkl_gf_lp64 -lmkl_core -lmkl_sequential -lmkl_blacs_intelmpi_lp64 -lpthread -lm
  # GNU, mt:  -Wl,--no-as-needed -L${MKLROOT}/lib/intel64 -lmkl_scalapack_lp64 -lmkl_gf_lp64 -lmkl_core -lmkl_gnu_thread -lmkl_blacs_intelmpi_lp64 -ldl -lpthread -lm
  # Intel, seq:  -L${MKLROOT}/lib/intel64 -lmkl_scalapack_lp64 -lmkl_intel_lp64 -lmkl_core -lmkl_sequential -lmkl_blacs_intelmpi_lp64 -lpthread -lm
  # Intel, mt:  -L${MKLROOT}/lib/intel64 -lmkl_scalapack_lp64 -lmkl_intel_lp64 -lmkl_core -lmkl_intel_thread -lmkl_blacs_intelmpi_lp64 -lpthread -lm

  # Attempt to guess MPI vendor
  EXECUTE_PROCESS(COMMAND ${MPIEXEC} --version
    OUTPUT_VARIABLE MKL_MPI_VENDOR_OUTPUT
    ERROR_VARIABLE MKL_MPI_VENDOR_ERROR)

  IF ("${MKL_MPI_VENDOR_OUTPUT}" MATCHES "(Intel.* MPI)")
    SET(MKL_MPI_VENDOR_BASENAME "intelmpi")
  ELSEIF ("${MKL_MPI_VENDOR_OUTPUT}" MATCHES "(Open MPI)")
    SET(MKL_MPI_VENDOR_BASENAME "openmpi")
  ELSE()
    IF (NOT MKL_FIND_QUIETLY)
      MESSAGE(WARNING "Could not determine MPI library type, assuming MPICH compatible MPI library")
    ENDIF()
    SET(MKL_MPI_VENDOR_BASENAME "intelmpi")
  ENDIF()

  SET(MKL_BLACS_LIB_NAME "mkl_blacs_${MKL_MPI_VENDOR_BASENAME}${MKL_SUFFIX}")
  SET(MKL_SCALAPACK_LIB_NAME "mkl_scalapack${MKL_SUFFIX}")
  UNSET(MKL_MPI_VENDOR_BASENAME)

  FIND_LIBRARY(MKL_BLACS_LIB ${MKL_BLACS_LIB_NAME} HINTS ${MKLLIB})
  FIND_LIBRARY(MKL_SCALAPACK_LIB ${MKL_SCALAPACK_LIB_NAME} HINTS ${MKLLIB})

  IF (MKL_BLACS_LIB AND MKL_SCALAPACK_LIB)
    SET(MKL_SCALAPACK_LIBRARIES ${MKL_SCALAPACK_LIB}
                                ${MKL_NUM_LIB} 
                                ${MKL_THREAD_LIB}
                                ${MKL_CORE_LIB} 
				${MKL_BLACS_LIB}
				${MKL_PTHREAD_LIB}
                                ${MKL_M_LIB} CACHE FILEPATH "MKL SCALAPACK libraries")
    SET(MKL_SCALAPACK_LIBRARIES_FOUND TRUE)
    # Attempt to find Cluster PARDISO for OpenMP compilations
    IF(THREADS_NEEDED)
      EXECUTE_PROCESS(COMMAND ${CMAKE_NM} ${MKL_NUM_LIB}
	OUTPUT_VARIABLE MKL_CPARDISO_OUTPUT
        ERROR_VARIABLE MKL_CPARDISO_ERROR)
      STRING(FIND "${MKL_CPARDISO_OUTPUT}" "cluster_sparse_solver" 
        MKL_CPARDISO_STR)
      IF("${MKL_CPARDISO_STR}" GREATER "-1" AND
	  "${MKL_CPARDISO_ERROR}" STREQUAL "")
	SET(MKL_CPARDISO_FOUND TRUE)
      ENDIF()
      UNSET(MKL_CPARDISO_STR)
      UNSET(MKL_CPARDISO_OUTPUT)
      UNSET(MKL_CPARDISO_ERROR)
    ENDIF()
  ELSE()
    SET(MKL_FAILMSG "MKL BLACS and SCALAPACK libraries not found.")
  ENDIF()
  # Unset SCALAPACK library names
  UNSET(MKL_BLACS_LIB_NAME)
  UNSET(MKL_SCALAPACK_LIB_NAME)
ENDIF()

IF (NOT MKL_FAILMSG)
  SET(MKL_FOUND TRUE)
ENDIF()

# Unset hints and base MKL library names
UNSET(MKLINCLUDE)
UNSET(MKLLIB)
UNSET(MKL_BASENAME)
UNSET(MKL_THR_BASENAME)
UNSET(MKL_CORE_LIB_NAME)
UNSET(MKL_NUM_LIB_NAME)
UNSET(MKL_THREAD_LIB_NAME)
UNSET(MKL_PTHREAD_LIB_NAME)
UNSET(MKL_M_LIB_NAME)
UNSET(MKL_FAILMSG)

IF (MKL_FOUND)
  IF (NOT MKL_FIND_QUIETLY)
    MESSAGE(STATUS "A library with MKL API found.")
    MESSAGE(STATUS "MKL include dir: ${MKL_INCLUDE_DIR}")
    MESSAGE(STATUS "MKL Fortran flags: ${MKL_Fortran_FLAGS}")
    MESSAGE(STATUS "MKL BLAS libraries: ${MKL_BLAS_LIBRARIES}")
    MESSAGE(STATUS "MKL LAPACK libraries: ${MKL_LAPACK_LIBRARIES}")
    IF(SCALAPACK_NEEDED)
      MESSAGE(STATUS "MKL SCALAPACK libraries: ${MKL_SCALAPACK_LIBRARIES}")
    ENDIF()
    IF(MKL_CPARDISO_FOUND)
      MESSAGE(STATUS "MKL Cluster PARDISO found")
    ENDIF()
  ENDIF()
ELSE()
  IF (MKL_FIND_REQUIRED)
    MESSAGE(FATAL_ERROR ${MKL_FAILMSG})
  ENDIF()
ENDIF()

MARK_AS_ADVANCED(
  MKL_INCLUDE_DIR
  MKL_Fortran_FLAGS
  MKL_NUM_LIB
  MKL_CORE_LIB
  MKL_THREAD_LIB
  MKL_PTHREAD_LIB
  MKL_M_LIB
  MKL_BLACS_LIB
  MKL_SCALAPACK_LIB
  MKL_BLAS_LIBRARIES
  MKL_LAPACK_LIBRARIES
  MKL_SCALAPACK_LIBRARIES
  MKL_BLAS_LIBRARIES_FOUND
  MKL_LAPACK_LIBRARIES_FOUND
  MKL_SCALAPACK_LIBRARIES_FOUND
  MKL_CPARDISO_FOUND
  )
