Merge branch 'master' into progguide-axel

This commit is contained in:
Axel Kohlmeyer
2020-10-06 17:11:47 -04:00
31 changed files with 1252 additions and 67 deletions

1
.gitignore vendored
View File

@ -37,6 +37,7 @@ vgcore.*
ehthumbs.db
Thumbs.db
.clang-format
.lammps_history
#cmake
/build*

View File

@ -90,6 +90,7 @@ if(BUILD_SHARED_LIBS) # for all pkg libs, mpi_stubs and linalg
endif()
option(BUILD_TOOLS "Build and install LAMMPS tools (msi2lmp, binary2txt, chain)" OFF)
option(BUILD_LAMMPS_SHELL "Build and install the LAMMPS shell" OFF)
include(GNUInstallDirs)
file(GLOB ALL_SOURCES ${LAMMPS_SOURCE_DIR}/[^.]*.cpp)
@ -642,6 +643,18 @@ if(BUILD_TOOLS)
install(FILES ${LAMMPS_DOC_DIR}/msi2lmp.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
endif()
if(BUILD_LAMMPS_SHELL)
find_package(PkgConfig REQUIRED)
pkg_check_modules(READLINE IMPORTED_TARGET REQUIRED readline)
if(NOT LAMMPS_EXCEPTIONS)
message(WARNING "The LAMMPS shell needs LAMMPS_EXCEPTIONS enabled for full functionality")
endif()
add_executable(lammps-shell ${LAMMPS_TOOLS_DIR}/lammps-shell/lammps-shell.cpp)
target_compile_definitions(lammps-shell PRIVATE -DLAMMPS_LIB_NO_MPI)
target_link_libraries(lammps-shell PRIVATE lammps PkgConfig::READLINE)
install(TARGETS lammps-shell EXPORT LAMMPS_Targets DESTINATION ${CMAKE_INSTALL_BINDIR})
endif()
include(Documentation)
###############################################################################

View File

@ -542,7 +542,8 @@ using CMake or Make.
.. code-block:: bash
-D BUILD_TOOLS=value # yes or no (default)
-D BUILD_TOOLS=value # yes or no (default)
-D BUILD_LAMMPS_SHELL=value # yes or no (default)
The generated binaries will also become part of the LAMMPS installation
(see below).
@ -558,6 +559,9 @@ using CMake or Make.
make micelle2d # build only micelle2d tool
make thermo_extract # build only thermo_extract tool
cd lammps/tools/lammps-shell
make # build LAMMPS shell
----------
.. _install:

View File

@ -328,6 +328,8 @@ Some common LAMMPS specific variables
- build LAMMPS with OpenMP support (default: ``on`` if compiler supports OpenMP fully, else ``off``)
* - ``BUILD_TOOLS``
- compile some additional executables from the ``tools`` folder (default: ``off``)
* - ``BUILD_LAMMPS_SHELL``
- compile the LAMMPS shell from the ``tools/lammps-shell`` folder (default: ``off``)
* - ``BUILD_DOC``
- include building the HTML format documentation for packaging/installing (default: ``off``)
* - ``CMAKE_TUNE_FLAGS``

View File

@ -15,6 +15,9 @@ This section documents the following functions:
- :cpp:func:`lammps_has_style`
- :cpp:func:`lammps_style_count`
- :cpp:func:`lammps_style_name`
- :cpp:func:`lammps_has_id`
- :cpp:func:`lammps_id_count`
- :cpp:func:`lammps_id_name`
--------------------
@ -124,3 +127,18 @@ approach.
.. doxygenfunction:: lammps_style_name
:project: progguide
-----------------------
.. doxygenfunction:: lammps_has_id
:project: progguide
-----------------------
.. doxygenfunction:: lammps_id_count
:project: progguide
-----------------------
.. doxygenfunction:: lammps_id_name
:project: progguide

View File

@ -9,6 +9,8 @@ functions. They do not directly call the LAMMPS library.
- :cpp:func:`lammps_set_fix_external_callback`
- :cpp:func:`lammps_fix_external_set_energy_global`
- :cpp:func:`lammps_fix_external_set_virial_global`
- :cpp:func:`lammps_is_running`
- :cpp:func:`lammps_force_timeout`
- :cpp:func:`lammps_has_error`
- :cpp:func:`lammps_get_last_error_message`
@ -39,6 +41,16 @@ functions. They do not directly call the LAMMPS library.
-----------------------
.. doxygenfunction:: lammps_is_running
:project: progguide
-----------------------
.. doxygenfunction:: lammps_force_timeout
:project: progguide
-----------------------
.. doxygenfunction:: lammps_has_error
:project: progguide

View File

@ -92,6 +92,7 @@ Miscellaneous tools
* :ref:`emacs <emacs>`
* :ref:`i-pi <ipi>`
* :ref:`kate <kate>`
* :ref:`LAMMPS shell <lammps_shell>`
* :ref:`singularity <singularity_tool>`
* :ref:`vim <vim>`
@ -397,10 +398,131 @@ The file was provided by Alessandro Luigi Sellerio
----------
.. _lammps_shell:
LAMMPS shell
------------
Overview
========
The LAMMPS Shell, ``lammps-shell`` is a program that functions very
similar to the regular LAMMPS executable but has several modifications
and additions that make it more powerful for interactive sessions,
i.e. where you type LAMMPS commands from the prompt instead of reading
them from a file.
- It uses the readline and history libraries to provide command line
editing and context aware TAB-expansion (details on that below).
- When processing an input file with the '-in' or '-i' flag from the
command line, it does not exit at the end of that input file but
stops at a prompt, so that additional commands can be issued
- Errors will not abort the shell but return to the prompt.
- It has additional commands aimed at interactive use (details below).
- Interrupting a calculation with CTRL-C will not terminate the
session but rather enforce a timeout to cleanly stop an ongoing
run (more info on timeouts is in the timer command documentation).
These enhancements makes the LAMMPS shell an attractive choice for
interactive LAMMPS sessions in graphical user interfaces.
TAB-expansion
=============
When writing commands interactively at the shell prompt, you can hit
the TAB key at any time to try and complete the text. This completion
is context aware and will expand any first word only to commands
available in that executable.
- For style commands it will expand to available styles of the
corresponding category (e.g. pair styles after a
:doc:`pair_style <pair_style>` command).
- For :doc:`compute <compute>`, :doc:`fix <fix>`, or :doc:`dump <dump>`
it will also expand only to already defined groups for the group-ID
keyword.
- For commands like :doc:`compute_modify <compute_modify>`,
:doc:`fix_modify <fix_modify>`, or :doc:`dump_modify <dump_modify>`
it will expand to known compute/fix/dump IDs only.
- When typing references to computes, fixes, or variables with a
"c\_", "f\_", or "v\_" prefix, respectively, then the expansion will
to known compute/fix IDs and variable names. Variable name expansion
is also available for the ${name} variable syntax.
- In all other cases, expansion will be performed on filenames.
Command line editing and history
================================
When typing commands, command line editing similar to what BASH
provides is available. Thus it is possible to move around the
currently line and perform various cut and insert and edit operations.
Previous commands can be retrieved by scrolling up (and down)
or searching (e.g. with CTRL-r).
Also history expansion through using the exclamation mark '!'
can be performed. Examples: '!!' will be replaced with the previous
command, '!-2' will repeat the command before that, '!30' will be
replaced with event number 30 in the command history list, and
'!run' with the last command line that started with "run". Adding
a ":p" to such a history expansion will result that the expansion is
printed and added to the history list, but NOT executed.
On exit the LAMMPS shell will write the history list to a file
".lammps_history" in the current working directory. If such a
file exists when the LAMMPS shell is launched it will be read to
populate the history list.
This is realized via the readline library and can thus be customized
with an ``.inputrc`` file in the home directory. For application
specific customization, the LAMMPS shell uses the name "lammps-shell".
For more information about using and customizing an application using
readline, please see the available documentation at:
`http://www.gnu.org/s/readline/#Documentation
<http://www.gnu.org/s/readline/#Documentation>`_
Additional commands
===================
The following commands are added to the LAMMPS shell on top of the
regular LAMMPS commands:
.. parsed-literal::
help (or ?) print a brief help message
history display the current command history list
clear_history wipe out the current command history list
\|<command> execute <command> as a shell command and return to the command prompt
exit exit the LAMMPS shell cleanly (unlike the "quit" command)
Compilation
===========
Compilation of the LAMMPS shell can be enabled by setting the CMake
variable ``BUILD_LAMMPS_SHELL`` to "on" or using the makefile in the
``tools/lammps-shell`` folder to compile after building LAMMPS using
the conventional make procedure. The makefile will likely need
customization depending on the features and settings used for
compiling LAMMPS.
Limitations
===========
The LAMMPS shell was not designed for use with MPI parallelization
via ``mpirun`` or ``mpiexec`` or ``srun``.
----------
.. _arc:
lmp2arc tool
----------------------
------------
The lmp2arc sub-directory contains a tool for converting LAMMPS output
files to the format for Accelrys' Insight MD code (formerly

View File

@ -205,11 +205,11 @@ the following table:
+-------+----------------------------------------------------+----------------+
| 4 | Force :math:`f_z` exerted on the wall | force units |
+-------+----------------------------------------------------+----------------+
| 5 | :math:`\Delta x` between wall surface and particle | distance units |
| 5 | :math:`x`-coordinate of contact point on wall | distance units |
+-------+----------------------------------------------------+----------------+
| 6 | :math:`\Delta y` between wall surface and particle | distance units |
| 6 | :math:`y`-coordinate of contact point on wall | distance units |
+-------+----------------------------------------------------+----------------+
| 7 | :math:`\Delta z` between wall surface and particle | distance units |
| 7 | :math:`z`-coordinate of contact point on wall | distance units |
+-------+----------------------------------------------------+----------------+
| 8 | Radius :math:`r` of atom | distance units |
+-------+----------------------------------------------------+----------------+

View File

@ -246,11 +246,11 @@ the following table:
+-------+----------------------------------------------------+----------------+
| 4 | Force :math:`f_z` exerted on the wall | force units |
+-------+----------------------------------------------------+----------------+
| 5 | :math:`\Delta x` between wall surface and particle | distance units |
| 5 | :math:`x`-coordinate of contact point on wall | distance units |
+-------+----------------------------------------------------+----------------+
| 6 | :math:`\Delta y` between wall surface and particle | distance units |
| 6 | :math:`y`-coordinate of contact point on wall | distance units |
+-------+----------------------------------------------------+----------------+
| 7 | :math:`\Delta z` between wall surface and particle | distance units |
| 7 | :math:`z`-coordinate of contact point on wall | distance units |
+-------+----------------------------------------------------+----------------+
| 8 | Radius :math:`r` of atom | distance units |
+-------+----------------------------------------------------+----------------+

View File

@ -250,7 +250,7 @@ void FixWallGranRegion::post_force(int /*vflag*/)
// store contact info
if (peratom_flag) {
array_atom[i][0] = (double)atom->tag[i];
array_atom[i][0] = 1.0;
array_atom[i][4] = x[i][0] - dx;
array_atom[i][5] = x[i][1] - dy;
array_atom[i][6] = x[i][2] - dz;

View File

@ -145,8 +145,6 @@ FixSAEDVTK::FixSAEDVTK(LAMMPS *lmp, int narg, char **arg) :
memory->create(vector,nrows,"saed/vtk:vector");
memory->create(vector_total,nrows,"saed/vtk:vector_total");
extlist = nullptr;
vector_flag = 1;
size_vector = nrows;
@ -282,7 +280,6 @@ FixSAEDVTK::FixSAEDVTK(LAMMPS *lmp, int narg, char **arg) :
FixSAEDVTK::~FixSAEDVTK()
{
delete [] extlist;
delete [] filename;
delete [] ids;
memory->destroy(vector);

View File

@ -53,8 +53,10 @@ ComputeViscosityCos::ComputeViscosityCos(LAMMPS *lmp, int narg, char **arg) :
/* ---------------------------------------------------------------------- */
ComputeViscosityCos::~ComputeViscosityCos() {
if (!copymode)
if (!copymode) {
delete[] vector;
delete[] extlist;
}
}
/* ---------------------------------------------------------------------- */

View File

@ -1863,6 +1863,8 @@ int FixBondReact::check_constraints()
if (prrhob < rrhandom[(int) constraints[i][2]]->uniform()) return 0;
} else if (constraints[i][1] == RMSD) {
// call superpose
int iatom;
int iref = -1; // choose first atom as reference
int n2superpose = 0;
double **xfrozen; // coordinates for the "frozen" target molecule
double **xmobile; // coordinates for the "mobile" molecule
@ -1875,20 +1877,28 @@ int FixBondReact::check_constraints()
int myincr = 0;
for (int j = 0; j < onemol->natoms; j++) {
if (onemol->fragmentmask[ifragment][j]) {
iatom = atom->map(glove[j][1]);
if (iref == -1) iref = iatom;
iatom = domain->closest_image(iref,iatom);
for (int k = 0; k < 3; k++) {
xfrozen[myincr][k] = x[atom->map(glove[j][1])][k];
xfrozen[myincr][k] = x[iatom][k];
xmobile[myincr][k] = onemol->x[j][k];
}
myincr++;
}
}
} else {
int iatom;
int iref = -1; // choose first atom as reference
n2superpose = onemol->natoms;
memory->create(xfrozen,n2superpose,3,"bond/react:xfrozen");
memory->create(xmobile,n2superpose,3,"bond/react:xmobile");
for (int j = 0; j < n2superpose; j++) {
iatom = atom->map(glove[j][1]);
if (iref == -1) iref = iatom;
iatom = domain->closest_image(iref,iatom);
for (int k = 0; k < 3; k++) {
xfrozen[j][k] = x[atom->map(glove[j][1])][k];
xfrozen[j][k] = x[iatom][k];
xmobile[j][k] = onemol->x[j][k];
}
}

View File

@ -224,6 +224,7 @@ ComputeSlice::~ComputeSlice()
for (int m = 0; m < nvalues; m++) delete [] ids[m];
delete [] ids;
delete [] value2index;
delete [] extlist;
memory->destroy(vector);
memory->destroy(array);

View File

@ -234,7 +234,7 @@ DumpCustom::~DumpCustom()
for (int i = 0; i < ncustom; i++) delete [] id_custom[i];
memory->sfree(id_custom);
delete [] flag_custom;
memory->sfree(flag_custom);
memory->destroy(choose);
memory->destroy(dchoose);

View File

@ -760,7 +760,7 @@ void FixAveHisto::end_of_step()
}
irepeat = 0;
nvalid = ntimestep + nfreq - (nrepeat-1)*nevery;
nvalid = ntimestep + nfreq - static_cast<bigint>(nrepeat-1)*nevery;
modify->addstep_compute(nvalid);
// merge histogram stats across procs if necessary
@ -1046,7 +1046,7 @@ bigint FixAveHisto::nextvalid()
if (nvalid-nfreq == update->ntimestep && nrepeat == 1)
nvalid = update->ntimestep;
else
nvalid -= (nrepeat-1)*nevery;
nvalid -= static_cast<bigint>(nrepeat-1)*nevery;
if (nvalid < update->ntimestep) nvalid += nfreq;
return nvalid;
}

View File

@ -403,7 +403,7 @@ void FixAveHistoWeight::end_of_step()
}
irepeat = 0;
nvalid = ntimestep + nfreq - (nrepeat-1)*nevery;
nvalid = ntimestep + nfreq - static_cast<bigint>(nrepeat-1)*nevery;
modify->addstep_compute(nvalid);
// merge histogram stats across procs if necessary

