Merge branch 'develop' into cmake-cpp-std-deprecation
This commit is contained in:
@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user