###########################################################
#
# MAIN CMAKE FILE FOR OPTIM 
# 
# Usage: 
#   $ mkdir ~/svn/OPTIM/builds/pgf90
#   $ cd ~/svn/OPTIM/builds/pgf90
#   $ FC=pgf90 cmake ../../source 
#   $ make -j8
#
############################################################

cmake_minimum_required(VERSION 2.8)

if (CMAKE_CURRENT_SOURCE_DIR MATCHES "^${CMAKE_BINARY_DIRECTORY}$")
  message( FATAL_ERROR "CMake should not be built in the source directory" )
endif (CMAKE_CURRENT_SOURCE_DIR MATCHES "^${CMAKE_BINARY_DIRECTORY}$")

project(OPTIM)

set(PROJECT_VERSION "0.0")
set(PROJECT_CONTACT "dw34@cam.ac.uk")
get_filename_component(SVN_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../.. ABSOLUTE)

# Cmake modules/macros are in a subdirectory to keep this file cleaner
# CMake modules implement some additional functionality to check
# for external dependencies
set(CMAKE_MODULE_PATH ${SVN_ROOT}/CMakeModules)

# if not specified by user, the standard build type is release
if(NOT CMAKE_BUILD_TYPE)
  #Release comes with -O3 by default
  set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel." FORCE)
endif(NOT CMAKE_BUILD_TYPE)

enable_language(CXX)

# the FORTRANCOMPILER check is in svn/CMakeModules
# it adds a compiler switch and sets flags
find_package(FORTRANCOMPILER)
find_package(MYBLAS)
find_package(MYLAPACK)

message("CMAKE_Fortran_COMPILER = ${CMAKE_Fortran_COMPILER}")
set(CMAKE_Fortran_MODULE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/modules)
include_directories(${CMAKE_CURRENT_BINARY_DIR}/modules)

include_directories(${CMAKE_SOURCE_DIR})

file(GLOB DUMMY_AMH amhdummy_cmake.f)
file(GLOB DUMMY_CHARMM chdummy.f)
file(GLOB DUMMY_AMBER9 amber9dummy.f90)
file(GLOB DUMMY_USERPOT dummy_userpot.f90)
file(GLOB DUMMY_UNRES unresdummy.f)
file(GLOB DUMMY_DLF dlfdummy.f90)

file(GLOB OPTIM_MAIN getparams.f)
file(GLOB OPTIM_SOURCES *.f *.f90 *.F *.F90 ./AMH/amhglobals.f ./AMH/amh_interfaces.f90 ./AMH/E_write.f90
NEB/*.f90 CONNECT/*.f90 float.c)

# Due to a compiler bug in ifort 13.1.3, we can't use -O3 for genrigid.f90
# Investigations continue...
if( ${COMPILER_SWITCH} STREQUAL "ifort" )
  SET_SOURCE_FILES_PROPERTIES( genrigid.f90 PROPERTIES COMPILE_FLAGS -O2 )
endif ( ${COMPILER_SWITCH} STREQUAL "ifort" )

file(GLOB NOT_OPTIM_SOURCES
  getparams.f  # main program will be added separately
  diis.f dsygvx.f editit.h2o.f
  gdiis.f90 makexyz.f
#  myblas.f mylapack.f 
  amber.f amhdummy.f # amberdummy.f
# just in case of a in place build or old files
  OPTIM.f porfuncs.f90 header.f90
# build sepearately 
  dummy_userpot.f90
  optim_quip_wrapper.f90
)

list(REMOVE_ITEM OPTIM_SOURCES ${NOT_OPTIM_SOURCES} ${DUMMY_AMH}
${DUMMY_CHARMM} ${DUMMY_AMBER9} ${DUMMY_UNRES} ${DUMMY_DLF})

 

# ---- add generated source files 
set(OPTIM_SOURCES ${OPTIM_SOURCES} header.f90 porfuncs.f90)
set(ALL_EXTRA_SOURCES ${OPTIM_MAIN} ${DUMMY_CHARMM} ${DUMMY_AMH} ${DUMMY_AMBER9} ${DUMMY_USERPOT} ${DUMMY_UNRES} ${DUMMY_DLF})

# ---- porfuncs.f90 TODO: should it build every time?
add_custom_command (
   OUTPUT porfuncs.f90 
   COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/porfuncs.sh ${COMPILER_SWITCH} > porfuncs.f90)
set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES porfuncs.f90)

add_custom_command (
   OUTPUT header.f90 
   COMMAND sh ${CMAKE_CURRENT_SOURCE_DIR}/header.sh > header.f90
   )
set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES header.f90)

# ----- Libraries 
# ----- generate an OPTIM library to avoid recompiling the whole code for every executable


add_library(optimlib ${OPTIM_SOURCES})

add_subdirectory(Bowman)

# --- Finally, the execs

# standard OPTIM
add_executable(OPTIM ${ALL_EXTRA_SOURCES})
target_link_libraries(OPTIM optimlib ${MYLAPACK_LIBS} ${BOWMAN_LIBS})

# # AMHOPTIM
option(WITH_AMH "Enable AMHOPTIM compilation" OFF)
if(WITH_AMH)
  SET(EXTRA_SOURCES ${ALL_EXTRA_SOURCES})
  list(REMOVE_ITEM EXTRA_SOURCES ${DUMMY_AMH})
  add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/AMH)
  add_executable(AMHOPTIM ${EXTRA_SOURCES})
  target_link_libraries(AMHOPTIM optimlib amh ${MYLAPACK_LIBS} ${BOWMAN_LIBS})
endif(WITH_AMH)

# 
# # A9OPTIM
option(WITH_AMBER9 "Enable A9OPTIM compilation" OFF)
if(WITH_AMBER9)
  SET(EXTRA_SOURCES ${ALL_EXTRA_SOURCES})
  list(REMOVE_ITEM EXTRA_SOURCES ${DUMMY_AMBER9})
  find_package(NAB)
  add_subdirectory(AMBER) # temporary folder to copy files from sander;  # TODO: make this folder hidden or consider moving sander files locally 
  add_executable(A9OPTIM ${EXTRA_SOURCES})
  target_link_libraries(A9OPTIM optimlib AMBER_LIB NAB_LIB ${MYLAPACK_LIBS} ${BOWMAN_LIBS})
  #add_dependencies(A9OPTIM nab_build)
endif(WITH_AMBER9)

#SPIN
option(WITH_SPIN "Enable SPINOPTIM compilation" OFF)
if(WITH_SPIN)
  SET(EXTRA_SOURCES ${ALL_EXTRA_SOURCES})
  list(REMOVE_ITEM EXTRA_SOURCES ${DUMMY_USERPOT})
  add_subdirectory(SPINinterface)
  add_executable(SPINOPTIM ${EXTRA_SOURCES})
  target_link_libraries(SPINOPTIM optimlib SPIN ${MYLAPACK_LIBS} ${BOWMAN_LIBS})
endif(WITH_SPIN)

option(WITH_PLUGIN "Enable shared library plugin support" OFF)
if(WITH_PLUGIN)
  SET(EXTRA_SOURCES ${ALL_EXTRA_SOURCES})
  list(REMOVE_ITEM EXTRA_SOURCES ${DUMMY_USERPOT})
  SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
  SET(CMAKE_SHARED_LIBRARY_LINK_Fortran_FLAGS "")
  add_subdirectory(pluginloader)
  add_executable(PLOPTIM ${EXTRA_SOURCES})
  target_link_libraries(PLOPTIM optimlib pluginloader ${MYLAPACK_LIBS} ${BOWMAN_LIBS})
endif(WITH_PLUGIN)

option(WITH_CPPNEB "Build with new C++ nudged elastic band support" OFF)
if(WITH_CPPNEB)
  add_subdirectory(cppneb)
  add_executable(OPTIM_CPPNEB ${ALL_EXTRA_SOURCES})
  target_link_libraries(OPTIM_CPPNEB optimlib cppneb ${MYLAPACK_LIBS} ${BOWMAN_LIBS})
endif(WITH_CPPNEB)

option(WITH_CHARMM35 "Enable C35OPTIM compilation" OFF)
if(WITH_CHARMM35)
  if(WITH_CHARMM36)
    message( FATAL_ERROR "cannot build CHARMM35 and CHARMM36 at the same time")
  endif(WITH_CHARMM36)
  SET(EXTRA_SOURCES ${ALL_EXTRA_SOURCES})
  list(REMOVE_ITEM EXTRA_SOURCES ${DUMMY_CHARMM})
  add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/CHARMMinterface)
  add_executable(C35OPTIM myblas.f mylapack.f ${EXTRA_SOURCES})
  # add the CHARMM library as a dependency
  add_dependencies(C35OPTIM CHARMM_WAS_BUILT)
  # Link in the CHARMM libraries and the CHARMM35 OPTIM interface
  target_link_libraries(C35OPTIM optimlib mylapack myblascharmm charmm35_interface_lib ${CHARMM_LIBS} ${BOWMAN_LIBS})
endif(WITH_CHARMM35)

option(WITH_CHARMM36 "Enable C36OPTIM compilation" OFF)
if(WITH_CHARMM36)
  if(WITH_CHARMM35)
    message( FATAL_ERROR "cannot build CHARMM35 and CHARMM36 at the same
time")
  endif(WITH_CHARMM35)
  SET(EXTRA_SOURCES ${ALL_EXTRA_SOURCES})
  list(REMOVE_ITEM EXTRA_SOURCES ${DUMMY_CHARMM})
  add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/CHARMMinterface)
  add_executable(C36OPTIM myblas.f mylapack.f ${EXTRA_SOURCES})
  # add the CHARMM library as a dependency
  add_dependencies(C36OPTIM CHARMM_WAS_BUILT)
  # Link in the CHARMM libraries and the CHARMM36 OPTIM interface
  target_link_libraries(C36OPTIM optimlib mylapack myblascharmm
charmm36_interface_lib ${CHARMM_LIBS} ${BOWMAN_LIBS})
endif(WITH_CHARMM36)

option(WITH_DLF "Enable DLFOPTIM compilation" OFF)
if(WITH_DLF)
  SET(EXTRA_SOURCES ${ALL_EXTRA_SOURCES})
  list(REMOVE_ITEM EXTRA_SOURCES ${DUMMY_DLF})
  add_subdirectory(DLFWrapper)
  add_executable(DLFOPTIM ${EXTRA_SOURCES})
  target_link_libraries(DLFOPTIM optimlib ${MYLAPACK_LIBS} ${BOWMAN_LIBS} DLF_LIB)
endif(WITH_DLF)



# Unres interface here for possible future reference. NOT to be routinely used
#option(WITH_UNRES "Enable UNOPTIM compilation" OFF)
#if(WITH_UNRES)
#  SET(EXTRA_SOURCES ${ALL_EXTRA_SOURCES})
#  list(REMOVE_ITEM EXTRA_SOURCES ${DUMMY_UNRES})
#  add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/UNRESinterface)
#  add_executable(UNOPTIM ${EXTRA_SOURCES})
#  target_link_libraries(UNOPTIM optimlib ${MYLAPACK_LIBS} unresinterface, ${BOWMAN_LIBS})
#endif(WITH_UNRES)


# Test for duplicates.
# In the standard build we first merge the object files together in a library
# (gminlib) to avoid duplicate compilation for multiple targets.  A
# drawback of this is that duplicate symbols (duplicate names of subroutines,
# functions, etc.) are simply ignored.  This is a separate target which builds
# GMIN directly from the sources, specifically to check for duplicate
# symbols.
option(WITH_DUPLICATE_TESTING "Compile OPTIM in such a way that duplicate symbols are flagged" OFF)
if(WITH_DUPLICATE_TESTING)
  add_executable(OPTIM_TEST_DUPLICATES ${OPTIM_SOURCES} ${ALL_EXTRA_SOURCES})
  target_link_libraries(OPTIM_TEST_DUPLICATES ${MYLAPACK_LIBS} ${BOWMAN_LIBS})
endif(WITH_DUPLICATE_TESTING)
