Merge branch 'develop' into add-error-explanations

This commit is contained in:
Axel Kohlmeyer
2025-01-13 01:27:34 -05:00
79 changed files with 3242 additions and 2613 deletions

View File

@ -3,6 +3,9 @@
# CMake build system
# This file is part of LAMMPS
cmake_minimum_required(VERSION 3.16)
if(CMAKE_VERSION VERSION_LESS 3.20)
message(WARNING "LAMMPS is planning to require at least CMake version 3.20 by Summer 2025. Please upgrade!")
endif()
########################################
# set policy to silence warnings about ignoring <PackageName>_ROOT but use it
if(POLICY CMP0074)
@ -144,16 +147,28 @@ if((PKG_KOKKOS) AND (Kokkos_ENABLE_CUDA) AND NOT (CMAKE_CXX_COMPILER_ID STREQUAL
set(CMAKE_TUNE_DEFAULT "${CMAKE_TUNE_DEFAULT}" "-Xcudafe --diag_suppress=unrecognized_pragma,--diag_suppress=128")
endif()
# we require C++11 without extensions. Kokkos requires at least C++17 (currently)
# we *require* C++11 without extensions but prefer C++17.
# Kokkos requires at least C++17 (currently)
if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 11)
if(cxx_std_17 IN_LIST CMAKE_CXX_COMPILE_FEATURES)
set(CMAKE_CXX_STANDARD 17)
else()
set(CMAKE_CXX_STANDARD 11)
endif()
endif()
if(CMAKE_CXX_STANDARD LESS 11)
message(FATAL_ERROR "C++ standard must be set to at least 11")
endif()
if(CMAKE_CXX_STANDARD LESS 17)
message(WARNING "Selecting C++17 standard is preferred over C++${CMAKE_CXX_STANDARD}")
endif()
if(PKG_KOKKOS AND (CMAKE_CXX_STANDARD LESS 17))
set(CMAKE_CXX_STANDARD 17)
endif()
# turn off C++17 check in lmptype.h
if(LAMMPS_CXX11)
add_compile_definitions(LAMMPS_CXX11)
endif()
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF CACHE BOOL "Use compiler extensions")
# ugly hacks for MSVC which by default always reports an old C++ standard in the __cplusplus macro
@ -347,6 +362,17 @@ foreach(PKG ${STANDARD_PACKAGES} ${SUFFIX_PACKAGES})
option(PKG_${PKG} "Build ${PKG} Package" OFF)
endforeach()
set(DEPRECATED_PACKAGES AWPMD ATC POEMS)
foreach(PKG ${DEPRECATED_PACKAGES})
if(PKG_${PKG})
message(WARNING
"The ${PKG} package will be removed from LAMMPS in Summer 2025 due to lack of "
"maintenance and use of code constructs that conflict with modern C++ compilers "
"and standards. Please contact developers@lammps.org if you have any concerns "
"about this step.")
endif()
endforeach()
######################################################
# packages with special compiler needs or external libs
######################################################

View File

