diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index a034cf6d17..e9f9136398 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -194,7 +194,6 @@ endif() # "hard" dependencies between packages resulting # in an error instead of skipping over files pkg_depends(MLIAP SNAP) -pkg_depends(MLIAP PYTHON) pkg_depends(MPIIO MPI) pkg_depends(USER-ATC MANYBODY) pkg_depends(USER-LB MPI) diff --git a/cmake/Modules/FindCythonize.cmake b/cmake/Modules/FindCythonize.cmake new file mode 100644 index 0000000000..9a37904ea7 --- /dev/null +++ b/cmake/Modules/FindCythonize.cmake @@ -0,0 +1,30 @@ +# Find the Cythonize tool. +# +# This code sets the following variables: +# +# Cythonize_EXECUTABLE +# +# adapted from https://github.com/cmarshall108/cython-cmake-example/blob/master/cmake/FindCython.cmake +#============================================================================= + +if(CMAKE_VERSION VERSION_LESS 3.12) + find_package(PythonInterp 3.6 QUIET) # Deprecated since version 3.12 + if(PYTHONINTERP_FOUND) + set(Python3_EXECUTABLE ${PYTHON_EXECUTABLE}) + endif() +else() + find_package(Python3 3.6 COMPONENTS Interpreter QUIET) +endif() + +# Use the Cython executable that lives next to the Python executable +# if it is a local installation. +if(Python3_EXECUTABLE) + get_filename_component(_python_path ${Python3_EXECUTABLE} PATH) + find_program(Cythonize_EXECUTABLE + NAMES cythonize3 cythonize cythonize.bat + HINTS ${_python_path}) +endif() + +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(Cythonize REQUIRED_VARS Cythonize_EXECUTABLE) +mark_as_advanced(Cythonize_EXECUTABLE) diff --git a/cmake/Modules/LAMMPSUtils.cmake b/cmake/Modules/LAMMPSUtils.cmake index 339ba867bd..fb1203ec73 100644 --- a/cmake/Modules/LAMMPSUtils.cmake +++ b/cmake/Modules/LAMMPSUtils.cmake @@ -50,6 +50,7 @@ function(check_for_autogen_files source_dir) file(GLOB SRC_AUTOGEN_FILES ${source_dir}/style_*.h) file(GLOB SRC_AUTOGEN_PACKAGES ${source_dir}/packages_*.h) list(APPEND SRC_AUTOGEN_FILES ${SRC_AUTOGEN_PACKAGES} ${source_dir}/lmpinstalledpkgs.h ${source_dir}/lmpgitversion.h) + list(APPEND SRC_AUTOGEN_FILES ${SRC_AUTOGEN_PACKAGES} ${source_dir}/MLIAP/mliap_model_python_couple ${source_dir}/MLIAP/mliap_model_python_couple.cpp) foreach(_SRC ${SRC_AUTOGEN_FILES}) get_filename_component(FILENAME "${_SRC}" NAME) if(EXISTS ${source_dir}/${FILENAME}) diff --git a/cmake/Modules/Packages/MLIAP.cmake b/cmake/Modules/Packages/MLIAP.cmake index e877d072b6..153900e2b8 100644 --- a/cmake/Modules/Packages/MLIAP.cmake +++ b/cmake/Modules/Packages/MLIAP.cmake @@ -1,3 +1,29 @@ -execute_process(COMMAND cythonize mliap_model_python_couple.pyx WORKING_DIRECTORY ../src/MLIAP) +# if PYTHON package is included we may also include Python support in MLIAP +set(ENABLE_MLIAP_PYTHON_DEFAULT OFF) +if(PKG_PYTHON) + find_package(Cythonize) + if(Cythonize_FOUND) + set(ENABLE_MLIAP_PYTHON_DEFAULT ON) + endif() +endif() -target_compile_definitions(lammps PRIVATE -DLMP_MLIAPPY) +option(ENABLE_MLIAP_PYTHON "Build MLIAP package with Python support" ${ENABLE_MLIAP_PYTHON_DEFAULT}) + +if(ENABLE_MLIAP_PYTHON) + find_package(Cythonize REQUIRED) + if(NOT_PKG_PYTHON) + message(FATAL_ERROR "Must install PYTHON package for MLIAP_PYTHON") + endif() + + set(MLIAP_CYTHON_DIR ${CMAKE_BINARY_DIR}/cython) + file(MAKE_DIRECTORY ${MLIAP_CYTHON_DIR}) + add_custom_command(OUTPUT ${MLIAP_CYTHON_DIR}/mliap_model_python_couple.cpp ${MLIAP_CYTHON_DIR}/mliap_model_python_couple.h + COMMAND ${CMAKE_COMMAND} -E copy ${LAMMPS_SOURCE_DIR}/MLIAP/mliap_model_python_couple.pyx ${MLIAP_CYTHON_DIR}/mliap_model_python_couple.pyx + COMMAND ${Cythonize_EXECUTABLE} ${MLIAP_CYTHON_DIR}/mliap_model_python_couple.pyx -3 + WORKING_DIRECTORY ${MLIAP_CYTHON_DIR} + MAIN_DEPENDENCY ${LAMMPS_SOURCE_DIR}/MLIAP/mliap_model_python_couple.pyx + COMMENT "Generating C++ sources with cythonize...") + target_compile_definitions(lammps PRIVATE -DMLIAP_PYTHON) + target_sources(lammps PRIVATE ${MLIAP_CYTHON_DIR}/mliap_model_python_couple.cpp) + target_include_directories(lammps PRIVATE ${MLIAP_CYTHON_DIR}) +endif() diff --git a/doc/src/Packages_details.rst b/doc/src/Packages_details.rst index 3ed5cabe37..3fb906addf 100644 --- a/doc/src/Packages_details.rst +++ b/doc/src/Packages_details.rst @@ -666,10 +666,10 @@ A general interface for machine-learning interatomic potentials, including PyTor **Install:** -To use this package, also the :ref:`SNAP package ` -package needs to be installed. If building the *mliappy* model, -use -DLMP_MLIAPPY and the :ref:`PYTHON package ` -package needs to be installed. The version of python must be >3.5. +To use this package, also the :ref:`SNAP package ` package needs +to be installed. To make the *mliappy* model available, also the +:ref:`PYTHON package ` package needs to be installed and the version of +python must be 3.5 or later. **Author:** Aidan Thompson (Sandia), Nicholas Lubbers (LANL). @@ -681,8 +681,8 @@ package needs to be installed. The version of python must be >3.5. * :doc:`compute_style mliap ` * examples/mliap (see README) -When built with the *mliappy* model using -DLMP_MLIAPPY, this package -includes an extension for coupling with python models, including PyTorch. +When built with the *mliappy* model this package includes an extension for +coupling with python models, including PyTorch. In this case, the python interpreter linked to LAMMPS will need cython and numpy installed. The examples build models with PyTorch, which would thus need to be installed. diff --git a/lib/python/Makefile.lammps b/lib/python/Makefile.lammps index 4289674e99..adda24caec 100644 --- a/lib/python/Makefile.lammps +++ b/lib/python/Makefile.lammps @@ -2,6 +2,6 @@ # See the README file for more explanation python_SYSINC = $(shell which python-config > /dev/null 2>&1 && python-config --includes || :) -python_SYSLIB = $(shell which python-config > /dev/null 2>&1 && python-config --ldflags || :) +python_SYSLIB = -lpython3 $(shell which python-config > /dev/null 2>&1 && python-config --ldflags || :) python_SYSPATH = PYTHON=python diff --git a/lib/python/Makefile.mliap_python b/lib/python/Makefile.mliap_python new file mode 100644 index 0000000000..00483a4a6a --- /dev/null +++ b/lib/python/Makefile.mliap_python @@ -0,0 +1,3 @@ + +../mliap_model_python_couple.cpp: ../mliap_model_python_couple.pyx + cythonize -3 ../mliap_model_python_couple.cpp diff --git a/src/Depend.sh b/src/Depend.sh index e629ca9197..f77d435fc5 100755 --- a/src/Depend.sh +++ b/src/Depend.sh @@ -106,6 +106,10 @@ if (test $1 = "PERI") then depend USER-OMP fi +if (test $1 = "PYTHON") then + depend MLIAP +fi + if (test $1 = "RIGID") then depend KOKKOS depend USER-OMP @@ -114,6 +118,7 @@ fi if (test $1 = "SNAP") then depend KOKKOS + depend MLIAP fi if (test $1 = "USER-CGSDK") then diff --git a/src/MLIAP/Install.sh b/src/MLIAP/Install.sh index bd7f7d23a8..e6ba4042a9 100755 --- a/src/MLIAP/Install.sh +++ b/src/MLIAP/Install.sh @@ -26,24 +26,42 @@ action () { fi } +# enforce package dependency +if (test $1 = 1 || test $1 = 2) then + if (test ! -e ../sna.h) then + echo "Must install SNAP package to use MLIAP package" + exit 1 + fi +fi + # all package files with no dependencies -for file in *.cpp *.h; do +for file in *.cpp *.h *.pyx; do test -f ${file} && action $file done # edit 2 Makefile.package files to include/exclude package info if (test $1 = 1) then - - if (test -e ../Makefile.package) then - sed -i -e 's|^PKG_INC =[ \t]*|&-DLMP_MLIAPPY |' ../Makefile.package + if (test "$(type cythonize 2> /dev/null)" != "" && test -e ../python_impl.cpp) then + if (test -e ../Makefile.package) then + sed -i -e 's|^PKG_INC =[ \t]*|&-DMLIAP_PYTHON |' ../Makefile.package + fi + if (test -e ../Makefile.package.settings) then + sed -i -e '/^include.*python.*mliap_python.*$/d' ../Makefile.package.settings + # multiline form needed for BSD sed on Macs + sed -i -e '4 i \ +include ..\/..\/lib\/python\/Makefile.mliap_python +' ../Makefile.package.settings + fi + cythonize -3 ../mliap_model_python_couple.pyx fi elif (test $1 = 0) then if (test -e ../Makefile.package) then - sed -i -e 's/[^ \t]*-DLMP_MLIAPPY[^ \t]* //g' ../Makefile.package + sed -i -e 's/[^ \t]*-DMLIAP_PYTHON[^ \t]* //g' ../Makefile.package fi - + rm -f ../mliap_model_python_couple.cpp ../mliap_model_python_couple.h + sed -i -e '/^include.*python.*mliap_python.*$/d' ../Makefile.package.settings fi diff --git a/src/MLIAP/compute_mliap.cpp b/src/MLIAP/compute_mliap.cpp index 72fb63ecda..0842e421c0 100644 --- a/src/MLIAP/compute_mliap.cpp +++ b/src/MLIAP/compute_mliap.cpp @@ -21,7 +21,7 @@ #include "mliap_model_linear.h" #include "mliap_model_quadratic.h" #include "mliap_descriptor_snap.h" -#ifdef LMP_MLIAPPY +#ifdef MLIAP_PYTHON #include "mliap_model_python.h" #endif @@ -74,12 +74,12 @@ ComputeMLIAP::ComputeMLIAP(LAMMPS *lmp, int narg, char **arg) : model = new MLIAPModelQuadratic(lmp); iarg += 2; } - #ifdef LMP_MLIAPPY +#ifdef MLIAP_PYTHON else if (strcmp(arg[iarg+1],"mliappy") == 0) { model = new MLIAPModelPython(lmp); iarg += 2; } - #endif +#endif else error->all(FLERR,"Illegal compute mliap command"); modelflag = 1; } else if (strcmp(arg[iarg],"descriptor") == 0) { diff --git a/src/MLIAP/pair_mliap.cpp b/src/MLIAP/pair_mliap.cpp index 5c0474d2ca..6f75ef542e 100644 --- a/src/MLIAP/pair_mliap.cpp +++ b/src/MLIAP/pair_mliap.cpp @@ -21,7 +21,7 @@ #include "mliap_model_linear.h" #include "mliap_model_quadratic.h" #include "mliap_descriptor_snap.h" -#ifdef LMP_MLIAPPY +#ifdef MLIAP_PYTHON #include "mliap_model_python.h" #endif @@ -128,7 +128,7 @@ void PairMLIAP::allocate() void PairMLIAP::settings(int narg, char ** arg) { - + if (narg < 4) error->all(FLERR,"Illegal pair_style command"); @@ -152,12 +152,12 @@ void PairMLIAP::settings(int narg, char ** arg) if (iarg+3 > narg) error->all(FLERR,"Illegal pair_style mliap command"); model = new MLIAPModelQuadratic(lmp,arg[iarg+2]); iarg += 3; - #ifdef LMP_MLIAPPY +#ifdef MLIAP_PYTHON } else if (strcmp(arg[iarg+1],"mliappy") == 0) { if (iarg+3 > narg) error->all(FLERR,"Illegal pair_style mliap command"); model = new MLIAPModelPython(lmp,arg[iarg+2]); iarg += 3; - #endif +#endif } else error->all(FLERR,"Illegal pair_style mliap command"); modelflag = 1; } else if (strcmp(arg[iarg],"descriptor") == 0) { diff --git a/src/PYTHON/python_impl.cpp b/src/PYTHON/python_impl.cpp index 62f19d0f12..533394f7b1 100644 --- a/src/PYTHON/python_impl.cpp +++ b/src/PYTHON/python_impl.cpp @@ -26,7 +26,7 @@ #include #include // IWYU pragma: export -#ifdef LMP_MLIAPPY +#ifdef MLIAP_PYTHON #include "mliap_model_python.h" // The above should somehow really be included in the next file. // We could get around this with cython --capi-reexport-cincludes @@ -58,14 +58,14 @@ PythonImpl::PythonImpl(LAMMPS *lmp) : Pointers(lmp) // one-time initialization of Python interpreter // pyMain stores pointer to main module external_interpreter = Py_IsInitialized(); - - #ifdef LMP_MLIAPPY + +#ifdef MLIAP_PYTHON // Inform python intialization scheme of the mliappy module. // This -must- happen before python is initialized. int err = PyImport_AppendInittab("mliap_model_python_couple", PyInit_mliap_model_python_couple); if (err) error->all(FLERR,"Could not register MLIAPPY embedded python module."); - #endif - +#endif + Py_Initialize(); PyEval_InitThreads(); diff --git a/src/Purge.list b/src/Purge.list index 0251f923be..2853ce2a7c 100644 --- a/src/Purge.list +++ b/src/Purge.list @@ -49,6 +49,8 @@ packages_ntopo.h # other auto-generated files lmpinstalledpkgs.h lmpgitversion.h +mliap_model_python_couple.cpp +mliap_model_python_couple.h # removed on 9 Sep 2020 mergesort.h # renamed on 8 May 2020