View File

@ -640,7 +640,7 @@ void FixAveTime::invoke_scalar(bigint ntimestep)
}
irepeat = 0;
nvalid = ntimestep + nfreq - (nrepeat-1)*nevery;
nvalid = ntimestep + nfreq - static_cast<bigint>(nrepeat-1)*nevery;
modify->addstep_compute(nvalid);
// average the final result for the Nfreq timestep
@ -743,7 +743,7 @@ void FixAveTime::invoke_vector(bigint ntimestep)
if (!varlen[i] || which[i] != COMPUTE) continue;
if (nrepeat > 1 && ave == ONE) {
Compute *compute = modify->compute[value2index[i]];
compute->lock(this,ntimestep,ntimestep+(nrepeat-1)*nevery);
compute->lock(this,ntimestep,ntimestep+static_cast<bigint>(nrepeat-1)*nevery);
} else if ((ave == RUNNING || ave == WINDOW) && !lockforever) {
Compute *compute = modify->compute[value2index[i]];
compute->lock(this,update->ntimestep,-1);
@ -838,7 +838,7 @@ void FixAveTime::invoke_vector(bigint ntimestep)
}
irepeat = 0;
nvalid = ntimestep+nfreq - (nrepeat-1)*nevery;
nvalid = ntimestep+nfreq - static_cast<bigint>(nrepeat-1)*nevery;
modify->addstep_compute(nvalid);
// unlock any variable length computes at end of Nfreq epoch
@ -1146,7 +1146,7 @@ bigint FixAveTime::nextvalid()
if (nvalid-nfreq == update->ntimestep && nrepeat == 1)
nvalid = update->ntimestep;
else
nvalid -= (nrepeat-1)*nevery;
nvalid -= static_cast<bigint>(nrepeat-1)*nevery;
if (nvalid < update->ntimestep) nvalid += nfreq;
return nvalid;
}

