Update and reorganize Python docs

This commit is contained in:
Richard Berger
2020-09-28 21:01:26 -04:00
parent cc5ef652e4
commit 507c2cb2a8
25 changed files with 1140 additions and 821 deletions

View File

@ -0,0 +1,27 @@
// LAMMPS -> Python
digraph api {
rankdir="LR";
edge [constraint=false];
input [shape=box label="LAMMPS\nInput Script" height=1.5];
subgraph cluster0 {
style=filled;
color="#e5e5e5";
rank=same;
capi [shape=box style=filled height=1 color="#666666" fontcolor=white label="LAMMPS\nC Library API"];
instance [shape=box style=filled height=1 color="#3465a4" fontcolor=white label="LAMMPS\ninstance\n\n0x01abcdef"];
capi -> instance [dir=both];
label="LAMMPS Shared Library";
}
python [shape=box style=filled color="#4e9a06" fontcolor=white label="Python\nScript" height=1.5];
subgraph cluster1 {
style=filled;
color="#e5e5e5";
lammps [shape=box style=filled height=1 color="#729fcf" label="lammps\n\nptr: 0x01abcdef"];
label="LAMMPS Python Module";
}
input -> instance [constraint=true];
instance -> python [dir=both constraint=true];
python:e -> lammps:w [dir=both constraint=true];
lammps:s -> capi:e [dir=both label=ctypes constraint=true];
}

View File

@ -0,0 +1,30 @@
// PyLammps -> LAMMPS
digraph api {
rankdir="LR";
edge [constraint=false];
python [shape=box style=filled color="#4e9a06" fontcolor=white label="Python\nScript" height=1.5];
subgraph cluster0 {
style=filled;
color="#e5e5e5";
height=1.5;
rank=same;
pylammps [shape=box style=filled height=1 color="#729fcf" label="(I)PyLammps"];
lammps [shape=box style=filled height=1 color="#729fcf" label="lammps\n\nptr: 0x01abcdef"];
pylammps -> lammps [dir=both];
label="LAMMPS Python Module";
}
subgraph cluster1 {
style=filled;
color="#e5e5e5";
height=1.5;
capi [shape=box style=filled height=1 color="#666666" fontcolor=white label="LAMMPS\nC Library API"];
instance [shape=box style=filled height=1 color="#3465a4" fontcolor=white label="LAMMPS\ninstance\n\n0x01abcdef"];
capi -> instance [dir=both constraint=true];
label="LAMMPS Shared Library";
}
python -> pylammps [dir=both constraint=true];
lammps -> capi [dir=both label=ctypes constraint=true];
pylammps:e -> instance:ne [dir=back, style=dashed label="captured standard output"];
}

View File

@ -0,0 +1,24 @@
// Python -> LAMMPS
digraph api {
rankdir="LR";
python [shape=box style=filled color="#4e9a06" fontcolor=white label="Python\nScript" height=1.5];
subgraph cluster0 {
style=filled;
color="#e5e5e5";
height=1.5;
lammps [shape=box style=filled height=1 color="#729fcf" label="lammps\n\nptr: 0x01abcdef"];
label="LAMMPS Python Module";
}
subgraph cluster1 {
style=filled;
color="#e5e5e5";
height=1.5;
capi [shape=box style=filled height=1 color="#666666" fontcolor=white label="LAMMPS\nC Library API"];
instance [shape=box style=filled height=1 color="#3465a4" fontcolor=white label="LAMMPS\ninstance\n\n0x01abcdef"];
capi -> instance [dir=both];
label="LAMMPS Shared Library";
}
python -> lammps [dir=both];
lammps -> capi [dir=both,label=ctypes];
}

View File

@ -329,6 +329,7 @@ LAMMPS.
----------
.. _exe:
.. _library:
Build the LAMMPS executable and library
---------------------------------------

View File

@ -11,7 +11,7 @@ on its own or use an existing lammps Python object. It creates a simpler,
more "pythonic" interface to common LAMMPS functionality, in contrast to
the ``lammps.py`` wrapper for the C-style LAMMPS library interface which
is written using `Python ctypes <ctypes_>`_. The ``lammps.py`` wrapper
is discussed on the :doc:`Python library <Python_library>` doc page.
is discussed on the :doc:`Python_head` doc page.
Unlike the flat ``ctypes`` interface, PyLammps exposes a discoverable
API. It no longer requires knowledge of the underlying C++ code

Binary file not shown.

Before

Width:  |  Height:  |  Size: 245 KiB

After

Width:  |  Height:  |  Size: 266 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

@ -1,5 +1,5 @@
Call Python from a LAMMPS input script
======================================
Calling Python from a LAMMPS input script
*****************************************
LAMMPS has several commands which can be used to invoke Python
code directly from an input script:
@ -47,32 +47,3 @@ See the :doc:`python <python>` doc page and the :doc:`variable <variable>`
doc page for its python-style variables for more info, including
examples of Python code you can write for both pure Python operations
and callbacks to LAMMPS.
The :doc:`fix python/invoke <fix_python_invoke>` command can execute
Python code at selected timesteps during a simulation run.
The :doc:`pair_style python <pair_python>` command allows you to define
pairwise potentials as python code which encodes a single pairwise
interaction. This is useful for rapid development and debugging of a
new potential.
To use any of these commands, you only need to build LAMMPS with the
PYTHON package installed:
.. code-block:: bash
make yes-python
make machine
Note that this will link LAMMPS with the Python library on your
system, which typically requires several auxiliary system libraries to
also be linked. The list of these libraries and the paths to find
them are specified in the lib/python/Makefile.lammps file. You need
to insure that file contains the correct information for your version
of Python and your machine to successfully build LAMMPS. See the
lib/python/README file for more info.
If you want to write Python code with callbacks to LAMMPS, then you
must also follow the steps summarized in the :doc:`Python run <Python_run>` doc page. I.e. you must build LAMMPS as a shared
library and insure that Python can find the python/lammps.py file and
the shared library.

15
doc/src/Python_error.rst Normal file
View File

@ -0,0 +1,15 @@
LAMMPS error handling in Python
*******************************
Compiling the shared library with :ref:`C++ exception support <exceptions>` provides a better error
handling experience. Without exceptions the LAMMPS code will terminate the
current Python process with an error message. C++ exceptions allow capturing
them on the C++ side and rethrowing them on the Python side. This way
LAMMPS errors can be handled through the Python exception handling mechanism.
.. warning::
Capturing a LAMMPS exception in Python can still mean that the
current LAMMPS process is in an illegal state and must be terminated. It is
advised to save your data and terminate the Python instance as quickly as
possible.

View File

@ -1,6 +1,9 @@
Example Python scripts that use LAMMPS
======================================
The python/examples directory has Python scripts which show how Python
can run LAMMPS, grab data, change it, and put it back into LAMMPS.
These are the Python scripts included as demos in the python/examples
directory of the LAMMPS distribution, to illustrate the kinds of
things that are possible when Python wraps LAMMPS. If you create your

16
doc/src/Python_ext.rst Normal file
View File

@ -0,0 +1,16 @@
Extending the library and Python interface
******************************************
As noted above, these Python class methods correspond one-to-one with
the functions in the LAMMPS library interface in src/library.cpp and
library.h. This means you can extend the Python wrapper via the
following steps:
* Add a new interface function to src/library.cpp and
src/library.h.
* Rebuild LAMMPS as a shared library.
* Add a wrapper method to python/lammps.py for this interface
function.
* You should now be able to invoke the new interface function from a
Python script.

View File

@ -8,16 +8,15 @@ used together.
:maxdepth: 1
Python_overview
Python_run
Python_shlib
Python_install
Python_mpi
Python_test
Python_library
Python_module
Python_pylammps
Python_examples
Python_run
Python_usage
Python_call
Python_module
Python_examples
Python_error
Python_ext
Python_trouble
If you're not familiar with `Python <http://www.python.org>`_, it's a
powerful scripting and programming language which can do most

View File

