Merge branch 'develop' into cmake-cpp-std-deprecation

This commit is contained in:
Axel Kohlmeyer
2025-01-12 23:54:50 -05:00
39 changed files with 2011 additions and 2332 deletions

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

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