View File

@ -22,6 +22,7 @@
#include "comm.h"
#include "compute.h"
#include "domain.h"
#include "dump.h"
#include "error.h"
#include "fix.h"
#include "fix_external.h"
@ -31,10 +32,13 @@
#include "input.h"
#include "memory.h"
#include "modify.h"
#include "molecule.h"
#include "neigh_list.h"
#include "neighbor.h"
#include "region.h"
#include "output.h"
#include "thermo.h"
#include "timer.h"
#include "universe.h"
#include "update.h"
#include "variable.h"
@ -4013,18 +4017,17 @@ int lammps_style_count(void *handle, const char *category) {
/** Look up the name of a style by index in the list of style of a given category in the LAMMPS library.
*
\verbatim embed:rst
This function copies the name of the package with the index *idx* into the
provided C-style string buffer. The length of the buffer must be provided
as *buf_size* argument. If the name of the package exceeds the length of the
buffer, it will be truncated accordingly. If the index is out of range,
the function returns 0 and *buffer* is set to an empty string, otherwise 1.
Please see :cpp:func:`lammps_has_style` for a list of valid categories.
\endverbatim
*
* This function copies the name of the *category* style with the index
* *idx* into the provided C-style string buffer. The length of the buffer
* must be provided as *buf_size* argument. If the name of the style
* exceeds the length of the buffer, it will be truncated accordingly.
* If the index is out of range, the function returns 0 and *buffer* is
* set to an empty string, otherwise 1.
*
* \param handle pointer to a previously created LAMMPS instance cast to ``void *``.
* \param category category of styles
* \param idx index of the package in the list of included packages (0 <= idx < style count)
* \param idx index of the style in the list of *category* styles (0 <= idx < style count)
* \param buffer string buffer to copy the name of the style to
* \param buf_size size of the provided string buffer
* \return 1 if successful, otherwise 0
@ -4046,6 +4049,167 @@ int lammps_style_name(void *handle, const char *category, int idx,
/* ---------------------------------------------------------------------- */
/** Check if a specific ID exists in the current LAMMPS instance
*
\verbatim embed:rst
This function checks if the current LAMMPS instance a *category* ID of
the given *name* exists. Valid categories are: *compute*\ , *dump*\ ,
*fix*\ , *group*\ , *molecule*\ , *region*\ , and *variable*\ .
\endverbatim
*
* \param handle pointer to a previously created LAMMPS instance cast to ``void *``.
* \param category category of the id
* \param name name of the id
* \return 1 if included, 0 if not.
*/
int lammps_has_id(void *handle, const char *category, const char *name) {
LAMMPS *lmp = (LAMMPS *) handle;
if (strcmp(category,"compute") == 0) {
int ncompute = lmp->modify->ncompute;
Compute **compute = lmp->modify->compute;
for (int i=0; i < ncompute; ++i) {
if (strcmp(name,compute[i]->id) == 0) return 1;
}
} else if (strcmp(category,"dump") == 0) {
int ndump = lmp->output->ndump;
Dump **dump = lmp->output->dump;
for (int i=0; i < ndump; ++i) {
if (strcmp(name,dump[i]->id) == 0) return 1;
}
} else if (strcmp(category,"fix") == 0) {
int nfix = lmp->modify->nfix;
Fix **fix = lmp->modify->fix;
for (int i=0; i < nfix; ++i) {
if (strcmp(name,fix[i]->id) == 0) return 1;
}
} else if (strcmp(category,"group") == 0) {
int ngroup = lmp->group->ngroup;
char **groups = lmp->group->names;
for (int i=0; i < ngroup; ++i) {
if (strcmp(groups[i],name) == 0) return 1;
}
} else if (strcmp(category,"molecule") == 0) {
int nmolecule = lmp->atom->nmolecule;
Molecule **molecule = lmp->atom->molecules;
for (int i=0; i < nmolecule; ++i) {
if (strcmp(name,molecule[i]->id) == 0) return 1;
}
} else if (strcmp(category,"region") == 0) {
int nregion = lmp->domain->nregion;
Region **region = lmp->domain->regions;
for (int i=0; i < nregion; ++i) {
if (strcmp(name,region[i]->id) == 0) return 1;
}
} else if (strcmp(category,"variable") == 0) {
int nvariable = lmp->input->variable->nvar;
char **varnames = lmp->input->variable->names;
for (int i=0; i < nvariable; ++i) {
if (strcmp(name,varnames[i]) == 0) return 1;
}
}
return 0;
}
/* ---------------------------------------------------------------------- */
/** Count the number of IDs of a category.
*
\verbatim embed:rst
This function counts how many IDs in the provided *category*
are defined in the current LAMMPS instance.
Please see :cpp:func:`lammps_has_id` for a list of valid
categories.
\endverbatim
*
* \param handle pointer to a previously created LAMMPS instance cast to ``void *``.
* \param category category of IDs
* \return number of IDs in category
*/
int lammps_id_count(void *handle, const char *category) {
LAMMPS *lmp = (LAMMPS *) handle;
if (strcmp(category,"compute") == 0) {
return lmp->modify->ncompute;
} else if (strcmp(category,"dump") == 0) {
return lmp->output->ndump;
} else if (strcmp(category,"fix") == 0) {
return lmp->modify->nfix;
} else if (strcmp(category,"group") == 0) {
return lmp->group->ngroup;
} else if (strcmp(category,"molecule") == 0) {
return lmp->atom->nmolecule;
} else if (strcmp(category,"region") == 0) {
return lmp->domain->nregion;
} else if (strcmp(category,"variable") == 0) {
return lmp->input->variable->nvar;
}
return 0;
}
/* ---------------------------------------------------------------------- */
/** Look up the name of an ID by index in the list of IDs of a given category.
*
* This function copies the name of the *category* ID with the index
* *idx* into the provided C-style string buffer. The length of the buffer
* must be provided as *buf_size* argument. If the name of the style
* exceeds the length of the buffer, it will be truncated accordingly.
* If the index is out of range, the function returns 0 and *buffer* is
* set to an empty string, otherwise 1.
*
* \param handle pointer to a previously created LAMMPS instance cast to ``void *``.
* \param category category of IDs
* \param idx index of the ID in the list of *category* styles (0 <= idx < count)
* \param buffer string buffer to copy the name of the style to
* \param buf_size size of the provided string buffer
* \return 1 if successful, otherwise 0
*/
int lammps_id_name(void *handle, const char *category, int idx,
char *buffer, int buf_size) {
LAMMPS *lmp = (LAMMPS *) handle;
if (strcmp(category,"compute") == 0) {
if ((idx >=0) && (idx < lmp->modify->ncompute)) {
strncpy(buffer, lmp->modify->compute[idx]->id, buf_size);
return 1;
}
} else if (strcmp(category,"dump") == 0) {
if ((idx >=0) && (idx < lmp->output->ndump)) {
strncpy(buffer, lmp->output->dump[idx]->id, buf_size);
return 1;
}
} else if (strcmp(category,"fix") == 0) {
if ((idx >=0) && (idx < lmp->modify->nfix)) {
strncpy(buffer, lmp->modify->fix[idx]->id, buf_size);
return 1;
}
} else if (strcmp(category,"group") == 0) {
if ((idx >=0) && (idx < lmp->group->ngroup)) {
strncpy(buffer, lmp->group->names[idx], buf_size);
return 1;
}
} else if (strcmp(category,"molecule") == 0) {
if ((idx >=0) && (idx < lmp->atom->nmolecule)) {
strncpy(buffer, lmp->atom->molecules[idx]->id, buf_size);
return 1;
}
} else if (strcmp(category,"region") == 0) {
if ((idx >=0) && (idx < lmp->domain->nregion)) {
strncpy(buffer, lmp->domain->regions[idx]->id, buf_size);
return 1;
}
} else if (strcmp(category,"variable") == 0) {
if ((idx >=0) && (idx < lmp->input->variable->nvar)) {
strncpy(buffer, lmp->input->variable->names[idx], buf_size);
return 1;
}
}
buffer[0] = '\0';
return 0;
}
/* ---------------------------------------------------------------------- */
/** This function is used to query whether LAMMPS was compiled with
* a real MPI library or in serial.
*
@ -4395,6 +4559,33 @@ void lammps_decode_image_flags(imageint image, int *flags)
flags[2] = (image >> IMG2BITS) - IMGMAX;
}
/** Check if LAMMPS is currently inside a run or minimization
*
* This function can be used from signal handlers or multi-threaded
* applications to determine if the LAMMPS instance is currently active.
*
* \param handle pointer to a previously created LAMMPS instance cast to ``void *``.
* \return 0 if idle or >0 if active */
int lammps_is_running(void *handle)
{
LAMMPS * lmp = (LAMMPS *) handle;
return lmp->update->whichflag;
}
/** Force a timeout to cleanly stop an ongoing run
*
* This function can be used from signal handlers or multi-threaded
* applications to cleanly terminate an ongoing run.
*
* \param handle pointer to a previously created LAMMPS instance cast to ``void *`` */
void lammps_force_timeout(void *handle)
{
LAMMPS * lmp = (LAMMPS *) handle;
return lmp->timer->force_timeout();
}
// ----------------------------------------------------------------------
// Library functions for error handling with exceptions enabled
// ----------------------------------------------------------------------

View File

@ -183,6 +183,10 @@ int lammps_has_style(void *, const char *, const char *);
int lammps_style_count(void *, const char *);
int lammps_style_name(void *, const char *, int, char *, int);
int lammps_has_id(void *, const char *, const char *);
int lammps_id_count(void *, const char *);
int lammps_id_name(void *, const char *, int, char *, int);
/* ----------------------------------------------------------------------
* Library functions for accessing neighbor lists
* ---------------------------------------------------------------------- */
@ -218,6 +222,9 @@ void lammps_set_fix_external_callback(void *, char *, FixExternalFnPtr, void*);
void lammps_fix_external_set_energy_global(void *, char *, double);
void lammps_fix_external_set_virial_global(void *, char *, double *);
int lammps_is_running(void *handle);
void lammps_force_timeout(void *handle);
int lammps_has_error(void *handle);
int lammps_get_last_error_message(void *handle, char *buffer, int buf_size);

View File

@ -935,7 +935,7 @@ run(real_t<T>& eigvalue, std::vector<T>& eigvec) const
//assert(matrix_size > 0);
//assert(0 < this->tridiag_eps_ratio && this->tridiag_eps_ratio < 1);
std::vector<std::vector<T>> u; // Lanczos vectors
std::vector<std::vector<T>> u; // Lanczos vectors
std::vector<real_t<T>> alpha; // Diagonal elements of an approximated tridiagonal matrix
std::vector<real_t<T>> beta; // Subdiagonal elements of an approximated tridiagonal matrix

View File

@ -244,7 +244,7 @@ void Min::setup(int flag)
bigint ndofme = 3 * static_cast<bigint>(atom->nlocal);
for (int m = 0; m < nextra_atom; m++)
ndofme += extra_peratom[m]*atom->nlocal;
ndofme += extra_peratom[m]*static_cast<bigint>(atom->nlocal);
MPI_Allreduce(&ndofme,&ndoftotal,1,MPI_LMP_BIGINT,MPI_SUM,world);
ndoftotal += nextra_global;

View File

@ -51,6 +51,7 @@ Update::Update(LAMMPS *lmp) : Pointers(lmp)
multireplica = 0;
eflag_global = vflag_global = -1;
eflag_atom = vflag_atom = 0;
dt_default = 1;
unit_style = nullptr;

View File

@ -2687,23 +2687,23 @@ double Variable::collapse_tree(Tree *tree)
}
if (tree->type == STAGGER) {
int ivalue1 = static_cast<int> (collapse_tree(tree->first));
int ivalue2 = static_cast<int> (collapse_tree(tree->second));
bigint ivalue1 = static_cast<bigint> (collapse_tree(tree->first));
bigint ivalue2 = static_cast<bigint> (collapse_tree(tree->second));
if (tree->first->type != VALUE || tree->second->type != VALUE) return 0.0;
tree->type = VALUE;
if (ivalue1 <= 0 || ivalue2 <= 0 || ivalue1 <= ivalue2)
error->one(FLERR,"Invalid math function in variable formula");
int lower = update->ntimestep/ivalue1 * ivalue1;
int delta = update->ntimestep - lower;
bigint lower = update->ntimestep/ivalue1 * ivalue1;
bigint delta = update->ntimestep - lower;
if (delta < ivalue2) tree->value = lower+ivalue2;
else tree->value = lower+ivalue1;
return tree->value;
}
if (tree->type == LOGFREQ) {
int ivalue1 = static_cast<int> (collapse_tree(tree->first));
int ivalue2 = static_cast<int> (collapse_tree(tree->second));
int ivalue3 = static_cast<int> (collapse_tree(tree->extra[0]));
bigint ivalue1 = static_cast<bigint> (collapse_tree(tree->first));
bigint ivalue2 = static_cast<bigint> (collapse_tree(tree->second));
bigint ivalue3 = static_cast<bigint> (collapse_tree(tree->extra[0]));
if (tree->first->type != VALUE || tree->second->type != VALUE ||
tree->extra[0]->type != VALUE) return 0.0;
tree->type = VALUE;
@ -2711,9 +2711,9 @@ double Variable::collapse_tree(Tree *tree)
error->one(FLERR,"Invalid math function in variable formula");
if (update->ntimestep < ivalue1) tree->value = ivalue1;
else {
int lower = ivalue1;
bigint lower = ivalue1;
while (update->ntimestep >= ivalue3*lower) lower *= ivalue3;
int multiple = update->ntimestep/lower;
bigint multiple = update->ntimestep/lower;
if (multiple < ivalue2) tree->value = (multiple+1)*lower;
else tree->value = lower*ivalue3;
}
@ -2721,9 +2721,9 @@ double Variable::collapse_tree(Tree *tree)
}
if (tree->type == LOGFREQ2) {
int ivalue1 = static_cast<int> (collapse_tree(tree->first));
int ivalue2 = static_cast<int> (collapse_tree(tree->second));
int ivalue3 = static_cast<int> (collapse_tree(tree->extra[0]));
bigint ivalue1 = static_cast<bigint> (collapse_tree(tree->first));
bigint ivalue2 = static_cast<bigint> (collapse_tree(tree->second));
bigint ivalue3 = static_cast<bigint> (collapse_tree(tree->extra[0]));
if (tree->first->type != VALUE || tree->second->type != VALUE ||
tree->extra[0]->type != VALUE) return 0.0;
tree->type = VALUE;
@ -2733,7 +2733,7 @@ double Variable::collapse_tree(Tree *tree)
else {
tree->value = ivalue1;
double delta = ivalue1*(ivalue3-1.0)/ivalue2;
int count = 0;
bigint count = 0;
while (update->ntimestep >= tree->value) {
tree->value += delta;
count++;
@ -2745,9 +2745,9 @@ double Variable::collapse_tree(Tree *tree)
}
if (tree->type == LOGFREQ3) {
int ivalue1 = static_cast<int> (collapse_tree(tree->first));
int ivalue2 = static_cast<int> (collapse_tree(tree->second));
int ivalue3 = static_cast<int> (collapse_tree(tree->extra[0]));
bigint ivalue1 = static_cast<bigint> (collapse_tree(tree->first));
bigint ivalue2 = static_cast<bigint> (collapse_tree(tree->second));
bigint ivalue3 = static_cast<bigint> (collapse_tree(tree->extra[0]));
if (tree->first->type != VALUE || tree->second->type != VALUE ||
tree->extra[0]->type != VALUE) return 0.0;
tree->type = VALUE;
@ -2760,7 +2760,7 @@ double Variable::collapse_tree(Tree *tree)
tree->value = ivalue1;
double logsp = ivalue1;
double factor = pow(((double)ivalue3)/ivalue1, 1.0/(ivalue2-1));
int linsp = ivalue1;
bigint linsp = ivalue1;
while (update->ntimestep >= (tree->value)) {
logsp *= factor;
linsp++;
@ -2774,9 +2774,9 @@ double Variable::collapse_tree(Tree *tree)
}
if (tree->type == STRIDE) {
int ivalue1 = static_cast<int> (collapse_tree(tree->first));
int ivalue2 = static_cast<int> (collapse_tree(tree->second));
int ivalue3 = static_cast<int> (collapse_tree(tree->extra[0]));
bigint ivalue1 = static_cast<bigint> (collapse_tree(tree->first));
bigint ivalue2 = static_cast<bigint> (collapse_tree(tree->second));
bigint ivalue3 = static_cast<bigint> (collapse_tree(tree->extra[0]));
if (tree->first->type != VALUE || tree->second->type != VALUE ||
tree->extra[0]->type != VALUE) return 0.0;
tree->type = VALUE;
@ -2784,7 +2784,7 @@ double Variable::collapse_tree(Tree *tree)
error->one(FLERR,"Invalid math function in variable formula");
if (update->ntimestep < ivalue1) tree->value = ivalue1;
else if (update->ntimestep < ivalue2) {
int offset = update->ntimestep - ivalue1;
bigint offset = update->ntimestep - ivalue1;
tree->value = ivalue1 + (offset/ivalue3)*ivalue3 + ivalue3;
if (tree->value > ivalue2) tree->value = (double) MAXBIGINT;
} else tree->value = (double) MAXBIGINT;
@ -2792,12 +2792,12 @@ double Variable::collapse_tree(Tree *tree)
}
if (tree->type == STRIDE2) {
int ivalue1 = static_cast<int> (collapse_tree(tree->first));
int ivalue2 = static_cast<int> (collapse_tree(tree->second));
int ivalue3 = static_cast<int> (collapse_tree(tree->extra[0]));
int ivalue4 = static_cast<int> (collapse_tree(tree->extra[1]));
int ivalue5 = static_cast<int> (collapse_tree(tree->extra[2]));
int ivalue6 = static_cast<int> (collapse_tree(tree->extra[3]));
bigint ivalue1 = static_cast<bigint> (collapse_tree(tree->first));
bigint ivalue2 = static_cast<bigint> (collapse_tree(tree->second));
bigint ivalue3 = static_cast<bigint> (collapse_tree(tree->extra[0]));
bigint ivalue4 = static_cast<bigint> (collapse_tree(tree->extra[1]));
bigint ivalue5 = static_cast<bigint> (collapse_tree(tree->extra[2]));
bigint ivalue6 = static_cast<bigint> (collapse_tree(tree->extra[3]));
if (tree->first->type != VALUE || tree->second->type != VALUE ||
tree->extra[0]->type != VALUE || tree->extra[1]->type != VALUE ||
tree->extra[2]->type != VALUE || tree->extra[3]->type != VALUE)
@ -2813,15 +2813,15 @@ double Variable::collapse_tree(Tree *tree)
if (update->ntimestep < ivalue1) istep = ivalue1;
else if (update->ntimestep < ivalue2) {
if (update->ntimestep < ivalue4 || update->ntimestep > ivalue5) {
int offset = update->ntimestep - ivalue1;
bigint offset = update->ntimestep - ivalue1;
istep = ivalue1 + (offset/ivalue3)*ivalue3 + ivalue3;
if (update->ntimestep < ivalue2 && istep > ivalue4)
tree->value = ivalue4;
} else {
int offset = update->ntimestep - ivalue4;
bigint offset = update->ntimestep - ivalue4;
istep = ivalue4 + (offset/ivalue6)*ivalue6 + ivalue6;
if (istep > ivalue5) {
int offset = ivalue5 - ivalue1;
bigint offset = ivalue5 - ivalue1;
istep = ivalue1 + (offset/ivalue3)*ivalue3 + ivalue3;
if (istep > ivalue2) istep = MAXBIGINT;
}

View File

@ -49,11 +49,13 @@ class Variable : protected Pointers {
tagint int_between_brackets(char *&, int);
double evaluate_boolean(char *);
public:
int nvar; // # of defined variables
char **names; // name of each variable
private:
int me;
int nvar; // # of defined variables
int maxvar; // max # of variables following lists can hold
char **names; // name of each variable
int *style; // style of each variable
int *num; // # of values for each variable
int *which; // next available value for each variable

View File

@ -29,6 +29,7 @@ fep scripts for free-energy perturbation with USER-FEP pkg
i-pi Python wrapper for performing path-integral MD (PIMD)
ipp input pre-processor Perl tool for creating input scripts
kate add-ons to Kate editor for editing LAMMPS input scripts
lammps-shell LAMMPS executable enhanced for interactive use
lmp2arc convert LAMMPS output to Accelrys Insight format
lmp2cfg convert LAMMPS output to CFG files for AtomEye viz
matlab MatLab scripts for post-processing LAMMPS output

1
tools/lammps-shell/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/lammps-shell

View File

@ -0,0 +1,14 @@
SHELL=/bin/sh
CXX=g++
CXXFLAGS=-O -g -Wall -I../../src -DLAMMPS_LIB_NO_MPI
LDFLAGS= -L../../src -llammps -lreadline
lammps-shell: lammps-shell.o
$(CXX) -o $@ $^ $(LDFLAGS)
lammps-shell.o: lammps-shell.cpp
$(CXX) -c $(CXXFLAGS) -o $@ $<
clean:
@rm -f lammps-shell lammps-shell.o core *~ .lammps-history

107
tools/lammps-shell/README Normal file
View File

@ -0,0 +1,107 @@
The LAMMPS Shell. An enhanced LAMMPS executable for interactive sessions.
Overview
========
This is a program that functions very similar to the regular LAMMPS
executable but has several modifications and additions that make it
more powerful for interactive sessions, i.e. where you type LAMMPS
commands from the prompt instead of reading them from a file.
- It uses the readline and history libraries to provide command line
editing and context aware TAB-expansion (details on that below).
- When processing an input file with the '-in' or '-i' flag from the
command line, it does not exit at the end of that input file but
stops at a prompt, so that additional commands can be issued
- Errors will not abort the shell but return to the prompt.
- It has additional commands aimed at interactive use (details below).
- Interrupting a calculation with CTRL-C will not terminate the
session but rather enforce a timeout to cleanly stop an ongoing
run (more info on timeouts is in the timer command documentation).
These enhancements makes the LAMMPS shell an attractive choice for
interactive LAMMPS sessions in graphical user interfaces.
TAB-expansion
=============
When writing commands interactively at the shell prompt, you can hit
the TAB key at any time to try and complete the text. This completion
is context aware and will expand any first word only to commands
available in that executable.
- For style commands it will expand to available styles of the
corresponding category (e.g. pair styles after a pair_style command).
- For "compute", "fix", or "dump" it will also expand only to already
defined groups for the group-ID keyword.
- For commands like "compute_modify", "fix_modify", or "dump_modify"
it will expand to known compute/fix/dump IDs only.
- When typing references to computes, fixes, or variables with a
"c_", "f_", or "v_" prefix, respectively, then the expansion will
to known compute/fix IDs and variable names. Variable name expansion
is also available for the ${name} variable syntax.
- In all other cases, expansion will be performed on filenames.
Command line editing and history
================================
When typing commands, command line editing similar to what BASH
provides is available. Thus it is possible to move around the
currently line and perform various cut and insert and edit operations.
Previous commands can be retrieved by scrolling up (and down)
or searching (e.g. with CTRL-r).
Also history expansion through using the exclamation mark '!'
can be performed. Examples: '!!' will be replaced with the previous
command, '!-2' will repeat the command before that, '!30' will be
replaced with event number 30 in the command history list, and
'!run' with the last command line that started with "run". Adding
a ":p" to such a history expansion will result that the expansion is
printed and added to the history list, but NOT executed.
On exit the LAMMPS shell will write the history list to a file
".lammps_history" in the current working directory. If such a
file exists when the LAMMPS shell is launched it will be read to
populate the history list.
This is realized via the readline library and can thus be customized
with an ".inputrc" file in the home directory. For application specific
customization, the LAMMPS shell uses the name "lammps-shell".
For more information about using and customizing an application using
readline, please see the available documentation at:
http://www.gnu.org/s/readline/#Documentation
Additional commands
===================
The followind commands are added to the LAMMPS shell on top of the
regular LAMMPS commands:
- help (or ?) print a brief help message
- history display the current command history list
- clear_history wipe out the current command history list
- |<command> execute <command> as a shell command and return to the command prompt
- exit exit the LAMMPS shell cleanly (unlike the "quit" command)
Compilation
===========
Compilation of the LAMMPS shell can be enabled by setting the CMake
variable BUILD_LAMMPS_SHELL to "on" or using the makefile in the
tools/lammps-shell folder to compile after building LAMMPS using
the conventional make procedure. The makefile will likely need
customization depending on the features and settings used for
compiling LAMMPS.
Limitations
===========
The LAMMPS shell was not designed for use with MPI parallelization
via "mpirun" or "mpiexec" or "srun".

View File

@ -0,0 +1,604 @@
// LAMMPS Shell. An improved interactive LAMMPS session with
// command line editing, history, TAB expansion and shell escapes
// Copyright (c) 2020 Axel Kohlmeyer <akohlmey@gmail.com>
// This software is distributed under the GNU General Public License.
#include "library.h"
#include "utils.h"
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <iostream>
#include <string>
#include <vector>
#if !defined(_WIN32)
#include <unistd.h>
#else
#if !defined(WIN32_LEAN_AND_MEAN)
#define WIN32_LEAN_AND_MEAN
#endif
#include <io.h>
#include <windows.h>
#define isatty(x) _isatty(x)
#endif
#if !defined(_WIN32)
#include <signal.h>
#endif
#include <readline/history.h>
#include <readline/readline.h>
using namespace LAMMPS_NS;
const int buflen = 512;
char buf[buflen];
void *lmp = nullptr;
enum {
ATOM_STYLE,
INTEGRATE_STYLE,
MINIMIZE_STYLE,
PAIR_STYLE,
BOND_STYLE,
ANGLE_STYLE,
DIHEDRAL_STYLE,
IMPROPER_STYLE,
KSPACE_STYLE,
FIX_STYLE,
COMPUTE_STYLE,
REGION_STYLE,
DUMP_STYLE
};
const char *lmp_style[] = {"atom", "integrate", "minimize", "pair", "bond",
"angle", "dihedral", "improper", "kspace", "fix",
"compute", "region", "dump"};
enum { COMPUTE_ID, DUMP_ID, FIX_ID, MOLECULE_ID, REGION_ID, VARIABLE_ID };
const char *lmp_id[] = {"compute", "dump", "fix", "molecule", "region", "variable"};
std::vector<std::string> commands;
// this list of commands is generated by:
// grep '!strcmp(command,' ../../src/input.cpp | sed -e 's/^.*!strcmp(command,"\(.*\)".*$/"\1",/'
const char *cmdlist[] = {"clear",
"echo",
"if",
"include",
"jump",
"label",
"log",
"next",
"partition",
"print",
"python",
"quit",
"shell",
"variable",
"angle_coeff",
"angle_style",
"atom_modify",
"atom_style",
"bond_coeff",
"bond_style",
"bond_write",
"boundary",
"box",
"comm_modify",
"comm_style",
"compute",
"compute_modify",
"dielectric",
"dihedral_coeff",
"dihedral_style",
"dimension",
"dump",
"dump_modify",
"fix",
"fix_modify",
"group",
"improper_coeff",
"improper_style",
"kspace_modify",
"kspace_style",
"lattice",
"mass",
"min_modify",
"min_style",
"molecule",
"neigh_modify",
"neighbor",
"newton",
"package",
"pair_coeff",
"pair_modify",
"pair_style",
"pair_write",
"processors",
"region",
"reset_timestep",
"restart",
"run_style",
"special_bonds",
"suffix",
"thermo",
"thermo_modify",
"thermo_style",
"timestep",
"timer",
"uncompute",
"undump",
"unfix",
"units"};
static char *dupstring(const std::string &text)
{
int len = text.size() + 1;
char *copy = (char *)malloc(len);
strcpy(copy, text.c_str());
return copy;
}
template <int STYLE> char *style_generator(const char *text, int state)
{
static int idx, num, len;
if (!state) {
idx = 0;
num = lammps_style_count(lmp, lmp_style[STYLE]);
len = strlen(text);
}
while (idx < num) {
lammps_style_name(lmp, lmp_style[STYLE], idx, buf, buflen);
++idx;
if ((len == 0) || (strncmp(text, buf, len) == 0)) return dupstring(buf);
}
return nullptr;
}
template <int ID> char *id_generator(const char *text, int state)
{
static int idx, num, len;
if (!state) {
idx = 0;
num = lammps_id_count(lmp, lmp_id[ID]);
len = strlen(text);
}
while (idx < num) {
lammps_id_name(lmp, lmp_id[ID], idx, buf, buflen);
++idx;
if ((len == 0) || (strncmp(text, buf, len) == 0)) return dupstring(buf);
}
return nullptr;
}
template <int ID, char PREFIX> char *ref_generator(const char *text, int state)
{
char prefix[] = "X_";
prefix[0] = PREFIX;
if (strncmp(text, prefix, 2) == 0) {
char *id = id_generator<ID>(text + 2, state);
char *ref = nullptr;
if (id) {
ref = (char *)malloc(strlen(id) + 3);
if (ref) {
ref[0] = PREFIX;
ref[1] = '_';
ref[2] = 0;
strcat(ref, id);
}
free(id);
}
return ref;
}
return nullptr;
}
extern "C" {
#if !defined(_WIN32)
static void ctrl_c_handler(int)
#else
static BOOL WINAPI ctrl_c_handler(DWORD event)
#endif
{
#if defined(_WIN32)
if (event == CTRL_C_EVENT) {
#endif
if (lmp)
if (lammps_is_running(lmp)) lammps_force_timeout(lmp);
#if defined(_WIN32)
return TRUE;
}
return FALSE;
#endif
}
static char *cmd_generator(const char *text, int state)
{
static std::size_t idx, len;
if (!state) idx = 0;
len = strlen(text);
do {
if ((len == 0) || (commands[idx].substr(0, len) == text))
return dupstring(commands[idx++]);
else
++idx;
} while (idx < commands.size());
return nullptr;
}
static char *compute_id_generator(const char *text, int state)
{
return id_generator<COMPUTE_ID>(text, state);
}
static char *compute_ref_generator(const char *text, int state)
{
return ref_generator<COMPUTE_ID, 'c'>(text, state);
}
static char *dump_id_generator(const char *text, int state)
{
return id_generator<DUMP_ID>(text, state);
}
static char *fix_id_generator(const char *text, int state)
{
return id_generator<FIX_ID>(text, state);
}
static char *fix_ref_generator(const char *text, int state)
{
return ref_generator<FIX_ID, 'f'>(text, state);
}
static char *variable_ref_generator(const char *text, int state)
{
return ref_generator<VARIABLE_ID, 'v'>(text, state);
}
static char *variable_expand_generator(const char *text, int state)
{
if (strncmp(text, "${", 2) == 0) {
char *id = id_generator<VARIABLE_ID>(text + 2, state);
char *ref = nullptr;
if (id) {
ref = (char *)malloc(strlen(id) + 4);
if (ref) {
ref[0] = '$';
ref[1] = '{';
ref[2] = 0;
strcat(ref, id);
strcat(ref, "}");
}
free(id);
}
return ref;
}
return nullptr;
}
static char *atom_generator(const char *text, int state)
{
return style_generator<ATOM_STYLE>(text, state);
}
static char *integrate_generator(const char *text, int state)
{
return style_generator<INTEGRATE_STYLE>(text, state);
}
static char *minimize_generator(const char *text, int state)
{
return style_generator<MINIMIZE_STYLE>(text, state);
}
static char *pair_generator(const char *text, int state)
{
return style_generator<PAIR_STYLE>(text, state);
}
static char *bond_generator(const char *text, int state)
{
return style_generator<BOND_STYLE>(text, state);
}
static char *angle_generator(const char *text, int state)
{
return style_generator<ANGLE_STYLE>(text, state);
}
static char *dihedral_generator(const char *text, int state)
{
return style_generator<DIHEDRAL_STYLE>(text, state);
}
static char *improper_generator(const char *text, int state)
{
return style_generator<IMPROPER_STYLE>(text, state);
}
static char *kspace_generator(const char *text, int state)
{
return style_generator<KSPACE_STYLE>(text, state);
}
static char *fix_generator(const char *text, int state)
{
return style_generator<FIX_STYLE>(text, state);
}
static char *compute_generator(const char *text, int state)
{
return style_generator<COMPUTE_STYLE>(text, state);
}
static char *region_generator(const char *text, int state)
{
return style_generator<REGION_STYLE>(text, state);
}
static char *dump_generator(const char *text, int state)
{
return style_generator<DUMP_STYLE>(text, state);
}
char *group_generator(const char *text, int state)
{
static int idx, num, len;
if (!state) {
idx = 0;
num = lammps_id_count(lmp, "group");
len = strlen(text);
}
while (idx < num) {
lammps_id_name(lmp, "group", idx, buf, buflen);
++idx;
if ((len == 0) || (strncmp(text, buf, len) == 0)) return dupstring(buf);
}
return nullptr;
}
static char **cmd_completion(const char *text, int start, int)
{
char **matches = nullptr;
// avoid segfaults
if (strlen(text) == 0) return matches;
if (start == 0) {
// match command names from the beginning of a line
matches = rl_completion_matches(text, cmd_generator);
} else {
// try to provide context specific matches
// first split the already completed text into words for position specific expansion
auto words = utils::split_words(std::string(rl_line_buffer).substr(0, start));
if (strncmp(text, "c_", 2) == 0) { // expand references to computes or fixes
matches = rl_completion_matches(text, compute_ref_generator);
} else if (strncmp(text, "f_", 2) == 0) {
matches = rl_completion_matches(text, fix_ref_generator);
} else if (strncmp(text, "v_", 2) == 0) {
matches = rl_completion_matches(text, variable_ref_generator);
} else if (strncmp(text, "${", 2) == 0) {
matches = rl_completion_matches(text, variable_expand_generator);
} else if (words.size() == 1) { // expand second word
if (words[0] == "atom_style") {
matches = rl_completion_matches(text, atom_generator);
} else if (words[0] == "pair_style") {
matches = rl_completion_matches(text, pair_generator);
} else if (words[0] == "bond_style") {
matches = rl_completion_matches(text, bond_generator);
} else if (words[0] == "angle_style") {
matches = rl_completion_matches(text, angle_generator);
} else if (words[0] == "dihedral_style") {
matches = rl_completion_matches(text, dihedral_generator);
} else if (words[0] == "improper_style") {
matches = rl_completion_matches(text, improper_generator);
} else if (words[0] == "kspace_style") {
matches = rl_completion_matches(text, kspace_generator);
} else if (words[0] == "run_style") {
matches = rl_completion_matches(text, integrate_generator);
} else if (words[0] == "min_style") {
matches = rl_completion_matches(text, minimize_generator);
} else if (words[0] == "compute_modify") {
matches = rl_completion_matches(text, compute_id_generator);
} else if (words[0] == "dump_modify") {
matches = rl_completion_matches(text, dump_id_generator);
} else if (words[0] == "fix_modify") {
matches = rl_completion_matches(text, fix_id_generator);
}
} else if (words.size() == 2) { // expand third word
// these commands have a group name as 3rd word
if ((words[0] == "fix") || (words[0] == "compute") || (words[0] == "dump")) {
matches = rl_completion_matches(text, group_generator);
} else if (words[0] == "region") {
matches = rl_completion_matches(text, region_generator);
}
} else if (words.size() == 3) { // expand fourth word
// style name is the fourth word
if (words[0] == "fix") {
matches = rl_completion_matches(text, fix_generator);
} else if (words[0] == "compute") {
matches = rl_completion_matches(text, compute_generator);
} else if (words[0] == "dump") {
matches = rl_completion_matches(text, dump_generator);
}
}
}
return matches;
}
} // end of extern "C"
static void init_commands()
{
// store internal commands
int ncmds = sizeof(cmdlist) / sizeof(const char *);
for (int i = 0; i < ncmds; ++i)
commands.push_back(cmdlist[i]);
// store optional commands from command styles
ncmds = lammps_style_count(lmp, "command");
for (int i = 0; i < ncmds; ++i) {
if (lammps_style_name(lmp, "command", i, buf, buflen)) commands.push_back(buf);
}
// store LAMMPS shell specific command names
commands.push_back("help");
commands.push_back("exit");
commands.push_back("history");
commands.push_back("clear_history");
// set name so there can be specific entries in ~/.inputrc
rl_readline_name = "lammps-shell";
rl_basic_word_break_characters = " \t\n\"\\'`@><=;|&(";
// attempt completions only if we are connected to a tty,
// otherwise any tabs in redirected input will cause havoc.
if (isatty(fileno(stdin))) {
rl_attempted_completion_function = cmd_completion;
} else {
rl_bind_key('\t', rl_insert);
}
// read old history
read_history(".lammps_history");
#if !defined(_WIN32)
signal(SIGINT, ctrl_c_handler);
#else
SetConsoleCtrlHandler(ctrl_c_handler, TRUE);
#endif
}
static int help_cmd()
{
std::cout << "\nThis is the LAMMPS Shell. An interactive LAMMPS session with command \n"
"line editing, context aware command expansion, and history.\n\n"
"- Hit the TAB key any time to try to expand the current word\n"
"- Issue shell commands by prefixing them with '|' (Example: '|ls -la')\n"
"- Use the '!' character for bash-like history epansion. (Example: '!run)\n\n"
"A history of the session will be written to the a file '.lammps_history'\n"
"in the current working directory and - if present - this file will be\n"
"read at the beginning of the next session of the LAMMPS shell.\n\n";
return 0;
}
static int shell_end()
{
write_history(".lammps_history");
if (lmp) lammps_close(lmp);
lammps_mpi_finalize();
lmp = nullptr;
return 0;
}
static int shell_cmd(const std::string &cmd)
{
char *expansion;
char *text = dupstring(cmd);
int retval = history_expand(text, &expansion);
// history expansion error
if (retval < 0) {
free(text);
free(expansion);
std::cout << "History error: " << utils::getsyserror() << "\n";
return 1;
}
// use expanded or original text and add to history
if (retval > 0) {
free(text);
text = expansion;
} else
free(expansion);
add_history(text);
// only print, don't execute.
if (retval == 2) {
std::cout << text << "\n";
free(text);
return 0;
}
// check for commands particular to lammps-shell
auto words = utils::split_words(text);
if (words[0][0] == '|') {
int rv = system(text + 1);
free(text);
return rv;
} else if ((words[0] == "help") || (words[0] == "?")) {
free(text);
return help_cmd();
} else if (words[0] == "exit") {
free(text);
return shell_end();
} else if (words[0] == "history") {
free(text);
HIST_ENTRY **list = history_list();
for (int i = 0; i < history_length; ++i) {
std::cout << i + history_base << ": " << list[i]->line << "\n";
}
return 0;
} else if (words[0] == "clear_history") {
free(text);
clear_history();
return 0;
}
lammps_command(lmp, text);
free(text);
return lammps_has_error(lmp);
}
int main(int argc, char **argv)
{
char *line;
std::string trimmed;
std::cout << "LAMMPS Shell version 1.0\n";
if (!lammps_config_has_exceptions())
std::cout << "WARNING: LAMMPS was compiled without exceptions\n"
"WARNING: The shell will terminate on errors.\n";
lmp = lammps_open_no_mpi(argc, argv, nullptr);
if (lmp == nullptr) return 1;
using_history();
init_commands();
// pre-load an input file that was provided on the command line
for (int i = 0; i < argc; ++i) {
if ((strcmp(argv[i], "-in") == 0) || (strcmp(argv[i], "-i") == 0)) {
lammps_file(lmp, argv[i + 1]);
}
}
while (lmp != nullptr) {
line = readline("LAMMPS Shell> ");
if (!line) break;
trimmed = utils::trim(line);
if (trimmed.size() > 0) {
shell_cmd(trimmed);
}
free(line);
}
return shell_end();
}

View File

@ -2,6 +2,7 @@
#include "lammps.h"
#include "library.h"
#include "timer.h"
#include <string>
#include "gmock/gmock.h"
@ -34,7 +35,11 @@ protected:
int argc = sizeof(args) / sizeof(char *);
::testing::internal::CaptureStdout();
lmp = lammps_open_no_mpi(argc, argv, NULL);
lmp = lammps_open_no_mpi(argc, argv, NULL);
lammps_command(lmp, "fix charge all property/atom q ghost yes");
lammps_command(lmp, "region box block 0 1 0 1 0 1");
lammps_command(lmp, "create_box 1 box");
lammps_command(lmp, "group none empty");
std::string output = ::testing::internal::GetCapturedStdout();
if (verbose) std::cout << output;
EXPECT_THAT(output, StartsWith("LAMMPS ("));
@ -118,6 +123,76 @@ TEST_F(LibraryConfig, style_name)
EXPECT_THAT(buf, StrEq(""));
};
TEST_F(LibraryConfig, has_id)
{
EXPECT_EQ(lammps_has_id(lmp, "compute", "thermo_temp"), 1);
EXPECT_EQ(lammps_has_id(lmp, "compute", "thermo_press"), 1);
EXPECT_EQ(lammps_has_id(lmp, "compute", "thermo_pe"), 1);
EXPECT_EQ(lammps_has_id(lmp, "dump", "xxx"), 0);
EXPECT_EQ(lammps_has_id(lmp, "fix", "charge"), 1);
EXPECT_EQ(lammps_has_id(lmp, "fix", "xxx"), 0);
EXPECT_EQ(lammps_has_id(lmp, "group", "all"), 1);
EXPECT_EQ(lammps_has_id(lmp, "group", "none"), 1);
EXPECT_EQ(lammps_has_id(lmp, "group", "xxx"), 0);
EXPECT_EQ(lammps_has_id(lmp, "molecule", "xxx"), 0);
EXPECT_EQ(lammps_has_id(lmp, "region", "box"), 1);
EXPECT_EQ(lammps_has_id(lmp, "region", "xxx"), 0);
EXPECT_EQ(lammps_has_id(lmp, "variable", "input_dir"), 1);
EXPECT_EQ(lammps_has_id(lmp, "variable", "xxx"), 0);
};
TEST_F(LibraryConfig, id_count)
{
EXPECT_EQ(lammps_id_count(lmp, "compute"), 3);
EXPECT_EQ(lammps_id_count(lmp, "dump"), 0);
EXPECT_EQ(lammps_id_count(lmp, "fix"), 1);
EXPECT_EQ(lammps_id_count(lmp, "group"), 2);
EXPECT_EQ(lammps_id_count(lmp, "molecule"), 0);
EXPECT_EQ(lammps_id_count(lmp, "region"), 1);
EXPECT_EQ(lammps_id_count(lmp, "variable"), 1);
};
TEST_F(LibraryConfig, id_name)
{
const int bufsize = 128;
char buf[bufsize];
EXPECT_EQ(lammps_id_name(lmp, "compute", 2, buf, bufsize), 1);
EXPECT_THAT(buf, StrEq("thermo_pe"));
EXPECT_EQ(lammps_id_name(lmp, "compute", 10, buf, bufsize), 0);
EXPECT_THAT(buf, StrEq(""));
EXPECT_EQ(lammps_id_name(lmp, "fix", 0, buf, bufsize), 1);
EXPECT_THAT(buf, StrEq("charge"));
EXPECT_EQ(lammps_id_name(lmp, "fix", 10, buf, bufsize), 0);
EXPECT_THAT(buf, StrEq(""));
EXPECT_EQ(lammps_id_name(lmp, "group", 0, buf, bufsize), 1);
EXPECT_THAT(buf, StrEq("all"));
EXPECT_EQ(lammps_id_name(lmp, "group", 1, buf, bufsize), 1);
EXPECT_THAT(buf, StrEq("none"));
EXPECT_EQ(lammps_id_name(lmp, "group", 10, buf, bufsize), 0);
EXPECT_THAT(buf, StrEq(""));
EXPECT_EQ(lammps_id_name(lmp, "region", 0, buf, bufsize), 1);
EXPECT_THAT(buf, StrEq("box"));
EXPECT_EQ(lammps_id_name(lmp, "region", 10, buf, bufsize), 0);
EXPECT_THAT(buf, StrEq(""));
EXPECT_EQ(lammps_id_name(lmp, "variable", 0, buf, bufsize), 1);
EXPECT_THAT(buf, StrEq("input_dir"));
EXPECT_EQ(lammps_id_name(lmp, "variable", 10, buf, bufsize), 0);
EXPECT_THAT(buf, StrEq(""));
};
TEST_F(LibraryConfig, is_running)
{
EXPECT_EQ(lammps_is_running(lmp), 0);
}
TEST_F(LibraryConfig, force_timeout)
{
LAMMPS_NS::Timer *timer = ((LAMMPS_NS::LAMMPS *)lmp)->timer;
EXPECT_EQ(timer->is_timeout(), false);
lammps_force_timeout(lmp);
EXPECT_EQ(timer->is_timeout(), true);
}
TEST(LAMMPSConfig, exceptions)
{
EXPECT_EQ(lammps_config_has_exceptions(), LAMMPS_HAS_EXCEPTIONS);