@ -1,68 +1,499 @@
Installing LAMMPS in Python
===========================
Installation
************
For Python to invoke LAMMPS, there are 2 files it needs to know about:
The LAMMPS Python module enables calling the :ref:`LAMMPS C library API <lammps_c_api>`
from Python by dynamically loading functions in the LAMMPS shared library through the
Python ``ctypes`` module. Because of the dynamic loading, it is required that
LAMMPS is compiled in *shared mode*.
* python/lammps.py
* liblammps.so or liblammps.dylib
Two files are necessary for Python to be able to invoke LAMMPS code:
The python source code in lammps.py is the Python wrapper on the
LAMMPS library interface. The liblammps.so or liblammps.dylib file
is the shared LAMMPS library that Python loads dynamically.
* LAMMPS Python Module (``python/lammps.py``)
* LAMMPS Shared Library (e.g., ``liblammps.so``)
You can achieve that Python can find these files in one of two ways:
* set two environment variables pointing to the location in the source tree
* run "make install-python" or run the python/install.py script explicitly
.. _python_virtualenv: https://packaging.python.org/guides/installing-using-pip-and-virtual-environments/#creating-a-virtual-environment
.. _python_venv: https://docs.python.org/3.8/library/venv.html
.. _python_pep405: https://www.python.org/dev/peps/pep-0405
When calling "make install-python" LAMMPS will try to install the
python module and the shared library into the python site-packages folders;
either the system-wide ones, or the local users ones (in case of insufficient
permissions for the global install). Python will then find the module
and shared library file automatically. The exact location of these folders
depends on your python version and your operating system. When using
the CMake build system, you can set the python executable to use during
the CMake configuration process. Details are given in the build instructions
for the :ref:`PYTHON <python>` package. When using the conventional make
system, you can override the python version to version x.y when calling
make with PYTHON=pythonx.y.
.. _python_install_guides:
If you set the paths to these files as environment variables, you only
have to do it once. For the csh or tcsh shells, add something like
this to your ~/.cshrc file, one line for each of the two files:
Installing the LAMMPS Python Module and Shared Library
======================================================
.. code-block:: csh
Making LAMMPS usable within Python and vice versa requires putting the LAMMPS
Python module into a location that the Python interpreter can find and
installing the LAMMPS shared library into a folder that the dynamic loader
searches. For some potentials LAMMPS also needs to know where it can find the
necessary potential files.
setenv PYTHONPATH ${PYTHONPATH}:/home/sjplimp/lammps/python
setenv LD_LIBRARY_PATH ${LD_LIBRARY_PATH}:/home/sjplimp/lammps/src
Both CMake and traditional make build options offer ways to automate these tasks.
On MacOSX you may also need to set DYLD_LIBRARY_PATH accordingly.
For Bourne/Korn shells accordingly into the corresponding files using
the "export" shell builtin.
.. tabs::
If you use "make install-python" or the python/install.py script, you need
to invoke it every time you rebuild LAMMPS (as a shared library) or
make changes to the python/lammps.py file, so that the site-packages
files are updated with the new version.
.. tab:: CMake (local user)
If the default settings of "make install-python" are not what you want,
you can invoke install.py from the python directory manually as
LAMMPS can be configured and compiled as shared library with CMake by enabling the ``BUILD_SHARED_LIBS`` option.
The file name of the shared library depends on the platform (Unix/Linux, MacOS, Windows) and the build configuration
being used. See :ref:`Build the LAMMPS executable and library <library>` for more details and how the name is
determined.
.. parsed-literal::
After compilation, the generated binaries, shared library, Python module,
and other files can be installed to a custom location defined by the
``CMAKE_INSTALL_PREFIX`` setting. By default, this is set to the current
user's ``$HOME/.local`` directory. This leads to an installation to the following locations:
% python install.py -m \<python module\> -l <shared library> -v <version.h file> [-d \<pydir\>]
+------------------------+-----------------------------------------------------------+-------------------------------------------------------------+
| File | Location | Notes |
+========================+===========================================================+=============================================================+
| LAMMPS Python Module | * ``$HOME/.local/lib/pythonX.Y/site-packages/`` (32bit) | ``X.Y`` depends on the installed Python version |
| | * ``$HOME/.local/lib64/pythonX.Y/site-packages/`` (64bit) | |
+------------------------+-----------------------------------------------------------+-------------------------------------------------------------+
| LAMMPS shared library | * ``$HOME/.local/lib/`` (32bit) | |
| | * ``$HOME/.local/lib64/`` (64bit) | |
+------------------------+-----------------------------------------------------------+-------------------------------------------------------------+
| LAMMPS potential files | ``$HOME/.local/share/lammps/potentials/`` | |
+------------------------+-----------------------------------------------------------+-------------------------------------------------------------+
* The -m flag points to the lammps.py python module file to be installed,
* the -l flag points to the LAMMPS shared library file to be installed,
* the -v flag points to the version.h file in the LAMMPS source
* and the optional -d flag to a custom (legacy) installation folder
The following is a minimal working example:
If you use a legacy installation folder, you will need to set your
PYTHONPATH and LD_LIBRARY_PATH (and/or DYLD_LIBRARY_PATH) environment
variables accordingly, as described above.
1. Install LAMMPS Shared Library and Python module using CMake
.. code-block:: bash
# create and change into build directory
mkdir build
cd build
# configure LAMMPS compilation
# compile with shared library, PYTHON package, and C++ exceptions
# TODO: add more options to customize your LAMMPS installation
cmake -C ../cmake/presets/minimal.cmake \
-D BUILD_SHARED_LIBS=on \
-D PKG_PYTHON=on \
-D LAMMPS_EXCEPTIONS=on \
../cmake
# compile LAMMPS (in parallel for faster builds)
cmake --build . --parallel
# install LAMMPS into myvenv
cmake --install .
2. Configure Environment Variables
To use this installation you have to ensure that the folder containing
the LAMMPS shared library is part of the ``LD_LIBRARY_PATH`` environment variable (or
``DYLD_LIBRARY_PATH`` on MacOS). This allows the dynamic library loader of your system
to find the LAMMPS shared library when needed.
.. code-block:: bash
# Unix/Linux
export LD_LIBRARY_PATH=$HOME/.local/lib:$LD_LIBRARY_PATH
# MacOS
export DYLD_LIBRARY_PATH=$HOME/.local/lib:$DYLD_LIBRARY_PATH
LAMMPS will also need to know the location of the folder
containing its potential files. This can be set with the ``LAMMPS_POTENTIALS``
environment variable:
.. code-block::
export LAMMPS_POTENTIALS=$HOME/.local/share/lammps/potentials
To set these environment variables for each new shell, add the above
``export`` commands at the end of the ``$HOME/.bashrc`` file.
3. Verify if LAMMPS can be successfully started from Python
.. code-block:: bash
$ python
Python 3.8.5 (default, Sep 5 2020, 10:50:12)
[GCC 10.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import lammps
>>> lmp = lammps.lammps()
LAMMPS (18 Sep 2020)
using 1 OpenMP thread(s) per MPI task
>>>
.. note::
If you recompile LAMMPS, you will have to also rerun the install step to
ensure the latest Python module and shared library are installed.
.. tab:: CMake (system-wide)
A system-wide installation allows all users to run Python with LAMMPS
included. Note that during the installation step you will need to either be
root or use ``sudo`` to elevate your write privileges. The compilation steps are identical
to the local user installation, with the only difference that
``CMAKE_INSTALL_PREFIX`` is set to system folder such as ``/usr``. This leads to
the following installation locations:
+------------------------+---------------------------------------------------+-------------------------------------------------------------+
| File | Location | Notes |
+========================+===================================================+=============================================================+
| LAMMPS Python Module | * ``/usr/lib/pythonX.Y/site-packages/`` (32bit) | ``X.Y`` depends on the installed Python version |
| | * ``/usr/lib64/pythonX.Y/site-packages/`` (64bit) | |
+------------------------+---------------------------------------------------+-------------------------------------------------------------+
| LAMMPS shared library | * ``/usr/lib/`` (32bit) | |
| | * ``/usr/lib64/`` (64bit) | |
+------------------------+---------------------------------------------------+-------------------------------------------------------------+
| LAMMPS potential files | ``/usr/share/lammps/potentials/`` | |
+------------------------+---------------------------------------------------+-------------------------------------------------------------+
The following is a minimal working example:
1. Install LAMMPS shared library and Python module into system folder
.. code-block:: bash
# configure LAMMPS compilation
# compile with shared library, PYTHON package, and C++ exceptions
# TODO: add more options to customize your LAMMPS installation
cmake -C ../cmake/presets/minimal.cmake \
-D BUILD_SHARED_LIBS=on \
-D PKG_PYTHON=on \
-D LAMMPS_EXCEPTIONS=on \
-D CMAKE_INSTALL_PREFIX=/usr \
../cmake
# compile LAMMPS (in parallel for faster builds)
cmake --build . --parallel
# install LAMMPS into /usr (requires write access)
sudo cmake --install .
Unlike the local user installation, no additional environment
variables need to be set. The system locations such as ``/usr/lib`` and
``/usr/lib64`` are already part of the search path of the dynamic library
loader. Therefore ``LD_LIBRARY_PATH`` or ``DYLD_LIBRARY_PATH`` on MacOS do not
have be set.
All other environment variables will be automatically set when
launching a new shell. This is due to files installed in system folders
``/etc/profile.d/``, such as ``/etc/profile.d/lammps.sh``, that are loaded when a
login shell is started.
2. Open a new shell
Close the current shell and open a new one or use ``source /etc/profile`` to
update your environment
.. note::
On some systems you might also need to log out your current user and log back in.
3. Verify if LAMMPS can be successfully started from Python
Open a new terminal and test if LAMMPS can be started from within Python:
.. code-block:: bash
$ python
Python 3.8.5 (default, Sep 5 2020, 10:50:12)
[GCC 10.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import lammps
>>> lmp = lammps.lammps()
LAMMPS (18 Sep 2020)
using 1 OpenMP thread(s) per MPI task
>>>
.. note::
If you recompile LAMMPS, you will have to also rerun the install step to
ensure the latest Python module and shared library are installed.
.. tab:: CMake (virtual environment)
LAMMPS and its Python module can be installed together into a
Python virtual environment.
A virtual environment is a minimalistic Python installation inside of a
folder. It allows isolating and customizing a Python environment that is
independent from a user or system installation. This gives you the flexibility
to install (newer) versions of Python packages that would potentially conflict
with already installed system packages. It also does not requite any superuser
privileges. See `PEP 405: Python Virtual Environments <python_pep405>`_
for more information.
To install into the virtual environment, it is first activated and the
``CMAKE_INSTALL_PREFIX`` is set to value of the ``$VIRTUAL_ENV`` environment
variable. This leads to the following installation locations:
+------------------------+-----------------------------------------------------------+-------------------------------------------------------------+
| File | Location | Notes |
+========================+===========================================================+=============================================================+
| LAMMPS Python Module | * ``$VIRTUAL_ENV/lib/pythonX.Y/site-packages/`` (32bit) | ``X.Y`` depends on the installed Python version |
| | * ``$VIRTUAL_ENV/lib64/pythonX.Y/site-packages/`` (64bit) | |
+------------------------+-----------------------------------------------------------+-------------------------------------------------------------+
| LAMMPS shared library | * ``$VIRTUAL_ENV/lib/`` (32bit) | |
| | * ``$VIRTUAL_ENV/lib64/`` (64bit) | |
+------------------------+-----------------------------------------------------------+-------------------------------------------------------------+
| LAMMPS potential files | ``$VIRTUAL_ENV/share/lammps/potentials/`` | |
+------------------------+-----------------------------------------------------------+-------------------------------------------------------------+
The following is a minimal working example using CMake:
1. Create a virtual environment
Use the `venv <python_venv>`_ module to create a new environment
inside of the folder ``$HOME/myenv``. For Python versions prior 3.3,
you can use `virtualenv <python_virtualenv>`_ instead.
.. code-block:: bash
# create virtual environment in folder $HOME/myenv
python3 -m venv $HOME/myenv
2. Modify the ``$HOME/myenv/bin/activate`` script
The ``activate`` script initializes the environment for use. For convienience,
add two additional lines at the end of this script:
* To allow the dynamic library loader to find the LAMMPS shared library, add
the folder where it will be installed to ``LD_LIBRARY_PATH`` environment
variable (``DYLD_LIBRARY_PATH`` on MacOS). When installing LAMMPS into a
virtual environment this location will be ``$VIRTUAL_ENV/lib``.
Run the following command to add the necessary line to the ``activate`` script:
.. code-block:: bash
# Unix/Linux
echo 'export LD_LIBRARY_PATH=$VIRTUAL_ENV/lib:$LD_LIBRARY_PATH' >> $HOME/myenv/bin/activate
# MacOS
echo 'export DYLD_LIBRARY_PATH=$VIRTUAL_ENV/lib:$LD_LIBRARY_PATH' >> $HOME/myenv/bin/activate
* Any LAMMPS installation will need to know the location of the folder containing its potential files.
This can be set with the ``LAMMPS_POTENTIALS`` environment variable. When installing LAMMPS into a
virtual environment this location will be ``$VIRTUAL_ENV/share/lammps/potentials``.
Run the following command to add the change in the ``activate`` script:
.. code-block:: bash
echo 'export LAMMPS_POTENTIALS=$VIRTUAL_ENV/share/lammps/potentials' >> $HOME/myenv/bin/activate
3. Compile LAMMPS and install it into virtual environment
.. code-block:: bash
# create and change into build directory
mkdir build
cd build
# activate environment, this sets VIRTUAL_ENV and other environment variables
source $HOME/myenv/bin/activate
# configure LAMMPS compilation
# compile with shared library, PYTHON package, and C++ exceptions
# and install into virtual environment folder (VIRTUAL_ENV)
# TODO: add more options to customize your LAMMPS installation
(myenv)$ cmake -C ../cmake/presets/minimal.cmake \
-D BUILD_SHARED_LIBS=on \
-D PKG_PYTHON=on \
-D LAMMPS_EXCEPTIONS=on \
-D CMAKE_INSTALL_PREFIX=$VIRTUAL_ENV \
../cmake
# compile LAMMPS (in parallel for faster builds)
(myenv)$ cmake --build . --parallel
# install LAMMPS into myenv
(myenv)$ cmake --install .
4. Verify if LAMMPS can be successfully started from Python
.. code-block:: bash
(myenv)$ python
Python 3.8.5 (default, Sep 5 2020, 10:50:12)
[GCC 10.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import lammps
>>> lmp = lammps.lammps()
LAMMPS (18 Sep 2020)
using 1 OpenMP thread(s) per MPI task
>>>
.. note::
If you recompile LAMMPS, you will have to also rerun the install step to
ensure the virtual environment contains the latest Python module and shared
library.
.. tab:: Traditional make
Instructions on how to build LAMMPS as a shared library are given on
the :doc:`Build_basics <Build_basics>` doc page. A shared library is
one that is dynamically loadable, which is what Python requires to
wrap LAMMPS. On Linux this is a library file that ends in ``.so``, not
``.a``.
From the src directory, type
.. code-block:: bash
make foo mode=shared
where ``foo`` is the machine target name, such as ``mpi`` or ``serial``.
This should create the file ``liblammps_foo.so`` in the ``src`` directory, as
well as a soft link ``liblammps.so``, which is what the Python wrapper will
load by default. Note that if you are building multiple machine
versions of the shared library, the soft link is always set to the
most recently built version.
.. note::
If you are building LAMMPS with an MPI or FFT library or other
auxiliary libraries (used by various packages), then all of these
extra libraries must also be shared libraries. If the LAMMPS
shared-library build fails with an error complaining about this, see
the :doc:`Build_basics <Build_basics>` doc page.
You can achieve that Python can find these files in one of two ways:
* set two environment variables pointing to the location in the source tree
* run ``make install-python`` or run the ``python/install.py`` script explicitly
When calling ``make install-python`` LAMMPS will try to install the
python module and the shared library into the python site-packages folders;
either the system-wide ones, or the local users ones (in case of insufficient
permissions for the global install). Python will then find the module
and shared library file automatically. The exact location of these folders
depends on your python version and your operating system.
You can override the python version to version x.y when calling
``make`` with ``PYTHON=pythonX.Y``.
If you set the paths to these files as environment variables, you only
have to do it once. For the csh or tcsh shells, add something like
this to your ~/.cshrc file, one line for each of the two files:
.. code-block:: csh
setenv PYTHONPATH ${PYTHONPATH}:/home/sjplimp/lammps/python
setenv LD_LIBRARY_PATH ${LD_LIBRARY_PATH}:/home/sjplimp/lammps/src
On MacOS you may also need to set ``DYLD_LIBRARY_PATH`` accordingly.
For Bourne/Korn shells accordingly into the corresponding files using
the ``export`` shell builtin.
If you use ``make install-python`` or the ``python/install.py`` script, you need
to invoke it every time you rebuild LAMMPS (as a shared library) or
make changes to the ``python/lammps.py`` file, so that the site-packages
files are updated with the new version.
If the default settings of ``make install-python`` are not what you want,
you can invoke ``install.py`` from the python directory manually as
.. code-block:: bash
$ python install.py -m <python module> -l <shared library> -v <version.h file> [-d <pydir>]
* The ``-m`` flag points to the ``lammps.py`` python module file to be installed,
* the ``-l`` flag points to the LAMMPS shared library file to be installed,
* the ``-v`` flag points to the ``version.h`` file in the LAMMPS source
* and the optional ``-d`` flag to a custom (legacy) installation folder
If you use a legacy installation folder, you will need to set your
``PYTHONPATH`` and ``LD_LIBRARY_PATH`` (and/or ``DYLD_LIBRARY_PATH``) environment
variables accordingly, as described above.
Note that if you want Python to be able to load different versions of
the LAMMPS shared library (see :ref:`python_create_lammps`), you will
need to manually copy files like ``liblammps_mpi.so`` into the appropriate
system directory. This is not needed if you set the ``LD_LIBRARY_PATH``
environment variable as described above.
Extending Python to run in parallel
===================================
If you wish to run LAMMPS in parallel from Python, you need to extend
your Python with an interface to MPI. This also allows you to
make MPI calls directly from Python in your script, if you desire.
We have tested this with mpi4py and pypar:
* `MPI for Python <https://mpi4py.readthedocs.io/>`_
* `pypar <https://github.com/daleroberts/pypar>`_
We recommend the use of mpi4py as it is the more complete MPI interface,
and as of version 2.0.0 mpi4py allows passing a custom MPI communicator
to the LAMMPS constructor, which means one can easily run one or more
LAMMPS instances on subsets of the total MPI ranks.
To install mpi4py (version 3.0.3 as of Sep 2020),
.. tabs::
.. tab:: local user
.. code-block:: bash
pip install --user mpi4py
.. tab:: system-wide
.. code-block:: bash
sudo pip install mpi4py
.. tab:: virtual environment
.. code-block:: bash
$ source $HOME/myenv/activate
(myenv)$ pip install mpi4py
.. _mpi4py_install: https://mpi4py.readthedocs.io/en/stable/install.html
For more detailed installation instructions, please see the `mpi4py installation <mpi4py_install>`_ page.
If you have successfully installed mpi4py, you should be able to run
Python and type
.. code-block:: python
from mpi4py import MPI
without error. You should also be able to run Python in parallel
on a simple test script
.. code-block:: bash
$ mpirun -np 4 python test.py
where ``test.py`` contains the lines
.. code-block:: python
from mpi4py import MPI
comm = MPI.COMM_WORLD
print "Proc %d out of %d procs" % (comm.Get_rank(),comm.Get_size())
and see one line of output for each processor you run on.
.. note::
To use mpi4py and LAMMPS in parallel from Python, you must
insure both are using the same version of MPI. If you only have one
MPI installed on your system, this is not an issue, but it can be if
you have multiple MPIs. Your LAMMPS build is explicit about which MPI
it is using, since you specify the details in your low-level
src/MAKE/Makefile.foo file. mpi4py uses the "mpicc" command to find
information about the MPI it uses to build against. And it tries to
load "libmpi.so" from the ``LD_LIBRARY_PATH``. This may or may not find
the MPI library that LAMMPS is using. If you have problems running
both mpi4py and LAMMPS together, this is an issue you may need to
address, e.g. by moving other MPI installations so that mpi4py finds
the right one.
Note that if you want Python to be able to load different versions of
the LAMMPS shared library (see :doc:`this section <Python_shlib>`), you will
need to manually copy files like liblammps_g++.so into the appropriate
system directory. This is not needed if you set the LD_LIBRARY_PATH
environment variable as described above.

View File

@ -28,278 +28,8 @@ There are multiple Python interface classes in the :py:mod:`lammps` module:
----------
Setting up a Python virtual environment
***************************************
LAMMPS and its Python module can be installed together into a Python virtual
environment. This lets you isolate your customized Python environment from
your user or system installation. The following is a minimal working example:
.. code-block:: bash
# create and change into build directory
mkdir build
cd build
# create virtual environment
virtualenv myenv
# Add venv lib folder to LD_LIBRARY_PATH when activating it
echo 'export LD_LIBRARY_PATH=$VIRTUAL_ENV/lib:$LD_LIBRARY_PATH' >> myenv/bin/activate
# Add LAMMPS_POTENTIALS path when activating venv
echo 'export LAMMPS_POTENTIALS=$VIRTUAL_ENV/share/lammps/potentials' >> myenv/bin/activate
# activate environment
source myenv/bin/activate
# configure LAMMPS compilation
# compiles as shared library with PYTHON package and C++ exceptions
# and installs into myvenv
(myenv)$ cmake -C ../cmake/presets/minimal.cmake \
-D BUILD_SHARED_LIBS=on \
-D PKG_PYTHON=on \
-D LAMMPS_EXCEPTIONS=on \
-D CMAKE_INSTALL_PREFIX=$VIRTUAL_ENV \
../cmake
# compile LAMMPS
(myenv)$ cmake --build . --parallel
# install LAMMPS into myvenv
(myenv)$ cmake --install .
Creating or deleting a LAMMPS object
************************************
With the Python interface the creation of a :cpp:class:`LAMMPS
<LAMMPS_NS::LAMMPS>` instance is included in the constructors for the
:py:meth:`lammps <lammps.lammps.__init__()>`, :py:meth:`PyLammps <lammps.PyLammps.__init__()>`,
and :py:meth:`PyLammps <lammps.IPyLammps.__init__()>` classes.
Internally it will call either :cpp:func:`lammps_open` or :cpp:func:`lammps_open_no_mpi` from the C
library API to create the class instance.
All arguments are optional. The *name* argument allows loading a
LAMMPS shared library that is named ``liblammps_machine.so`` instead of
the default name of ``liblammps.so``. In most cases the latter will be
installed or used. The *ptr* argument is for use of the
:py:mod:`lammps` module from inside a LAMMPS instance, e.g. with the
:doc:`python <python>` command, where a pointer to the already existing
:cpp:class:`LAMMPS <LAMMPS_NS::LAMMPS>` class instance can be passed
to the Python class and used instead of creating a new instance. The
*comm* argument may be used in combination with the `mpi4py <mpi4py_url_>`_
module to pass an MPI communicator to LAMMPS and thus it is possible
to run the Python module like the library interface on a subset of the
MPI ranks after splitting the communicator.
Here are simple examples using all three Python interfaces:
.. tabs::
.. tab:: lammps API
.. code-block:: python
from lammps import lammps
# NOTE: argv[0] is set by the lammps class constructor
args = ["-log", "none"]
# create LAMMPS instance
lmp = lammps(cmdargs=args)
# get and print numerical version code
print("LAMMPS Version: ", lmp.version())
# explicitly close and delete LAMMPS instance (optional)
lmp.close()
.. tab:: PyLammps API
The :py:class:`PyLammps` class is a wrapper around the
:py:class:`lammps` class and all of its lower level functions.
By default, it will create a new instance of :py:class:`lammps` passing
along all arguments to the constructor of :py:class:`lammps`.
.. code-block:: python
from lammps import PyLammps
# NOTE: argv[0] is set by the lammps class constructor
args = ["-log", "none"]
# create LAMMPS instance
L = PyLammps(cmdargs=args)
# get and print numerical version code
print("LAMMPS Version: ", L.version())
# explicitly close and delete LAMMPS instance (optional)
L.close()
:py:class:`PyLammps` objects can also be created on top of an existing :py:class:`lammps` object:
.. code-block:: Python
from lammps import lammps, PyLammps
...
# create LAMMPS instance
lmp = lammps(cmdargs=args)
# create PyLammps instance using previously created LAMMPS instance
L = PyLammps(ptr=lmp)
This is useful if you have to create the :py:class:`lammps <lammps.lammps>`
instance is a specific way, but want to take advantage of the
:py:class:`PyLammps <lammps.PyLammps>` interface.
.. tab:: IPyLammps API
The :py:class:`IPyLammps` class is an extension of the
:py:class:`PyLammps` class. It has the same construction behavior. By
default, it will create a new instance of :py:class:`lammps` passing
along all arguments to the constructor of :py:class:`lammps`.
.. code-block:: python
from lammps import IPyLammps
# NOTE: argv[0] is set by the lammps class constructor
args = ["-log", "none"]
# create LAMMPS instance
L = IPyLammps(cmdargs=args)
# get and print numerical version code
print("LAMMPS Version: ", L.version())
# explicitly close and delete LAMMPS instance (optional)
L.close()
You can also initialize IPyLammps on top of an existing :py:class:`lammps` or :py:class:`PyLammps` object:
.. code-block:: Python
from lammps import lammps, IPyLammps
...
# create LAMMPS instance
lmp = lammps(cmdargs=args)
# create PyLammps instance using previously created LAMMPS instance
L = PyLammps(ptr=lmp)
This is useful if you have to create the :py:class:`lammps <lammps.lammps>`
instance is a specific way, but want to take advantage of the
:py:class:`IPyLammps <lammps.IPyLammps>` interface.
In all of the above cases, same as with the :ref:`C library API <lammps_c_api>`, this will use the
``MPI_COMM_WORLD`` communicator for the MPI library that LAMMPS was
compiled with. The :py:func:`lmp.close() <lammps.lammps.close>` call is
optional since the LAMMPS class instance will also be deleted
automatically during the :py:class:`lammps <lammps.lammps>` class
destructor.
Executing LAMMPS commands
*************************
Once an instance of the :py:class:`lammps`, :py:class:`PyLammps`, or
:py:class:`IPyLammps` class is created, there are multiple ways to "feed" it
commands. In a way that is not very different from running a LAMMPS input
script, except that Python has many more facilities for structured
programming than the LAMMPS input script syntax. Furthermore it is possible
to "compute" what the next LAMMPS command should be.
.. tabs::
.. tab:: lammps API
Same as in the equivalent
:doc:`C library functions <Library_execute>`, commands can be read from a file, a
single string, a list of strings and a block of commands in a single
multi-line string. They are processed under the same boundary conditions
as the C library counterparts. The example below demonstrates the use
of :py:func:`lammps.file`, :py:func:`lammps.command`,
:py:func:`lammps.commands_list`, and :py:func:`lammps.commands_string`:
.. code-block:: python
from lammps import lammps
lmp = lammps()
# read commands from file 'in.melt'
lmp.file('in.melt')
# issue a single command
lmp.command('variable zpos index 1.0')
# create 10 groups with 10 atoms each
cmds = ["group g{} id {}:{}".format(i,10*i+1,10*(i+1)) for i in range(10)]
lmp.commands_list(cmds)
# run commands from a multi-line string
block = """
clear
region box block 0 2 0 2 0 2
create_box 1 box
create_atoms 1 single 1.0 1.0 ${zpos}
"""
lmp.commands_string(block)
.. tab:: PyLammps/IPyLammps API
Unlike the lammps API, the PyLammps/IPyLammps APIs allow running LAMMPS
commands by calling equivalent member functions.
For instance, the following LAMMPS command
.. code-block:: LAMMPS
region box block 0 10 0 5 -0.5 0.5
can be executed using the following Python code if *L* is a :py:class:`lammps` instance:
.. code-block:: Python
L.command("region box block 0 10 0 5 -0.5 0.5")
With the PyLammps interface, any LAMMPS command can be split up into arbitrary parts.
These parts are then passed to a member function with the name of the command.
For the ``region`` command that means the :code:`region` method can be called.
The arguments of the command can be passed as one string, or
individually.
.. code-block:: Python
L.region("box block", 0, 10, 0, 5, -0.5, 0.5)
In this example all parameters except the first are Python floating-point literals. The
PyLammps interface takes the entire parameter list and transparently
merges it to a single command string.
The benefit of this approach is avoiding redundant command calls and easier
parameterization. In the original interface parameterization this needed to be done
manually by creating formatted strings.
.. code-block:: Python
L.command("region box block %f %f %f %f %f %f" % (xlo, xhi, ylo, yhi, zlo, zhi))
In contrast, methods of PyLammps accept parameters directly and will convert
them automatically to a final command string.
.. code-block:: Python
L.region("box block", xlo, xhi, ylo, yhi, zlo, zhi)
Using these facilities, the example shown for the lammps API can be rewritten as follows:
.. code-block:: python
from lammps import PyLammps
L = PyLammps()
# read commands from file 'in.melt'
L.file('in.melt')
# issue a single command
L.variable('zpos', 'index', 1.0)
# create 10 groups with 10 atoms each
for i in range(10):
L.group(f"g{i}", "id", f"{10*i+1}:{10*(i+1)}")
L.clear()
L.region("box block", 0, 2, 0, 2, 0, 2)
L.create_box(1, "box")
L.create_atoms(1, "single", 1.0, 1.0, "${zpos}")
----------
The ``lammps`` class API
************************
========================
The :py:class:`lammps <lammps.lammps>` class is the core of the LAMMPS
Python interfaces. It is a wrapper around the :ref:`LAMMPS C library
@ -317,7 +47,7 @@ functions. Below is a detailed documentation of the API.
----------
The ``PyLammps`` class API
**************************
==========================
The :py:class:`PyLammps <lammps.PyLammps>` class is a wrapper that creates a
simpler, more "Pythonic" interface to common LAMMPS functionality. LAMMPS
@ -340,7 +70,7 @@ scripts shorter and more concise. See the :doc:`PyLammps Tutorial
----------
The ``IPyLammps`` class API
***************************
===========================
The :py:class:`IPyLammps <lammps.PyLammps>` class is an extension of
:py:class:`PyLammps <lammps.PyLammps>`, adding additional functions to
@ -353,7 +83,7 @@ See the :doc:`PyLammps Tutorial <Howto_pylammps>` for examples.
----------
Additional components of the ``lammps`` module
**********************************************
==============================================
The :py:mod:`lammps` module additionally contains several constants
and the :py:class:`NeighList <lammps.NeighList>` class:
@ -415,20 +145,3 @@ Classes representing internal objects
.. autoclass:: lammps.NeighList
:members:
:no-undoc-members:
LAMMPS error handling in Python
*******************************
Compiling the shared library with :ref:`C++ exception support <exceptions>` provides a better error
handling experience. Without exceptions the LAMMPS code will terminate the
current Python process with an error message. C++ exceptions allow capturing
them on the C++ side and rethrowing them on the Python side. This way
LAMMPS errors can be handled through the Python exception handling mechanism.
.. warning::
Capturing a LAMMPS exception in Python can still mean that the
current LAMMPS process is in an illegal state and must be terminated. It is
advised to save your data and terminate the Python instance as quickly as
possible.

View File

@ -1,71 +0,0 @@
Extending Python to run in parallel
===================================
If you wish to run LAMMPS in parallel from Python, you need to extend
your Python with an interface to MPI. This also allows you to
make MPI calls directly from Python in your script, if you desire.
We have tested this with mpi4py and pypar:
* `MPI for Python <https://mpi4py.readthedocs.io/>`_
* `pypar <https://github.com/daleroberts/pypar>`_
We recommend the use of mpi4py as it is the more complete MPI interface,
and as of version 2.0.0 mpi4py allows passing a custom MPI communicator
to the LAMMPS constructor, which means one can easily run one or more
LAMMPS instances on subsets of the total MPI ranks.
To install mpi4py (version mpi4py-3.0.3 as of Nov 2019), unpack it
and from its main directory, type
.. code-block:: bash
python setup.py build
sudo python setup.py install
Again, the "sudo" is only needed if required to copy mpi4py files into
your Python distribution's site-packages directory. To install with
user privilege into the user local directory type
.. code-block:: bash
python setup.py install --user
If you have successfully installed mpi4py, you should be able to run
Python and type
.. code-block:: python
from mpi4py import MPI
without error. You should also be able to run python in parallel
on a simple test script
.. code-block:: bash
% mpirun -np 4 python test.py
where test.py contains the lines
.. code-block:: python
from mpi4py import MPI
comm = MPI.COMM_WORLD
print "Proc %d out of %d procs" % (comm.Get_rank(),comm.Get_size())
and see one line of output for each processor you run on.
.. note::
To use mpi4py and LAMMPS in parallel from Python, you must
insure both are using the same version of MPI. If you only have one
MPI installed on your system, this is not an issue, but it can be if
you have multiple MPIs. Your LAMMPS build is explicit about which MPI
it is using, since you specify the details in your low-level
src/MAKE/Makefile.foo file. Mpi4py uses the "mpicc" command to find
information about the MPI it uses to build against. And it tries to
load "libmpi.so" from the LD_LIBRARY_PATH. This may or may not find
the MPI library that LAMMPS is using. If you have problems running
both mpi4py and LAMMPS together, this is an issue you may need to
address, e.g. by moving other MPI installations so that mpi4py finds
the right one.

View File

@ -1,5 +1,37 @@
Overview of Python and LAMMPS
=============================
Overview
========
The LAMMPS distribution includes a python directory with all you need
to run LAMMPS from Python. The python/lammps.py file wraps the LAMMPS
library interface, with one wrapper function per LAMMPS library
function. This file makes it is possible to do the following either
from a Python script, or interactively from a Python prompt: create
one or more instances of LAMMPS, invoke LAMMPS commands or give it an
input script, run LAMMPS incrementally, extract LAMMPS results, an
modify internal LAMMPS variables. From a Python script you can do
this in serial or parallel. Running Python interactively in parallel
does not generally work, unless you have a version of Python that
extends Python to enable multiple instances of Python to read what you
type.
To do all of this, you must first build LAMMPS as a shared library,
then insure that your Python can find the python/lammps.py file and
the shared library.
The Python wrapper for LAMMPS uses the "ctypes" package in Python,
which auto-generates the interface code needed between Python and a
set of C-style library functions. Ctypes is part of standard Python
for versions 2.5 and later. You can check which version of Python you
have by simply typing "python" at a shell prompt.
.. warning:: Python 2 support is deprecated
While the LAMMPS Python module was originally developed to support both
Python 2 and 3, Python 2 is no longer maintained as of `January 1, 2020 <https://www.python.org/doc/sunset-python-2/>`_.
Therefore, we will no longer backport any new features to Python 2 and
highly recommend using Python versions 3.6+.
---------
LAMMPS can work together with Python in three ways. First, Python can
wrap LAMMPS through the its :doc:`library interface <Howto_library>`, so
@ -7,14 +39,25 @@ that a Python script can create one or more instances of LAMMPS and
launch one or more simulations. In Python lingo, this is called
"extending" Python with a LAMMPS module.
Second, a lower-level Python interface can be used indirectly through
the provided PyLammps and IPyLammps wrapper classes, written in Python.
.. figure:: JPG/python-invoke-lammps.png
:figclass: align-center
Launching LAMMPS via Python
Second, the lower-level Python interface can be used indirectly through
the provided :code`PyLammps` and :code:`IPyLammps` wrapper classes, written in Python.
These wrappers try to simplify the usage of LAMMPS in Python by
providing an object-based interface to common LAMMPS functionality.
They also reduces the amount of code necessary to parameterize LAMMPS
scripts through Python and make variables and computes directly
accessible.
.. figure:: JPG/pylammps-invoke-lammps.png
:figclass: align-center
Using the PyLammps / IPyLammps wrappers
Third, LAMMPS can use the Python interpreter, so that a LAMMPS
input script or styles can invoke Python code directly, and pass
information back-and-forth between the input script and Python
@ -23,3 +66,8 @@ to query or change its attributes through the LAMMPS Python module
mentioned above. In Python lingo, this is "embedding" Python in
LAMMPS. When used in this mode, Python can perform script operations
that the simple LAMMPS input script syntax can not.
.. figure:: JPG/lammps-invoke-python.png
:figclass: align-center
Calling Python code from LAMMPS

View File

@ -1,5 +0,0 @@
PyLammps interface
==================
PyLammps is a Python wrapper class which can be created on its own or
use an existing lammps Python object. It has its own :doc:`Howto pylammps <Howto_pylammps>` doc page.

View File

@ -1,32 +1,118 @@
Run LAMMPS from Python
======================
The LAMMPS distribution includes a python directory with all you need
to run LAMMPS from Python. The python/lammps.py file wraps the LAMMPS
library interface, with one wrapper function per LAMMPS library
function. This file makes it is possible to do the following either
from a Python script, or interactively from a Python prompt: create
one or more instances of LAMMPS, invoke LAMMPS commands or give it an
input script, run LAMMPS incrementally, extract LAMMPS results, an
modify internal LAMMPS variables. From a Python script you can do
this in serial or parallel. Running Python interactively in parallel
does not generally work, unless you have a version of Python that
extends Python to enable multiple instances of Python to read what you
type.
Running LAMMPS and Python in serial:
-------------------------------------
To do all of this, you must first build LAMMPS as a shared library,
then insure that your Python can find the python/lammps.py file and
the shared library.
To run a LAMMPS in serial, type these lines into Python
interactively from the bench directory:
Two advantages of using Python to run LAMMPS are how concise the
language is, and that it can be run interactively, enabling rapid
development and debugging. If you use it to mostly invoke costly
operations within LAMMPS, such as running a simulation for a
reasonable number of timesteps, then the overhead cost of invoking
LAMMPS through Python will be negligible.
.. parsed-literal::
The Python wrapper for LAMMPS uses the "ctypes" package in Python,
which auto-generates the interface code needed between Python and a
set of C-style library functions. Ctypes is part of standard Python
for versions 2.5 and later. You can check which version of Python you
have by simply typing "python" at a shell prompt.
>>> from lammps import lammps
>>> lmp = lammps()
>>> lmp.file("in.lj")
Or put the same lines in the file ``test.py`` and run it as
.. code-block:: bash
% python test.py
Either way, you should see the results of running the ``in.lj`` benchmark
on a single processor appear on the screen, the same as if you had
typed something like:
.. parsed-literal::
lmp_serial -in in.lj
Test LAMMPS and Python in parallel:
---------------------------------------
To run LAMMPS in parallel, assuming you have installed the
`PyPar <https://github.com/daleroberts/pypar>`_ package as discussed
above, create a ``test.py`` file containing these lines:
.. code-block:: python
import pypar
from lammps import lammps
lmp = lammps()
lmp.file("in.lj")
print "Proc %d out of %d procs has" % (pypar.rank(),pypar.size()),lmp
pypar.finalize()
To run LAMMPS in parallel, assuming you have installed the
`mpi4py <https://mpi4py.readthedocs.io>`_ package as discussed
above, create a ``test.py`` file containing these lines:
.. code-block:: python
from mpi4py import MPI
from lammps import lammps
lmp = lammps()
lmp.file("in.lj")
me = MPI.COMM_WORLD.Get_rank()
nprocs = MPI.COMM_WORLD.Get_size()
print "Proc %d out of %d procs has" % (me,nprocs),lmp
MPI.Finalize()
You can run either script in parallel as:
.. code-block:: bash
$ mpirun -np 4 python test.py
and you should see the same output as if you had typed
.. code-block:: bash
$ mpirun -np 4 lmp_mpi -in in.lj
Note that if you leave out the 3 lines from ``test.py`` that specify PyPar
commands you will instantiate and run LAMMPS independently on each of
the :math:`P` processors specified in the mpirun command. In this case you
should get 4 sets of output, each showing that a LAMMPS run was made
on a single processor, instead of one set of output showing that
LAMMPS ran on 4 processors. If the 1-processor outputs occur, it
means that PyPar is not working correctly.
Also note that once you import the PyPar module, PyPar initializes MPI
for you, and you can use MPI calls directly in your Python script, as
described in the PyPar documentation. The last line of your Python
script should be ``pypar.finalize()``, to insure MPI is shut down
correctly.
Running Python scripts:
---------------------------
Note that any Python script (not just for LAMMPS) can be invoked in
one of several ways:
.. code-block:: bash
$ python script.py
$ python -i script.py
$ ./script.py
The last command requires that the first line of the script be
something like this:
.. code-block:: bash
#!/usr/bin/python
#!/usr/bin/python -i
where the path points to where you have Python installed, and that you
have made the script file executable:
.. code-block:: bash
$ chmod +x script.py
Without the ``-i`` flag, Python will exit when the script finishes.
With the ``-i`` flag, you will be left in the Python interpreter when
the script finishes, so you can type subsequent commands. As
mentioned above, you can only run Python interactively when running
Python on a single processor, not in parallel.

View File

@ -1,78 +0,0 @@
Build LAMMPS as a shared library
================================
.. TODO this is mostly redundant and should be addressed in the 'progguide' branch if it has not already
Build LAMMPS as a shared library using make
-------------------------------------------
Instructions on how to build LAMMPS as a shared library are given on
the :doc:`Build_basics <Build_basics>` doc page. A shared library is
one that is dynamically loadable, which is what Python requires to
wrap LAMMPS. On Linux this is a library file that ends in ".so", not
".a".
From the src directory, type
.. code-block:: bash
make foo mode=shared
where foo is the machine target name, such as mpi or serial.
This should create the file liblammps_foo.so in the src directory, as
well as a soft link liblammps.so, which is what the Python wrapper will
load by default. Note that if you are building multiple machine
versions of the shared library, the soft link is always set to the
most recently built version.
.. note::
If you are building LAMMPS with an MPI or FFT library or other
auxiliary libraries (used by various packages), then all of these
extra libraries must also be shared libraries. If the LAMMPS
shared-library build fails with an error complaining about this, see
the :doc:`Build_basics <Build_basics>` doc page.
Build LAMMPS as a shared library using CMake
--------------------------------------------
When using CMake the following two options are necessary to generate the LAMMPS
shared library:
.. code-block:: bash
-D BUILD_SHARED_LIBS=on # enable building of LAMMPS shared library (both options are needed!)
What this does is create a liblammps.so which contains the majority of LAMMPS
code. The generated lmp binary also dynamically links to this library. This
means that either this liblammps.so file has to be in the same directory, a system
library path (e.g. /usr/lib64/) or in the LD_LIBRARY_PATH.
If you want to use the shared library with Python the recommended way is to create a virtualenv and use it as
CMAKE_INSTALL_PREFIX.
.. code-block:: bash
# create virtualenv
virtualenv --python=$(which python3) myenv3
source myenv3/bin/activate
# build library
mkdir build
cd build
cmake -D PKG_PYTHON=on -D BUILD_SHARED_LIBS=on -D CMAKE_INSTALL_PREFIX=$VIRTUAL_ENV ../cmake
make -j 4
# install into prefix
make install
This will also install the Python module into your virtualenv. Since virtualenv
does not change your LD_LIBRARY_PATH, you still need to add its lib64 folder to
it, which contains the installed liblammps.so.
.. code-block:: bash
export LD_LIBRARY_PATH=$VIRTUAL_ENV/lib64:$LD_LIBRARY_PATH
Starting Python outside (!) of your build directory, but with the virtualenv
enabled and with the LD_LIBRARY_PATH set gives you access to LAMMPS via Python.

View File

@ -1,152 +0,0 @@
Test the Python/LAMMPS interface
================================
To test if LAMMPS is callable from Python, launch Python interactively
and type:
.. parsed-literal::
>>> from lammps import lammps
>>> lmp = lammps()
If you get no errors, you're ready to use LAMMPS from Python. If the
second command fails, the most common error to see is
.. parsed-literal::
OSError: Could not load LAMMPS dynamic library
which means Python was unable to load the LAMMPS shared library. This
typically occurs if the system can't find the LAMMPS shared library or
one of the auxiliary shared libraries it depends on, or if something
about the library is incompatible with your Python. The error message
should give you an indication of what went wrong.
You can also test the load directly in Python as follows, without
first importing from the lammps.py file:
.. parsed-literal::
>>> from ctypes import CDLL
>>> CDLL("liblammps.so")
If an error occurs, carefully go through the steps on the
:doc:`Build_basics <Build_basics>` doc page about building a shared
library and the :doc:`Python_install <Python_install>` doc page about
insuring Python can find the necessary two files it needs.
Test LAMMPS and Python in serial:
-------------------------------------
To run a LAMMPS test in serial, type these lines into Python
interactively from the bench directory:
.. parsed-literal::
>>> from lammps import lammps
>>> lmp = lammps()
>>> lmp.file("in.lj")
Or put the same lines in the file test.py and run it as
.. code-block:: bash
% python test.py
Either way, you should see the results of running the in.lj benchmark
on a single processor appear on the screen, the same as if you had
typed something like:
.. parsed-literal::
lmp_g++ -in in.lj
Test LAMMPS and Python in parallel:
---------------------------------------
To run LAMMPS in parallel, assuming you have installed the
`PyPar <https://github.com/daleroberts/pypar>`_ package as discussed
above, create a test.py file containing these lines:
.. code-block:: python
import pypar
from lammps import lammps
lmp = lammps()
lmp.file("in.lj")
print "Proc %d out of %d procs has" % (pypar.rank(),pypar.size()),lmp
pypar.finalize()
To run LAMMPS in parallel, assuming you have installed the
`mpi4py <https://mpi4py.readthedocs.io>`_ package as discussed
above, create a test.py file containing these lines:
.. code-block:: python
from mpi4py import MPI
from lammps import lammps
lmp = lammps()
lmp.file("in.lj")
me = MPI.COMM_WORLD.Get_rank()
nprocs = MPI.COMM_WORLD.Get_size()
print "Proc %d out of %d procs has" % (me,nprocs),lmp
MPI.Finalize()
You can either script in parallel as:
.. code-block:: bash
% mpirun -np 4 python test.py
and you should see the same output as if you had typed
.. code-block:: bash
% mpirun -np 4 lmp_g++ -in in.lj
Note that if you leave out the 3 lines from test.py that specify PyPar
commands you will instantiate and run LAMMPS independently on each of
the P processors specified in the mpirun command. In this case you
should get 4 sets of output, each showing that a LAMMPS run was made
on a single processor, instead of one set of output showing that
LAMMPS ran on 4 processors. If the 1-processor outputs occur, it
means that PyPar is not working correctly.
Also note that once you import the PyPar module, PyPar initializes MPI
for you, and you can use MPI calls directly in your Python script, as
described in the PyPar documentation. The last line of your Python
script should be pypar.finalize(), to insure MPI is shut down
correctly.
Running Python scripts:
---------------------------
Note that any Python script (not just for LAMMPS) can be invoked in
one of several ways:
.. code-block:: bash
% python foo.script
% python -i foo.script
% foo.script
The last command requires that the first line of the script be
something like this:
.. code-block:: bash
#!/usr/local/bin/python
#!/usr/local/bin/python -i
where the path points to where you have Python installed, and that you
have made the script file executable:
.. code-block:: bash
% chmod +x foo.script
Without the "-i" flag, Python will exit when the script finishes.
With the "-i" flag, you will be left in the Python interpreter when
the script finishes, so you can type subsequent commands. As
mentioned above, you can only run Python interactively when running
Python on a single processor, not in parallel.

View File

@ -0,0 +1,44 @@
Troubleshooting
***************
Testing if Python can launch LAMMPS
===================================
To test if LAMMPS is callable from Python, launch Python interactively
and type:
.. code-block:: python
>>> from lammps import lammps
>>> lmp = lammps()
If you get no errors, you're ready to use LAMMPS from Python. If the
second command fails, the most common error to see is
.. code-block:: bash
OSError: Could not load LAMMPS dynamic library
which means Python was unable to load the LAMMPS shared library. This
typically occurs if the system can't find the LAMMPS shared library or
one of the auxiliary shared libraries it depends on, or if something
about the library is incompatible with your Python. The error message
should give you an indication of what went wrong.
If your shared library uses a suffix, such as ``liblammps_mpi.so``, change
the constructor call as follows (see :ref:`python_create_lammps` for more details):
.. code-block:: python
>>> lmp = lammps(name='mpi')
You can also test the load directly in Python as follows, without
first importing from the lammps.py file:
.. code-block:: python
>>> from ctypes import CDLL
>>> CDLL("liblammps.so")
If an error occurs, carefully go through the steps in :ref:`python_install_guides` and on the
:doc:`Build_basics <Build_basics>` doc page about building a shared library.

View File

@ -1,25 +1,126 @@
Python library interface
========================
.. _mpi4py_url: https://mpi4py.readthedocs.io/
As described previously, the Python interface to LAMMPS consists of a
Python "lammps" module, the source code for which is in
python/lammps.py, which creates a "lammps" object, with a set of
methods that can be invoked on that object. The sample Python code
below assumes you have first imported the "lammps" module in your
Python script, as follows:
.. _python_create_lammps:
.. code-block:: Python
Creating or deleting a LAMMPS object
************************************
from lammps import lammps
With the Python interface the creation of a :cpp:class:`LAMMPS
<LAMMPS_NS::LAMMPS>` instance is included in the constructors for the
:py:meth:`lammps <lammps.lammps.__init__()>`, :py:meth:`PyLammps <lammps.PyLammps.__init__()>`,
and :py:meth:`PyLammps <lammps.IPyLammps.__init__()>` classes.
Internally it will call either :cpp:func:`lammps_open` or :cpp:func:`lammps_open_no_mpi` from the C
library API to create the class instance.
These are the methods defined by the lammps module. If you look at
the files src/library.cpp and src/library.h you will see they
correspond one-to-one with calls you can make to the LAMMPS library
from a C++ or C or Fortran program, and which are described on the
:doc:`Howto library <Howto_library>` doc page.
All arguments are optional. The *name* argument allows loading a
LAMMPS shared library that is named ``liblammps_machine.so`` instead of
the default name of ``liblammps.so``. In most cases the latter will be
installed or used. The *ptr* argument is for use of the
:py:mod:`lammps` module from inside a LAMMPS instance, e.g. with the
:doc:`python <python>` command, where a pointer to the already existing
:cpp:class:`LAMMPS <LAMMPS_NS::LAMMPS>` class instance can be passed
to the Python class and used instead of creating a new instance. The
*comm* argument may be used in combination with the `mpi4py <mpi4py_url_>`_
module to pass an MPI communicator to LAMMPS and thus it is possible
to run the Python module like the library interface on a subset of the
MPI ranks after splitting the communicator.
The python/examples directory has Python scripts which show how Python
can run LAMMPS, grab data, change it, and put it back into LAMMPS.
Here are simple examples using all three Python interfaces:
.. tabs::
.. tab:: lammps API
.. code-block:: python
from lammps import lammps
# NOTE: argv[0] is set by the lammps class constructor
args = ["-log", "none"]
# create LAMMPS instance
lmp = lammps(cmdargs=args)
# get and print numerical version code
print("LAMMPS Version: ", lmp.version())
# explicitly close and delete LAMMPS instance (optional)
lmp.close()
.. tab:: PyLammps API
The :py:class:`PyLammps` class is a wrapper around the
:py:class:`lammps` class and all of its lower level functions.
By default, it will create a new instance of :py:class:`lammps` passing
along all arguments to the constructor of :py:class:`lammps`.
.. code-block:: python
from lammps import PyLammps
# NOTE: argv[0] is set by the lammps class constructor
args = ["-log", "none"]
# create LAMMPS instance
L = PyLammps(cmdargs=args)
# get and print numerical version code
print("LAMMPS Version: ", L.version())
# explicitly close and delete LAMMPS instance (optional)
L.close()
:py:class:`PyLammps` objects can also be created on top of an existing :py:class:`lammps` object:
.. code-block:: Python
from lammps import lammps, PyLammps
...
# create LAMMPS instance
lmp = lammps(cmdargs=args)
# create PyLammps instance using previously created LAMMPS instance
L = PyLammps(ptr=lmp)
This is useful if you have to create the :py:class:`lammps <lammps.lammps>`
instance is a specific way, but want to take advantage of the
:py:class:`PyLammps <lammps.PyLammps>` interface.
.. tab:: IPyLammps API
The :py:class:`IPyLammps` class is an extension of the
:py:class:`PyLammps` class. It has the same construction behavior. By
default, it will create a new instance of :py:class:`lammps` passing
along all arguments to the constructor of :py:class:`lammps`.
.. code-block:: python
from lammps import IPyLammps
# NOTE: argv[0] is set by the lammps class constructor
args = ["-log", "none"]
# create LAMMPS instance
L = IPyLammps(cmdargs=args)
# get and print numerical version code
print("LAMMPS Version: ", L.version())
# explicitly close and delete LAMMPS instance (optional)
L.close()
You can also initialize IPyLammps on top of an existing :py:class:`lammps` or :py:class:`PyLammps` object:
.. code-block:: Python
from lammps import lammps, IPyLammps
...
# create LAMMPS instance
lmp = lammps(cmdargs=args)
# create PyLammps instance using previously created LAMMPS instance
L = PyLammps(ptr=lmp)
This is useful if you have to create the :py:class:`lammps <lammps.lammps>`
instance is a specific way, but want to take advantage of the
:py:class:`IPyLammps <lammps.IPyLammps>` interface.
In all of the above cases, same as with the :ref:`C library API <lammps_c_api>`, this will use the
``MPI_COMM_WORLD`` communicator for the MPI library that LAMMPS was
compiled with. The :py:func:`lmp.close() <lammps.lammps.close>` call is
optional since the LAMMPS class instance will also be deleted
automatically during the :py:class:`lammps <lammps.lammps>` class
destructor.
.. code-block:: Python
@ -32,67 +133,6 @@ can run LAMMPS, grab data, change it, and put it back into LAMMPS.
lmp.close() # destroy a LAMMPS object
version = lmp.version() # return the numerical version id, e.g. LAMMPS 2 Sep 2015 -> 20150902
lmp.file(file) # run an entire input script, file = "in.lj"
lmp.command(cmd) # invoke a single LAMMPS command, cmd = "run 100"
lmp.commands_list(cmdlist) # invoke commands in cmdlist = **"run 10", "run 20"**
lmp.commands_string(multicmd) # invoke commands in multicmd = "run 10\nrun 20"
size = lmp.extract_setting(name) # return data type info
xlo = lmp.extract_global(name,type) # extract a global quantity
# name = "boxxlo", "nlocal", etc
# type = 0 = int
# 1 = double
boxlo,boxhi,xy,yz,xz,periodicity,box_change = lmp.extract_box() # extract box info
coords = lmp.extract_atom(name,type) # extract a per-atom quantity
# name = "x", "type", etc
# type = 0 = vector of ints
# 1 = array of ints
# 2 = vector of doubles
# 3 = array of doubles
eng = lmp.extract_compute(id,style,type) # extract value(s) from a compute
v3 = lmp.extract_fix(id,style,type,i,j) # extract value(s) from a fix
# id = ID of compute or fix
# style = 0 = global data
# 1 = per-atom data
# 2 = local data
# type = 0 = scalar
# 1 = vector
# 2 = array
# i,j = indices of value in global vector or array
var = lmp.extract_variable(name,group,flag) # extract value(s) from a variable
# name = name of variable
# group = group ID (ignored for equal-style variables)
# flag = 0 = equal-style variable
# 1 = atom-style variable
value = lmp.get_thermo(name) # return current value of a thermo keyword
natoms = lmp.get_natoms() # total # of atoms as int
flag = lmp.set_variable(name,value) # set existing named string-style variable to value, flag = 0 if successful
lmp.reset_box(boxlo,boxhi,xy,yz,xz) # reset the simulation box size
data = lmp.gather_atoms(name,type,count) # return per-atom property of all atoms gathered into data, ordered by atom ID
# name = "x", "charge", "type", etc
data = lmp.gather_atoms_concat(name,type,count) # ditto, but concatenated atom values from each proc (unordered)
data = lmp.gather_atoms_subset(name,type,count,ndata,ids) # ditto, but for subset of Ndata atoms with IDs
lmp.scatter_atoms(name,type,count,data) # scatter per-atom property to all atoms from data, ordered by atom ID
# name = "x", "charge", "type", etc
# count = # of per-atom values, 1 or 3, etc
lmp.scatter_atoms_subset(name,type,count,ndata,ids,data) # ditto, but for subset of Ndata atoms with IDs
lmp.create_atoms(n,ids,types,x,v,image,shrinkexceed) # create N atoms with IDs, types, x, v, and image flags
----------
The lines
.. code-block:: Python
@ -135,10 +175,163 @@ script, and coordinate and run multiple simulations, e.g.
lmp1.file("in.file1")
lmp2.file("in.file2")
Executing LAMMPS commands
*************************
Once an instance of the :py:class:`lammps`, :py:class:`PyLammps`, or
:py:class:`IPyLammps` class is created, there are multiple ways to "feed" it
commands. In a way that is not very different from running a LAMMPS input
script, except that Python has many more facilities for structured
programming than the LAMMPS input script syntax. Furthermore it is possible
to "compute" what the next LAMMPS command should be.
.. tabs::
.. tab:: lammps API
Same as in the equivalent
:doc:`C library functions <Library_execute>`, commands can be read from a file, a
single string, a list of strings and a block of commands in a single
multi-line string. They are processed under the same boundary conditions
as the C library counterparts. The example below demonstrates the use
of :py:func:`lammps.file`, :py:func:`lammps.command`,
:py:func:`lammps.commands_list`, and :py:func:`lammps.commands_string`:
.. code-block:: python
from lammps import lammps
lmp = lammps()
# read commands from file 'in.melt'
lmp.file('in.melt')
# issue a single command
lmp.command('variable zpos index 1.0')
# create 10 groups with 10 atoms each
cmds = ["group g{} id {}:{}".format(i,10*i+1,10*(i+1)) for i in range(10)]
lmp.commands_list(cmds)
# run commands from a multi-line string
block = """
clear
region box block 0 2 0 2 0 2
create_box 1 box
create_atoms 1 single 1.0 1.0 ${zpos}
"""
lmp.commands_string(block)
.. tab:: PyLammps/IPyLammps API
Unlike the lammps API, the PyLammps/IPyLammps APIs allow running LAMMPS
commands by calling equivalent member functions.
For instance, the following LAMMPS command
.. code-block:: LAMMPS
region box block 0 10 0 5 -0.5 0.5
can be executed using the following Python code if *L* is a :py:class:`lammps` instance:
.. code-block:: Python
L.command("region box block 0 10 0 5 -0.5 0.5")
With the PyLammps interface, any LAMMPS command can be split up into arbitrary parts.
These parts are then passed to a member function with the name of the command.
For the ``region`` command that means the :code:`region` method can be called.
The arguments of the command can be passed as one string, or
individually.
.. code-block:: Python
L.region("box block", 0, 10, 0, 5, -0.5, 0.5)
In this example all parameters except the first are Python floating-point literals. The
PyLammps interface takes the entire parameter list and transparently
merges it to a single command string.
The benefit of this approach is avoiding redundant command calls and easier
parameterization. In the original interface parameterization this needed to be done
manually by creating formatted strings.
.. code-block:: Python
L.command("region box block %f %f %f %f %f %f" % (xlo, xhi, ylo, yhi, zlo, zhi))
In contrast, methods of PyLammps accept parameters directly and will convert
them automatically to a final command string.
.. code-block:: Python
L.region("box block", xlo, xhi, ylo, yhi, zlo, zhi)
Using these facilities, the example shown for the lammps API can be rewritten as follows:
.. code-block:: python
from lammps import PyLammps
L = PyLammps()
# read commands from file 'in.melt'
L.file('in.melt')
# issue a single command
L.variable('zpos', 'index', 1.0)
# create 10 groups with 10 atoms each
for i in range(10):
L.group(f"g{i}", "id", f"{10*i+1}:{10*(i+1)}")
L.clear()
L.region("box block", 0, 2, 0, 2, 0, 2)
L.create_box(1, "box")
L.create_atoms(1, "single", 1.0, 1.0, "${zpos}")
.. code-block:: Python
lmp.file(file) # run an entire input script, file = "in.lj"
lmp.command(cmd) # invoke a single LAMMPS command, cmd = "run 100"
lmp.commands_list(cmdlist) # invoke commands in cmdlist = **"run 10", "run 20"**
lmp.commands_string(multicmd) # invoke commands in multicmd = "run 10\nrun 20"
The file(), command(), commands_list(), commands_string() methods
allow an input script, a single command, or multiple commands to be
invoked.
Retrieving or setting LAMMPS system properties
**********************************************
.. code-block:: Python
version = lmp.version() # return the numerical version id, e.g. LAMMPS 2 Sep 2015 -> 20150902
size = lmp.extract_setting(name) # return data type info
xlo = lmp.extract_global(name,type) # extract a global quantity
# name = "boxxlo", "nlocal", etc
# type = 0 = int
# 1 = double
boxlo,boxhi,xy,yz,xz,periodicity,box_change = lmp.extract_box() # extract box info
value = lmp.get_thermo(name) # return current value of a thermo keyword
natoms = lmp.get_natoms() # total # of atoms as int
lmp.reset_box(boxlo,boxhi,xy,yz,xz) # reset the simulation box size
lmp.create_atoms(n,ids,types,x,v,image,shrinkexceed) # create N atoms with IDs, types, x, v, and image flags
The :py:meth:`get_thermo() <lammps.lammps.get_thermo()>` method returns the current value of a thermo
keyword as a float.
The get_natoms() method returns the total number of atoms in the
simulation, as an int.
The reset_box() method resets the size and shape of the simulation
box, e.g. as part of restoring a previously extracted and saved state
of a simulation.
The extract_setting(), extract_global(), extract_box(),
extract_atom(), extract_compute(), extract_fix(), and
extract_variable() methods return values or pointers to data
@ -149,6 +342,37 @@ valid names. New names could easily be added. A double or integer is
returned. You need to specify the appropriate data type via the type
argument.
Retrieving or setting properties of LAMMPS objects
**************************************************
.. code-block:: Python
coords = lmp.extract_atom(name,type) # extract a per-atom quantity
# name = "x", "type", etc
# type = 0 = vector of ints
# 1 = array of ints
# 2 = vector of doubles
# 3 = array of doubles
eng = lmp.extract_compute(id,style,type) # extract value(s) from a compute
v3 = lmp.extract_fix(id,style,type,i,j) # extract value(s) from a fix
# id = ID of compute or fix
# style = 0 = global data
# 1 = per-atom data
# 2 = local data
# type = 0 = scalar
# 1 = vector
# 2 = array
# i,j = indices of value in global vector or array
var = lmp.extract_variable(name,group,flag) # extract value(s) from a variable
# name = name of variable
# group = group ID (ignored for equal-style variables)
# flag = 0 = equal-style variable
# 1 = atom-style variable
flag = lmp.set_variable(name,value) # set existing named string-style variable to value, flag = 0 if successful
For extract_atom(), a pointer to internal LAMMPS atom-based data is
returned, which you can use via normal Python subscripting. See the
extract() method in the src/atom.cpp file for a list of valid names.
@ -181,19 +405,27 @@ doubles is returned, one value per atom, which you can use via normal
Python subscripting. The values will be zero for atoms not in the
specified group.
The get_thermo() method returns the current value of a thermo
keyword as a float.
The get_natoms() method returns the total number of atoms in the
simulation, as an int.
The set_variable() method sets an existing string-style variable to a
new string value, so that subsequent LAMMPS commands can access the
variable.
The reset_box() method resets the size and shape of the simulation
box, e.g. as part of restoring a previously extracted and saved state
of a simulation.
Gather and Scatter Data between MPI processors
**********************************************
.. code-block:: Python
data = lmp.gather_atoms(name,type,count) # return per-atom property of all atoms gathered into data, ordered by atom ID
# name = "x", "charge", "type", etc
data = lmp.gather_atoms_concat(name,type,count) # ditto, but concatenated atom values from each proc (unordered)
data = lmp.gather_atoms_subset(name,type,count,ndata,ids) # ditto, but for subset of Ndata atoms with IDs
lmp.scatter_atoms(name,type,count,data) # scatter per-atom property to all atoms from data, ordered by atom ID
# name = "x", "charge", "type", etc
# count = # of per-atom values, 1 or 3, etc
lmp.scatter_atoms_subset(name,type,count,ndata,ids,data) # ditto, but for subset of Ndata atoms with IDs
The gather methods collect peratom info of the requested type (atom
coords, atom types, forces, etc) from all processors, and returns the
@ -239,18 +471,3 @@ like this:
Alternatively, you can just change values in the vector returned by
the gather methods, since they are also ctypes vectors.
----------
As noted above, these Python class methods correspond one-to-one with
the functions in the LAMMPS library interface in src/library.cpp and
library.h. This means you can extend the Python wrapper via the
following steps:
* Add a new interface function to src/library.cpp and
src/library.h.
* Rebuild LAMMPS as a shared library.
* Add a wrapper method to python/lammps.py for this interface
function.
* You should now be able to invoke the new interface function from a
Python script.

View File

@ -340,7 +340,7 @@ to the screen and log file. Note that since the LAMMPS print command
itself takes a string in quotes as its argument, the Python string
must be delimited with a different style of quotes.
The :doc:`Python library <Python_library>` doc page describes the syntax
The :doc:`Python_head` doc page describes the syntax
for how Python wraps the various functions included in the LAMMPS
library interface.