diff --git a/doc/src/Library_create.rst b/doc/src/Library_create.rst index b3fea4b89e..3566cb3cc9 100644 --- a/doc/src/Library_create.rst +++ b/doc/src/Library_create.rst @@ -10,6 +10,7 @@ This section documents the following functions: - :cpp:func:`lammps_mpi_init` - :cpp:func:`lammps_mpi_finalize` - :cpp:func:`lammps_kokkos_finalize` +- :cpp:func:`lammps_python_finalize` -------------------- @@ -104,3 +105,13 @@ calling program. .. doxygenfunction:: lammps_mpi_finalize :project: progguide + +----------------------- + +.. doxygenfunction:: lammps_kokkos_finalize + :project: progguide + +----------------------- + +.. doxygenfunction:: lammps_python_finalize + :project: progguide diff --git a/src/PYTHON/python_impl.cpp b/src/PYTHON/python_impl.cpp index 29a2ea9dba..08fba05367 100644 --- a/src/PYTHON/python_impl.cpp +++ b/src/PYTHON/python_impl.cpp @@ -63,10 +63,6 @@ PythonImpl::PythonImpl(LAMMPS *lmp) : Pointers(lmp) #endif #endif - // one-time initialization of Python interpreter - // pyMain stores pointer to main module - external_interpreter = Py_IsInitialized(); - #ifdef MLIAP_PYTHON // Inform python intialization scheme of the mliappy module. // This -must- happen before python is initialized. @@ -108,12 +104,6 @@ PythonImpl::~PythonImpl() } } - // shutdown Python interpreter - if (!external_interpreter) { - PyGILState_Ensure(); - Py_Finalize(); - } - memory->sfree(pfuncs); } @@ -545,3 +535,10 @@ bool PythonImpl::has_minimum_version(int major, int minor) { return (PY_MAJOR_VERSION == major && PY_MINOR_VERSION >= minor) || (PY_MAJOR_VERSION > major); } + +/* ------------------------------------------------------------------ */ + +void PythonImpl::finalize() +{ + if (Py_IsInitialized()) Py_Finalize(); +} diff --git a/src/PYTHON/python_impl.h b/src/PYTHON/python_impl.h index dd215fdedf..fe14862186 100644 --- a/src/PYTHON/python_impl.h +++ b/src/PYTHON/python_impl.h @@ -20,9 +20,8 @@ namespace LAMMPS_NS { class PythonImpl : protected Pointers, public PythonInterface { - public: - bool external_interpreter; + public: PythonImpl(class LAMMPS *); ~PythonImpl(); void command(int, char **); @@ -33,6 +32,7 @@ class PythonImpl : protected Pointers, public PythonInterface { int execute_string(char *); int execute_file(char *); bool has_minimum_version(int major, int minor); + static void finalize(); private: void *pyMain; diff --git a/src/library.cpp b/src/library.cpp index b60f8659ee..1acb61c66d 100644 --- a/src/library.cpp +++ b/src/library.cpp @@ -33,17 +33,18 @@ #include "group.h" #include "info.h" #include "input.h" +#include "lmppython.h" #include "memory.h" #include "modify.h" #include "molecule.h" #include "neigh_list.h" #include "neighbor.h" -#include "region.h" -#include "respa.h" #include "output.h" #if defined(LMP_PLUGIN) #include "plugin.h" #endif +#include "region.h" +#include "respa.h" #include "thermo.h" #include "timer.h" #include "universe.h" @@ -339,6 +340,8 @@ function no more MPI calls may be made. .. versionadded:: 18Sep2020 +*See also* + :cpp:func:`lammps_kokkos_finalize`, :cpp:func:`lammps_python_finalize` \endverbatim */ void lammps_mpi_finalize() @@ -369,6 +372,8 @@ After calling this function no Kokkos functionality may be used. .. versionadded:: 2Jul2021 +*See also* + :cpp:func:`lammps_mpi_finalize`, :cpp:func:`lammps_python_finalize` \endverbatim */ void lammps_kokkos_finalize() @@ -376,6 +381,42 @@ void lammps_kokkos_finalize() KokkosLMP::finalize(); } +/* ---------------------------------------------------------------------- */ + +/** Clear the embedded Python environment + * +\verbatim embed:rst + +This function resets and clears an embedded Python environment +by calling the `Py_Finalize() function +`_ +of the embedded Python library, if enabled. +This call would free up all allocated resources and release +loaded shared objects. + +However, this is **not** done when a LAMMPS instance is deleted because +a) LAMMPS may have been used through the Python module and thus +the Python interpreter is external and not embedded into LAMMPS +and therefore may not be reset by LAMMPS b) some Python modules +and extensions, most notably NumPy, are not compatible with being +initialized multiple times, which would happen if additional +LAMMPS instances using Python would be created *after* +after calling Py_Finalize(). + +This function can be called to explicitly clear the Python +environment in case it is safe to do so. + +.. versionadded:: TBD + +*See also* + :cpp:func:`lammps_mpi_finalize`, :cpp:func:`lammps_kokkos_finalize` +\endverbatim */ + +void lammps_python_finalize() +{ + Python::finalize(); +} + // ---------------------------------------------------------------------- // Library functions to process commands // ---------------------------------------------------------------------- diff --git a/src/library.h b/src/library.h index e55f906a11..1605267818 100644 --- a/src/library.h +++ b/src/library.h @@ -95,6 +95,7 @@ void lammps_close(void *handle); void lammps_mpi_init(); void lammps_mpi_finalize(); void lammps_kokkos_finalize(); +void lammps_python_finalize(); /* ---------------------------------------------------------------------- * Library functions to process commands diff --git a/src/lmppython.cpp b/src/lmppython.cpp index 44b469eed3..c200b4ba50 100644 --- a/src/lmppython.cpp +++ b/src/lmppython.cpp @@ -126,3 +126,12 @@ bool Python::has_minimum_version(int major, int minor) init(); return impl->has_minimum_version(major, minor); } + +/* ------------------------------------------------------------------ */ + +void Python::finalize() +{ +#if defined(LMP_PYTHON) + PythonImpl::finalize(); +#endif +} diff --git a/src/lmppython.h b/src/lmppython.h index 3c7ae396bc..7ecee915e5 100644 --- a/src/lmppython.h +++ b/src/lmppython.h @@ -47,6 +47,7 @@ class Python : protected Pointers { bool is_enabled() const; void init(); + static void finalize(); private: PythonInterface *impl; diff --git a/src/main.cpp b/src/main.cpp index 608ef4ae5b..32420324ef 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -15,6 +15,8 @@ #include "accelerator_kokkos.h" #include "input.h" +#include "lmppython.h" + #if defined(LAMMPS_EXCEPTIONS) #include "exceptions.h" #endif @@ -79,15 +81,18 @@ int main(int argc, char **argv) delete lammps; } catch (LAMMPSAbortException &ae) { KokkosLMP::finalize(); + Python::finalize(); MPI_Abort(ae.universe, 1); } catch (LAMMPSException &e) { KokkosLMP::finalize(); + Python::finalize(); MPI_Barrier(lammps_comm); MPI_Finalize(); exit(1); } catch (fmt::format_error &fe) { fprintf(stderr, "fmt::format_error: %s\n", fe.what()); KokkosLMP::finalize(); + Python::finalize(); MPI_Abort(MPI_COMM_WORLD, 1); exit(1); } @@ -99,11 +104,13 @@ int main(int argc, char **argv) } catch (fmt::format_error &fe) { fprintf(stderr, "fmt::format_error: %s\n", fe.what()); KokkosLMP::finalize(); + Python::finalize(); MPI_Abort(MPI_COMM_WORLD, 1); exit(1); } #endif KokkosLMP::finalize(); + Python::finalize(); MPI_Barrier(lammps_comm); MPI_Finalize(); } diff --git a/tools/swig/lammps.i b/tools/swig/lammps.i index 2767e4c068..4d0d52f779 100644 --- a/tools/swig/lammps.i +++ b/tools/swig/lammps.i @@ -64,6 +64,7 @@ extern void lammps_close(void *handle); extern void lammps_mpi_init(); extern void lammps_mpi_finalize(); extern void lammps_kokkos_finalize(); +extern void lammps_python_finalize(); extern void lammps_file(void *handle, const char *file); extern char *lammps_command(void *handle, const char *cmd); extern void lammps_commands_list(void *handle, int ncmd, const char **cmds); @@ -199,6 +200,7 @@ extern void lammps_close(void *handle); extern void lammps_mpi_init(); extern void lammps_mpi_finalize(); extern void lammps_kokkos_finalize(); +extern void lammps_python_finalize(); extern void lammps_file(void *handle, const char *file); extern char *lammps_command(void *handle, const char *cmd); extern void lammps_commands_list(void *handle, int ncmd, const char **cmds);