Merge branch 'develop' into cmake-cpp-std-deprecation
This commit is contained in:
@ -103,6 +103,7 @@ Tutorials howto
|
||||
Howto_github
|
||||
Howto_lammps_gui
|
||||
Howto_moltemplate
|
||||
Howto_python
|
||||
Howto_pylammps
|
||||
Howto_wsl
|
||||
|
||||
|
||||
@ -1,564 +1,6 @@
|
||||
PyLammps Tutorial
|
||||
=================
|
||||
|
||||
.. contents::
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
:py:class:`PyLammps <lammps.PyLammps>` is a Python wrapper class for
|
||||
LAMMPS which can be created on its own or use an existing
|
||||
:py:class:`lammps Python <lammps.lammps>` object. It creates a simpler,
|
||||
more "pythonic" interface to common LAMMPS functionality, in contrast to
|
||||
the :py:class:`lammps <lammps.lammps>` wrapper for the LAMMPS :ref:`C
|
||||
language library interface API <lammps_c_api>` which is written using
|
||||
`Python ctypes <ctypes_>`_. The :py:class:`lammps <lammps.lammps>`
|
||||
wrapper is discussed on the :doc:`Python_head` doc page.
|
||||
|
||||
Unlike the flat `ctypes <ctypes_>`_ interface, PyLammps exposes a
|
||||
discoverable API. It no longer requires knowledge of the underlying C++
|
||||
code implementation. Finally, the :py:class:`IPyLammps
|
||||
<lammps.IPyLammps>` wrapper builds on top of :py:class:`PyLammps
|
||||
<lammps.PyLammps>` and adds some additional features for `IPython
|
||||
integration <ipython_>`_ into `Jupyter notebooks <jupyter_>`_, e.g. for
|
||||
embedded visualization output from :doc:`dump style image <dump_image>`.
|
||||
|
||||
.. _ctypes: https://docs.python.org/3/library/ctypes.html
|
||||
.. _ipython: https://ipython.org/
|
||||
.. _jupyter: https://jupyter.org/
|
||||
|
||||
Comparison of lammps and PyLammps interfaces
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
lammps.lammps
|
||||
"""""""""""""
|
||||
|
||||
* uses `ctypes <ctypes_>`_
|
||||
* direct memory access to native C++ data with optional support for NumPy arrays
|
||||
* provides functions to send and receive data to LAMMPS
|
||||
* interface modeled after the LAMMPS :ref:`C language library interface API <lammps_c_api>`
|
||||
* requires knowledge of how LAMMPS internally works (C pointers, etc)
|
||||
* full support for running Python with MPI using `mpi4py <https://mpi4py.readthedocs.io>`_
|
||||
* no overhead from creating a more Python-like interface
|
||||
|
||||
lammps.PyLammps
|
||||
"""""""""""""""
|
||||
|
||||
* higher-level abstraction built on *top* of the original :py:class:`ctypes based interface <lammps.lammps>`
|
||||
* manipulation of Python objects
|
||||
* communication with LAMMPS is hidden from API user
|
||||
* shorter, more concise Python
|
||||
* better IPython integration, designed for quick prototyping
|
||||
* designed for serial execution
|
||||
* additional overhead from capturing and parsing the LAMMPS screen output
|
||||
|
||||
Quick Start
|
||||
-----------
|
||||
|
||||
System-wide Installation
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Step 1: Building LAMMPS as a shared library
|
||||
"""""""""""""""""""""""""""""""""""""""""""
|
||||
|
||||
To use LAMMPS inside of Python it has to be compiled as shared
|
||||
library. This library is then loaded by the Python interface. In this
|
||||
example we enable the MOLECULE package and compile LAMMPS with PNG, JPEG
|
||||
and FFMPEG output support enabled.
|
||||
|
||||
Step 1a: For the CMake based build system, the steps are:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
mkdir $LAMMPS_DIR/build-shared
|
||||
cd $LAMMPS_DIR/build-shared
|
||||
|
||||
# MPI, PNG, Jpeg, FFMPEG are auto-detected
|
||||
cmake ../cmake -DPKG_MOLECULE=yes -DBUILD_LIB=yes -DBUILD_SHARED_LIBS=yes
|
||||
make
|
||||
|
||||
Step 1b: For the legacy, make based build system, the steps are:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cd $LAMMPS_DIR/src
|
||||
|
||||
# add packages if necessary
|
||||
make yes-MOLECULE
|
||||
|
||||
# compile shared library using Makefile
|
||||
make mpi mode=shlib LMP_INC="-DLAMMPS_PNG -DLAMMPS_JPEG -DLAMMPS_FFMPEG" JPG_LIB="-lpng -ljpeg"
|
||||
|
||||
Step 2: Installing the LAMMPS Python package
|
||||
""""""""""""""""""""""""""""""""""""""""""""
|
||||
|
||||
PyLammps is part of the lammps Python package. To install it simply install
|
||||
that package into your current Python installation with:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
make install-python
|
||||
|
||||
.. note::
|
||||
|
||||
Recompiling the shared library requires re-installing the Python package
|
||||
|
||||
Installation inside of a virtualenv
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
You can use virtualenv to create a custom Python environment specifically tuned
|
||||
for your workflow.
|
||||
|
||||
Benefits of using a virtualenv
|
||||
""""""""""""""""""""""""""""""
|
||||
|
||||
* isolation of your system Python installation from your development installation
|
||||
* installation can happen in your user directory without root access (useful for HPC clusters)
|
||||
* installing packages through pip allows you to get newer versions of packages than e.g., through apt-get or yum package managers (and without root access)
|
||||
* you can even install specific old versions of a package if necessary
|
||||
|
||||
**Prerequisite (e.g. on Ubuntu)**
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
apt-get install python-virtualenv
|
||||
|
||||
Creating a virtualenv with lammps installed
|
||||
"""""""""""""""""""""""""""""""""""""""""""
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# create virtualenv named 'testing'
|
||||
virtualenv $HOME/python/testing
|
||||
|
||||
# activate 'testing' environment
|
||||
source $HOME/python/testing/bin/activate
|
||||
|
||||
Now configure and compile the LAMMPS shared library as outlined above.
|
||||
When using CMake and the shared library has already been build, you
|
||||
need to re-run CMake to update the location of the python executable
|
||||
to the location in the virtual environment with:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cmake . -DPython_EXECUTABLE=$(which python)
|
||||
|
||||
# install LAMMPS package in virtualenv
|
||||
(testing) make install-python
|
||||
|
||||
# install other useful packages
|
||||
(testing) pip install matplotlib jupyter mpi4py
|
||||
|
||||
...
|
||||
|
||||
# return to original shell
|
||||
(testing) deactivate
|
||||
|
||||
Creating a new instance of PyLammps
|
||||
-----------------------------------
|
||||
|
||||
To create a PyLammps object you need to first import the class from the lammps
|
||||
module. By using the default constructor, a new *lammps* instance is created.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from lammps import PyLammps
|
||||
L = PyLammps()
|
||||
|
||||
You can also initialize PyLammps on top of this existing *lammps* object:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from lammps import lammps, PyLammps
|
||||
lmp = lammps()
|
||||
L = PyLammps(ptr=lmp)
|
||||
|
||||
Commands
|
||||
--------
|
||||
|
||||
Sending a LAMMPS command with the existing library interfaces is done using
|
||||
the command method of the lammps object instance.
|
||||
|
||||
For instance, let's take the following LAMMPS command:
|
||||
|
||||
.. code-block:: LAMMPS
|
||||
|
||||
region box block 0 10 0 5 -0.5 0.5
|
||||
|
||||
In the original interface this command can be executed with the following
|
||||
Python code if *L* was a lammps instance:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
L.command("region box block 0 10 0 5 -0.5 0.5")
|
||||
|
||||
With the PyLammps interface, any command can be split up into arbitrary parts
|
||||
separated by white-space, passed as individual arguments to a region method.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
L.region("box block", 0, 10, 0, 5, -0.5, 0.5)
|
||||
|
||||
Note that each parameter is set as Python literal floating-point number. In the
|
||||
PyLammps interface, each command takes an arbitrary parameter list and transparently
|
||||
merges it to a single command string, separating individual parameters by white-space.
|
||||
|
||||
The benefit of this approach is avoiding redundant command calls and easier
|
||||
parameterization. In the original interface parameterization 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)
|
||||
|
||||
System state
|
||||
------------
|
||||
|
||||
In addition to dispatching commands directly through the PyLammps object, it
|
||||
also provides several properties which allow you to query the system state.
|
||||
|
||||
L.system
|
||||
Is a dictionary describing the system such as the bounding box or number of atoms
|
||||
|
||||
L.system.xlo, L.system.xhi
|
||||
bounding box limits along x-axis
|
||||
|
||||
L.system.ylo, L.system.yhi
|
||||
bounding box limits along y-axis
|
||||
|
||||
L.system.zlo, L.system.zhi
|
||||
bounding box limits along z-axis
|
||||
|
||||
L.communication
|
||||
configuration of communication subsystem, such as the number of threads or processors
|
||||
|
||||
L.communication.nthreads
|
||||
number of threads used by each LAMMPS process
|
||||
|
||||
L.communication.nprocs
|
||||
number of MPI processes used by LAMMPS
|
||||
|
||||
L.fixes
|
||||
List of fixes in the current system
|
||||
|
||||
L.computes
|
||||
List of active computes in the current system
|
||||
|
||||
L.dump
|
||||
List of active dumps in the current system
|
||||
|
||||
L.groups
|
||||
List of groups present in the current system
|
||||
|
||||
Working with LAMMPS variables
|
||||
-----------------------------
|
||||
|
||||
LAMMPS variables can be both defined and accessed via the PyLammps interface.
|
||||
|
||||
To define a variable you can use the :doc:`variable <variable>` command:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
L.variable("a index 2")
|
||||
|
||||
A dictionary of all variables is returned by L.variables
|
||||
|
||||
you can access an individual variable by retrieving a variable object from the
|
||||
L.variables dictionary by name
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
a = L.variables['a']
|
||||
|
||||
The variable value can then be easily read and written by accessing the value
|
||||
property of this object.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
print(a.value)
|
||||
a.value = 4
|
||||
|
||||
Retrieving the value of an arbitrary LAMMPS expressions
|
||||
-------------------------------------------------------
|
||||
|
||||
LAMMPS expressions can be immediately evaluated by using the eval method. The
|
||||
passed string parameter can be any expression containing global thermo values,
|
||||
variables, compute or fix data.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
result = L.eval("ke") # kinetic energy
|
||||
result = L.eval("pe") # potential energy
|
||||
|
||||
result = L.eval("v_t/2.0")
|
||||
|
||||
Accessing atom data
|
||||
-------------------
|
||||
|
||||
All atoms in the current simulation can be accessed by using the L.atoms list.
|
||||
Each element of this list is an object which exposes its properties (id, type,
|
||||
position, velocity, force, etc.).
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# access first atom
|
||||
L.atoms[0].id
|
||||
L.atoms[0].type
|
||||
|
||||
# access second atom
|
||||
L.atoms[1].position
|
||||
L.atoms[1].velocity
|
||||
L.atoms[1].force
|
||||
|
||||
Some properties can also be used to set:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# set position in 2D simulation
|
||||
L.atoms[0].position = (1.0, 0.0)
|
||||
|
||||
# set position in 3D simulation
|
||||
L.atoms[0].position = (1.0, 0.0, 1.)
|
||||
|
||||
Evaluating thermo data
|
||||
----------------------
|
||||
|
||||
Each simulation run usually produces thermo output based on system state,
|
||||
computes, fixes or variables. The trajectories of these values can be queried
|
||||
after a run via the L.runs list. This list contains a growing list of run data.
|
||||
The first element is the output of the first run, the second element that of
|
||||
the second run.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
L.run(1000)
|
||||
L.runs[0] # data of first 1000 time steps
|
||||
|
||||
L.run(1000)
|
||||
L.runs[1] # data of second 1000 time steps
|
||||
|
||||
Each run contains a dictionary of all trajectories. Each trajectory is
|
||||
accessible through its thermo name:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
L.runs[0].thermo.Step # list of time steps in first run
|
||||
L.runs[0].thermo.Ke # list of kinetic energy values in first run
|
||||
|
||||
Together with matplotlib plotting data out of LAMMPS becomes simple:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import matplotlib.plot as plt
|
||||
steps = L.runs[0].thermo.Step
|
||||
ke = L.runs[0].thermo.Ke
|
||||
plt.plot(steps, ke)
|
||||
|
||||
Error handling with PyLammps
|
||||
----------------------------
|
||||
|
||||
Using C++ exceptions in LAMMPS for errors allows capturing them on the
|
||||
C++ side and rethrowing them on the Python side. This way you can handle
|
||||
LAMMPS errors 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.
|
||||
|
||||
Using PyLammps in IPython notebooks and Jupyter
|
||||
-----------------------------------------------
|
||||
|
||||
If the LAMMPS Python package is installed for the same Python interpreter as
|
||||
IPython, you can use PyLammps directly inside of an IPython notebook inside of
|
||||
Jupyter. Jupyter is a powerful integrated development environment (IDE) for
|
||||
many dynamic languages like Python, Julia and others, which operates inside of
|
||||
any web browser. Besides auto-completion and syntax highlighting it allows you
|
||||
to create formatted documents using Markup, mathematical formulas, graphics and
|
||||
animations intermixed with executable Python code. It is a great format for
|
||||
tutorials and showcasing your latest research.
|
||||
|
||||
To launch an instance of Jupyter simply run the following command inside your
|
||||
Python environment (this assumes you followed the Quick Start instructions):
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
jupyter notebook
|
||||
|
||||
IPyLammps Examples
|
||||
------------------
|
||||
|
||||
Examples of IPython notebooks can be found in the python/examples/pylammps
|
||||
subdirectory. To open these notebooks launch *jupyter notebook* inside this
|
||||
directory and navigate to one of them. If you compiled and installed
|
||||
a LAMMPS shared library with exceptions, PNG, JPEG and FFMPEG support
|
||||
you should be able to rerun all of these notebooks.
|
||||
|
||||
Validating a dihedral potential
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
This example showcases how an IPython Notebook can be used to compare a simple
|
||||
LAMMPS simulation of a harmonic dihedral potential to its analytical solution.
|
||||
Four atoms are placed in the simulation and the dihedral potential is applied on
|
||||
them using a datafile. Then one of the atoms is rotated along the central axis by
|
||||
setting its position from Python, which changes the dihedral angle.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
phi = [d \* math.pi / 180 for d in range(360)]
|
||||
|
||||
pos = [(1.0, math.cos(p), math.sin(p)) for p in phi]
|
||||
|
||||
pe = []
|
||||
for p in pos:
|
||||
L.atoms[3].position = p
|
||||
L.run(0)
|
||||
pe.append(L.eval("pe"))
|
||||
|
||||
By evaluating the potential energy for each position we can verify that
|
||||
trajectory with the analytical formula. To compare both solutions, we plot
|
||||
both trajectories over each other using matplotlib, which embeds the generated
|
||||
plot inside the IPython notebook.
|
||||
|
||||
.. image:: JPG/pylammps_dihedral.jpg
|
||||
:align: center
|
||||
|
||||
Running a Monte Carlo relaxation
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
This second example shows how to use PyLammps to create a 2D Monte Carlo Relaxation
|
||||
simulation, computing and plotting energy terms and even embedding video output.
|
||||
|
||||
Initially, a 2D system is created in a state with minimal energy.
|
||||
|
||||
.. image:: JPG/pylammps_mc_minimum.jpg
|
||||
:align: center
|
||||
|
||||
It is then disordered by moving each atom by a random delta.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
random.seed(27848)
|
||||
deltaperturb = 0.2
|
||||
|
||||
for i in range(L.system.natoms):
|
||||
x, y = L.atoms[i].position
|
||||
dx = deltaperturb \* random.uniform(-1, 1)
|
||||
dy = deltaperturb \* random.uniform(-1, 1)
|
||||
L.atoms[i].position = (x+dx, y+dy)
|
||||
|
||||
L.run(0)
|
||||
|
||||
.. image:: JPG/pylammps_mc_disordered.jpg
|
||||
:align: center
|
||||
|
||||
Finally, the Monte Carlo algorithm is implemented in Python. It continuously
|
||||
moves random atoms by a random delta and only accepts certain moves.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
estart = L.eval("pe")
|
||||
elast = estart
|
||||
|
||||
naccept = 0
|
||||
energies = [estart]
|
||||
|
||||
niterations = 3000
|
||||
deltamove = 0.1
|
||||
kT = 0.05
|
||||
|
||||
natoms = L.system.natoms
|
||||
|
||||
for i in range(niterations):
|
||||
iatom = random.randrange(0, natoms)
|
||||
current_atom = L.atoms[iatom]
|
||||
|
||||
x0, y0 = current_atom.position
|
||||
|
||||
dx = deltamove \* random.uniform(-1, 1)
|
||||
dy = deltamove \* random.uniform(-1, 1)
|
||||
|
||||
current_atom.position = (x0+dx, y0+dy)
|
||||
|
||||
L.run(1, "pre no post no")
|
||||
|
||||
e = L.eval("pe")
|
||||
energies.append(e)
|
||||
|
||||
if e <= elast:
|
||||
naccept += 1
|
||||
elast = e
|
||||
elif random.random() <= math.exp(natoms\*(elast-e)/kT):
|
||||
naccept += 1
|
||||
elast = e
|
||||
else:
|
||||
current_atom.position = (x0, y0)
|
||||
|
||||
The energies of each iteration are collected in a Python list and finally plotted using matplotlib.
|
||||
|
||||
.. image:: JPG/pylammps_mc_energies_plot.jpg
|
||||
:align: center
|
||||
|
||||
The IPython notebook also shows how to use dump commands and embed video files
|
||||
inside of the IPython notebook.
|
||||
|
||||
Using PyLammps and mpi4py (Experimental)
|
||||
----------------------------------------
|
||||
|
||||
PyLammps can be run in parallel using `mpi4py
|
||||
<https://mpi4py.readthedocs.io>`_. This python package can be installed
|
||||
using
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pip install mpi4py
|
||||
|
||||
.. warning::
|
||||
|
||||
Usually, any :py:class:`PyLammps <lammps.PyLammps>` command must be
|
||||
executed by *all* MPI processes. However, evaluations and querying
|
||||
the system state is only available on MPI rank 0. Using these
|
||||
functions from other MPI ranks will raise an exception.
|
||||
|
||||
The following is a short example which reads in an existing LAMMPS input
|
||||
file and executes it in parallel. You can find in.melt in the
|
||||
examples/melt folder. Please take note that the
|
||||
:py:meth:`PyLammps.eval() <lammps.PyLammps.eval>` is called only from
|
||||
MPI rank 0.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from mpi4py import MPI
|
||||
from lammps import PyLammps
|
||||
|
||||
L = PyLammps()
|
||||
L.file("in.melt")
|
||||
|
||||
if MPI.COMM_WORLD.rank == 0:
|
||||
print("Potential energy: ", L.eval("pe"))
|
||||
|
||||
MPI.Finalize()
|
||||
|
||||
To run this script (melt.py) in parallel using 4 MPI processes we invoke the
|
||||
following mpirun command:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
mpirun -np 4 python melt.py
|
||||
|
||||
Feedback and Contributing
|
||||
-------------------------
|
||||
|
||||
If you find this Python interface useful, please feel free to provide feedback
|
||||
and ideas on how to improve it to Richard Berger (richard.berger@outlook.com). We also
|
||||
want to encourage people to write tutorial style IPython notebooks showcasing LAMMPS usage
|
||||
and maybe their latest research results.
|
||||
The PyLammps interface is deprecated and will be removed in a future release of
|
||||
LAMMPS. As such, the PyLammps version of this tutorial has been removed and is
|
||||
replaced by the :doc:`Python_head`.
|
||||
|
||||
441
doc/src/Howto_python.rst
Normal file
441
doc/src/Howto_python.rst
Normal file
@ -0,0 +1,441 @@
|
||||
LAMMPS Python Tutorial
|
||||
======================
|
||||
|
||||
.. contents::
|
||||
|
||||
-----
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
The :py:class:`lammps <lammps.lammps>` Python module is a wrapper class for the
|
||||
LAMMPS :ref:`C language library interface API <lammps_c_api>` which is written using
|
||||
`Python ctypes <ctypes_>`_. The design choice of this wrapper class is to
|
||||
follow the C language API closely with only small changes related to Python
|
||||
specific requirements and to better accommodate object oriented programming.
|
||||
|
||||
In addition to this flat `ctypes <ctypes_>`_ interface, the
|
||||
:py:class:`lammps <lammps.lammps>` wrapper class exposes a discoverable
|
||||
API that doesn't require as much knowledge of the underlying C language
|
||||
library interface or LAMMPS C++ code implementation.
|
||||
|
||||
Finally, the API exposes some additional features for `IPython integration
|
||||
<ipython_>`_ into `Jupyter notebooks <jupyter_>`_, e.g. for embedded
|
||||
visualization output from :doc:`dump style image <dump_image>`.
|
||||
|
||||
.. _ctypes: https://docs.python.org/3/library/ctypes.html
|
||||
.. _ipython: https://ipython.org/
|
||||
.. _jupyter: https://jupyter.org/
|
||||
|
||||
-----
|
||||
|
||||
Quick Start
|
||||
-----------
|
||||
|
||||
System-wide or User Installation
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Step 1: Building LAMMPS as a shared library
|
||||
"""""""""""""""""""""""""""""""""""""""""""
|
||||
|
||||
To use LAMMPS inside of Python it has to be compiled as shared library.
|
||||
This library is then loaded by the Python interface. In this example we
|
||||
enable the :ref:`MOLECULE package <PKG-MOLECULE>` and compile LAMMPS
|
||||
with :ref:`PNG, JPEG and FFMPEG output support <graphics>` enabled.
|
||||
|
||||
.. tabs::
|
||||
|
||||
.. tab:: CMake build
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
mkdir $LAMMPS_DIR/build-shared
|
||||
cd $LAMMPS_DIR/build-shared
|
||||
|
||||
# MPI, PNG, Jpeg, FFMPEG are auto-detected
|
||||
cmake ../cmake -DPKG_MOLECULE=yes -DPKG_PYTHON=on -DBUILD_SHARED_LIBS=yes
|
||||
make
|
||||
|
||||
.. tab:: Traditional make
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cd $LAMMPS_DIR/src
|
||||
|
||||
# add packages if necessary
|
||||
make yes-MOLECULE
|
||||
make yes-PYTHON
|
||||
|
||||
# compile shared library using Makefile
|
||||
make mpi mode=shlib LMP_INC="-DLAMMPS_PNG -DLAMMPS_JPEG -DLAMMPS_FFMPEG" JPG_LIB="-lpng -ljpeg"
|
||||
|
||||
Step 2: Installing the LAMMPS Python package
|
||||
""""""""""""""""""""""""""""""""""""""""""""
|
||||
|
||||
Next install the LAMMPS Python package into your current Python installation with:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
make install-python
|
||||
|
||||
This will create a so-called `"wheel"
|
||||
<https://packaging.python.org/en/latest/discussions/package-formats/#what-is-a-wheel>`_
|
||||
and then install the LAMMPS Python module from that "wheel" into either
|
||||
into a system folder (provided the command is executed with root
|
||||
privileges) or into your personal Python module folder.
|
||||
|
||||
.. note::
|
||||
|
||||
Recompiling the shared library requires re-installing the Python
|
||||
package.
|
||||
|
||||
Installation inside of a virtual environment
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
You can use virtual environments to create a custom Python environment
|
||||
specifically tuned for your workflow.
|
||||
|
||||
Benefits of using a virtualenv
|
||||
""""""""""""""""""""""""""""""
|
||||
|
||||
* isolation of your system Python installation from your development installation
|
||||
* installation can happen in your user directory without root access (useful for HPC clusters)
|
||||
* installing packages through pip allows you to get newer versions of packages than e.g., through apt-get or yum package managers (and without root access)
|
||||
* you can even install specific old versions of a package if necessary
|
||||
|
||||
**Prerequisite (e.g. on Ubuntu)**
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
apt-get install python-venv
|
||||
|
||||
Creating a virtualenv with lammps installed
|
||||
"""""""""""""""""""""""""""""""""""""""""""
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# create virtual envrionment named 'testing'
|
||||
python3 -m venv $HOME/python/testing
|
||||
|
||||
# activate 'testing' environment
|
||||
source $HOME/python/testing/bin/activate
|
||||
|
||||
Now configure and compile the LAMMPS shared library as outlined above.
|
||||
When using CMake and the shared library has already been build, you
|
||||
need to re-run CMake to update the location of the python executable
|
||||
to the location in the virtual environment with:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cmake . -DPython_EXECUTABLE=$(which python)
|
||||
|
||||
# install LAMMPS package in virtualenv
|
||||
(testing) make install-python
|
||||
|
||||
# install other useful packages
|
||||
(testing) pip install matplotlib jupyter mpi4py pandas
|
||||
|
||||
...
|
||||
|
||||
# return to original shell
|
||||
(testing) deactivate
|
||||
|
||||
-------
|
||||
|
||||
Creating a new lammps instance
|
||||
------------------------------
|
||||
|
||||
To create a lammps object you need to first import the class from the lammps
|
||||
module. By using the default constructor, a new :py:class:`lammps
|
||||
<lammps.lammps>` instance is created.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from lammps import lammps
|
||||
L = lammps()
|
||||
|
||||
See the :doc:`LAMMPS Python documentation <Python_create>` for how to customize
|
||||
the instance creation with optional arguments.
|
||||
|
||||
-----
|
||||
|
||||
Commands
|
||||
--------
|
||||
|
||||
Sending a LAMMPS command with the library interface is done using
|
||||
the ``command`` method of the lammps object.
|
||||
|
||||
For instance, let's take the following LAMMPS command:
|
||||
|
||||
.. code-block:: LAMMPS
|
||||
|
||||
region box block 0 10 0 5 -0.5 0.5
|
||||
|
||||
This command can be executed with the following Python code if ``L`` is a ``lammps``
|
||||
instance:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
L.command("region box block 0 10 0 5 -0.5 0.5")
|
||||
|
||||
For convenience, the ``lammps`` class also provides a command wrapper ``cmd``
|
||||
that turns any LAMMPS command into a regular function call:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
L.cmd.region("box block", 0, 10, 0, 5, -0.5, 0.5)
|
||||
|
||||
Note that each parameter is set as Python number literal. With
|
||||
the wrapper each command takes an arbitrary parameter list and transparently
|
||||
merges it to a single command string, separating individual parameters by
|
||||
white-space.
|
||||
|
||||
The benefit of this approach is avoiding redundant command calls and easier
|
||||
parameterization. With the ``command`` function each call needs to be assembled
|
||||
manually using formatted strings.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
L.command(f"region box block {xlo} {xhi} {ylo} {yhi} {zlo} {zhi}")
|
||||
|
||||
The wrapper accepts parameters directly and will convert
|
||||
them automatically to a final command string.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
L.cmd.region("box block", xlo, xhi, ylo, yhi, zlo, zhi)
|
||||
|
||||
.. note::
|
||||
|
||||
When running in IPython you can use Tab-completion after ``L.cmd.`` to see
|
||||
all available LAMMPS commands.
|
||||
|
||||
-----
|
||||
|
||||
Accessing atom data
|
||||
-------------------
|
||||
|
||||
All per-atom properties that are part of the :doc:`atom style
|
||||
<atom_style>` in the current simulation can be accessed using the
|
||||
:py:meth:`extract_atoms() <lammps.lammps.extract_atoms()>` method. This
|
||||
can be retrieved as ctypes objects or as NumPy arrays through the
|
||||
lammps.numpy module. Those represent the *local* atoms of the
|
||||
individual sub-domain for the current MPI process and may contain
|
||||
information for the local ghost atoms or not depending on the property.
|
||||
Both can be accessed as lists, but for the ctypes list object the size
|
||||
is not known and hast to be retrieved first to avoid out-of-bounds
|
||||
accesses.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
nlocal = L.extract_setting("nlocal")
|
||||
nall = L.extract_setting("nall")
|
||||
print("Number of local atoms ", nlocal, " Number of local and ghost atoms ", nall);
|
||||
|
||||
# access via ctypes directly
|
||||
atom_id = L.extract_atom("id")
|
||||
print("Atom IDs", atom_id[0:nlocal])
|
||||
|
||||
# access through numpy wrapper
|
||||
atom_type = L.numpy.extract_atom("type")
|
||||
print("Atom types", atom_type)
|
||||
|
||||
x = L.numpy.extract_atom("x")
|
||||
v = L.numpy.extract_atom("v")
|
||||
print("positions array shape", x.shape)
|
||||
print("velocity array shape", v.shape)
|
||||
# turn on communicating velocities to ghost atoms
|
||||
L.cmd.comm_modify("vel", "yes")
|
||||
v = L.numpy.extract_atom('v')
|
||||
print("velocity array shape", v.shape)
|
||||
|
||||
Some properties can also be set from Python since internally the
|
||||
data of the C++ code is accessed directly:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# set position in 2D simulation
|
||||
x[0] = (1.0, 0.0)
|
||||
|
||||
# set position in 3D simulation
|
||||
x[0] = (1.0, 0.0, 1.)
|
||||
|
||||
------
|
||||
|
||||
Retrieving the values of thermodynamic data and variables
|
||||
---------------------------------------------------------
|
||||
|
||||
To access thermodynamic data from the last completed timestep,
|
||||
you can use the :py:meth:`get_thermo() <lammps.lammps.get_thermo>`
|
||||
method, and to extract the value of (compatible) variables, you
|
||||
can use the :py:meth:`extract_variable() <lammps.lammps.extract_variable>`
|
||||
method.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
result = L.get_thermo("ke") # kinetic energy
|
||||
result = L.get_thermo("pe") # potential energy
|
||||
|
||||
result = L.extract_variable("t") / 2.0
|
||||
|
||||
Error handling
|
||||
--------------
|
||||
|
||||
We are using C++ exceptions in LAMMPS for errors and the C language
|
||||
library interface captures and records them. This allows checking
|
||||
whether errors have happened in Python during a call into LAMMPS and
|
||||
then re-throw the error as a Python exception. This way you can handle
|
||||
LAMMPS errors in the conventional way 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.
|
||||
|
||||
Using LAMMPS in IPython notebooks and Jupyter
|
||||
---------------------------------------------
|
||||
|
||||
If the LAMMPS Python package is installed for the same Python
|
||||
interpreter as IPython, you can use LAMMPS directly inside of an IPython
|
||||
notebook inside of Jupyter. Jupyter is a powerful integrated development
|
||||
environment (IDE) for many dynamic languages like Python, Julia and
|
||||
others, which operates inside of any web browser. Besides
|
||||
auto-completion and syntax highlighting it allows you to create
|
||||
formatted documents using Markup, mathematical formulas, graphics and
|
||||
animations intermixed with executable Python code. It is a great format
|
||||
for tutorials and showcasing your latest research.
|
||||
|
||||
To launch an instance of Jupyter simply run the following command inside your
|
||||
Python environment (this assumes you followed the Quick Start instructions):
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
jupyter notebook
|
||||
|
||||
Interactive Python Examples
|
||||
---------------------------
|
||||
|
||||
Examples of IPython notebooks can be found in the ``python/examples/ipython``
|
||||
subdirectory. To open these notebooks launch ``jupyter notebook`` inside this
|
||||
directory and navigate to one of them. If you compiled and installed
|
||||
a LAMMPS shared library with PNG, JPEG and FFMPEG support
|
||||
you should be able to rerun all of these notebooks.
|
||||
|
||||
Validating a dihedral potential
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
This example showcases how an IPython Notebook can be used to compare a simple
|
||||
LAMMPS simulation of a harmonic dihedral potential to its analytical solution.
|
||||
Four atoms are placed in the simulation and the dihedral potential is applied on
|
||||
them using a datafile. Then one of the atoms is rotated along the central axis by
|
||||
setting its position from Python, which changes the dihedral angle.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
phi = [d \* math.pi / 180 for d in range(360)]
|
||||
|
||||
pos = [(1.0, math.cos(p), math.sin(p)) for p in phi]
|
||||
|
||||
x = L.numpy.extract_atom("x")
|
||||
|
||||
pe = []
|
||||
for p in pos:
|
||||
x[3] = p
|
||||
L.cmd.run(0, "post", "no")
|
||||
pe.append(L.get_thermo("pe"))
|
||||
|
||||
By evaluating the potential energy for each position we can verify that
|
||||
trajectory with the analytical formula. To compare both solutions, we plot
|
||||
both trajectories over each other using matplotlib, which embeds the generated
|
||||
plot inside the IPython notebook.
|
||||
|
||||
.. image:: JPG/pylammps_dihedral.jpg
|
||||
:align: center
|
||||
|
||||
Running a Monte Carlo relaxation
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
This second example shows how to use the `lammps` Python interface to create a
|
||||
2D Monte Carlo Relaxation simulation, computing and plotting energy terms and
|
||||
even embedding video output.
|
||||
|
||||
Initially, a 2D system is created in a state with minimal energy.
|
||||
|
||||
.. image:: JPG/pylammps_mc_minimum.jpg
|
||||
:align: center
|
||||
|
||||
It is then disordered by moving each atom by a random delta.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
random.seed(27848)
|
||||
deltaperturb = 0.2
|
||||
x = L.numpy.extract_atom("x")
|
||||
natoms = x.shape[0]
|
||||
|
||||
for i in range(natoms):
|
||||
dx = deltaperturb \* random.uniform(-1, 1)
|
||||
dy = deltaperturb \* random.uniform(-1, 1)
|
||||
x[i][0] += dx
|
||||
x[i][1] += dy
|
||||
|
||||
L.cmd.run(0, "post", "no")
|
||||
|
||||
.. image:: JPG/pylammps_mc_disordered.jpg
|
||||
:align: center
|
||||
|
||||
Finally, the Monte Carlo algorithm is implemented in Python. It continuously
|
||||
moves random atoms by a random delta and only accepts certain moves.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
estart = L.get_thermo("pe")
|
||||
elast = estart
|
||||
|
||||
naccept = 0
|
||||
energies = [estart]
|
||||
|
||||
niterations = 3000
|
||||
deltamove = 0.1
|
||||
kT = 0.05
|
||||
|
||||
for i in range(niterations):
|
||||
x = L.numpy.extract_atom("x")
|
||||
natoms = x.shape[0]
|
||||
iatom = random.randrange(0, natoms)
|
||||
current_atom = x[iatom]
|
||||
|
||||
x0 = current_atom[0]
|
||||
y0 = current_atom[1]
|
||||
|
||||
dx = deltamove \* random.uniform(-1, 1)
|
||||
dy = deltamove \* random.uniform(-1, 1)
|
||||
|
||||
current_atom[0] = x0 + dx
|
||||
current_atom[1] = y0 + dy
|
||||
|
||||
L.cmd.run(1, "pre no post no")
|
||||
|
||||
e = L.get_thermo("pe")
|
||||
energies.append(e)
|
||||
|
||||
if e <= elast:
|
||||
naccept += 1
|
||||
elast = e
|
||||
elif random.random() <= math.exp(natoms\*(elast-e)/kT):
|
||||
naccept += 1
|
||||
elast = e
|
||||
else:
|
||||
current_atom[0] = x0
|
||||
current_atom[1] = y0
|
||||
|
||||
The energies of each iteration are collected in a Python list and finally plotted using matplotlib.
|
||||
|
||||
.. image:: JPG/pylammps_mc_energies_plot.jpg
|
||||
:align: center
|
||||
|
||||
The IPython notebook also shows how to use dump commands and embed video files
|
||||
inside of the IPython notebook.
|
||||
@ -131,16 +131,15 @@ run LAMMPS in serial mode.
|
||||
|
||||
.. _lammps_python_api:
|
||||
|
||||
LAMMPS Python APIs
|
||||
==================
|
||||
LAMMPS Python API
|
||||
=================
|
||||
|
||||
The LAMMPS Python module enables calling the LAMMPS C library API from
|
||||
Python by dynamically loading functions in the LAMMPS shared library through
|
||||
the `Python ctypes module <https://docs.python.org/3/library/ctypes.html>`_.
|
||||
Because of the dynamic loading, it is **required** that LAMMPS is compiled
|
||||
in :ref:`"shared" mode <exe>`. The Python interface is object-oriented, but
|
||||
otherwise tries to be very similar to the C library API. Three different
|
||||
Python classes to run LAMMPS are available and they build on each other.
|
||||
otherwise tries to be very similar to the C library API.
|
||||
More information on this is in the :doc:`Python_head`
|
||||
section of the manual. Use of the LAMMPS Python module is described in
|
||||
:doc:`Python_module`.
|
||||
|
||||
@ -2,14 +2,8 @@ Per-atom properties
|
||||
===================
|
||||
|
||||
Similar to what is described in :doc:`Library_atoms`, the instances of
|
||||
:py:class:`lammps <lammps.lammps>`, :py:class:`PyLammps <lammps.PyLammps>`, or
|
||||
:py:class:`IPyLammps <lammps.IPyLammps>` can be used to extract atom quantities
|
||||
and modify some of them. The main difference between the interfaces is how the information
|
||||
is exposed.
|
||||
|
||||
While the :py:class:`lammps <lammps.lammps>` is just a thin layer that wraps C API calls,
|
||||
:py:class:`PyLammps <lammps.PyLammps>` and :py:class:`IPyLammps <lammps.IPyLammps>` expose
|
||||
information as objects and properties.
|
||||
:py:class:`lammps <lammps.lammps>` can be used to extract atom quantities
|
||||
and modify some of them.
|
||||
|
||||
In some cases the data returned is a direct reference to the original data
|
||||
inside LAMMPS cast to ``ctypes`` pointers. Where possible, the wrappers will
|
||||
@ -25,57 +19,41 @@ against invalid accesses.
|
||||
accordingly. These arrays can change sizes and order at every neighbor list
|
||||
rebuild and atom sort event as atoms are migrating between subdomains.
|
||||
|
||||
.. tabs::
|
||||
.. code-block:: python
|
||||
|
||||
.. tab:: lammps API
|
||||
from lammps import lammps
|
||||
|
||||
.. code-block:: python
|
||||
lmp = lammps()
|
||||
lmp.file("in.sysinit")
|
||||
|
||||
from lammps import lammps
|
||||
|
||||
lmp = lammps()
|
||||
lmp.file("in.sysinit")
|
||||
# Read/Write access via ctypes
|
||||
nlocal = lmp.extract_global("nlocal")
|
||||
x = lmp.extract_atom("x")
|
||||
|
||||
nlocal = lmp.extract_global("nlocal")
|
||||
x = lmp.extract_atom("x")
|
||||
for i in range(nlocal):
|
||||
print("(x,y,z) = (", x[i][0], x[i][1], x[i][2], ")")
|
||||
|
||||
for i in range(nlocal):
|
||||
print("(x,y,z) = (", x[i][0], x[i][1], x[i][2], ")")
|
||||
# Read/Write access via NumPy arrays
|
||||
atom_id = L.numpy.extract_atom("id")
|
||||
atom_type = L.numpy.extract_atom("type")
|
||||
x = L.numpy.extract_atom("x")
|
||||
v = L.numpy.extract_atom("v")
|
||||
f = L.numpy.extract_atom("f")
|
||||
|
||||
lmp.close()
|
||||
# set position in 2D simulation
|
||||
x[0] = (1.0, 0.0)
|
||||
|
||||
**Methods**:
|
||||
# set position in 3D simulation
|
||||
x[0] = (1.0, 0.0, 1.)
|
||||
|
||||
* :py:meth:`extract_atom() <lammps.lammps.extract_atom()>`: extract a per-atom quantity
|
||||
lmp.close()
|
||||
|
||||
**Numpy Methods**:
|
||||
|
||||
* :py:meth:`numpy.extract_atom() <lammps.numpy_wrapper.numpy_wrapper.extract_atom()>`: extract a per-atom quantity as numpy array
|
||||
**Methods**:
|
||||
|
||||
.. tab:: PyLammps/IPyLammps API
|
||||
* :py:meth:`extract_atom() <lammps.lammps.extract_atom()>`: extract a per-atom quantity
|
||||
|
||||
All atoms in the current simulation can be accessed by using the :py:attr:`PyLammps.atoms <lammps.PyLammps.atoms>` property.
|
||||
Each element of this list is a :py:class:`Atom <lammps.Atom>` or :py:class:`Atom2D <lammps.Atom2D>` object. The attributes of
|
||||
these objects provide access to their data (id, type, position, velocity, force, etc.):
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# access first atom
|
||||
L.atoms[0].id
|
||||
L.atoms[0].type
|
||||
|
||||
# access second atom
|
||||
L.atoms[1].position
|
||||
L.atoms[1].velocity
|
||||
L.atoms[1].force
|
||||
|
||||
Some attributes can be changed:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# set position in 2D simulation
|
||||
L.atoms[0].position = (1.0, 0.0)
|
||||
|
||||
# set position in 3D simulation
|
||||
L.atoms[0].position = (1.0, 0.0, 1.0)
|
||||
**Numpy Methods**:
|
||||
|
||||
* :py:meth:`numpy.extract_atom() <lammps.numpy_wrapper.numpy_wrapper.extract_atom()>`: extract a per-atom quantity as numpy array
|
||||
|
||||
@ -6,11 +6,10 @@ 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:class:`lammps <lammps.lammps>`, :py:class:`PyLammps <lammps.PyLammps>`,
|
||||
and :py:class:`IPyLammps <lammps.IPyLammps>` 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.
|
||||
<LAMMPS_NS::LAMMPS>` instance is included in the constructor for the
|
||||
:py:class:`lammps <lammps.lammps>` class. 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
|
||||
@ -26,108 +25,25 @@ 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:
|
||||
Here is a simple example using the LAMMPS Python interface:
|
||||
|
||||
.. tabs::
|
||||
.. code-block:: python
|
||||
|
||||
.. tab:: lammps API
|
||||
from lammps import lammps
|
||||
|
||||
.. code-block:: python
|
||||
# NOTE: argv[0] is set by the lammps class constructor
|
||||
args = ["-log", "none"]
|
||||
|
||||
from lammps import lammps
|
||||
# create LAMMPS instance
|
||||
lmp = lammps(cmdargs=args)
|
||||
|
||||
# NOTE: argv[0] is set by the lammps class constructor
|
||||
args = ["-log", "none"]
|
||||
# get and print numerical version code
|
||||
print("LAMMPS Version: ", lmp.version())
|
||||
|
||||
# create LAMMPS instance
|
||||
lmp = lammps(cmdargs=args)
|
||||
# explicitly close and delete LAMMPS instance (optional)
|
||||
lmp.close()
|
||||
|
||||
# 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 <lammps.PyLammps>` class is a wrapper around the
|
||||
:py:class:`lammps <lammps.lammps>` class and all of its lower level functions.
|
||||
By default, it will create a new instance of :py:class:`lammps <lammps.lammps>` passing
|
||||
along all arguments to the constructor of :py:class:`lammps <lammps.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 <lammps.PyLammps>` objects can also be created on top of an existing
|
||||
:py:class:`lammps <lammps.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 <lammps.IPyLammps>` class is an extension of the
|
||||
:py:class:`PyLammps <lammps.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
|
||||
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.
|
||||
|
||||
|
||||
@ -1,127 +1,123 @@
|
||||
Executing commands
|
||||
==================
|
||||
|
||||
Once an instance of the :py:class:`lammps <lammps.lammps>`,
|
||||
:py:class:`PyLammps <lammps.PyLammps>`, or
|
||||
:py:class:`IPyLammps <lammps.IPyLammps>` class is created, there are
|
||||
Once an instance of the :py:class:`lammps <lammps.lammps>` 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::
|
||||
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()`:
|
||||
|
||||
.. tab:: lammps API
|
||||
.. code-block:: python
|
||||
|
||||
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()`:
|
||||
from lammps import lammps
|
||||
lmp = lammps()
|
||||
|
||||
.. code-block:: python
|
||||
# read commands from file 'in.melt'
|
||||
lmp.file('in.melt')
|
||||
|
||||
from lammps import lammps
|
||||
lmp = lammps()
|
||||
# issue a single command
|
||||
lmp.command('variable zpos index 1.0')
|
||||
|
||||
# read commands from file 'in.melt'
|
||||
lmp.file('in.melt')
|
||||
# create 10 groups with 10 atoms each
|
||||
cmds = [f"group g{i} id {10*i+1}:{10*(i+1)}" for i in range(10)]
|
||||
lmp.commands_list(cmds)
|
||||
|
||||
# issue a single command
|
||||
lmp.command('variable zpos index 1.0')
|
||||
# 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)
|
||||
|
||||
# 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)
|
||||
For convenience, the :py:class:`lammps <lammps.lammps>` class also provides a
|
||||
command wrapper ``cmd`` that turns any LAMMPS command into a regular function
|
||||
call.
|
||||
|
||||
# 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)
|
||||
For instance, the following LAMMPS command
|
||||
|
||||
.. tab:: PyLammps/IPyLammps API
|
||||
.. code-block:: LAMMPS
|
||||
|
||||
Unlike the lammps API, the PyLammps/IPyLammps APIs allow running LAMMPS
|
||||
commands by calling equivalent member functions of :py:class:`PyLammps <lammps.PyLammps>`
|
||||
and :py:class:`IPyLammps <lammps.IPyLammps>` instances.
|
||||
region box block 0 10 0 5 -0.5 0.5
|
||||
|
||||
For instance, the following LAMMPS command
|
||||
would normally be executed with the following Python code:
|
||||
|
||||
.. code-block:: LAMMPS
|
||||
.. code-block:: python
|
||||
|
||||
region box block 0 10 0 5 -0.5 0.5
|
||||
from lammps import lammps
|
||||
|
||||
can be executed using with the lammps API with the following Python code if ``lmp`` is an
|
||||
instance of :py:class:`lammps <lammps.lammps>`:
|
||||
lmp = lammps()
|
||||
lmp.command("region box block 0 10 0 5 -0.5 0.5")
|
||||
|
||||
.. code-block:: python
|
||||
With the ``cmd`` wrapper, any LAMMPS command can be split up into arbitrary parts.
|
||||
These parts are then passed to a member function with the name of the :doc:`command <Commands_all>`.
|
||||
For the :doc:`region <region>` command that means the :code:`region()` method can be called.
|
||||
The arguments of the command can be passed as one string, or
|
||||
individually.
|
||||
|
||||
from lammps import lammps
|
||||
.. code-block:: python
|
||||
|
||||
lmp = lammps()
|
||||
lmp.command("region box block 0 10 0 5 -0.5 0.5")
|
||||
from lammps import lammps
|
||||
|
||||
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 :doc:`command <Commands_all>`.
|
||||
For the :doc:`region <region>` command that means the :code:`region()` method can be called.
|
||||
The arguments of the command can be passed as one string, or
|
||||
individually.
|
||||
L = lammps()
|
||||
|
||||
.. code-block:: python
|
||||
# pass command parameters as one string
|
||||
L.cmd.region("box block 0 10 0 5 -0.5 0.5")
|
||||
|
||||
from lammps import PyLammps
|
||||
# OR pass them individually
|
||||
L.cmd.region("box block", 0, 10, 0, 5, -0.5, 0.5)
|
||||
|
||||
L = PyLammps()
|
||||
In the latter example, all parameters except the first are Python floating-point literals. The
|
||||
member function takes the entire parameter list and transparently merges it to a single command
|
||||
string.
|
||||
|
||||
# pass command parameters as one string
|
||||
L.region("box block 0 10 0 5 -0.5 0.5")
|
||||
The benefit of this approach is avoiding redundant command calls and easier
|
||||
parameterization. With `command`, `commands_list`, and `commands_string` the
|
||||
parameterization needed to be done manually by creating formatted command
|
||||
strings.
|
||||
|
||||
# OR pass them individually
|
||||
L.region("box block", 0, 10, 0, 5, -0.5, 0.5)
|
||||
.. code-block:: python
|
||||
|
||||
In the latter example, all parameters except the first are Python floating-point literals. The
|
||||
member function takes the entire parameter list and transparently merges it to a single command
|
||||
string.
|
||||
lmp.command("region box block %f %f %f %f %f %f" % (xlo, xhi, ylo, yhi, zlo, zhi))
|
||||
|
||||
The benefit of this approach is avoiding redundant command calls and easier
|
||||
parameterization. In the lammps API parameterization needed to be done
|
||||
manually by creating formatted command strings.
|
||||
In contrast, methods of the `cmd` wrapper accept parameters directly and will convert
|
||||
them automatically to a final command string.
|
||||
|
||||
.. code-block:: python
|
||||
.. code-block:: python
|
||||
|
||||
lmp.command("region box block %f %f %f %f %f %f" % (xlo, xhi, ylo, yhi, zlo, zhi))
|
||||
L.cmd.region("box block", xlo, xhi, ylo, yhi, zlo, zhi)
|
||||
|
||||
In contrast, methods of PyLammps accept parameters directly and will convert
|
||||
them automatically to a final command string.
|
||||
.. note::
|
||||
|
||||
.. code-block:: python
|
||||
When running in IPython you can use Tab-completion after ``L.cmd.`` to see
|
||||
all available LAMMPS commands.
|
||||
|
||||
L.region("box block", xlo, xhi, ylo, yhi, zlo, zhi)
|
||||
Using these facilities, the previous example shown above can be rewritten as follows:
|
||||
|
||||
Using these facilities, the example shown for the lammps API can be rewritten as follows:
|
||||
.. code-block:: python
|
||||
|
||||
.. code-block:: python
|
||||
from lammps import lammps
|
||||
L = lammps()
|
||||
|
||||
from lammps import PyLammps
|
||||
L = PyLammps()
|
||||
# read commands from file 'in.melt'
|
||||
L.file('in.melt')
|
||||
|
||||
# read commands from file 'in.melt'
|
||||
L.file('in.melt')
|
||||
# issue a single command
|
||||
L.cmd.variable('zpos', 'index', 1.0)
|
||||
|
||||
# issue a single command
|
||||
L.variable('zpos', 'index', 1.0)
|
||||
# create 10 groups with 10 atoms each
|
||||
for i in range(10):
|
||||
L.cmd.group(f"g{i}", "id", f"{10*i+1}:{10*(i+1)}")
|
||||
|
||||
# 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}")
|
||||
L.cmd.clear()
|
||||
L.cmd.region("box block", 0, 2, 0, 2, 0, 2)
|
||||
L.cmd.create_box(1, "box")
|
||||
L.cmd.create_atoms(1, "single", 1.0, 1.0, "${zpos}")
|
||||
|
||||
@ -15,6 +15,7 @@ together.
|
||||
Python_call
|
||||
Python_formats
|
||||
Python_examples
|
||||
Python_jupyter
|
||||
Python_error
|
||||
Python_trouble
|
||||
|
||||
|
||||
45
doc/src/Python_jupyter.rst
Normal file
45
doc/src/Python_jupyter.rst
Normal file
@ -0,0 +1,45 @@
|
||||
Using LAMMPS in IPython notebooks and Jupyter
|
||||
=============================================
|
||||
|
||||
If the LAMMPS Python package is installed for the same Python interpreter as
|
||||
`IPython <ipython>`_, you can use LAMMPS directly inside of an IPython notebook inside of
|
||||
Jupyter. `Jupyter <juypter>`_ is a powerful integrated development environment (IDE) for
|
||||
many dynamic languages like Python, Julia and others, which operates inside of
|
||||
any web browser. Besides auto-completion and syntax highlighting it allows you
|
||||
to create formatted documents using Markup, mathematical formulas, graphics and
|
||||
animations intermixed with executable Python code. It is a great format for
|
||||
tutorials and showcasing your latest research.
|
||||
|
||||
The easiest way to install it is via ``pip``:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pip install --user jupyter
|
||||
|
||||
To launch an instance of Jupyter simply run the following command inside your
|
||||
Python environment:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
jupyter notebook
|
||||
|
||||
Interactive Python Examples
|
||||
---------------------------
|
||||
|
||||
Examples of IPython notebooks can be found in the ``python/examples/ipython``
|
||||
subdirectory. They require LAMMPS to be compiled as shared library with PYTHON,
|
||||
PNG, JPEG and FFMPEG support.
|
||||
|
||||
To open these notebooks launch ``jupyter notebook index.ipynb`` inside this
|
||||
directory. The opened file provides an overview of the available examples.
|
||||
|
||||
- Example 1: Using LAMMPS with Python (``simple.ipynb``)
|
||||
- Example 2: Analyzing LAMMPS thermodynamic data (``thermo.ipynb``)
|
||||
- Example 3: Working with Per-Atom Data (``atoms.ipynb``)
|
||||
- Example 4: Working with LAMMPS variables (``variables.ipynb``)
|
||||
- Example 5: Validating a dihedral potential (``dihedrals/dihedral.ipynb``)
|
||||
- Example 6: Running a Monte Carlo relaxation (``montecarlo/mc.ipynb``)
|
||||
|
||||
.. note::
|
||||
|
||||
Typically clicking a link in Jupyter will open a new tab, which might be blocked by your pop-up blocker.
|
||||
@ -10,19 +10,11 @@ be installed into a Python system folder or a user folder with ``make
|
||||
install-python``. Components of the module can then loaded into a Python
|
||||
session with the ``import`` command.
|
||||
|
||||
There are multiple Python interface classes in the :py:mod:`lammps` module:
|
||||
.. warning::
|
||||
|
||||
- the :py:class:`lammps <lammps.lammps>` class. This is a wrapper around
|
||||
the C-library interface and its member functions try to replicate the
|
||||
:ref:`C-library API <lammps_c_api>` closely. This is the most
|
||||
feature-complete Python API.
|
||||
- the :py:class:`PyLammps <lammps.PyLammps>` class. This is a more high-level
|
||||
and more Python style class implemented on top of the
|
||||
:py:class:`lammps <lammps.lammps>` class.
|
||||
- the :py:class:`IPyLammps <lammps.IPyLammps>` class is derived from
|
||||
:py:class:`PyLammps <lammps.PyLammps>` and adds embedded graphics
|
||||
features to conveniently include LAMMPS into `Jupyter
|
||||
<https://jupyter.org/>`_ notebooks.
|
||||
Alternative interfaces such as :py:class:`PyLammps <lammps.PyLammps>` and
|
||||
:py:class:`IPyLammps <lammps.IPyLammps>` classes have been deprecated and
|
||||
will be removed in a future version of LAMMPS.
|
||||
|
||||
.. _mpi4py_url: https://mpi4py.readthedocs.io
|
||||
|
||||
@ -49,7 +41,7 @@ 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
|
||||
Python interface. It is a wrapper around the :ref:`LAMMPS C library
|
||||
API <lammps_c_api>` using the `Python ctypes module
|
||||
<https://docs.python.org/3/library/ctypes.html>`_ and a shared library
|
||||
compiled from the LAMMPS sources code. The individual methods in this
|
||||
@ -64,40 +56,7 @@ functions. Below is a detailed documentation of the API.
|
||||
.. autoclass:: lammps.numpy_wrapper::numpy_wrapper
|
||||
:members:
|
||||
|
||||
----------
|
||||
|
||||
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
|
||||
data structures are exposed through objects and properties. This makes Python
|
||||
scripts shorter and more concise. See the :doc:`PyLammps Tutorial
|
||||
<Howto_pylammps>` for an introduction on how to use this interface.
|
||||
|
||||
.. autoclass:: lammps.PyLammps
|
||||
:members:
|
||||
|
||||
.. autoclass:: lammps.AtomList
|
||||
:members:
|
||||
|
||||
.. autoclass:: lammps.Atom
|
||||
:members:
|
||||
|
||||
.. autoclass:: lammps.Atom2D
|
||||
:members:
|
||||
|
||||
----------
|
||||
|
||||
The ``IPyLammps`` class API
|
||||
===========================
|
||||
|
||||
The :py:class:`IPyLammps <lammps.PyLammps>` class is an extension of
|
||||
:py:class:`PyLammps <lammps.PyLammps>`, adding additional functions to
|
||||
quickly display visualizations such as images and videos inside of IPython.
|
||||
See the :doc:`PyLammps Tutorial <Howto_pylammps>` for examples.
|
||||
|
||||
.. autoclass:: lammps.IPyLammps
|
||||
.. autoclass:: lammps.ipython::wrapper
|
||||
:members:
|
||||
|
||||
----------
|
||||
|
||||
@ -4,95 +4,52 @@ Compute, fixes, variables
|
||||
This section documents accessing or modifying data from objects like
|
||||
computes, fixes, or variables in LAMMPS using the :py:mod:`lammps` module.
|
||||
|
||||
.. tabs::
|
||||
For :py:meth:`lammps.extract_compute() <lammps.lammps.extract_compute()>` and
|
||||
:py:meth:`lammps.extract_fix() <lammps.lammps.extract_fix()>`, the global, per-atom,
|
||||
or local data calculated by the compute or fix can be accessed. What is returned
|
||||
depends on whether the compute or fix calculates a scalar or vector or array.
|
||||
For a scalar, a single double value is returned. If the compute or fix calculates
|
||||
a vector or array, a pointer to the internal LAMMPS data is returned, which you can
|
||||
use via normal Python subscripting.
|
||||
|
||||
.. tab:: lammps API
|
||||
The one exception is that for a fix that calculates a
|
||||
global vector or array, a single double value from the vector or array
|
||||
is returned, indexed by I (vector) or I and J (array). I,J are
|
||||
zero-based indices.
|
||||
See the :doc:`Howto output <Howto_output>` page for a discussion of
|
||||
global, per-atom, and local data, and of scalar, vector, and array
|
||||
data types. See the doc pages for individual :doc:`computes <compute>`
|
||||
and :doc:`fixes <fix>` for a description of what they calculate and
|
||||
store.
|
||||
|
||||
For :py:meth:`lammps.extract_compute() <lammps.lammps.extract_compute()>` and
|
||||
:py:meth:`lammps.extract_fix() <lammps.lammps.extract_fix()>`, the global, per-atom,
|
||||
or local data calculated by the compute or fix can be accessed. What is returned
|
||||
depends on whether the compute or fix calculates a scalar or vector or array.
|
||||
For a scalar, a single double value is returned. If the compute or fix calculates
|
||||
a vector or array, a pointer to the internal LAMMPS data is returned, which you can
|
||||
use via normal Python subscripting.
|
||||
For :py:meth:`lammps.extract_variable() <lammps.lammps.extract_variable()>`,
|
||||
an :doc:`equal-style or atom-style variable <variable>` is evaluated and
|
||||
its result returned.
|
||||
|
||||
The one exception is that for a fix that calculates a
|
||||
global vector or array, a single double value from the vector or array
|
||||
is returned, indexed by I (vector) or I and J (array). I,J are
|
||||
zero-based indices.
|
||||
See the :doc:`Howto output <Howto_output>` page for a discussion of
|
||||
global, per-atom, and local data, and of scalar, vector, and array
|
||||
data types. See the doc pages for individual :doc:`computes <compute>`
|
||||
and :doc:`fixes <fix>` for a description of what they calculate and
|
||||
store.
|
||||
For equal-style variables a single ``c_double`` value is returned and the
|
||||
group argument is ignored. For atom-style variables, a vector of
|
||||
``c_double`` 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.
|
||||
|
||||
For :py:meth:`lammps.extract_variable() <lammps.lammps.extract_variable()>`,
|
||||
an :doc:`equal-style or atom-style variable <variable>` is evaluated and
|
||||
its result returned.
|
||||
:py:meth:`lammps.numpy.extract_compute() <lammps.numpy_wrapper.numpy_wrapper.extract_compute()>`,
|
||||
:py:meth:`lammps.numpy.extract_fix() <lammps.numpy_wrapper.numpy_wrapper.extract_fix()>`, and
|
||||
:py:meth:`lammps.numpy.extract_variable() <lammps.numpy_wrapper.numpy_wrapper.extract_variable()>` are
|
||||
equivalent NumPy implementations that return NumPy arrays instead of ``ctypes`` pointers.
|
||||
|
||||
For equal-style variables a single ``c_double`` value is returned and the
|
||||
group argument is ignored. For atom-style variables, a vector of
|
||||
``c_double`` 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 :py:meth:`lammps.set_variable() <lammps.lammps.set_variable()>` method sets an
|
||||
existing string-style variable to a new string value, so that subsequent LAMMPS
|
||||
commands can access the variable.
|
||||
|
||||
:py:meth:`lammps.numpy.extract_compute() <lammps.numpy_wrapper.numpy_wrapper.extract_compute()>`,
|
||||
:py:meth:`lammps.numpy.extract_fix() <lammps.numpy_wrapper.numpy_wrapper.extract_fix()>`, and
|
||||
:py:meth:`lammps.numpy.extract_variable() <lammps.numpy_wrapper.numpy_wrapper.extract_variable()>` are
|
||||
equivalent NumPy implementations that return NumPy arrays instead of ``ctypes`` pointers.
|
||||
**Methods**:
|
||||
|
||||
The :py:meth:`lammps.set_variable() <lammps.lammps.set_variable()>` method sets an
|
||||
existing string-style variable to a new string value, so that subsequent LAMMPS
|
||||
commands can access the variable.
|
||||
* :py:meth:`lammps.extract_compute() <lammps.lammps.extract_compute()>`: extract value(s) from a compute
|
||||
* :py:meth:`lammps.extract_fix() <lammps.lammps.extract_fix()>`: extract value(s) from a fix
|
||||
* :py:meth:`lammps.extract_variable() <lammps.lammps.extract_variable()>`: extract value(s) from a variable
|
||||
* :py:meth:`lammps.set_variable() <lammps.lammps.set_variable()>`: set existing named string-style variable to value
|
||||
|
||||
**Methods**:
|
||||
**NumPy Methods**:
|
||||
|
||||
* :py:meth:`lammps.extract_compute() <lammps.lammps.extract_compute()>`: extract value(s) from a compute
|
||||
* :py:meth:`lammps.extract_fix() <lammps.lammps.extract_fix()>`: extract value(s) from a fix
|
||||
* :py:meth:`lammps.extract_variable() <lammps.lammps.extract_variable()>`: extract value(s) from a variable
|
||||
* :py:meth:`lammps.set_variable() <lammps.lammps.set_variable()>`: set existing named string-style variable to value
|
||||
|
||||
**NumPy Methods**:
|
||||
|
||||
* :py:meth:`lammps.numpy.extract_compute() <lammps.numpy_wrapper.numpy_wrapper.extract_compute()>`: extract value(s) from a compute, return arrays as numpy arrays
|
||||
* :py:meth:`lammps.numpy.extract_fix() <lammps.numpy_wrapper.numpy_wrapper.extract_fix()>`: extract value(s) from a fix, return arrays as numpy arrays
|
||||
* :py:meth:`lammps.numpy.extract_variable() <lammps.numpy_wrapper.numpy_wrapper.extract_variable()>`: extract value(s) from a variable, return arrays as numpy arrays
|
||||
|
||||
|
||||
.. tab:: PyLammps/IPyLammps API
|
||||
|
||||
PyLammps and IPyLammps classes currently do not add any additional ways of
|
||||
retrieving information out of computes and fixes. This information can still be accessed by using the lammps API:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
L.lmp.extract_compute(...)
|
||||
L.lmp.extract_fix(...)
|
||||
# OR
|
||||
L.lmp.numpy.extract_compute(...)
|
||||
L.lmp.numpy.extract_fix(...)
|
||||
|
||||
LAMMPS variables can be both defined and accessed via the :py:class:`PyLammps <lammps.PyLammps>` interface.
|
||||
|
||||
To define a variable you can use the :doc:`variable <variable>` command:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
L.variable("a index 2")
|
||||
|
||||
A dictionary of all variables is returned by the :py:attr:`PyLammps.variables <lammps.PyLammps.variables>` property:
|
||||
|
||||
you can access an individual variable by retrieving a variable object from the
|
||||
``L.variables`` dictionary by name
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
a = L.variables['a']
|
||||
|
||||
The variable value can then be easily read and written by accessing the value
|
||||
property of this object.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
print(a.value)
|
||||
a.value = 4
|
||||
* :py:meth:`lammps.numpy.extract_compute() <lammps.numpy_wrapper.numpy_wrapper.extract_compute()>`: extract value(s) from a compute, return arrays as numpy arrays
|
||||
* :py:meth:`lammps.numpy.extract_fix() <lammps.numpy_wrapper.numpy_wrapper.extract_fix()>`: extract value(s) from a fix, return arrays as numpy arrays
|
||||
* :py:meth:`lammps.numpy.extract_variable() <lammps.numpy_wrapper.numpy_wrapper.extract_variable()>`: extract value(s) from a variable, return arrays as numpy arrays
|
||||
|
||||
@ -56,7 +56,7 @@ Below is an example output for Python version 3.8.5.
|
||||
|
||||
---------
|
||||
|
||||
LAMMPS can work together with Python in three ways. First, Python can
|
||||
LAMMPS can work together with Python in two ways. First, Python can
|
||||
wrap LAMMPS through the its :doc:`library interface <Library>`, so
|
||||
that a Python script can create one or more instances of LAMMPS and
|
||||
launch one or more simulations. In Python terms, this is referred to as
|
||||
@ -67,22 +67,7 @@ launch one or more simulations. In Python terms, this is referred to as
|
||||
|
||||
Launching LAMMPS via Python
|
||||
|
||||
|
||||
Second, the lower-level Python interface in the :py:class:`lammps Python
|
||||
class <lammps.lammps>` can be used indirectly through the provided
|
||||
:py:class:`PyLammps <lammps.PyLammps>` and :py:class:`IPyLammps
|
||||
<lammps.IPyLammps>` wrapper classes, also written in Python. These
|
||||
wrappers try to simplify the usage of LAMMPS in Python by providing a
|
||||
more object-based interface to common LAMMPS functionality. They also
|
||||
reduce 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
|
||||
Second, 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 functions you write.
|
||||
This Python code can also call back to LAMMPS to query or change its
|
||||
|
||||
@ -2,14 +2,8 @@ System properties
|
||||
=================
|
||||
|
||||
Similar to what is described in :doc:`Library_properties`, the instances of
|
||||
:py:class:`lammps <lammps.lammps>`, :py:class:`PyLammps <lammps.PyLammps>`, or
|
||||
:py:class:`IPyLammps <lammps.IPyLammps>` can be used to extract different kinds
|
||||
of information about the active LAMMPS instance and also to modify some of it. The
|
||||
main difference between the interfaces is how the information is exposed.
|
||||
|
||||
While the :py:class:`lammps <lammps.lammps>` is just a thin layer that wraps C API calls,
|
||||
:py:class:`PyLammps <lammps.PyLammps>` and :py:class:`IPyLammps <lammps.IPyLammps>` expose
|
||||
information as objects and properties.
|
||||
:py:class:`lammps <lammps.lammps>` can be used to extract different kinds
|
||||
of information about the active LAMMPS instance and also to modify some of it.
|
||||
|
||||
In some cases the data returned is a direct reference to the original data
|
||||
inside LAMMPS cast to ``ctypes`` pointers. Where possible, the wrappers will
|
||||
@ -25,113 +19,38 @@ against invalid accesses.
|
||||
accordingly. These arrays can change sizes and order at every neighbor list
|
||||
rebuild and atom sort event as atoms are migrating between subdomains.
|
||||
|
||||
.. tabs::
|
||||
.. code-block:: python
|
||||
|
||||
.. tab:: lammps API
|
||||
from lammps import lammps
|
||||
|
||||
.. code-block:: python
|
||||
lmp = lammps()
|
||||
lmp.file("in.sysinit")
|
||||
|
||||
from lammps import lammps
|
||||
natoms = lmp.get_natoms()
|
||||
print(f"running simulation with {natoms} atoms")
|
||||
|
||||
lmp = lammps()
|
||||
lmp.file("in.sysinit")
|
||||
lmp.command("run 1000 post no");
|
||||
|
||||
natoms = lmp.get_natoms()
|
||||
print(f"running simulation with {natoms} atoms")
|
||||
for i in range(10):
|
||||
lmp.command("run 100 pre no post no")
|
||||
pe = lmp.get_thermo("pe")
|
||||
ke = lmp.get_thermo("ke")
|
||||
print(f"PE = {pe}\nKE = {ke}")
|
||||
|
||||
lmp.command("run 1000 post no");
|
||||
lmp.close()
|
||||
|
||||
for i in range(10):
|
||||
lmp.command("run 100 pre no post no")
|
||||
pe = lmp.get_thermo("pe")
|
||||
ke = lmp.get_thermo("ke")
|
||||
print(f"PE = {pe}\nKE = {ke}")
|
||||
**Methods**:
|
||||
|
||||
lmp.close()
|
||||
* :py:meth:`version() <lammps.lammps.version()>`: return the numerical version id, e.g. LAMMPS 2 Sep 2015 -> 20150902
|
||||
* :py:meth:`get_thermo() <lammps.lammps.get_thermo()>`: return current value of a thermo keyword
|
||||
* :py:meth:`last_thermo() <lammps.lammps.last_thermo()>`: return a dictionary of the last thermodynamic output
|
||||
* :py:meth:`get_natoms() <lammps.lammps.get_natoms()>`: total # of atoms as int
|
||||
* :py:meth:`reset_box() <lammps.lammps.reset_box()>`: reset the simulation box size
|
||||
* :py:meth:`extract_setting() <lammps.lammps.extract_setting()>`: return a global setting
|
||||
* :py:meth:`extract_global() <lammps.lammps.extract_global()>`: extract a global quantity
|
||||
* :py:meth:`extract_box() <lammps.lammps.extract_box()>`: extract box info
|
||||
* :py:meth:`create_atoms() <lammps.lammps.create_atoms()>`: create N atoms with IDs, types, x, v, and image flags
|
||||
|
||||
**Methods**:
|
||||
**Properties**:
|
||||
|
||||
* :py:meth:`version() <lammps.lammps.version()>`: return the numerical version id, e.g. LAMMPS 2 Sep 2015 -> 20150902
|
||||
* :py:meth:`get_thermo() <lammps.lammps.get_thermo()>`: return current value of a thermo keyword
|
||||
* :py:meth:`last_thermo() <lammps.lammps.last_thermo()>`: return a dictionary of the last thermodynamic output
|
||||
* :py:meth:`get_natoms() <lammps.lammps.get_natoms()>`: total # of atoms as int
|
||||
* :py:meth:`reset_box() <lammps.lammps.reset_box()>`: reset the simulation box size
|
||||
* :py:meth:`extract_setting() <lammps.lammps.extract_setting()>`: return a global setting
|
||||
* :py:meth:`extract_global() <lammps.lammps.extract_global()>`: extract a global quantity
|
||||
* :py:meth:`extract_box() <lammps.lammps.extract_box()>`: extract box info
|
||||
* :py:meth:`create_atoms() <lammps.lammps.create_atoms()>`: create N atoms with IDs, types, x, v, and image flags
|
||||
|
||||
**Properties**:
|
||||
|
||||
* :py:attr:`last_thermo_step <lammps.lammps.last_thermo_step>`: the last timestep thermodynamic output was computed
|
||||
|
||||
.. tab:: PyLammps/IPyLammps API
|
||||
|
||||
In addition to the functions provided by :py:class:`lammps <lammps.lammps>`, :py:class:`PyLammps <lammps.PyLammps>` objects
|
||||
have several properties which allow you to query the system state:
|
||||
|
||||
L.system
|
||||
Is a dictionary describing the system such as the bounding box or number of atoms
|
||||
|
||||
L.system.xlo, L.system.xhi
|
||||
bounding box limits along x-axis
|
||||
|
||||
L.system.ylo, L.system.yhi
|
||||
bounding box limits along y-axis
|
||||
|
||||
L.system.zlo, L.system.zhi
|
||||
bounding box limits along z-axis
|
||||
|
||||
L.communication
|
||||
configuration of communication subsystem, such as the number of threads or processors
|
||||
|
||||
L.communication.nthreads
|
||||
number of threads used by each LAMMPS process
|
||||
|
||||
L.communication.nprocs
|
||||
number of MPI processes used by LAMMPS
|
||||
|
||||
L.fixes
|
||||
List of fixes in the current system
|
||||
|
||||
L.computes
|
||||
List of active computes in the current system
|
||||
|
||||
L.dump
|
||||
List of active dumps in the current system
|
||||
|
||||
L.groups
|
||||
List of groups present in the current system
|
||||
|
||||
**Retrieving the value of an arbitrary LAMMPS expressions**
|
||||
|
||||
LAMMPS expressions can be immediately evaluated by using the ``eval`` method. The
|
||||
passed string parameter can be any expression containing global :doc:`thermo` values,
|
||||
variables, compute or fix data (see :doc:`Howto_output`):
|
||||
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
result = L.eval("ke") # kinetic energy
|
||||
result = L.eval("pe") # potential energy
|
||||
|
||||
result = L.eval("v_t/2.0")
|
||||
|
||||
**Example**
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from lammps import PyLammps
|
||||
|
||||
L = PyLammps()
|
||||
L.file("in.sysinit")
|
||||
|
||||
print(f"running simulation with {L.system.natoms} atoms")
|
||||
|
||||
L.run(1000, "post no");
|
||||
|
||||
for i in range(10):
|
||||
L.run(100, "pre no post no")
|
||||
pe = L.eval("pe")
|
||||
ke = L.eval("ke")
|
||||
print(f"PE = {pe}\nKE = {ke}")
|
||||
* :py:attr:`last_thermo_step <lammps.lammps.last_thermo_step>`: the last timestep thermodynamic output was computed
|
||||
|
||||
@ -9,3 +9,4 @@ Pygments
|
||||
six
|
||||
pyyaml
|
||||
linkchecker
|
||||
ipython
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
# PyLammps and Jupyter Notebooks
|
||||
# IPython and Jupyter Notebooks
|
||||
|
||||
This folder contains examples showcasing the usage of the PyLammps Python
|
||||
This folder contains examples showcasing the usage of the LAMMPS Python
|
||||
interface and Jupyter notebooks. To use this you will need LAMMPS compiled as
|
||||
a shared library and the LAMMPS Python package installed.
|
||||
|
||||
An extensive guide on how to achieve this is documented in the [LAMMPS manual](https://docs.lammps.org/Python_install.html). There is also a [PyLammps tutorial](https://docs.lammps.org/Howto_pylammps.html).
|
||||
An extensive guide on how to achieve this is documented in the [LAMMPS manual](https://docs.lammps.org/Python_install.html). There is also a [LAMMPS Python tutorial](https://docs.lammps.org/Howto_python.html).
|
||||
|
||||
The following will show one way of creating a Python virtual environment
|
||||
which has both LAMMPS and its Python package installed:
|
||||
@ -53,7 +53,7 @@ which has both LAMMPS and its Python package installed:
|
||||
```shell
|
||||
(myenv)$ cmake -C ../cmake/presets/basic.cmake \
|
||||
-D BUILD_SHARED_LIBS=on \
|
||||
-D LAMMPS_EXCEPTIONS=on -D PKG_PYTHON=on \
|
||||
-D PKG_PYTHON=on \
|
||||
-D CMAKE_INSTALL_PREFIX=$VIRTUAL_ENV \
|
||||
../cmake
|
||||
```
|
||||
@ -67,19 +67,19 @@ which has both LAMMPS and its Python package installed:
|
||||
8. Install LAMMPS and Python package into virtual environment
|
||||
|
||||
```shell
|
||||
(myenv)$ cmake --install .
|
||||
(myenv)$ make install-python
|
||||
```
|
||||
|
||||
9. Install other Python packages into virtual environment
|
||||
|
||||
```shell
|
||||
(myenv)$ pip install jupyter matplotlib mpi4py
|
||||
(myenv)$ pip install jupyter matplotlib pandas mpi4py
|
||||
```
|
||||
|
||||
10. Navigate to pylammps examples folder
|
||||
10. Navigate to ipython examples folder
|
||||
|
||||
```shell
|
||||
(myenv)$ cd ../python/examples/pylammmps
|
||||
(myenv)$ cd ../python/examples/ipython
|
||||
```
|
||||
|
||||
11. Launch Jupyter and work inside browser
|
||||
224
python/examples/ipython/atoms.ipynb
Normal file
224
python/examples/ipython/atoms.ipynb
Normal file
@ -0,0 +1,224 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"<div style=\"text-align: center\"><a href=\"index.ipynb\">LAMMPS Python Tutorials</a></div>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Example 3: Working with Per-Atom Data"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Author: [Richard Berger](mailto:richard.berger@outlook.com)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"2D circle of particles inside of box with LJ walls"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Setup system"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from lammps import lammps"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L = lammps()\n",
|
||||
"cmd = L.cmd"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 2d circle of particles inside a box with LJ walls\n",
|
||||
"import math\n",
|
||||
"\n",
|
||||
"b = 0\n",
|
||||
"x = 50\n",
|
||||
"y = 20\n",
|
||||
"d = 20\n",
|
||||
"\n",
|
||||
"# careful not to slam into wall too hard\n",
|
||||
"\n",
|
||||
"v = 0.3\n",
|
||||
"w = 0.08\n",
|
||||
" \n",
|
||||
"cmd.units(\"lj\")\n",
|
||||
"cmd.dimension(2)\n",
|
||||
"cmd.atom_style(\"bond\")\n",
|
||||
"cmd.boundary(\"f f p\")\n",
|
||||
"\n",
|
||||
"cmd.lattice(\"hex\", 0.85)\n",
|
||||
"cmd.region(\"box\", \"block\", 0, x, 0, y, -0.5, 0.5)\n",
|
||||
"cmd.create_box(1, \"box\", \"bond/types\", 1, \"extra/bond/per/atom\", 6)\n",
|
||||
"cmd.region(\"circle\", \"sphere\", d/2.0+1.0, d/2.0/math.sqrt(3.0)+1, 0.0, d/2.0)\n",
|
||||
"cmd.create_atoms(1, \"region\", \"circle\")\n",
|
||||
"cmd.mass(1, 1.0)\n",
|
||||
"\n",
|
||||
"cmd.velocity(\"all create 0.5 87287 loop geom\")\n",
|
||||
"cmd.velocity(\"all set\", v, w, 0, \"sum yes\")\n",
|
||||
"\n",
|
||||
"cmd.pair_style(\"lj/cut\", 2.5)\n",
|
||||
"cmd.pair_coeff(1, 1, 10.0, 1.0, 2.5)\n",
|
||||
"\n",
|
||||
"cmd.bond_style(\"harmonic\")\n",
|
||||
"cmd.bond_coeff(1, 10.0, 1.2)\n",
|
||||
"\n",
|
||||
"cmd.create_bonds(\"many\", \"all\", \"all\", 1, 1.0, 1.5)\n",
|
||||
"\n",
|
||||
"cmd.neighbor(0.3, \"bin\")\n",
|
||||
"cmd.neigh_modify(\"delay\", 0, \"every\", 1, \"check yes\")\n",
|
||||
"\n",
|
||||
"cmd.fix(1, \"all\", \"nve\")\n",
|
||||
"\n",
|
||||
"cmd.fix(2, \"all wall/lj93 xlo 0.0 1 1 2.5 xhi\", x, \"1 1 2.5\")\n",
|
||||
"cmd.fix(3, \"all wall/lj93 ylo 0.0 1 1 2.5 yhi\", y, \"1 1 2.5\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Visualize initial state"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.ipython.image(zoom=1.8)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Run simulation and visualize new state"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"cmd.thermo_style(\"custom step temp epair press\")\n",
|
||||
"cmd.thermo(100)\n",
|
||||
"output = cmd.run(40000)\n",
|
||||
"L.ipython.image(zoom=1.8)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Accessing Atom data"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.numpy.extract_atom(\"x\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.numpy.extract_atom(\"id\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.numpy.extract_atom(\"v\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.numpy.extract_atom(\"f\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.numpy.extract_atom(\"type\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.12.7"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 4
|
||||
}
|
||||
@ -4,7 +4,14 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Validating a dihedral potential"
|
||||
"<div style=\"text-align: center\"><a href=\"../index.ipynb\">LAMMPS Python Tutorials</a></div>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Example 4: Validating a dihedral potential"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -13,7 +20,8 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%matplotlib notebook"
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"from lammps import lammps"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -22,25 +30,8 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import matplotlib.pyplot as plt"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from lammps import IPyLammps"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L = IPyLammps()"
|
||||
"L = lammps()\n",
|
||||
"cmd = L.cmd"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -51,13 +42,13 @@
|
||||
"source": [
|
||||
"import math\n",
|
||||
"\n",
|
||||
"L.units(\"real\")\n",
|
||||
"L.atom_style(\"molecular\")\n",
|
||||
"cmd.units(\"real\")\n",
|
||||
"cmd.atom_style(\"molecular\")\n",
|
||||
"\n",
|
||||
"L.boundary(\"f f f\")\n",
|
||||
"L.neighbor(0.3, \"bin\")\n",
|
||||
"cmd.boundary(\"f f f\")\n",
|
||||
"cmd.neighbor(0.3, \"bin\")\n",
|
||||
"\n",
|
||||
"L.dihedral_style(\"harmonic\")"
|
||||
"cmd.dihedral_style(\"harmonic\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -66,7 +57,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.read_data(\"data.dihedral\")"
|
||||
"cmd.read_data(\"data.dihedral\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -75,8 +66,8 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.pair_style(\"zero\", 5)\n",
|
||||
"L.pair_coeff(\"*\", \"*\")"
|
||||
"cmd.pair_style(\"zero\", 5)\n",
|
||||
"cmd.pair_coeff(\"*\", \"*\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -85,7 +76,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.mass(1, 1.0)"
|
||||
"cmd.mass(1, 1.0)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -94,7 +85,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.velocity(\"all\", \"set\", 0.0, 0.0, 0.0)"
|
||||
"cmd.velocity(\"all\", \"set\", 0.0, 0.0, 0.0)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -103,7 +94,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.run(0);"
|
||||
"cmd.run(0, \"post\", \"no\");"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -112,7 +103,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.image(zoom=1.0)"
|
||||
"L.ipython.image(zoom=1.0,size=[320,320])"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -121,7 +112,8 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.atoms[3].position"
|
||||
"x = L.numpy.extract_atom(\"x\")\n",
|
||||
"print(x[3])"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -130,7 +122,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.atoms[3].position = (1.0, 0.0, 1.0)"
|
||||
"x[3] = (1.0, 0.0, 1.0)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -139,7 +131,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.image(zoom=1.0)"
|
||||
"L.ipython.image(zoom=1.0,size=[320,320])"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -148,7 +140,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.eval(\"pe\")"
|
||||
"L.get_thermo(\"pe\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -157,7 +149,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.atoms[3].position = (1.0, 0.0, -1.0)"
|
||||
"x[3] = (1.0, 0.0, -1.0)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -166,7 +158,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.run(0);"
|
||||
"cmd.run(0, \"post\", \"no\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -207,9 +199,9 @@
|
||||
"source": [
|
||||
"pe = []\n",
|
||||
"for p in pos:\n",
|
||||
" L.atoms[3].position = p\n",
|
||||
" L.run(0);\n",
|
||||
" pe.append(L.eval(\"pe\"))"
|
||||
" x[3] = p\n",
|
||||
" cmd.run(0, \"post\", \"no\");\n",
|
||||
" pe.append(L.get_thermo(\"pe\"))"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -233,7 +225,7 @@
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
@ -247,9 +239,9 @@
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.9.2"
|
||||
"version": "3.12.7"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 1
|
||||
"nbformat_minor": 4
|
||||
}
|
||||
@ -158,7 +158,8 @@ def elastic():
|
||||
parser.add_argument("--up", type=float, default=1.0e-6, help="the deformation magnitude (in strain units)")
|
||||
args = parser.parse_args()
|
||||
|
||||
L = PyLammps()
|
||||
lmp = lammps()
|
||||
L = lmp.cmd
|
||||
|
||||
L.units("metal")
|
||||
|
||||
63
python/examples/ipython/index.ipynb
Normal file
63
python/examples/ipython/index.ipynb
Normal file
@ -0,0 +1,63 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "666d3036-47d5-44d2-bc1a-ca4b00a9e9b8",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# LAMMPS Python Tutorials"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "f1422a43-f76b-456b-bf76-61ad92bd4ff0",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Author: [Richard Berger](mailto:richard.berger@outlook.com)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "8f2ea92d-8cc3-4999-81a0-79aa55bb66ab",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Contents\n",
|
||||
"\n",
|
||||
"- [Example 1: Using LAMMPS with Python](simple.ipynb)\n",
|
||||
"- [Example 2: Analyzing LAMMPS thermodynamic data](thermo.ipynb)\n",
|
||||
"- [Example 3: Using Atom Data](atoms.ipynb)\n",
|
||||
"- [Example 4: Validating a dihedral potential](dihedrals/dihedral.ipynb)\n",
|
||||
"- [Example 5: Running a Monte Carlo relaxation](montecarlo/mc.ipynb)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "b41dc533-be6d-4450-8ad7-7345e9f44ea3",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.12.7"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
@ -4,7 +4,14 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Monte Carlo Relaxation"
|
||||
"<div style=\"text-align: center\"><a href=\"../index.ipynb\">LAMMPS Python Tutorials</a></div>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Example 5: Monte Carlo Relaxation"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -13,16 +20,6 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from __future__ import print_function"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%matplotlib inline\n",
|
||||
"import matplotlib.pyplot as plt"
|
||||
]
|
||||
},
|
||||
@ -48,7 +45,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from lammps import IPyLammps"
|
||||
"from lammps import lammps"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -57,7 +54,8 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L = IPyLammps()"
|
||||
"L = lammps()\n",
|
||||
"cmd = L.cmd"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -66,25 +64,25 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.units(\"lj\")\n",
|
||||
"L.atom_style(\"atomic\")\n",
|
||||
"L.atom_modify(\"map array sort\", 0, 0.0)\n",
|
||||
"cmd.units(\"lj\")\n",
|
||||
"cmd.atom_style(\"atomic\")\n",
|
||||
"cmd.atom_modify(\"map array sort\", 0, 0.0)\n",
|
||||
"\n",
|
||||
"L.dimension(2)\n",
|
||||
"cmd.dimension(2)\n",
|
||||
"\n",
|
||||
"L.lattice(\"hex\", 1.0)\n",
|
||||
"L.region(\"box block\", 0, 10, 0, 5, -0.5, 0.5)\n",
|
||||
"cmd.lattice(\"hex\", 1.0)\n",
|
||||
"cmd.region(\"box block\", 0, 10, 0, 5, -0.5, 0.5)\n",
|
||||
"\n",
|
||||
"L.create_box(1, \"box\")\n",
|
||||
"L.create_atoms(1, \"box\")\n",
|
||||
"L.mass(1, 1.0)\n",
|
||||
"cmd.create_box(1, \"box\")\n",
|
||||
"cmd.create_atoms(1, \"box\")\n",
|
||||
"cmd.mass(1, 1.0)\n",
|
||||
"\n",
|
||||
"L.pair_style(\"lj/cut\", 2.5)\n",
|
||||
"L.pair_coeff(1, 1, 1.0, 1.0, 2.5)\n",
|
||||
"L.pair_modify(\"shift\", \"yes\")\n",
|
||||
"cmd.pair_style(\"lj/cut\", 2.5)\n",
|
||||
"cmd.pair_coeff(1, 1, 1.0, 1.0, 2.5)\n",
|
||||
"cmd.pair_modify(\"shift\", \"yes\")\n",
|
||||
"\n",
|
||||
"L.neighbor(0.3, \"bin\")\n",
|
||||
"L.neigh_modify(\"delay\", 0, \"every\", 1, \"check\", \"yes\")"
|
||||
"cmd.neighbor(0.3, \"bin\")\n",
|
||||
"cmd.neigh_modify(\"delay\", 0, \"every\", 1, \"check\", \"yes\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -93,7 +91,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.image(zoom=1.6)"
|
||||
"L.ipython.image(zoom=1.6,size=[320,320])"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -102,7 +100,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.run(0);"
|
||||
"cmd.run(0, \"post\", \"no\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -111,7 +109,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"emin = L.eval(\"pe\")"
|
||||
"emin = L.get_thermo(\"pe\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -120,7 +118,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.dump(\"3 all movie 25 movie.mp4 type type zoom 1.6 adiam 1.0\")"
|
||||
"cmd.dump(\"3 all movie 25 movie.mp4 type type zoom 1.6 adiam 1.0\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -146,11 +144,12 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"for i in range(L.system.natoms):\n",
|
||||
" x, y = L.atoms[i].position\n",
|
||||
"pos = L.numpy.extract_atom(\"x\")\n",
|
||||
"for i in range(len(pos)):\n",
|
||||
" x, y = pos[i][0], pos[i][1]\n",
|
||||
" dx = deltaperturb * random.uniform(-1, 1)\n",
|
||||
" dy = deltaperturb * random.uniform(-1, 1)\n",
|
||||
" L.atoms[i].position = (x+dx, y+dy)"
|
||||
" pos[i] = (x+dx, y+dy, 0)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -159,7 +158,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.run(0);"
|
||||
"cmd.run(0, \"post\", \"no\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -168,7 +167,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.image(zoom=1.6)"
|
||||
"L.ipython.image(zoom=1.6,size=[320,320])"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -184,7 +183,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"estart = L.eval(\"pe\")\n",
|
||||
"estart = L.get_thermo(\"pe\")\n",
|
||||
"elast = estart"
|
||||
]
|
||||
},
|
||||
@ -223,22 +222,23 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"natoms = L.system.natoms\n",
|
||||
"natoms = L.extract_global(\"natoms\")\n",
|
||||
"\n",
|
||||
"for i in range(niterations):\n",
|
||||
" pos = L.numpy.extract_atom(\"x\")\n",
|
||||
" iatom = random.randrange(0, natoms)\n",
|
||||
" current_atom = L.atoms[iatom]\n",
|
||||
" current_atom = pos[iatom]\n",
|
||||
" \n",
|
||||
" x0, y0 = current_atom.position\n",
|
||||
" x0, y0 = current_atom[0], current_atom[1]\n",
|
||||
" \n",
|
||||
" dx = deltamove * random.uniform(-1, 1)\n",
|
||||
" dy = deltamove * random.uniform(-1, 1)\n",
|
||||
" \n",
|
||||
" current_atom.position = (x0+dx, y0+dy)\n",
|
||||
" pos[iatom] = (x0+dx, y0+dy, 0)\n",
|
||||
" \n",
|
||||
" L.run(1, \"pre no post no\")\n",
|
||||
" cmd.run(1, \"pre no post no\")\n",
|
||||
" \n",
|
||||
" e = L.eval(\"pe\")\n",
|
||||
" e = L.get_thermo(\"pe\")\n",
|
||||
" energies.append(e)\n",
|
||||
" \n",
|
||||
" if e <= elast:\n",
|
||||
@ -248,7 +248,7 @@
|
||||
" naccept += 1\n",
|
||||
" elast = e\n",
|
||||
" else:\n",
|
||||
" current_atom.position = (x0, y0)"
|
||||
" pos[iatom] = (x0, y0, 0)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -268,7 +268,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.eval(\"pe\")"
|
||||
"L.get_thermo(\"pe\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -304,7 +304,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.image(zoom=1.6)"
|
||||
"L.ipython.image(zoom=1.6, size=[320,320])"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -314,7 +314,7 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# close dump file to access it\n",
|
||||
"L.undump(3)"
|
||||
"cmd.undump(3)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -323,7 +323,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.video(\"movie.mp4\")"
|
||||
"L.ipython.video(\"movie.mp4\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -336,7 +336,7 @@
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
@ -350,9 +350,9 @@
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.9.2"
|
||||
"version": "3.12.7"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 1
|
||||
"nbformat_minor": 4
|
||||
}
|
||||
@ -1,10 +1,10 @@
|
||||
from mpi4py import MPI
|
||||
from lammps import PyLammps
|
||||
from lammps import lammps
|
||||
|
||||
L = PyLammps()
|
||||
L = lammps()
|
||||
L.file('in.melt')
|
||||
|
||||
|
||||
if MPI.COMM_WORLD.rank == 0:
|
||||
pe = L.eval("pe")
|
||||
pe = L.get_thermo("pe")
|
||||
print("Potential Energy:", pe)
|
||||
@ -4,14 +4,28 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Example 1: Using LAMMPS with PyLammps"
|
||||
"<div style=\"text-align: center\"><a href=\"index.ipynb\">LAMMPS Python Tutorials</a></div>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"The LAMMPS Python package provides multiple interfaces. The `PyLammps` interface is a high-level abstration of the low-level `lammps` interface. `IPyLammps` further extends this interface with functions that are useful for Jupyter notebooks to enable embedding generated graphics and videos."
|
||||
"# Example 1: Using LAMMPS with Python"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Author: [Richard Berger](mailto:richard.berger@outlook.com)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"The LAMMPS Python package enables calling the LAMMPS C library API."
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -20,7 +34,7 @@
|
||||
"source": [
|
||||
"## Prerequisites\n",
|
||||
"\n",
|
||||
"Before Running this example, make sure your Python environment can find the LAMMPS shared library (`liblammps.so`) and the LAMMPS Python package is installed. If you followed the [README](README.md) in this folder, this should already be the case. You can also find more information about how to compile LAMMPS and install the LAMMPS Python package in the [LAMMPS manual](https://docs.lammps.org/Python_install.html). There is also a dedicated [PyLammps HowTo](https://docs.lammps.org/Howto_pylammps.html)."
|
||||
"Before running this example, make sure your Python environment can find the LAMMPS shared library (`liblammps.so`) and the LAMMPS Python package is installed. If you followed the [README](README.md) in this folder, this should already be the case. You can also find more information about how to compile LAMMPS and install the LAMMPS Python package in the [LAMMPS manual](https://docs.lammps.org/Python_install.html). There is also a dedicated [LAMMPS Python HowTo](https://docs.lammps.org/Howto_python.html)."
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -38,17 +52,17 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from lammps import IPyLammps\n",
|
||||
"L = IPyLammps()"
|
||||
"from lammps import lammps\n",
|
||||
"L = lammps()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"With `PyLammps`/`IPyLammps` you can write LAMMPS simulations similar to the input script language. Take the following LAMMPS input script:\n",
|
||||
"With the `lammps` class you can write LAMMPS simulations similar to the input script language. Take the following LAMMPS input script:\n",
|
||||
"\n",
|
||||
"```bash\n",
|
||||
"```lammps\n",
|
||||
"# 3d Lennard-Jones melt\n",
|
||||
"\n",
|
||||
"units lj\n",
|
||||
@ -72,7 +86,7 @@
|
||||
"\n",
|
||||
"thermo 50\n",
|
||||
"```\n",
|
||||
"The equivalent can be written with `PyLammps`/`IPyLammps`:"
|
||||
"The equivalent can be written in Python:"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -83,35 +97,33 @@
|
||||
"source": [
|
||||
"# 3d Lennard-Jones melt\n",
|
||||
"\n",
|
||||
"L.units(\"lj\")\n",
|
||||
"L.atom_style(\"atomic\")\n",
|
||||
"L.cmd.units(\"lj\")\n",
|
||||
"L.cmd.atom_style(\"atomic\")\n",
|
||||
"\n",
|
||||
"L.lattice(\"fcc\", 0.8442)\n",
|
||||
"L.region(\"box\", \"block\", 0, 4, 0, 4, 0, 4)\n",
|
||||
"L.create_box(1, \"box\")\n",
|
||||
"L.create_atoms(1, \"box\")\n",
|
||||
"L.mass(1, 1.0)\n",
|
||||
"L.cmd.lattice(\"fcc\", 0.8442)\n",
|
||||
"L.cmd.region(\"box\", \"block\", 0, 4, 0, 4, 0, 4)\n",
|
||||
"L.cmd.create_box(1, \"box\")\n",
|
||||
"L.cmd.create_atoms(1, \"box\")\n",
|
||||
"L.cmd.mass(1, 1.0)\n",
|
||||
"\n",
|
||||
"L.velocity(\"all\", \"create\", 1.44, 87287, \"loop geom\")\n",
|
||||
"L.cmd.velocity(\"all\", \"create\", 1.44, 87287, \"loop geom\")\n",
|
||||
"\n",
|
||||
"L.pair_style(\"lj/cut\", 2.5)\n",
|
||||
"L.pair_coeff(1, 1, 1.0, 1.0, 2.5)\n",
|
||||
"L.cmd.pair_style(\"lj/cut\", 2.5)\n",
|
||||
"L.cmd.pair_coeff(1, 1, 1.0, 1.0, 2.5)\n",
|
||||
"\n",
|
||||
"L.neighbor(0.3, \"bin\")\n",
|
||||
"L.neigh_modify(\"delay\", 0, \"every\", 20, \"check no\")\n",
|
||||
"L.cmd.neighbor(0.3, \"bin\")\n",
|
||||
"L.cmd.neigh_modify(\"delay\", 0, \"every\", 20, \"check no\")\n",
|
||||
"\n",
|
||||
"L.fix(\"1\", \"all\", \"nve\")\n",
|
||||
"L.cmd.fix(\"1\", \"all\", \"nve\")\n",
|
||||
"\n",
|
||||
"L.thermo(50)"
|
||||
"L.cmd.thermo(50)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Visualizing the initial state\n",
|
||||
"\n",
|
||||
"`IPyLammps` allows you to visualize the current simulation state with the [image](https://docs.lammps.org/Python_module.html#lammps.IPyLammps.image) command. Here we use it to create an image of the initial state of the system."
|
||||
"Some LAMMPS commands will produce output that will be visible in the notebook. However, due to buffering, it might not be shown right away. Use the `flush_buffers` method to see all the output that has been written so far."
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -120,7 +132,109 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.image(zoom=1.0)"
|
||||
"L.flush_buffers()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"An alternative to this is to enable auto flushing after each command by setting `cmd.auto_flush` to `True`. Each command will then call `flush_buffers()` automatically."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.cmd.auto_flush = True\n",
|
||||
"L.cmd.info(\"system\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"In many cases the LAMMPS output will become excessive, which is why you may want to suppress it. For this purpose we provide a IPython extension in the `lammps.ipython` package. To load the extension, add a code cell with the following content:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%load_ext lammps.ipython"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Once the extension is loaded you have access to the `%%capture_lammps_output` magic. In its simplest form it can be used to supress LAMMPS output:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%%capture_lammps_output\n",
|
||||
"L.cmd.info(\"system\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"You can also use the same `%%capture_lammps_output` magic to store the output in a variable by providing a variable name:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%%capture_lammps_output out\n",
|
||||
"L.cmd.info(\"system\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"In this case we are storing the output in a `out` variable. Note the output is only available after the cell has been executed, not within the same cell."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"print(out)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Visualizing the initial state\n",
|
||||
"\n",
|
||||
"The `lammps` class also has an `ipython` attribute which provides some basic visualization capabilities in IPython Jupyter notebooks. E.g., you can visualize the current simulation state with the [image](https://docs.lammps.org/Python_module.html#lammps.ipython_wrapper.image) command. Here we use it to create an image of the initial state of the system."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.ipython.image()"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -129,7 +243,7 @@
|
||||
"source": [
|
||||
"## Running simulations\n",
|
||||
"\n",
|
||||
"Use the `run` command to start the simulation. In Jupyter the return value of the last command will be displayed. The `run` command will return the output of the simulation."
|
||||
"Use the `run` command to start the simulation. It will print the output of the simulation."
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -138,23 +252,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.run(150)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"You can suppress it by adding a semicolon `;`."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.run(100);"
|
||||
"L.cmd.run(250)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -170,127 +268,23 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.image(zoom=1.0)"
|
||||
"L.ipython.image(zoom=1.0)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Post-processing thermo output\n",
|
||||
"## Conclusion\n",
|
||||
"This covered the basics of creating an instance of LAMMPS from Python, passing commands to LAMMPS and potentially supressing or capturing its output, and visualizing the system. In the [following tutorial](thermo.ipynb) we will look at how to process thermodynamic output from LAMMPS.\n",
|
||||
"\n",
|
||||
"Independent of whether or not you suppress or show the output of the `run` command, `PyLammps` will record the output. Each `run` command creates a new entry in the `L.runs` list. So far our PyLammps instance `L` executed two `run` commands:"
|
||||
"<div style=\"text-align:right\"><a href=\"thermo.ipynb\">Next</a>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"len(L.runs)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Each entry contains information about the simulation run, including the thermo output for the printed out time steps.\n",
|
||||
"\n",
|
||||
"```bash\n",
|
||||
"# thermo output of a LAMMPS simulation run\n",
|
||||
"Step Temp E_pair E_mol TotEng Press\n",
|
||||
" 0 1.44 -6.7733681 0 -4.6218056 -5.0244179\n",
|
||||
" 50 0.70303849 -5.6796164 0 -4.629178 0.50453907\n",
|
||||
" 100 0.72628044 -5.7150774 0 -4.6299123 0.29765862\n",
|
||||
" 150 0.78441711 -5.805142 0 -4.6331125 -0.086709661\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"`PyLammps` already parses this information and makes it available as dictionaries and arrays."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.runs[0]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.runs[1]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"For example, the first run was 150 time steps, with printing out a line every 50 steps. You can access the list of time steps using `{entry}.thermo.Step`."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.runs[0].thermo.Step"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"The corresponding values of each thermo quantity are also accessed this way:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.runs[0].thermo.TotEng"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Together you can use this information to run post-processing on these values or even plot it using `matplotlib`:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%matplotlib inline\n",
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"\n",
|
||||
"plt.xlabel('time step')\n",
|
||||
"plt.ylabel('Total Energy')\n",
|
||||
"plt.plot(L.runs[0].thermo.Step, L.runs[0].thermo.TotEng)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
@ -304,9 +298,9 @@
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.9.2"
|
||||
"version": "3.12.7"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 1
|
||||
"nbformat_minor": 4
|
||||
}
|
||||
323
python/examples/ipython/thermo.ipynb
Normal file
323
python/examples/ipython/thermo.ipynb
Normal file
@ -0,0 +1,323 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Example 2: Analyzing LAMMPS thermodynamic data"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Author: [Richard Berger](mailto:richard.berger@outlook.com)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"This tutorial assumes you've completed the [first example](simple.ipynb) and understand the basics of running LAMMPS through Python. In this tutorial we will build on top of that example and look at how to extract thermodynamic data produced by LAMMPS into Python and visualize it. Let's first start by recreating our simple melt example:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%load_ext lammps.ipython"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from lammps import lammps\n",
|
||||
"L = lammps()\n",
|
||||
"L.cmd.auto_flush = True\n",
|
||||
"\n",
|
||||
"def init_melt_system(L):\n",
|
||||
" # 3d Lennard-Jones melt\n",
|
||||
" L.cmd.clear()\n",
|
||||
" L.cmd.units(\"lj\")\n",
|
||||
" L.cmd.atom_style(\"atomic\")\n",
|
||||
" \n",
|
||||
" L.cmd.lattice(\"fcc\", 0.8442)\n",
|
||||
" L.cmd.region(\"box\", \"block\", 0, 4, 0, 4, 0, 4)\n",
|
||||
" L.cmd.create_box(1, \"box\")\n",
|
||||
" L.cmd.create_atoms(1, \"box\")\n",
|
||||
" L.cmd.mass(1, 1.0)\n",
|
||||
" \n",
|
||||
" L.cmd.velocity(\"all\", \"create\", 1.44, 87287, \"loop geom\")\n",
|
||||
" \n",
|
||||
" L.cmd.pair_style(\"lj/cut\", 2.5)\n",
|
||||
" L.cmd.pair_coeff(1, 1, 1.0, 1.0, 2.5)\n",
|
||||
" \n",
|
||||
" L.cmd.neighbor(0.3, \"bin\")\n",
|
||||
" L.cmd.neigh_modify(\"delay\", 0, \"every\", 20, \"check no\")\n",
|
||||
" \n",
|
||||
" L.cmd.fix(\"1\", \"all\", \"nve\")\n",
|
||||
" \n",
|
||||
" L.cmd.thermo(50)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Here we take advantage of the fact that we can write regular Python functions to organize our LAMMPS simulation. This allows us to clear and initialize a new system by calling the `init_melt_system()` function. With this we can now go ahead an run this simulation for 100 steps."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"init_melt_system(L)\n",
|
||||
"L.cmd.run(100)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Extracting thermodynamic data"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Looking at the above output we see that LAMMPS prints out thermodynamic data for steps 0, 50 and 100.\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
" Step Temp E_pair E_mol TotEng Press \n",
|
||||
" 0 1.44 -6.7733681 0 -4.6218056 -5.0244179 \n",
|
||||
" 50 0.70303849 -5.6796164 0 -4.629178 0.50453907 \n",
|
||||
" 100 0.72628044 -5.7150774 0 -4.6299123 0.29765862\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"We could parse the text output and extract the necessary information, but this has proven to be error-prone and clunky, especially in cases where other output gets interleaved with thermo output lines. Instead, we can make use of the Python integration within LAMMPS to execute arbitrary Python code during time steps using `fix python/invoke`. We can extract the thermodynamic data directly using the LAMMPS Python interface and process it in any way we want.\n",
|
||||
"\n",
|
||||
"For this we first define the data structure we want to use to store the data. For each column of the thermodynamic data we want to store a list of values for each time step. Let's use a Python `dict` with the following structure:\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"{'Step': [0, 50, 100, ...], 'Temp': [...], 'E_pair': [...], 'E_mol': [...], 'TotEng': [...], 'Press': [...]}\n",
|
||||
"```"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"To start, let's define an empty `dict` and call it `current_run`. As the simulation progresses, we append new data into this dictionary:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"current_run = {}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Next, let's define a function that should be executed every time step a thermodynamic output line would be written. This function takes a `lammps` class instance and through it can access LAMMPS state and data. We can use the [`last_thermo()`](https://docs.lammps.org/Python_module.html#lammps.lammps.last_thermo) function of the `lammps` class to get the latest thermodynamic data as a dictionary. This data is all we need to populate our `current_run` data structure."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def append_thermo_data(lmp):\n",
|
||||
" for k, v in lmp.last_thermo().items():\n",
|
||||
" current_run.setdefault(k, []).append(v)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"With these two pieces in place, it is now time to tell LAMMPS about how we want to call this function.\n",
|
||||
"\n",
|
||||
"First, let's suppress any LAMMPS output via `%%capture_lammps_output` and reinitialize our system with `init_melt_system()` so our system is back in its initial state and the time step is back to 0.\n",
|
||||
"\n",
|
||||
"Next, we add a new fix `python/invoke` that should execute every 50 time steps, the same as our `thermo 50` command above. At the end of every 50 time steps (including the first one), it should call the `append_thermo_data` function we just defined. Notice we can just pass the function as parameter. Finally, we tell LAMMPS to run for 250 steps."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%%capture_lammps_output\n",
|
||||
"init_melt_system(L)\n",
|
||||
"L.cmd.fix(\"myfix\", \"all\", \"python/invoke\", 50, \"end_of_step\", append_thermo_data)\n",
|
||||
"L.cmd.run(250)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Let's inspect our `current_run` dictionary after the run has completed:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"current_run"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"As we can see, the time steps 0, 50, 100, 150, and 200 were added to dictionary. However, the last time step 250 is still missing. For this we need to manually add a final call to our `append_thermo_data()` helper function."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"append_thermo_data(L)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"With this our `current_run` dictionary now has all the data of the completed run:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"current_run"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Plotting thermodynamic data with matplotlib\n",
|
||||
"\n",
|
||||
"Now that we have our data available as Python variables, we can easily use other libraries for visualization."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%matplotlib inline\n",
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"\n",
|
||||
"plt.xlabel('time step')\n",
|
||||
"plt.ylabel('Total Energy')\n",
|
||||
"plt.plot(current_run['Step'], current_run['TotEng'])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Using Pandas library\n",
|
||||
"\n",
|
||||
"Since we can call any Python code from LAMMPS, the above example can also be rewritten using the Pandas library:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%%capture_lammps_output\n",
|
||||
"import pandas as pd\n",
|
||||
"\n",
|
||||
"current_run = pd.DataFrame()\n",
|
||||
"\n",
|
||||
"def append_thermo_data(lmp):\n",
|
||||
" global current_run\n",
|
||||
" current_time_step = pd.DataFrame.from_records([lmp.last_thermo()])\n",
|
||||
" current_run = pd.concat([current_run, current_time_step], ignore_index=True)\n",
|
||||
"\n",
|
||||
"init_melt_system(L)\n",
|
||||
"L.cmd.fix(\"myfix\", \"all\", \"python/invoke\", 50, \"end_of_step\", append_thermo_data)\n",
|
||||
"L.cmd.run(250)\n",
|
||||
"append_thermo_data(L)\n",
|
||||
"current_run"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"current_run.plot(x='Step', y='TotEng')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Conclusion\n",
|
||||
"\n",
|
||||
"The Python interface gives you a powerful way of invoking and extracting simulation data while the simulation is running. Next we'll look at how to extract information about the atoms in your system.\n",
|
||||
"\n",
|
||||
"<div style=\"text-align:right\"><a href=\"atoms.ipynb\">Next</a>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.12.7"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 4
|
||||
}
|
||||
@ -1,546 +0,0 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Example 2: Using the PyLammps interface"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Prerequisites\n",
|
||||
"\n",
|
||||
"Before running this example, make sure your Python environment can find the LAMMPS shared library (`liblammps.so`) and the LAMMPS Python package is installed. If you followed the [README](README.md) in this folder, this should already be the case. You can also find more information about how to compile LAMMPS and install the LAMMPS Python package in the [LAMMPS manual](https://docs.lammps.org/Python_install.html). There is also a dedicated [PyLammps HowTo](https://docs.lammps.org/Howto_pylammps.html)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Setup system"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from lammps import IPyLammps"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L = IPyLammps()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 3d Lennard-Jones melt\n",
|
||||
"L.units(\"lj\")\n",
|
||||
"L.atom_style(\"atomic\")\n",
|
||||
"L.atom_modify(\"map array\")\n",
|
||||
"\n",
|
||||
"L.lattice(\"fcc\", 0.8442)\n",
|
||||
"L.region(\"box block\", 0, 4, 0, 4, 0, 4)\n",
|
||||
"L.create_box(1, \"box\")\n",
|
||||
"L.create_atoms(1, \"box\")\n",
|
||||
"L.mass(1, 1.0)\n",
|
||||
"\n",
|
||||
"L.velocity(\"all create\", 1.44, 87287, \"loop geom\")\n",
|
||||
"\n",
|
||||
"L.pair_style(\"lj/cut\", 2.5)\n",
|
||||
"L.pair_coeff(1, 1, 1.0, 1.0, 2.5)\n",
|
||||
"\n",
|
||||
"L.neighbor(0.3, \"bin\")\n",
|
||||
"L.neigh_modify(\"delay 0 every 20 check no\")\n",
|
||||
"\n",
|
||||
"L.fix(\"1 all nve\")\n",
|
||||
"\n",
|
||||
"L.variable(\"fx atom fx\")\n",
|
||||
"\n",
|
||||
"L.run(10)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Visualize the initial state"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.image(zoom=1)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Queries about LAMMPS simulation"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.system"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.system.natoms"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.communication"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.fixes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.computes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.dumps"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.groups"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Working with LAMMPS Variables"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.variable(\"a index 2\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.variables"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.variable(\"t equal temp\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.variables"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import sys\n",
|
||||
"\n",
|
||||
"if sys.version_info < (3, 0):\n",
|
||||
" # In Python 2 'print' is a restricted keyword, which is why you have to use the lmp_print function instead.\n",
|
||||
" x = float(L.lmp_print('\"${a}\"'))\n",
|
||||
"else:\n",
|
||||
" # In Python 3 the print function can be redefined.\n",
|
||||
" # x = float(L.print('\"${a}\"')\")\n",
|
||||
" \n",
|
||||
" # To avoid a syntax error in Python 2 executions of this notebook, this line is packed into an eval statement\n",
|
||||
" x = float(eval(\"L.print('\\\"${a}\\\"')\"))\n",
|
||||
"x"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.variables['t'].value"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.eval(\"v_t/2.0\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.variable(\"b index a b c\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.variables['b'].value"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.eval(\"v_b\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.variables['b'].definition"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.lmp.command('variable i loop 10')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.variable(\"i loop 10\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.variables['i'].value"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.next(\"i\")\n",
|
||||
"L.variables['i'].value"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.eval(\"ke\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Accessing Atom data"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.atoms[0]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"dir(L.atoms[0])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.atoms[0].position"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.atoms[0].id"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.atoms[0].velocity"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.atoms[0].force"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.atoms[0].type"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.variables['fx'].value"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Accessing thermo data"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.runs"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.runs[0]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.runs[0].thermo"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.runs[0].thermo"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"dir(L.runs[0].thermo)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Saving session to as LAMMPS input file"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"PyLammps can keep track of all LAMMPS commands that are executed. This allows you to prototype a script and then later on save it as a regular input script:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L = IPyLammps()\n",
|
||||
"\n",
|
||||
"# enable command history\n",
|
||||
"L.enable_cmd_history = True\n",
|
||||
"\n",
|
||||
"# 3d Lennard-Jones melt\n",
|
||||
"L.units(\"lj\")\n",
|
||||
"L.atom_style(\"atomic\")\n",
|
||||
"L.atom_modify(\"map array\")\n",
|
||||
"\n",
|
||||
"L.lattice(\"fcc\", 0.8442)\n",
|
||||
"L.region(\"box block\", 0, 4, 0, 4, 0, 4)\n",
|
||||
"L.create_box(1, \"box\")\n",
|
||||
"L.create_atoms(1, \"box\")\n",
|
||||
"L.mass(1, 1.0)\n",
|
||||
"\n",
|
||||
"L.velocity(\"all create\", 1.44, 87287, \"loop geom\")\n",
|
||||
"\n",
|
||||
"L.pair_style(\"lj/cut\", 2.5)\n",
|
||||
"L.pair_coeff(1, 1, 1.0, 1.0, 2.5)\n",
|
||||
"\n",
|
||||
"L.neighbor(0.3, \"bin\")\n",
|
||||
"L.neigh_modify(\"delay 0 every 20 check no\")\n",
|
||||
"\n",
|
||||
"L.fix(\"1 all nve\")\n",
|
||||
"\n",
|
||||
"L.run(10)\n",
|
||||
"\n",
|
||||
"# write LAMMPS input script with all commands executed so far (including implicit ones)\n",
|
||||
"L.write_script(\"in.output\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!cat in.output"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.9.2"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 1
|
||||
}
|
||||
@ -1,471 +0,0 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Example 3: 2D circle of particles inside of box with LJ walls"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Prerequisites\n",
|
||||
"\n",
|
||||
"Before running this example, make sure your Python environment can find the LAMMPS shared library (`liblammps.so`) and the LAMMPS Python package is installed. If you followed the [README](README.md) in this folder, this should already be the case. You can also find more information about how to compile LAMMPS and install the LAMMPS Python package in the [LAMMPS manual](https://docs.lammps.org/Python_install.html). There is also a dedicated [PyLammps HowTo](https://docs.lammps.org/Howto_pylammps.html)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Setup system"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from lammps import IPyLammps"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L = IPyLammps()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 2d circle of particles inside a box with LJ walls\n",
|
||||
"import math\n",
|
||||
"\n",
|
||||
"b = 0\n",
|
||||
"x = 50\n",
|
||||
"y = 20\n",
|
||||
"d = 20\n",
|
||||
"\n",
|
||||
"# careful not to slam into wall too hard\n",
|
||||
"\n",
|
||||
"v = 0.3\n",
|
||||
"w = 0.08\n",
|
||||
" \n",
|
||||
"L.units(\"lj\")\n",
|
||||
"L.dimension(2)\n",
|
||||
"L.atom_style(\"bond\")\n",
|
||||
"L.boundary(\"f f p\")\n",
|
||||
"\n",
|
||||
"L.lattice(\"hex\", 0.85)\n",
|
||||
"L.region(\"box\", \"block\", 0, x, 0, y, -0.5, 0.5)\n",
|
||||
"L.create_box(1, \"box\", \"bond/types\", 1, \"extra/bond/per/atom\", 6)\n",
|
||||
"L.region(\"circle\", \"sphere\", d/2.0+1.0, d/2.0/math.sqrt(3.0)+1, 0.0, d/2.0)\n",
|
||||
"L.create_atoms(1, \"region\", \"circle\")\n",
|
||||
"L.mass(1, 1.0)\n",
|
||||
"\n",
|
||||
"L.velocity(\"all create 0.5 87287 loop geom\")\n",
|
||||
"L.velocity(\"all set\", v, w, 0, \"sum yes\")\n",
|
||||
"\n",
|
||||
"L.pair_style(\"lj/cut\", 2.5)\n",
|
||||
"L.pair_coeff(1, 1, 10.0, 1.0, 2.5)\n",
|
||||
"\n",
|
||||
"L.bond_style(\"harmonic\")\n",
|
||||
"L.bond_coeff(1, 10.0, 1.2)\n",
|
||||
"\n",
|
||||
"L.create_bonds(\"many\", \"all\", \"all\", 1, 1.0, 1.5)\n",
|
||||
"\n",
|
||||
"L.neighbor(0.3, \"bin\")\n",
|
||||
"L.neigh_modify(\"delay\", 0, \"every\", 1, \"check yes\")\n",
|
||||
"\n",
|
||||
"L.fix(1, \"all\", \"nve\")\n",
|
||||
"\n",
|
||||
"L.fix(2, \"all wall/lj93 xlo 0.0 1 1 2.5 xhi\", x, \"1 1 2.5\")\n",
|
||||
"L.fix(3, \"all wall/lj93 ylo 0.0 1 1 2.5 yhi\", y, \"1 1 2.5\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Visualize initial state"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.image(zoom=1.8)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Run simulation and visualize new state"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.thermo_style(\"custom step temp epair press\")\n",
|
||||
"L.thermo(100)\n",
|
||||
"output = L.run(40000)\n",
|
||||
"L.image(zoom=1.8)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Queries about LAMMPS simulation"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.system"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.system.natoms"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.system.nbonds"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.system.nbondtypes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.communication"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.fixes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.computes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.dumps"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.groups"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Working with LAMMPS Variables"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.variable(\"a index 2\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.variables"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.variable(\"t equal temp\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.variables"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import sys\n",
|
||||
"\n",
|
||||
"if sys.version_info < (3, 0):\n",
|
||||
" # In Python 2 'print' is a restricted keyword, which is why you have to use the lmp_print function instead.\n",
|
||||
" x = float(L.lmp_print('\"${a}\"'))\n",
|
||||
"else:\n",
|
||||
" # In Python 3 the print function can be redefined.\n",
|
||||
" # x = float(L.print('\"${a}\"')\")\n",
|
||||
" \n",
|
||||
" # To avoid a syntax error in Python 2 executions of this notebook, this line is packed into an eval statement\n",
|
||||
" x = float(eval(\"L.print('\\\"${a}\\\"')\"))\n",
|
||||
"x"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.variables['t'].value"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.eval(\"v_t/2.0\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.variable(\"b index a b c\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.variables['b'].value"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.eval(\"v_b\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.variables['b'].definition"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.variable(\"i loop 10\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.variables['i'].value"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.next(\"i\")\n",
|
||||
"L.variables['i'].value"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.eval(\"ke\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Accessing Atom data"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.atoms[0]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"dir(L.atoms[0])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.atoms[0].position"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.atoms[0].id"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.atoms[0].velocity"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.atoms[0].force"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"L.atoms[0].type"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.9.2"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 1
|
||||
}
|
||||
@ -59,6 +59,87 @@ class ExceptionCheck:
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
class command_wrapper(object):
|
||||
def __init__(self, lmp):
|
||||
self.lmp = lmp
|
||||
self.auto_flush = False
|
||||
|
||||
def lmp_print(self, s):
|
||||
""" needed for Python2 compatibility, since print is a reserved keyword """
|
||||
return self.__getattr__("print")(s)
|
||||
|
||||
def __dir__(self):
|
||||
return sorted(set(['angle_coeff', 'angle_style', 'atom_modify', 'atom_style', 'atom_style',
|
||||
'bond_coeff', 'bond_style', 'boundary', 'change_box', 'communicate', 'compute',
|
||||
'create_atoms', 'create_box', 'delete_atoms', 'delete_bonds', 'dielectric',
|
||||
'dihedral_coeff', 'dihedral_style', 'dimension', 'dump', 'fix', 'fix_modify',
|
||||
'group', 'improper_coeff', 'improper_style', 'include', 'kspace_modify',
|
||||
'kspace_style', 'lattice', 'mass', 'minimize', 'min_style', 'neighbor',
|
||||
'neigh_modify', 'newton', 'nthreads', 'pair_coeff', 'pair_modify',
|
||||
'pair_style', 'processors', 'read', 'read_data', 'read_restart', 'region',
|
||||
'replicate', 'reset_timestep', 'restart', 'run', 'run_style', 'thermo',
|
||||
'thermo_modify', 'thermo_style', 'timestep', 'undump', 'unfix', 'units',
|
||||
'variable', 'velocity', 'write_restart'] + self.lmp.available_styles("command")))
|
||||
|
||||
def _wrap_args(self, x):
|
||||
if callable(x):
|
||||
if sys.version_info < (3,):
|
||||
raise Exception("Passing functions or lambdas directly as arguments is only supported in Python 3 or newer")
|
||||
import hashlib
|
||||
import __main__
|
||||
sha = hashlib.sha256()
|
||||
sha.update(str(x).encode())
|
||||
func_name = f"_lmp_cb_{sha.hexdigest()}"
|
||||
def handler(*args, **kwargs):
|
||||
args = list(args)
|
||||
args[0] = lammps(ptr=args[0])
|
||||
x(*args)
|
||||
setattr(__main__, func_name, handler)
|
||||
return func_name
|
||||
return x
|
||||
|
||||
def __getattr__(self, name):
|
||||
"""
|
||||
This method is where the Python 'magic' happens. If a method is not
|
||||
defined by the class command_wrapper, it assumes it is a LAMMPS command. It takes
|
||||
all the arguments, concatinates them to a single string, and executes it using
|
||||
:py:meth:`lammps.command()`.
|
||||
|
||||
Starting with Python 3.6 it also supports keyword arguments. key=value is
|
||||
transformed into 'key value'. Note, since these have come last in the
|
||||
parameter list, only a subset of LAMMPS commands can be used with this
|
||||
syntax.
|
||||
|
||||
LAMMPS commands that accept callback functions (such as fix python/invoke)
|
||||
can be passed functions and lambdas directly. The first argument of such
|
||||
callbacks will be an lammps object constructed from the passed LAMMPS
|
||||
pointer.
|
||||
|
||||
:return: line or list of lines of output, None if no output
|
||||
:rtype: list or string
|
||||
"""
|
||||
def handler(*args, **kwargs):
|
||||
cmd_args = [name] + [str(self._wrap_args(x)) for x in args]
|
||||
|
||||
if len(kwargs) > 0 and sys.version_info < (3,6):
|
||||
raise Exception("Keyword arguments are only supported in Python 3.6 or newer")
|
||||
|
||||
# Python 3.6+ maintains ordering of kwarg keys
|
||||
for k in kwargs.keys():
|
||||
cmd_args.append(k)
|
||||
if type(kwargs[k]) == bool:
|
||||
cmd_args.append("true" if kwargs[k] else "false")
|
||||
else:
|
||||
cmd_args.append(str(self._wrap_args(kwargs[k])))
|
||||
|
||||
cmd = ' '.join(cmd_args)
|
||||
self.lmp.command(cmd)
|
||||
if self.auto_flush:
|
||||
self.lmp.flush_buffers()
|
||||
return handler
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
class lammps(object):
|
||||
"""Create an instance of the LAMMPS Python class.
|
||||
|
||||
@ -103,6 +184,8 @@ class lammps(object):
|
||||
winpath = os.environ.get("LAMMPSDLLPATH")
|
||||
self.lib = None
|
||||
self.lmp = None
|
||||
self._cmd = None
|
||||
self._ipython = None
|
||||
|
||||
# if a pointer to a LAMMPS object is handed in
|
||||
# when being called from a Python interpreter
|
||||
@ -509,6 +592,61 @@ class lammps(object):
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
@property
|
||||
def cmd(self):
|
||||
""" Return object that acts as LAMMPS command wrapper
|
||||
|
||||
It provides alternative to :py:meth:`lammps.command` to call LAMMPS
|
||||
commands as if they were regular Python functions and enables auto-complete
|
||||
in interactive Python sessions.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from lammps import lammps
|
||||
|
||||
# melt example
|
||||
L = lammps()
|
||||
L.cmd.units("lj")
|
||||
L.cmd.atom_style("atomic")
|
||||
L.cmd.lattice("fcc", 0.8442)
|
||||
L.cmd.region("box block", 0, 10, 0, 10, 0, 10)
|
||||
L.cmd.create_box(1, "box")
|
||||
L.cmd.create_atoms(1, "box")
|
||||
L.cmd.mass(1, 1.0)
|
||||
L.cmd.velocity("all create", 3.0, 87287, "loop geom")
|
||||
L.cmd.pair_style("lj/cut", 2.5)
|
||||
L.cmd.pair_coeff(1, 1, 1.0, 1.0, 2.5)
|
||||
L.cmd.neighbor(0.3, "bin")
|
||||
L.cmd.neigh_modify(every=20, delay=0, check=False)
|
||||
L.cmd.fix(1, "all nve")
|
||||
L.cmd.thermo(50)
|
||||
L.cmd.run(250)
|
||||
|
||||
:return: instance of command_wrapper object
|
||||
:rtype: command_wrapper
|
||||
"""
|
||||
if not self._cmd:
|
||||
self._cmd = command_wrapper(self)
|
||||
return self._cmd
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
@property
|
||||
def ipython(self):
|
||||
""" Return object to access ipython extensions
|
||||
|
||||
Adds commands for visualization in IPython and Jupyter Notebooks.
|
||||
|
||||
:return: instance of ipython wrapper object
|
||||
:rtype: ipython.wrapper
|
||||
"""
|
||||
if not self._ipython:
|
||||
from .ipython import wrapper
|
||||
self._ipython = wrapper(self)
|
||||
return self._ipython
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
def close(self):
|
||||
"""Explicitly delete a LAMMPS instance through the C-library interface.
|
||||
|
||||
|
||||
23
python/lammps/ipython/__init__.py
Normal file
23
python/lammps/ipython/__init__.py
Normal file
@ -0,0 +1,23 @@
|
||||
# ----------------------------------------------------------------------
|
||||
# LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
|
||||
# https://www.lammps.org/ Sandia National Laboratories
|
||||
# LAMMPS Development team: developers@lammps.org
|
||||
#
|
||||
# Copyright (2003) Sandia Corporation. Under the terms of Contract
|
||||
# DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
|
||||
# certain rights in this software. This software is distributed under
|
||||
# the GNU General Public License.
|
||||
#
|
||||
# See the README file in the top-level LAMMPS directory.
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
################################################################################
|
||||
# IPython/Jupyter Notebook additions
|
||||
# Written by Richard Berger <richard.berger@outlook.com>
|
||||
################################################################################
|
||||
|
||||
from .wrapper import wrapper
|
||||
from .magics import LammpsMagics
|
||||
|
||||
def load_ipython_extension(ipython):
|
||||
ipython.register_magics(LammpsMagics)
|
||||
75
python/lammps/ipython/magics.py
Normal file
75
python/lammps/ipython/magics.py
Normal file
@ -0,0 +1,75 @@
|
||||
# ----------------------------------------------------------------------
|
||||
# LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
|
||||
# https://www.lammps.org/ Sandia National Laboratories
|
||||
# LAMMPS Development team: developers@lammps.org
|
||||
#
|
||||
# Copyright (2003) Sandia Corporation. Under the terms of Contract
|
||||
# DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
|
||||
# certain rights in this software. This software is distributed under
|
||||
# the GNU General Public License.
|
||||
#
|
||||
# See the README file in the top-level LAMMPS directory.
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
################################################################################
|
||||
# IPython/Jupyter Notebook additions
|
||||
# Written by Richard Berger <richard.berger@outlook.com>
|
||||
################################################################################
|
||||
|
||||
import io
|
||||
import os
|
||||
import sys
|
||||
import tempfile
|
||||
from IPython.core.magic import (Magics, magics_class, cell_magic)
|
||||
import IPython.core.magic_arguments as magic_arguments
|
||||
|
||||
class OutputCapture(object):
|
||||
""" Utility class to capture LAMMPS library output """
|
||||
def __init__(self):
|
||||
self.stdout_fd = 1
|
||||
self.captured_output = ""
|
||||
|
||||
def __enter__(self):
|
||||
self.tmpfile = tempfile.TemporaryFile(mode='w+b')
|
||||
|
||||
sys.stdout.flush()
|
||||
|
||||
# make copy of original stdout
|
||||
self.stdout_orig = os.dup(self.stdout_fd)
|
||||
|
||||
# replace stdout and redirect to temp file
|
||||
os.dup2(self.tmpfile.fileno(), self.stdout_fd)
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
os.dup2(self.stdout_orig, self.stdout_fd)
|
||||
os.close(self.stdout_orig)
|
||||
self.tmpfile.close()
|
||||
|
||||
@property
|
||||
def output(self):
|
||||
sys.stdout.flush()
|
||||
self.tmpfile.flush()
|
||||
self.tmpfile.seek(0, io.SEEK_SET)
|
||||
self.captured_output = self.tmpfile.read().decode('utf-8')
|
||||
return self.captured_output
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
@magics_class
|
||||
class LammpsMagics(Magics):
|
||||
@magic_arguments.magic_arguments()
|
||||
@magic_arguments.argument('output', type=str, default='', nargs='?',
|
||||
help="""The name of the variable in which to store output.
|
||||
|
||||
If unspecified, captured output is discarded.
|
||||
"""
|
||||
)
|
||||
@cell_magic
|
||||
def capture_lammps_output(self, line, cell):
|
||||
"""run the cell, capturing LAMMPS stdout and stderr."""
|
||||
args = magic_arguments.parse_argstring(self.capture_lammps_output, line)
|
||||
with OutputCapture() as capture:
|
||||
self.shell.run_cell(cell)
|
||||
if args.output:
|
||||
self.shell.user_ns[args.output] = capture.output
|
||||
113
python/lammps/ipython/wrapper.py
Normal file
113
python/lammps/ipython/wrapper.py
Normal file
@ -0,0 +1,113 @@
|
||||
# ----------------------------------------------------------------------
|
||||
# LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
|
||||
# https://www.lammps.org/ Sandia National Laboratories
|
||||
# LAMMPS Development team: developers@lammps.org
|
||||
#
|
||||
# Copyright (2003) Sandia Corporation. Under the terms of Contract
|
||||
# DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
|
||||
# certain rights in this software. This software is distributed under
|
||||
# the GNU General Public License.
|
||||
#
|
||||
# See the README file in the top-level LAMMPS directory.
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
################################################################################
|
||||
# IPython/Jupyter Notebook additions
|
||||
# Written by Richard Berger <richard.berger@outlook.com>
|
||||
################################################################################
|
||||
|
||||
class wrapper(object):
|
||||
"""lammps API IPython Wrapper
|
||||
|
||||
This is a wrapper class that provides additional methods on top of an
|
||||
existing :py:class:`lammps` instance. It provides additional methods
|
||||
that allow create and/or embed visualizations created by native LAMMPS
|
||||
commands.
|
||||
|
||||
There is no need to explicitly instantiate this class. Each instance
|
||||
of :py:class:`lammps` has a :py:attr:`ipython <lammps.ipython>` property
|
||||
that returns an instance.
|
||||
|
||||
:param lmp: instance of the :py:class:`lammps` class
|
||||
:type lmp: lammps
|
||||
"""
|
||||
def __init__(self, lmp):
|
||||
self.lmp = lmp
|
||||
|
||||
def image(self, filename="snapshot.png", group="all", color="type", diameter="type",
|
||||
size=None, view=None, center=None, up=None, zoom=1.0, background_color="white"):
|
||||
""" Generate image using write_dump command and display it
|
||||
|
||||
See :doc:`dump image <dump_image>` for more information.
|
||||
|
||||
:param filename: Name of the image file that should be generated. The extension determines whether it is PNG or JPEG
|
||||
:type filename: string
|
||||
:param group: the group of atoms write_image should use
|
||||
:type group: string
|
||||
:param color: name of property used to determine color
|
||||
:type color: string
|
||||
:param diameter: name of property used to determine atom diameter
|
||||
:type diameter: string
|
||||
:param size: dimensions of image
|
||||
:type size: tuple (width, height)
|
||||
:param view: view parameters
|
||||
:type view: tuple (theta, phi)
|
||||
:param center: center parameters
|
||||
:type center: tuple (flag, center_x, center_y, center_z)
|
||||
:param up: vector pointing to up direction
|
||||
:type up: tuple (up_x, up_y, up_z)
|
||||
:param zoom: zoom factor
|
||||
:type zoom: float
|
||||
:param background_color: background color of scene
|
||||
:type background_color: string
|
||||
|
||||
:return: Image instance used to display image in notebook
|
||||
:rtype: :py:class:`IPython.core.display.Image`
|
||||
"""
|
||||
cmd_args = [group, "image", filename, color, diameter]
|
||||
|
||||
if size is not None:
|
||||
width = size[0]
|
||||
height = size[1]
|
||||
cmd_args += ["size", width, height]
|
||||
|
||||
if view is not None:
|
||||
theta = view[0]
|
||||
phi = view[1]
|
||||
cmd_args += ["view", theta, phi]
|
||||
|
||||
if center is not None:
|
||||
flag = center[0]
|
||||
Cx = center[1]
|
||||
Cy = center[2]
|
||||
Cz = center[3]
|
||||
cmd_args += ["center", flag, Cx, Cy, Cz]
|
||||
|
||||
if up is not None:
|
||||
Ux = up[0]
|
||||
Uy = up[1]
|
||||
Uz = up[2]
|
||||
cmd_args += ["up", Ux, Uy, Uz]
|
||||
|
||||
if zoom is not None:
|
||||
cmd_args += ["zoom", zoom]
|
||||
|
||||
cmd_args.append("modify backcolor " + background_color)
|
||||
|
||||
self.lmp.cmd.write_dump(*cmd_args)
|
||||
from IPython.core.display import Image
|
||||
return Image(filename)
|
||||
|
||||
def video(self, filename):
|
||||
"""
|
||||
Load video from file
|
||||
|
||||
Can be used to visualize videos from :doc:`dump movie <dump_image>`.
|
||||
|
||||
:param filename: Path to video file
|
||||
:type filename: string
|
||||
:return: HTML Video Tag used by notebook to embed a video
|
||||
:rtype: :py:class:`IPython.display.HTML`
|
||||
"""
|
||||
from IPython.display import HTML
|
||||
return HTML("<video controls><source src=\"" + filename + "\"></video>")
|
||||
@ -428,6 +428,8 @@ class PyLammps(object):
|
||||
lower-level interface. The original interface can still be accessed via
|
||||
:py:attr:`PyLammps.lmp`.
|
||||
|
||||
.. deprecated:: TBA
|
||||
|
||||
:param name: "machine" name of the shared LAMMPS library ("mpi" loads ``liblammps_mpi.so``, "" loads ``liblammps.so``)
|
||||
:type name: string
|
||||
:param cmdargs: list of command line arguments to be passed to the :cpp:func:`lammps_open` function. The executable name is automatically added.
|
||||
@ -447,6 +449,12 @@ class PyLammps(object):
|
||||
"""
|
||||
|
||||
def __init__(self, name="", cmdargs=None, ptr=None, comm=None, verbose=False):
|
||||
print("WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING")
|
||||
print()
|
||||
print("The PyLammps interface is deprecated and will be removed in future versions.")
|
||||
print("Please use the lammps Python class instead.")
|
||||
print()
|
||||
print("WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING")
|
||||
self.has_echo = False
|
||||
self.verbose = verbose
|
||||
|
||||
|
||||
@ -26,7 +26,7 @@ class BinaryDistribution(Distribution):
|
||||
return True
|
||||
|
||||
if version_info.major >= 3:
|
||||
pkgs = ['lammps', 'lammps.mliap']
|
||||
pkgs = ['lammps', 'lammps.mliap', 'lammps.ipython']
|
||||
else:
|
||||
pkgs = ['lammps']
|
||||
|
||||
|
||||
@ -105,6 +105,11 @@ if(Python_EXECUTABLE)
|
||||
set_tests_properties(PythonPyLammps PROPERTIES ENVIRONMENT "${PYTHON_TEST_ENVIRONMENT}")
|
||||
endif()
|
||||
|
||||
add_test(NAME PythonCmdWrapper
|
||||
COMMAND ${PYTHON_TEST_RUNNER} ${CMAKE_CURRENT_SOURCE_DIR}/python-cmdwrapper.py -v
|
||||
WORKING_DIRECTORY ${EXECUTABLE_OUTPUT_PATH})
|
||||
set_tests_properties(PythonCmdWrapper PROPERTIES ENVIRONMENT "${PYTHON_TEST_ENVIRONMENT}")
|
||||
|
||||
add_test(NAME PythonFormats
|
||||
COMMAND ${PYTHON_TEST_RUNNER} ${CMAKE_CURRENT_SOURCE_DIR}/python-formats.py -v
|
||||
WORKING_DIRECTORY ${EXECUTABLE_OUTPUT_PATH})
|
||||
|
||||
97
unittest/python/python-cmdwrapper.py
Normal file
97
unittest/python/python-cmdwrapper.py
Normal file
@ -0,0 +1,97 @@
|
||||
import os,unittest
|
||||
from lammps import lammps
|
||||
|
||||
try:
|
||||
import numpy
|
||||
NUMPY_INSTALLED = True
|
||||
except ImportError:
|
||||
NUMPY_INSTALLED = False
|
||||
|
||||
@unittest.skipIf(not NUMPY_INSTALLED, "numpy is not available")
|
||||
class PythonCmdWrapper(unittest.TestCase):
|
||||
def setUp(self):
|
||||
machine = None
|
||||
if 'LAMMPS_MACHINE_NAME' in os.environ:
|
||||
machine=os.environ['LAMMPS_MACHINE_NAME']
|
||||
self.lmp = lammps(name=machine, cmdargs=['-nocite', '-log','none', '-echo', 'screen'])
|
||||
self.lmp.cmd.units("lj")
|
||||
self.lmp.cmd.atom_style("atomic")
|
||||
self.lmp.cmd.atom_modify("map array")
|
||||
|
||||
if 'LAMMPS_CMAKE_CACHE' in os.environ:
|
||||
self.cmake_cache = {}
|
||||
|
||||
with open(os.environ['LAMMPS_CMAKE_CACHE'], 'r') as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if not line or line.startswith('#') or line.startswith('//'): continue
|
||||
parts = line.split('=')
|
||||
key, value_type = parts[0].split(':')
|
||||
if len(parts) > 1:
|
||||
value = parts[1]
|
||||
if value_type == "BOOL":
|
||||
value = (value.upper() == "ON")
|
||||
else:
|
||||
value = None
|
||||
self.cmake_cache[key] = value
|
||||
|
||||
def tearDown(self):
|
||||
self.lmp.close()
|
||||
del self.lmp
|
||||
|
||||
def test_version(self):
|
||||
self.assertGreaterEqual(self.lmp.version(), 20200824)
|
||||
|
||||
def test_create_atoms(self):
|
||||
self.lmp.cmd.region("box block", 0, 2, 0, 2, 0, 2)
|
||||
self.lmp.cmd.create_box(1, "box")
|
||||
|
||||
x = [
|
||||
1.0, 1.0, 1.0,
|
||||
1.0, 1.0, 1.5
|
||||
]
|
||||
|
||||
types = [1, 1]
|
||||
|
||||
self.assertEqual(self.lmp.create_atoms(2, id=None, type=types, x=x), 2)
|
||||
self.assertEqual(self.lmp.extract_global("natoms"), 2)
|
||||
pos = self.lmp.numpy.extract_atom("x")
|
||||
self.assertEqual(pos.shape[0], 2)
|
||||
numpy.testing.assert_array_equal(pos[0], tuple(x[0:3]))
|
||||
numpy.testing.assert_array_equal(pos[1], tuple(x[3:6]))
|
||||
|
||||
def test_thermo_capture(self):
|
||||
self.lmp.cmd.lattice("fcc", 0.8442),
|
||||
self.lmp.cmd.region("box block", 0, 4, 0, 4, 0, 4)
|
||||
self.lmp.cmd.create_box(1, "box")
|
||||
self.lmp.cmd.create_atoms(1, "box")
|
||||
self.lmp.cmd.mass(1, 1.0)
|
||||
self.lmp.cmd.velocity("all create", 1.44, 87287, "loop geom")
|
||||
self.lmp.cmd.pair_style("lj/cut", 2.5)
|
||||
self.lmp.cmd.pair_coeff(1, 1, 1.0, 1.0, 2.5)
|
||||
self.lmp.cmd.neighbor(0.3, "bin")
|
||||
self.lmp.cmd.neigh_modify("delay 0 every 20 check no")
|
||||
self.lmp.cmd.fix("1 all nve")
|
||||
|
||||
current_run = {}
|
||||
|
||||
def append_thermo_data(lmp):
|
||||
for k, v in lmp.last_thermo().items():
|
||||
current_run.setdefault(k, []).append(v)
|
||||
|
||||
# thermo data is only captured during a run if PYTHON package is enabled
|
||||
# without it, it will only capture the final thermo at completion
|
||||
nvalues = 1
|
||||
if self.lmp.has_package("PYTHON"):
|
||||
self.lmp.cmd.fix("myfix", "all", "python/invoke", 10, "end_of_step", append_thermo_data)
|
||||
nvalues = 2
|
||||
|
||||
self.lmp.cmd.run(10)
|
||||
append_thermo_data(self.lmp)
|
||||
|
||||
for k in ('Step', 'Temp', 'E_pair', 'E_mol', 'TotEng', 'Press'):
|
||||
self.assertIn(k, current_run)
|
||||
self.assertEqual(len(current_run[k]), nvalues)
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user