Merge branch 'master' into collected-small-changes
This commit is contained in:
@ -3,11 +3,16 @@
|
||||
#
|
||||
# Requires latest gcovr (for GCC 8.1 support):#
|
||||
# pip install git+https://github.com/gcovr/gcovr.git
|
||||
#
|
||||
# For Python coverage the coverage package needs to be installed
|
||||
###############################################################################
|
||||
if(ENABLE_COVERAGE)
|
||||
find_program(GCOVR_BINARY gcovr)
|
||||
find_package_handle_standard_args(GCOVR DEFAULT_MSG GCOVR_BINARY)
|
||||
|
||||
find_program(COVERAGE_BINARY coverage)
|
||||
find_package_handle_standard_args(COVERAGE DEFAULT_MSG COVERAGE_BINARY)
|
||||
|
||||
if(GCOVR_FOUND)
|
||||
get_filename_component(ABSOLUTE_LAMMPS_SOURCE_DIR ${LAMMPS_SOURCE_DIR} ABSOLUTE)
|
||||
|
||||
@ -46,4 +51,30 @@ if(ENABLE_COVERAGE)
|
||||
)
|
||||
add_dependencies(reset_coverage clean_coverage_html)
|
||||
endif()
|
||||
|
||||
if(COVERAGE_FOUND)
|
||||
set(PYTHON_COVERAGE_HTML_DIR ${CMAKE_BINARY_DIR}/python_coverage_html)
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_BINARY_DIR}/unittest/python/.coverage
|
||||
COMMAND ${COVERAGE_BINARY} combine
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/unittest/python
|
||||
COMMENT "Combine Python coverage files..."
|
||||
)
|
||||
|
||||
add_custom_target(
|
||||
gen_python_coverage_html
|
||||
COMMAND ${COVERAGE_BINARY} html -d ${PYTHON_COVERAGE_HTML_DIR}
|
||||
DEPENDS ${CMAKE_BINARY_DIR}/unittest/python/.coverage
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/unittest/python
|
||||
COMMENT "Generating HTML Python coverage report..."
|
||||
)
|
||||
|
||||
add_custom_target(
|
||||
gen_python_coverage_xml
|
||||
COMMAND ${COVERAGE_BINARY} xml -o ${CMAKE_BINARY_DIR}/python_coverage.xml
|
||||
DEPENDS ${CMAKE_BINARY_DIR}/unittest/python/.coverage
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/unittest/python
|
||||
COMMENT "Generating XML Python coverage report..."
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@ -26,6 +26,8 @@ computes, fixes, or variables in LAMMPS.
|
||||
|
||||
-----------------------
|
||||
|
||||
.. doxygenenum:: _LMP_DATATYPE_CONST
|
||||
|
||||
.. doxygenenum:: _LMP_STYLE_CONST
|
||||
|
||||
.. doxygenenum:: _LMP_TYPE_CONST
|
||||
|
||||
@ -84,11 +84,22 @@ event as atoms are migrating between sub-domains.
|
||||
|
||||
-----------------------
|
||||
|
||||
.. doxygenfunction:: lammps_extract_global_datatype
|
||||
:project: progguide
|
||||
|
||||
-----------------------
|
||||
|
||||
.. doxygenfunction:: lammps_extract_global
|
||||
:project: progguide
|
||||
|
||||
-----------------------
|
||||
|
||||
.. doxygenfunction:: lammps_extract_atom_datatype
|
||||
:project: progguide
|
||||
|
||||
|
||||
-----------------------
|
||||
|
||||
.. doxygenfunction:: lammps_extract_atom
|
||||
:project: progguide
|
||||
|
||||
|
||||
@ -28,16 +28,58 @@ There are multiple Python interface classes in the :py:mod:`lammps` module:
|
||||
|
||||
----------
|
||||
|
||||
Setting up a Python virtual environment
|
||||
***************************************
|
||||
|
||||
LAMMPS and its Python module can be installed together into a Python virtual
|
||||
environment. This lets you isolate your customized Python environment from
|
||||
your user or system installation. The following is a minimal working example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# create and change into build directory
|
||||
mkdir build
|
||||
cd build
|
||||
|
||||
# create virtual environment
|
||||
virtualenv myenv
|
||||
|
||||
# Add venv lib folder to LD_LIBRARY_PATH when activating it
|
||||
echo 'export LD_LIBRARY_PATH=$VIRTUAL_ENV/lib:$LD_LIBRARY_PATH' >> myenv/bin/activate
|
||||
|
||||
# Add LAMMPS_POTENTIALS path when activating venv
|
||||
echo 'export LAMMPS_POTENTIALS=$VIRTUAL_ENV/share/lammps/potentials' >> myenv/bin/activate
|
||||
|
||||
# activate environment
|
||||
source myenv/bin/activate
|
||||
|
||||
# configure LAMMPS compilation
|
||||
# compiles as shared library with PYTHON package and C++ exceptions
|
||||
# and installs into myvenv
|
||||
(myenv)$ cmake -C ../cmake/presets/minimal.cmake \
|
||||
-D BUILD_SHARED_LIBS=on \
|
||||
-D PKG_PYTHON=on \
|
||||
-D LAMMPS_EXCEPTIONS=on \
|
||||
-D CMAKE_INSTALL_PREFIX=$VIRTUAL_ENV \
|
||||
../cmake
|
||||
|
||||
# compile LAMMPS
|
||||
(myenv)$ cmake --build . --parallel
|
||||
|
||||
# install LAMMPS into myvenv
|
||||
(myenv)$ cmake --install .
|
||||
|
||||
Creating or deleting a LAMMPS object
|
||||
************************************
|
||||
|
||||
With the Python interface the creation of a :cpp:class:`LAMMPS
|
||||
<LAMMPS_NS::LAMMPS>` instance is included in the constructor for the
|
||||
:py:func:`lammps <lammps.lammps>` class. Internally it will call either
|
||||
:cpp:func:`lammps_open` or :cpp:func:`lammps_open_no_mpi` from the C
|
||||
<LAMMPS_NS::LAMMPS>` instance is included in the constructors for the
|
||||
:py:meth:`lammps <lammps.lammps.__init__()>`, :py:meth:`PyLammps <lammps.PyLammps.__init__()>`,
|
||||
and :py:meth:`PyLammps <lammps.IPyLammps.__init__()>` classes.
|
||||
Internally it will call either :cpp:func:`lammps_open` or :cpp:func:`lammps_open_no_mpi` from the C
|
||||
library API to create the class instance.
|
||||
|
||||
All arguments are optional. The *name* argument is to allow loading a
|
||||
All arguments are optional. The *name* argument allows loading a
|
||||
LAMMPS shared library that is named ``liblammps_machine.so`` instead of
|
||||
the default name of ``liblammps.so``. In most cases the latter will be
|
||||
installed or used. The *ptr* argument is for use of the
|
||||
@ -48,22 +90,99 @@ to the Python class and used instead of creating a new instance. The
|
||||
*comm* argument may be used in combination with the `mpi4py <mpi4py_url_>`_
|
||||
module to pass an MPI communicator to LAMMPS and thus it is possible
|
||||
to run the Python module like the library interface on a subset of the
|
||||
MPI ranks after splitting the communicator. Here is a simple example:
|
||||
MPI ranks after splitting the communicator.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from lammps import lammps
|
||||
Here are simple examples using all three Python interfaces:
|
||||
|
||||
# NOTE: argv[0] is set by the Python module
|
||||
args = ["-log", "none"]
|
||||
# create LAMMPS instance
|
||||
lmp = lammps(cmdargs=args)
|
||||
# get and print numerical version code
|
||||
print("LAMMPS Version: ", lmp.version())
|
||||
# explicitly close and delete LAMMPS instance (optional)
|
||||
lmp.close()
|
||||
.. tabs::
|
||||
|
||||
Same as with the :ref:`C library API <lammps_c_api>` this will use the
|
||||
.. tab:: lammps API
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from lammps import lammps
|
||||
|
||||
# NOTE: argv[0] is set by the lammps class constructor
|
||||
args = ["-log", "none"]
|
||||
# create LAMMPS instance
|
||||
lmp = lammps(cmdargs=args)
|
||||
# get and print numerical version code
|
||||
print("LAMMPS Version: ", lmp.version())
|
||||
# explicitly close and delete LAMMPS instance (optional)
|
||||
lmp.close()
|
||||
|
||||
.. tab:: PyLammps API
|
||||
|
||||
The :py:class:`PyLammps` class is a wrapper around the
|
||||
:py:class:`lammps` class and all of its lower level functions.
|
||||
By default, it will create a new instance of :py:class:`lammps` passing
|
||||
along all arguments to the constructor of :py:class:`lammps`.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from lammps import PyLammps
|
||||
|
||||
# NOTE: argv[0] is set by the lammps class constructor
|
||||
args = ["-log", "none"]
|
||||
# create LAMMPS instance
|
||||
L = PyLammps(cmdargs=args)
|
||||
# get and print numerical version code
|
||||
print("LAMMPS Version: ", L.version())
|
||||
# explicitly close and delete LAMMPS instance (optional)
|
||||
L.close()
|
||||
|
||||
:py:class:`PyLammps` objects can also be created on top of an existing :py:class:`lammps` object:
|
||||
|
||||
.. code-block:: Python
|
||||
|
||||
from lammps import lammps, PyLammps
|
||||
...
|
||||
# create LAMMPS instance
|
||||
lmp = lammps(cmdargs=args)
|
||||
# create PyLammps instance using previously created LAMMPS instance
|
||||
L = PyLammps(ptr=lmp)
|
||||
|
||||
This is useful if you have to create the :py:class:`lammps <lammps.lammps>`
|
||||
instance is a specific way, but want to take advantage of the
|
||||
:py:class:`PyLammps <lammps.PyLammps>` interface.
|
||||
|
||||
.. tab:: IPyLammps API
|
||||
|
||||
The :py:class:`IPyLammps` class is an extension of the
|
||||
:py:class:`PyLammps` class. It has the same construction behavior. By
|
||||
default, it will create a new instance of :py:class:`lammps` passing
|
||||
along all arguments to the constructor of :py:class:`lammps`.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from lammps import IPyLammps
|
||||
|
||||
# NOTE: argv[0] is set by the lammps class constructor
|
||||
args = ["-log", "none"]
|
||||
# create LAMMPS instance
|
||||
L = IPyLammps(cmdargs=args)
|
||||
# get and print numerical version code
|
||||
print("LAMMPS Version: ", L.version())
|
||||
# explicitly close and delete LAMMPS instance (optional)
|
||||
L.close()
|
||||
|
||||
You can also initialize IPyLammps on top of an existing :py:class:`lammps` or :py:class:`PyLammps` object:
|
||||
|
||||
.. code-block:: Python
|
||||
|
||||
from lammps import lammps, IPyLammps
|
||||
...
|
||||
# create LAMMPS instance
|
||||
lmp = lammps(cmdargs=args)
|
||||
# create PyLammps instance using previously created LAMMPS instance
|
||||
L = PyLammps(ptr=lmp)
|
||||
|
||||
This is useful if you have to create the :py:class:`lammps <lammps.lammps>`
|
||||
instance is a specific way, but want to take advantage of the
|
||||
:py:class:`IPyLammps <lammps.IPyLammps>` interface.
|
||||
|
||||
In all of the above cases, same as with the :ref:`C library API <lammps_c_api>`, this will use the
|
||||
``MPI_COMM_WORLD`` communicator for the MPI library that LAMMPS was
|
||||
compiled with. The :py:func:`lmp.close() <lammps.lammps.close>` call is
|
||||
optional since the LAMMPS class instance will also be deleted
|
||||
@ -73,39 +192,109 @@ destructor.
|
||||
Executing LAMMPS commands
|
||||
*************************
|
||||
|
||||
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. Same as in the equivalent `C
|
||||
library functions <pg_lib_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`:
|
||||
Once an instance of the :py:class:`lammps`, :py:class:`PyLammps`, or
|
||||
:py:class:`IPyLammps` class is created, there are multiple ways to "feed" it
|
||||
commands. In a way that is not very different from running a LAMMPS input
|
||||
script, except that Python has many more facilities for structured
|
||||
programming than the LAMMPS input script syntax. Furthermore it is possible
|
||||
to "compute" what the next LAMMPS command should be.
|
||||
|
||||
.. code-block:: python
|
||||
.. tabs::
|
||||
|
||||
from lammps import lammps
|
||||
.. tab:: lammps API
|
||||
|
||||
lmp = lammps()
|
||||
# read commands from file 'in.melt'
|
||||
lmp.file('in.melt')
|
||||
# issue a single command
|
||||
lmp.command('variable zpos index 1.0')
|
||||
# create 10 groups with 10 atoms each
|
||||
cmds = ["group g{} id {}:{}".format(i,10*i+1,10*(i+1)) for i in range(10)]
|
||||
lmp.commands_list(cmds)
|
||||
# run commands from a multi-line string
|
||||
block = """
|
||||
clear
|
||||
region box block 0 2 0 2 0 2
|
||||
create_box 1 box
|
||||
create_atoms 1 single 1.0 1.0 ${zpos}
|
||||
"""
|
||||
lmp.commands_string(block)
|
||||
Same as in the equivalent
|
||||
:doc:`C library functions <pg_lib_execute>`, commands can be read from a file, a
|
||||
single string, a list of strings and a block of commands in a single
|
||||
multi-line string. They are processed under the same boundary conditions
|
||||
as the C library counterparts. The example below demonstrates the use
|
||||
of :py:func:`lammps.file`, :py:func:`lammps.command`,
|
||||
:py:func:`lammps.commands_list`, and :py:func:`lammps.commands_string`:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from lammps import lammps
|
||||
lmp = lammps()
|
||||
# read commands from file 'in.melt'
|
||||
lmp.file('in.melt')
|
||||
# issue a single command
|
||||
lmp.command('variable zpos index 1.0')
|
||||
# create 10 groups with 10 atoms each
|
||||
cmds = ["group g{} id {}:{}".format(i,10*i+1,10*(i+1)) for i in range(10)]
|
||||
lmp.commands_list(cmds)
|
||||
# run commands from a multi-line string
|
||||
block = """
|
||||
clear
|
||||
region box block 0 2 0 2 0 2
|
||||
create_box 1 box
|
||||
create_atoms 1 single 1.0 1.0 ${zpos}
|
||||
"""
|
||||
lmp.commands_string(block)
|
||||
|
||||
.. tab:: PyLammps/IPyLammps API
|
||||
|
||||
Unlike the lammps API, the PyLammps/IPyLammps APIs allow running LAMMPS
|
||||
commands by calling equivalent member functions.
|
||||
|
||||
For instance, the following LAMMPS command
|
||||
|
||||
.. code-block:: LAMMPS
|
||||
|
||||
region box block 0 10 0 5 -0.5 0.5
|
||||
|
||||
can be executed using the following Python code if *L* is a :py:class:`lammps` instance:
|
||||
|
||||
.. code-block:: Python
|
||||
|
||||
L.command("region box block 0 10 0 5 -0.5 0.5")
|
||||
|
||||
With the PyLammps interface, any LAMMPS command can be split up into arbitrary parts.
|
||||
These parts are then passed to a member function with the name of the command.
|
||||
For the ``region`` command that means the :code:`region` method can be called.
|
||||
The arguments of the command can be passed as one string, or
|
||||
individually.
|
||||
|
||||
.. code-block:: Python
|
||||
|
||||
L.region("box block", 0, 10, 0, 5, -0.5, 0.5)
|
||||
|
||||
In this example all parameters except the first are Python floating-point literals. The
|
||||
PyLammps interface takes the entire parameter list and transparently
|
||||
merges it to a single command string.
|
||||
|
||||
The benefit of this approach is avoiding redundant command calls and easier
|
||||
parameterization. In the original interface parameterization this needed to be done
|
||||
manually by creating formatted strings.
|
||||
|
||||
.. code-block:: Python
|
||||
|
||||
L.command("region box block %f %f %f %f %f %f" % (xlo, xhi, ylo, yhi, zlo, zhi))
|
||||
|
||||
In contrast, methods of PyLammps accept parameters directly and will convert
|
||||
them automatically to a final command string.
|
||||
|
||||
.. code-block:: Python
|
||||
|
||||
L.region("box block", xlo, xhi, ylo, yhi, zlo, zhi)
|
||||
|
||||
Using these facilities, the example shown for the lammps API can be rewritten as follows:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from lammps import PyLammps
|
||||
L = PyLammps()
|
||||
# read commands from file 'in.melt'
|
||||
L.file('in.melt')
|
||||
# issue a single command
|
||||
L.variable('zpos', 'index', 1.0)
|
||||
# create 10 groups with 10 atoms each
|
||||
for i in range(10):
|
||||
L.group(f"g{i}", "id", f"{10*i+1}:{10*(i+1)}")
|
||||
|
||||
L.clear()
|
||||
L.region("box block", 0, 2, 0, 2, 0, 2)
|
||||
L.create_box(1, "box")
|
||||
L.create_atoms(1, "single", 1.0, 1.0, "${zpos}")
|
||||
|
||||
----------
|
||||
|
||||
@ -130,14 +319,34 @@ functions. Below is a detailed documentation of the API.
|
||||
The ``PyLammps`` class API
|
||||
**************************
|
||||
|
||||
The :py:class:`PyLammps <lammps.PyLammps>` class is a wrapper that creates a
|
||||
simpler, more "Pythonic" interface to common LAMMPS functionality. LAMMPS
|
||||
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
|
||||
:members:
|
||||
|
||||
@ -150,14 +359,24 @@ The :py:mod:`lammps` module additionally contains several constants
|
||||
and the :py:class:`NeighList <lammps.NeighList>` class:
|
||||
|
||||
.. _py_data_constants:
|
||||
.. py:data:: LAMMPS_INT, LAMMPS_DOUBLE, LAMMPS_BIGINT, LAMMPS_TAGINT, LAMMPS_STRING
|
||||
|
||||
Data Types
|
||||
----------
|
||||
|
||||
.. py:data:: LAMMPS_INT, LAMMPS_INT_2D, LAMMPS_DOUBLE, LAMMPS_DOUBLE_2D, LAMMPS_INT64, LAMMPS_INT64_2D, LAMMPS_STRING
|
||||
:type: int
|
||||
|
||||
Constants in the :py:mod:`lammps` module to indicate how to
|
||||
cast data when the C library function returns a void pointer.
|
||||
Used in :py:func:`lammps.extract_global`.
|
||||
Used in :py:func:`lammps.extract_global` and :py:func:`lammps.extract_atom`.
|
||||
See :cpp:enum:`_LMP_DATATYPE_CONST` for the equivalent constants in the
|
||||
C library interface.
|
||||
|
||||
.. _py_style_constants:
|
||||
|
||||
Style Constants
|
||||
---------------
|
||||
|
||||
.. py:data:: LMP_STYLE_GLOBAL, LMP_STYLE_ATOM, LMP_STYLE_LOCAL
|
||||
:type: int
|
||||
|
||||
@ -167,6 +386,10 @@ and the :py:class:`NeighList <lammps.NeighList>` class:
|
||||
:py:func:`lammps.extract_compute` and :py:func:`lammps.extract_fix`.
|
||||
|
||||
.. _py_type_constants:
|
||||
|
||||
Type Constants
|
||||
--------------
|
||||
|
||||
.. py:data:: LMP_TYPE_SCALAR, LMP_TYLE_VECTOR, LMP_TYPE_ARRAY, LMP_SIZE_VECTOR, LMP_SIZE_ROWS, LMP_SIZE_COLS
|
||||
:type: int
|
||||
|
||||
@ -176,13 +399,36 @@ and the :py:class:`NeighList <lammps.NeighList>` class:
|
||||
:py:func:`lammps.extract_compute` and :py:func:`lammps.extract_fix`.
|
||||
|
||||
.. _py_var_constants:
|
||||
|
||||
Variable Style Constants
|
||||
------------------------
|
||||
|
||||
.. py:data:: LMP_VAR_EQUAL, LMP_VAR_ATOM
|
||||
:type: int
|
||||
|
||||
Constants in the :py:mod:`lammps` module to select what style of
|
||||
variable to query when calling :py:func:`lammps.extract_variable`.
|
||||
|
||||
Classes representing internal objects
|
||||
-------------------------------------
|
||||
|
||||
.. autoclass:: lammps.NeighList
|
||||
:members:
|
||||
:no-undoc-members:
|
||||
|
||||
|
||||
LAMMPS error handling in Python
|
||||
*******************************
|
||||
|
||||
Compiling the shared library with :ref:`C++ exception support <exceptions>` provides a better error
|
||||
handling experience. Without exceptions the LAMMPS code will terminate the
|
||||
current Python process with an error message. C++ exceptions allow capturing
|
||||
them on the C++ side and rethrowing them on the Python side. This way
|
||||
LAMMPS errors can be handled through the Python exception handling mechanism.
|
||||
|
||||
.. warning::
|
||||
|
||||
Capturing a LAMMPS exception in Python can still mean that the
|
||||
current LAMMPS process is in an illegal state and must be terminated. It is
|
||||
advised to save your data and terminate the Python instance as quickly as
|
||||
possible.
|
||||
|
||||
@ -2018,6 +2018,7 @@ Nakano
|
||||
nall
|
||||
namespace
|
||||
namespaces
|
||||
namedtuple
|
||||
nan
|
||||
NaN
|
||||
Nandor
|
||||
|
||||
@ -23,12 +23,12 @@ from lammps import lammps
|
||||
|
||||
def end_of_step_callback(lmp):
|
||||
L = lammps(ptr=lmp)
|
||||
t = L.extract_global("ntimestep", 0)
|
||||
t = L.extract_global("ntimestep")
|
||||
print("### END OF STEP ###", t)
|
||||
|
||||
def post_force_callback(lmp, v):
|
||||
L = lammps(ptr=lmp)
|
||||
t = L.extract_global("ntimestep", 0)
|
||||
t = L.extract_global("ntimestep")
|
||||
print("### POST_FORCE ###", t)
|
||||
"""
|
||||
|
||||
|
||||
@ -35,14 +35,13 @@ def post_force_callback(lmp, v):
|
||||
#mylist = L.get_neighlist(0)
|
||||
mylist = L.find_pair_neighlist("lj/cut", request=0)
|
||||
print(pid_prefix, mylist)
|
||||
nlocal = L.extract_global("nlocal", 0)
|
||||
nghost = L.extract_global("nghost", 0)
|
||||
ntypes = L.extract_global("ntypes", 0)
|
||||
mass = L.numpy.extract_atom_darray("mass", ntypes+1)
|
||||
atype = L.numpy.extract_atom_iarray("type", nlocal+nghost)
|
||||
x = L.numpy.extract_atom_darray("x", nlocal+nghost, dim=3)
|
||||
v = L.numpy.extract_atom_darray("v", nlocal+nghost, dim=3)
|
||||
f = L.numpy.extract_atom_darray("f", nlocal+nghost, dim=3)
|
||||
nlocal = L.extract_global("nlocal")
|
||||
nghost = L.extract_global("nghost")
|
||||
mass = L.numpy.extract_atom("mass")
|
||||
atype = L.numpy.extract_atom("type", nelem=nlocal+nghost)
|
||||
x = L.numpy.extract_atom("x", nelem=nlocal+nghost, dim=3)
|
||||
v = L.numpy.extract_atom("v", nelem=nlocal+nghost, dim=3)
|
||||
f = L.numpy.extract_atom("f", nelem=nlocal+nghost, dim=3)
|
||||
|
||||
for iatom, numneigh, neighs in mylist:
|
||||
print(pid_prefix, "- {}".format(iatom), x[iatom], v[iatom], f[iatom], " : ", numneigh, "Neighbors")
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
from __future__ import print_function
|
||||
import lammps
|
||||
from lammps import lammps, LAMMPS_INT, LAMMPS_DOUBLE
|
||||
import ctypes
|
||||
import traceback
|
||||
import numpy as np
|
||||
|
||||
class LAMMPSFix(object):
|
||||
def __init__(self, ptr, group_name="all"):
|
||||
self.lmp = lammps.lammps(ptr=ptr)
|
||||
self.lmp = lammps(ptr=ptr)
|
||||
self.group_name = group_name
|
||||
|
||||
class LAMMPSFixMove(LAMMPSFix):
|
||||
@ -39,19 +39,18 @@ class NVE(LAMMPSFixMove):
|
||||
assert(self.group_name == "all")
|
||||
|
||||
def init(self):
|
||||
dt = self.lmp.extract_global("dt", 1)
|
||||
ftm2v = self.lmp.extract_global("ftm2v", 1)
|
||||
self.ntypes = self.lmp.extract_global("ntypes", 0)
|
||||
dt = self.lmp.extract_global("dt")
|
||||
ftm2v = self.lmp.extract_global("ftm2v")
|
||||
self.ntypes = self.lmp.extract_global("ntypes")
|
||||
self.dtv = dt
|
||||
self.dtf = 0.5 * dt * ftm2v
|
||||
|
||||
def initial_integrate(self, vflag):
|
||||
nlocal = self.lmp.extract_global("nlocal", 0)
|
||||
mass = self.lmp.numpy.extract_atom_darray("mass", self.ntypes+1)
|
||||
atype = self.lmp.numpy.extract_atom_iarray("type", nlocal)
|
||||
x = self.lmp.numpy.extract_atom_darray("x", nlocal, dim=3)
|
||||
v = self.lmp.numpy.extract_atom_darray("v", nlocal, dim=3)
|
||||
f = self.lmp.numpy.extract_atom_darray("f", nlocal, dim=3)
|
||||
mass = self.lmp.numpy.extract_atom("mass")
|
||||
atype = self.lmp.numpy.extract_atom("type")
|
||||
x = self.lmp.numpy.extract_atom("x")
|
||||
v = self.lmp.numpy.extract_atom("v")
|
||||
f = self.lmp.numpy.extract_atom("f")
|
||||
|
||||
for i in range(x.shape[0]):
|
||||
dtfm = self.dtf / mass[int(atype[i])]
|
||||
@ -59,11 +58,10 @@ class NVE(LAMMPSFixMove):
|
||||
x[i,:] += self.dtv * v[i,:]
|
||||
|
||||
def final_integrate(self):
|
||||
nlocal = self.lmp.extract_global("nlocal", 0)
|
||||
mass = self.lmp.numpy.extract_atom_darray("mass", self.ntypes+1)
|
||||
atype = self.lmp.numpy.extract_atom_iarray("type", nlocal)
|
||||
v = self.lmp.numpy.extract_atom_darray("v", nlocal, dim=3)
|
||||
f = self.lmp.numpy.extract_atom_darray("f", nlocal, dim=3)
|
||||
mass = self.lmp.numpy.extract_atom("mass")
|
||||
atype = self.lmp.numpy.extract_atom("type")
|
||||
v = self.lmp.numpy.extract_atom("v")
|
||||
f = self.lmp.numpy.extract_atom("f")
|
||||
|
||||
for i in range(v.shape[0]):
|
||||
dtfm = self.dtf / mass[int(atype[i])]
|
||||
@ -77,19 +75,19 @@ class NVE_Opt(LAMMPSFixMove):
|
||||
assert(self.group_name == "all")
|
||||
|
||||
def init(self):
|
||||
dt = self.lmp.extract_global("dt", 1)
|
||||
ftm2v = self.lmp.extract_global("ftm2v", 1)
|
||||
self.ntypes = self.lmp.extract_global("ntypes", 0)
|
||||
dt = self.lmp.extract_global("dt")
|
||||
ftm2v = self.lmp.extract_global("ftm2v")
|
||||
self.ntypes = self.lmp.extract_global("ntypes")
|
||||
self.dtv = dt
|
||||
self.dtf = 0.5 * dt * ftm2v
|
||||
self.mass = self.lmp.numpy.extract_atom_darray("mass", self.ntypes+1)
|
||||
self.mass = self.lmp.numpy.extract_atom("mass")
|
||||
|
||||
def initial_integrate(self, vflag):
|
||||
nlocal = self.lmp.extract_global("nlocal", 0)
|
||||
atype = self.lmp.numpy.extract_atom_iarray("type", nlocal)
|
||||
x = self.lmp.numpy.extract_atom_darray("x", nlocal, dim=3)
|
||||
v = self.lmp.numpy.extract_atom_darray("v", nlocal, dim=3)
|
||||
f = self.lmp.numpy.extract_atom_darray("f", nlocal, dim=3)
|
||||
nlocal = self.lmp.extract_global("nlocal")
|
||||
atype = self.lmp.numpy.extract_atom("type")
|
||||
x = self.lmp.numpy.extract_atom("x")
|
||||
v = self.lmp.numpy.extract_atom("v")
|
||||
f = self.lmp.numpy.extract_atom("f")
|
||||
dtf = self.dtf
|
||||
dtv = self.dtv
|
||||
mass = self.mass
|
||||
@ -102,13 +100,12 @@ class NVE_Opt(LAMMPSFixMove):
|
||||
x[:,d] += dtv * v[:,d]
|
||||
|
||||
def final_integrate(self):
|
||||
nlocal = self.lmp.extract_global("nlocal", 0)
|
||||
mass = self.lmp.numpy.extract_atom_darray("mass", self.ntypes+1)
|
||||
atype = self.lmp.numpy.extract_atom_iarray("type", nlocal)
|
||||
v = self.lmp.numpy.extract_atom_darray("v", nlocal, dim=3)
|
||||
f = self.lmp.numpy.extract_atom_darray("f", nlocal, dim=3)
|
||||
nlocal = self.lmp.extract_global("nlocal")
|
||||
mass = self.lmp.numpy.extract_atom("mass")
|
||||
atype = self.lmp.numpy.extract_atom("type")
|
||||
v = self.lmp.numpy.extract_atom("v")
|
||||
f = self.lmp.numpy.extract_atom("f")
|
||||
dtf = self.dtf
|
||||
dtv = self.dtv
|
||||
mass = self.mass
|
||||
|
||||
dtfm = dtf / np.take(mass, atype)
|
||||
|
||||
@ -16,7 +16,7 @@ if len(argv) != 1:
|
||||
print("Syntax: demo.py")
|
||||
sys.exit()
|
||||
|
||||
from lammps import lammps
|
||||
from lammps import lammps, LAMMPS_INT, LMP_STYLE_GLOBAL, LMP_VAR_EQUAL, LMP_VAR_ATOM
|
||||
lmp = lammps()
|
||||
|
||||
# test out various library functions after running in.demo
|
||||
@ -25,18 +25,18 @@ lmp.file("in.demo")
|
||||
|
||||
print("\nPython output:")
|
||||
|
||||
natoms = lmp.extract_global("natoms",0)
|
||||
mass = lmp.extract_atom("mass",2)
|
||||
x = lmp.extract_atom("x",3)
|
||||
natoms = lmp.extract_global("natoms")
|
||||
mass = lmp.extract_atom("mass")
|
||||
x = lmp.extract_atom("x")
|
||||
print("Natoms, mass, x[0][0] coord =",natoms,mass[1],x[0][0])
|
||||
|
||||
temp = lmp.extract_compute("thermo_temp",0,0)
|
||||
temp = lmp.extract_compute("thermo_temp", LMP_STYLE_GLOBAL, LAMMPS_INT)
|
||||
print("Temperature from compute =",temp)
|
||||
|
||||
eng = lmp.extract_variable("eng",None,0)
|
||||
eng = lmp.extract_variable("eng",None, LMP_VAR_EQUAL)
|
||||
print("Energy from equal-style variable =",eng)
|
||||
|
||||
vy = lmp.extract_variable("vy","all",1)
|
||||
vy = lmp.extract_variable("vy","all", LMP_VAR_ATOM)
|
||||
print("Velocity component from atom-style variable =",vy[1])
|
||||
|
||||
vol = lmp.get_thermo("vol")
|
||||
|
||||
@ -27,7 +27,7 @@ if len(argv) != 2:
|
||||
|
||||
infile = sys.argv[1]
|
||||
|
||||
from lammps import lammps
|
||||
from lammps import lammps, LAMMPS_INT, LMP_STYLE_GLOBAL, LMP_VAR_EQUAL
|
||||
lmp = lammps()
|
||||
|
||||
# run infile one line at a time
|
||||
@ -42,14 +42,14 @@ lmp.command("variable e equal pe")
|
||||
|
||||
lmp.command("run 0")
|
||||
|
||||
natoms = lmp.extract_global("natoms",0)
|
||||
emin = lmp.extract_compute("thermo_pe",0,0) / natoms
|
||||
natoms = lmp.extract_global("natoms")
|
||||
emin = lmp.extract_compute("thermo_pe",LMP_STYLE_GLOBAL,LAMMPS_INT) / natoms
|
||||
lmp.command("variable emin equal $e")
|
||||
|
||||
# disorder the system
|
||||
# estart = initial energy
|
||||
|
||||
x = lmp.extract_atom("x",3)
|
||||
x = lmp.extract_atom("x")
|
||||
|
||||
for i in range(natoms):
|
||||
x[i][0] += deltaperturb * (2*random.random()-1)
|
||||
@ -58,10 +58,10 @@ for i in range(natoms):
|
||||
lmp.command("variable elast equal $e")
|
||||
lmp.command("thermo_style custom step v_emin v_elast pe")
|
||||
lmp.command("run 0")
|
||||
x = lmp.extract_atom("x",3)
|
||||
x = lmp.extract_atom("x")
|
||||
lmp.command("variable elast equal $e")
|
||||
|
||||
estart = lmp.extract_compute("thermo_pe",0,0) / natoms
|
||||
estart = lmp.extract_compute("thermo_pe", LMP_STYLE_GLOBAL, LAMMPS_INT) / natoms
|
||||
|
||||
# loop over Monte Carlo moves
|
||||
# extract x after every run, in case reneighboring changed ptr in LAMMPS
|
||||
@ -78,8 +78,8 @@ for i in range(nloop):
|
||||
x[iatom][1] += deltamove * (2*random.random()-1)
|
||||
|
||||
lmp.command("run 1 pre no post no")
|
||||
x = lmp.extract_atom("x",3)
|
||||
e = lmp.extract_compute("thermo_pe",0,0) / natoms
|
||||
x = lmp.extract_atom("x")
|
||||
e = lmp.extract_compute("thermo_pe", LMP_STYLE_GLOBAL, LAMMPS_INT) / natoms
|
||||
|
||||
if e <= elast:
|
||||
elast = e
|
||||
@ -96,10 +96,10 @@ for i in range(nloop):
|
||||
# final energy and stats
|
||||
|
||||
lmp.command("variable nbuild equal nbuild")
|
||||
nbuild = lmp.extract_variable("nbuild",None,0)
|
||||
nbuild = lmp.extract_variable("nbuild", None, LMP_VAR_EQUAL)
|
||||
|
||||
lmp.command("run 0")
|
||||
estop = lmp.extract_compute("thermo_pe",0,0) / natoms
|
||||
estop = lmp.extract_compute("thermo_pe", LMP_STYLE_GLOBAL, LAMMPS_INT) / natoms
|
||||
|
||||
print("MC stats:")
|
||||
print(" starting energy =",estart)
|
||||
|
||||
@ -61,7 +61,7 @@ lmp.command("run 1");
|
||||
|
||||
# extract force on single atom two different ways
|
||||
|
||||
f = lmp.extract_atom("f",3)
|
||||
f = lmp.extract_atom("f")
|
||||
print("Force on 1 atom via extract_atom: ",f[0][0])
|
||||
|
||||
fx = lmp.extract_variable("fx","all",1)
|
||||
|
||||
@ -57,7 +57,7 @@ if color == 0:
|
||||
lmp.scatter_atoms("x",1,3,x)
|
||||
lmp.command("run 1");
|
||||
|
||||
f = lmp.extract_atom("f",3)
|
||||
f = lmp.extract_atom("f")
|
||||
print("Force on 1 atom via extract_atom: ",f[0][0])
|
||||
|
||||
fx = lmp.extract_variable("fx","all",1)
|
||||
|
||||
616
python/lammps.py
616
python/lammps.py
@ -19,6 +19,7 @@ from __future__ import print_function
|
||||
# imports for simple LAMMPS python wrapper module "lammps"
|
||||
|
||||
import sys,traceback,types
|
||||
import warnings
|
||||
from ctypes import *
|
||||
from os.path import dirname,abspath,join
|
||||
from inspect import getsourcefile
|
||||
@ -33,12 +34,13 @@ import sys
|
||||
|
||||
# various symbolic constants to be used
|
||||
# in certain calls to select data formats
|
||||
LAMMPS_AUTODETECT = None
|
||||
LAMMPS_INT = 0
|
||||
LAMMPS_INT2D = 1
|
||||
LAMMPS_INT_2D = 1
|
||||
LAMMPS_DOUBLE = 2
|
||||
LAMMPS_DOUBLE2D = 3
|
||||
LAMMPS_BIGINT = 4
|
||||
LAMMPS_TAGINT = 5
|
||||
LAMMPS_DOUBLE_2D = 3
|
||||
LAMMPS_INT64 = 4
|
||||
LAMMPS_INT64_2D = 5
|
||||
LAMMPS_STRING = 6
|
||||
|
||||
# these must be kept in sync with the enums in library.h
|
||||
@ -313,6 +315,8 @@ class lammps(object):
|
||||
self.lib.lammps_get_last_error_message.restype = c_int
|
||||
|
||||
self.lib.lammps_extract_global.argtypes = [c_void_p, c_char_p]
|
||||
self.lib.lammps_extract_global_datatype.argtypes = [c_void_p, c_char_p]
|
||||
self.lib.lammps_extract_global_datatype.restype = c_int
|
||||
self.lib.lammps_extract_compute.argtypes = [c_void_p, c_char_p, c_int, c_int]
|
||||
|
||||
self.lib.lammps_get_thermo.argtypes = [c_void_p, c_char_p]
|
||||
@ -337,6 +341,8 @@ class lammps(object):
|
||||
self.lib.lammps_decode_image_flags.argtypes = [self.c_imageint, POINTER(c_int*3)]
|
||||
|
||||
self.lib.lammps_extract_atom.argtypes = [c_void_p, c_char_p]
|
||||
self.lib.lammps_extract_atom_datatype.argtypes = [c_void_p, c_char_p]
|
||||
self.lib.lammps_extract_atom_datatype.restype = c_int
|
||||
|
||||
self.lib.lammps_extract_fix.argtypes = [c_void_p, c_char_p, c_int, c_int, c_int, c_int]
|
||||
|
||||
@ -473,7 +479,73 @@ class lammps(object):
|
||||
return np.int64
|
||||
return np.intc
|
||||
|
||||
def extract_atom(self, name, dtype=LAMMPS_AUTODETECT, nelem=LAMMPS_AUTODETECT, dim=LAMMPS_AUTODETECT):
|
||||
"""Retrieve per-atom properties from LAMMPS as NumPy arrays
|
||||
|
||||
This is a wrapper around the :cpp:func:`lammps_extract_atom`
|
||||
function of the C-library interface. Its documentation includes a
|
||||
list of the supported keywords and their data types.
|
||||
Since Python needs to know the data type to be able to interpret
|
||||
the result, by default, this function will try to auto-detect the data
|
||||
type by asking the library. You can also force a specific data type.
|
||||
For that purpose the :py:mod:`lammps` module contains the constants
|
||||
``LAMMPS_INT``, ``LAMMPS_INT_2D``, ``LAMMPS_DOUBLE``,
|
||||
``LAMMPS_DOUBLE_2D``, ``LAMMPS_INT64``, ``LAMMPS_INT64_2D``, and
|
||||
``LAMMPS_STRING``.
|
||||
This function returns ``None`` if either the keyword is not
|
||||
recognized, or an invalid data type constant is used.
|
||||
|
||||
.. note::
|
||||
|
||||
While the returned arrays of per-atom data are dimensioned
|
||||
for the range [0:nmax] - as is the underlying storage -
|
||||
the data is usually only valid for the range of [0:nlocal],
|
||||
unless the property of interest is also updated for ghost
|
||||
atoms. In some cases, this depends on a LAMMPS setting, see
|
||||
for example :doc:`comm_modify vel yes <comm_modify>`.
|
||||
|
||||
:param name: name of the property
|
||||
:type name: string
|
||||
:param dtype: type of the returned data (see :ref:`py_data_constants`)
|
||||
:type dtype: int, optional
|
||||
:param nelem: number of elements in array
|
||||
:type nelem: int, optional
|
||||
:param dim: dimension of each element
|
||||
:type dim: int, optional
|
||||
:return: requested data as NumPy array with direct access to C data
|
||||
:rtype: numpy.array
|
||||
"""
|
||||
if dtype == LAMMPS_AUTODETECT:
|
||||
dtype = self.lmp.extract_atom_datatype(name)
|
||||
|
||||
if nelem == LAMMPS_AUTODETECT:
|
||||
if name == "mass":
|
||||
nelem = self.lmp.extract_global("ntypes") + 1
|
||||
else:
|
||||
nelem = self.lmp.extract_global("nlocal")
|
||||
if dim == LAMMPS_AUTODETECT:
|
||||
if dtype in (LAMMPS_INT_2D, LAMMPS_DOUBLE_2D, LAMMPS_INT64_2D):
|
||||
# TODO add other fields
|
||||
if name in ("x", "v", "f", "angmom", "torque", "csforce", "vforce"):
|
||||
dim = 3
|
||||
else:
|
||||
dim = 2
|
||||
else:
|
||||
dim = 1
|
||||
|
||||
raw_ptr = self.lmp.extract_atom(name, dtype)
|
||||
|
||||
if dtype in (LAMMPS_DOUBLE, LAMMPS_DOUBLE_2D):
|
||||
return self.darray(raw_ptr, nelem, dim)
|
||||
elif dtype in (LAMMPS_INT, LAMMPS_INT_2D):
|
||||
return self.iarray(c_int32, raw_ptr, nelem, dim)
|
||||
elif dtype in (LAMMPS_INT64, LAMMPS_INT64_2D):
|
||||
return self.iarray(c_int64, raw_ptr, nelem, dim)
|
||||
return raw_ptr
|
||||
|
||||
def extract_atom_iarray(self, name, nelem, dim=1):
|
||||
warnings.warn("deprecated, use extract_atom instead", DeprecationWarning)
|
||||
|
||||
if name in ['id', 'molecule']:
|
||||
c_int_type = self.lmp.c_tagint
|
||||
elif name in ['image']:
|
||||
@ -484,15 +556,17 @@ class lammps(object):
|
||||
if dim == 1:
|
||||
raw_ptr = self.lmp.extract_atom(name, LAMMPS_INT)
|
||||
else:
|
||||
raw_ptr = self.lmp.extract_atom(name, LAMMPS_INT2D)
|
||||
raw_ptr = self.lmp.extract_atom(name, LAMMPS_INT_2D)
|
||||
|
||||
return self.iarray(c_int_type, raw_ptr, nelem, dim)
|
||||
|
||||
def extract_atom_darray(self, name, nelem, dim=1):
|
||||
warnings.warn("deprecated, use extract_atom instead", DeprecationWarning)
|
||||
|
||||
if dim == 1:
|
||||
raw_ptr = self.lmp.extract_atom(name, LAMMPS_DOUBLE)
|
||||
else:
|
||||
raw_ptr = self.lmp.extract_atom(name, LAMMPS_DOUBLE2D)
|
||||
raw_ptr = self.lmp.extract_atom(name, LAMMPS_DOUBLE_2D)
|
||||
|
||||
return self.darray(raw_ptr, nelem, dim)
|
||||
|
||||
@ -705,9 +779,9 @@ class lammps(object):
|
||||
underlying :cpp:func:`lammps_get_natoms` function returning a double.
|
||||
|
||||
:return: number of atoms
|
||||
:rtype: float
|
||||
:rtype: int
|
||||
"""
|
||||
return self.lib.lammps_get_natoms(self.lmp)
|
||||
return int(self.lib.lammps_get_natoms(self.lmp))
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
@ -801,10 +875,35 @@ class lammps(object):
|
||||
else: return None
|
||||
return int(self.lib.lammps_extract_setting(self.lmp,name))
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# extract global info datatype
|
||||
|
||||
def extract_global_datatype(self, name):
|
||||
"""Retrieve global property datatype from LAMMPS
|
||||
|
||||
This is a wrapper around the :cpp:func:`lammps_extract_global_datatype`
|
||||
function of the C-library interface. Its documentation includes a
|
||||
list of the supported keywords.
|
||||
This function returns ``None`` if the keyword is not
|
||||
recognized. Otherwise it will return a positive integer value that
|
||||
corresponds to one of the constants define in the :py:mod:`lammps` module:
|
||||
``LAMMPS_INT``, ``LAMMPS_INT_2D``, ``LAMMPS_DOUBLE``, ``LAMMPS_DOUBLE_2D``,
|
||||
``LAMMPS_INT64``, ``LAMMPS_INT64_2D``, and ``LAMMPS_STRING``. These values
|
||||
are equivalent to the ones defined in :cpp:enum:`_LMP_DATATYPE_CONST`.
|
||||
|
||||
:param name: name of the property
|
||||
:type name: string
|
||||
:return: datatype of global property
|
||||
:rtype: int
|
||||
"""
|
||||
if name: name = name.encode()
|
||||
else: return None
|
||||
return self.lib.lammps_extract_global_datatype(self.lmp, name)
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# extract global info
|
||||
|
||||
def extract_global(self, name, type):
|
||||
def extract_global(self, name, dtype=LAMMPS_AUTODETECT):
|
||||
"""Query LAMMPS about global settings of different types.
|
||||
|
||||
This is a wrapper around the :cpp:func:`lammps_extract_global`
|
||||
@ -814,55 +913,87 @@ class lammps(object):
|
||||
of values. The :cpp:func:`lammps_extract_global` documentation
|
||||
includes a list of the supported keywords and their data types.
|
||||
Since Python needs to know the data type to be able to interpret
|
||||
the result, the type has to be provided as an argument. For
|
||||
that purpose the :py:mod:`lammps` module contains the constants
|
||||
``LAMMPS_INT``, ``LAMMPS_DOUBLE``, ``LAMMPS_BIGINT``,
|
||||
``LAMMPS_TAGINT``, and ``LAMMPS_STRING``.
|
||||
This function returns ``None`` if either the keyword is not
|
||||
recognized, or an invalid data type constant is used.
|
||||
the result, by default, this function will try to auto-detect the data type
|
||||
by asking the library. You can also force a specific data type. For that
|
||||
purpose the :py:mod:`lammps` module contains the constants ``LAMMPS_INT``,
|
||||
``LAMMPS_DOUBLE``, ``LAMMPS_INT64``, and ``LAMMPS_STRING``. These values
|
||||
are equivalent to the ones defined in :cpp:enum:`_LMP_DATATYPE_CONST`.
|
||||
This function returns ``None`` if either the keyword is not recognized,
|
||||
or an invalid data type constant is used.
|
||||
|
||||
:param name: name of the setting
|
||||
:param name: name of the property
|
||||
:type name: string
|
||||
:param type: type of the returned data
|
||||
:type type: int
|
||||
:return: value of the setting
|
||||
:rtype: integer or double or string or None
|
||||
:param dtype: data type of the returned data (see :ref:`py_data_constants`)
|
||||
:type dtype: int, optional
|
||||
:return: value of the property or None
|
||||
:rtype: int, float, or NoneType
|
||||
"""
|
||||
if dtype == LAMMPS_AUTODETECT:
|
||||
dtype = self.extract_global_datatype(name)
|
||||
|
||||
if name: name = name.encode()
|
||||
else: return None
|
||||
|
||||
if dtype == LAMMPS_INT:
|
||||
self.lib.lammps_extract_global.restype = POINTER(c_int32)
|
||||
target_type = int
|
||||
elif dtype == LAMMPS_INT64:
|
||||
self.lib.lammps_extract_global.restype = POINTER(c_int64)
|
||||
target_type = int
|
||||
elif dtype == LAMMPS_DOUBLE:
|
||||
self.lib.lammps_extract_global.restype = POINTER(c_double)
|
||||
target_type = float
|
||||
elif dtype == LAMMPS_STRING:
|
||||
self.lib.lammps_extract_global.restype = c_char_p
|
||||
target_type = lambda x: str(x, 'ascii')
|
||||
|
||||
ptr = self.lib.lammps_extract_global(self.lmp, name)
|
||||
if ptr:
|
||||
return target_type(ptr[0])
|
||||
return None
|
||||
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# extract per-atom info datatype
|
||||
|
||||
def extract_atom_datatype(self, name):
|
||||
"""Retrieve per-atom property datatype from LAMMPS
|
||||
|
||||
This is a wrapper around the :cpp:func:`lammps_extract_atom_datatype`
|
||||
function of the C-library interface. Its documentation includes a
|
||||
list of the supported keywords.
|
||||
This function returns ``None`` if the keyword is not
|
||||
recognized. Otherwise it will return an integer value that
|
||||
corresponds to one of the constants define in the :py:mod:`lammps` module:
|
||||
``LAMMPS_INT``, ``LAMMPS_INT_2D``, ``LAMMPS_DOUBLE``, ``LAMMPS_DOUBLE_2D``,
|
||||
``LAMMPS_INT64``, ``LAMMPS_INT64_2D``, and ``LAMMPS_STRING``. These values
|
||||
are equivalent to the ones defined in :cpp:enum:`_LMP_DATATYPE_CONST`.
|
||||
|
||||
:param name: name of the property
|
||||
:type name: string
|
||||
:return: data type of per-atom property (see :ref:`py_data_constants`)
|
||||
:rtype: int
|
||||
"""
|
||||
if name: name = name.encode()
|
||||
else: return None
|
||||
if type == LAMMPS_INT:
|
||||
self.lib.lammps_extract_global.restype = POINTER(c_int)
|
||||
elif type == LAMMPS_DOUBLE:
|
||||
self.lib.lammps_extract_global.restype = POINTER(c_double)
|
||||
elif type == LAMMPS_BIGINT:
|
||||
self.lib.lammps_extract_global.restype = POINTER(self.c_bigint)
|
||||
elif type == LAMMPS_TAGINT:
|
||||
self.lib.lammps_extract_global.restype = POINTER(self.c_tagint)
|
||||
elif type == LAMMPS_STRING:
|
||||
self.lib.lammps_extract_global.restype = c_char_p
|
||||
ptr = self.lib.lammps_extract_global(self.lmp,name)
|
||||
return str(ptr,'ascii')
|
||||
else: return None
|
||||
ptr = self.lib.lammps_extract_global(self.lmp,name)
|
||||
if ptr: return ptr[0]
|
||||
else: return None
|
||||
return self.lib.lammps_extract_atom_datatype(self.lmp, name)
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# extract per-atom info
|
||||
# NOTE: need to insure are converting to/from correct Python type
|
||||
# e.g. for Python list or NumPy or ctypes
|
||||
|
||||
def extract_atom(self,name,type):
|
||||
def extract_atom(self, name, dtype=LAMMPS_AUTODETECT):
|
||||
"""Retrieve per-atom properties from LAMMPS
|
||||
|
||||
This is a wrapper around the :cpp:func:`lammps_extract_atom`
|
||||
function of the C-library interface. Its documentation includes a
|
||||
list of the supported keywords and their data types.
|
||||
Since Python needs to know the data type to be able to interpret
|
||||
the result, the type has to be provided as an argument. For
|
||||
the result, by default, this function will try to auto-detect the data type
|
||||
by asking the library. You can also force a specific data type. For
|
||||
that purpose the :py:mod:`lammps` module contains the constants
|
||||
``LAMMPS_INT``, ``LAMMPS_INT2D``, ``LAMMPS_DOUBLE``,
|
||||
and ``LAMMPS_DOUBLE2D``.
|
||||
``LAMMPS_INT``, ``LAMMPS_INT_2D``, ``LAMMPS_DOUBLE``, ``LAMMPS_DOUBLE_2D``,
|
||||
``LAMMPS_INT64``, ``LAMMPS_INT64_2D``, and ``LAMMPS_STRING``. These values
|
||||
are equivalent to the ones defined in :cpp:enum:`_LMP_DATATYPE_CONST`.
|
||||
This function returns ``None`` if either the keyword is not
|
||||
recognized, or an invalid data type constant is used.
|
||||
|
||||
@ -875,27 +1006,36 @@ class lammps(object):
|
||||
atoms. In some cases, this depends on a LAMMPS setting, see
|
||||
for example :doc:`comm_modify vel yes <comm_modify>`.
|
||||
|
||||
:param name: name of the setting
|
||||
:param name: name of the property
|
||||
:type name: string
|
||||
:param type: type of the returned data
|
||||
:type type: int
|
||||
:return: requested data
|
||||
:rtype: pointer to integer or double or None
|
||||
:param dtype: data type of the returned data (see :ref:`py_data_constants`)
|
||||
:type dtype: int, optional
|
||||
:return: requested data or ``None``
|
||||
:rtype: ctypes.POINTER(ctypes.c_int32), ctypes.POINTER(ctypes.POINTER(ctypes.c_int32)),
|
||||
ctypes.POINTER(ctypes.c_int64), ctypes.POINTER(ctypes.POINTER(ctypes.c_int64)),
|
||||
ctypes.POINTER(ctypes.c_double), ctypes.POINTER(ctypes.POINTER(ctypes.c_double)),
|
||||
or NoneType
|
||||
"""
|
||||
ntypes = int(self.extract_setting('ntypes'))
|
||||
nmax = int(self.extract_setting('nmax'))
|
||||
if dtype == LAMMPS_AUTODETECT:
|
||||
dtype = self.extract_atom_datatype(name)
|
||||
|
||||
if name: name = name.encode()
|
||||
else: return None
|
||||
if type == LAMMPS_INT:
|
||||
self.lib.lammps_extract_atom.restype = POINTER(c_int)
|
||||
elif type == LAMMPS_INT2D:
|
||||
self.lib.lammps_extract_atom.restype = POINTER(POINTER(c_int))
|
||||
elif type == LAMMPS_DOUBLE:
|
||||
|
||||
if dtype == LAMMPS_INT:
|
||||
self.lib.lammps_extract_atom.restype = POINTER(c_int32)
|
||||
elif dtype == LAMMPS_INT_2D:
|
||||
self.lib.lammps_extract_atom.restype = POINTER(POINTER(c_int32))
|
||||
elif dtype == LAMMPS_DOUBLE:
|
||||
self.lib.lammps_extract_atom.restype = POINTER(c_double)
|
||||
elif type == LAMMPS_DOUBLE2D:
|
||||
elif dtype == LAMMPS_DOUBLE_2D:
|
||||
self.lib.lammps_extract_atom.restype = POINTER(POINTER(c_double))
|
||||
elif dtype == LAMMPS_INT64:
|
||||
self.lib.lammps_extract_atom.restype = POINTER(c_int64)
|
||||
elif dtype == LAMMPS_INT64_2D:
|
||||
self.lib.lammps_extract_atom.restype = POINTER(POINTER(c_int64))
|
||||
else: return None
|
||||
ptr = self.lib.lammps_extract_atom(self.lmp,name)
|
||||
ptr = self.lib.lammps_extract_atom(self.lmp, name)
|
||||
if ptr: return ptr
|
||||
else: return None
|
||||
|
||||
@ -1140,7 +1280,7 @@ class lammps(object):
|
||||
|
||||
def gather_atoms(self,name,type,count):
|
||||
if name: name = name.encode()
|
||||
natoms = self.lib.lammps_get_natoms(self.lmp)
|
||||
natoms = self.get_natoms()
|
||||
if type == 0:
|
||||
data = ((count*natoms)*c_int)()
|
||||
self.lib.lammps_gather_atoms(self.lmp,name,type,count,data)
|
||||
@ -1154,7 +1294,7 @@ class lammps(object):
|
||||
|
||||
def gather_atoms_concat(self,name,type,count):
|
||||
if name: name = name.encode()
|
||||
natoms = self.lib.lammps_get_natoms(self.lmp)
|
||||
natoms = self.get_natoms()
|
||||
if type == 0:
|
||||
data = ((count*natoms)*c_int)()
|
||||
self.lib.lammps_gather_atoms_concat(self.lmp,name,type,count,data)
|
||||
@ -1206,7 +1346,7 @@ class lammps(object):
|
||||
# e.g. for Python list or NumPy or ctypes
|
||||
def gather(self,name,type,count):
|
||||
if name: name = name.encode()
|
||||
natoms = self.lib.lammps_get_natoms(self.lmp)
|
||||
natoms = self.get_natoms()
|
||||
if type == 0:
|
||||
data = ((count*natoms)*c_int)()
|
||||
self.lib.lammps_gather(self.lmp,name,type,count,data)
|
||||
@ -1218,7 +1358,7 @@ class lammps(object):
|
||||
|
||||
def gather_concat(self,name,type,count):
|
||||
if name: name = name.encode()
|
||||
natoms = self.lib.lammps_get_natoms(self.lmp)
|
||||
natoms = self.get_natoms()
|
||||
if type == 0:
|
||||
data = ((count*natoms)*c_int)()
|
||||
self.lib.lammps_gather_concat(self.lmp,name,type,count,data)
|
||||
@ -1525,8 +1665,8 @@ class lammps(object):
|
||||
def available_styles(self, category):
|
||||
"""Returns a list of styles available for a given category
|
||||
|
||||
This is a wrapper around the functions :cpp:func:`lammps_style_count`
|
||||
and :cpp:func`lammps_style_name` of the library interface.
|
||||
This is a wrapper around the functions :cpp:func:`lammps_style_count()`
|
||||
and :cpp:func:`lammps_style_name()` of the library interface.
|
||||
|
||||
:param category: name of category
|
||||
:type category: string
|
||||
@ -1723,8 +1863,8 @@ class OutputCapture(object):
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
class Variable(object):
|
||||
def __init__(self, lammps_wrapper_instance, name, style, definition):
|
||||
self.wrapper = lammps_wrapper_instance
|
||||
def __init__(self, pylammps_instance, name, style, definition):
|
||||
self._pylmp = pylammps_instance
|
||||
self.name = name
|
||||
self.style = style
|
||||
self.definition = definition.split()
|
||||
@ -1732,9 +1872,9 @@ class Variable(object):
|
||||
@property
|
||||
def value(self):
|
||||
if self.style == 'atom':
|
||||
return list(self.wrapper.lmp.extract_variable(self.name, "all", 1))
|
||||
return list(self._pylmp.lmp.extract_variable(self.name, "all", 1))
|
||||
else:
|
||||
value = self.wrapper.lmp_print('"${%s}"' % self.name).strip()
|
||||
value = self._pylmp.lmp_print('"${%s}"' % self.name).strip()
|
||||
try:
|
||||
return float(value)
|
||||
except ValueError:
|
||||
@ -1743,103 +1883,136 @@ class Variable(object):
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
class AtomList(object):
|
||||
def __init__(self, lammps_wrapper_instance):
|
||||
self.lmp = lammps_wrapper_instance
|
||||
self.natoms = self.lmp.system.natoms
|
||||
self.dimensions = self.lmp.system.dimensions
|
||||
"""
|
||||
A dynamic list of atoms that returns either an Atom or Atom2D instance for
|
||||
each atom. Instances are only allocated when accessed.
|
||||
|
||||
:ivar natoms: total number of atoms
|
||||
:ivar dimensions: number of dimensions in system
|
||||
"""
|
||||
def __init__(self, pylammps_instance):
|
||||
self._pylmp = pylammps_instance
|
||||
self.natoms = self._pylmp.system.natoms
|
||||
self.dimensions = self._pylmp.system.dimensions
|
||||
self._loaded = {}
|
||||
|
||||
def __getitem__(self, index):
|
||||
if self.dimensions == 2:
|
||||
return Atom2D(self.lmp, index + 1)
|
||||
return Atom(self.lmp, index + 1)
|
||||
"""
|
||||
Return Atom with given local index
|
||||
|
||||
:param index: Local index of atom
|
||||
:type index: int
|
||||
:rtype: Atom or Atom2D
|
||||
"""
|
||||
if index not in self._loaded:
|
||||
if self.dimensions == 2:
|
||||
atom = Atom2D(self._pylmp, index + 1)
|
||||
else:
|
||||
atom = Atom(self._pylmp, index + 1)
|
||||
self._loaded[index] = atom
|
||||
return self._loaded[index]
|
||||
|
||||
def __len__(self):
|
||||
return self.natoms
|
||||
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
class Atom(object):
|
||||
def __init__(self, lammps_wrapper_instance, index):
|
||||
self.lmp = lammps_wrapper_instance
|
||||
"""
|
||||
A wrapper class then represents a single atom inside of LAMMPS
|
||||
|
||||
It provides access to properties of the atom and allows you to change some of them.
|
||||
"""
|
||||
def __init__(self, pylammps_instance, index):
|
||||
self._pylmp = pylammps_instance
|
||||
self.index = index
|
||||
|
||||
@property
|
||||
def id(self):
|
||||
return int(self.lmp.eval("id[%d]" % self.index))
|
||||
return int(self._pylmp.eval("id[%d]" % self.index))
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
return int(self.lmp.eval("type[%d]" % self.index))
|
||||
return int(self._pylmp.eval("type[%d]" % self.index))
|
||||
|
||||
@property
|
||||
def mol(self):
|
||||
return self.lmp.eval("mol[%d]" % self.index)
|
||||
return self._pylmp.eval("mol[%d]" % self.index)
|
||||
|
||||
@property
|
||||
def mass(self):
|
||||
return self.lmp.eval("mass[%d]" % self.index)
|
||||
return self._pylmp.eval("mass[%d]" % self.index)
|
||||
|
||||
@property
|
||||
def position(self):
|
||||
return (self.lmp.eval("x[%d]" % self.index),
|
||||
self.lmp.eval("y[%d]" % self.index),
|
||||
self.lmp.eval("z[%d]" % self.index))
|
||||
return (self._pylmp.eval("x[%d]" % self.index),
|
||||
self._pylmp.eval("y[%d]" % self.index),
|
||||
self._pylmp.eval("z[%d]" % self.index))
|
||||
|
||||
@position.setter
|
||||
def position(self, value):
|
||||
self.lmp.set("atom", self.index, "x", value[0])
|
||||
self.lmp.set("atom", self.index, "y", value[1])
|
||||
self.lmp.set("atom", self.index, "z", value[2])
|
||||
self._pylmp.set("atom", self.index, "x", value[0])
|
||||
self._pylmp.set("atom", self.index, "y", value[1])
|
||||
self._pylmp.set("atom", self.index, "z", value[2])
|
||||
|
||||
@property
|
||||
def velocity(self):
|
||||
return (self.lmp.eval("vx[%d]" % self.index),
|
||||
self.lmp.eval("vy[%d]" % self.index),
|
||||
self.lmp.eval("vz[%d]" % self.index))
|
||||
return (self._pylmp.eval("vx[%d]" % self.index),
|
||||
self._pylmp.eval("vy[%d]" % self.index),
|
||||
self._pylmp.eval("vz[%d]" % self.index))
|
||||
|
||||
@velocity.setter
|
||||
def velocity(self, value):
|
||||
self.lmp.set("atom", self.index, "vx", value[0])
|
||||
self.lmp.set("atom", self.index, "vy", value[1])
|
||||
self.lmp.set("atom", self.index, "vz", value[2])
|
||||
self._pylmp.set("atom", self.index, "vx", value[0])
|
||||
self._pylmp.set("atom", self.index, "vy", value[1])
|
||||
self._pylmp.set("atom", self.index, "vz", value[2])
|
||||
|
||||
@property
|
||||
def force(self):
|
||||
return (self.lmp.eval("fx[%d]" % self.index),
|
||||
self.lmp.eval("fy[%d]" % self.index),
|
||||
self.lmp.eval("fz[%d]" % self.index))
|
||||
return (self._pylmp.eval("fx[%d]" % self.index),
|
||||
self._pylmp.eval("fy[%d]" % self.index),
|
||||
self._pylmp.eval("fz[%d]" % self.index))
|
||||
|
||||
@property
|
||||
def charge(self):
|
||||
return self.lmp.eval("q[%d]" % self.index)
|
||||
return self._pylmp.eval("q[%d]" % self.index)
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
class Atom2D(Atom):
|
||||
def __init__(self, lammps_wrapper_instance, index):
|
||||
super(Atom2D, self).__init__(lammps_wrapper_instance, index)
|
||||
"""
|
||||
A wrapper class then represents a single 2D atom inside of LAMMPS
|
||||
|
||||
It provides access to properties of the atom and allows you to change some of them.
|
||||
"""
|
||||
def __init__(self, pylammps_instance, index):
|
||||
super(Atom2D, self).__init__(pylammps_instance, index)
|
||||
|
||||
@property
|
||||
def position(self):
|
||||
return (self.lmp.eval("x[%d]" % self.index),
|
||||
self.lmp.eval("y[%d]" % self.index))
|
||||
return (self._pylmp.eval("x[%d]" % self.index),
|
||||
self._pylmp.eval("y[%d]" % self.index))
|
||||
|
||||
@position.setter
|
||||
def position(self, value):
|
||||
self.lmp.set("atom", self.index, "x", value[0])
|
||||
self.lmp.set("atom", self.index, "y", value[1])
|
||||
self._pylmp.set("atom", self.index, "x", value[0])
|
||||
self._pylmp.set("atom", self.index, "y", value[1])
|
||||
|
||||
@property
|
||||
def velocity(self):
|
||||
return (self.lmp.eval("vx[%d]" % self.index),
|
||||
self.lmp.eval("vy[%d]" % self.index))
|
||||
return (self._pylmp.eval("vx[%d]" % self.index),
|
||||
self._pylmp.eval("vy[%d]" % self.index))
|
||||
|
||||
@velocity.setter
|
||||
def velocity(self, value):
|
||||
self.lmp.set("atom", self.index, "vx", value[0])
|
||||
self.lmp.set("atom", self.index, "vy", value[1])
|
||||
self._pylmp.set("atom", self.index, "vx", value[0])
|
||||
self._pylmp.set("atom", self.index, "vy", value[1])
|
||||
|
||||
@property
|
||||
def force(self):
|
||||
return (self.lmp.eval("fx[%d]" % self.index),
|
||||
self.lmp.eval("fy[%d]" % self.index))
|
||||
return (self._pylmp.eval("fx[%d]" % self.index),
|
||||
self._pylmp.eval("fy[%d]" % self.index))
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
@ -1919,11 +2092,41 @@ def get_thermo_data(output):
|
||||
|
||||
class PyLammps(object):
|
||||
"""
|
||||
More Python-like wrapper for LAMMPS (e.g., for IPython)
|
||||
See examples/ipython for usage
|
||||
This is a Python wrapper class around the lower-level
|
||||
:py:class:`lammps` class, exposing a more Python-like,
|
||||
object-oriented interface for prototyping system inside of IPython and
|
||||
Jupyter notebooks.
|
||||
|
||||
It either creates its own instance of :py:class:`lammps` or can be
|
||||
initialized with an existing instance. The arguments are the same of the
|
||||
lower-level interface. The original interface can still be accessed via
|
||||
:py:attr:`PyLammps.lmp`.
|
||||
|
||||
: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.
|
||||
:type cmdargs: list
|
||||
:param ptr: pointer to a LAMMPS C++ class instance when called from an embedded Python interpreter. None means load symbols from shared library.
|
||||
:type ptr: pointer
|
||||
:param comm: MPI communicator (as provided by `mpi4py <mpi4py_docs_>`_). ``None`` means use ``MPI_COMM_WORLD`` implicitly.
|
||||
:type comm: MPI_Comm
|
||||
|
||||
:ivar lmp: instance of original LAMMPS Python interface
|
||||
:vartype lmp: :py:class:`lammps`
|
||||
|
||||
:ivar runs: list of completed runs, each storing the thermo output
|
||||
:vartype run: list
|
||||
"""
|
||||
|
||||
def __init__(self,name="",cmdargs=None,ptr=None,comm=None):
|
||||
def __init__(self, name="", cmdargs=None, ptr=None, comm=None):
|
||||
self.has_echo = False
|
||||
|
||||
if cmdargs:
|
||||
if '-echo' in cmdargs:
|
||||
idx = cmdargs.index('-echo')
|
||||
# ensures that echo line is ignored during output capture
|
||||
self.has_echo = idx+1 < len(cmdargs) and cmdargs[idx+1] in ('screen', 'both')
|
||||
|
||||
if ptr:
|
||||
if isinstance(ptr,PyLammps):
|
||||
self.lmp = ptr.lmp
|
||||
@ -1942,26 +2145,65 @@ class PyLammps(object):
|
||||
self.lmp = None
|
||||
|
||||
def close(self):
|
||||
"""Explicitly delete a LAMMPS instance
|
||||
|
||||
This is a wrapper around the :py:meth:`lammps.close` of the Python interface.
|
||||
"""
|
||||
if self.lmp: self.lmp.close()
|
||||
self.lmp = None
|
||||
|
||||
def version(self):
|
||||
"""Return a numerical representation of the LAMMPS version in use.
|
||||
|
||||
This is a wrapper around the :py:meth:`lammps.version` function of the Python interface.
|
||||
|
||||
:return: version number
|
||||
:rtype: int
|
||||
"""
|
||||
return self.lmp.version()
|
||||
|
||||
def file(self,file):
|
||||
def file(self, file):
|
||||
"""Read LAMMPS commands from a file.
|
||||
|
||||
This is a wrapper around the :py:meth:`lammps.file` function of the Python interface.
|
||||
|
||||
:param path: Name of the file/path with LAMMPS commands
|
||||
:type path: string
|
||||
"""
|
||||
self.lmp.file(file)
|
||||
|
||||
def write_script(self,filename):
|
||||
""" Write LAMMPS script file containing all commands executed up until now """
|
||||
with open(filename, "w") as f:
|
||||
for cmd in self._cmd_history:
|
||||
f.write("%s\n" % cmd)
|
||||
def write_script(self, filepath):
|
||||
"""
|
||||
Write LAMMPS script file containing all commands executed up until now
|
||||
|
||||
def command(self,cmd):
|
||||
:param filepath: path to script file that should be written
|
||||
:type filepath: string
|
||||
"""
|
||||
with open(filepath, "w") as f:
|
||||
for cmd in self._cmd_history:
|
||||
print(cmd, file=f)
|
||||
|
||||
def command(self, cmd):
|
||||
"""
|
||||
Execute LAMMPS command
|
||||
|
||||
All commands executed will be stored in a command history which can be
|
||||
written to a file using :py:meth:`PyLammps.write_script()`
|
||||
|
||||
:param cmd: command string that should be executed
|
||||
:type: cmd: string
|
||||
"""
|
||||
self.lmp.command(cmd)
|
||||
self._cmd_history.append(cmd)
|
||||
|
||||
def run(self, *args, **kwargs):
|
||||
"""
|
||||
Execute LAMMPS run command with given arguments
|
||||
|
||||
All thermo output during the run is captured and saved as new entry in
|
||||
:py:attr:`PyLammps.runs`. The latest run can be retrieved by
|
||||
:py:attr:`PyLammps.last_run`.
|
||||
"""
|
||||
output = self.__getattr__('run')(*args, **kwargs)
|
||||
|
||||
if(self.has_mpi4py):
|
||||
@ -1972,48 +2214,102 @@ class PyLammps(object):
|
||||
|
||||
@property
|
||||
def last_run(self):
|
||||
"""
|
||||
Return data produced of last completed run command
|
||||
|
||||
:getter: Returns an object containing information about the last run command
|
||||
:type: dict
|
||||
"""
|
||||
if len(self.runs) > 0:
|
||||
return self.runs[-1]
|
||||
return None
|
||||
|
||||
@property
|
||||
def atoms(self):
|
||||
"""
|
||||
All atoms of this LAMMPS instance
|
||||
|
||||
:getter: Returns a list of atoms currently in the system
|
||||
:type: AtomList
|
||||
"""
|
||||
return AtomList(self)
|
||||
|
||||
@property
|
||||
def system(self):
|
||||
"""
|
||||
The system state of this LAMMPS instance
|
||||
|
||||
:getter: Returns an object with properties storing the current system state
|
||||
:type: namedtuple
|
||||
"""
|
||||
output = self.info("system")
|
||||
d = self._parse_info_system(output)
|
||||
return namedtuple('System', d.keys())(*d.values())
|
||||
|
||||
@property
|
||||
def communication(self):
|
||||
"""
|
||||
The communication state of this LAMMPS instance
|
||||
|
||||
:getter: Returns an object with properties storing the current communication state
|
||||
:type: namedtuple
|
||||
"""
|
||||
output = self.info("communication")
|
||||
d = self._parse_info_communication(output)
|
||||
return namedtuple('Communication', d.keys())(*d.values())
|
||||
|
||||
@property
|
||||
def computes(self):
|
||||
"""
|
||||
The list of active computes of this LAMMPS instance
|
||||
|
||||
:getter: Returns a list of computes that are currently active in this LAMMPS instance
|
||||
:type: list
|
||||
"""
|
||||
output = self.info("computes")
|
||||
return self._parse_element_list(output)
|
||||
|
||||
@property
|
||||
def dumps(self):
|
||||
"""
|
||||
The list of active dumps of this LAMMPS instance
|
||||
|
||||
:getter: Returns a list of dumps that are currently active in this LAMMPS instance
|
||||
:type: list
|
||||
"""
|
||||
output = self.info("dumps")
|
||||
return self._parse_element_list(output)
|
||||
|
||||
@property
|
||||
def fixes(self):
|
||||
"""
|
||||
The list of active fixes of this LAMMPS instance
|
||||
|
||||
:getter: Returns a list of fixes that are currently active in this LAMMPS instance
|
||||
:type: list
|
||||
"""
|
||||
output = self.info("fixes")
|
||||
return self._parse_element_list(output)
|
||||
|
||||
@property
|
||||
def groups(self):
|
||||
"""
|
||||
The list of active atom groups of this LAMMPS instance
|
||||
|
||||
:getter: Returns a list of atom groups that are currently active in this LAMMPS instance
|
||||
:type: list
|
||||
"""
|
||||
output = self.info("groups")
|
||||
return self._parse_groups(output)
|
||||
|
||||
@property
|
||||
def variables(self):
|
||||
"""
|
||||
Returns a dictionary of all variables defined in the current LAMMPS instance
|
||||
|
||||
:getter: Returns a dictionary of all variables that are defined in this LAMMPS instance
|
||||
:type: dict
|
||||
"""
|
||||
output = self.info("variables")
|
||||
vars = {}
|
||||
for v in self._parse_element_list(output):
|
||||
@ -2021,6 +2317,15 @@ class PyLammps(object):
|
||||
return vars
|
||||
|
||||
def eval(self, expr):
|
||||
"""
|
||||
Evaluate expression
|
||||
|
||||
:param expr: the expression string that should be evaluated inside of LAMMPS
|
||||
:type expr: string
|
||||
|
||||
:return: the value of the evaluated expression
|
||||
:rtype: float if numeric, string otherwise
|
||||
"""
|
||||
value = self.lmp_print('"$(%s)"' % expr).strip()
|
||||
try:
|
||||
return float(value)
|
||||
@ -2156,11 +2461,23 @@ class PyLammps(object):
|
||||
'variable', 'velocity', 'write_restart']
|
||||
|
||||
def __getattr__(self, name):
|
||||
"""
|
||||
This method is where the Python 'magic' happens. If a method is not
|
||||
defined by the class PyLammps, 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.PyLammps.command()`.
|
||||
|
||||
:param verbose: Print output of command
|
||||
:type verbose: bool
|
||||
:return: line or list of lines of output, None if no output
|
||||
:rtype: list or string
|
||||
"""
|
||||
def handler(*args, **kwargs):
|
||||
cmd_args = [name] + [str(x) for x in args]
|
||||
|
||||
with OutputCapture() as capture:
|
||||
self.command(' '.join(cmd_args))
|
||||
cmd = ' '.join(cmd_args)
|
||||
self.command(cmd)
|
||||
output = capture.output
|
||||
|
||||
if 'verbose' in kwargs and kwargs['verbose']:
|
||||
@ -2168,6 +2485,9 @@ class PyLammps(object):
|
||||
|
||||
lines = output.splitlines()
|
||||
|
||||
if self.has_echo:
|
||||
lines = lines[1:]
|
||||
|
||||
if len(lines) > 1:
|
||||
return lines
|
||||
elif len(lines) == 1:
|
||||
@ -2179,14 +2499,56 @@ class PyLammps(object):
|
||||
|
||||
class IPyLammps(PyLammps):
|
||||
"""
|
||||
IPython wrapper for LAMMPS which adds embedded graphics capabilities
|
||||
IPython wrapper for LAMMPS which adds embedded graphics capabilities to PyLammmps interface
|
||||
|
||||
It either creates its own instance of :py:class:`lammps` or can be
|
||||
initialized with an existing instance. The arguments are the same of the
|
||||
lower-level interface. The original interface can still be accessed via
|
||||
:py:attr:`PyLammps.lmp`.
|
||||
|
||||
: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.
|
||||
:type cmdargs: list
|
||||
:param ptr: pointer to a LAMMPS C++ class instance when called from an embedded Python interpreter. None means load symbols from shared library.
|
||||
:type ptr: pointer
|
||||
:param comm: MPI communicator (as provided by `mpi4py <mpi4py_docs_>`_). ``None`` means use ``MPI_COMM_WORLD`` implicitly.
|
||||
:type comm: MPI_Comm
|
||||
"""
|
||||
|
||||
def __init__(self,name="",cmdargs=None,ptr=None,comm=None):
|
||||
super(IPyLammps, self).__init__(name=name,cmdargs=cmdargs,ptr=ptr,comm=comm)
|
||||
|
||||
def image(self, filename="snapshot.png", group="all", color="type", diameter="type",
|
||||
size=None, view=None, center=None, up=None, zoom=1.0):
|
||||
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:
|
||||
@ -2215,12 +2577,22 @@ class IPyLammps(PyLammps):
|
||||
if zoom:
|
||||
cmd_args += ["zoom", zoom]
|
||||
|
||||
cmd_args.append("modify backcolor white")
|
||||
cmd_args.append("modify backcolor " + background_color)
|
||||
|
||||
self.write_dump(*cmd_args)
|
||||
from IPython.core.display import Image
|
||||
return Image('snapshot.png')
|
||||
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>")
|
||||
|
||||
89
src/atom.cpp
89
src/atom.cpp
@ -31,6 +31,8 @@
|
||||
#include "update.h"
|
||||
#include "variable.h"
|
||||
|
||||
#include "library.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
|
||||
@ -2506,6 +2508,8 @@ length of the data area, and a short description.
|
||||
:cpp:func:`lammps_extract_atom`
|
||||
|
||||
\endverbatim
|
||||
*
|
||||
* \sa extract_datatype
|
||||
*
|
||||
* \param name string with the keyword of the desired property.
|
||||
Typically the name of the pointer variable returned
|
||||
@ -2515,6 +2519,8 @@ void *Atom::extract(const char *name)
|
||||
{
|
||||
// --------------------------------------------------------------------
|
||||
// 4th customization section: customize by adding new variable name
|
||||
// please see the following function to set the type of the data
|
||||
// so that programs can detect it dynamically at run time.
|
||||
|
||||
/* NOTE: this array is only of length ntypes+1 */
|
||||
if (strcmp(name,"mass") == 0) return (void *) mass;
|
||||
@ -2583,6 +2589,89 @@ void *Atom::extract(const char *name)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
/** Provide data type info about internal data of the Atom class
|
||||
*
|
||||
\verbatim embed:rst
|
||||
|
||||
.. versionadded:: 18Sep2020
|
||||
|
||||
\endverbatim
|
||||
*
|
||||
* \sa extract
|
||||
*
|
||||
* \param name string with the keyword of the desired property.
|
||||
* \return data type constant for desired property or -1 */
|
||||
|
||||
int Atom::extract_datatype(const char *name)
|
||||
{
|
||||
// --------------------------------------------------------------------
|
||||
// 5th customization section: customize by adding new variable name
|
||||
|
||||
if (strcmp(name,"mass") == 0) return LAMMPS_DOUBLE;
|
||||
|
||||
if (strcmp(name,"id") == 0) return LAMMPS_TAGINT;
|
||||
if (strcmp(name,"type") == 0) return LAMMPS_INT;
|
||||
if (strcmp(name,"mask") == 0) return LAMMPS_INT;
|
||||
if (strcmp(name,"image") == 0) return LAMMPS_TAGINT;
|
||||
if (strcmp(name,"x") == 0) return LAMMPS_DOUBLE_2D;
|
||||
if (strcmp(name,"v") == 0) return LAMMPS_DOUBLE_2D;
|
||||
if (strcmp(name,"f") == 0) return LAMMPS_DOUBLE_2D;
|
||||
if (strcmp(name,"molecule") == 0) return LAMMPS_TAGINT;
|
||||
if (strcmp(name,"q") == 0) return LAMMPS_DOUBLE;
|
||||
if (strcmp(name,"mu") == 0) return LAMMPS_DOUBLE_2D;
|
||||
if (strcmp(name,"omega") == 0) return LAMMPS_DOUBLE_2D;
|
||||
if (strcmp(name,"angmom") == 0) return LAMMPS_DOUBLE_2D;
|
||||
if (strcmp(name,"torque") == 0) return LAMMPS_DOUBLE_2D;
|
||||
if (strcmp(name,"radius") == 0) return LAMMPS_DOUBLE;
|
||||
if (strcmp(name,"rmass") == 0) return LAMMPS_DOUBLE;
|
||||
if (strcmp(name,"ellipsoid") == 0) return LAMMPS_INT;
|
||||
if (strcmp(name,"line") == 0) return LAMMPS_INT;
|
||||
if (strcmp(name,"tri") == 0) return LAMMPS_INT;
|
||||
if (strcmp(name,"body") == 0) return LAMMPS_INT;
|
||||
|
||||
if (strcmp(name,"vfrac") == 0) return LAMMPS_DOUBLE;
|
||||
if (strcmp(name,"s0") == 0) return LAMMPS_DOUBLE;
|
||||
if (strcmp(name,"x0") == 0) return LAMMPS_DOUBLE_2D;
|
||||
|
||||
if (strcmp(name,"spin") == 0) return LAMMPS_INT;
|
||||
if (strcmp(name,"eradius") == 0) return LAMMPS_DOUBLE;
|
||||
if (strcmp(name,"ervel") == 0) return LAMMPS_DOUBLE;
|
||||
if (strcmp(name,"erforce") == 0) return LAMMPS_DOUBLE;
|
||||
if (strcmp(name,"ervelforce") == 0) return LAMMPS_DOUBLE;
|
||||
if (strcmp(name,"cs") == 0) return LAMMPS_DOUBLE_2D;
|
||||
if (strcmp(name,"csforce") == 0) return LAMMPS_DOUBLE_2D;
|
||||
if (strcmp(name,"vforce") == 0) return LAMMPS_DOUBLE_2D;
|
||||
if (strcmp(name,"etag") == 0) return LAMMPS_INT;
|
||||
|
||||
if (strcmp(name,"rho") == 0) return LAMMPS_DOUBLE;
|
||||
if (strcmp(name,"drho") == 0) return LAMMPS_DOUBLE;
|
||||
if (strcmp(name,"esph") == 0) return LAMMPS_DOUBLE;
|
||||
if (strcmp(name,"desph") == 0) return LAMMPS_DOUBLE;
|
||||
if (strcmp(name,"cv") == 0) return LAMMPS_DOUBLE;
|
||||
if (strcmp(name,"vest") == 0) return LAMMPS_DOUBLE_2D;
|
||||
|
||||
// USER-MESONT package
|
||||
if (strcmp(name,"length") == 0) return LAMMPS_DOUBLE;
|
||||
if (strcmp(name,"buckling") == 0) return LAMMPS_INT;
|
||||
if (strcmp(name,"bond_nt") == 0) return LAMMPS_TAGINT_2D;
|
||||
|
||||
if (strcmp(name, "contact_radius") == 0) return LAMMPS_DOUBLE;
|
||||
if (strcmp(name, "smd_data_9") == 0) return LAMMPS_DOUBLE_2D;
|
||||
if (strcmp(name, "smd_stress") == 0) return LAMMPS_DOUBLE_2D;
|
||||
if (strcmp(name, "eff_plastic_strain") == 0) return LAMMPS_DOUBLE;
|
||||
if (strcmp(name, "eff_plastic_strain_rate") == 0) return LAMMPS_DOUBLE;
|
||||
if (strcmp(name, "damage") == 0) return LAMMPS_DOUBLE;
|
||||
|
||||
if (strcmp(name,"dpdTheta") == 0) return LAMMPS_DOUBLE;
|
||||
if (strcmp(name,"edpd_temp") == 0) return LAMMPS_DOUBLE;
|
||||
|
||||
// end of customization section
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
return # of bytes of allocated memory
|
||||
call to avec tallies per-atom vectors
|
||||
|
||||
@ -335,6 +335,7 @@ class Atom : protected Pointers {
|
||||
virtual void sync_modify(ExecutionSpace, unsigned int, unsigned int) {}
|
||||
|
||||
void *extract(const char *);
|
||||
int extract_datatype(const char *);
|
||||
|
||||
inline int* get_map_array() {return map_array;};
|
||||
inline int get_map_size() {return map_tag_max+1;};
|
||||
|
||||
@ -18,7 +18,7 @@
|
||||
#include <vector>
|
||||
|
||||
// The fmt library version in the form major * 10000 + minor * 100 + patch.
|
||||
#define FMT_VERSION 70002
|
||||
#define FMT_VERSION 70003
|
||||
|
||||
#ifdef __clang__
|
||||
# define FMT_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__)
|
||||
@ -177,6 +177,12 @@
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// LAMMPS customization
|
||||
// use 'v7_lmp' namespace instead of 'v7' so that our
|
||||
// bundled copy does not collide with linking other code
|
||||
// using system wide installations which may be using
|
||||
// a different version.
|
||||
|
||||
#ifndef FMT_BEGIN_NAMESPACE
|
||||
# if FMT_HAS_FEATURE(cxx_inline_namespaces) || FMT_GCC_VERSION >= 404 || \
|
||||
FMT_MSC_VER >= 1900
|
||||
@ -299,7 +305,7 @@ template <typename T> struct std_string_view {};
|
||||
|
||||
#ifdef FMT_USE_INT128
|
||||
// Do nothing.
|
||||
#elif defined(__SIZEOF_INT128__) && !FMT_NVCC
|
||||
#elif defined(__SIZEOF_INT128__) && !FMT_NVCC && !(FMT_CLANG_VERSION && FMT_MSC_VER)
|
||||
# define FMT_USE_INT128 1
|
||||
using int128_t = __int128_t;
|
||||
using uint128_t = __uint128_t;
|
||||
@ -489,6 +495,8 @@ constexpr basic_string_view<typename S::char_type> to_string_view(const S& s) {
|
||||
return s;
|
||||
}
|
||||
|
||||
// LAMMPS customization using 'v7_lmp' instead of 'v7'
|
||||
|
||||
namespace detail {
|
||||
void to_string_view(...);
|
||||
using fmt::v7_lmp::to_string_view;
|
||||
@ -1713,7 +1721,7 @@ template <typename Context> class basic_format_args {
|
||||
}
|
||||
|
||||
template <typename Char> int get_id(basic_string_view<Char> name) const {
|
||||
if (!has_named_args()) return {};
|
||||
if (!has_named_args()) return -1;
|
||||
const auto& named_args =
|
||||
(is_packed() ? values_[-1] : args_[-1].value_).named_args;
|
||||
for (size_t i = 0; i < named_args.size; ++i) {
|
||||
|
||||
@ -69,6 +69,12 @@
|
||||
# define FMT_NOINLINE
|
||||
#endif
|
||||
|
||||
// LAMMPS customizations:
|
||||
// 1) Intel compilers on MacOS have __clang__ defined
|
||||
// but fail to recognize [[clang::fallthrough]]
|
||||
// 2) Intel compilers on Linux identify as GCC compatible
|
||||
// but fail to recognize [[gnu::fallthrough]]
|
||||
|
||||
#if __cplusplus == 201103L || __cplusplus == 201402L
|
||||
# if defined(__clang__) && !defined(__INTEL_COMPILER)
|
||||
# define FMT_FALLTHROUGH [[clang::fallthrough]]
|
||||
@ -724,13 +730,18 @@ class FMT_API format_error : public std::runtime_error {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename T>
|
||||
using is_signed =
|
||||
std::integral_constant<bool, std::numeric_limits<T>::is_signed ||
|
||||
std::is_same<T, int128_t>::value>;
|
||||
|
||||
// Returns true if value is negative, false otherwise.
|
||||
// Same as `value < 0` but doesn't produce warnings if T is an unsigned type.
|
||||
template <typename T, FMT_ENABLE_IF(std::numeric_limits<T>::is_signed)>
|
||||
template <typename T, FMT_ENABLE_IF(is_signed<T>::value)>
|
||||
FMT_CONSTEXPR bool is_negative(T value) {
|
||||
return value < 0;
|
||||
}
|
||||
template <typename T, FMT_ENABLE_IF(!std::numeric_limits<T>::is_signed)>
|
||||
template <typename T, FMT_ENABLE_IF(!is_signed<T>::value)>
|
||||
FMT_CONSTEXPR bool is_negative(T) {
|
||||
return false;
|
||||
}
|
||||
@ -745,9 +756,9 @@ FMT_CONSTEXPR bool is_supported_floating_point(T) {
|
||||
// Smallest of uint32_t, uint64_t, uint128_t that is large enough to
|
||||
// represent all values of T.
|
||||
template <typename T>
|
||||
using uint32_or_64_or_128_t = conditional_t<
|
||||
num_bits<T>() <= 32, uint32_t,
|
||||
conditional_t<num_bits<T>() <= 64, uint64_t, uint128_t>>;
|
||||
using uint32_or_64_or_128_t =
|
||||
conditional_t<num_bits<T>() <= 32, uint32_t,
|
||||
conditional_t<num_bits<T>() <= 64, uint64_t, uint128_t>>;
|
||||
|
||||
// Static data is placed in this class template for the header-only config.
|
||||
template <typename T = void> struct FMT_EXTERN_TEMPLATE_API basic_data {
|
||||
@ -1593,7 +1604,11 @@ template <typename OutputIt, typename Char, typename UInt> struct int_writer {
|
||||
make_checked(p, s.size()));
|
||||
}
|
||||
if (prefix_size != 0) p[-1] = static_cast<Char>('-');
|
||||
write(out, basic_string_view<Char>(buffer.data(), buffer.size()), specs);
|
||||
using iterator = remove_reference_t<decltype(reserve(out, 0))>;
|
||||
auto data = buffer.data();
|
||||
out = write_padded<align::right>(out, specs, size, size, [=](iterator it) {
|
||||
return copy_str<Char>(data, data + size, it);
|
||||
});
|
||||
}
|
||||
|
||||
void on_chr() { *out++ = static_cast<Char>(abs_value); }
|
||||
|
||||
141
src/library.cpp
141
src/library.cpp
@ -917,7 +917,7 @@ int lammps_extract_setting(void *handle, const char *keyword)
|
||||
This function returns a pointer to the location of some global property
|
||||
stored in one of the constituent classes of a LAMMPS instance. The
|
||||
returned pointer is cast to ``void *`` and needs to be cast to a pointer
|
||||
of the type that the entity represents. The pointers returned by this
|
||||
of the type that the entity represents. The pointers returned by this
|
||||
function are generally persistent; therefore it is not necessary to call
|
||||
the function again, unless a :doc:`clear` command is issued which wipes
|
||||
out and recreates the contents of the :cpp:class:`LAMMPS
|
||||
@ -1227,7 +1227,7 @@ of data type that the entity represents.
|
||||
A table with supported keywords is included in the documentation
|
||||
of the :cpp:func:`Atom::extract() <LAMMPS_NS::Atom::extract>` function.
|
||||
|
||||
.. note::
|
||||
.. warning::
|
||||
|
||||
The pointers returned by this function are generally not persistent
|
||||
since per-atom data may be re-distributed, re-allocated, and
|
||||
@ -1248,6 +1248,117 @@ void *lammps_extract_atom(void *handle, const char *name)
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
/** Get data type of internal global LAMMPS variables or arrays.
|
||||
*
|
||||
\verbatim embed:rst
|
||||
|
||||
This function returns an integer that encodes the data type of the global
|
||||
property with the specified name. See :cpp:enum:`_LMP_DATATYPE_CONST` for valid
|
||||
values. Callers of :cpp:func:`lammps_extract_global` can use this information
|
||||
to then decide how to cast the (void*) pointer and access the data.
|
||||
|
||||
.. versionadded:: 18Sep2020
|
||||
|
||||
\endverbatim
|
||||
*
|
||||
* \param handle pointer to a previously created LAMMPS instance
|
||||
* \param name string with the name of the extracted property
|
||||
* \return integer constant encoding the data type of the property
|
||||
* or -1 if not found. */
|
||||
|
||||
int lammps_extract_global_datatype(void *handle, const char *name)
|
||||
{
|
||||
LAMMPS *lmp = (LAMMPS *) handle;
|
||||
|
||||
if (strcmp(name,"units") == 0) return LAMMPS_STRING;
|
||||
if (strcmp(name,"dt") == 0) return LAMMPS_DOUBLE;
|
||||
if (strcmp(name,"ntimestep") == 0) return LAMMPS_BIGINT;
|
||||
if (strcmp(name,"boxlo") == 0) return LAMMPS_DOUBLE;
|
||||
if (strcmp(name,"boxhi") == 0) return LAMMPS_DOUBLE;
|
||||
if (strcmp(name,"boxxlo") == 0) return LAMMPS_DOUBLE;
|
||||
if (strcmp(name,"boxxhi") == 0) return LAMMPS_DOUBLE;
|
||||
if (strcmp(name,"boxylo") == 0) return LAMMPS_DOUBLE;
|
||||
if (strcmp(name,"boxyhi") == 0) return LAMMPS_DOUBLE;
|
||||
if (strcmp(name,"boxzlo") == 0) return LAMMPS_DOUBLE;
|
||||
if (strcmp(name,"boxzhi") == 0) return LAMMPS_DOUBLE;
|
||||
if (strcmp(name,"periodicity") == 0) return LAMMPS_INT;
|
||||
if (strcmp(name,"triclinic") == 0) return LAMMPS_INT;
|
||||
if (strcmp(name,"xy") == 0) return LAMMPS_DOUBLE;
|
||||
if (strcmp(name,"xz") == 0) return LAMMPS_DOUBLE;
|
||||
if (strcmp(name,"yz") == 0) return LAMMPS_DOUBLE;
|
||||
if (strcmp(name,"natoms") == 0) return LAMMPS_BIGINT;
|
||||
if (strcmp(name,"nbonds") == 0) return LAMMPS_BIGINT;
|
||||
if (strcmp(name,"nangles") == 0) return LAMMPS_BIGINT;
|
||||
if (strcmp(name,"ndihedrals") == 0) return LAMMPS_BIGINT;
|
||||
if (strcmp(name,"nimpropers") == 0) return LAMMPS_BIGINT;
|
||||
if (strcmp(name,"nlocal") == 0) return LAMMPS_INT;
|
||||
if (strcmp(name,"nghost") == 0) return LAMMPS_INT;
|
||||
if (strcmp(name,"nmax") == 0) return LAMMPS_INT;
|
||||
if (strcmp(name,"ntypes") == 0) return LAMMPS_INT;
|
||||
|
||||
if (strcmp(name,"q_flag") == 0) return LAMMPS_INT;
|
||||
|
||||
// update->atime can be referenced as a pointer
|
||||
// thermo "timer" data cannot be, since it is computed on request
|
||||
// lammps_get_thermo() can access all thermo keywords by value
|
||||
|
||||
if (strcmp(name,"atime") == 0) return LAMMPS_DOUBLE;
|
||||
if (strcmp(name,"atimestep") == 0) return LAMMPS_BIGINT;
|
||||
|
||||
// global constants defined by units
|
||||
|
||||
if (strcmp(name,"boltz") == 0) return LAMMPS_DOUBLE;
|
||||
if (strcmp(name,"hplanck") == 0) return LAMMPS_DOUBLE;
|
||||
if (strcmp(name,"mvv2e") == 0) return LAMMPS_DOUBLE;
|
||||
if (strcmp(name,"ftm2v") == 0) return LAMMPS_DOUBLE;
|
||||
if (strcmp(name,"mv2d") == 0) return LAMMPS_DOUBLE;
|
||||
if (strcmp(name,"nktv2p") == 0) return LAMMPS_DOUBLE;
|
||||
if (strcmp(name,"qqr2e") == 0) return LAMMPS_DOUBLE;
|
||||
if (strcmp(name,"qe2f") == 0) return LAMMPS_DOUBLE;
|
||||
if (strcmp(name,"vxmu2f") == 0) return LAMMPS_DOUBLE;
|
||||
if (strcmp(name,"xxt2kmu") == 0) return LAMMPS_DOUBLE;
|
||||
if (strcmp(name,"dielectric") == 0) return LAMMPS_DOUBLE;
|
||||
if (strcmp(name,"qqrd2e") == 0) return LAMMPS_DOUBLE;
|
||||
if (strcmp(name,"e_mass") == 0) return LAMMPS_DOUBLE;
|
||||
if (strcmp(name,"hhmrr2e") == 0) return LAMMPS_DOUBLE;
|
||||
if (strcmp(name,"mvh2r") == 0) return LAMMPS_DOUBLE;
|
||||
|
||||
if (strcmp(name,"angstrom") == 0) return LAMMPS_DOUBLE;
|
||||
if (strcmp(name,"femtosecond") == 0) return LAMMPS_DOUBLE;
|
||||
if (strcmp(name,"qelectron") == 0) return LAMMPS_DOUBLE;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
/** Get data type of a LAMMPS per-atom property
|
||||
*
|
||||
\verbatim embed:rst
|
||||
|
||||
This function returns an integer that encodes the data type of the per-atom
|
||||
property with the specified name. See :cpp:enum:`_LMP_DATATYPE_CONST` for valid
|
||||
values. Callers of :cpp:func:`lammps_extract_atom` can use this information
|
||||
to then decide how to cast the (void*) pointer and access the data.
|
||||
|
||||
.. versionadded:: 18Sep2020
|
||||
|
||||
\endverbatim
|
||||
*
|
||||
* \param handle pointer to a previously created LAMMPS instance
|
||||
* \param name string with the name of the extracted property
|
||||
* \return integer constant encoding the data type of the property
|
||||
* or -1 if not found.
|
||||
* */
|
||||
|
||||
int lammps_extract_atom_datatype(void *handle, const char *name)
|
||||
{
|
||||
LAMMPS *lmp = (LAMMPS *) handle;
|
||||
return lmp->atom->extract_datatype(name);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
/** Create N atoms from list of coordinates
|
||||
*
|
||||
\verbatim embed:rst
|
||||
@ -1472,11 +1583,13 @@ lists the available options.
|
||||
- ``int *``
|
||||
- Number of local data columns
|
||||
|
||||
The pointers returned by this function are generally not persistent
|
||||
since the computed data may be re-distributed, re-allocated, and
|
||||
re-ordered at every invocation. It is advisable to re-invoke this
|
||||
function before the data is accessed, or make a copy if the data shall
|
||||
be used after other LAMMPS commands have been issued.
|
||||
.. warning::
|
||||
|
||||
The pointers returned by this function are generally not persistent
|
||||
since the computed data may be re-distributed, re-allocated, and
|
||||
re-ordered at every invocation. It is advisable to re-invoke this
|
||||
function before the data is accessed, or make a copy if the data shall
|
||||
be used after other LAMMPS commands have been issued.
|
||||
|
||||
.. note::
|
||||
|
||||
@ -1656,12 +1769,14 @@ The following table lists the available options.
|
||||
- ``int *``
|
||||
- Number of local data columns
|
||||
|
||||
The pointers returned by this function for per-atom or local data are
|
||||
generally not persistent, since the computed data may be re-distributed,
|
||||
re-allocated, and re-ordered at every invocation of the fix. It is thus
|
||||
advisable to re-invoke this function before the data is accessed, or
|
||||
make a copy, if the data shall be used after other LAMMPS commands have
|
||||
been issued.
|
||||
.. warning::
|
||||
|
||||
The pointers returned by this function for per-atom or local data are
|
||||
generally not persistent, since the computed data may be re-distributed,
|
||||
re-allocated, and re-ordered at every invocation of the fix. It is thus
|
||||
advisable to re-invoke this function before the data is accessed, or
|
||||
make a copy, if the data shall be used after other LAMMPS commands have
|
||||
been issued.
|
||||
|
||||
.. note::
|
||||
|
||||
|
||||
@ -40,6 +40,20 @@
|
||||
#include <inttypes.h> /* for int64_t */
|
||||
#endif
|
||||
|
||||
/** Data type constants for extracting data from atoms, computes and fixes
|
||||
*
|
||||
* Must be kept in sync with the equivalent constants in lammps.py */
|
||||
|
||||
enum _LMP_DATATYPE_CONST {
|
||||
LAMMPS_INT = 0, /*!< 32-bit integer (array) */
|
||||
LAMMPS_INT_2D = 1, /*!< two-dimensional 32-bit integer array */
|
||||
LAMMPS_DOUBLE = 2, /*!< 64-bit double (array) */
|
||||
LAMMPS_DOUBLE_2D = 3, /*!< two-dimensional 64-bit double array */
|
||||
LAMMPS_INT64 = 4, /*!< 64-bit integer (array) */
|
||||
LAMMPS_INT64_2D = 5, /*!< two-dimensional 64-bit integer array */
|
||||
LAMMPS_STRING = 6 /*!< C-String */
|
||||
};
|
||||
|
||||
/** Style constants for extracting data from computes and fixes.
|
||||
*
|
||||
* Must be kept in sync with the equivalent constants in lammps.py */
|
||||
@ -113,6 +127,9 @@ int lammps_extract_setting(void *handle, const char *keyword);
|
||||
void *lammps_extract_global(void *handle, const char *name);
|
||||
void *lammps_extract_atom(void *handle, const char *name);
|
||||
|
||||
int lammps_extract_global_datatype(void *handle, const char *name);
|
||||
int lammps_extract_atom_datatype(void *handle, const char *name);
|
||||
|
||||
#if !defined(LAMMPS_BIGBIG)
|
||||
int lammps_create_atoms(void *handle, int n, int *id, int *type,
|
||||
double *x, double *v, int *image, int bexpand);
|
||||
|
||||
@ -102,6 +102,11 @@ typedef int64_t bigint;
|
||||
#define ATOTAGINT atoi
|
||||
#define ATOBIGINT ATOLL
|
||||
|
||||
#define LAMMPS_TAGINT LAMMPS_INT
|
||||
#define LAMMPS_TAGINT_2D LAMMPS_INT_2D
|
||||
#define LAMMPS_BIGINT LAMMPS_INT64
|
||||
#define LAMMPS_BIGINT_2D LAMMPS_INT64_2D
|
||||
|
||||
#define IMGMASK 1023
|
||||
#define IMGMAX 512
|
||||
#define IMGBITS 10
|
||||
@ -134,6 +139,11 @@ typedef int64_t bigint;
|
||||
#define ATOTAGINT ATOLL
|
||||
#define ATOBIGINT ATOLL
|
||||
|
||||
#define LAMMPS_TAGINT LAMMPS_INT64
|
||||
#define LAMMPS_TAGINT_2D LAMMPS_INT64_2D
|
||||
#define LAMMPS_BIGINT LAMMPS_INT64
|
||||
#define LAMMPS_BIGINT_2D LAMMPS_INT64_2D
|
||||
|
||||
#define IMGMASK 2097151
|
||||
#define IMGMAX 1048576
|
||||
#define IMGBITS 21
|
||||
@ -165,6 +175,11 @@ typedef int bigint;
|
||||
#define ATOTAGINT atoi
|
||||
#define ATOBIGINT atoi
|
||||
|
||||
#define LAMMPS_TAGINT LAMMPS_INT
|
||||
#define LAMMPS_TAGINT_2D LAMMPS_INT_2D
|
||||
#define LAMMPS_BIGINT LAMMPS_INT
|
||||
#define LAMMPS_BIGINT_2D LAMMPS_INT_2D
|
||||
|
||||
#define IMGMASK 1023
|
||||
#define IMGMAX 512
|
||||
#define IMGBITS 10
|
||||
|
||||
@ -251,4 +251,90 @@ TEST_F(LibraryProperties, global)
|
||||
EXPECT_EQ((*b_ptr), 2);
|
||||
d_ptr = (double *)lammps_extract_global(lmp, "dt");
|
||||
EXPECT_DOUBLE_EQ((*d_ptr), 0.1);
|
||||
int dtype = lammps_extract_global_datatype(lmp, "dt");
|
||||
EXPECT_EQ(dtype, LAMMPS_DOUBLE);
|
||||
};
|
||||
|
||||
class AtomProperties : public ::testing::Test {
|
||||
protected:
|
||||
void *lmp;
|
||||
|
||||
AtomProperties(){};
|
||||
~AtomProperties() override{};
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
const char *args[] = {"LAMMPS_test", "-log", "none",
|
||||
"-echo", "screen", "-nocite"};
|
||||
|
||||
char **argv = (char **)args;
|
||||
int argc = sizeof(args) / sizeof(char *);
|
||||
|
||||
::testing::internal::CaptureStdout();
|
||||
lmp = lammps_open_no_mpi(argc, argv, NULL);
|
||||
std::string output = ::testing::internal::GetCapturedStdout();
|
||||
if (verbose) std::cout << output;
|
||||
EXPECT_THAT(output, StartsWith("LAMMPS ("));
|
||||
::testing::internal::CaptureStdout();
|
||||
lammps_command(lmp, "region box block 0 2 0 2 0 2");
|
||||
lammps_command(lmp, "create_box 1 box");
|
||||
lammps_command(lmp, "mass 1 3.0");
|
||||
lammps_command(lmp, "create_atoms 1 single 1.0 1.0 1.5");
|
||||
lammps_command(lmp, "create_atoms 1 single 0.2 0.1 0.1");
|
||||
output = ::testing::internal::GetCapturedStdout();
|
||||
if (verbose) std::cout << output;
|
||||
}
|
||||
void TearDown() override
|
||||
{
|
||||
::testing::internal::CaptureStdout();
|
||||
lammps_close(lmp);
|
||||
std::string output = ::testing::internal::GetCapturedStdout();
|
||||
EXPECT_THAT(output, HasSubstr("Total wall time:"));
|
||||
if (verbose) std::cout << output;
|
||||
lmp = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(AtomProperties, invalid)
|
||||
{
|
||||
ASSERT_EQ(lammps_extract_atom(lmp, "UNKNOWN"), nullptr);
|
||||
}
|
||||
|
||||
TEST_F(AtomProperties, mass)
|
||||
{
|
||||
EXPECT_EQ(lammps_extract_atom_datatype(lmp, "mass"), LAMMPS_DOUBLE);
|
||||
double * mass = (double *)lammps_extract_atom(lmp, "mass");
|
||||
ASSERT_NE(mass, nullptr);
|
||||
ASSERT_DOUBLE_EQ(mass[1], 3.0);
|
||||
}
|
||||
|
||||
TEST_F(AtomProperties, id)
|
||||
{
|
||||
EXPECT_EQ(lammps_extract_atom_datatype(lmp, "id"), LAMMPS_TAGINT);
|
||||
LAMMPS_NS::tagint * id = (LAMMPS_NS::tagint *)lammps_extract_atom(lmp, "id");
|
||||
ASSERT_NE(id, nullptr);
|
||||
ASSERT_EQ(id[0], 1);
|
||||
ASSERT_EQ(id[1], 2);
|
||||
}
|
||||
|
||||
TEST_F(AtomProperties, type)
|
||||
{
|
||||
EXPECT_EQ(lammps_extract_atom_datatype(lmp, "type"), LAMMPS_INT);
|
||||
int * type = (int *)lammps_extract_atom(lmp, "type");
|
||||
ASSERT_NE(type, nullptr);
|
||||
ASSERT_EQ(type[0], 1);
|
||||
ASSERT_EQ(type[1], 1);
|
||||
}
|
||||
|
||||
TEST_F(AtomProperties, position)
|
||||
{
|
||||
EXPECT_EQ(lammps_extract_atom_datatype(lmp, "x"), LAMMPS_DOUBLE_2D);
|
||||
double ** x = (double **)lammps_extract_atom(lmp, "x");
|
||||
ASSERT_NE(x, nullptr);
|
||||
EXPECT_DOUBLE_EQ(x[0][0], 1.0);
|
||||
EXPECT_DOUBLE_EQ(x[0][1], 1.0);
|
||||
EXPECT_DOUBLE_EQ(x[0][2], 1.5);
|
||||
EXPECT_DOUBLE_EQ(x[1][0], 0.2);
|
||||
EXPECT_DOUBLE_EQ(x[1][1], 0.1);
|
||||
EXPECT_DOUBLE_EQ(x[1][2], 0.1);
|
||||
}
|
||||
|
||||
@ -62,40 +62,40 @@ if (PKG_COMPRESS)
|
||||
set_tests_properties(DumpLocalGZ PROPERTIES ENVIRONMENT "LAMMPS_POTENTIALS=${LAMMPS_POTENTIALS_DIR}")
|
||||
set_tests_properties(DumpLocalGZ PROPERTIES ENVIRONMENT "GZIP_BINARY=${GZIP_BINARY}")
|
||||
|
||||
if(Zstd_FOUND)
|
||||
find_program(ZSTD_BINARY NAMES zstd)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(Zstd IMPORTED_TARGET libzstd>=1.4)
|
||||
find_program(ZSTD_BINARY NAMES zstd)
|
||||
|
||||
if (ZSTD_BINARY)
|
||||
add_executable(test_dump_atom_zstd test_dump_atom_zstd.cpp)
|
||||
target_link_libraries(test_dump_atom_zstd PRIVATE lammps GTest::GMock GTest::GTest)
|
||||
add_test(NAME DumpAtomZstd COMMAND test_dump_atom_zstd WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
set_tests_properties(DumpAtomZstd PROPERTIES ENVIRONMENT "LAMMPS_POTENTIALS=${LAMMPS_POTENTIALS_DIR}")
|
||||
set_tests_properties(DumpAtomZstd PROPERTIES ENVIRONMENT "ZSTD_BINARY=${ZSTD_BINARY}")
|
||||
if(Zstd_FOUND AND ZSTD_BINARY)
|
||||
add_executable(test_dump_atom_zstd test_dump_atom_zstd.cpp)
|
||||
target_link_libraries(test_dump_atom_zstd PRIVATE lammps GTest::GMock GTest::GTest)
|
||||
add_test(NAME DumpAtomZstd COMMAND test_dump_atom_zstd WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
set_tests_properties(DumpAtomZstd PROPERTIES ENVIRONMENT "LAMMPS_POTENTIALS=${LAMMPS_POTENTIALS_DIR}")
|
||||
set_tests_properties(DumpAtomZstd PROPERTIES ENVIRONMENT "ZSTD_BINARY=${ZSTD_BINARY}")
|
||||
|
||||
add_executable(test_dump_custom_zstd test_dump_custom_zstd.cpp)
|
||||
target_link_libraries(test_dump_custom_zstd PRIVATE lammps GTest::GMock GTest::GTest)
|
||||
add_test(NAME DumpCustomZstd COMMAND test_dump_custom_zstd WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
set_tests_properties(DumpCustomZstd PROPERTIES ENVIRONMENT "LAMMPS_POTENTIALS=${LAMMPS_POTENTIALS_DIR}")
|
||||
set_tests_properties(DumpCustomZstd PROPERTIES ENVIRONMENT "ZSTD_BINARY=${ZSTD_BINARY}")
|
||||
add_executable(test_dump_custom_zstd test_dump_custom_zstd.cpp)
|
||||
target_link_libraries(test_dump_custom_zstd PRIVATE lammps GTest::GMock GTest::GTest)
|
||||
add_test(NAME DumpCustomZstd COMMAND test_dump_custom_zstd WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
set_tests_properties(DumpCustomZstd PROPERTIES ENVIRONMENT "LAMMPS_POTENTIALS=${LAMMPS_POTENTIALS_DIR}")
|
||||
set_tests_properties(DumpCustomZstd PROPERTIES ENVIRONMENT "ZSTD_BINARY=${ZSTD_BINARY}")
|
||||
|
||||
add_executable(test_dump_cfg_zstd test_dump_cfg_zstd.cpp)
|
||||
target_link_libraries(test_dump_cfg_zstd PRIVATE lammps GTest::GMock GTest::GTest)
|
||||
add_test(NAME DumpCfgZstd COMMAND test_dump_cfg_zstd WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
set_tests_properties(DumpCfgZstd PROPERTIES ENVIRONMENT "LAMMPS_POTENTIALS=${LAMMPS_POTENTIALS_DIR}")
|
||||
set_tests_properties(DumpCfgZstd PROPERTIES ENVIRONMENT "ZSTD_BINARY=${ZSTD_BINARY}")
|
||||
add_executable(test_dump_cfg_zstd test_dump_cfg_zstd.cpp)
|
||||
target_link_libraries(test_dump_cfg_zstd PRIVATE lammps GTest::GMock GTest::GTest)
|
||||
add_test(NAME DumpCfgZstd COMMAND test_dump_cfg_zstd WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
set_tests_properties(DumpCfgZstd PROPERTIES ENVIRONMENT "LAMMPS_POTENTIALS=${LAMMPS_POTENTIALS_DIR}")
|
||||
set_tests_properties(DumpCfgZstd PROPERTIES ENVIRONMENT "ZSTD_BINARY=${ZSTD_BINARY}")
|
||||
|
||||
add_executable(test_dump_xyz_zstd test_dump_xyz_zstd.cpp)
|
||||
target_link_libraries(test_dump_xyz_zstd PRIVATE lammps GTest::GMock GTest::GTest)
|
||||
add_test(NAME DumpXYZZstd COMMAND test_dump_xyz_zstd WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
set_tests_properties(DumpXYZZstd PROPERTIES ENVIRONMENT "LAMMPS_POTENTIALS=${LAMMPS_POTENTIALS_DIR}")
|
||||
set_tests_properties(DumpXYZZstd PROPERTIES ENVIRONMENT "ZSTD_BINARY=${ZSTD_BINARY}")
|
||||
add_executable(test_dump_xyz_zstd test_dump_xyz_zstd.cpp)
|
||||
target_link_libraries(test_dump_xyz_zstd PRIVATE lammps GTest::GMock GTest::GTest)
|
||||
add_test(NAME DumpXYZZstd COMMAND test_dump_xyz_zstd WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
set_tests_properties(DumpXYZZstd PROPERTIES ENVIRONMENT "LAMMPS_POTENTIALS=${LAMMPS_POTENTIALS_DIR}")
|
||||
set_tests_properties(DumpXYZZstd PROPERTIES ENVIRONMENT "ZSTD_BINARY=${ZSTD_BINARY}")
|
||||
|
||||
add_executable(test_dump_local_zstd test_dump_local_zstd.cpp)
|
||||
target_link_libraries(test_dump_local_zstd PRIVATE lammps GTest::GMock GTest::GTest)
|
||||
add_test(NAME DumpLocalZstd COMMAND test_dump_local_zstd WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
set_tests_properties(DumpLocalZstd PROPERTIES ENVIRONMENT "LAMMPS_POTENTIALS=${LAMMPS_POTENTIALS_DIR}")
|
||||
set_tests_properties(DumpLocalZstd PROPERTIES ENVIRONMENT "ZSTD_BINARY=${ZSTD_BINARY}")
|
||||
endif()
|
||||
add_executable(test_dump_local_zstd test_dump_local_zstd.cpp)
|
||||
target_link_libraries(test_dump_local_zstd PRIVATE lammps GTest::GMock GTest::GTest)
|
||||
add_test(NAME DumpLocalZstd COMMAND test_dump_local_zstd WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
set_tests_properties(DumpLocalZstd PROPERTIES ENVIRONMENT "LAMMPS_POTENTIALS=${LAMMPS_POTENTIALS_DIR}")
|
||||
set_tests_properties(DumpLocalZstd PROPERTIES ENVIRONMENT "ZSTD_BINARY=${ZSTD_BINARY}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
@ -17,9 +17,9 @@ if (Python_EXECUTABLE)
|
||||
# prepare to augment the environment so that the LAMMPS python module and the shared library is found.
|
||||
set(PYTHON_TEST_ENVIRONMENT PYTHONPATH=${LAMMPS_PYTHON_DIR}:$ENV{PYTHONPATH})
|
||||
if(APPLE)
|
||||
list(APPEND PYTHON_TEST_ENVIRONMENT DYLD_LIBRARY_PATH=${CMAKE_BINARY_DIR}:$ENV{DYLD_LIBRARY_PATH})
|
||||
list(APPEND PYTHON_TEST_ENVIRONMENT "DYLD_LIBRARY_PATH=${CMAKE_BINARY_DIR}:$ENV{DYLD_LIBRARY_PATH};LAMMPS_CMAKE_CACHE=${CMAKE_BINARY_DIR}/CMakeCache.txt")
|
||||
else()
|
||||
list(APPEND PYTHON_TEST_ENVIRONMENT LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}:$ENV{LD_LIBRARY_PATH})
|
||||
list(APPEND PYTHON_TEST_ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}:$ENV{LD_LIBRARY_PATH};LAMMPS_CMAKE_CACHE=${CMAKE_BINARY_DIR}/CMakeCache.txt")
|
||||
endif()
|
||||
if(LAMMPS_MACHINE)
|
||||
# convert from '_machine' to 'machine'
|
||||
@ -27,20 +27,43 @@ if (Python_EXECUTABLE)
|
||||
list(APPEND PYTHON_TEST_ENVIRONMENT LAMMPS_MACHINE_NAME=${LAMMPS_MACHINE_NAME})
|
||||
endif()
|
||||
|
||||
if(ENABLE_COVERAGE)
|
||||
find_program(COVERAGE_BINARY coverage)
|
||||
find_package_handle_standard_args(COVERAGE DEFAULT_MSG COVERAGE_BINARY)
|
||||
|
||||
if(COVERAGE_FOUND)
|
||||
set(PYTHON_TEST_RUNNER ${Python_EXECUTABLE} -u ${COVERAGE_BINARY} run --parallel-mode --include=${LAMMPS_PYTHON_DIR}/lammps.py --omit=${LAMMPS_PYTHON_DIR}/install.py)
|
||||
else()
|
||||
set(PYTHON_TEST_RUNNER ${Python_EXECUTABLE} -u)
|
||||
endif()
|
||||
else()
|
||||
set(PYTHON_TEST_RUNNER ${Python_EXECUTABLE})
|
||||
endif()
|
||||
|
||||
add_test(NAME PythonOpen
|
||||
COMMAND ${Python_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/python-open.py -v
|
||||
COMMAND ${PYTHON_TEST_RUNNER} ${CMAKE_CURRENT_SOURCE_DIR}/python-open.py -v
|
||||
WORKING_DIRECTORY ${EXECUTABLE_OUTPUT_PATH})
|
||||
set_tests_properties(PythonOpen PROPERTIES ENVIRONMENT "${PYTHON_TEST_ENVIRONMENT}")
|
||||
|
||||
add_test(NAME PythonCommands
|
||||
COMMAND ${Python_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/python-commands.py -v
|
||||
COMMAND ${PYTHON_TEST_RUNNER} ${CMAKE_CURRENT_SOURCE_DIR}/python-commands.py -v
|
||||
WORKING_DIRECTORY ${EXECUTABLE_OUTPUT_PATH})
|
||||
set_tests_properties(PythonCommands PROPERTIES ENVIRONMENT "${PYTHON_TEST_ENVIRONMENT}")
|
||||
|
||||
add_test(NAME PythonNumpy
|
||||
COMMAND ${Python_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/python-numpy.py -v
|
||||
COMMAND ${PYTHON_TEST_RUNNER} ${CMAKE_CURRENT_SOURCE_DIR}/python-numpy.py -v
|
||||
WORKING_DIRECTORY ${EXECUTABLE_OUTPUT_PATH})
|
||||
set_tests_properties(PythonNumpy PROPERTIES ENVIRONMENT "${PYTHON_TEST_ENVIRONMENT}")
|
||||
|
||||
add_test(NAME PythonCapabilities
|
||||
COMMAND ${PYTHON_TEST_RUNNER} ${CMAKE_CURRENT_SOURCE_DIR}/python-capabilities.py -v
|
||||
WORKING_DIRECTORY ${EXECUTABLE_OUTPUT_PATH})
|
||||
set_tests_properties(PythonCapabilities PROPERTIES ENVIRONMENT "${PYTHON_TEST_ENVIRONMENT}")
|
||||
|
||||
add_test(NAME PythonPyLammps
|
||||
COMMAND ${PYTHON_TEST_RUNNER} ${CMAKE_CURRENT_SOURCE_DIR}/python-pylammps.py -v
|
||||
WORKING_DIRECTORY ${EXECUTABLE_OUTPUT_PATH})
|
||||
set_tests_properties(PythonPyLammps PROPERTIES ENVIRONMENT "${PYTHON_TEST_ENVIRONMENT}")
|
||||
else()
|
||||
message(STATUS "Skipping Tests for the LAMMPS Python Module: no suitable Python interpreter")
|
||||
endif()
|
||||
|
||||
62
unittest/python/python-capabilities.py
Normal file
62
unittest/python/python-capabilities.py
Normal file
@ -0,0 +1,62 @@
|
||||
import sys,os,unittest
|
||||
from lammps import lammps
|
||||
|
||||
class PythonCapabilities(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'])
|
||||
|
||||
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):
|
||||
del self.lmp
|
||||
|
||||
def test_version(self):
|
||||
self.assertGreaterEqual(self.lmp.version(), 20200824)
|
||||
|
||||
def test_has_gzip_support(self):
|
||||
self.assertEqual(self.lmp.has_gzip_support, self.cmake_cache['WITH_GZIP'])
|
||||
|
||||
def test_has_png_support(self):
|
||||
self.assertEqual(self.lmp.has_png_support, self.cmake_cache['WITH_PNG'])
|
||||
|
||||
def test_has_jpeg_support(self):
|
||||
self.assertEqual(self.lmp.has_jpeg_support, self.cmake_cache['WITH_JPEG'])
|
||||
|
||||
def test_has_ffmpeg_support(self):
|
||||
self.assertEqual(self.lmp.has_ffmpeg_support, self.cmake_cache['WITH_FFMPEG'])
|
||||
|
||||
def test_installed_packages(self):
|
||||
installed_packages = self.lmp.installed_packages
|
||||
selected_packages = [key[4:] for key in self.cmake_cache.keys() if not key.startswith('PKG_CONFIG') and key.startswith('PKG_') and self.cmake_cache[key]]
|
||||
|
||||
for pkg in selected_packages:
|
||||
self.assertIn(pkg, installed_packages)
|
||||
|
||||
def test_has_style(self):
|
||||
self.assertTrue(self.lmp.has_style('pair', 'lj/cut'))
|
||||
self.assertFalse(self.lmp.has_style('pair', 'lennard_jones'))
|
||||
|
||||
def test_available_styles(self):
|
||||
pairs = self.lmp.available_styles('pair')
|
||||
self.assertIn('lj/cut', pairs)
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@ -43,46 +43,46 @@ create_atoms 1 single &
|
||||
##############################
|
||||
def testFile(self):
|
||||
"""Test reading commands from a file"""
|
||||
natoms = int(self.lmp.get_natoms())
|
||||
natoms = self.lmp.get_natoms()
|
||||
self.assertEqual(natoms,0)
|
||||
self.lmp.file(self.demo_file)
|
||||
natoms = int(self.lmp.get_natoms())
|
||||
natoms = self.lmp.get_natoms()
|
||||
self.assertEqual(natoms,1)
|
||||
self.lmp.file(self.cont_file)
|
||||
natoms = int(self.lmp.get_natoms())
|
||||
natoms = self.lmp.get_natoms()
|
||||
self.assertEqual(natoms,2)
|
||||
|
||||
def testNoFile(self):
|
||||
"""Test (not) reading commands from no file"""
|
||||
self.lmp.file(None)
|
||||
natoms = int(self.lmp.get_natoms())
|
||||
natoms = self.lmp.get_natoms()
|
||||
self.assertEqual(natoms,0)
|
||||
|
||||
def testCommand(self):
|
||||
"""Test executing individual commands"""
|
||||
natoms = int(self.lmp.get_natoms())
|
||||
natoms = self.lmp.get_natoms()
|
||||
self.assertEqual(natoms,0)
|
||||
cmds = self.demo_input.splitlines()
|
||||
for cmd in cmds:
|
||||
self.lmp.command(cmd)
|
||||
natoms = int(self.lmp.get_natoms())
|
||||
natoms = self.lmp.get_natoms()
|
||||
self.assertEqual(natoms,1)
|
||||
|
||||
def testCommandsList(self):
|
||||
"""Test executing commands from list of strings"""
|
||||
natoms = int(self.lmp.get_natoms())
|
||||
natoms = self.lmp.get_natoms()
|
||||
self.assertEqual(natoms,0)
|
||||
cmds = self.demo_input.splitlines()+self.cont_input.splitlines()
|
||||
self.lmp.commands_list(cmds)
|
||||
natoms = int(self.lmp.get_natoms())
|
||||
natoms = self.lmp.get_natoms()
|
||||
self.assertEqual(natoms,2)
|
||||
|
||||
def testCommandsString(self):
|
||||
"""Test executing block of commands from string"""
|
||||
natoms = int(self.lmp.get_natoms())
|
||||
natoms = self.lmp.get_natoms()
|
||||
self.assertEqual(natoms,0)
|
||||
self.lmp.commands_string(self.demo_input+self.cont_input)
|
||||
natoms = int(self.lmp.get_natoms())
|
||||
natoms = self.lmp.get_natoms()
|
||||
self.assertEqual(natoms,2)
|
||||
|
||||
##############################
|
||||
|
||||
@ -1,7 +1,14 @@
|
||||
import sys,os,unittest
|
||||
from lammps import lammps, LMP_STYLE_GLOBAL, LMP_STYLE_LOCAL, LMP_STYLE_ATOM, LMP_TYPE_VECTOR, LMP_TYPE_SCALAR, LMP_TYPE_ARRAY
|
||||
from lammps import lammps, LAMMPS_INT, LMP_STYLE_GLOBAL, LMP_STYLE_LOCAL, LMP_STYLE_ATOM, LMP_TYPE_VECTOR, LMP_TYPE_SCALAR, LMP_TYPE_ARRAY
|
||||
from ctypes import c_void_p
|
||||
|
||||
try:
|
||||
import numpy
|
||||
NUMPY_INSTALLED = True
|
||||
except ImportError:
|
||||
NUMPY_INSTALLED = False
|
||||
|
||||
@unittest.skipIf(not NUMPY_INSTALLED, "numpy is not available")
|
||||
class PythonNumpy(unittest.TestCase):
|
||||
def setUp(self):
|
||||
machine = None
|
||||
@ -25,7 +32,7 @@ class PythonNumpy(unittest.TestCase):
|
||||
self.lmp.command("create_atoms 1 single 1.0 1.0 1.0")
|
||||
self.lmp.command("create_atoms 1 single 1.0 1.0 1.5")
|
||||
self.lmp.command("compute coordsum all reduce sum x y z")
|
||||
natoms = int(self.lmp.get_natoms())
|
||||
natoms = self.lmp.get_natoms()
|
||||
self.assertEqual(natoms,2)
|
||||
values = self.lmp.numpy.extract_compute("coordsum", LMP_STYLE_GLOBAL, LMP_TYPE_VECTOR)
|
||||
self.assertEqual(len(values), 3)
|
||||
@ -43,7 +50,7 @@ class PythonNumpy(unittest.TestCase):
|
||||
self.lmp.command("create_atoms 1 single 1.0 1.0 1.0")
|
||||
self.lmp.command("create_atoms 1 single 1.0 1.0 1.5")
|
||||
self.lmp.command("compute ke all ke/atom")
|
||||
natoms = int(self.lmp.get_natoms())
|
||||
natoms = self.lmp.get_natoms()
|
||||
self.assertEqual(natoms,2)
|
||||
values = self.lmp.numpy.extract_compute("ke", LMP_STYLE_ATOM, LMP_TYPE_VECTOR)
|
||||
self.assertEqual(len(values), 2)
|
||||
@ -66,5 +73,67 @@ class PythonNumpy(unittest.TestCase):
|
||||
# TODO
|
||||
pass
|
||||
|
||||
def testExtractAtomDeprecated(self):
|
||||
self.lmp.command("units lj")
|
||||
self.lmp.command("atom_style atomic")
|
||||
self.lmp.command("atom_modify map array")
|
||||
self.lmp.command("region box block 0 2 0 2 0 2")
|
||||
self.lmp.command("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)
|
||||
nlocal = self.lmp.extract_global("nlocal", LAMMPS_INT)
|
||||
self.assertEqual(nlocal, 2)
|
||||
|
||||
ident = self.lmp.numpy.extract_atom_iarray("id", nlocal, dim=1)
|
||||
self.assertEqual(len(ident), 2)
|
||||
|
||||
ntypes = self.lmp.extract_global("ntypes", LAMMPS_INT)
|
||||
self.assertEqual(ntypes, 1)
|
||||
|
||||
x = self.lmp.numpy.extract_atom_darray("x", nlocal, dim=3)
|
||||
v = self.lmp.numpy.extract_atom_darray("v", nlocal, dim=3)
|
||||
self.assertEqual(len(x), 2)
|
||||
self.assertTrue((x[0] == (1.0, 1.0, 1.0)).all())
|
||||
self.assertTrue((x[1] == (1.0, 1.0, 1.5)).all())
|
||||
self.assertEqual(len(v), 2)
|
||||
|
||||
def testExtractAtom(self):
|
||||
self.lmp.command("units lj")
|
||||
self.lmp.command("atom_style atomic")
|
||||
self.lmp.command("atom_modify map array")
|
||||
self.lmp.command("region box block 0 2 0 2 0 2")
|
||||
self.lmp.command("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)
|
||||
nlocal = self.lmp.extract_global("nlocal")
|
||||
self.assertEqual(nlocal, 2)
|
||||
|
||||
ident = self.lmp.numpy.extract_atom("id")
|
||||
self.assertEqual(len(ident), 2)
|
||||
|
||||
ntypes = self.lmp.extract_global("ntypes")
|
||||
self.assertEqual(ntypes, 1)
|
||||
|
||||
x = self.lmp.numpy.extract_atom("x")
|
||||
v = self.lmp.numpy.extract_atom("v")
|
||||
self.assertEqual(len(x), 2)
|
||||
self.assertTrue((x[0] == (1.0, 1.0, 1.0)).all())
|
||||
self.assertTrue((x[1] == (1.0, 1.0, 1.5)).all())
|
||||
self.assertEqual(len(v), 2)
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
88
unittest/python/python-pylammps.py
Normal file
88
unittest/python/python-pylammps.py
Normal file
@ -0,0 +1,88 @@
|
||||
import sys,os,unittest
|
||||
from lammps import PyLammps
|
||||
|
||||
class PythonPyLammps(unittest.TestCase):
|
||||
def setUp(self):
|
||||
machine = None
|
||||
if 'LAMMPS_MACHINE_NAME' in os.environ:
|
||||
machine=os.environ['LAMMPS_MACHINE_NAME']
|
||||
self.pylmp = PyLammps(name=machine, cmdargs=['-nocite', '-log','none', '-echo', 'screen'])
|
||||
self.pylmp.units("lj")
|
||||
self.pylmp.atom_style("atomic")
|
||||
self.pylmp.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.pylmp.close()
|
||||
del self.pylmp
|
||||
|
||||
def test_version(self):
|
||||
self.assertGreaterEqual(self.pylmp.version(), 20200824)
|
||||
|
||||
def test_create_atoms(self):
|
||||
self.pylmp.region("box block", 0, 2, 0, 2, 0, 2)
|
||||
self.pylmp.create_box(1, "box")
|
||||
|
||||
x = [
|
||||
1.0, 1.0, 1.0,
|
||||
1.0, 1.0, 1.5
|
||||
]
|
||||
|
||||
types = [1, 1]
|
||||
|
||||
self.assertEqual(self.pylmp.lmp.create_atoms(2, id=None, type=types, x=x), 2)
|
||||
self.assertEqual(self.pylmp.system.natoms, 2)
|
||||
self.assertEqual(len(self.pylmp.atoms), 2)
|
||||
self.assertEqual(self.pylmp.atoms[0].position, tuple(x[0:3]))
|
||||
self.assertEqual(self.pylmp.atoms[1].position, tuple(x[3:6]))
|
||||
self.assertEqual(self.pylmp.last_run, None)
|
||||
|
||||
|
||||
def test_write_script(self):
|
||||
outfile = 'in.test_write_script'
|
||||
self.pylmp.write_script(outfile)
|
||||
self.assertTrue(os.path.exists(outfile))
|
||||
os.remove(outfile)
|
||||
|
||||
def test_runs(self):
|
||||
self.pylmp.lattice("fcc", 0.8442),
|
||||
self.pylmp.region("box block", 0, 4, 0, 4, 0, 4)
|
||||
self.pylmp.create_box(1, "box")
|
||||
self.pylmp.create_atoms(1, "box")
|
||||
self.pylmp.mass(1, 1.0)
|
||||
self.pylmp.velocity("all create", 1.44, 87287, "loop geom")
|
||||
self.pylmp.pair_style("lj/cut", 2.5)
|
||||
self.pylmp.pair_coeff(1, 1, 1.0, 1.0, 2.5)
|
||||
self.pylmp.neighbor(0.3, "bin")
|
||||
self.pylmp.neigh_modify("delay 0 every 20 check no")
|
||||
self.pylmp.fix("1 all nve")
|
||||
self.pylmp.variable("fx atom fx")
|
||||
self.pylmp.run(10)
|
||||
|
||||
self.assertEqual(len(self.pylmp.runs), 1)
|
||||
self.assertEqual(self.pylmp.last_run, self.pylmp.runs[0])
|
||||
self.assertEqual(len(self.pylmp.last_run.thermo.Step), 2)
|
||||
self.assertEqual(len(self.pylmp.last_run.thermo.Temp), 2)
|
||||
self.assertEqual(len(self.pylmp.last_run.thermo.E_pair), 2)
|
||||
self.assertEqual(len(self.pylmp.last_run.thermo.E_mol), 2)
|
||||
self.assertEqual(len(self.pylmp.last_run.thermo.TotEng), 2)
|
||||
self.assertEqual(len(self.pylmp.last_run.thermo.Press), 2)
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user