python: update examples and docs

This commit is contained in:
Richard Berger
2024-11-04 09:19:38 -07:00
committed by Richard Berger
parent 9da58b3ffc
commit 24a4ff78b6
31 changed files with 1608 additions and 1730 deletions

View File

@ -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

View File

@ -4,16 +4,21 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"# Example 3: 2D circle of particles inside of box with LJ walls"
"# Example 3: Example 3: Using Atom Data"
]
},
{
"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)."
"Author: [Richard Berger](mailto:richard.berger@outlook.com)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"2D circle of particles inside of box with LJ walls"
]
},
{
@ -29,7 +34,7 @@
"metadata": {},
"outputs": [],
"source": [
"from lammps import IPyLammps"
"from lammps import lammps"
]
},
{
@ -38,7 +43,8 @@
"metadata": {},
"outputs": [],
"source": [
"L = IPyLammps()"
"L = lammps()\n",
"cmd = L.cmd"
]
},
{
@ -60,36 +66,36 @@
"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",
"cmd.units(\"lj\")\n",
"cmd.dimension(2)\n",
"cmd.atom_style(\"bond\")\n",
"cmd.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",
"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",
"L.velocity(\"all create 0.5 87287 loop geom\")\n",
"L.velocity(\"all set\", v, w, 0, \"sum yes\")\n",
"cmd.velocity(\"all create 0.5 87287 loop geom\")\n",
"cmd.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",
"cmd.pair_style(\"lj/cut\", 2.5)\n",
"cmd.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",
"cmd.bond_style(\"harmonic\")\n",
"cmd.bond_coeff(1, 10.0, 1.2)\n",
"\n",
"L.create_bonds(\"many\", \"all\", \"all\", 1, 1.0, 1.5)\n",
"cmd.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",
"cmd.neighbor(0.3, \"bin\")\n",
"cmd.neigh_modify(\"delay\", 0, \"every\", 1, \"check yes\")\n",
"\n",
"L.fix(1, \"all\", \"nve\")\n",
"cmd.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\")"
"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\")"
]
},
{
@ -105,7 +111,7 @@
"metadata": {},
"outputs": [],
"source": [
"L.image(zoom=1.8)"
"L.ipython.image(zoom=1.8)"
]
},
{
@ -121,10 +127,10 @@
"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)"
"cmd.thermo_style(\"custom step temp epair press\")\n",
"cmd.thermo(100)\n",
"output = cmd.run(40000)\n",
"L.ipython.image(zoom=1.8)"
]
},
{
@ -366,7 +372,7 @@
"metadata": {},
"outputs": [],
"source": [
"L.eval(\"ke\")"
"L.expand(\"ke\")"
]
},
{
@ -382,7 +388,7 @@
"metadata": {},
"outputs": [],
"source": [
"L.atoms[0]"
"L.numpy.extract_atom(\"x\")"
]
},
{
@ -391,7 +397,7 @@
"metadata": {},
"outputs": [],
"source": [
"dir(L.atoms[0])"
"L.numpy.extract_atom(\"id\")"
]
},
{
@ -400,7 +406,7 @@
"metadata": {},
"outputs": [],
"source": [
"L.atoms[0].position"
"L.numpy.extract_atom(\"v\")"
]
},
{
@ -409,7 +415,7 @@
"metadata": {},
"outputs": [],
"source": [
"L.atoms[0].id"
"L.numpy.extract_atom(\"f\")"
]
},
{
@ -418,25 +424,7 @@
"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"
"L.numpy.extract_atom(\"type\")"
]
},
{
@ -449,7 +437,7 @@
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
@ -463,9 +451,9 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.2"
"version": "3.9.6"
}
},
"nbformat": 4,
"nbformat_minor": 1
"nbformat_minor": 4
}

View File