@ -1,50 +1,62 @@
# PACE library support for ML-PACE package
find_package(pace QUIET)
# set policy to silence warnings about timestamps of downloaded files. review occasionally if it may be set to NEW
if(POLICY CMP0135)
cmake_policy(SET CMP0135 OLD)
endif()
set(PACELIB_URL "https://github.com/ICAMS/lammps-user-pace/archive/refs/tags/v.2023.11.25.fix.tar.gz" CACHE STRING "URL for PACE evaluator library sources")
set(PACELIB_MD5 "b45de9a633f42ed65422567e3ce56f9f" CACHE STRING "MD5 checksum of PACE evaluator library tarball")
mark_as_advanced(PACELIB_URL)
mark_as_advanced(PACELIB_MD5)
GetFallbackURL(PACELIB_URL PACELIB_FALLBACK)
# LOCAL_ML-PACE points to top-level dir with local lammps-user-pace repo,
# to make it easier to check local build without going through the public github releases
if(LOCAL_ML-PACE)
set(lib-pace "${LOCAL_ML-PACE}")
if(pace_FOUND)
find_package(pace)
target_link_libraries(lammps PRIVATE pace::pace)
else()
# download library sources to build folder
if(EXISTS ${CMAKE_BINARY_DIR}/libpace.tar.gz)
file(MD5 ${CMAKE_BINARY_DIR}/libpace.tar.gz DL_MD5)
endif()
if(NOT "${DL_MD5}" STREQUAL "${PACELIB_MD5}")
message(STATUS "Downloading ${PACELIB_URL}")
file(DOWNLOAD ${PACELIB_URL} ${CMAKE_BINARY_DIR}/libpace.tar.gz STATUS DL_STATUS SHOW_PROGRESS)
file(MD5 ${CMAKE_BINARY_DIR}/libpace.tar.gz DL_MD5)
if((NOT DL_STATUS EQUAL 0) OR (NOT "${DL_MD5}" STREQUAL "${PACELIB_MD5}"))
message(WARNING "Download from primary URL ${PACELIB_URL} failed\nTrying fallback URL ${PACELIB_FALLBACK}")
file(DOWNLOAD ${PACELIB_FALLBACK} ${CMAKE_BINARY_DIR}/libpace.tar.gz EXPECTED_HASH MD5=${PACELIB_MD5} SHOW_PROGRESS)
# set policy to silence warnings about timestamps of downloaded files. review occasionally if it may be set to NEW
if(POLICY CMP0135)
cmake_policy(SET CMP0135 OLD)
endif()
else()
message(STATUS "Using already downloaded archive ${CMAKE_BINARY_DIR}/libpace.tar.gz")
endif()
set(PACELIB_URL "https://github.com/ICAMS/lammps-user-pace/archive/refs/tags/v.2023.11.25.fix2.tar.gz" CACHE STRING "URL for PACE evaluator library sources")
set(PACELIB_MD5 "a53bd87cfee8b07d9f44bc17aad69c3f" CACHE STRING "MD5 checksum of PACE evaluator library tarball")
mark_as_advanced(PACELIB_URL)
mark_as_advanced(PACELIB_MD5)
GetFallbackURL(PACELIB_URL PACELIB_FALLBACK)
# LOCAL_ML-PACE points to top-level dir with local lammps-user-pace repo,
# to make it easier to check local build without going through the public github releases
if(LOCAL_ML-PACE)
set(lib-pace "${LOCAL_ML-PACE}")
else()
# download library sources to build folder
if(EXISTS ${CMAKE_BINARY_DIR}/libpace.tar.gz)
file(MD5 ${CMAKE_BINARY_DIR}/libpace.tar.gz DL_MD5)
endif()
if(NOT "${DL_MD5}" STREQUAL "${PACELIB_MD5}")
message(STATUS "Downloading ${PACELIB_URL}")
file(DOWNLOAD ${PACELIB_URL} ${CMAKE_BINARY_DIR}/libpace.tar.gz STATUS DL_STATUS SHOW_PROGRESS)
file(MD5 ${CMAKE_BINARY_DIR}/libpace.tar.gz DL_MD5)
if((NOT DL_STATUS EQUAL 0) OR (NOT "${DL_MD5}" STREQUAL "${PACELIB_MD5}"))
message(WARNING "Download from primary URL ${PACELIB_URL} failed\nTrying fallback URL ${PACELIB_FALLBACK}")
file(DOWNLOAD ${PACELIB_FALLBACK} ${CMAKE_BINARY_DIR}/libpace.tar.gz EXPECTED_HASH MD5=${PACELIB_MD5} SHOW_PROGRESS)
endif()
else()
message(STATUS "Using already downloaded archive ${CMAKE_BINARY_DIR}/libpace.tar.gz")
endif()
# uncompress downloaded sources
execute_process(
COMMAND ${CMAKE_COMMAND} -E remove_directory lammps-user-pace*
COMMAND ${CMAKE_COMMAND} -E tar xzf libpace.tar.gz
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
get_newest_file(${CMAKE_BINARY_DIR}/lammps-user-pace-* lib-pace)
endif()
add_subdirectory(${lib-pace} build-pace)
set_target_properties(pace PROPERTIES CXX_EXTENSIONS ON OUTPUT_NAME lammps_pace${LAMMPS_MACHINE})
if(CMAKE_PROJECT_NAME STREQUAL "lammps")
target_link_libraries(lammps PRIVATE pace)
# uncompress downloaded sources
execute_process(
COMMAND ${CMAKE_COMMAND} -E remove_directory lammps-user-pace*
COMMAND ${CMAKE_COMMAND} -E tar xzf libpace.tar.gz
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
get_newest_file(${CMAKE_BINARY_DIR}/lammps-user-pace-* lib-pace)
endif()
# some preinstalled yaml-cpp versions don't provide a namespaced target
find_package(yaml-cpp QUIET)
if(TARGET yaml-cpp AND NOT TARGET yaml-cpp::yaml-cpp)
add_library(yaml-cpp::yaml-cpp ALIAS yaml-cpp)
endif()
add_subdirectory(${lib-pace} build-pace)
set_target_properties(pace PROPERTIES CXX_EXTENSIONS ON OUTPUT_NAME lammps_pace${LAMMPS_MACHINE})
if(CMAKE_PROJECT_NAME STREQUAL "lammps")
target_link_libraries(lammps PRIVATE pace)
endif()
endif()

View File

@ -1,10 +1,14 @@
Build LAMMPS
============
LAMMPS is built as a library and an executable from source code using
either traditional makefiles for use with GNU make (which may require
manual editing), or using a build environment generated by CMake (Unix
Makefiles, Ninja, Xcode, Visual Studio, KDevelop, CodeBlocks and more).
LAMMPS is built as a library and an executable from source code using a
build environment generated by CMake (Unix Makefiles, Ninja, Xcode,
Visual Studio, KDevelop, CodeBlocks and more depending on the platform).
Using CMake is the preferred way to build LAMMPS. In addition, LAMMPS
can be compiled using the legacy build system based on traditional
makefiles for use with GNU make (which may require manual editing).
Support for the legacy build system is slowly being phased out and may
not be available for all optional features.
As an alternative, you can download a package with pre-built executables
or automated build trees, as described in the :doc:`Install <Install>`

View File

@ -16,7 +16,7 @@ environments is on a :doc:`separate page <Howto_cmake>`.
.. note::
LAMMPS currently requires that CMake version 3.16 or later is available.
LAMMPS currently requires that CMake version 3.20 or later is available.
.. warning::
@ -32,11 +32,11 @@ environments is on a :doc:`separate page <Howto_cmake>`.
Advantages of using CMake
^^^^^^^^^^^^^^^^^^^^^^^^^
CMake is an alternative to compiling LAMMPS in the traditional way
through :doc:`(manually customized) makefiles <Build_make>`. Using
CMake has multiple advantages that are specifically helpful for
people with limited experience in compiling software or for people
that want to modify or extend LAMMPS.
CMake is the preferred way of compiling LAMMPS in contrast to the legacy
build system based on GNU make and through :doc:`(manually customized)
makefiles <Build_make>`. Using CMake has multiple advantages that are
specifically helpful for people with limited experience in compiling
software or for people that want to modify or extend LAMMPS.
- CMake can detect available hardware, tools, features, and libraries
and adapt the LAMMPS default build configuration accordingly.
@ -47,7 +47,7 @@ that want to modify or extend LAMMPS.
knowledge of file formats or complex command-line syntax is required.
- All enabled components are compiled in a single build operation.
- Automated dependency tracking for all files and configuration options.
- Support for true out-of-source compilation. Multiple configurations
- Support for true out-of-source compilation. Multiple configurations
and settings with different choices of LAMMPS packages, settings, or
compilers can be configured and built concurrently from the same
source tree.

View File

@ -8,6 +8,10 @@ Building LAMMPS with traditional makefiles requires that you have a
for customizing your LAMMPS build with a number of global compilation
options and features.
This build system is slowly being phased out and may not support all
optional features and packages in LAMMPS. It is recommended to switch
to the :doc:`CMake based build system <Build_cmake>`.
Requirements
^^^^^^^^^^^^

View File

@ -90,6 +90,7 @@ OPT.
* :doc:`lepton (o) <angle_lepton>`
* :doc:`mesocnt <angle_mesocnt>`
* :doc:`mm3 <angle_mm3>`
* :doc:`mwlc <angle_mwlc>`
* :doc:`quartic (o) <angle_quartic>`
* :doc:`spica (ko) <angle_spica>`
* :doc:`table (o) <angle_table>`

View File

@ -227,12 +227,12 @@ Tests for the C-style library interface
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Tests for validating the LAMMPS C-style library interface are in the
``unittest/c-library`` folder. They are implemented either to be used
for utility functions or for LAMMPS commands, but use the functions
implemented in the ``src/library.cpp`` file as much as possible. There
may be some overlap with other tests, but only in as much as is required
to test the C-style library API. The tests are distributed over
multiple test programs which try to match the grouping of the
``unittest/c-library`` folder. They text either utility functions or
LAMMPS commands, but use the functions implemented in
``src/library.cpp`` as much as possible. There may be some overlap with
other tests as far as the LAMMPS functionality is concerned, but the
focus is on testing the C-style library API. The tests are distributed
over multiple test programs which try to match the grouping of the
functions in the source code and :ref:`in the manual <lammps_c_api>`.
This group of tests also includes tests invoking LAMMPS in parallel
@ -258,7 +258,7 @@ Tests for the Python module and package
The ``unittest/python`` folder contains primarily tests for classes and
functions in the LAMMPS python module but also for commands in the
PYTHON package. These tests are only enabled if the necessary
PYTHON package. These tests are only enabled, if the necessary
prerequisites are detected or enabled during configuration and
compilation of LAMMPS (shared library build enabled, Python interpreter
found, Python development files found).
@ -272,29 +272,30 @@ Tests for the Fortran interface
Tests for using the Fortran module are in the ``unittest/fortran``
folder. Since they are also using the GoogleTest library, they require
implementing test wrappers in C++ that will call fortran functions
which provide a C function interface through ISO_C_BINDINGS that will in
turn call the functions in the LAMMPS Fortran module.
test wrappers written in C++ that will call fortran functions with a C
function interface through ISO_C_BINDINGS which will in turn call the
functions in the LAMMPS Fortran module.
Tests for the C++-style library interface
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The tests in the ``unittest/cplusplus`` folder are somewhat similar to
the tests for the C-style library interface, but do not need to test the
several convenience and utility functions that are only available through
the C-style interface. Instead it can focus on the more generic features
that are used internally. This part of the unit tests is currently still
mostly in the planning stage.
convenience and utility functions that are only available through the
C-style library interface. Instead they focus on the more generic
features that are used in LAMMPS internally. This part of the unit
tests is currently still mostly in the planning stage.
Tests for reading and writing file formats
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The ``unittest/formats`` folder contains test programs for reading and
writing files like data files, restart files, potential files or dump files.
This covers simple things like the file i/o convenience functions in the
``utils::`` namespace to complex tests of atom styles where creating and
deleting atoms with different properties is tested in different ways
and through script commands or reading and writing of data or restart files.
writing files like data files, restart files, potential files or dump
files. This covers simple things like the file i/o convenience
functions in the ``utils::`` namespace to complex tests of atom styles
where creating and deleting of atoms with different properties is tested
in different ways and through script commands or reading and writing of
data or restart files.
Tests for styles computing or modifying forces
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -443,7 +444,7 @@ file for a style that is similar to one to be tested. The file name should
follow the naming conventions described above and after copying the file,
the first step is to replace the style names where needed. The coefficient
values do not have to be meaningful, just in a reasonable range for the
given system. It does not matter if some forces are large, as long as
given system. It does not matter if some forces are large, for as long as
they do not diverge.
The template input files define a large number of index variables at the top
@ -531,19 +532,20 @@ Python module.
Troubleshooting failed unit tests
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The are by default no unit tests for newly added features (e.g. pair, fix,
or compute styles) unless your pull request also includes tests for the
added features. If you are modifying some features, you may see failures
for existing tests, if your modifications have some unexpected side effects
or your changes render the existing test invalid. If you are adding an
accelerated version of an existing style, then only tests for INTEL,
KOKKOS (with OpenMP only), OPENMP, and OPT will be run automatically.
Tests for the GPU package are time consuming and thus are only run
*after* a merge, or when a special label, ``gpu_unit_tests`` is added
to the pull request. After the test has started, it is often best to
remove the label since every PR activity will re-trigger the test (that
is a limitation of triggering a test with a label). Support for unit
tests when using KOKKOS with GPU acceleration is currently not supported.
There are by default no unit tests for newly added features (e.g. pair,
fix, or compute styles) unless your pull request also includes tests for
these added features. If you are modifying some existing LAMMPS
features, you may see failures for existing tests, if your modifications
have some unexpected side effects or your changes render the existing
test invalid. If you are adding an accelerated version of an existing
style, then only tests for INTEL, KOKKOS (with OpenMP only), OPENMP, and
OPT will be run automatically. Tests for the GPU package are time
consuming and thus are only run *after* a merge, or when a special
label, ``gpu_unit_tests`` is added to the pull request. After the test
has started, it is often best to remove the label since every PR
activity will re-trigger the test (that is a limitation of triggering a
test with a label). Support for unit tests using KOKKOS with GPU
acceleration is currently not supported.
When you see a failed build on GitHub, click on ``Details`` to be taken
to the corresponding LAMMPS Jenkins CI web page. Click on the "Exit"
@ -588,7 +590,7 @@ While the epsilon (relative precision) for a single, `IEEE 754 compliant
<https://en.wikipedia.org/wiki/IEEE_754>`_, double precision floating
point operation is at about 2.2e-16, the achievable precision for the
tests is lower due to most numbers being sums over intermediate results
and the non-associativity of floating point math leading to larger
for which the non-associativity of floating point math leads to larger
errors. As a rule of thumb, the test epsilon can often be in the range
5.0e-14 to 1.0e-13. But for "noisy" force kernels, e.g. those a larger
amount of arithmetic operations involving `exp()`, `log()` or `sin()`
@ -602,7 +604,7 @@ of floating point operations or that some or most intermediate operations
may be done using approximations or with single precision floating point
math.
To rerun the failed unit test individually, change to the ``build`` directory
To rerun a failed unit test individually, change to the ``build`` directory
and run the test with verbose output. For example,
.. code-block:: bash

View File

@ -235,3 +235,53 @@ from GDB. In addition you get a more specific hint about what cause the
segmentation fault, i.e. that it is a NULL pointer dereference. To find
out which pointer exactly was NULL, you need to use the debugger, though.
Debugging when LAMMPS appears to be stuck
=========================================
Sometimes the LAMMPS calculation appears to be stuck, that is the LAMMPS
process or processes are active, but there is no visible progress. This
can have multiple reasons:
- The selected styles are slow and require a lot of CPU time and the
system is large. When extrapolating the expected speed from smaller
systems, one has to factor in that not all models scale linearly with
system size, e.g. :doc:`kspace styles like ewald or pppm
<kspace_style>`. There is very little that can be done in this case.
- The output interval is not set or set to a large value with the
:doc:`thermo <thermo>` command. I the first case, there will be output
only at the first and last step.
- The output is block-buffered and instead of line-buffered. The output
will only be written to the screen after 4096 or 8192 characters of
output have accumulated. This most often happens for files but also
with MPI parallel executables for output to the screen, since the
output to the screen is handled by the MPI library so that output from
all processes can be shown. This can be suppressed by using the
``-nonblock`` or ``-nb`` command-line flag, which turns off buffering
for screen and logfile output.
- An MPI parallel calculation has a bug where a collective MPI function
is called (e.g. ``MPI_Barrier()``, ``MPI_Bcast()``,
``MPI_Allreduce()`` and so on) before pending point-to-point
communications are completed or when the collective function is only
called from a subset of the MPI processes. This also applies to some
internal LAMMPS functions like ``Error::all()`` which uses
``MPI_Barrier()`` and thus ``Error::one()`` must be called, if the
error condition does not happen on all MPI processes simultaneously.
- Some function in LAMMPS has a bug where a ``for`` or ``while`` loop
does not trigger the exit condition and thus will loop forever. This
can happen when the wrong variable is incremented or when one value in
a comparison becomes ``NaN`` due to an overflow.
In the latter two cases, further information and stack traces (see above)
can be obtain by attaching a debugger to a running process. For that the
process ID (PID) is needed; this can be found on Linux machines with the
``top``, ``htop``, ``ps``, or ``pstree`` commands.
Then running the (GNU) debugger ``gdb`` with the ``-p`` flag followed by
the process id will attach the process to the debugger and stop
execution of that specific process. From there on it is possible to
issue all debugger commands in the same way as when LAMMPS was started
from the debugger (see above). Most importantly it is possible to
obtain a stack trace with the ``where`` command and thus determine where
in the execution of a timestep this process is. Also internal data can
be printed and execution single stepped or continued. When the debugger
is exited, the calculation will resume normally.

View File

@ -103,6 +103,7 @@ Tutorials howto
Howto_github
Howto_lammps_gui
Howto_moltemplate
Howto_python
Howto_pylammps
Howto_wsl

View File

@ -1,564 +1,6 @@
PyLammps Tutorial
=================
.. contents::
Overview
--------
:py:class:`PyLammps <lammps.PyLammps>` is a Python wrapper class for
LAMMPS which can be created on its own or use an existing
:py:class:`lammps Python <lammps.lammps>` object. It creates a simpler,
more "pythonic" interface to common LAMMPS functionality, in contrast to
the :py:class:`lammps <lammps.lammps>` wrapper for the LAMMPS :ref:`C
language library interface API <lammps_c_api>` which is written using
`Python ctypes <ctypes_>`_. The :py:class:`lammps <lammps.lammps>`
wrapper is discussed on the :doc:`Python_head` doc page.
Unlike the flat `ctypes <ctypes_>`_ interface, PyLammps exposes a
discoverable API. It no longer requires knowledge of the underlying C++
code implementation. Finally, the :py:class:`IPyLammps
<lammps.IPyLammps>` wrapper builds on top of :py:class:`PyLammps
<lammps.PyLammps>` and adds some additional features for `IPython
integration <ipython_>`_ into `Jupyter notebooks <jupyter_>`_, e.g. for
embedded visualization output from :doc:`dump style image <dump_image>`.
.. _ctypes: https://docs.python.org/3/library/ctypes.html
.. _ipython: https://ipython.org/
.. _jupyter: https://jupyter.org/
Comparison of lammps and PyLammps interfaces
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
lammps.lammps
"""""""""""""
* uses `ctypes <ctypes_>`_
* direct memory access to native C++ data with optional support for NumPy arrays
* provides functions to send and receive data to LAMMPS
* interface modeled after the LAMMPS :ref:`C language library interface API <lammps_c_api>`
* requires knowledge of how LAMMPS internally works (C pointers, etc)
* full support for running Python with MPI using `mpi4py <https://mpi4py.readthedocs.io>`_
* no overhead from creating a more Python-like interface
lammps.PyLammps
"""""""""""""""
* higher-level abstraction built on *top* of the original :py:class:`ctypes based interface <lammps.lammps>`
* manipulation of Python objects
* communication with LAMMPS is hidden from API user
* shorter, more concise Python
* better IPython integration, designed for quick prototyping
* designed for serial execution
* additional overhead from capturing and parsing the LAMMPS screen output
Quick Start
-----------
System-wide Installation
^^^^^^^^^^^^^^^^^^^^^^^^
Step 1: Building LAMMPS as a shared library
"""""""""""""""""""""""""""""""""""""""""""
To use LAMMPS inside of Python it has to be compiled as shared
library. This library is then loaded by the Python interface. In this
example we enable the MOLECULE package and compile LAMMPS with PNG, JPEG
and FFMPEG output support enabled.
Step 1a: For the CMake based build system, the steps are:
.. code-block:: bash
mkdir $LAMMPS_DIR/build-shared
cd $LAMMPS_DIR/build-shared
# MPI, PNG, Jpeg, FFMPEG are auto-detected
cmake ../cmake -DPKG_MOLECULE=yes -DBUILD_LIB=yes -DBUILD_SHARED_LIBS=yes
make
Step 1b: For the legacy, make based build system, the steps are:
.. code-block:: bash
cd $LAMMPS_DIR/src
# add packages if necessary
make yes-MOLECULE
# compile shared library using Makefile
make mpi mode=shlib LMP_INC="-DLAMMPS_PNG -DLAMMPS_JPEG -DLAMMPS_FFMPEG" JPG_LIB="-lpng -ljpeg"
Step 2: Installing the LAMMPS Python package
""""""""""""""""""""""""""""""""""""""""""""
PyLammps is part of the lammps Python package. To install it simply install
that package into your current Python installation with:
.. code-block:: bash
make install-python
.. note::
Recompiling the shared library requires re-installing the Python package
Installation inside of a virtualenv
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
You can use virtualenv to create a custom Python environment specifically tuned
for your workflow.
Benefits of using a virtualenv
""""""""""""""""""""""""""""""
* isolation of your system Python installation from your development installation
* installation can happen in your user directory without root access (useful for HPC clusters)
* installing packages through pip allows you to get newer versions of packages than e.g., through apt-get or yum package managers (and without root access)
* you can even install specific old versions of a package if necessary
**Prerequisite (e.g. on Ubuntu)**
.. code-block:: bash
apt-get install python-virtualenv
Creating a virtualenv with lammps installed
"""""""""""""""""""""""""""""""""""""""""""
.. code-block:: bash
# create virtualenv named 'testing'
virtualenv $HOME/python/testing
# activate 'testing' environment
source $HOME/python/testing/bin/activate
Now configure and compile the LAMMPS shared library as outlined above.
When using CMake and the shared library has already been build, you
need to re-run CMake to update the location of the python executable
to the location in the virtual environment with:
.. code-block:: bash
cmake . -DPython_EXECUTABLE=$(which python)
# install LAMMPS package in virtualenv
(testing) make install-python
# install other useful packages
(testing) pip install matplotlib jupyter mpi4py
...
# return to original shell
(testing) deactivate
Creating a new instance of PyLammps
-----------------------------------
To create a PyLammps object you need to first import the class from the lammps
module. By using the default constructor, a new *lammps* instance is created.
.. code-block:: python
from lammps import PyLammps
L = PyLammps()
You can also initialize PyLammps on top of this existing *lammps* object:
.. code-block:: python
from lammps import lammps, PyLammps
lmp = lammps()
L = PyLammps(ptr=lmp)
Commands
--------
Sending a LAMMPS command with the existing library interfaces is done using
the command method of the lammps object instance.
For instance, let's take the following LAMMPS command:
.. code-block:: LAMMPS
region box block 0 10 0 5 -0.5 0.5
In the original interface this command can be executed with the following
Python code if *L* was a lammps instance:
.. code-block:: python
L.command("region box block 0 10 0 5 -0.5 0.5")
With the PyLammps interface, any command can be split up into arbitrary parts
separated by white-space, passed as individual arguments to a region method.
.. code-block:: python
L.region("box block", 0, 10, 0, 5, -0.5, 0.5)
Note that each parameter is set as Python literal floating-point number. In the
PyLammps interface, each command takes an arbitrary parameter list and transparently
merges it to a single command string, separating individual parameters by white-space.
The benefit of this approach is avoiding redundant command calls and easier
parameterization. In the original interface parameterization needed to be done
manually by creating formatted strings.
.. code-block:: python
L.command("region box block %f %f %f %f %f %f" % (xlo, xhi, ylo, yhi, zlo, zhi))
In contrast, methods of PyLammps accept parameters directly and will convert
them automatically to a final command string.
.. code-block:: python
L.region("box block", xlo, xhi, ylo, yhi, zlo, zhi)
System state
------------
In addition to dispatching commands directly through the PyLammps object, it
also provides several properties which allow you to query the system state.
L.system
Is a dictionary describing the system such as the bounding box or number of atoms
L.system.xlo, L.system.xhi
bounding box limits along x-axis
L.system.ylo, L.system.yhi
bounding box limits along y-axis
L.system.zlo, L.system.zhi
bounding box limits along z-axis
L.communication
configuration of communication subsystem, such as the number of threads or processors
L.communication.nthreads
number of threads used by each LAMMPS process
L.communication.nprocs
number of MPI processes used by LAMMPS
L.fixes
List of fixes in the current system
L.computes
List of active computes in the current system
L.dump
List of active dumps in the current system
L.groups
List of groups present in the current system
Working with LAMMPS variables
-----------------------------
LAMMPS variables can be both defined and accessed via the PyLammps interface.
To define a variable you can use the :doc:`variable <variable>` command:
.. code-block:: python
L.variable("a index 2")
A dictionary of all variables is returned by L.variables
you can access an individual variable by retrieving a variable object from the
L.variables dictionary by name
.. code-block:: python
a = L.variables['a']
The variable value can then be easily read and written by accessing the value
property of this object.
.. code-block:: python
print(a.value)
a.value = 4
Retrieving the value of an arbitrary LAMMPS expressions
-------------------------------------------------------
LAMMPS expressions can be immediately evaluated by using the eval method. The
passed string parameter can be any expression containing global thermo values,
variables, compute or fix data.
.. code-block:: python
result = L.eval("ke") # kinetic energy
result = L.eval("pe") # potential energy
result = L.eval("v_t/2.0")
Accessing atom data
-------------------
All atoms in the current simulation can be accessed by using the L.atoms list.
Each element of this list is an object which exposes its properties (id, type,
position, velocity, force, etc.).
.. code-block:: python
# access first atom
L.atoms[0].id
L.atoms[0].type
# access second atom
L.atoms[1].position
L.atoms[1].velocity
L.atoms[1].force
Some properties can also be used to set:
.. code-block:: python
# set position in 2D simulation
L.atoms[0].position = (1.0, 0.0)
# set position in 3D simulation
L.atoms[0].position = (1.0, 0.0, 1.)
Evaluating thermo data
----------------------
Each simulation run usually produces thermo output based on system state,
computes, fixes or variables. The trajectories of these values can be queried
after a run via the L.runs list. This list contains a growing list of run data.
The first element is the output of the first run, the second element that of
the second run.
.. code-block:: python
L.run(1000)
L.runs[0] # data of first 1000 time steps
L.run(1000)
L.runs[1] # data of second 1000 time steps
Each run contains a dictionary of all trajectories. Each trajectory is
accessible through its thermo name:
.. code-block:: python
L.runs[0].thermo.Step # list of time steps in first run
L.runs[0].thermo.Ke # list of kinetic energy values in first run
Together with matplotlib plotting data out of LAMMPS becomes simple:
.. code-block:: python
import matplotlib.plot as plt
steps = L.runs[0].thermo.Step
ke = L.runs[0].thermo.Ke
plt.plot(steps, ke)
Error handling with PyLammps
----------------------------
Using C++ exceptions in LAMMPS for errors allows capturing them on the
C++ side and rethrowing them on the Python side. This way you can handle
LAMMPS errors through the Python exception handling mechanism.
.. warning::
Capturing a LAMMPS exception in Python can still mean that the
current LAMMPS process is in an illegal state and must be
terminated. It is advised to save your data and terminate the Python
instance as quickly as possible.
Using PyLammps in IPython notebooks and Jupyter
-----------------------------------------------
If the LAMMPS Python package is installed for the same Python interpreter as
IPython, you can use PyLammps directly inside of an IPython notebook inside of
Jupyter. Jupyter is a powerful integrated development environment (IDE) for
many dynamic languages like Python, Julia and others, which operates inside of
any web browser. Besides auto-completion and syntax highlighting it allows you
to create formatted documents using Markup, mathematical formulas, graphics and
animations intermixed with executable Python code. It is a great format for
tutorials and showcasing your latest research.
To launch an instance of Jupyter simply run the following command inside your
Python environment (this assumes you followed the Quick Start instructions):
.. code-block:: bash
jupyter notebook
IPyLammps Examples
------------------
Examples of IPython notebooks can be found in the python/examples/pylammps
subdirectory. To open these notebooks launch *jupyter notebook* inside this
directory and navigate to one of them. If you compiled and installed
a LAMMPS shared library with exceptions, PNG, JPEG and FFMPEG support
you should be able to rerun all of these notebooks.
Validating a dihedral potential
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This example showcases how an IPython Notebook can be used to compare a simple
LAMMPS simulation of a harmonic dihedral potential to its analytical solution.
Four atoms are placed in the simulation and the dihedral potential is applied on
them using a datafile. Then one of the atoms is rotated along the central axis by
setting its position from Python, which changes the dihedral angle.
.. code-block:: python
phi = [d \* math.pi / 180 for d in range(360)]
pos = [(1.0, math.cos(p), math.sin(p)) for p in phi]
pe = []
for p in pos:
L.atoms[3].position = p
L.run(0)
pe.append(L.eval("pe"))
By evaluating the potential energy for each position we can verify that
trajectory with the analytical formula. To compare both solutions, we plot
both trajectories over each other using matplotlib, which embeds the generated
plot inside the IPython notebook.
.. image:: JPG/pylammps_dihedral.jpg
:align: center
Running a Monte Carlo relaxation
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This second example shows how to use PyLammps to create a 2D Monte Carlo Relaxation
simulation, computing and plotting energy terms and even embedding video output.
Initially, a 2D system is created in a state with minimal energy.
.. image:: JPG/pylammps_mc_minimum.jpg
:align: center
It is then disordered by moving each atom by a random delta.
.. code-block:: python
random.seed(27848)
deltaperturb = 0.2
for i in range(L.system.natoms):
x, y = L.atoms[i].position
dx = deltaperturb \* random.uniform(-1, 1)
dy = deltaperturb \* random.uniform(-1, 1)
L.atoms[i].position = (x+dx, y+dy)
L.run(0)
.. image:: JPG/pylammps_mc_disordered.jpg
:align: center
Finally, the Monte Carlo algorithm is implemented in Python. It continuously
moves random atoms by a random delta and only accepts certain moves.
.. code-block:: python
estart = L.eval("pe")
elast = estart
naccept = 0
energies = [estart]
niterations = 3000
deltamove = 0.1
kT = 0.05
natoms = L.system.natoms
for i in range(niterations):
iatom = random.randrange(0, natoms)
current_atom = L.atoms[iatom]
x0, y0 = current_atom.position
dx = deltamove \* random.uniform(-1, 1)
dy = deltamove \* random.uniform(-1, 1)
current_atom.position = (x0+dx, y0+dy)
L.run(1, "pre no post no")
e = L.eval("pe")
energies.append(e)
if e <= elast:
naccept += 1
elast = e
elif random.random() <= math.exp(natoms\*(elast-e)/kT):
naccept += 1
elast = e
else:
current_atom.position = (x0, y0)
The energies of each iteration are collected in a Python list and finally plotted using matplotlib.
.. image:: JPG/pylammps_mc_energies_plot.jpg
:align: center
The IPython notebook also shows how to use dump commands and embed video files
inside of the IPython notebook.
Using PyLammps and mpi4py (Experimental)
----------------------------------------
PyLammps can be run in parallel using `mpi4py
<https://mpi4py.readthedocs.io>`_. This python package can be installed
using
.. code-block:: bash
pip install mpi4py
.. warning::
Usually, any :py:class:`PyLammps <lammps.PyLammps>` command must be
executed by *all* MPI processes. However, evaluations and querying
the system state is only available on MPI rank 0. Using these
functions from other MPI ranks will raise an exception.
The following is a short example which reads in an existing LAMMPS input
file and executes it in parallel. You can find in.melt in the
examples/melt folder. Please take note that the
:py:meth:`PyLammps.eval() <lammps.PyLammps.eval>` is called only from
MPI rank 0.
.. code-block:: python
from mpi4py import MPI
from lammps import PyLammps
L = PyLammps()
L.file("in.melt")
if MPI.COMM_WORLD.rank == 0:
print("Potential energy: ", L.eval("pe"))
MPI.Finalize()
To run this script (melt.py) in parallel using 4 MPI processes we invoke the
following mpirun command:
.. code-block:: bash
mpirun -np 4 python melt.py
Feedback and Contributing
-------------------------
If you find this Python interface useful, please feel free to provide feedback
and ideas on how to improve it to Richard Berger (richard.berger@outlook.com). We also
want to encourage people to write tutorial style IPython notebooks showcasing LAMMPS usage
and maybe their latest research results.
The PyLammps interface is deprecated and will be removed in a future release of
LAMMPS. As such, the PyLammps version of this tutorial has been removed and is
replaced by the :doc:`Python_head`.

441
doc/src/Howto_python.rst Normal file
View File

@ -0,0 +1,441 @@
LAMMPS Python Tutorial
======================
.. contents::
-----
Overview
--------
The :py:class:`lammps <lammps.lammps>` Python module is a wrapper class for the
LAMMPS :ref:`C language library interface API <lammps_c_api>` which is written using
`Python ctypes <ctypes_>`_. The design choice of this wrapper class is to
follow the C language API closely with only small changes related to Python
specific requirements and to better accommodate object oriented programming.
In addition to this flat `ctypes <ctypes_>`_ interface, the
:py:class:`lammps <lammps.lammps>` wrapper class exposes a discoverable
API that doesn't require as much knowledge of the underlying C language
library interface or LAMMPS C++ code implementation.
Finally, the API exposes some additional features for `IPython integration
<ipython_>`_ into `Jupyter notebooks <jupyter_>`_, e.g. for embedded
visualization output from :doc:`dump style image <dump_image>`.
.. _ctypes: https://docs.python.org/3/library/ctypes.html
.. _ipython: https://ipython.org/
.. _jupyter: https://jupyter.org/
-----
Quick Start
-----------
System-wide or User Installation
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Step 1: Building LAMMPS as a shared library
"""""""""""""""""""""""""""""""""""""""""""
To use LAMMPS inside of Python it has to be compiled as shared library.
This library is then loaded by the Python interface. In this example we
enable the :ref:`MOLECULE package <PKG-MOLECULE>` and compile LAMMPS
with :ref:`PNG, JPEG and FFMPEG output support <graphics>` enabled.
.. tabs::
.. tab:: CMake build
.. code-block:: bash
mkdir $LAMMPS_DIR/build-shared
cd $LAMMPS_DIR/build-shared
# MPI, PNG, Jpeg, FFMPEG are auto-detected
cmake ../cmake -DPKG_MOLECULE=yes -DPKG_PYTHON=on -DBUILD_SHARED_LIBS=yes
make
.. tab:: Traditional make
.. code-block:: bash
cd $LAMMPS_DIR/src
# add packages if necessary
make yes-MOLECULE
make yes-PYTHON
# compile shared library using Makefile
make mpi mode=shlib LMP_INC="-DLAMMPS_PNG -DLAMMPS_JPEG -DLAMMPS_FFMPEG" JPG_LIB="-lpng -ljpeg"
Step 2: Installing the LAMMPS Python package
""""""""""""""""""""""""""""""""""""""""""""
Next install the LAMMPS Python package into your current Python installation with:
.. code-block:: bash
make install-python
This will create a so-called `"wheel"
<https://packaging.python.org/en/latest/discussions/package-formats/#what-is-a-wheel>`_
and then install the LAMMPS Python module from that "wheel" into either
into a system folder (provided the command is executed with root
privileges) or into your personal Python module folder.
.. note::
Recompiling the shared library requires re-installing the Python
package.
Installation inside of a virtual environment
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
You can use virtual environments to create a custom Python environment
specifically tuned for your workflow.
Benefits of using a virtualenv
""""""""""""""""""""""""""""""
* isolation of your system Python installation from your development installation
* installation can happen in your user directory without root access (useful for HPC clusters)
* installing packages through pip allows you to get newer versions of packages than e.g., through apt-get or yum package managers (and without root access)
* you can even install specific old versions of a package if necessary
**Prerequisite (e.g. on Ubuntu)**
.. code-block:: bash
apt-get install python-venv
Creating a virtualenv with lammps installed
"""""""""""""""""""""""""""""""""""""""""""
.. code-block:: bash
# create virtual envrionment named 'testing'
python3 -m venv $HOME/python/testing
# activate 'testing' environment
source $HOME/python/testing/bin/activate
Now configure and compile the LAMMPS shared library as outlined above.
When using CMake and the shared library has already been build, you
need to re-run CMake to update the location of the python executable
to the location in the virtual environment with:
.. code-block:: bash
cmake . -DPython_EXECUTABLE=$(which python)
# install LAMMPS package in virtualenv
(testing) make install-python
# install other useful packages
(testing) pip install matplotlib jupyter mpi4py pandas
...
# return to original shell
(testing) deactivate
-------
Creating a new lammps instance
------------------------------
To create a lammps object you need to first import the class from the lammps
module. By using the default constructor, a new :py:class:`lammps
<lammps.lammps>` instance is created.
.. code-block:: python
from lammps import lammps
L = lammps()
See the :doc:`LAMMPS Python documentation <Python_create>` for how to customize
the instance creation with optional arguments.
-----
Commands
--------
Sending a LAMMPS command with the library interface is done using
the ``command`` method of the lammps object.
For instance, let's take the following LAMMPS command:
.. code-block:: LAMMPS
region box block 0 10 0 5 -0.5 0.5
This command can be executed with the following Python code if ``L`` is a ``lammps``
instance:
.. code-block:: python
L.command("region box block 0 10 0 5 -0.5 0.5")
For convenience, the ``lammps`` class also provides a command wrapper ``cmd``
that turns any LAMMPS command into a regular function call:
.. code-block:: python
L.cmd.region("box block", 0, 10, 0, 5, -0.5, 0.5)
Note that each parameter is set as Python number literal. With
the wrapper each command takes an arbitrary parameter list and transparently
merges it to a single command string, separating individual parameters by
white-space.
The benefit of this approach is avoiding redundant command calls and easier
parameterization. With the ``command`` function each call needs to be assembled
manually using formatted strings.
.. code-block:: python
L.command(f"region box block {xlo} {xhi} {ylo} {yhi} {zlo} {zhi}")
The wrapper accepts parameters directly and will convert
them automatically to a final command string.
.. code-block:: python
L.cmd.region("box block", xlo, xhi, ylo, yhi, zlo, zhi)
.. note::
When running in IPython you can use Tab-completion after ``L.cmd.`` to see
all available LAMMPS commands.
-----
Accessing atom data
-------------------
All per-atom properties that are part of the :doc:`atom style
<atom_style>` in the current simulation can be accessed using the
:py:meth:`extract_atoms() <lammps.lammps.extract_atoms()>` method. This
can be retrieved as ctypes objects or as NumPy arrays through the
lammps.numpy module. Those represent the *local* atoms of the
individual sub-domain for the current MPI process and may contain
information for the local ghost atoms or not depending on the property.
Both can be accessed as lists, but for the ctypes list object the size
is not known and hast to be retrieved first to avoid out-of-bounds
accesses.
.. code-block:: python
nlocal = L.extract_setting("nlocal")
nall = L.extract_setting("nall")
print("Number of local atoms ", nlocal, " Number of local and ghost atoms ", nall);
# access via ctypes directly
atom_id = L.extract_atom("id")
print("Atom IDs", atom_id[0:nlocal])
# access through numpy wrapper
atom_type = L.numpy.extract_atom("type")
print("Atom types", atom_type)
x = L.numpy.extract_atom("x")
v = L.numpy.extract_atom("v")
print("positions array shape", x.shape)
print("velocity array shape", v.shape)
# turn on communicating velocities to ghost atoms
L.cmd.comm_modify("vel", "yes")
v = L.numpy.extract_atom('v')
print("velocity array shape", v.shape)
Some properties can also be set from Python since internally the
data of the C++ code is accessed directly:
.. code-block:: python
# set position in 2D simulation
x[0] = (1.0, 0.0)
# set position in 3D simulation
x[0] = (1.0, 0.0, 1.)
------
Retrieving the values of thermodynamic data and variables
---------------------------------------------------------
To access thermodynamic data from the last completed timestep,
you can use the :py:meth:`get_thermo() <lammps.lammps.get_thermo>`
method, and to extract the value of (compatible) variables, you
can use the :py:meth:`extract_variable() <lammps.lammps.extract_variable>`
method.
.. code-block:: python
result = L.get_thermo("ke") # kinetic energy
result = L.get_thermo("pe") # potential energy
result = L.extract_variable("t") / 2.0
Error handling
--------------
We are using C++ exceptions in LAMMPS for errors and the C language
library interface captures and records them. This allows checking
whether errors have happened in Python during a call into LAMMPS and
then re-throw the error as a Python exception. This way you can handle
LAMMPS errors in the conventional way through the Python exception
handling mechanism.
.. warning::
Capturing a LAMMPS exception in Python can still mean that the
current LAMMPS process is in an illegal state and must be
terminated. It is advised to save your data and terminate the Python
instance as quickly as possible.
Using LAMMPS in IPython notebooks and Jupyter
---------------------------------------------
If the LAMMPS Python package is installed for the same Python
interpreter as IPython, you can use LAMMPS directly inside of an IPython
notebook inside of Jupyter. Jupyter is a powerful integrated development
environment (IDE) for many dynamic languages like Python, Julia and
others, which operates inside of any web browser. Besides
auto-completion and syntax highlighting it allows you to create
formatted documents using Markup, mathematical formulas, graphics and
animations intermixed with executable Python code. It is a great format
for tutorials and showcasing your latest research.
To launch an instance of Jupyter simply run the following command inside your
Python environment (this assumes you followed the Quick Start instructions):
.. code-block:: bash
jupyter notebook
Interactive Python Examples
---------------------------
Examples of IPython notebooks can be found in the ``python/examples/ipython``
subdirectory. To open these notebooks launch ``jupyter notebook`` inside this
directory and navigate to one of them. If you compiled and installed
a LAMMPS shared library with PNG, JPEG and FFMPEG support
you should be able to rerun all of these notebooks.
Validating a dihedral potential
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This example showcases how an IPython Notebook can be used to compare a simple
LAMMPS simulation of a harmonic dihedral potential to its analytical solution.
Four atoms are placed in the simulation and the dihedral potential is applied on
them using a datafile. Then one of the atoms is rotated along the central axis by
setting its position from Python, which changes the dihedral angle.
.. code-block:: python
phi = [d \* math.pi / 180 for d in range(360)]
pos = [(1.0, math.cos(p), math.sin(p)) for p in phi]
x = L.numpy.extract_atom("x")
pe = []
for p in pos:
x[3] = p
L.cmd.run(0, "post", "no")
pe.append(L.get_thermo("pe"))
By evaluating the potential energy for each position we can verify that
trajectory with the analytical formula. To compare both solutions, we plot
both trajectories over each other using matplotlib, which embeds the generated
plot inside the IPython notebook.
.. image:: JPG/pylammps_dihedral.jpg
:align: center
Running a Monte Carlo relaxation
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This second example shows how to use the `lammps` Python interface to create a
2D Monte Carlo Relaxation simulation, computing and plotting energy terms and
even embedding video output.
Initially, a 2D system is created in a state with minimal energy.
.. image:: JPG/pylammps_mc_minimum.jpg
:align: center
It is then disordered by moving each atom by a random delta.
.. code-block:: python
random.seed(27848)
deltaperturb = 0.2
x = L.numpy.extract_atom("x")
natoms = x.shape[0]
for i in range(natoms):
dx = deltaperturb \* random.uniform(-1, 1)
dy = deltaperturb \* random.uniform(-1, 1)
x[i][0] += dx
x[i][1] += dy
L.cmd.run(0, "post", "no")
.. image:: JPG/pylammps_mc_disordered.jpg
:align: center
Finally, the Monte Carlo algorithm is implemented in Python. It continuously
moves random atoms by a random delta and only accepts certain moves.
.. code-block:: python
estart = L.get_thermo("pe")
elast = estart
naccept = 0
energies = [estart]
niterations = 3000
deltamove = 0.1
kT = 0.05
for i in range(niterations):
x = L.numpy.extract_atom("x")
natoms = x.shape[0]
iatom = random.randrange(0, natoms)
current_atom = x[iatom]
x0 = current_atom[0]
y0 = current_atom[1]
dx = deltamove \* random.uniform(-1, 1)
dy = deltamove \* random.uniform(-1, 1)
current_atom[0] = x0 + dx
current_atom[1] = y0 + dy
L.cmd.run(1, "pre no post no")
e = L.get_thermo("pe")
energies.append(e)
if e <= elast:
naccept += 1
elast = e
elif random.random() <= math.exp(natoms\*(elast-e)/kT):
naccept += 1
elast = e
else:
current_atom[0] = x0
current_atom[1] = y0
The energies of each iteration are collected in a Python list and finally plotted using matplotlib.
.. image:: JPG/pylammps_mc_energies_plot.jpg
:align: center
The IPython notebook also shows how to use dump commands and embed video files
inside of the IPython notebook.

View File

@ -131,16 +131,15 @@ run LAMMPS in serial mode.
.. _lammps_python_api:
LAMMPS Python APIs
==================
LAMMPS Python API
=================
The LAMMPS Python module enables calling the LAMMPS C library API from
Python by dynamically loading functions in the LAMMPS shared library through
the `Python ctypes module <https://docs.python.org/3/library/ctypes.html>`_.
Because of the dynamic loading, it is **required** that LAMMPS is compiled
in :ref:`"shared" mode <exe>`. The Python interface is object-oriented, but
otherwise tries to be very similar to the C library API. Three different
Python classes to run LAMMPS are available and they build on each other.
otherwise tries to be very similar to the C library API.
More information on this is in the :doc:`Python_head`
section of the manual. Use of the LAMMPS Python module is described in
:doc:`Python_module`.

View File

@ -208,20 +208,21 @@ Build system (strict)
LAMMPS currently supports two build systems: one that is based on
:doc:`traditional Makefiles <Build_make>` and one that is based on
:doc:`CMake <Build_cmake>`. Therefore, your contribution must be
compatible with and support both build systems.
:doc:`CMake <Build_cmake>`. As of fall 2024, it is no longer required
to support the traditional make build system. New packages may choose
to only support building with CMake. Additions to existing packages
must follow the requirements set by that package.
For a single pair of header and implementation files that are an
independent feature, it is usually only required to add them to
``src/.gitignore``.
For traditional make, if your contributed files or package depend on
other LAMMPS style files or packages also being installed
(e.g. because your file is a derived class from the other LAMMPS
class), then an ``Install.sh`` file is also needed to check for those
dependencies and modifications to ``src/Depend.sh`` to trigger the checks.
See other README and Install.sh files in other directories as
examples.
other LAMMPS style files or packages also being installed (e.g. because
your file is a derived class from the other LAMMPS class), then an
``Install.sh`` file is also needed to check for those dependencies and
modifications to ``src/Depend.sh`` to trigger the checks. See other
README and Install.sh files in other directories as examples.
Similarly, for CMake support, changes may need to be made to
``cmake/CMakeLists.txt``, some of the files in ``cmake/presets``, and

View File

@ -2,14 +2,8 @@ Per-atom properties
===================
Similar to what is described in :doc:`Library_atoms`, the instances of
:py:class:`lammps <lammps.lammps>`, :py:class:`PyLammps <lammps.PyLammps>`, or
:py:class:`IPyLammps <lammps.IPyLammps>` can be used to extract atom quantities
and modify some of them. The main difference between the interfaces is how the information
is exposed.
While the :py:class:`lammps <lammps.lammps>` is just a thin layer that wraps C API calls,
:py:class:`PyLammps <lammps.PyLammps>` and :py:class:`IPyLammps <lammps.IPyLammps>` expose
information as objects and properties.
:py:class:`lammps <lammps.lammps>` can be used to extract atom quantities
and modify some of them.
In some cases the data returned is a direct reference to the original data
inside LAMMPS cast to ``ctypes`` pointers. Where possible, the wrappers will
@ -25,57 +19,41 @@ against invalid accesses.
accordingly. These arrays can change sizes and order at every neighbor list
rebuild and atom sort event as atoms are migrating between subdomains.
.. tabs::
.. code-block:: python
.. tab:: lammps API
from lammps import lammps
.. code-block:: python
lmp = lammps()
lmp.file("in.sysinit")
from lammps import lammps
lmp = lammps()
lmp.file("in.sysinit")
# Read/Write access via ctypes
nlocal = lmp.extract_global("nlocal")
x = lmp.extract_atom("x")
nlocal = lmp.extract_global("nlocal")
x = lmp.extract_atom("x")
for i in range(nlocal):
print("(x,y,z) = (", x[i][0], x[i][1], x[i][2], ")")
for i in range(nlocal):
print("(x,y,z) = (", x[i][0], x[i][1], x[i][2], ")")
# Read/Write access via NumPy arrays
atom_id = L.numpy.extract_atom("id")
atom_type = L.numpy.extract_atom("type")
x = L.numpy.extract_atom("x")
v = L.numpy.extract_atom("v")
f = L.numpy.extract_atom("f")
lmp.close()
# set position in 2D simulation
x[0] = (1.0, 0.0)
**Methods**:
# set position in 3D simulation
x[0] = (1.0, 0.0, 1.)
* :py:meth:`extract_atom() <lammps.lammps.extract_atom()>`: extract a per-atom quantity
lmp.close()
**Numpy Methods**:
* :py:meth:`numpy.extract_atom() <lammps.numpy_wrapper.numpy_wrapper.extract_atom()>`: extract a per-atom quantity as numpy array
**Methods**:
.. tab:: PyLammps/IPyLammps API
* :py:meth:`extract_atom() <lammps.lammps.extract_atom()>`: extract a per-atom quantity
All atoms in the current simulation can be accessed by using the :py:attr:`PyLammps.atoms <lammps.PyLammps.atoms>` property.
Each element of this list is a :py:class:`Atom <lammps.Atom>` or :py:class:`Atom2D <lammps.Atom2D>` object. The attributes of
these objects provide access to their data (id, type, position, velocity, force, etc.):
.. code-block:: python
# access first atom
L.atoms[0].id
L.atoms[0].type
# access second atom
L.atoms[1].position
L.atoms[1].velocity
L.atoms[1].force
Some attributes can be changed:
.. code-block:: python
# set position in 2D simulation
L.atoms[0].position = (1.0, 0.0)
# set position in 3D simulation
L.atoms[0].position = (1.0, 0.0, 1.0)
**Numpy Methods**:
* :py:meth:`numpy.extract_atom() <lammps.numpy_wrapper.numpy_wrapper.extract_atom()>`: extract a per-atom quantity as numpy array

View File

@ -6,11 +6,10 @@ Creating or deleting a LAMMPS object
====================================
With the Python interface the creation of a :cpp:class:`LAMMPS
<LAMMPS_NS::LAMMPS>` instance is included in the constructors for the
:py:class:`lammps <lammps.lammps>`, :py:class:`PyLammps <lammps.PyLammps>`,
and :py:class:`IPyLammps <lammps.IPyLammps>` classes.
Internally it will call either :cpp:func:`lammps_open` or :cpp:func:`lammps_open_no_mpi` from the C
library API to create the class instance.
<LAMMPS_NS::LAMMPS>` instance is included in the constructor for the
:py:class:`lammps <lammps.lammps>` class. Internally it will call either
:cpp:func:`lammps_open` or :cpp:func:`lammps_open_no_mpi` from the C library
API to create the class instance.
All arguments are optional. The *name* argument allows loading a
LAMMPS shared library that is named ``liblammps_machine.so`` instead of
@ -26,108 +25,25 @@ to run the Python module like the library interface on a subset of the
MPI ranks after splitting the communicator.
Here are simple examples using all three Python interfaces:
Here is a simple example using the LAMMPS Python interface:
.. tabs::
.. code-block:: python
.. tab:: lammps API
from lammps import lammps
.. code-block:: python
# NOTE: argv[0] is set by the lammps class constructor
args = ["-log", "none"]
from lammps import lammps
# create LAMMPS instance
lmp = lammps(cmdargs=args)
# NOTE: argv[0] is set by the lammps class constructor
args = ["-log", "none"]
# get and print numerical version code
print("LAMMPS Version: ", lmp.version())
# create LAMMPS instance
lmp = lammps(cmdargs=args)
# explicitly close and delete LAMMPS instance (optional)
lmp.close()
# get and print numerical version code
print("LAMMPS Version: ", lmp.version())
# explicitly close and delete LAMMPS instance (optional)
lmp.close()
.. tab:: PyLammps API
The :py:class:`PyLammps <lammps.PyLammps>` class is a wrapper around the
:py:class:`lammps <lammps.lammps>` class and all of its lower level functions.
By default, it will create a new instance of :py:class:`lammps <lammps.lammps>` passing
along all arguments to the constructor of :py:class:`lammps <lammps.lammps>`.
.. code-block:: python
from lammps import PyLammps
# NOTE: argv[0] is set by the lammps class constructor
args = ["-log", "none"]
# create LAMMPS instance
L = PyLammps(cmdargs=args)
# get and print numerical version code
print("LAMMPS Version: ", L.version())
# explicitly close and delete LAMMPS instance (optional)
L.close()
:py:class:`PyLammps <lammps.PyLammps>` objects can also be created on top of an existing
:py:class:`lammps <lammps.lammps>` object:
.. code-block:: python
from lammps import lammps, PyLammps
...
# create LAMMPS instance
lmp = lammps(cmdargs=args)
# create PyLammps instance using previously created LAMMPS instance
L = PyLammps(ptr=lmp)
This is useful if you have to create the :py:class:`lammps <lammps.lammps>`
instance is a specific way, but want to take advantage of the
:py:class:`PyLammps <lammps.PyLammps>` interface.
.. tab:: IPyLammps API
The :py:class:`IPyLammps <lammps.IPyLammps>` class is an extension of the
:py:class:`PyLammps <lammps.PyLammps>` class. It has the same construction behavior. By
default, it will create a new instance of :py:class:`lammps` passing
along all arguments to the constructor of :py:class:`lammps`.
.. code-block:: python
from lammps import IPyLammps
# NOTE: argv[0] is set by the lammps class constructor
args = ["-log", "none"]
# create LAMMPS instance
L = IPyLammps(cmdargs=args)
# get and print numerical version code
print("LAMMPS Version: ", L.version())
# explicitly close and delete LAMMPS instance (optional)
L.close()
You can also initialize IPyLammps on top of an existing :py:class:`lammps` or :py:class:`PyLammps` object:
.. code-block:: python
from lammps import lammps, IPyLammps
...
# create LAMMPS instance
lmp = lammps(cmdargs=args)
# create PyLammps instance using previously created LAMMPS instance
L = PyLammps(ptr=lmp)
This is useful if you have to create the :py:class:`lammps <lammps.lammps>`
instance is a specific way, but want to take advantage of the
:py:class:`IPyLammps <lammps.IPyLammps>` interface.
In all of the above cases, same as with the :ref:`C library API <lammps_c_api>`, this will use the
Same as with the :ref:`C library API <lammps_c_api>`, this will use the
``MPI_COMM_WORLD`` communicator for the MPI library that LAMMPS was
compiled with.

View File

@ -1,127 +1,123 @@
Executing commands
==================
Once an instance of the :py:class:`lammps <lammps.lammps>`,
:py:class:`PyLammps <lammps.PyLammps>`, or
:py:class:`IPyLammps <lammps.IPyLammps>` class is created, there are
Once an instance of the :py:class:`lammps <lammps.lammps>` class is created, there are
multiple ways to "feed" it commands. In a way that is not very different from
running a LAMMPS input script, except that Python has many more facilities
for structured programming than the LAMMPS input script syntax. Furthermore
it is possible to "compute" what the next LAMMPS command should be.
.. tabs::
Same as in the equivalent :doc:`C library functions <Library_execute>`,
commands can be read from a file, a single string, a list of strings and a
block of commands in a single multi-line string. They are processed under the
same boundary conditions as the C library counterparts. The example below
demonstrates the use of :py:func:`lammps.file()`, :py:func:`lammps.command()`,
:py:func:`lammps.commands_list()`, and :py:func:`lammps.commands_string()`:
.. tab:: lammps API
.. code-block:: python
Same as in the equivalent
:doc:`C library functions <Library_execute>`, commands can be read from a file, a
single string, a list of strings and a block of commands in a single
multi-line string. They are processed under the same boundary conditions
as the C library counterparts. The example below demonstrates the use
of :py:func:`lammps.file()`, :py:func:`lammps.command()`,
:py:func:`lammps.commands_list()`, and :py:func:`lammps.commands_string()`:
from lammps import lammps
lmp = lammps()
.. code-block:: python
# read commands from file 'in.melt'
lmp.file('in.melt')
from lammps import lammps
lmp = lammps()
# issue a single command
lmp.command('variable zpos index 1.0')
# read commands from file 'in.melt'
lmp.file('in.melt')
# create 10 groups with 10 atoms each
cmds = [f"group g{i} id {10*i+1}:{10*(i+1)}" for i in range(10)]
lmp.commands_list(cmds)
# issue a single command
lmp.command('variable zpos index 1.0')
# run commands from a multi-line string
block = """
clear
region box block 0 2 0 2 0 2
create_box 1 box
create_atoms 1 single 1.0 1.0 ${zpos}
"""
lmp.commands_string(block)
# create 10 groups with 10 atoms each
cmds = ["group g{} id {}:{}".format(i,10*i+1,10*(i+1)) for i in range(10)]
lmp.commands_list(cmds)
For convenience, the :py:class:`lammps <lammps.lammps>` class also provides a
command wrapper ``cmd`` that turns any LAMMPS command into a regular function
call.
# run commands from a multi-line string
block = """
clear
region box block 0 2 0 2 0 2
create_box 1 box
create_atoms 1 single 1.0 1.0 ${zpos}
"""
lmp.commands_string(block)
For instance, the following LAMMPS command
.. tab:: PyLammps/IPyLammps API
.. code-block:: LAMMPS
Unlike the lammps API, the PyLammps/IPyLammps APIs allow running LAMMPS
commands by calling equivalent member functions of :py:class:`PyLammps <lammps.PyLammps>`
and :py:class:`IPyLammps <lammps.IPyLammps>` instances.
region box block 0 10 0 5 -0.5 0.5
For instance, the following LAMMPS command
would normally be executed with the following Python code:
.. code-block:: LAMMPS
.. code-block:: python
region box block 0 10 0 5 -0.5 0.5
from lammps import lammps
can be executed using with the lammps API with the following Python code if ``lmp`` is an
instance of :py:class:`lammps <lammps.lammps>`:
lmp = lammps()
lmp.command("region box block 0 10 0 5 -0.5 0.5")
.. code-block:: python
With the ``cmd`` wrapper, any LAMMPS command can be split up into arbitrary parts.
These parts are then passed to a member function with the name of the :doc:`command <Commands_all>`.
For the :doc:`region <region>` command that means the :code:`region()` method can be called.
The arguments of the command can be passed as one string, or
individually.
from lammps import lammps
.. code-block:: python
lmp = lammps()
lmp.command("region box block 0 10 0 5 -0.5 0.5")
from lammps import lammps
With the PyLammps interface, any LAMMPS command can be split up into arbitrary parts.
These parts are then passed to a member function with the name of the :doc:`command <Commands_all>`.
For the :doc:`region <region>` command that means the :code:`region()` method can be called.
The arguments of the command can be passed as one string, or
individually.
L = lammps()
.. code-block:: python
# pass command parameters as one string
L.cmd.region("box block 0 10 0 5 -0.5 0.5")
from lammps import PyLammps
# OR pass them individually
L.cmd.region("box block", 0, 10, 0, 5, -0.5, 0.5)
L = PyLammps()
In the latter example, all parameters except the first are Python floating-point literals. The
member function takes the entire parameter list and transparently merges it to a single command
string.
# pass command parameters as one string
L.region("box block 0 10 0 5 -0.5 0.5")
The benefit of this approach is avoiding redundant command calls and easier
parameterization. With `command`, `commands_list`, and `commands_string` the
parameterization needed to be done manually by creating formatted command
strings.
# OR pass them individually
L.region("box block", 0, 10, 0, 5, -0.5, 0.5)
.. code-block:: python
In the latter example, all parameters except the first are Python floating-point literals. The
member function takes the entire parameter list and transparently merges it to a single command
string.
lmp.command("region box block %f %f %f %f %f %f" % (xlo, xhi, ylo, yhi, zlo, zhi))
The benefit of this approach is avoiding redundant command calls and easier
parameterization. In the lammps API parameterization needed to be done
manually by creating formatted command strings.
In contrast, methods of the `cmd` wrapper accept parameters directly and will convert
them automatically to a final command string.
.. code-block:: python
.. code-block:: python
lmp.command("region box block %f %f %f %f %f %f" % (xlo, xhi, ylo, yhi, zlo, zhi))
L.cmd.region("box block", xlo, xhi, ylo, yhi, zlo, zhi)
In contrast, methods of PyLammps accept parameters directly and will convert
them automatically to a final command string.
.. note::
.. code-block:: python
When running in IPython you can use Tab-completion after ``L.cmd.`` to see
all available LAMMPS commands.
L.region("box block", xlo, xhi, ylo, yhi, zlo, zhi)
Using these facilities, the previous example shown above can be rewritten as follows:
Using these facilities, the example shown for the lammps API can be rewritten as follows:
.. code-block:: python
.. code-block:: python
from lammps import lammps
L = lammps()
from lammps import PyLammps
L = PyLammps()
# read commands from file 'in.melt'
L.file('in.melt')
# read commands from file 'in.melt'
L.file('in.melt')
# issue a single command
L.cmd.variable('zpos', 'index', 1.0)
# issue a single command
L.variable('zpos', 'index', 1.0)
# create 10 groups with 10 atoms each
for i in range(10):
L.cmd.group(f"g{i}", "id", f"{10*i+1}:{10*(i+1)}")
# create 10 groups with 10 atoms each
for i in range(10):
L.group(f"g{i}", "id", f"{10*i+1}:{10*(i+1)}")
L.clear()
L.region("box block", 0, 2, 0, 2, 0, 2)
L.create_box(1, "box")
L.create_atoms(1, "single", 1.0, 1.0, "${zpos}")
L.cmd.clear()
L.cmd.region("box block", 0, 2, 0, 2, 0, 2)
L.cmd.create_box(1, "box")
L.cmd.create_atoms(1, "single", 1.0, 1.0, "${zpos}")

View File

@ -15,6 +15,7 @@ together.
Python_call
Python_formats
Python_examples
Python_jupyter
Python_error
Python_trouble

View File

@ -0,0 +1,45 @@
Using LAMMPS in IPython notebooks and Jupyter
=============================================
If the LAMMPS Python package is installed for the same Python interpreter as
`IPython <ipython>`_, you can use LAMMPS directly inside of an IPython notebook inside of
Jupyter. `Jupyter <juypter>`_ is a powerful integrated development environment (IDE) for
many dynamic languages like Python, Julia and others, which operates inside of
any web browser. Besides auto-completion and syntax highlighting it allows you
to create formatted documents using Markup, mathematical formulas, graphics and
animations intermixed with executable Python code. It is a great format for
tutorials and showcasing your latest research.
The easiest way to install it is via ``pip``:
.. code-block:: bash
pip install --user jupyter
To launch an instance of Jupyter simply run the following command inside your
Python environment:
.. code-block:: bash
jupyter notebook
Interactive Python Examples
---------------------------
Examples of IPython notebooks can be found in the ``python/examples/ipython``
subdirectory. They require LAMMPS to be compiled as shared library with PYTHON,
PNG, JPEG and FFMPEG support.
To open these notebooks launch ``jupyter notebook index.ipynb`` inside this
directory. The opened file provides an overview of the available examples.
- Example 1: Using LAMMPS with Python (``simple.ipynb``)
- Example 2: Analyzing LAMMPS thermodynamic data (``thermo.ipynb``)
- Example 3: Working with Per-Atom Data (``atoms.ipynb``)
- Example 4: Working with LAMMPS variables (``variables.ipynb``)
- Example 5: Validating a dihedral potential (``dihedrals/dihedral.ipynb``)
- Example 6: Running a Monte Carlo relaxation (``montecarlo/mc.ipynb``)
.. note::
Typically clicking a link in Jupyter will open a new tab, which might be blocked by your pop-up blocker.

View File

@ -10,19 +10,11 @@ be installed into a Python system folder or a user folder with ``make
install-python``. Components of the module can then loaded into a Python
session with the ``import`` command.
There are multiple Python interface classes in the :py:mod:`lammps` module:
.. warning::
- the :py:class:`lammps <lammps.lammps>` class. This is a wrapper around
the C-library interface and its member functions try to replicate the
:ref:`C-library API <lammps_c_api>` closely. This is the most
feature-complete Python API.
- the :py:class:`PyLammps <lammps.PyLammps>` class. This is a more high-level
and more Python style class implemented on top of the
:py:class:`lammps <lammps.lammps>` class.
- the :py:class:`IPyLammps <lammps.IPyLammps>` class is derived from
:py:class:`PyLammps <lammps.PyLammps>` and adds embedded graphics
features to conveniently include LAMMPS into `Jupyter
<https://jupyter.org/>`_ notebooks.
Alternative interfaces such as :py:class:`PyLammps <lammps.PyLammps>` and
:py:class:`IPyLammps <lammps.IPyLammps>` classes have been deprecated and
will be removed in a future version of LAMMPS.
.. _mpi4py_url: https://mpi4py.readthedocs.io
@ -49,7 +41,7 @@ The ``lammps`` class API
========================
The :py:class:`lammps <lammps.lammps>` class is the core of the LAMMPS
Python interfaces. It is a wrapper around the :ref:`LAMMPS C library
Python interface. It is a wrapper around the :ref:`LAMMPS C library
API <lammps_c_api>` using the `Python ctypes module
<https://docs.python.org/3/library/ctypes.html>`_ and a shared library
compiled from the LAMMPS sources code. The individual methods in this
@ -64,40 +56,7 @@ functions. Below is a detailed documentation of the API.
.. autoclass:: lammps.numpy_wrapper::numpy_wrapper
:members:
----------
The ``PyLammps`` class API
==========================
The :py:class:`PyLammps <lammps.PyLammps>` class is a wrapper that creates a
simpler, more "Pythonic" interface to common LAMMPS functionality. LAMMPS
data structures are exposed through objects and properties. This makes Python
scripts shorter and more concise. See the :doc:`PyLammps Tutorial
<Howto_pylammps>` for an introduction on how to use this interface.
.. autoclass:: lammps.PyLammps
:members:
.. autoclass:: lammps.AtomList
:members:
.. autoclass:: lammps.Atom
:members:
.. autoclass:: lammps.Atom2D
:members:
----------
The ``IPyLammps`` class API
===========================
The :py:class:`IPyLammps <lammps.PyLammps>` class is an extension of
:py:class:`PyLammps <lammps.PyLammps>`, adding additional functions to
quickly display visualizations such as images and videos inside of IPython.
See the :doc:`PyLammps Tutorial <Howto_pylammps>` for examples.
.. autoclass:: lammps.IPyLammps
.. autoclass:: lammps.ipython::wrapper
:members:
----------

View File

@ -4,95 +4,52 @@ Compute, fixes, variables
This section documents accessing or modifying data from objects like
computes, fixes, or variables in LAMMPS using the :py:mod:`lammps` module.
.. tabs::
For :py:meth:`lammps.extract_compute() <lammps.lammps.extract_compute()>` and
:py:meth:`lammps.extract_fix() <lammps.lammps.extract_fix()>`, the global, per-atom,
or local data calculated by the compute or fix can be accessed. What is returned
depends on whether the compute or fix calculates a scalar or vector or array.
For a scalar, a single double value is returned. If the compute or fix calculates
a vector or array, a pointer to the internal LAMMPS data is returned, which you can
use via normal Python subscripting.
.. tab:: lammps API
The one exception is that for a fix that calculates a
global vector or array, a single double value from the vector or array
is returned, indexed by I (vector) or I and J (array). I,J are
zero-based indices.
See the :doc:`Howto output <Howto_output>` page for a discussion of
global, per-atom, and local data, and of scalar, vector, and array
data types. See the doc pages for individual :doc:`computes <compute>`
and :doc:`fixes <fix>` for a description of what they calculate and
store.
For :py:meth:`lammps.extract_compute() <lammps.lammps.extract_compute()>` and
:py:meth:`lammps.extract_fix() <lammps.lammps.extract_fix()>`, the global, per-atom,
or local data calculated by the compute or fix can be accessed. What is returned
depends on whether the compute or fix calculates a scalar or vector or array.
For a scalar, a single double value is returned. If the compute or fix calculates
a vector or array, a pointer to the internal LAMMPS data is returned, which you can
use via normal Python subscripting.
For :py:meth:`lammps.extract_variable() <lammps.lammps.extract_variable()>`,
an :doc:`equal-style or atom-style variable <variable>` is evaluated and
its result returned.
The one exception is that for a fix that calculates a
global vector or array, a single double value from the vector or array
is returned, indexed by I (vector) or I and J (array). I,J are
zero-based indices.
See the :doc:`Howto output <Howto_output>` page for a discussion of
global, per-atom, and local data, and of scalar, vector, and array
data types. See the doc pages for individual :doc:`computes <compute>`
and :doc:`fixes <fix>` for a description of what they calculate and
store.
For equal-style variables a single ``c_double`` value is returned and the
group argument is ignored. For atom-style variables, a vector of
``c_double`` is returned, one value per atom, which you can use via normal
Python subscripting. The values will be zero for atoms not in the
specified group.
For :py:meth:`lammps.extract_variable() <lammps.lammps.extract_variable()>`,
an :doc:`equal-style or atom-style variable <variable>` is evaluated and
its result returned.
:py:meth:`lammps.numpy.extract_compute() <lammps.numpy_wrapper.numpy_wrapper.extract_compute()>`,
:py:meth:`lammps.numpy.extract_fix() <lammps.numpy_wrapper.numpy_wrapper.extract_fix()>`, and
:py:meth:`lammps.numpy.extract_variable() <lammps.numpy_wrapper.numpy_wrapper.extract_variable()>` are
equivalent NumPy implementations that return NumPy arrays instead of ``ctypes`` pointers.
For equal-style variables a single ``c_double`` value is returned and the
group argument is ignored. For atom-style variables, a vector of
``c_double`` is returned, one value per atom, which you can use via normal
Python subscripting. The values will be zero for atoms not in the
specified group.
The :py:meth:`lammps.set_variable() <lammps.lammps.set_variable()>` method sets an
existing string-style variable to a new string value, so that subsequent LAMMPS
commands can access the variable.
:py:meth:`lammps.numpy.extract_compute() <lammps.numpy_wrapper.numpy_wrapper.extract_compute()>`,
:py:meth:`lammps.numpy.extract_fix() <lammps.numpy_wrapper.numpy_wrapper.extract_fix()>`, and
:py:meth:`lammps.numpy.extract_variable() <lammps.numpy_wrapper.numpy_wrapper.extract_variable()>` are
equivalent NumPy implementations that return NumPy arrays instead of ``ctypes`` pointers.
**Methods**:
The :py:meth:`lammps.set_variable() <lammps.lammps.set_variable()>` method sets an
existing string-style variable to a new string value, so that subsequent LAMMPS
commands can access the variable.
* :py:meth:`lammps.extract_compute() <lammps.lammps.extract_compute()>`: extract value(s) from a compute
* :py:meth:`lammps.extract_fix() <lammps.lammps.extract_fix()>`: extract value(s) from a fix
* :py:meth:`lammps.extract_variable() <lammps.lammps.extract_variable()>`: extract value(s) from a variable
* :py:meth:`lammps.set_variable() <lammps.lammps.set_variable()>`: set existing named string-style variable to value
**Methods**:
**NumPy Methods**:
* :py:meth:`lammps.extract_compute() <lammps.lammps.extract_compute()>`: extract value(s) from a compute
* :py:meth:`lammps.extract_fix() <lammps.lammps.extract_fix()>`: extract value(s) from a fix
* :py:meth:`lammps.extract_variable() <lammps.lammps.extract_variable()>`: extract value(s) from a variable
* :py:meth:`lammps.set_variable() <lammps.lammps.set_variable()>`: set existing named string-style variable to value
**NumPy Methods**:
* :py:meth:`lammps.numpy.extract_compute() <lammps.numpy_wrapper.numpy_wrapper.extract_compute()>`: extract value(s) from a compute, return arrays as numpy arrays
* :py:meth:`lammps.numpy.extract_fix() <lammps.numpy_wrapper.numpy_wrapper.extract_fix()>`: extract value(s) from a fix, return arrays as numpy arrays
* :py:meth:`lammps.numpy.extract_variable() <lammps.numpy_wrapper.numpy_wrapper.extract_variable()>`: extract value(s) from a variable, return arrays as numpy arrays
.. tab:: PyLammps/IPyLammps API
PyLammps and IPyLammps classes currently do not add any additional ways of
retrieving information out of computes and fixes. This information can still be accessed by using the lammps API:
.. code-block:: python
L.lmp.extract_compute(...)
L.lmp.extract_fix(...)
# OR
L.lmp.numpy.extract_compute(...)
L.lmp.numpy.extract_fix(...)
LAMMPS variables can be both defined and accessed via the :py:class:`PyLammps <lammps.PyLammps>` interface.
To define a variable you can use the :doc:`variable <variable>` command:
.. code-block:: python
L.variable("a index 2")
A dictionary of all variables is returned by the :py:attr:`PyLammps.variables <lammps.PyLammps.variables>` property:
you can access an individual variable by retrieving a variable object from the
``L.variables`` dictionary by name
.. code-block:: python
a = L.variables['a']
The variable value can then be easily read and written by accessing the value
property of this object.
.. code-block:: python
print(a.value)
a.value = 4
* :py:meth:`lammps.numpy.extract_compute() <lammps.numpy_wrapper.numpy_wrapper.extract_compute()>`: extract value(s) from a compute, return arrays as numpy arrays
* :py:meth:`lammps.numpy.extract_fix() <lammps.numpy_wrapper.numpy_wrapper.extract_fix()>`: extract value(s) from a fix, return arrays as numpy arrays
* :py:meth:`lammps.numpy.extract_variable() <lammps.numpy_wrapper.numpy_wrapper.extract_variable()>`: extract value(s) from a variable, return arrays as numpy arrays

View File

@ -56,7 +56,7 @@ Below is an example output for Python version 3.8.5.
---------
LAMMPS can work together with Python in three ways. First, Python can
LAMMPS can work together with Python in two ways. First, Python can
wrap LAMMPS through the its :doc:`library interface <Library>`, so
that a Python script can create one or more instances of LAMMPS and
launch one or more simulations. In Python terms, this is referred to as
@ -67,22 +67,7 @@ launch one or more simulations. In Python terms, this is referred to as
Launching LAMMPS via Python
Second, the lower-level Python interface in the :py:class:`lammps Python
class <lammps.lammps>` can be used indirectly through the provided
:py:class:`PyLammps <lammps.PyLammps>` and :py:class:`IPyLammps
<lammps.IPyLammps>` wrapper classes, also written in Python. These
wrappers try to simplify the usage of LAMMPS in Python by providing a
more object-based interface to common LAMMPS functionality. They also
reduce the amount of code necessary to parameterize LAMMPS scripts
through Python and make variables and computes directly accessible.
.. figure:: JPG/pylammps-invoke-lammps.png
:figclass: align-center
Using the PyLammps / IPyLammps wrappers
Third, LAMMPS can use the Python interpreter, so that a LAMMPS input
Second, LAMMPS can use the Python interpreter, so that a LAMMPS input
script or styles can invoke Python code directly, and pass information
back-and-forth between the input script and Python functions you write.
This Python code can also call back to LAMMPS to query or change its

View File

@ -2,14 +2,8 @@ System properties
=================
Similar to what is described in :doc:`Library_properties`, the instances of
:py:class:`lammps <lammps.lammps>`, :py:class:`PyLammps <lammps.PyLammps>`, or
:py:class:`IPyLammps <lammps.IPyLammps>` can be used to extract different kinds
of information about the active LAMMPS instance and also to modify some of it. The
main difference between the interfaces is how the information is exposed.
While the :py:class:`lammps <lammps.lammps>` is just a thin layer that wraps C API calls,
:py:class:`PyLammps <lammps.PyLammps>` and :py:class:`IPyLammps <lammps.IPyLammps>` expose
information as objects and properties.
:py:class:`lammps <lammps.lammps>` can be used to extract different kinds
of information about the active LAMMPS instance and also to modify some of it.
In some cases the data returned is a direct reference to the original data
inside LAMMPS cast to ``ctypes`` pointers. Where possible, the wrappers will
@ -25,113 +19,38 @@ against invalid accesses.
accordingly. These arrays can change sizes and order at every neighbor list
rebuild and atom sort event as atoms are migrating between subdomains.
.. tabs::
.. code-block:: python
.. tab:: lammps API
from lammps import lammps
.. code-block:: python
lmp = lammps()
lmp.file("in.sysinit")
from lammps import lammps
natoms = lmp.get_natoms()
print(f"running simulation with {natoms} atoms")
lmp = lammps()
lmp.file("in.sysinit")
lmp.command("run 1000 post no");
natoms = lmp.get_natoms()
print(f"running simulation with {natoms} atoms")
for i in range(10):
lmp.command("run 100 pre no post no")
pe = lmp.get_thermo("pe")
ke = lmp.get_thermo("ke")
print(f"PE = {pe}\nKE = {ke}")
lmp.command("run 1000 post no");
lmp.close()
for i in range(10):
lmp.command("run 100 pre no post no")
pe = lmp.get_thermo("pe")
ke = lmp.get_thermo("ke")
print(f"PE = {pe}\nKE = {ke}")
**Methods**:
lmp.close()
* :py:meth:`version() <lammps.lammps.version()>`: return the numerical version id, e.g. LAMMPS 2 Sep 2015 -> 20150902
* :py:meth:`get_thermo() <lammps.lammps.get_thermo()>`: return current value of a thermo keyword
* :py:meth:`last_thermo() <lammps.lammps.last_thermo()>`: return a dictionary of the last thermodynamic output
* :py:meth:`get_natoms() <lammps.lammps.get_natoms()>`: total # of atoms as int
* :py:meth:`reset_box() <lammps.lammps.reset_box()>`: reset the simulation box size
* :py:meth:`extract_setting() <lammps.lammps.extract_setting()>`: return a global setting
* :py:meth:`extract_global() <lammps.lammps.extract_global()>`: extract a global quantity
* :py:meth:`extract_box() <lammps.lammps.extract_box()>`: extract box info
* :py:meth:`create_atoms() <lammps.lammps.create_atoms()>`: create N atoms with IDs, types, x, v, and image flags
**Methods**:
**Properties**:
* :py:meth:`version() <lammps.lammps.version()>`: return the numerical version id, e.g. LAMMPS 2 Sep 2015 -> 20150902
* :py:meth:`get_thermo() <lammps.lammps.get_thermo()>`: return current value of a thermo keyword
* :py:meth:`last_thermo() <lammps.lammps.last_thermo()>`: return a dictionary of the last thermodynamic output
* :py:meth:`get_natoms() <lammps.lammps.get_natoms()>`: total # of atoms as int
* :py:meth:`reset_box() <lammps.lammps.reset_box()>`: reset the simulation box size
* :py:meth:`extract_setting() <lammps.lammps.extract_setting()>`: return a global setting
* :py:meth:`extract_global() <lammps.lammps.extract_global()>`: extract a global quantity
* :py:meth:`extract_box() <lammps.lammps.extract_box()>`: extract box info
* :py:meth:`create_atoms() <lammps.lammps.create_atoms()>`: create N atoms with IDs, types, x, v, and image flags
**Properties**:
* :py:attr:`last_thermo_step <lammps.lammps.last_thermo_step>`: the last timestep thermodynamic output was computed
.. tab:: PyLammps/IPyLammps API
In addition to the functions provided by :py:class:`lammps <lammps.lammps>`, :py:class:`PyLammps <lammps.PyLammps>` objects
have several properties which allow you to query the system state:
L.system
Is a dictionary describing the system such as the bounding box or number of atoms
L.system.xlo, L.system.xhi
bounding box limits along x-axis
L.system.ylo, L.system.yhi
bounding box limits along y-axis
L.system.zlo, L.system.zhi
bounding box limits along z-axis
L.communication
configuration of communication subsystem, such as the number of threads or processors
L.communication.nthreads
number of threads used by each LAMMPS process
L.communication.nprocs
number of MPI processes used by LAMMPS
L.fixes
List of fixes in the current system
L.computes
List of active computes in the current system
L.dump
List of active dumps in the current system
L.groups
List of groups present in the current system
**Retrieving the value of an arbitrary LAMMPS expressions**
LAMMPS expressions can be immediately evaluated by using the ``eval`` method. The
passed string parameter can be any expression containing global :doc:`thermo` values,
variables, compute or fix data (see :doc:`Howto_output`):
.. code-block:: python
result = L.eval("ke") # kinetic energy
result = L.eval("pe") # potential energy
result = L.eval("v_t/2.0")
**Example**
.. code-block:: python
from lammps import PyLammps
L = PyLammps()
L.file("in.sysinit")
print(f"running simulation with {L.system.natoms} atoms")
L.run(1000, "post no");
for i in range(10):
L.run(100, "pre no post no")
pe = L.eval("pe")
ke = L.eval("ke")
print(f"PE = {pe}\nKE = {ke}")
* :py:attr:`last_thermo_step <lammps.lammps.last_thermo_step>`: the last timestep thermodynamic output was computed

94
doc/src/angle_mwlc.rst Normal file
View File

@ -0,0 +1,94 @@
.. index:: angle_style mwlc
angle_style mwlc command
==========================
Syntax
""""""
.. code-block:: LAMMPS
angle_style mwlc
Examples
""""""""
.. code-block:: LAMMPS
angle_style mwlc
angle_coeff * 25 1 10 1
Description
"""""""""""
.. versionadded:: TBD
The *mwlc* angle style models a meltable wormlike chain and can be used
to model non-linear bending elasticity of polymers, e.g. DNA. *mwlc*
uses a potential that is a canonical-ensemble superposition of a
non-melted and a melted state :ref:`(Farrell) <Farrell>`. The potential
is
.. math::
E = -k_{B}T\,\log [q + q^{m}] + E_{0},
where the non-melted and melted partition functions are
.. math::
q = \exp [-k_{1}(1+\cos{\theta})/k_{B}T]; \\
q^{m} = \exp [-(\mu+k_{2}(1+\cos{\theta}))/k_{B}T].
:math:`k_1` is the bending elastic constant of the non-melted state,
:math:`k_2` is the bending elastic constant of the melted state,
:math:`\mu` is the melting energy, and
:math:`T` is the reference temperature.
The reference energy,
.. math::
E_{0} = -k_{B}T\,\log [1 + \exp[-\mu/k_{B}T]],
ensures that E is zero for a fully extended chain.
This potential is a continuous version of the two-state potential
introduced by :ref:`(Yan) <Yan>`.
The following coefficients must be defined for each angle type via the
:doc:`angle_coeff <angle_coeff>` command as in the example above, or in
the data file or restart files read by the :doc:`read_data <read_data>`
or :doc:`read_restart <read_restart>` commands:
* :math:`k_1` (energy)
* :math:`k_2` (energy)
* :math:`\mu` (energy)
* :math:`T` (temperature)
----------
Restrictions
""""""""""""
This angle style can only be used if LAMMPS was built with the
EXTRA-MOLECULE package. See the :doc:`Build package <Build_package>`
doc page for more info.
Related commands
""""""""""""""""
:doc:`angle_coeff <angle_coeff>`
Default
"""""""
none
----------
.. _Farrell:
**(Farrell)** `Farrell, Dobnikar, Podgornik, Curk, Phys Rev Lett, 133, 148101 (2024). <https://doi.org/10.1103/PhysRevLett.133.148101>`_
.. _Yan:
**(Yan)** `Yan, Marko, Phys Rev Lett, 93, 108108 (2004). <https://doi.org/10.1103/PhysRevLett.93.108108>`_

View File

@ -94,6 +94,7 @@ of (g,i,k,o,t) to indicate which accelerated styles exist.
* :doc:`lepton <angle_lepton>` - angle potential from evaluating a string
* :doc:`mesocnt <angle_mesocnt>` - piecewise harmonic and linear angle for bending-buckling of nanotubes
* :doc:`mm3 <angle_mm3>` - anharmonic angle
* :doc:`mwlc <angle_mwlc>` - meltable wormlike chain
* :doc:`quartic <angle_quartic>` - angle with cubic and quartic terms
* :doc:`spica <angle_spica>` - harmonic angle with repulsive SPICA pair style between 1-3 atoms
* :doc:`table <angle_table>` - tabulated by angle

View File

@ -406,6 +406,8 @@ sub-style name. The angle styles that currently work with fix adapt are:
+--------------------------------------------------------------------+--------------------+-------------+
| :doc:`mm3 <angle_mm3>` | k,theta0 | type angles |
+--------------------------------------------------------------------+--------------------+-------------+
| :doc:`mwlc <angle_mwlc>` | k1,k2,mu,T | type angles |
+--------------------------------------------------------------------+--------------------+-------------+
| :doc:`quartic <angle_quartic>` | k2,k3,k4,theta0 | type angles |
+--------------------------------------------------------------------+--------------------+-------------+
| :doc:`spica <angle_spica>` | k,theta0 | type angles |

View File

@ -71,9 +71,9 @@ Syntax
feature functions = is_available(category,feature), is_active(category,feature), is_defined(category,id)
atom value = id[i], mass[i], type[i], mol[i], x[i], y[i], z[i], vx[i], vy[i], vz[i], fx[i], fy[i], fz[i], q[i]
atom vector = id, mass, type, mol, radius, q, x, y, z, vx, vy, vz, fx, fy, fz
custom atom property = i_name, d_name, i_name[i], d_name[i], i2_name[i], d2_name[i], i2_name[i][j], d_name[i][j]
compute references = c_ID, c_ID[i], c_ID[i][j], C_ID, C_ID[i]
fix references = f_ID, f_ID[i], f_ID[i][j], F_ID, F_ID[i]
custom atom property = i_name, d_name, i_name[i], d_name[i], i2_name[i], d2_name[i], i2_name[i][j], d2_name[i][j]
compute references = c_ID, c_ID[i], c_ID[i][j], C_ID, C_ID[i], C_ID[i][j]
fix references = f_ID, f_ID[i], f_ID[i][j], F_ID, F_ID[i], F_ID[i][j]
variable references = v_name, v_name[i]
vector initialization = [1,3,7,10] (for *vector* variables only)

View File

@ -9,3 +9,4 @@ Pygments
six
pyyaml
linkchecker
ipython

View File

@ -2116,6 +2116,7 @@ Marchi
Mariella
Marinica
Markland
Marko
Marrink
Marroquin
Marsaglia
@ -2198,6 +2199,7 @@ Meissner
Melchor
Meloni
Melrose
meltable
mem
Mem
memalign
@ -2408,6 +2410,7 @@ mV
Mvapich
mvh
mvv
mwlc
MxN
myCompute
myIndex
@ -2929,6 +2932,7 @@ Pmoltrans
pN
png
podd
Podgornik
Podhorszki
Poiseuille
poisson
@ -4113,6 +4117,7 @@ workflow
workflows
Workum
Worley
wormlike
Wriggers
writedata
Wuppertal
@ -4181,6 +4186,7 @@ yaff
YAFF
Yamada
yaml
Yan
Yanxon
Yaser
Yazdani

View File

@ -18,11 +18,11 @@ from install_helpers import fullpath, geturl, checkmd5sum, getfallback
# settings
thisdir = fullpath('.')
version ='v.2023.11.25.fix'
version ='v.2023.11.25.fix2'
# known checksums for different PACE versions. used to validate the download.
checksums = { \
'v.2023.11.25.fix': 'b45de9a633f42ed65422567e3ce56f9f'
'v.2023.11.25.fix2': 'a53bd87cfee8b07d9f44bc17aad69c3f'
}
parser = ArgumentParser(prog='Install.py', description="LAMMPS library build wrapper script")

View File

@ -1,10 +1,10 @@
# PyLammps and Jupyter Notebooks
# IPython and Jupyter Notebooks
This folder contains examples showcasing the usage of the PyLammps Python
This folder contains examples showcasing the usage of the LAMMPS Python
interface and Jupyter notebooks. To use this you will need LAMMPS compiled as
a shared library and the LAMMPS Python package installed.
An extensive guide on how to achieve this is documented in the [LAMMPS manual](https://docs.lammps.org/Python_install.html). There is also a [PyLammps tutorial](https://docs.lammps.org/Howto_pylammps.html).
An extensive guide on how to achieve this is documented in the [LAMMPS manual](https://docs.lammps.org/Python_install.html). There is also a [LAMMPS Python tutorial](https://docs.lammps.org/Howto_python.html).
The following will show one way of creating a Python virtual environment
which has both LAMMPS and its Python package installed:
@ -53,7 +53,7 @@ which has both LAMMPS and its Python package installed:
```shell
(myenv)$ cmake -C ../cmake/presets/basic.cmake \
-D BUILD_SHARED_LIBS=on \
-D LAMMPS_EXCEPTIONS=on -D PKG_PYTHON=on \
-D PKG_PYTHON=on \
-D CMAKE_INSTALL_PREFIX=$VIRTUAL_ENV \
../cmake
```
@ -67,19 +67,19 @@ which has both LAMMPS and its Python package installed:
8. Install LAMMPS and Python package into virtual environment
```shell
(myenv)$ cmake --install .
(myenv)$ make install-python
```
9. Install other Python packages into virtual environment
```shell
(myenv)$ pip install jupyter matplotlib mpi4py
(myenv)$ pip install jupyter matplotlib pandas mpi4py
```
10. Navigate to pylammps examples folder
10. Navigate to ipython examples folder
```shell
(myenv)$ cd ../python/examples/pylammmps
(myenv)$ cd ../python/examples/ipython
```
11. Launch Jupyter and work inside browser

View File

@ -0,0 +1,224 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<div style=\"text-align: center\"><a href=\"index.ipynb\">LAMMPS Python Tutorials</a></div>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Example 3: Working with Per-Atom Data"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Author: [Richard Berger](mailto:richard.berger@outlook.com)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"2D circle of particles inside of box with LJ walls"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Setup system"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from lammps import lammps"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L = lammps()\n",
"cmd = L.cmd"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# 2d circle of particles inside a box with LJ walls\n",
"import math\n",
"\n",
"b = 0\n",
"x = 50\n",
"y = 20\n",
"d = 20\n",
"\n",
"# careful not to slam into wall too hard\n",
"\n",
"v = 0.3\n",
"w = 0.08\n",
" \n",
"cmd.units(\"lj\")\n",
"cmd.dimension(2)\n",
"cmd.atom_style(\"bond\")\n",
"cmd.boundary(\"f f p\")\n",
"\n",
"cmd.lattice(\"hex\", 0.85)\n",
"cmd.region(\"box\", \"block\", 0, x, 0, y, -0.5, 0.5)\n",
"cmd.create_box(1, \"box\", \"bond/types\", 1, \"extra/bond/per/atom\", 6)\n",
"cmd.region(\"circle\", \"sphere\", d/2.0+1.0, d/2.0/math.sqrt(3.0)+1, 0.0, d/2.0)\n",
"cmd.create_atoms(1, \"region\", \"circle\")\n",
"cmd.mass(1, 1.0)\n",
"\n",
"cmd.velocity(\"all create 0.5 87287 loop geom\")\n",
"cmd.velocity(\"all set\", v, w, 0, \"sum yes\")\n",
"\n",
"cmd.pair_style(\"lj/cut\", 2.5)\n",
"cmd.pair_coeff(1, 1, 10.0, 1.0, 2.5)\n",
"\n",
"cmd.bond_style(\"harmonic\")\n",
"cmd.bond_coeff(1, 10.0, 1.2)\n",
"\n",
"cmd.create_bonds(\"many\", \"all\", \"all\", 1, 1.0, 1.5)\n",
"\n",
"cmd.neighbor(0.3, \"bin\")\n",
"cmd.neigh_modify(\"delay\", 0, \"every\", 1, \"check yes\")\n",
"\n",
"cmd.fix(1, \"all\", \"nve\")\n",
"\n",
"cmd.fix(2, \"all wall/lj93 xlo 0.0 1 1 2.5 xhi\", x, \"1 1 2.5\")\n",
"cmd.fix(3, \"all wall/lj93 ylo 0.0 1 1 2.5 yhi\", y, \"1 1 2.5\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Visualize initial state"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.ipython.image(zoom=1.8)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Run simulation and visualize new state"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"cmd.thermo_style(\"custom step temp epair press\")\n",
"cmd.thermo(100)\n",
"output = cmd.run(40000)\n",
"L.ipython.image(zoom=1.8)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Accessing Atom data"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.numpy.extract_atom(\"x\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.numpy.extract_atom(\"id\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.numpy.extract_atom(\"v\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.numpy.extract_atom(\"f\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.numpy.extract_atom(\"type\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.7"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

View File

@ -4,7 +4,14 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"# Validating a dihedral potential"
"<div style=\"text-align: center\"><a href=\"../index.ipynb\">LAMMPS Python Tutorials</a></div>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Example 4: Validating a dihedral potential"
]
},
{
@ -13,7 +20,8 @@
"metadata": {},
"outputs": [],
"source": [
"%matplotlib notebook"
"import matplotlib.pyplot as plt\n",
"from lammps import lammps"
]
},
{
@ -22,25 +30,8 @@
"metadata": {},
"outputs": [],
"source": [
"import matplotlib.pyplot as plt"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from lammps import IPyLammps"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L = IPyLammps()"
"L = lammps()\n",
"cmd = L.cmd"
]
},
{
@ -51,13 +42,13 @@
"source": [
"import math\n",
"\n",
"L.units(\"real\")\n",
"L.atom_style(\"molecular\")\n",
"cmd.units(\"real\")\n",
"cmd.atom_style(\"molecular\")\n",
"\n",
"L.boundary(\"f f f\")\n",
"L.neighbor(0.3, \"bin\")\n",
"cmd.boundary(\"f f f\")\n",
"cmd.neighbor(0.3, \"bin\")\n",
"\n",
"L.dihedral_style(\"harmonic\")"
"cmd.dihedral_style(\"harmonic\")"
]
},
{
@ -66,7 +57,7 @@
"metadata": {},
"outputs": [],
"source": [
"L.read_data(\"data.dihedral\")"
"cmd.read_data(\"data.dihedral\")"
]
},
{
@ -75,8 +66,8 @@
"metadata": {},
"outputs": [],
"source": [
"L.pair_style(\"zero\", 5)\n",
"L.pair_coeff(\"*\", \"*\")"
"cmd.pair_style(\"zero\", 5)\n",
"cmd.pair_coeff(\"*\", \"*\")"
]
},
{
@ -85,7 +76,7 @@
"metadata": {},
"outputs": [],
"source": [
"L.mass(1, 1.0)"
"cmd.mass(1, 1.0)"
]
},
{
@ -94,7 +85,7 @@
"metadata": {},
"outputs": [],
"source": [
"L.velocity(\"all\", \"set\", 0.0, 0.0, 0.0)"
"cmd.velocity(\"all\", \"set\", 0.0, 0.0, 0.0)"
]
},
{
@ -103,7 +94,7 @@
"metadata": {},
"outputs": [],
"source": [
"L.run(0);"
"cmd.run(0, \"post\", \"no\");"
]
},
{
@ -112,7 +103,7 @@
"metadata": {},
"outputs": [],
"source": [
"L.image(zoom=1.0)"
"L.ipython.image(zoom=1.0,size=[320,320])"
]
},
{
@ -121,7 +112,8 @@
"metadata": {},
"outputs": [],
"source": [
"L.atoms[3].position"
"x = L.numpy.extract_atom(\"x\")\n",
"print(x[3])"
]
},
{
@ -130,7 +122,7 @@
"metadata": {},
"outputs": [],
"source": [
"L.atoms[3].position = (1.0, 0.0, 1.0)"
"x[3] = (1.0, 0.0, 1.0)"
]
},
{
@ -139,7 +131,7 @@
"metadata": {},
"outputs": [],
"source": [
"L.image(zoom=1.0)"
"L.ipython.image(zoom=1.0,size=[320,320])"
]
},
{
@ -148,7 +140,7 @@
"metadata": {},
"outputs": [],
"source": [
"L.eval(\"pe\")"
"L.get_thermo(\"pe\")"
]
},
{
@ -157,7 +149,7 @@
"metadata": {},
"outputs": [],
"source": [
"L.atoms[3].position = (1.0, 0.0, -1.0)"
"x[3] = (1.0, 0.0, -1.0)"
]
},
{
@ -166,7 +158,7 @@
"metadata": {},
"outputs": [],
"source": [
"L.run(0);"
"cmd.run(0, \"post\", \"no\")"
]
},
{
@ -207,9 +199,9 @@
"source": [
"pe = []\n",
"for p in pos:\n",
" L.atoms[3].position = p\n",
" L.run(0);\n",
" pe.append(L.eval(\"pe\"))"
" x[3] = p\n",
" cmd.run(0, \"post\", \"no\");\n",
" pe.append(L.get_thermo(\"pe\"))"
]
},
{
@ -233,7 +225,7 @@
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
@ -247,9 +239,9 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.2"
"version": "3.12.7"
}
},
"nbformat": 4,
"nbformat_minor": 1
"nbformat_minor": 4
}

View File

@ -158,7 +158,8 @@ def elastic():
parser.add_argument("--up", type=float, default=1.0e-6, help="the deformation magnitude (in strain units)")
args = parser.parse_args()
L = PyLammps()
lmp = lammps()
L = lmp.cmd
L.units("metal")

View File

@ -0,0 +1,63 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "666d3036-47d5-44d2-bc1a-ca4b00a9e9b8",
"metadata": {},
"source": [
"# LAMMPS Python Tutorials"
]
},
{
"cell_type": "markdown",
"id": "f1422a43-f76b-456b-bf76-61ad92bd4ff0",
"metadata": {},
"source": [
"Author: [Richard Berger](mailto:richard.berger@outlook.com)"
]
},
{
"cell_type": "markdown",
"id": "8f2ea92d-8cc3-4999-81a0-79aa55bb66ab",
"metadata": {},
"source": [
"## Contents\n",
"\n",
"- [Example 1: Using LAMMPS with Python](simple.ipynb)\n",
"- [Example 2: Analyzing LAMMPS thermodynamic data](thermo.ipynb)\n",
"- [Example 3: Using Atom Data](atoms.ipynb)\n",
"- [Example 4: Validating a dihedral potential](dihedrals/dihedral.ipynb)\n",
"- [Example 5: Running a Monte Carlo relaxation](montecarlo/mc.ipynb)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b41dc533-be6d-4450-8ad7-7345e9f44ea3",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.7"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@ -4,7 +4,14 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"# Monte Carlo Relaxation"
"<div style=\"text-align: center\"><a href=\"../index.ipynb\">LAMMPS Python Tutorials</a></div>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Example 5: Monte Carlo Relaxation"
]
},
{
@ -13,16 +20,6 @@
"metadata": {},
"outputs": [],
"source": [
"from __future__ import print_function"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"%matplotlib inline\n",
"import matplotlib.pyplot as plt"
]
},
@ -48,7 +45,7 @@
"metadata": {},
"outputs": [],
"source": [
"from lammps import IPyLammps"
"from lammps import lammps"
]
},
{
@ -57,7 +54,8 @@
"metadata": {},
"outputs": [],
"source": [
"L = IPyLammps()"
"L = lammps()\n",
"cmd = L.cmd"
]
},
{
@ -66,25 +64,25 @@
"metadata": {},
"outputs": [],
"source": [
"L.units(\"lj\")\n",
"L.atom_style(\"atomic\")\n",
"L.atom_modify(\"map array sort\", 0, 0.0)\n",
"cmd.units(\"lj\")\n",
"cmd.atom_style(\"atomic\")\n",
"cmd.atom_modify(\"map array sort\", 0, 0.0)\n",
"\n",
"L.dimension(2)\n",
"cmd.dimension(2)\n",
"\n",
"L.lattice(\"hex\", 1.0)\n",
"L.region(\"box block\", 0, 10, 0, 5, -0.5, 0.5)\n",
"cmd.lattice(\"hex\", 1.0)\n",
"cmd.region(\"box block\", 0, 10, 0, 5, -0.5, 0.5)\n",
"\n",
"L.create_box(1, \"box\")\n",
"L.create_atoms(1, \"box\")\n",
"L.mass(1, 1.0)\n",
"cmd.create_box(1, \"box\")\n",
"cmd.create_atoms(1, \"box\")\n",
"cmd.mass(1, 1.0)\n",
"\n",
"L.pair_style(\"lj/cut\", 2.5)\n",
"L.pair_coeff(1, 1, 1.0, 1.0, 2.5)\n",
"L.pair_modify(\"shift\", \"yes\")\n",
"cmd.pair_style(\"lj/cut\", 2.5)\n",
"cmd.pair_coeff(1, 1, 1.0, 1.0, 2.5)\n",
"cmd.pair_modify(\"shift\", \"yes\")\n",
"\n",
"L.neighbor(0.3, \"bin\")\n",
"L.neigh_modify(\"delay\", 0, \"every\", 1, \"check\", \"yes\")"
"cmd.neighbor(0.3, \"bin\")\n",
"cmd.neigh_modify(\"delay\", 0, \"every\", 1, \"check\", \"yes\")"
]
},
{
@ -93,7 +91,7 @@
"metadata": {},
"outputs": [],
"source": [
"L.image(zoom=1.6)"
"L.ipython.image(zoom=1.6,size=[320,320])"
]
},
{
@ -102,7 +100,7 @@
"metadata": {},
"outputs": [],
"source": [
"L.run(0);"
"cmd.run(0, \"post\", \"no\")"
]
},
{
@ -111,7 +109,7 @@
"metadata": {},
"outputs": [],
"source": [
"emin = L.eval(\"pe\")"
"emin = L.get_thermo(\"pe\")"
]
},
{
@ -120,7 +118,7 @@
"metadata": {},
"outputs": [],
"source": [
"L.dump(\"3 all movie 25 movie.mp4 type type zoom 1.6 adiam 1.0\")"
"cmd.dump(\"3 all movie 25 movie.mp4 type type zoom 1.6 adiam 1.0\")"
]
},
{
@ -146,11 +144,12 @@
"metadata": {},
"outputs": [],
"source": [
"for i in range(L.system.natoms):\n",
" x, y = L.atoms[i].position\n",
"pos = L.numpy.extract_atom(\"x\")\n",
"for i in range(len(pos)):\n",
" x, y = pos[i][0], pos[i][1]\n",
" dx = deltaperturb * random.uniform(-1, 1)\n",
" dy = deltaperturb * random.uniform(-1, 1)\n",
" L.atoms[i].position = (x+dx, y+dy)"
" pos[i] = (x+dx, y+dy, 0)"
]
},
{
@ -159,7 +158,7 @@
"metadata": {},
"outputs": [],
"source": [
"L.run(0);"
"cmd.run(0, \"post\", \"no\")"
]
},
{
@ -168,7 +167,7 @@
"metadata": {},
"outputs": [],
"source": [
"L.image(zoom=1.6)"
"L.ipython.image(zoom=1.6,size=[320,320])"
]
},
{
@ -184,7 +183,7 @@
"metadata": {},
"outputs": [],
"source": [
"estart = L.eval(\"pe\")\n",
"estart = L.get_thermo(\"pe\")\n",
"elast = estart"
]
},
@ -223,22 +222,23 @@
"metadata": {},
"outputs": [],
"source": [
"natoms = L.system.natoms\n",
"natoms = L.extract_global(\"natoms\")\n",
"\n",
"for i in range(niterations):\n",
" pos = L.numpy.extract_atom(\"x\")\n",
" iatom = random.randrange(0, natoms)\n",
" current_atom = L.atoms[iatom]\n",
" current_atom = pos[iatom]\n",
" \n",
" x0, y0 = current_atom.position\n",
" x0, y0 = current_atom[0], current_atom[1]\n",
" \n",
" dx = deltamove * random.uniform(-1, 1)\n",
" dy = deltamove * random.uniform(-1, 1)\n",
" \n",
" current_atom.position = (x0+dx, y0+dy)\n",
" pos[iatom] = (x0+dx, y0+dy, 0)\n",
" \n",
" L.run(1, \"pre no post no\")\n",
" cmd.run(1, \"pre no post no\")\n",
" \n",
" e = L.eval(\"pe\")\n",
" e = L.get_thermo(\"pe\")\n",
" energies.append(e)\n",
" \n",
" if e <= elast:\n",
@ -248,7 +248,7 @@
" naccept += 1\n",
" elast = e\n",
" else:\n",
" current_atom.position = (x0, y0)"
" pos[iatom] = (x0, y0, 0)"
]
},
{
@ -268,7 +268,7 @@
"metadata": {},
"outputs": [],
"source": [
"L.eval(\"pe\")"
"L.get_thermo(\"pe\")"
]
},
{
@ -304,7 +304,7 @@
"metadata": {},
"outputs": [],
"source": [
"L.image(zoom=1.6)"
"L.ipython.image(zoom=1.6, size=[320,320])"
]
},
{
@ -314,7 +314,7 @@
"outputs": [],
"source": [
"# close dump file to access it\n",
"L.undump(3)"
"cmd.undump(3)"
]
},
{
@ -323,7 +323,7 @@
"metadata": {},
"outputs": [],
"source": [
"L.video(\"movie.mp4\")"
"L.ipython.video(\"movie.mp4\")"
]
},
{
@ -336,7 +336,7 @@
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
@ -350,9 +350,9 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.2"
"version": "3.12.7"
}
},
"nbformat": 4,
"nbformat_minor": 1
"nbformat_minor": 4
}

View File

@ -1,10 +1,10 @@
from mpi4py import MPI
from lammps import PyLammps
from lammps import lammps
L = PyLammps()
L = lammps()
L.file('in.melt')
if MPI.COMM_WORLD.rank == 0:
pe = L.eval("pe")
pe = L.get_thermo("pe")
print("Potential Energy:", pe)

View File

@ -4,14 +4,28 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"# Example 1: Using LAMMPS with PyLammps"
"<div style=\"text-align: center\"><a href=\"index.ipynb\">LAMMPS Python Tutorials</a></div>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The LAMMPS Python package provides multiple interfaces. The `PyLammps` interface is a high-level abstration of the low-level `lammps` interface. `IPyLammps` further extends this interface with functions that are useful for Jupyter notebooks to enable embedding generated graphics and videos."
"# Example 1: Using LAMMPS with Python"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Author: [Richard Berger](mailto:richard.berger@outlook.com)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The LAMMPS Python package enables calling the LAMMPS C library API."
]
},
{
@ -20,7 +34,7 @@
"source": [
"## Prerequisites\n",
"\n",
"Before Running this example, make sure your Python environment can find the LAMMPS shared library (`liblammps.so`) and the LAMMPS Python package is installed. If you followed the [README](README.md) in this folder, this should already be the case. You can also find more information about how to compile LAMMPS and install the LAMMPS Python package in the [LAMMPS manual](https://docs.lammps.org/Python_install.html). There is also a dedicated [PyLammps HowTo](https://docs.lammps.org/Howto_pylammps.html)."
"Before running this example, make sure your Python environment can find the LAMMPS shared library (`liblammps.so`) and the LAMMPS Python package is installed. If you followed the [README](README.md) in this folder, this should already be the case. You can also find more information about how to compile LAMMPS and install the LAMMPS Python package in the [LAMMPS manual](https://docs.lammps.org/Python_install.html). There is also a dedicated [LAMMPS Python HowTo](https://docs.lammps.org/Howto_python.html)."
]
},
{
@ -38,17 +52,17 @@
"metadata": {},
"outputs": [],
"source": [
"from lammps import IPyLammps\n",
"L = IPyLammps()"
"from lammps import lammps\n",
"L = lammps()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"With `PyLammps`/`IPyLammps` you can write LAMMPS simulations similar to the input script language. Take the following LAMMPS input script:\n",
"With the `lammps` class you can write LAMMPS simulations similar to the input script language. Take the following LAMMPS input script:\n",
"\n",
"```bash\n",
"```lammps\n",
"# 3d Lennard-Jones melt\n",
"\n",
"units lj\n",
@ -72,7 +86,7 @@
"\n",
"thermo 50\n",
"```\n",
"The equivalent can be written with `PyLammps`/`IPyLammps`:"
"The equivalent can be written in Python:"
]
},
{
@ -83,35 +97,33 @@
"source": [
"# 3d Lennard-Jones melt\n",
"\n",
"L.units(\"lj\")\n",
"L.atom_style(\"atomic\")\n",
"L.cmd.units(\"lj\")\n",
"L.cmd.atom_style(\"atomic\")\n",
"\n",
"L.lattice(\"fcc\", 0.8442)\n",
"L.region(\"box\", \"block\", 0, 4, 0, 4, 0, 4)\n",
"L.create_box(1, \"box\")\n",
"L.create_atoms(1, \"box\")\n",
"L.mass(1, 1.0)\n",
"L.cmd.lattice(\"fcc\", 0.8442)\n",
"L.cmd.region(\"box\", \"block\", 0, 4, 0, 4, 0, 4)\n",
"L.cmd.create_box(1, \"box\")\n",
"L.cmd.create_atoms(1, \"box\")\n",
"L.cmd.mass(1, 1.0)\n",
"\n",
"L.velocity(\"all\", \"create\", 1.44, 87287, \"loop geom\")\n",
"L.cmd.velocity(\"all\", \"create\", 1.44, 87287, \"loop geom\")\n",
"\n",
"L.pair_style(\"lj/cut\", 2.5)\n",
"L.pair_coeff(1, 1, 1.0, 1.0, 2.5)\n",
"L.cmd.pair_style(\"lj/cut\", 2.5)\n",
"L.cmd.pair_coeff(1, 1, 1.0, 1.0, 2.5)\n",
"\n",
"L.neighbor(0.3, \"bin\")\n",
"L.neigh_modify(\"delay\", 0, \"every\", 20, \"check no\")\n",
"L.cmd.neighbor(0.3, \"bin\")\n",
"L.cmd.neigh_modify(\"delay\", 0, \"every\", 20, \"check no\")\n",
"\n",
"L.fix(\"1\", \"all\", \"nve\")\n",
"L.cmd.fix(\"1\", \"all\", \"nve\")\n",
"\n",
"L.thermo(50)"
"L.cmd.thermo(50)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Visualizing the initial state\n",
"\n",
"`IPyLammps` allows you to visualize the current simulation state with the [image](https://docs.lammps.org/Python_module.html#lammps.IPyLammps.image) command. Here we use it to create an image of the initial state of the system."
"Some LAMMPS commands will produce output that will be visible in the notebook. However, due to buffering, it might not be shown right away. Use the `flush_buffers` method to see all the output that has been written so far."
]
},
{
@ -120,7 +132,109 @@
"metadata": {},
"outputs": [],
"source": [
"L.image(zoom=1.0)"
"L.flush_buffers()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"An alternative to this is to enable auto flushing after each command by setting `cmd.auto_flush` to `True`. Each command will then call `flush_buffers()` automatically."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.cmd.auto_flush = True\n",
"L.cmd.info(\"system\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In many cases the LAMMPS output will become excessive, which is why you may want to suppress it. For this purpose we provide a IPython extension in the `lammps.ipython` package. To load the extension, add a code cell with the following content:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"%load_ext lammps.ipython"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Once the extension is loaded you have access to the `%%capture_lammps_output` magic. In its simplest form it can be used to supress LAMMPS output:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"%%capture_lammps_output\n",
"L.cmd.info(\"system\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"You can also use the same `%%capture_lammps_output` magic to store the output in a variable by providing a variable name:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"%%capture_lammps_output out\n",
"L.cmd.info(\"system\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In this case we are storing the output in a `out` variable. Note the output is only available after the cell has been executed, not within the same cell."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"print(out)"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"## Visualizing the initial state\n",
"\n",
"The `lammps` class also has an `ipython` attribute which provides some basic visualization capabilities in IPython Jupyter notebooks. E.g., you can visualize the current simulation state with the [image](https://docs.lammps.org/Python_module.html#lammps.ipython_wrapper.image) command. Here we use it to create an image of the initial state of the system."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.ipython.image()"
]
},
{
@ -129,7 +243,7 @@
"source": [
"## Running simulations\n",
"\n",
"Use the `run` command to start the simulation. In Jupyter the return value of the last command will be displayed. The `run` command will return the output of the simulation."
"Use the `run` command to start the simulation. It will print the output of the simulation."
]
},
{
@ -138,23 +252,7 @@
"metadata": {},
"outputs": [],
"source": [
"L.run(150)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"You can suppress it by adding a semicolon `;`."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.run(100);"
"L.cmd.run(250)"
]
},
{
@ -170,127 +268,23 @@
"metadata": {},
"outputs": [],
"source": [
"L.image(zoom=1.0)"
"L.ipython.image(zoom=1.0)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Post-processing thermo output\n",
"## Conclusion\n",
"This covered the basics of creating an instance of LAMMPS from Python, passing commands to LAMMPS and potentially supressing or capturing its output, and visualizing the system. In the [following tutorial](thermo.ipynb) we will look at how to process thermodynamic output from LAMMPS.\n",
"\n",
"Independent of whether or not you suppress or show the output of the `run` command, `PyLammps` will record the output. Each `run` command creates a new entry in the `L.runs` list. So far our PyLammps instance `L` executed two `run` commands:"
"<div style=\"text-align:right\"><a href=\"thermo.ipynb\">Next</a>"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"len(L.runs)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Each entry contains information about the simulation run, including the thermo output for the printed out time steps.\n",
"\n",
"```bash\n",
"# thermo output of a LAMMPS simulation run\n",
"Step Temp E_pair E_mol TotEng Press\n",
" 0 1.44 -6.7733681 0 -4.6218056 -5.0244179\n",
" 50 0.70303849 -5.6796164 0 -4.629178 0.50453907\n",
" 100 0.72628044 -5.7150774 0 -4.6299123 0.29765862\n",
" 150 0.78441711 -5.805142 0 -4.6331125 -0.086709661\n",
"```\n",
"\n",
"`PyLammps` already parses this information and makes it available as dictionaries and arrays."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.runs[0]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.runs[1]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"For example, the first run was 150 time steps, with printing out a line every 50 steps. You can access the list of time steps using `{entry}.thermo.Step`."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.runs[0].thermo.Step"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The corresponding values of each thermo quantity are also accessed this way:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.runs[0].thermo.TotEng"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Together you can use this information to run post-processing on these values or even plot it using `matplotlib`:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"%matplotlib inline\n",
"import matplotlib.pyplot as plt\n",
"\n",
"plt.xlabel('time step')\n",
"plt.ylabel('Total Energy')\n",
"plt.plot(L.runs[0].thermo.Step, L.runs[0].thermo.TotEng)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
@ -304,9 +298,9 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.2"
"version": "3.12.7"
}
},
"nbformat": 4,
"nbformat_minor": 1
"nbformat_minor": 4
}

View File

@ -0,0 +1,323 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Example 2: Analyzing LAMMPS thermodynamic data"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Author: [Richard Berger](mailto:richard.berger@outlook.com)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This tutorial assumes you've completed the [first example](simple.ipynb) and understand the basics of running LAMMPS through Python. In this tutorial we will build on top of that example and look at how to extract thermodynamic data produced by LAMMPS into Python and visualize it. Let's first start by recreating our simple melt example:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"%load_ext lammps.ipython"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from lammps import lammps\n",
"L = lammps()\n",
"L.cmd.auto_flush = True\n",
"\n",
"def init_melt_system(L):\n",
" # 3d Lennard-Jones melt\n",
" L.cmd.clear()\n",
" L.cmd.units(\"lj\")\n",
" L.cmd.atom_style(\"atomic\")\n",
" \n",
" L.cmd.lattice(\"fcc\", 0.8442)\n",
" L.cmd.region(\"box\", \"block\", 0, 4, 0, 4, 0, 4)\n",
" L.cmd.create_box(1, \"box\")\n",
" L.cmd.create_atoms(1, \"box\")\n",
" L.cmd.mass(1, 1.0)\n",
" \n",
" L.cmd.velocity(\"all\", \"create\", 1.44, 87287, \"loop geom\")\n",
" \n",
" L.cmd.pair_style(\"lj/cut\", 2.5)\n",
" L.cmd.pair_coeff(1, 1, 1.0, 1.0, 2.5)\n",
" \n",
" L.cmd.neighbor(0.3, \"bin\")\n",
" L.cmd.neigh_modify(\"delay\", 0, \"every\", 20, \"check no\")\n",
" \n",
" L.cmd.fix(\"1\", \"all\", \"nve\")\n",
" \n",
" L.cmd.thermo(50)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Here we take advantage of the fact that we can write regular Python functions to organize our LAMMPS simulation. This allows us to clear and initialize a new system by calling the `init_melt_system()` function. With this we can now go ahead an run this simulation for 100 steps."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"init_melt_system(L)\n",
"L.cmd.run(100)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Extracting thermodynamic data"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Looking at the above output we see that LAMMPS prints out thermodynamic data for steps 0, 50 and 100.\n",
"\n",
"```\n",
" Step Temp E_pair E_mol TotEng Press \n",
" 0 1.44 -6.7733681 0 -4.6218056 -5.0244179 \n",
" 50 0.70303849 -5.6796164 0 -4.629178 0.50453907 \n",
" 100 0.72628044 -5.7150774 0 -4.6299123 0.29765862\n",
"```\n",
"\n",
"We could parse the text output and extract the necessary information, but this has proven to be error-prone and clunky, especially in cases where other output gets interleaved with thermo output lines. Instead, we can make use of the Python integration within LAMMPS to execute arbitrary Python code during time steps using `fix python/invoke`. We can extract the thermodynamic data directly using the LAMMPS Python interface and process it in any way we want.\n",
"\n",
"For this we first define the data structure we want to use to store the data. For each column of the thermodynamic data we want to store a list of values for each time step. Let's use a Python `dict` with the following structure:\n",
"\n",
"```python\n",
"{'Step': [0, 50, 100, ...], 'Temp': [...], 'E_pair': [...], 'E_mol': [...], 'TotEng': [...], 'Press': [...]}\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"To start, let's define an empty `dict` and call it `current_run`. As the simulation progresses, we append new data into this dictionary:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"current_run = {}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Next, let's define a function that should be executed every time step a thermodynamic output line would be written. This function takes a `lammps` class instance and through it can access LAMMPS state and data. We can use the [`last_thermo()`](https://docs.lammps.org/Python_module.html#lammps.lammps.last_thermo) function of the `lammps` class to get the latest thermodynamic data as a dictionary. This data is all we need to populate our `current_run` data structure."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def append_thermo_data(lmp):\n",
" for k, v in lmp.last_thermo().items():\n",
" current_run.setdefault(k, []).append(v)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"With these two pieces in place, it is now time to tell LAMMPS about how we want to call this function.\n",
"\n",
"First, let's suppress any LAMMPS output via `%%capture_lammps_output` and reinitialize our system with `init_melt_system()` so our system is back in its initial state and the time step is back to 0.\n",
"\n",
"Next, we add a new fix `python/invoke` that should execute every 50 time steps, the same as our `thermo 50` command above. At the end of every 50 time steps (including the first one), it should call the `append_thermo_data` function we just defined. Notice we can just pass the function as parameter. Finally, we tell LAMMPS to run for 250 steps."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"%%capture_lammps_output\n",
"init_melt_system(L)\n",
"L.cmd.fix(\"myfix\", \"all\", \"python/invoke\", 50, \"end_of_step\", append_thermo_data)\n",
"L.cmd.run(250)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's inspect our `current_run` dictionary after the run has completed:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"current_run"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"As we can see, the time steps 0, 50, 100, 150, and 200 were added to dictionary. However, the last time step 250 is still missing. For this we need to manually add a final call to our `append_thermo_data()` helper function."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"append_thermo_data(L)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"With this our `current_run` dictionary now has all the data of the completed run:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"current_run"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Plotting thermodynamic data with matplotlib\n",
"\n",
"Now that we have our data available as Python variables, we can easily use other libraries for visualization."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"%matplotlib inline\n",
"import matplotlib.pyplot as plt\n",
"\n",
"plt.xlabel('time step')\n",
"plt.ylabel('Total Energy')\n",
"plt.plot(current_run['Step'], current_run['TotEng'])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Using Pandas library\n",
"\n",
"Since we can call any Python code from LAMMPS, the above example can also be rewritten using the Pandas library:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"%%capture_lammps_output\n",
"import pandas as pd\n",
"\n",
"current_run = pd.DataFrame()\n",
"\n",
"def append_thermo_data(lmp):\n",
" global current_run\n",
" current_time_step = pd.DataFrame.from_records([lmp.last_thermo()])\n",
" current_run = pd.concat([current_run, current_time_step], ignore_index=True)\n",
"\n",
"init_melt_system(L)\n",
"L.cmd.fix(\"myfix\", \"all\", \"python/invoke\", 50, \"end_of_step\", append_thermo_data)\n",
"L.cmd.run(250)\n",
"append_thermo_data(L)\n",
"current_run"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"current_run.plot(x='Step', y='TotEng')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Conclusion\n",
"\n",
"The Python interface gives you a powerful way of invoking and extracting simulation data while the simulation is running. Next we'll look at how to extract information about the atoms in your system.\n",
"\n",
"<div style=\"text-align:right\"><a href=\"atoms.ipynb\">Next</a>"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.7"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

View File

@ -1,546 +0,0 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Example 2: Using the PyLammps interface"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Prerequisites\n",
"\n",
"Before running this example, make sure your Python environment can find the LAMMPS shared library (`liblammps.so`) and the LAMMPS Python package is installed. If you followed the [README](README.md) in this folder, this should already be the case. You can also find more information about how to compile LAMMPS and install the LAMMPS Python package in the [LAMMPS manual](https://docs.lammps.org/Python_install.html). There is also a dedicated [PyLammps HowTo](https://docs.lammps.org/Howto_pylammps.html)."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Setup system"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from lammps import IPyLammps"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L = IPyLammps()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# 3d Lennard-Jones melt\n",
"L.units(\"lj\")\n",
"L.atom_style(\"atomic\")\n",
"L.atom_modify(\"map array\")\n",
"\n",
"L.lattice(\"fcc\", 0.8442)\n",
"L.region(\"box block\", 0, 4, 0, 4, 0, 4)\n",
"L.create_box(1, \"box\")\n",
"L.create_atoms(1, \"box\")\n",
"L.mass(1, 1.0)\n",
"\n",
"L.velocity(\"all create\", 1.44, 87287, \"loop geom\")\n",
"\n",
"L.pair_style(\"lj/cut\", 2.5)\n",
"L.pair_coeff(1, 1, 1.0, 1.0, 2.5)\n",
"\n",
"L.neighbor(0.3, \"bin\")\n",
"L.neigh_modify(\"delay 0 every 20 check no\")\n",
"\n",
"L.fix(\"1 all nve\")\n",
"\n",
"L.variable(\"fx atom fx\")\n",
"\n",
"L.run(10)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Visualize the initial state"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.image(zoom=1)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Queries about LAMMPS simulation"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.system"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.system.natoms"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.communication"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.fixes"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.computes"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.dumps"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.groups"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Working with LAMMPS Variables"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.variable(\"a index 2\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.variables"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.variable(\"t equal temp\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.variables"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import sys\n",
"\n",
"if sys.version_info < (3, 0):\n",
" # In Python 2 'print' is a restricted keyword, which is why you have to use the lmp_print function instead.\n",
" x = float(L.lmp_print('\"${a}\"'))\n",
"else:\n",
" # In Python 3 the print function can be redefined.\n",
" # x = float(L.print('\"${a}\"')\")\n",
" \n",
" # To avoid a syntax error in Python 2 executions of this notebook, this line is packed into an eval statement\n",
" x = float(eval(\"L.print('\\\"${a}\\\"')\"))\n",
"x"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.variables['t'].value"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.eval(\"v_t/2.0\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.variable(\"b index a b c\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.variables['b'].value"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.eval(\"v_b\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.variables['b'].definition"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.lmp.command('variable i loop 10')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.variable(\"i loop 10\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.variables['i'].value"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.next(\"i\")\n",
"L.variables['i'].value"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.eval(\"ke\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Accessing Atom data"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.atoms[0]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"dir(L.atoms[0])"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.atoms[0].position"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.atoms[0].id"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.atoms[0].velocity"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.atoms[0].force"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.atoms[0].type"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.variables['fx'].value"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Accessing thermo data"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.runs"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.runs[0]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.runs[0].thermo"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.runs[0].thermo"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"dir(L.runs[0].thermo)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Saving session to as LAMMPS input file"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"PyLammps can keep track of all LAMMPS commands that are executed. This allows you to prototype a script and then later on save it as a regular input script:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L = IPyLammps()\n",
"\n",
"# enable command history\n",
"L.enable_cmd_history = True\n",
"\n",
"# 3d Lennard-Jones melt\n",
"L.units(\"lj\")\n",
"L.atom_style(\"atomic\")\n",
"L.atom_modify(\"map array\")\n",
"\n",
"L.lattice(\"fcc\", 0.8442)\n",
"L.region(\"box block\", 0, 4, 0, 4, 0, 4)\n",
"L.create_box(1, \"box\")\n",
"L.create_atoms(1, \"box\")\n",
"L.mass(1, 1.0)\n",
"\n",
"L.velocity(\"all create\", 1.44, 87287, \"loop geom\")\n",
"\n",
"L.pair_style(\"lj/cut\", 2.5)\n",
"L.pair_coeff(1, 1, 1.0, 1.0, 2.5)\n",
"\n",
"L.neighbor(0.3, \"bin\")\n",
"L.neigh_modify(\"delay 0 every 20 check no\")\n",
"\n",
"L.fix(\"1 all nve\")\n",
"\n",
"L.run(10)\n",
"\n",
"# write LAMMPS input script with all commands executed so far (including implicit ones)\n",
"L.write_script(\"in.output\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"!cat in.output"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.2"
}
},
"nbformat": 4,
"nbformat_minor": 1
}

View File

@ -1,471 +0,0 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Example 3: 2D circle of particles inside of box with LJ walls"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Prerequisites\n",
"\n",
"Before running this example, make sure your Python environment can find the LAMMPS shared library (`liblammps.so`) and the LAMMPS Python package is installed. If you followed the [README](README.md) in this folder, this should already be the case. You can also find more information about how to compile LAMMPS and install the LAMMPS Python package in the [LAMMPS manual](https://docs.lammps.org/Python_install.html). There is also a dedicated [PyLammps HowTo](https://docs.lammps.org/Howto_pylammps.html)."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Setup system"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from lammps import IPyLammps"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L = IPyLammps()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# 2d circle of particles inside a box with LJ walls\n",
"import math\n",
"\n",
"b = 0\n",
"x = 50\n",
"y = 20\n",
"d = 20\n",
"\n",
"# careful not to slam into wall too hard\n",
"\n",
"v = 0.3\n",
"w = 0.08\n",
" \n",
"L.units(\"lj\")\n",
"L.dimension(2)\n",
"L.atom_style(\"bond\")\n",
"L.boundary(\"f f p\")\n",
"\n",
"L.lattice(\"hex\", 0.85)\n",
"L.region(\"box\", \"block\", 0, x, 0, y, -0.5, 0.5)\n",
"L.create_box(1, \"box\", \"bond/types\", 1, \"extra/bond/per/atom\", 6)\n",
"L.region(\"circle\", \"sphere\", d/2.0+1.0, d/2.0/math.sqrt(3.0)+1, 0.0, d/2.0)\n",
"L.create_atoms(1, \"region\", \"circle\")\n",
"L.mass(1, 1.0)\n",
"\n",
"L.velocity(\"all create 0.5 87287 loop geom\")\n",
"L.velocity(\"all set\", v, w, 0, \"sum yes\")\n",
"\n",
"L.pair_style(\"lj/cut\", 2.5)\n",
"L.pair_coeff(1, 1, 10.0, 1.0, 2.5)\n",
"\n",
"L.bond_style(\"harmonic\")\n",
"L.bond_coeff(1, 10.0, 1.2)\n",
"\n",
"L.create_bonds(\"many\", \"all\", \"all\", 1, 1.0, 1.5)\n",
"\n",
"L.neighbor(0.3, \"bin\")\n",
"L.neigh_modify(\"delay\", 0, \"every\", 1, \"check yes\")\n",
"\n",
"L.fix(1, \"all\", \"nve\")\n",
"\n",
"L.fix(2, \"all wall/lj93 xlo 0.0 1 1 2.5 xhi\", x, \"1 1 2.5\")\n",
"L.fix(3, \"all wall/lj93 ylo 0.0 1 1 2.5 yhi\", y, \"1 1 2.5\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Visualize initial state"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.image(zoom=1.8)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Run simulation and visualize new state"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.thermo_style(\"custom step temp epair press\")\n",
"L.thermo(100)\n",
"output = L.run(40000)\n",
"L.image(zoom=1.8)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Queries about LAMMPS simulation"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.system"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.system.natoms"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.system.nbonds"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.system.nbondtypes"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.communication"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.fixes"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.computes"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.dumps"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.groups"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Working with LAMMPS Variables"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.variable(\"a index 2\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.variables"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.variable(\"t equal temp\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.variables"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import sys\n",
"\n",
"if sys.version_info < (3, 0):\n",
" # In Python 2 'print' is a restricted keyword, which is why you have to use the lmp_print function instead.\n",
" x = float(L.lmp_print('\"${a}\"'))\n",
"else:\n",
" # In Python 3 the print function can be redefined.\n",
" # x = float(L.print('\"${a}\"')\")\n",
" \n",
" # To avoid a syntax error in Python 2 executions of this notebook, this line is packed into an eval statement\n",
" x = float(eval(\"L.print('\\\"${a}\\\"')\"))\n",
"x"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.variables['t'].value"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.eval(\"v_t/2.0\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.variable(\"b index a b c\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.variables['b'].value"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.eval(\"v_b\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.variables['b'].definition"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.variable(\"i loop 10\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.variables['i'].value"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.next(\"i\")\n",
"L.variables['i'].value"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.eval(\"ke\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Accessing Atom data"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.atoms[0]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"dir(L.atoms[0])"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.atoms[0].position"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.atoms[0].id"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.atoms[0].velocity"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.atoms[0].force"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"L.atoms[0].type"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.2"
}
},
"nbformat": 4,
"nbformat_minor": 1
}

View File

@ -59,6 +59,87 @@ class ExceptionCheck:
# -------------------------------------------------------------------------
class command_wrapper(object):
def __init__(self, lmp):
self.lmp = lmp
self.auto_flush = False
def lmp_print(self, s):
""" needed for Python2 compatibility, since print is a reserved keyword """
return self.__getattr__("print")(s)
def __dir__(self):
return sorted(set(['angle_coeff', 'angle_style', 'atom_modify', 'atom_style', 'atom_style',
'bond_coeff', 'bond_style', 'boundary', 'change_box', 'communicate', 'compute',
'create_atoms', 'create_box', 'delete_atoms', 'delete_bonds', 'dielectric',
'dihedral_coeff', 'dihedral_style', 'dimension', 'dump', 'fix', 'fix_modify',
'group', 'improper_coeff', 'improper_style', 'include', 'kspace_modify',
'kspace_style', 'lattice', 'mass', 'minimize', 'min_style', 'neighbor',
'neigh_modify', 'newton', 'nthreads', 'pair_coeff', 'pair_modify',
'pair_style', 'processors', 'read', 'read_data', 'read_restart', 'region',
'replicate', 'reset_timestep', 'restart', 'run', 'run_style', 'thermo',
'thermo_modify', 'thermo_style', 'timestep', 'undump', 'unfix', 'units',
'variable', 'velocity', 'write_restart'] + self.lmp.available_styles("command")))
def _wrap_args(self, x):
if callable(x):
if sys.version_info < (3,):
raise Exception("Passing functions or lambdas directly as arguments is only supported in Python 3 or newer")
import hashlib
import __main__
sha = hashlib.sha256()
sha.update(str(x).encode())
func_name = f"_lmp_cb_{sha.hexdigest()}"
def handler(*args, **kwargs):
args = list(args)
args[0] = lammps(ptr=args[0])
x(*args)
setattr(__main__, func_name, handler)
return func_name
return x
def __getattr__(self, name):
"""
This method is where the Python 'magic' happens. If a method is not
defined by the class command_wrapper, it assumes it is a LAMMPS command. It takes
all the arguments, concatinates them to a single string, and executes it using
:py:meth:`lammps.command()`.
Starting with Python 3.6 it also supports keyword arguments. key=value is
transformed into 'key value'. Note, since these have come last in the
parameter list, only a subset of LAMMPS commands can be used with this
syntax.
LAMMPS commands that accept callback functions (such as fix python/invoke)
can be passed functions and lambdas directly. The first argument of such
callbacks will be an lammps object constructed from the passed LAMMPS
pointer.
:return: line or list of lines of output, None if no output
:rtype: list or string
"""
def handler(*args, **kwargs):
cmd_args = [name] + [str(self._wrap_args(x)) for x in args]
if len(kwargs) > 0 and sys.version_info < (3,6):
raise Exception("Keyword arguments are only supported in Python 3.6 or newer")
# Python 3.6+ maintains ordering of kwarg keys
for k in kwargs.keys():
cmd_args.append(k)
if type(kwargs[k]) == bool:
cmd_args.append("true" if kwargs[k] else "false")
else:
cmd_args.append(str(self._wrap_args(kwargs[k])))
cmd = ' '.join(cmd_args)
self.lmp.command(cmd)
if self.auto_flush:
self.lmp.flush_buffers()
return handler
# -------------------------------------------------------------------------
class lammps(object):
"""Create an instance of the LAMMPS Python class.
@ -103,6 +184,8 @@ class lammps(object):
winpath = os.environ.get("LAMMPSDLLPATH")
self.lib = None
self.lmp = None
self._cmd = None
self._ipython = None
# if a pointer to a LAMMPS object is handed in
# when being called from a Python interpreter
@ -509,6 +592,61 @@ class lammps(object):
# -------------------------------------------------------------------------
@property
def cmd(self):
""" Return object that acts as LAMMPS command wrapper
It provides alternative to :py:meth:`lammps.command` to call LAMMPS
commands as if they were regular Python functions and enables auto-complete
in interactive Python sessions.
.. code-block:: python
from lammps import lammps
# melt example
L = lammps()
L.cmd.units("lj")
L.cmd.atom_style("atomic")
L.cmd.lattice("fcc", 0.8442)
L.cmd.region("box block", 0, 10, 0, 10, 0, 10)
L.cmd.create_box(1, "box")
L.cmd.create_atoms(1, "box")
L.cmd.mass(1, 1.0)
L.cmd.velocity("all create", 3.0, 87287, "loop geom")
L.cmd.pair_style("lj/cut", 2.5)
L.cmd.pair_coeff(1, 1, 1.0, 1.0, 2.5)
L.cmd.neighbor(0.3, "bin")
L.cmd.neigh_modify(every=20, delay=0, check=False)
L.cmd.fix(1, "all nve")
L.cmd.thermo(50)
L.cmd.run(250)
:return: instance of command_wrapper object
:rtype: command_wrapper
"""
if not self._cmd:
self._cmd = command_wrapper(self)
return self._cmd
# -------------------------------------------------------------------------
@property
def ipython(self):
""" Return object to access ipython extensions
Adds commands for visualization in IPython and Jupyter Notebooks.
:return: instance of ipython wrapper object
:rtype: ipython.wrapper
"""
if not self._ipython:
from .ipython import wrapper
self._ipython = wrapper(self)
return self._ipython
# -------------------------------------------------------------------------
def close(self):
"""Explicitly delete a LAMMPS instance through the C-library interface.

View File

@ -0,0 +1,23 @@
# ----------------------------------------------------------------------
# LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
# https://www.lammps.org/ Sandia National Laboratories
# LAMMPS Development team: developers@lammps.org
#
# Copyright (2003) Sandia Corporation. Under the terms of Contract
# DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
# certain rights in this software. This software is distributed under
# the GNU General Public License.
#
# See the README file in the top-level LAMMPS directory.
# -------------------------------------------------------------------------
################################################################################
# IPython/Jupyter Notebook additions
# Written by Richard Berger <richard.berger@outlook.com>
################################################################################
from .wrapper import wrapper
from .magics import LammpsMagics
def load_ipython_extension(ipython):
ipython.register_magics(LammpsMagics)

View File

@ -0,0 +1,75 @@
# ----------------------------------------------------------------------
# LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
# https://www.lammps.org/ Sandia National Laboratories
# LAMMPS Development team: developers@lammps.org
#
# Copyright (2003) Sandia Corporation. Under the terms of Contract
# DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
# certain rights in this software. This software is distributed under
# the GNU General Public License.
#
# See the README file in the top-level LAMMPS directory.
# -------------------------------------------------------------------------
################################################################################
# IPython/Jupyter Notebook additions
# Written by Richard Berger <richard.berger@outlook.com>
################################################################################
import io
import os
import sys
import tempfile
from IPython.core.magic import (Magics, magics_class, cell_magic)
import IPython.core.magic_arguments as magic_arguments
class OutputCapture(object):
""" Utility class to capture LAMMPS library output """
def __init__(self):
self.stdout_fd = 1
self.captured_output = ""
def __enter__(self):
self.tmpfile = tempfile.TemporaryFile(mode='w+b')
sys.stdout.flush()
# make copy of original stdout
self.stdout_orig = os.dup(self.stdout_fd)
# replace stdout and redirect to temp file
os.dup2(self.tmpfile.fileno(), self.stdout_fd)
return self
def __exit__(self, exc_type, exc_value, traceback):
os.dup2(self.stdout_orig, self.stdout_fd)
os.close(self.stdout_orig)
self.tmpfile.close()
@property
def output(self):
sys.stdout.flush()
self.tmpfile.flush()
self.tmpfile.seek(0, io.SEEK_SET)
self.captured_output = self.tmpfile.read().decode('utf-8')
return self.captured_output
# -------------------------------------------------------------------------
@magics_class
class LammpsMagics(Magics):
@magic_arguments.magic_arguments()
@magic_arguments.argument('output', type=str, default='', nargs='?',
help="""The name of the variable in which to store output.
If unspecified, captured output is discarded.
"""
)
@cell_magic
def capture_lammps_output(self, line, cell):
"""run the cell, capturing LAMMPS stdout and stderr."""
args = magic_arguments.parse_argstring(self.capture_lammps_output, line)
with OutputCapture() as capture:
self.shell.run_cell(cell)
if args.output:
self.shell.user_ns[args.output] = capture.output

View File

@ -0,0 +1,113 @@
# ----------------------------------------------------------------------
# LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
# https://www.lammps.org/ Sandia National Laboratories
# LAMMPS Development team: developers@lammps.org
#
# Copyright (2003) Sandia Corporation. Under the terms of Contract
# DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
# certain rights in this software. This software is distributed under
# the GNU General Public License.
#
# See the README file in the top-level LAMMPS directory.
# -------------------------------------------------------------------------
################################################################################
# IPython/Jupyter Notebook additions
# Written by Richard Berger <richard.berger@outlook.com>
################################################################################
class wrapper(object):
"""lammps API IPython Wrapper
This is a wrapper class that provides additional methods on top of an
existing :py:class:`lammps` instance. It provides additional methods
that allow create and/or embed visualizations created by native LAMMPS
commands.
There is no need to explicitly instantiate this class. Each instance
of :py:class:`lammps` has a :py:attr:`ipython <lammps.ipython>` property
that returns an instance.
:param lmp: instance of the :py:class:`lammps` class
:type lmp: lammps
"""
def __init__(self, lmp):
self.lmp = lmp
def image(self, filename="snapshot.png", group="all", color="type", diameter="type",
size=None, view=None, center=None, up=None, zoom=1.0, background_color="white"):
""" Generate image using write_dump command and display it
See :doc:`dump image <dump_image>` for more information.
:param filename: Name of the image file that should be generated. The extension determines whether it is PNG or JPEG
:type filename: string
:param group: the group of atoms write_image should use
:type group: string
:param color: name of property used to determine color
:type color: string
:param diameter: name of property used to determine atom diameter
:type diameter: string
:param size: dimensions of image
:type size: tuple (width, height)
:param view: view parameters
:type view: tuple (theta, phi)
:param center: center parameters
:type center: tuple (flag, center_x, center_y, center_z)
:param up: vector pointing to up direction
:type up: tuple (up_x, up_y, up_z)
:param zoom: zoom factor
:type zoom: float
:param background_color: background color of scene
:type background_color: string
:return: Image instance used to display image in notebook
:rtype: :py:class:`IPython.core.display.Image`
"""
cmd_args = [group, "image", filename, color, diameter]
if size is not None:
width = size[0]
height = size[1]
cmd_args += ["size", width, height]
if view is not None:
theta = view[0]
phi = view[1]
cmd_args += ["view", theta, phi]
if center is not None:
flag = center[0]
Cx = center[1]
Cy = center[2]
Cz = center[3]
cmd_args += ["center", flag, Cx, Cy, Cz]
if up is not None:
Ux = up[0]
Uy = up[1]
Uz = up[2]
cmd_args += ["up", Ux, Uy, Uz]
if zoom is not None:
cmd_args += ["zoom", zoom]
cmd_args.append("modify backcolor " + background_color)
self.lmp.cmd.write_dump(*cmd_args)
from IPython.core.display import Image
return Image(filename)
def video(self, filename):
"""
Load video from file
Can be used to visualize videos from :doc:`dump movie <dump_image>`.
:param filename: Path to video file
:type filename: string
:return: HTML Video Tag used by notebook to embed a video
:rtype: :py:class:`IPython.display.HTML`
"""
from IPython.display import HTML
return HTML("<video controls><source src=\"" + filename + "\"></video>")

View File

@ -428,6 +428,8 @@ class PyLammps(object):
lower-level interface. The original interface can still be accessed via
:py:attr:`PyLammps.lmp`.
.. deprecated:: TBA
:param name: "machine" name of the shared LAMMPS library ("mpi" loads ``liblammps_mpi.so``, "" loads ``liblammps.so``)
:type name: string
:param cmdargs: list of command line arguments to be passed to the :cpp:func:`lammps_open` function. The executable name is automatically added.
@ -468,6 +470,12 @@ class PyLammps(object):
self.comm_nprocs = self.lmp.extract_setting("world_size")
self.comm_me = self.lmp.extract_setting("world_rank")
if self.comm_me == 0:
print("\nWARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING")
print("WARNING:")
print("WARNING: The PyLammps class is obsolete and will be removed from LAMMPS soon.")
print("WARNING: Please use the lammps Python class instead.")
print("WARNING:")
print("WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING\n")
print("LAMMPS output is captured by PyLammps wrapper")
if self.comm_nprocs > 1:
print("WARNING: Using PyLammps with multiple MPI ranks is experimental. Not all functionality is supported.")

View File

@ -26,7 +26,7 @@ class BinaryDistribution(Distribution):
return True
if version_info.major >= 3:
pkgs = ['lammps', 'lammps.mliap']
pkgs = ['lammps', 'lammps.mliap', 'lammps.ipython']
else:
pkgs = ['lammps']

2
src/.gitignore vendored
View File

@ -507,6 +507,8 @@
/angle_harmonic.h
/angle_mm3.cpp
/angle_mm3.h
/angle_mwlc.cpp
/angle_mwlc.h
/angle_quartic.cpp
/angle_quartic.h
/angle_spica.cpp

View File

@ -9,6 +9,19 @@ mode=$1
LC_ALL=C
export LC_ALL
cat <<EOF
WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING
WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING
The ATC package will be removed from LAMMPS in Summer 2025 due to lack of
maintenance and use of code constructs that conflict with modern C++ compilers
and standards. Please contact developers@lammps.org if you have any concerns
about this step.
WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING
WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING
EOF
action () {
if (test $mode = 0) then
rm -f ../$1

View File

@ -9,6 +9,19 @@ mode=$1
LC_ALL=C
export LC_ALL
cat <<EOF
WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING
WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING
The AWPMD package will be removed from LAMMPS in Summer 2025 due to lack of
maintenance and use of code constructs that conflict with modern C++ compilers
and standards. Please contact developers@lammps.org if you have any concerns
about this step.
WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING
WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING
EOF
action () {
if (test $mode = 0) then
rm -f ../$1

View File

@ -9,6 +9,19 @@ mode=$1
LC_ALL=C
export LC_ALL
cat <<EOF
WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING
WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING
Support for building the COLVARS package with the legacy build system using GNU
make will be removed in Summer 2025. Please switch to using CMake to build
LAMMPS as soon as possible and report any problems to developers@lammps.org
or post a bug report issue at https://github.com/lammps/lammps/issues
WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING
WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING
EOF
action () {
if (test $mode = 0) then
rm -f ../$1

View File

@ -7,6 +7,19 @@ mode=$1
LC_ALL=C
export LC_ALL
cat <<EOF
WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING
WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING
Support for building the COMPRESS package with the legacy build system using
GNU make will be removed in Summer 2025. Please switch to using CMake to build
LAMMPS as soon as possible and report any problems to developers@lammps.org
or post a bug report issue at https://github.com/lammps/lammps/issues
WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING
WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING
EOF
# arg1 = file, arg2 = file it depends on
action () {

View File

@ -11,6 +11,19 @@ mode=$1
LC_ALL=C
export LC_ALL
cat <<EOF
WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING
WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING
Support for building the ELECTRODE package with the legacy build system using
GNU make will be removed in Summer 2025. Please switch to using CMake to build
LAMMPS as soon as possible and report any problems to developers@lammps.org
or post a bug report issue at https://github.com/lammps/lammps/issues
WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING
WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING
EOF
# arg1 = file, arg2 = file it depends on
action () {

View File

@ -0,0 +1,326 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
https://www.lammps.org/, Sandia National Laboratories
LAMMPS development team: developers@lammps.org
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing author: James D. Farrell (IoP CAS) j.d.farrell at gmail.com
[ based on angle_cosine.cpp ]
------------------------------------------------------------------------- */
#include "angle_mwlc.h"
#include "atom.h"
#include "comm.h"
#include "domain.h"
#include "error.h"
#include "force.h"
#include "math_const.h"
#include "memory.h"
#include "neighbor.h"
#include <cmath>
#include <cstring>
using namespace LAMMPS_NS;
using MathConst::MY_PI;
/* ---------------------------------------------------------------------- */
AngleMWLC::AngleMWLC(LAMMPS *_lmp) : Angle(_lmp)
{
born_matrix_enable = 1;
}
/* ---------------------------------------------------------------------- */
AngleMWLC::~AngleMWLC()
{
if (allocated && !copymode) {
memory->destroy(setflag);
memory->destroy(k1);
memory->destroy(k2);
memory->destroy(mu);
memory->destroy(temp);
}
}
/* ---------------------------------------------------------------------- */
void AngleMWLC::compute(int eflag, int vflag)
{
int i1, i2, i3, n, type;
double delx1, dely1, delz1, delx2, dely2, delz2;
double eangle, f1[3], f3[3];
double rsq1, rsq2, r1, r2, c, a, a11, a12, a22;
double q, qm, Q;
eangle = 0.0;
ev_init(eflag, vflag);
double **x = atom->x;
double **f = atom->f;
int **anglelist = neighbor->anglelist;
int nanglelist = neighbor->nanglelist;
int nlocal = atom->nlocal;
int newton_bond = force->newton_bond;
double kbt, v_min;
for (n = 0; n < nanglelist; n++) {
i1 = anglelist[n][0];
i2 = anglelist[n][1];
i3 = anglelist[n][2];
type = anglelist[n][3];
kbt = temp[type] * force->boltz;
v_min = -kbt * log(1 + exp(-mu[type] / kbt));
// 1st bond
delx1 = x[i1][0] - x[i2][0];
dely1 = x[i1][1] - x[i2][1];
delz1 = x[i1][2] - x[i2][2];
rsq1 = delx1 * delx1 + dely1 * dely1 + delz1 * delz1;
r1 = sqrt(rsq1);
// 2nd bond
delx2 = x[i3][0] - x[i2][0];
dely2 = x[i3][1] - x[i2][1];
delz2 = x[i3][2] - x[i2][2];
rsq2 = delx2 * delx2 + dely2 * dely2 + delz2 * delz2;
r2 = sqrt(rsq2);
// c = cosine of angle
c = delx1 * delx2 + dely1 * dely2 + delz1 * delz2;
c /= r1 * r2;
if (c > 1.0) c = 1.0;
if (c < -1.0) c = -1.0;
// force & energy
q = exp(-k1[type] * (1.0 + c) / kbt);
qm = exp((-k2[type] * (1.0 + c) - mu[type]) / kbt);
Q = q + qm;
if (eflag) eangle = -kbt * log(Q) - v_min;
a = (k1[type] * q + k2[type] * qm) / Q;
a11 = a * c / rsq1;
a12 = -a / (r1 * r2);
a22 = a * c / rsq2;
f1[0] = a11 * delx1 + a12 * delx2;
f1[1] = a11 * dely1 + a12 * dely2;
f1[2] = a11 * delz1 + a12 * delz2;
f3[0] = a22 * delx2 + a12 * delx1;
f3[1] = a22 * dely2 + a12 * dely1;
f3[2] = a22 * delz2 + a12 * delz1;
// apply force to each of 3 atoms
if (newton_bond || i1 < nlocal) {
f[i1][0] += f1[0];
f[i1][1] += f1[1];
f[i1][2] += f1[2];
}
if (newton_bond || i2 < nlocal) {
f[i2][0] -= f1[0] + f3[0];
f[i2][1] -= f1[1] + f3[1];
f[i2][2] -= f1[2] + f3[2];
}
if (newton_bond || i3 < nlocal) {
f[i3][0] += f3[0];
f[i3][1] += f3[1];
f[i3][2] += f3[2];
}
if (evflag)
ev_tally(i1, i2, i3, nlocal, newton_bond, eangle, f1, f3, delx1, dely1, delz1, delx2, dely2,
delz2);
}
}
/* ---------------------------------------------------------------------- */
void AngleMWLC::allocate()
{
allocated = 1;
const int np1 = atom->nangletypes + 1;
memory->create(k1, np1, "angle:k1");
memory->create(k2, np1, "angle:k2");
memory->create(mu, np1, "angle:mu");
memory->create(temp, np1, "angle:temp");
memory->create(setflag, np1, "angle:setflag");
for (int i = 1; i < np1; i++) setflag[i] = 0;
}
/* ----------------------------------------------------------------------
set coeffs for one type
------------------------------------------------------------------------- */
void AngleMWLC::coeff(int narg, char **arg)
{
if (narg != 5) error->all(FLERR, "Incorrect args for angle coefficients");
if (!allocated) allocate();
int ilo, ihi;
utils::bounds(FLERR, arg[0], 1, atom->nangletypes, ilo, ihi, error);
double k1_one = utils::numeric(FLERR, arg[1], false, lmp);
double k2_one = utils::numeric(FLERR, arg[2], false, lmp);
double mu_one = utils::numeric(FLERR, arg[3], false, lmp);
double temp_one = utils::numeric(FLERR, arg[4], false, lmp);
int count = 0;
for (int i = ilo; i <= ihi; i++) {
k1[i] = k1_one;
k2[i] = k2_one;
mu[i] = mu_one;
temp[i] = temp_one;
setflag[i] = 1;
count++;
}
if (count == 0) error->all(FLERR, "Incorrect args for angle coefficients");
}
/* ---------------------------------------------------------------------- */
double AngleMWLC::equilibrium_angle(int /*i*/)
{
return MY_PI;
}
/* ----------------------------------------------------------------------
proc 0 writes out coeffs to restart file
------------------------------------------------------------------------- */
void AngleMWLC::write_restart(FILE *fp)
{
fwrite(&k1[1], sizeof(double), atom->nangletypes, fp);
fwrite(&k2[1], sizeof(double), atom->nangletypes, fp);
fwrite(&mu[1], sizeof(double), atom->nangletypes, fp);
fwrite(&temp[1], sizeof(double), atom->nangletypes, fp);
}
/* ----------------------------------------------------------------------
proc 0 reads coeffs from restart file, bcasts them
------------------------------------------------------------------------- */
void AngleMWLC::read_restart(FILE *fp)
{
allocate();
if (comm->me == 0) {
utils::sfread(FLERR, &k1[1], sizeof(double), atom->nangletypes, fp, nullptr, error);
utils::sfread(FLERR, &k2[1], sizeof(double), atom->nangletypes, fp, nullptr, error);
utils::sfread(FLERR, &mu[1], sizeof(double), atom->nangletypes, fp, nullptr, error);
utils::sfread(FLERR, &temp[1], sizeof(double), atom->nangletypes, fp, nullptr, error);
}
MPI_Bcast(&k1[1], atom->nangletypes, MPI_DOUBLE, 0, world);
MPI_Bcast(&k2[1], atom->nangletypes, MPI_DOUBLE, 0, world);
MPI_Bcast(&mu[1], atom->nangletypes, MPI_DOUBLE, 0, world);
MPI_Bcast(&temp[1], atom->nangletypes, MPI_DOUBLE, 0, world);
for (int i = 1; i <= atom->nangletypes; i++) setflag[i] = 1;
}
/* ----------------------------------------------------------------------
proc 0 writes to data file
------------------------------------------------------------------------- */
void AngleMWLC::write_data(FILE *fp)
{
for (int i = 1; i <= atom->nangletypes; i++)
fprintf(fp, "%d %g %g %g %g\n", i, k1[i], k2[i], mu[i], temp[i]);
}
/* ---------------------------------------------------------------------- */
double AngleMWLC::single(int type, int i1, int i2, int i3)
{
double **x = atom->x;
double kbt = temp[type] * force->boltz;
double v_min = -kbt * log(1 + exp(-mu[type] / kbt));
double delx1 = x[i1][0] - x[i2][0];
double dely1 = x[i1][1] - x[i2][1];
double delz1 = x[i1][2] - x[i2][2];
domain->minimum_image(delx1, dely1, delz1);
double r1 = sqrt(delx1 * delx1 + dely1 * dely1 + delz1 * delz1);
double delx2 = x[i3][0] - x[i2][0];
double dely2 = x[i3][1] - x[i2][1];
double delz2 = x[i3][2] - x[i2][2];
domain->minimum_image(delx2, dely2, delz2);
double r2 = sqrt(delx2 * delx2 + dely2 * dely2 + delz2 * delz2);
double c = delx1 * delx2 + dely1 * dely2 + delz1 * delz2;
c /= r1 * r2;
if (c > 1.0) c = 1.0;
if (c < -1.0) c = -1.0;
double q = exp(-k1[type] * (1.0 + c) / kbt);
double qm = exp((-k2[type] * (1.0 + c) - mu[type]) / kbt);
return -kbt * log(q + qm) - v_min;
}
/* ---------------------------------------------------------------------- */
void AngleMWLC::born_matrix(int type, int i1, int i2, int i3, double &du, double &du2)
{
double **x = atom->x;
double kbt = temp[type] * force->boltz;
double delx1 = x[i1][0] - x[i2][0];
double dely1 = x[i1][1] - x[i2][1];
double delz1 = x[i1][2] - x[i2][2];
domain->minimum_image(delx1, dely1, delz1);
double delx2 = x[i3][0] - x[i2][0];
double dely2 = x[i3][1] - x[i2][1];
double delz2 = x[i3][2] - x[i2][2];
domain->minimum_image(delx2, dely2, delz2);
double c = delx1 * delx2 + dely1 * dely2 + delz1 * delz2;
c /= sqrt((delx1 * delx1 + dely1 * dely1 + delz1 * delz1) *
(delx2 * delx2 + dely2 * dely2 + delz2 * delz2));
if (c > 1.0) c = 1.0;
if (c < -1.0) c = -1.0;
const double q = exp(-k1[type] * (1.0 + c) / kbt);
const double qm = exp((-k2[type] * (1.0 + c) - mu[type]) / kbt);
const double Q = q + qm;
du = (k1[type] * q + k2[type] * qm) / Q;
du2 = (k1[type] - k2[type]) / Q;
du2 *= -du2 * q * qm / kbt;
}
/* ----------------------------------------------------------------------
return ptr to internal members upon request
------------------------------------------------------------------------ */
void *AngleMWLC::extract(const char *str, int &dim)
{
dim = 1;
if (strcmp(str, "k1") == 0) return (void *) k1;
if (strcmp(str, "k2") == 0) return (void *) k2;
if (strcmp(str, "mu") == 0) return (void *) mu;
if (strcmp(str, "temp") == 0) return (void *) temp;
return nullptr;
}

View File

@ -0,0 +1,53 @@
/* -*- c++ -*- ----------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
https://www.lammps.org/, Sandia National Laboratories
LAMMPS development team: developers@lammps.org
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
#ifdef ANGLE_CLASS
// clang-format off
AngleStyle(mwlc,AngleMWLC);
// clang-format on
#else
#ifndef LMP_ANGLE_MWLC_H
#define LMP_ANGLE_MWLC_H
#include "angle.h"
namespace LAMMPS_NS {
class AngleMWLC : public Angle {
public:
AngleMWLC(class LAMMPS *);
~AngleMWLC() override;
void compute(int, int) override;
void coeff(int, char **) override;
double equilibrium_angle(int) override;
void write_restart(FILE *) override;
void read_restart(FILE *) override;
void write_data(FILE *) override;
double single(int, int, int, int) override;
void born_matrix(int type, int i1, int i2, int i3, double &du, double &du2) override;
void *extract(const char *, int &) override;
protected:
double *k1;
double *k2;
double *mu;
double *temp;
virtual void allocate();
};
} // namespace LAMMPS_NS
#endif
#endif

View File

@ -7,6 +7,19 @@ mode=$1
LC_ALL=C
export LC_ALL
cat <<EOF
WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING
WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING
Support for building the GPU package with the legacy build system using GNU
make will be removed in Summer 2025. Please switch to using CMake to build
LAMMPS as soon as possible and report any problems to developers@lammps.org
or post a bug report issue at https://github.com/lammps/lammps/issues
WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING
WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING
EOF
# arg1 = file, arg2 = file it depends on
action () {

View File

@ -7,6 +7,19 @@ mode=$1
LC_ALL=C
export LC_ALL
cat <<EOF
WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING
WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING
Support for building the KOKKOS package with the legacy build system using GNU
make will be removed in Summer 2025. Please switch to using CMake to build
LAMMPS as soon as possible and report any problems to developers@lammps.org
or post a bug report issue at https://github.com/lammps/lammps/issues
WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING
WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING
EOF
# arg1 = file, arg2 = file it depends on
action () {

View File

@ -9,6 +9,19 @@ mode=$1
LC_ALL=C
export LC_ALL
cat <<EOF
WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING
WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING
Support for building the LEPTON package with the legacy build system using GNU
make will be removed in Summer 2025. Please switch to using CMake to build
LAMMPS as soon as possible and report any problems to developers@lammps.org
or post a bug report issue at https://github.com/lammps/lammps/issues
WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING
WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING
EOF
action () {
if (test $mode = 0) then
rm -f ../$1

View File

@ -7,12 +7,12 @@ SHELL = /bin/sh
# specify flags and libraries needed for your compiler
CC = mpicxx
CCFLAGS = -g -O3 -std=c++11
CCFLAGS = -g -O3 # -std=c++17
SHFLAGS = -fPIC
DEPFLAGS = -M
LINK = mpicxx
LINKFLAGS = -g -O3 -std=c++11
LINKFLAGS = -g -O3 # -std=c++17
LIB =
SIZE = size
@ -28,7 +28,7 @@ SHLIBFLAGS = -shared -rdynamic
# LAMMPS ifdef settings
# see possible settings in Section 3.5 of the manual
LMP_INC = -DLAMMPS_GZIP -DLAMMPS_MEMALIGN=64 # -DLAMMPS_CXX98
LMP_INC = -DLAMMPS_GZIP -DLAMMPS_MEMALIGN=64 # -DLAMMPS_CXX11
# MPI library
# see discussion in Section 3.4 of the manual

View File

@ -7,12 +7,12 @@ SHELL = /bin/sh
# specify flags and libraries needed for your compiler
CC = g++
CCFLAGS = -g -O3 -std=c++11
CCFLAGS = -g -O3 # -std=c++17
SHFLAGS = -fPIC
DEPFLAGS = -M
LINK = g++
LINKFLAGS = -g -O -std=c++11
LINKFLAGS = -g -O # -std=c++17
LIB =
SIZE = size
@ -28,7 +28,7 @@ SHLIBFLAGS = -shared -rdynamic
# LAMMPS ifdef settings
# see possible settings in Section 3.5 of the manual
LMP_INC = -DLAMMPS_GZIP -DLAMMPS_MEMALIGN=64 # -DLAMMPS_CXX98
LMP_INC = -DLAMMPS_GZIP -DLAMMPS_MEMALIGN=64 # -DLAMMPS_CXX11
# MPI library
# see discussion in Section 3.4 of the manual

View File

@ -438,7 +438,7 @@ void FixIPI::final_integrate()
char header[MSGLEN+1];
double vir[9], pot=0.0;
double forceconv, potconv, posconv, pressconv, posconv3;
char retstr[1024];
char retstr[1024] = { '\0' };
// conversions from LAMMPS units to atomic units, which are used by i-PI
potconv=3.1668152e-06/force->boltz;
@ -488,7 +488,7 @@ void FixIPI::final_integrate()
vir[1] = comp_p->vector[3]*pressconv*myvol;
vir[2] = comp_p->vector[4]*pressconv*myvol;
vir[5] = comp_p->vector[5]*pressconv*myvol;
retstr[0]=0;
retstr[0] = '\0';
}
if (master) {
@ -511,7 +511,8 @@ void FixIPI::final_integrate()
writebuffer(ipisock,(char*) &nat,4, error);
writebuffer(ipisock,(char*) buffer, bsize*8, error);
writebuffer(ipisock,(char*) vir,9*8, error);
nat=strlen(retstr); writebuffer(ipisock,(char*) &nat,4, error);
nat=strlen(retstr);
writebuffer(ipisock,(char*) &nat,4, error);
writebuffer(ipisock,(char*) retstr, nat, error);
}
else

View File

@ -7,6 +7,19 @@ mode=$1
LC_ALL=C
export LC_ALL
cat <<EOF
WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING
WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING
Support for building the ML-POD package with the legacy build system using GNU
make will be removed in Summer 2025. Please switch to using CMake to build
LAMMPS as soon as possible and report any problems to developers@lammps.org
or post a bug report issue at https://github.com/lammps/lammps/issues
WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING
WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING
EOF
# arg1 = file, arg2 = file it depends on
action () {

View File

@ -639,8 +639,8 @@ void DumpNetCDFMPIIO::write()
nme = count();
int *block_sizes = new int[comm->nprocs];
MPI_Allgather(&nme, 1, MPI_INT, block_sizes, 1, MPI_INT, world);
blocki = 0;
for (int i = 0; i < comm->me; i++) blocki += block_sizes[i];
blocki = (MPI_Offset) 0;
for (int i = 0; i < comm->me; i++) blocki += (MPI_Offset) (block_sizes[i]);
delete[] block_sizes;
// ensure buf is sized for packing and communicating

View File

@ -49,11 +49,11 @@ class DumpNetCDFMPIIO : public DumpCustom {
int quantity; // type of the quantity
};
int framei; // current frame index
int blocki; // current block index
MPI_Offset framei; // current frame index
MPI_Offset blocki; // current block index
int ndata; // number of data blocks to expect
bigint ntotalgr; // # of atoms
MPI_Offset ntotalgr; // # of atoms
int n_perat; // # of netcdf per-atom properties
nc_perat_t *perat; // per-atom properties

View File

@ -7,6 +7,19 @@ mode=$1
LC_ALL=C
export LC_ALL
cat <<EOF
WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING
WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING
Support for building the PLUMED package with the legacy build system using GNU
make will be removed in Summer 2025. Please switch to using CMake to build
LAMMPS as soon as possible and report any problems to developers@lammps.org
or post a bug report issue at https://github.com/lammps/lammps/issues
WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING
WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING
EOF
# arg1 = file, arg2 = file it depends on
action () {

View File

@ -9,6 +9,19 @@ mode=$1
LC_ALL=C
export LC_ALL
cat <<EOF
WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING
WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING
The POEMS package will be removed from LAMMPS in Summer 2025 due to lack of
maintenance and use of code constructs that conflict with modern C++ compilers
and standards. Please contact developers@lammps.org if you have any concerns
about this step.
WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING
WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING
EOF
action () {
if (test $mode = 0) then
rm -f ../$1

View File

@ -261,7 +261,8 @@ FixReaxFFSpecies::FixReaxFFSpecies(LAMMPS *lmp, int narg, char **arg) :
posflag = 1;
posfreq = utils::inumeric(FLERR, arg[iarg + 1], false, lmp);
if (posfreq < nfreq || (posfreq % nfreq != 0))
error->all(FLERR, "Incompatible fix reaxff/species postion frequency {}", posfreq);
error->all(FLERR, "Incompatible fix reaxff/species position frequency {}",
posfreq);
filepos = new char[255];
strcpy(filepos, arg[iarg + 2]);

View File

@ -7,6 +7,19 @@ mode=$1
LC_ALL=C
export LC_ALL
cat <<EOF
WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING
WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING
Support for building the VTK package with the legacy build system using GNU
make will be removed in Summer 2025. Please switch to using CMake to build
LAMMPS as soon as possible and report any problems to developers@lammps.org
or post a bug report issue at https://github.com/lammps/lammps/issues
WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING
WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING-WARNING
EOF
# arg1 = file, arg2 = file it depends on
action () {

View File

@ -107,7 +107,7 @@ static constexpr int DELTA = 1048576;
DumpVTK::DumpVTK(LAMMPS *lmp, int narg, char **arg) :
DumpCustom(lmp, narg, arg)
{
if (narg == 5) error->all(FLERR,"No dump vtk arguments specified");
if (narg < 6) utils::missing_cmd_args(FLERR,"dump vtk", error);
pack_choice.clear();
vtype.clear();
@ -214,17 +214,18 @@ void DumpVTK::init_style()
// check that fix frequency is acceptable
for (int i = 0; i < ncompute; i++) {
int icompute = modify->find_compute(id_compute[i]);
if (icompute < 0) error->all(FLERR,"Could not find dump vtk compute ID");
compute[i] = modify->compute[icompute];
compute[i] = modify->get_compute_by_id(id_compute[i]);
if (!compute[i]) error->all(FLERR,"Could not find dump vtk compute ID {}", id_compute[i]);
}
for (int i = 0; i < nfix; i++) {
int ifix = modify->find_fix(id_fix[i]);
if (ifix < 0) error->all(FLERR,"Could not find dump vtk fix ID");
fix[i] = modify->fix[ifix];
if (nevery % modify->fix[ifix]->peratom_freq)
error->all(FLERR,"Dump vtk and fix not computed at compatible times");
fix[i] = modify->get_fix_by_id(id_fix[i]);
if (!fix[i]) {
error->all(FLERR,"Could not find dump vtk fix ID {}", id_fix[i]);
} else {
if (nevery % fix[i]->peratom_freq)
error->all(FLERR,"Dump vtk and fix ID {} not called at compatible times", id_fix[i]);
}
}
for (int i = 0; i < nvariable; i++) {
@ -359,8 +360,7 @@ int DumpVTK::count()
nstride = 1;
} else if (thresh_array[ithresh] == MOL) {
if (!atom->molecule_flag)
error->all(FLERR,
"Threshold for an atom property that isn't allocated");
error->all(FLERR, "Threshold for an atom property that isn't allocated");
tagint *molecule = atom->molecule;
for (i = 0; i < nlocal; i++) dchoose[i] = molecule[i];
ptr = dchoose;
@ -654,64 +654,54 @@ int DumpVTK::count()
} else if (thresh_array[ithresh] == RADIUS) {
if (!atom->radius_flag)
error->all(FLERR,
"Threshold for an atom property that isn't allocated");
error->all(FLERR,"Threshold for an atom property that isn't allocated");
ptr = atom->radius;
nstride = 1;
} else if (thresh_array[ithresh] == DIAMETER) {
if (!atom->radius_flag)
error->all(FLERR,
"Threshold for an atom property that isn't allocated");
error->all(FLERR,"Threshold for an atom property that isn't allocated");
double *radius = atom->radius;
for (i = 0; i < nlocal; i++) dchoose[i] = 2.0*radius[i];
ptr = dchoose;
nstride = 1;
} else if (thresh_array[ithresh] == OMEGAX) {
if (!atom->omega_flag)
error->all(FLERR,
"Threshold for an atom property that isn't allocated");
error->all(FLERR,"Threshold for an atom property that isn't allocated");
ptr = &atom->omega[0][0];
nstride = 3;
} else if (thresh_array[ithresh] == OMEGAY) {
if (!atom->omega_flag)
error->all(FLERR,
"Threshold for an atom property that isn't allocated");
error->all(FLERR,"Threshold for an atom property that isn't allocated");
ptr = &atom->omega[0][1];
nstride = 3;
} else if (thresh_array[ithresh] == OMEGAZ) {
if (!atom->omega_flag)
error->all(FLERR,
"Threshold for an atom property that isn't allocated");
error->all(FLERR,"Threshold for an atom property that isn't allocated");
ptr = &atom->omega[0][2];
nstride = 3;
} else if (thresh_array[ithresh] == ANGMOMX) {
if (!atom->angmom_flag)
error->all(FLERR,
"Threshold for an atom property that isn't allocated");
error->all(FLERR,"Threshold for an atom property that isn't allocated");
ptr = &atom->angmom[0][0];
nstride = 3;
} else if (thresh_array[ithresh] == ANGMOMY) {
if (!atom->angmom_flag)
error->all(FLERR,
"Threshold for an atom property that isn't allocated");
error->all(FLERR,"Threshold for an atom property that isn't allocated");
ptr = &atom->angmom[0][1];
nstride = 3;
} else if (thresh_array[ithresh] == ANGMOMZ) {
if (!atom->angmom_flag)
error->all(FLERR,
"Threshold for an atom property that isn't allocated");
error->all(FLERR,"Threshold for an atom property that isn't allocated");
ptr = &atom->angmom[0][2];
nstride = 3;
} else if (thresh_array[ithresh] == TQX) {
if (!atom->torque_flag)
error->all(FLERR,
"Threshold for an atom property that isn't allocated");
error->all(FLERR,"Threshold for an atom property that isn't allocated");
ptr = &atom->torque[0][0];
nstride = 3;
} else if (thresh_array[ithresh] == TQY) {
if (!atom->torque_flag)
error->all(FLERR,
"Threshold for an atom property that isn't allocated");
error->all(FLERR,"Threshold for an atom property that isn't allocated");
ptr = &atom->torque[0][1];
nstride = 3;
} else if (thresh_array[ithresh] == TQZ) {
@ -928,7 +918,7 @@ void DumpVTK::write()
if (nmax > maxbuf) {
if ((bigint) nmax * size_one > MAXSMALLINT)
error->all(FLERR,"Too much per-proc info for dump");
error->all(FLERR,"Too much per processor data info for dump");
maxbuf = nmax;
memory->destroy(buf);
memory->create(buf,maxbuf*size_one,"dump:buf");
@ -983,9 +973,10 @@ void DumpVTK::write()
void DumpVTK::pack(tagint *ids)
{
int n = 0;
for (std::map<int,FnPtrPack>::iterator it=pack_choice.begin(); it!=pack_choice.end(); ++it, ++n) {
current_pack_choice_key = it->first; // work-around for pack_compute, pack_fix, pack_variable
(this->*(it->second))(n);
for (auto &choice : pack_choice) {
current_pack_choice_key = choice.first; // work-around for pack_compute, pack_fix, pack_variable
(this->*(choice.second))(n);
++n;
}
if (ids) {
@ -1108,10 +1099,10 @@ void DumpVTK::buf2arrays(int n, double *mybuf)
pid[0] = points->InsertNextPoint(mybuf[iatom*size_one],mybuf[iatom*size_one+1],mybuf[iatom*size_one+2]);
int j=3; // 0,1,2 = x,y,z handled just above
for (std::map<int, vtkSmartPointer<vtkAbstractArray> >::iterator it=myarrays.begin(); it!=myarrays.end(); ++it) {
vtkAbstractArray *paa = it->second;
if (it->second->GetNumberOfComponents() == 3) {
switch (vtype[it->first]) {
for (auto &it : myarrays) {
vtkAbstractArray *paa = it.second;
if (it.second->GetNumberOfComponents() == 3) {
switch (vtype[it.first]) {
case Dump::INT:
{
int iv3[3] = { static_cast<int>(mybuf[iatom*size_one+j ]),
@ -1130,7 +1121,7 @@ void DumpVTK::buf2arrays(int n, double *mybuf)
}
j+=3;
} else {
switch (vtype[it->first]) {
switch (vtype[it.first]) {
case Dump::INT:
{
vtkIntArray *pia = static_cast<vtkIntArray*>(paa);
@ -1317,8 +1308,8 @@ void DumpVTK::write_vtk(int n, double *mybuf)
unstructuredGrid->SetPoints(points);
unstructuredGrid->SetCells(VTK_VERTEX, pointsCells);
for (std::map<int, vtkSmartPointer<vtkAbstractArray> >::iterator it=myarrays.begin(); it!=myarrays.end(); ++it) {
unstructuredGrid->GetPointData()->AddArray(it->second);
for (const auto & it : myarrays) {
unstructuredGrid->GetPointData()->AddArray(it.second);
}
vtkSmartPointer<vtkUnstructuredGridWriter> writer = vtkSmartPointer<vtkUnstructuredGridWriter>::New();
@ -1327,8 +1318,8 @@ void DumpVTK::write_vtk(int n, double *mybuf)
polyData->SetPoints(points);
polyData->SetVerts(pointsCells);
for (std::map<int, vtkSmartPointer<vtkAbstractArray> >::iterator it=myarrays.begin(); it!=myarrays.end(); ++it) {
polyData->GetPointData()->AddArray(it->second);
for (auto &it : myarrays) {
polyData->GetPointData()->AddArray(it.second);
}
vtkSmartPointer<vtkPolyDataWriter> writer = vtkSmartPointer<vtkPolyDataWriter>::New();
@ -1384,8 +1375,8 @@ void DumpVTK::write_vtp(int n, double *mybuf)
polyData->SetPoints(points);
polyData->SetVerts(pointsCells);
for (std::map<int, vtkSmartPointer<vtkAbstractArray> >::iterator it=myarrays.begin(); it!=myarrays.end(); ++it) {
polyData->GetPointData()->AddArray(it->second);
for (auto &it : myarrays) {
polyData->GetPointData()->AddArray(it.second);
}
vtkSmartPointer<vtkXMLPolyDataWriter> writer = vtkSmartPointer<vtkXMLPolyDataWriter>::New();
@ -1448,8 +1439,8 @@ void DumpVTK::write_vtu(int n, double *mybuf)
unstructuredGrid->SetPoints(points);
unstructuredGrid->SetCells(VTK_VERTEX, pointsCells);
for (std::map<int, vtkSmartPointer<vtkAbstractArray> >::iterator it=myarrays.begin(); it!=myarrays.end(); ++it) {
unstructuredGrid->GetPointData()->AddArray(it->second);
for (auto &it : myarrays) {
unstructuredGrid->GetPointData()->AddArray(it.second);
}
vtkSmartPointer<vtkXMLUnstructuredGridWriter> writer = vtkSmartPointer<vtkXMLUnstructuredGridWriter>::New();
@ -1540,9 +1531,8 @@ int DumpVTK::parse_fields(int narg, char **arg)
name[Z] = "z";
// customize by adding to if statement
int i;
for (int iarg = 5; iarg < narg; iarg++) {
i = iarg-5;
for (int iarg = 0; iarg < narg; iarg++) {
if (strcmp(arg[iarg],"id") == 0) {
pack_choice[ID] = &DumpVTK::pack_id;
@ -1550,7 +1540,7 @@ int DumpVTK::parse_fields(int narg, char **arg)
name[ID] = arg[iarg];
} else if (strcmp(arg[iarg],"mol") == 0) {
if (!atom->molecule_flag)
error->all(FLERR,"Dumping an atom property that isn't allocated");
error->all(FLERR,"Dumping atom property 'mol' that isn't allocated");
pack_choice[MOL] = &DumpVTK::pack_molecule;
vtype[MOL] = Dump::INT;
name[MOL] = arg[iarg];
@ -1665,98 +1655,97 @@ int DumpVTK::parse_fields(int narg, char **arg)
name[FZ] = arg[iarg];
} else if (strcmp(arg[iarg],"q") == 0) {
if (!atom->q_flag)
error->all(FLERR,"Dumping an atom property that isn't allocated");
error->all(FLERR,"Dumping atom property '{}' that isn't allocated", arg[iarg]);
pack_choice[Q] = &DumpVTK::pack_q;
vtype[Q] = Dump::DOUBLE;
name[Q] = arg[iarg];
} else if (strcmp(arg[iarg],"mux") == 0) {
if (!atom->mu_flag)
error->all(FLERR,"Dumping an atom property that isn't allocated");
error->all(FLERR,"Dumping atom property '{}' that isn't allocated", arg[iarg]);
pack_choice[MUX] = &DumpVTK::pack_mux;
vtype[MUX] = Dump::DOUBLE;
name[MUX] = arg[iarg];
} else if (strcmp(arg[iarg],"muy") == 0) {
if (!atom->mu_flag)
error->all(FLERR,"Dumping an atom property that isn't allocated");
error->all(FLERR,"Dumping atom property '{}' that isn't allocated", arg[iarg]);
pack_choice[MUY] = &DumpVTK::pack_muy;
vtype[MUY] = Dump::DOUBLE;
name[MUY] = arg[iarg];
} else if (strcmp(arg[iarg],"muz") == 0) {
if (!atom->mu_flag)
error->all(FLERR,"Dumping an atom property that isn't allocated");
error->all(FLERR,"Dumping atom property '{}' that isn't allocated", arg[iarg]);
pack_choice[MUZ] = &DumpVTK::pack_muz;
vtype[MUZ] = Dump::DOUBLE;
name[MUZ] = arg[iarg];
} else if (strcmp(arg[iarg],"mu") == 0) {
if (!atom->mu_flag)
error->all(FLERR,"Dumping an atom property that isn't allocated");
error->all(FLERR,"Dumping atom property '{}' that isn't allocated", arg[iarg]);
pack_choice[MU] = &DumpVTK::pack_mu;
vtype[MU] = Dump::DOUBLE;
name[MU] = arg[iarg];
} else if (strcmp(arg[iarg],"radius") == 0) {
if (!atom->radius_flag)
error->all(FLERR,"Dumping an atom property that isn't allocated");
error->all(FLERR,"Dumping atom property '{}' that isn't allocated", arg[iarg]);
pack_choice[RADIUS] = &DumpVTK::pack_radius;
vtype[RADIUS] = Dump::DOUBLE;
name[RADIUS] = arg[iarg];
} else if (strcmp(arg[iarg],"diameter") == 0) {
if (!atom->radius_flag)
error->all(FLERR,"Dumping an atom property that isn't allocated");
error->all(FLERR,"Dumping atom property '{}' that isn't allocated", arg[iarg]);
pack_choice[DIAMETER] = &DumpVTK::pack_diameter;
vtype[DIAMETER] = Dump::DOUBLE;
name[DIAMETER] = arg[iarg];
} else if (strcmp(arg[iarg],"omegax") == 0) {
if (!atom->omega_flag)
error->all(FLERR,"Dumping an atom property that isn't allocated");
error->all(FLERR,"Dumping atom property '{}' that isn't allocated", arg[iarg]);
pack_choice[OMEGAX] = &DumpVTK::pack_omegax;
vtype[OMEGAX] = Dump::DOUBLE;
name[OMEGAX] = arg[iarg];
} else if (strcmp(arg[iarg],"omegay") == 0) {
if (!atom->omega_flag)
error->all(FLERR,"Dumping an atom property that isn't allocated");
error->all(FLERR,"Dumping atom property '{}' that isn't allocated", arg[iarg]);
pack_choice[OMEGAY] = &DumpVTK::pack_omegay;
vtype[OMEGAY] = Dump::DOUBLE;
name[OMEGAY] = arg[iarg];
} else if (strcmp(arg[iarg],"omegaz") == 0) {
if (!atom->omega_flag)
error->all(FLERR,"Dumping an atom property that isn't allocated");
error->all(FLERR,"Dumping atom property '{}' that isn't allocated", arg[iarg]);
pack_choice[OMEGAZ] = &DumpVTK::pack_omegaz;
vtype[OMEGAZ] = Dump::DOUBLE;
name[OMEGAZ] = arg[iarg];
} else if (strcmp(arg[iarg],"angmomx") == 0) {
if (!atom->angmom_flag)
error->all(FLERR,"Dumping an atom property that isn't allocated");
error->all(FLERR,"Dumping atom property '{}' that isn't allocated", arg[iarg]);
pack_choice[ANGMOMX] = &DumpVTK::pack_angmomx;
vtype[ANGMOMX] = Dump::DOUBLE;
name[ANGMOMX] = arg[iarg];
} else if (strcmp(arg[iarg],"angmomy") == 0) {
if (!atom->angmom_flag)
error->all(FLERR,"Dumping an atom property that isn't allocated");
error->all(FLERR,"Dumping atom property '{}' that isn't allocated", arg[iarg]);
pack_choice[ANGMOMY] = &DumpVTK::pack_angmomy;
vtype[ANGMOMY] = Dump::DOUBLE;
name[ANGMOMY] = arg[iarg];
} else if (strcmp(arg[iarg],"angmomz") == 0) {
if (!atom->angmom_flag)
error->all(FLERR,"Dumping an atom property that isn't allocated");
error->all(FLERR,"Dumping atom property '{}' that isn't allocated", arg[iarg]);
pack_choice[ANGMOMZ] = &DumpVTK::pack_angmomz;
vtype[ANGMOMZ] = Dump::DOUBLE;
name[ANGMOMZ] = arg[iarg];
} else if (strcmp(arg[iarg],"tqx") == 0) {
if (!atom->torque_flag)
error->all(FLERR,"Dumping an atom property that isn't allocated");
error->all(FLERR,"Dumping atom property '{}' that isn't allocated", arg[iarg]);
pack_choice[TQX] = &DumpVTK::pack_tqx;
vtype[TQX] = Dump::DOUBLE;
name[TQX] = arg[iarg];
} else if (strcmp(arg[iarg],"tqy") == 0) {
if (!atom->torque_flag)
error->all(FLERR,"Dumping an atom property that isn't allocated");
error->all(FLERR,"Dumping atom property '{}' that isn't allocated", arg[iarg]);
pack_choice[TQY] = &DumpVTK::pack_tqy;
vtype[TQY] = Dump::DOUBLE;
name[TQY] = arg[iarg];
} else if (strcmp(arg[iarg],"tqz") == 0) {
if (!atom->torque_flag)
error->all(FLERR,"Dumping an atom property that isn't allocated");
error->all(FLERR,"Dumping atom property '{}' that isn't allocated", arg[iarg]);
pack_choice[TQZ] = &DumpVTK::pack_tqz;
vtype[TQZ] = Dump::DOUBLE;
name[TQZ] = arg[iarg];
@ -1766,7 +1755,7 @@ int DumpVTK::parse_fields(int narg, char **arg)
int n,flag,cols;
ArgInfo argi(arg[iarg],ArgInfo::COMPUTE|ArgInfo::FIX|ArgInfo::VARIABLE
|ArgInfo::DNAME|ArgInfo::INAME);
argindex[ATTRIBUTES+i] = argi.get_index1();
argindex[ATTRIBUTES+iarg] = argi.get_index1();
auto aname = argi.get_name();
switch (argi.get_type()) {
@ -1779,107 +1768,114 @@ int DumpVTK::parse_fields(int narg, char **arg)
// if no trailing [], then arg is set to 0, else arg is int between []
case ArgInfo::COMPUTE:
pack_choice[ATTRIBUTES+i] = &DumpVTK::pack_compute;
vtype[ATTRIBUTES+i] = Dump::DOUBLE;
{
pack_choice[ATTRIBUTES+iarg] = &DumpVTK::pack_compute;
vtype[ATTRIBUTES+iarg] = Dump::DOUBLE;
n = modify->find_compute(aname);
if (n < 0) error->all(FLERR,"Could not find dump vtk compute ID: {}",aname);
if (modify->compute[n]->peratom_flag == 0)
error->all(FLERR,"Dump vtk compute {} does not compute per-atom info",aname);
if (argi.get_dim() == 0 && modify->compute[n]->size_peratom_cols > 0)
error->all(FLERR,"Dump vtk compute {} does not calculate per-atom vector",aname);
if (argi.get_dim() > 0 && modify->compute[n]->size_peratom_cols == 0)
error->all(FLERR,"Dump vtk compute {} does not calculate per-atom array",aname);
if (argi.get_dim() > 0 &&
argi.get_index1() > modify->compute[n]->size_peratom_cols)
error->all(FLERR,"Dump vtk compute {} vector is accessed out-of-range",aname);
field2index[ATTRIBUTES+i] = add_compute(aname);
name[ATTRIBUTES+i] = arg[iarg];
auto icompute = modify->get_compute_by_id(aname);
if (!icompute) {
error->all(FLERR,"Could not find dump vtk compute ID: {}",aname);
} else {
if (icompute->peratom_flag == 0)
error->all(FLERR,"Dump vtk compute {} does not compute per-atom info",aname);
if (argi.get_dim() == 0 && icompute->size_peratom_cols > 0)
error->all(FLERR,"Dump vtk compute {} does not calculate per-atom vector",aname);
if (argi.get_dim() > 0 && icompute->size_peratom_cols == 0)
error->all(FLERR,"Dump vtk compute {} does not calculate per-atom array",aname);
if (argi.get_dim() > 0 && argi.get_index1() > icompute->size_peratom_cols)
error->all(FLERR,"Dump vtk compute {} vector is accessed out-of-range",aname);
field2index[ATTRIBUTES+iarg] = add_compute(aname);
name[ATTRIBUTES+iarg] = arg[iarg];
}
break;
}
// fix value = f_ID
// if no trailing [], then arg is set to 0, else arg is between []
case ArgInfo::FIX:
pack_choice[ATTRIBUTES+i] = &DumpVTK::pack_fix;
vtype[ATTRIBUTES+i] = Dump::DOUBLE;
{
pack_choice[ATTRIBUTES+iarg] = &DumpVTK::pack_fix;
vtype[ATTRIBUTES+iarg] = Dump::DOUBLE;
n = modify->find_fix(aname);
if (n < 0) error->all(FLERR,"Could not find dump vtk fix ID: {}",aname);
if (modify->fix[n]->peratom_flag == 0)
error->all(FLERR,"Dump vtk fix {} does not compute per-atom info",aname);
if (argi.get_dim() == 0 && modify->fix[n]->size_peratom_cols > 0)
error->all(FLERR,"Dump vtk fix {} does not compute per-atom vector",aname);
if (argi.get_dim() > 0 && modify->fix[n]->size_peratom_cols == 0)
error->all(FLERR,"Dump vtk fix {} does not compute per-atom array",aname);
if (argi.get_dim() > 0 &&
argi.get_index1() > modify->fix[n]->size_peratom_cols)
error->all(FLERR,"Dump vtk fix {} vector is accessed out-of-range",aname);
auto ifix = modify->get_fix_by_id(aname);
if (!ifix) {
error->all(FLERR,"Could not find dump vtk fix ID: {}",aname);
} else {
if (ifix->peratom_flag == 0)
error->all(FLERR,"Dump vtk fix {} does not compute per-atom info",aname);
if (argi.get_dim() == 0 && ifix->size_peratom_cols > 0)
error->all(FLERR,"Dump vtk fix {} does not compute per-atom vector",aname);
if (argi.get_dim() > 0 && ifix->size_peratom_cols == 0)
error->all(FLERR,"Dump vtk fix {} does not compute per-atom array",aname);
if (argi.get_dim() > 0 && argi.get_index1() > ifix->size_peratom_cols)
error->all(FLERR,"Dump vtk fix {} vector is accessed out-of-range",aname);
field2index[ATTRIBUTES+i] = add_fix(aname);
name[ATTRIBUTES+i] = arg[iarg];
field2index[ATTRIBUTES+iarg] = add_fix(aname);
name[ATTRIBUTES+iarg] = arg[iarg];
}
break;
}
// variable value = v_name
case ArgInfo::VARIABLE:
pack_choice[ATTRIBUTES+i] = &DumpVTK::pack_variable;
vtype[ATTRIBUTES+i] = Dump::DOUBLE;
pack_choice[ATTRIBUTES+iarg] = &DumpVTK::pack_variable;
vtype[ATTRIBUTES+iarg] = Dump::DOUBLE;
n = input->variable->find(aname);
if (n < 0) error->all(FLERR,"Could not find dump vtk variable name {}",aname);
if (input->variable->atomstyle(n) == 0)
error->all(FLERR,"Dump vtk variable {} is not atom-style variable",aname);
field2index[ATTRIBUTES+i] = add_variable(aname);
name[ATTRIBUTES+i] = arg[iarg];
field2index[ATTRIBUTES+iarg] = add_variable(aname);
name[ATTRIBUTES+iarg] = arg[iarg];
break;
// custom per-atom floating point vector or array = d_ID d2_ID
case ArgInfo::DNAME:
pack_choice[ATTRIBUTES+i] = &DumpVTK::pack_custom;
vtype[ATTRIBUTES+i] = Dump::DOUBLE;
pack_choice[ATTRIBUTES+iarg] = &DumpVTK::pack_custom;
vtype[ATTRIBUTES+iarg] = Dump::DOUBLE;
n = atom->find_custom(aname,flag,cols);
if (n < 0)
error->all(FLERR,"Could not find custom per-atom property ID: {}", aname);
if (argindex[ATTRIBUTES+i] == 0) {
if (argindex[ATTRIBUTES+iarg] == 0) {
if (!flag || cols)
error->all(FLERR,"Property double vector {} for dump vtk does not exist",aname);
} else {
if (!flag || !cols)
error->all(FLERR,"Property double array {} for dump vtk does not exist",aname);
if (argindex[ATTRIBUTES+i] > atom->dcols[n])
if (argindex[ATTRIBUTES+iarg] > atom->dcols[n])
error->all(FLERR,"Dump vtk property array {} is accessed out-of-range",aname);
}
field2index[ATTRIBUTES+i] = add_custom(aname,1);
name[ATTRIBUTES+i] = arg[iarg];
field2index[ATTRIBUTES+iarg] = add_custom(aname,1);
name[ATTRIBUTES+iarg] = arg[iarg];
break;
// custom per-atom integer vector or array = i_ID or i2_ID
case ArgInfo::INAME:
pack_choice[ATTRIBUTES+i] = &DumpVTK::pack_custom;
vtype[ATTRIBUTES+i] = Dump::INT;
pack_choice[ATTRIBUTES+iarg] = &DumpVTK::pack_custom;
vtype[ATTRIBUTES+iarg] = Dump::INT;
n = atom->find_custom(aname,flag,cols);
if (n < 0)
error->all(FLERR,"Could not find custom per-atom property ID: {}", aname);
if (argindex[ATTRIBUTES+i] == 0) {
if (argindex[ATTRIBUTES+iarg] == 0) {
if (flag || cols)
error->all(FLERR,"Property integer vector {} for dump vtk does not exist",aname);
} else {
if (flag || !cols)
error->all(FLERR,"Property integer array {} for dump vtk does not exist",aname);
if (argindex[ATTRIBUTES+i] > atom->icols[n])
if (argindex[ATTRIBUTES+iarg] > atom->icols[n])
error->all(FLERR,"Dump vtk property array {} is accessed out-of-range",aname);
}
field2index[ATTRIBUTES+i] = add_custom(aname,0);
name[ATTRIBUTES+i] = arg[iarg];
field2index[ATTRIBUTES+iarg] = add_custom(aname,0);
name[ATTRIBUTES+iarg] = arg[iarg];
break;
// no match
@ -2232,42 +2228,50 @@ int DumpVTK::modify_param(int narg, char **arg)
// if no trailing [], then arg is set to 0, else arg is between []
case ArgInfo::COMPUTE:
{
thresh_array[nthresh] = COMPUTE;
n = modify->find_compute(aname);
if (n < 0) error->all(FLERR,"Could not find dump modify compute ID: {}",aname);
auto icompute = modify->get_compute_by_id(aname);
if (!icompute) {
error->all(FLERR,"Could not find dump modify compute ID: {}",aname);
} else {
if (modify->compute[n]->peratom_flag == 0)
error->all(FLERR,"Dump modify compute ID {} does not compute per-atom info",aname);
if (argi.get_dim() == 0 && icompute->size_peratom_cols > 0)
error->all(FLERR,"Dump modify compute ID {} does not compute per-atom vector",aname);
if (argi.get_index1() > 0 && icompute->size_peratom_cols == 0)
error->all(FLERR,"Dump modify compute ID {} does not compute per-atom array",aname);
if (argi.get_index1() > 0 &&
argi.get_index1() > icompute->size_peratom_cols)
error->all(FLERR,"Dump modify compute ID {} vector is not large enough",aname);
if (modify->compute[n]->peratom_flag == 0)
error->all(FLERR,"Dump modify compute ID {} does not compute per-atom info",aname);
if (argi.get_dim() == 0 && modify->compute[n]->size_peratom_cols > 0)
error->all(FLERR,"Dump modify compute ID {} does not compute per-atom vector",aname);
if (argi.get_index1() > 0 && modify->compute[n]->size_peratom_cols == 0)
error->all(FLERR,"Dump modify compute ID {} does not compute per-atom array",aname);
if (argi.get_index1() > 0 &&
argi.get_index1() > modify->compute[n]->size_peratom_cols)
error->all(FLERR,"Dump modify compute ID {} vector is not large enough",aname);
field2index[ATTRIBUTES+nfield+nthresh] = add_compute(aname);
field2index[ATTRIBUTES+nfield+nthresh] = add_compute(aname);
}
break;
}
// fix value = f_ID
// if no trailing [], then arg is set to 0, else arg is between []
case ArgInfo::FIX:
{
thresh_array[nthresh] = FIX;
n = modify->find_fix(aname);
if (n < 0) error->all(FLERR,"Could not find dump modify fix ID: {}",aname);
auto ifix = modify->get_fix_by_id(aname);
if (!ifix) {
error->all(FLERR,"Could not find dump modify fix ID: {}",aname);
} else {
if (ifix->peratom_flag == 0)
error->all(FLERR,"Dump modify fix ID {} does not compute per-atom info",aname);
if (argi.get_dim() == 0 && ifix->size_peratom_cols > 0)
error->all(FLERR,"Dump modify fix ID {} does not compute per-atom vector",aname);
if (argi.get_index1() > 0 && ifix->size_peratom_cols == 0)
error->all(FLERR,"Dump modify fix ID {} does not compute per-atom array",aname);
if (argi.get_index1() > 0 && argi.get_index1() > ifix->size_peratom_cols)
error->all(FLERR,"Dump modify fix ID {} vector is not large enough",aname);
if (modify->fix[n]->peratom_flag == 0)
error->all(FLERR,"Dump modify fix ID {} does not compute per-atom info",aname);
if (argi.get_dim() == 0 && modify->fix[n]->size_peratom_cols > 0)
error->all(FLERR,"Dump modify fix ID {} does not compute per-atom vector",aname);
if (argi.get_index1() > 0 && modify->fix[n]->size_peratom_cols == 0)
error->all(FLERR,"Dump modify fix ID {} does not compute per-atom array",aname);
if (argi.get_index1() > 0 && argi.get_index1() > modify->fix[n]->size_peratom_cols)
error->all(FLERR,"Dump modify fix ID {} vector is not large enough",aname);
field2index[ATTRIBUTES+nfield+nthresh] = add_fix(aname);
field2index[ATTRIBUTES+nfield+nthresh] = add_fix(aname);
}
break;
}
// variable value = v_ID

View File

@ -34,6 +34,13 @@
#error LAMMPS requires a C++11 (or later) compliant compiler. Enable C++11 compatibility or upgrade the compiler.
#endif
// C++17 check
#ifndef LAMMPS_CXX11
#if __cplusplus < 201703L
#error LAMMPS is planning to transition to requiring C++17. To disable this error please use a C++17 compliant compiler, enable C++17 support, or define -DLAMMPS_CXX11 in your makefile or when running cmake
#endif
#endif
#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS
#endif

View File

@ -55,30 +55,31 @@ index 0000000..b4f0fe6
+ TYPE DOC
+ PERMISSIONS OWNER_READ GROUP_READ WORLD_READ
+)
diff --git a/wham/wham.c b/wham/wham.c
index 487871b..526908e 100644
--- a/wham/wham.c
+++ b/wham/wham.c
@@ -21,7 +21,7 @@
#include "wham.h"
diff --git a/wham-2d/wham-2d.c b/wham-2d/wham-2d.c
index fb6e059..2c5594f 100644
--- a/wham-2d/wham-2d.c
+++ b/wham-2d/wham-2d.c
@@ -25,7 +25,7 @@
#include <time.h>
#include "wham-2d.h"
-#define COMMAND_LINE "Command line: wham [P|Ppi|Pval] hist_min hist_max num_bins tol temperature numpad metadatafile freefile [num_MC_trials randSeed]\n"
+#define COMMAND_LINE "Command line: wham [P|Ppi|Pval] [units <real|metal|lj|...>] hist_min hist_max num_bins tol temperature numpad metadatafile freefile [num_MC_trials randSeed]\n"
double HIST_MAX,HIST_MIN,BIN_WIDTH,TOL;
double *HISTOGRAM;
@@ -29,6 +29,7 @@ double kT;
int NUM_BINS;
int PERIODIC;
double PERIOD;
-#define COMMAND_LINE "Command line: wham-2d Px[=0|pi|val] hist_min_x hist_max_x num_bins_x Py[=0|pi|val] hist_min_y hist_max_y num_bins_y tol temperature numpad metadatafile freefile use_mask\n"
+#define COMMAND_LINE "Command line: wham-2d [units <real|metal|lj|...>] Px[=0|pi|val] hist_min_x hist_max_x num_bins_x Py[=0|pi|val] hist_min_y hist_max_y num_bins_y tol temperature numpad metadatafile freefile use_mask\n"
double HIST_MAXx,HIST_MINx,BIN_WIDTHx;
double HIST_MAXy,HIST_MINy,BIN_WIDTHy;
double TOL;
@@ -35,7 +35,7 @@ int NUM_BINSx, NUM_BINSy;
int PERIODICx, PERIODICy;
double PERIODx, PERIODy;
double *data1,**num,***bias;
-
+double k_B = k_B_DEFAULT;
int main(int argc, char *argv[])
{
@@ -117,6 +118,61 @@ else
PERIODIC = 0;
@@ -76,6 +76,61 @@ for (i=0; i<argc; i++)
}
printf("\n");
+// set k_B according to LAMMPS units settings
+if (strcmp(argv[1],"units") == 0)
@ -135,9 +136,116 @@ index 487871b..526908e 100644
+ argv += 2;
+ }
+
// Parse command line arguments
if (argc != 9 && argc !=11)
PERIODICx = parse_periodic(argv[1], &PERIODx);
if (PERIODICx)
{
diff --git a/wham-2d/wham-2d.h b/wham-2d/wham-2d.h
index b17e4bd..5fc17ff 100644
--- a/wham-2d/wham-2d.h
+++ b/wham-2d/wham-2d.h
@@ -20,15 +20,15 @@ extern int NUM_BINSy;
extern int PERIODICx,PERIODICy; // flags to turn on periodicity
extern double PERIODx, PERIODy; // flags to control periodic interval
+extern double k_B;
// A couple of predefined periodic units
#define DEGREES 360.0
#define RADIANS 6.28318530717959
-#define k_B 0.001982923700 // Boltzmann's constant in kcal/mol K
-//#define k_B 0.0083144621 // Boltzmann's constant kJ/mol-K
-//#define k_B 1.0 // Boltzmann's constant in reduced units
-
+#define k_B_DEFAULT 0.001982923700 // Boltzmann's constant in kcal/mol K
+//#define k_B_DEFAULT 0.0083144621 // Boltzmann's constant kJ/mol-K
+//#define k_B_DEFAULT 1.0 // Boltzmann's constant in reduced units
// Value inserted for the free energy of masked values
diff --git a/wham/wham.c b/wham/wham.c
index 487871b..1496eed 100644
--- a/wham/wham.c
+++ b/wham/wham.c
@@ -21,7 +21,7 @@
#include "wham.h"
-#define COMMAND_LINE "Command line: wham [P|Ppi|Pval] hist_min hist_max num_bins tol temperature numpad metadatafile freefile [num_MC_trials randSeed]\n"
+#define COMMAND_LINE "Command line: wham [units <real|metal|lj|...>] [P|Ppi|Pval] hist_min hist_max num_bins tol temperature numpad metadatafile freefile [num_MC_trials randSeed]\n"
double HIST_MAX,HIST_MIN,BIN_WIDTH,TOL;
double *HISTOGRAM;
@@ -29,6 +29,7 @@ double kT;
int NUM_BINS;
int PERIODIC;
double PERIOD;
+double k_B = k_B_DEFAULT;
int main(int argc, char *argv[])
{
@@ -82,6 +83,61 @@ for (i=0; i<argc; i++)
}
printf("\n");
+// set k_B according to LAMMPS units settings
+if (strcmp(argv[1],"units") == 0)
+ {
+ if (argc < 3)
+ {
+ printf( COMMAND_LINE );
+ exit(-1);
+ }
+
+ if (strcmp(argv[2], "lj") == 0)
+ {
+ k_B = 1.0;
+ }
+ else if (strcmp(argv[2], "real") == 0)
+ {
+ k_B = 0.0019872067;
+ }
+ else if (strcmp(argv[2], "metal") == 0)
+ {
+ k_B = 8.617343e-5;
+ }
+ else if (strcmp(argv[2], "si") == 0)
+ {
+ k_B = 1.3806504e-23;
+ }
+ else if (strcmp(argv[2], "cgs") == 0)
+ {
+ k_B = 1.3806504e-16;
+ }
+ else if (strcmp(argv[2], "electron") == 0)
+ {
+ k_B = 3.16681534e-6;
+ }
+ else if (strcmp(argv[2], "micro") == 0)
+ {
+ k_B = 1.3806504e-8;
+ }
+ else if (strcmp(argv[2], "nano") == 0)
+ {
+ k_B = 0.013806504;
+ }
+ else if (strcmp(argv[2], "default") == 0)
+ {
+ k_B = k_B_DEFAULT;
+ }
+ else
+ {
+ printf("Unknown unit style: %s\n%s", argv[2], COMMAND_LINE);
+ exit(-1);
+ }
+ printf("# Setting value of k_B to = %.15g\n", k_B);
+ argc -= 2;
+ argv += 2;
+ }
+
if (toupper(argv[1][0]) == 'P')
{
PERIODIC = 1;
diff --git a/wham/wham.h b/wham/wham.h
index aacc1e8..7d509f2 100644
--- a/wham/wham.h

View File

@ -0,0 +1,89 @@
---
lammps_version: 19 Nov 2024
tags: generated
date_generated: Fri Jan 10 13:54:41 2025
epsilon: 2.5e-13
skip_tests:
prerequisites: ! |
atom full
angle mwlc
pre_commands: ! ""
post_commands: ! ""
input_file: in.fourmol
angle_style: mwlc
angle_coeff: ! |
* 6.0 0.6 15.0 300.0
equilibrium: 4 3.141592653589793 3.141592653589793 3.141592653589793 3.141592653589793
extract: ! |
k1 1
k2 1
mu 1
temp 1
natoms: 29
init_energy: 115.97311255470154
init_stress: ! |2-
1.0785144954758131e+01 -5.1561329771224154e+00 -5.6290119776357184e+00 1.7509753155291005e+01 8.4620050528315804e+00 5.4460179571966592e+00
init_forces: ! |2
1 2.0049292277552344e+00 -3.4967838538707023e+00 -7.7679149207041780e+00
2 5.2379550897725657e-01 4.2410446627574743e+00 3.4103186723411198e+00
3 -2.6364713466403744e+00 1.7646356480410195e+00 6.7422761915790446e+00
4 5.9780828166032607e-01 -1.0977711474862293e+00 -1.2762851805838284e+00
5 2.7519993963547762e-02 -1.3655215729181727e+00 -4.0557483263144212e-01
6 -1.4407532935169898e-01 -1.5931923885520087e+00 -1.8663167177332292e+00
7 -4.1794796128320089e-01 4.1379756743889873e-01 -9.9274508603132139e-02
8 8.6885282425298183e-01 2.9273693794680500e-01 3.9875384936490477e+00
9 -7.4989162989673552e-01 1.9120936074864758e-02 1.6480002237326197e-01
10 4.5851731938743301e+00 5.1383619725146579e-01 -7.8986229128522627e+00
11 -1.3361238263371962e+00 -1.6154590769980759e+00 1.3132946273952864e+00
12 -9.8353444089007258e-01 5.7660344986117273e-01 -1.6760444984003993e+00
13 4.8213326840430115e-02 7.5476102608997231e-02 9.7662630040726750e-01
14 1.7020627463903515e-01 -4.9418713351985666e-02 -6.9510195676192543e-02
15 5.7466130382222369e-01 -3.0791486600816609e-01 9.0601148952989252e-01
16 -5.6604535775268596e+00 5.0708111379184277e+00 1.7013150451815964e+00
17 2.5273381761407760e+00 -3.4420010207137852e+00 1.8573629247281453e+00
18 2.0828420935010161e-01 2.1765636018344789e+00 -8.8331994782253780e+00
19 -2.5502877667816710e+00 -3.1771408888391202e+00 3.7828819753880119e+00
20 2.3420035574315694e+00 1.0005772870046410e+00 5.0503175028373661e+00
21 2.2520112617177057e+00 2.8191460010961373e+00 -8.4251146760580085e+00
22 -4.0101778142198494e+00 -2.7341370977288624e+00 2.9783951433938527e+00
23 1.7581665525021437e+00 -8.5008903367275068e-02 5.4467195326641562e+00
24 -1.9792115156439898e+00 7.6933124498060685e+00 -4.5803031378051688e+00
25 -1.5876110942732853e+00 -5.3190980720841390e+00 8.6990568523236744e-01
26 3.5668226099172751e+00 -2.3742143777219300e+00 3.7103974525728014e+00
27 -1.0535801895693373e+00 8.6490680045193269e+00 -2.9461596365031912e+00
28 -2.3037157984215133e+00 -5.1714048596555164e+00 1.2013129729191907e-01
29 3.3572959879908506e+00 -3.4776631448638109e+00 2.8260283392112724e+00
run_energy: 115.88929660500146
run_stress: ! |2-
1.0741962021125900e+01 -5.1494210571452070e+00 -5.5925409639806976e+00 1.7499135911989786e+01 8.4401379697723158e+00 5.4365488644723161e+00
run_forces: ! |2
1 2.0024084967323734e+00 -3.4852712888973301e+00 -7.7681384109278948e+00
2 5.1802520314744682e-01 4.2290273746409701e+00 3.4156643023763298e+00
3 -2.6176139409651311e+00 1.7481727755506558e+00 6.7276571726932186e+00
4 5.9646423832275675e-01 -1.0896302596160039e+00 -1.2658946496090273e+00
5 2.0626395368878558e-02 -1.3553597325783064e+00 -4.0428709993242351e-01
6 -1.5043849290340794e-01 -1.6020934387436645e+00 -1.8709909377854954e+00
7 -4.1644858135120844e-01 4.1712949378864117e-01 -1.0014611176127630e-01
8 8.7761514222742898e-01 2.9932822072179732e-01 3.9914298835888857e+00
9 -7.5185528312840066e-01 1.9244616790871305e-02 1.6542886887136499e-01
10 4.5736254271229742e+00 4.9828467262363496e-01 -7.8986022120685373e+00
11 -1.3323136450232624e+00 -1.6103729207690813e+00 1.3097303435864336e+00
12 -1.0040757700004965e+00 5.7836875530999343e-01 -1.6448472694236678e+00
13 4.8392108795294986e-02 7.7447222505411639e-02 9.6494421976551426e-01
14 1.8086042252760026e-01 -5.1422366669672037e-02 -7.3717779732260791e-02
15 5.8324025586810402e-01 -3.0468600966273196e-01 8.9577956208287191e-01
16 -5.6548207755179911e+00 5.0752603376691656e+00 1.6979261789431477e+00
17 2.5263087987770385e+00 -3.4434274526643489e+00 1.8580639393328193e+00
18 2.1733330742608858e-01 2.1830182266117371e+00 -8.8242777257965024e+00
19 -2.5415995943828809e+00 -3.1730376716173803e+00 3.7883421709467422e+00
20 2.3242662869567923e+00 9.9001944500564321e-01 5.0359355548497611e+00
21 2.2580025853773256e+00 2.8068061574356138e+00 -8.4373139893370634e+00
22 -4.0070465500208554e+00 -2.7223210888728504e+00 2.9888102357206301e+00
23 1.7490439646435296e+00 -8.4485068562763388e-02 5.4485037536164329e+00
24 -1.9860712475490458e+00 7.7098710540424751e+00 -4.5855114458364374e+00
25 -1.5787959452376497e+00 -5.3290411597315357e+00 8.7215941857315382e-01
26 3.5648671927866955e+00 -2.3808298943109389e+00 3.7133520272632836e+00
27 -1.0631738916816893e+00 8.6588340987013801e+00 -2.9324082303496679e+00
28 -2.2973201808293515e+00 -5.1771902142248960e+00 1.1264225202087563e-01
29 3.3604940725110408e+00 -3.4816438844764841e+00 2.8197659783287921e+00
...

View File

@ -105,6 +105,11 @@ if(Python_EXECUTABLE)
set_tests_properties(PythonPyLammps PROPERTIES ENVIRONMENT "${PYTHON_TEST_ENVIRONMENT}")
endif()
add_test(NAME PythonCmdWrapper
COMMAND ${PYTHON_TEST_RUNNER} ${CMAKE_CURRENT_SOURCE_DIR}/python-cmdwrapper.py -v
WORKING_DIRECTORY ${EXECUTABLE_OUTPUT_PATH})
set_tests_properties(PythonCmdWrapper PROPERTIES ENVIRONMENT "${PYTHON_TEST_ENVIRONMENT}")
add_test(NAME PythonFormats
COMMAND ${PYTHON_TEST_RUNNER} ${CMAKE_CURRENT_SOURCE_DIR}/python-formats.py -v
WORKING_DIRECTORY ${EXECUTABLE_OUTPUT_PATH})

View File

@ -0,0 +1,97 @@
import os,unittest
from lammps import lammps
try:
import numpy
NUMPY_INSTALLED = True
except ImportError:
NUMPY_INSTALLED = False
@unittest.skipIf(not NUMPY_INSTALLED, "numpy is not available")
class PythonCmdWrapper(unittest.TestCase):
def setUp(self):
machine = None
if 'LAMMPS_MACHINE_NAME' in os.environ:
machine=os.environ['LAMMPS_MACHINE_NAME']
self.lmp = lammps(name=machine, cmdargs=['-nocite', '-log','none', '-echo', 'screen'])
self.lmp.cmd.units("lj")
self.lmp.cmd.atom_style("atomic")
self.lmp.cmd.atom_modify("map array")
if 'LAMMPS_CMAKE_CACHE' in os.environ:
self.cmake_cache = {}
with open(os.environ['LAMMPS_CMAKE_CACHE'], 'r') as f:
for line in f:
line = line.strip()
if not line or line.startswith('#') or line.startswith('//'): continue
parts = line.split('=')
key, value_type = parts[0].split(':')
if len(parts) > 1:
value = parts[1]
if value_type == "BOOL":
value = (value.upper() == "ON")
else:
value = None
self.cmake_cache[key] = value
def tearDown(self):
self.lmp.close()
del self.lmp
def test_version(self):
self.assertGreaterEqual(self.lmp.version(), 20200824)
def test_create_atoms(self):
self.lmp.cmd.region("box block", 0, 2, 0, 2, 0, 2)
self.lmp.cmd.create_box(1, "box")
x = [
1.0, 1.0, 1.0,
1.0, 1.0, 1.5
]
types = [1, 1]
self.assertEqual(self.lmp.create_atoms(2, id=None, type=types, x=x), 2)
self.assertEqual(self.lmp.extract_global("natoms"), 2)
pos = self.lmp.numpy.extract_atom("x")
self.assertEqual(pos.shape[0], 2)
numpy.testing.assert_array_equal(pos[0], tuple(x[0:3]))
numpy.testing.assert_array_equal(pos[1], tuple(x[3:6]))
def test_thermo_capture(self):
self.lmp.cmd.lattice("fcc", 0.8442),
self.lmp.cmd.region("box block", 0, 4, 0, 4, 0, 4)
self.lmp.cmd.create_box(1, "box")
self.lmp.cmd.create_atoms(1, "box")
self.lmp.cmd.mass(1, 1.0)
self.lmp.cmd.velocity("all create", 1.44, 87287, "loop geom")
self.lmp.cmd.pair_style("lj/cut", 2.5)
self.lmp.cmd.pair_coeff(1, 1, 1.0, 1.0, 2.5)
self.lmp.cmd.neighbor(0.3, "bin")
self.lmp.cmd.neigh_modify("delay 0 every 20 check no")
self.lmp.cmd.fix("1 all nve")
current_run = {}
def append_thermo_data(lmp):
for k, v in lmp.last_thermo().items():
current_run.setdefault(k, []).append(v)
# thermo data is only captured during a run if PYTHON package is enabled
# without it, it will only capture the final thermo at completion
nvalues = 1
if self.lmp.has_package("PYTHON"):
self.lmp.cmd.fix("myfix", "all", "python/invoke", 10, "end_of_step", append_thermo_data)
nvalues = 2
self.lmp.cmd.run(10)
append_thermo_data(self.lmp)
for k in ('Step', 'Temp', 'E_pair', 'E_mol', 'TotEng', 'Press'):
self.assertIn(k, current_run)
self.assertEqual(len(current_run[k]), nvalues)
if __name__ == "__main__":
unittest.main()