Update and reorganize Python docs
This commit is contained in:
27
doc/graphviz/lammps-invoke-python.dot
Normal file
27
doc/graphviz/lammps-invoke-python.dot
Normal 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];
|
||||
}
|
||||
|
||||
30
doc/graphviz/pylammps-invoke-lammps.dot
Normal file
30
doc/graphviz/pylammps-invoke-lammps.dot
Normal 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"];
|
||||
}
|
||||
|
||||
24
doc/graphviz/python-invoke-lammps.dot
Normal file
24
doc/graphviz/python-invoke-lammps.dot
Normal 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];
|
||||
}
|
||||
|
||||
@ -329,6 +329,7 @@ LAMMPS.
|
||||
----------
|
||||
|
||||
.. _exe:
|
||||
.. _library:
|
||||
|
||||
Build the LAMMPS executable and library
|
||||
---------------------------------------
|
||||
|
||||
@ -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 |
BIN
doc/src/JPG/lammps-invoke-python.png
Normal file
BIN
doc/src/JPG/lammps-invoke-python.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 36 KiB |
BIN
doc/src/JPG/pylammps-invoke-lammps.png
Normal file
BIN
doc/src/JPG/pylammps-invoke-lammps.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 36 KiB |
BIN
doc/src/JPG/python-invoke-lammps.png
Normal file
BIN
doc/src/JPG/python-invoke-lammps.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 28 KiB |
@ -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
15
doc/src/Python_error.rst
Normal 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.
|
||||
@ -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
16
doc/src/Python_ext.rst
Normal 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.
|
||||
|
||||
@ -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
|
||||
|
||||
@ -1,31 +1,377 @@
|
||||
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``)
|
||||
|
||||
|
||||
.. _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
|
||||
|
||||
.. _python_install_guides:
|
||||
|
||||
Installing the LAMMPS Python Module and Shared Library
|
||||
======================================================
|
||||
|
||||
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.
|
||||
|
||||
Both CMake and traditional make build options offer ways to automate these tasks.
|
||||
|
||||
.. tabs::
|
||||
|
||||
.. tab:: CMake (local user)
|
||||
|
||||
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.
|
||||
|
||||
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:
|
||||
|
||||
+------------------------+-----------------------------------------------------------+-------------------------------------------------------------+
|
||||
| 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 following is a minimal working example:
|
||||
|
||||
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
|
||||
* run ``make install-python`` or run the ``python/install.py`` script explicitly
|
||||
|
||||
When calling "make install-python" LAMMPS will try to install the
|
||||
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.
|
||||
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
|
||||
@ -36,33 +382,118 @@ this to your ~/.cshrc file, one line for each of the two files:
|
||||
setenv PYTHONPATH ${PYTHONPATH}:/home/sjplimp/lammps/python
|
||||
setenv LD_LIBRARY_PATH ${LD_LIBRARY_PATH}:/home/sjplimp/lammps/src
|
||||
|
||||
On MacOSX you may also need to set DYLD_LIBRARY_PATH accordingly.
|
||||
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.
|
||||
the ``export`` shell builtin.
|
||||
|
||||
If you use "make install-python" or the python/install.py script, you need
|
||||
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
|
||||
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
|
||||
If the default settings of ``make install-python`` are not what you want,
|
||||
you can invoke ``install.py`` from the python directory manually as
|
||||
|
||||
.. parsed-literal::
|
||||
.. code-block:: bash
|
||||
|
||||
% python install.py -m \<python module\> -l <shared library> -v <version.h file> [-d \<pydir\>]
|
||||
$ 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
|
||||
* 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
|
||||
``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 :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
|
||||
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.
|
||||
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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.
|
||||
@ -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
|
||||
|
||||
@ -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.
|
||||
@ -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.
|
||||
|
||||
@ -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.
|
||||
@ -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.
|
||||
44
doc/src/Python_trouble.rst
Normal file
44
doc/src/Python_trouble.rst
Normal 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.
|
||||
@ -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
|
||||
************************************
|
||||
|
||||
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
|
||||
|
||||
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.
|
||||
# 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()
|
||||
|
||||
The python/examples directory has Python scripts which show how Python
|
||||
can run LAMMPS, grab data, change it, and put it back into LAMMPS.
|
||||
.. 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.
|
||||
|
||||
@ -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.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user