@ -13,7 +13,8 @@
"metadata": {},
"outputs": [],
"source": [
"%matplotlib notebook"
"import matplotlib.pyplot as plt\n",
"from lammps import lammps"
]
},
{
@ -22,25 +23,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 +35,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 +50,7 @@
"metadata": {},
"outputs": [],
"source": [
"L.read_data(\"data.dihedral\")"
"cmd.read_data(\"data.dihedral\")"
]
},
{
@ -75,8 +59,8 @@
"metadata": {},
"outputs": [],
"source": [
"L.pair_style(\"zero\", 5)\n",
"L.pair_coeff(\"*\", \"*\")"
"cmd.pair_style(\"zero\", 5)\n",
"cmd.pair_coeff(\"*\", \"*\")"
]
},
{
@ -85,7 +69,7 @@
"metadata": {},
"outputs": [],
"source": [
"L.mass(1, 1.0)"
"cmd.mass(1, 1.0)"
]
},
{
@ -94,7 +78,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 +87,7 @@
"metadata": {},
"outputs": [],
"source": [
"L.run(0);"
"cmd.run(0);"
]
},
{
@ -112,7 +96,7 @@
"metadata": {},
"outputs": [],
"source": [
"L.image(zoom=1.0)"
"L.ipython.image(zoom=1.0,size=[320,320])"
]
},
{
@ -121,7 +105,8 @@
"metadata": {},
"outputs": [],
"source": [
"L.atoms[3].position"
"x = L.numpy.extract_atom(\"x\")\n",
"print(x[3])"
]
},
{
@ -130,7 +115,7 @@
"metadata": {},
"outputs": [],
"source": [
"L.atoms[3].position = (1.0, 0.0, 1.0)"
"x[3] = (1.0, 0.0, 1.0)"
]
},
{
@ -139,7 +124,7 @@
"metadata": {},
"outputs": [],
"source": [
"L.image(zoom=1.0)"
"L.ipython.image(zoom=1.0,size=[320,320])"
]
},
{
@ -148,7 +133,7 @@
"metadata": {},
"outputs": [],
"source": [
"L.eval(\"pe\")"
"L.get_thermo(\"pe\")"
]
},
{
@ -157,7 +142,7 @@
"metadata": {},
"outputs": [],
"source": [
"L.atoms[3].position = (1.0, 0.0, -1.0)"
"x[3] = (1.0, 0.0, -1.0)"
]
},
{
@ -166,7 +151,7 @@
"metadata": {},
"outputs": [],
"source": [
"L.run(0);"
"cmd.run(0)"
]
},
{
@ -207,9 +192,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);\n",
" pe.append(L.get_thermo(\"pe\"))"
]
},
{
@ -233,7 +218,7 @@
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
@ -247,9 +232,9 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.2"
"version": "3.9.6"
}
},
"nbformat": 4,
"nbformat_minor": 1
"nbformat_minor": 4
}

View File

@ -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")

View File

@ -0,0 +1,61 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "666d3036-47d5-44d2-bc1a-ca4b00a9e9b8",
"metadata": {},
"source": [
"# LAMMPS IPython Tutorial"
]
},
{
"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](atom.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.9.6"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@ -13,16 +13,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 +38,7 @@
"metadata": {},
"outputs": [],
"source": [
"from lammps import IPyLammps"
"from lammps import lammps"
]
},
{
@ -57,7 +47,8 @@
"metadata": {},
"outputs": [],
"source": [
"L = IPyLammps()"
"L = lammps()\n",
"cmd = L.cmd"
]
},
{
@ -66,25 +57,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 +84,7 @@
"metadata": {},
"outputs": [],
"source": [
"L.image(zoom=1.6)"
"L.ipython.image(zoom=1.6,size=[320,320])"
]
},
{
@ -102,7 +93,7 @@
"metadata": {},
"outputs": [],
"source": [
"L.run(0);"
"cmd.run(0)"
]
},
{
@ -111,7 +102,7 @@
"metadata": {},
"outputs": [],
"source": [
"emin = L.eval(\"pe\")"
"emin = L.get_thermo(\"pe\")"
]
},
{
@ -120,7 +111,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 +137,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 +151,7 @@
"metadata": {},
"outputs": [],
"source": [
"L.run(0);"
"cmd.run(0)"
]
},
{
@ -168,7 +160,7 @@
"metadata": {},
"outputs": [],
"source": [
"L.image(zoom=1.6)"
"L.ipython.image(zoom=1.6,size=[320,320])"
]
},
{
@ -184,7 +176,7 @@
"metadata": {},
"outputs": [],
"source": [
"estart = L.eval(\"pe\")\n",
"estart = L.get_thermo(\"pe\")\n",
"elast = estart"
]
},
@ -223,22 +215,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 +241,7 @@
" naccept += 1\n",
" elast = e\n",
" else:\n",
" current_atom.position = (x0, y0)"
" pos[iatom] = (x0, y0, 0)"
]
},
{
@ -268,7 +261,7 @@
"metadata": {},
"outputs": [],
"source": [
"L.eval(\"pe\")"
"L.get_thermo(\"pe\")"
]
},
{
@ -304,7 +297,7 @@
"metadata": {},
"outputs": [],
"source": [
"L.image(zoom=1.6)"
"L.ipython.image(zoom=1.6, size=[320,320])"
]
},
{
@ -314,7 +307,7 @@
"outputs": [],
"source": [
"# close dump file to access it\n",
"L.undump(3)"
"cmd.undump(3)"
]
},
{
@ -323,7 +316,7 @@
"metadata": {},
"outputs": [],
"source": [
"L.video(\"movie.mp4\")"
"L.ipython.video(\"movie.mp4\")"
]
},
{
@ -336,7 +329,7 @@
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
@ -350,9 +343,9 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.2"
"version": "3.9.6"
}
},
"nbformat": 4,
"nbformat_minor": 1
"nbformat_minor": 4
}

View File

@ -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)

View File

@ -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.9.6"
}
},
"nbformat": 4,
"nbformat_minor": 1
"nbformat_minor": 4
}

View File

@ -0,0 +1,305 @@
{
"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')"
]
}
],
"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.9.6"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

View File

@ -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
}

View File

@ -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.

View 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)

View 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

View 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>")

View File

@ -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']