From 314d0a0e614c9a1abdd9bcf67fb7226a17f8c7de Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sat, 8 Feb 2025 05:50:10 -0500 Subject: [PATCH] only support Python version 3.6 or later. Update and correct docs and README --- doc/src/Python_install.rst | 19 ++++----- python/README | 86 ++++++++++++++++++++------------------ python/lammps/__init__.py | 3 ++ python/lammps/core.py | 24 ++--------- 4 files changed, 62 insertions(+), 70 deletions(-) diff --git a/doc/src/Python_install.rst b/doc/src/Python_install.rst index 01610b84f0..1e53a99914 100644 --- a/doc/src/Python_install.rst +++ b/doc/src/Python_install.rst @@ -7,6 +7,10 @@ LAMMPS shared library through the Python `ctypes `_ module. Because of the dynamic loading, it is required that LAMMPS is compiled in :ref:`"shared" mode `. +.. versionchanged:: TBD + +LAMMPS currently only supports Python version 3.6 or later. + Two components are necessary for Python to be able to invoke LAMMPS code: * The LAMMPS Python Package (``lammps``) from the ``python`` folder @@ -136,11 +140,6 @@ folder that the dynamic loader searches or inside of the installed # create virtual environment in folder $HOME/myenv python3 -m venv $HOME/myenv - For Python versions prior 3.3 you can use `virtualenv - `_ - command instead of "python3 -m venv". This step has to be done - only once. - To activate the virtual environment type: .. code-block:: bash @@ -245,14 +244,14 @@ make MPI calls directly from Python in your script, if you desire. We have tested this with `MPI for Python `_ (aka mpi4py) and you will find installation instruction for it below. -Installation of mpi4py (version 3.0.3 as of Sep 2020) can be done as +Installation of mpi4py (version 4.0.1 as of Feb 2025) can be done as follows: - Via ``pip`` into a local user folder with: .. code-block:: bash - pip install --user mpi4py + python3 -m pip install --user mpi4py - Via ``dnf`` into a system folder for RedHat/Fedora systems: @@ -261,20 +260,20 @@ follows: # for use with OpenMPI sudo dnf install python3-mpi4py-openmpi # for use with MPICH - sudo dnf install python3-mpi4py-openmpi + sudo dnf install python3-mpi4py-mpich - Via ``pip`` into a virtual environment (see above): .. code-block:: console $ source $HOME/myenv/activate - (myenv)$ pip install mpi4py + (myenv)$ python -m pip install mpi4py - Via ``pip`` into a system folder (not recommended): .. code-block:: bash - sudo pip install mpi4py + sudo python3 -m pip install mpi4py For more detailed installation instructions and additional options, please see the `mpi4py installation `_ page. diff --git a/python/README b/python/README index 0757a84cd6..97f47b2a36 100644 --- a/python/README +++ b/python/README @@ -1,20 +1,27 @@ -This directory contains Python code which wraps LAMMPS as a library -and allows the LAMMPS library interface to be invoked from Python, -either from a Python script or using Python interactively. +This directory contains the LAMMPS Python module that allows the LAMMPS +C library interface to be invoked from Python, either from a Python +script or using Python interactively. Details on the Python interface to LAMMPS and how to build LAMMPS as a shared library, for use with Python, are given in -doc/Section_python.html and in doc/Section_start.html#start_5. +https://docs.lammps.org/Build_basics.html#exe +and +https://docs.lammps.org/Python_install.html -Basically you need to follow these steps in the src directory: +Basically you need to use the flag -D BUILD_SHARED_LIBS=ON when +configuring LAMMPS with CMake and then in the build folder use the +command % cmake --build . --target install-python + +or for the legacy GNU build system execute these steps in the src folder: % make g++ mode=shlib # build for whatever machine target you wish % make install-python # install into site-packages folder You can replace the last step by a one-time setting of environment -variables in your shell script. Or you can run the python/install.py -script directly to give you more control over where the two relevant -files are installed. See doc/Python_install.html for details. +variables in your shell environment. Or you can run the +python/install.py script directly to give you more control over where +the two relevant files are installed. See +https://docs.lammps.org/Python_install.html for details. You should then be able to launch Python and instantiate an instance of LAMMPS: @@ -24,39 +31,41 @@ of LAMMPS: >>> lmp = lammps() If that gives no errors, you have successfully wrapped LAMMPS with -Python. See doc/Section_python.html#py_7 for tests you can then use -to run LAMMPS both in serial or parallel thru Python. +Python. See https://docs.lammps.org/Python_launch.html for examples how +to run LAMMPS both in serial or parallel from Python. Note that you can also invoke Python code from within a LAMMPS input -script, using the "python" command. See the doc/python.html doc page -for details. The Python code you invoke can also call back to LAMMPS -using the same interface described here for wrapping LAMMPS. +script, using the "python" command. See the +https://docs.lammps.org/python.html doc page for details. The Python +code you invoke can also call back to LAMMPS using the same interface +described here for wrapping LAMMPS. ------------------------------------------------------------------- Once you have successfully wrapped LAMMPS, you can run the Python scripts in the examples sub-directory: -trivial.py read/run a LAMMPS input script thru Python -demo.py invoke various LAMMPS library interface routines -simple.py parallel example, mimicing examples/COUPLE/simple/simple.cpp -split.py parallel example -mc.py Monte Carlo energy relaxation wrapper on LAMMPS -gui.py GUI go/stop/temperature-slider to control LAMMPS -plot.py real-time temperature plot with GnuPlot via Pizza.py -matplotlib_plot.py real-time temperature plot with Matplotlib via Pizza.py -viz_tool.py real-time viz via some viz package -vizplotgui_tool.py combination of viz.py and plot.py and gui.py +trivial.py read/run a LAMMPS input script thru Python +demo.py invoke various LAMMPS library interface routines +simple.py parallel example, mimicing examples/COUPLE/simple/simple.cpp +split.py parallel example +mc.py Monte Carlo energy relaxation wrapper on LAMMPS +gui.py GUI go/stop/temperature-slider to control LAMMPS +plot.py real-time temperature plot with GnuPlot via Pizza.py +matplotlib_plot.py real-time temperature plot with Matplotlib via Pizza.py +viz_.py real-time viz via some viz package +vizplotgui_.py combination of viz.py and plot.py and gui.py -For the viz_tool.py and vizplotgui_tool.py commands, replace "tool" -with "gl" or "atomeye" or "pymol", depending on what visualization -package you have installed. We hope to add a VMD option soon. +For the viz_.py and vizplotgui_.py commands, replace +"" with "gl" or "atomeye" or "pymol", depending on what +visualization package you have installed. We hope to add a VMD option +soon. Note that for GL, you need to be able to run the Pizza.py GL tool, which is included in the pizza sub-directory. See the Pizza.py doc pages for more info: -http://www.sandia.gov/~sjplimp/pizza.html +https://lammps.github.io/pizza/ Note that for AtomEye, you need version 3, and their is a line in the scripts that specifies the path and name of the executable. See @@ -115,17 +124,14 @@ one-processor run, where both Python and LAMMPS will run on single processors. Each running job will read the same input file, and write to same log.lammps file, which isn't too useful. -However, if you have the mpi4py Python package installed and uncomment mpi4py -code in simple.py, then the above commands will invoke 1 instance of a -P-processor run. Both Python and LAMMPS will run on P processors. The job will -read the input file and write a single log.lammps file. - -The split.py script can also be run in parallel. It uses mpi4py -version 2.0.0 (or later), which makes it possible to pass a -communicator when creating the LAMMPS object and thus run multiple -instances of LAMMPS at the same time, each on a different subset of -MPI ranks. Or run LAMMPS on one subset and some other program on the -rest of the MPI ranks, concurrently. See comments in the split.py -script for more details. - +However, if you have the mpi4py Python package installed and uncomment +mpi4py code in simple.py, then the above commands will invoke 1 instance +of a P-processor run. Both Python and LAMMPS will run on P processors. +The job will read the input file and write a single log.lammps file. +The split.py script can also be run in parallel. It uses mpi4py version +2.0.0 (or later), which makes it possible to pass a communicator when +creating the LAMMPS object and thus run multiple instances of LAMMPS at +the same time, each on a different subset of MPI ranks. Or run LAMMPS +on one subset and some other program on the rest of the MPI ranks, +concurrently. See comments in the split.py script for more details. diff --git a/python/lammps/__init__.py b/python/lammps/__init__.py index fc35e45225..0cc658371f 100644 --- a/python/lammps/__init__.py +++ b/python/lammps/__init__.py @@ -23,6 +23,9 @@ def get_version_number(): if __file__.find(join('python', 'lammps', '__init__.py')) > 0: return 0 + if version_info.major < 3 or (version_info.major == 3 and version_info.minor < 6): + raise SystemError('LAMMPS only supports Python version 3.6 or later') + vstring = None if version_info.major == 3 and version_info.minor >= 8: from importlib.metadata import version, PackageNotFoundError diff --git a/python/lammps/core.py b/python/lammps/core.py index 43d142c7de..d8fc3a666e 100644 --- a/python/lammps/core.py +++ b/python/lammps/core.py @@ -83,8 +83,6 @@ class command_wrapper(object): def _wrap_args(self, x): if callable(x): - if sys.version_info < (3,): - raise Exception("Passing functions or lambdas directly as arguments is only supported in Python 3 or newer") import hashlib import __main__ sha = hashlib.sha256() @@ -105,11 +103,6 @@ class command_wrapper(object): all the arguments, concatinates them to a single string, and executes it using :py:meth:`lammps.command`. - Starting with Python 3.6 it also supports keyword arguments. key=value is - transformed into 'key value'. Note, since these have come last in the - parameter list, only a subset of LAMMPS commands can be used with this - syntax. - LAMMPS commands that accept callback functions (such as fix python/invoke) can be passed functions and lambdas directly. The first argument of such callbacks will be an lammps object constructed from the passed LAMMPS @@ -121,9 +114,6 @@ class command_wrapper(object): def handler(*args, **kwargs): cmd_args = [name] + [str(self._wrap_args(x)) for x in args] - if len(kwargs) > 0 and sys.version_info < (3,6): - raise Exception("Keyword arguments are only supported in Python 3.6 or newer") - # Python 3.6+ maintains ordering of kwarg keys for k in kwargs.keys(): cmd_args.append(k) @@ -530,16 +520,10 @@ class lammps(object): else: # magic to convert ptr to ctypes ptr - if sys.version_info >= (3, 0): - # Python 3 (uses PyCapsule API) - pythonapi.PyCapsule_GetPointer.restype = c_void_p - pythonapi.PyCapsule_GetPointer.argtypes = [py_object, c_char_p] - self.lmp = c_void_p(pythonapi.PyCapsule_GetPointer(ptr, None)) - else: - # Python 2 (uses PyCObject API) - pythonapi.PyCObject_AsVoidPtr.restype = c_void_p - pythonapi.PyCObject_AsVoidPtr.argtypes = [py_object] - self.lmp = c_void_p(pythonapi.PyCObject_AsVoidPtr(ptr)) + # Python 3 (uses PyCapsule API) + pythonapi.PyCapsule_GetPointer.restype = c_void_p + pythonapi.PyCapsule_GetPointer.argtypes = [py_object, c_char_p] + self.lmp = c_void_p(pythonapi.PyCapsule_GetPointer(ptr, None)) # check if library initilialization failed if not self.lmp: