From ea3af3c2bc3ee5a16528cef9c6875dbd98bb056f Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 1 Oct 2020 09:34:38 -0400 Subject: [PATCH 01/37] resolve delete/free() mismatch --- src/dump_custom.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dump_custom.cpp b/src/dump_custom.cpp index cf034b0450..b5609b754f 100644 --- a/src/dump_custom.cpp +++ b/src/dump_custom.cpp @@ -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); From 8c56f609398f9c8c3cb826837060a0ec4cd6be52 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 1 Oct 2020 09:35:45 -0400 Subject: [PATCH 02/37] use bigint instead of int for timestep related variable functions to avoid overflows --- src/variable.cpp | 60 ++++++++++++++++++++++++------------------------ 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/src/variable.cpp b/src/variable.cpp index 16677ef5ae..6931fd9122 100644 --- a/src/variable.cpp +++ b/src/variable.cpp @@ -2687,23 +2687,23 @@ double Variable::collapse_tree(Tree *tree) } if (tree->type == STAGGER) { - int ivalue1 = static_cast (collapse_tree(tree->first)); - int ivalue2 = static_cast (collapse_tree(tree->second)); + bigint ivalue1 = static_cast (collapse_tree(tree->first)); + bigint ivalue2 = static_cast (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 (collapse_tree(tree->first)); - int ivalue2 = static_cast (collapse_tree(tree->second)); - int ivalue3 = static_cast (collapse_tree(tree->extra[0])); + bigint ivalue1 = static_cast (collapse_tree(tree->first)); + bigint ivalue2 = static_cast (collapse_tree(tree->second)); + bigint ivalue3 = static_cast (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 (collapse_tree(tree->first)); - int ivalue2 = static_cast (collapse_tree(tree->second)); - int ivalue3 = static_cast (collapse_tree(tree->extra[0])); + bigint ivalue1 = static_cast (collapse_tree(tree->first)); + bigint ivalue2 = static_cast (collapse_tree(tree->second)); + bigint ivalue3 = static_cast (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 (collapse_tree(tree->first)); - int ivalue2 = static_cast (collapse_tree(tree->second)); - int ivalue3 = static_cast (collapse_tree(tree->extra[0])); + bigint ivalue1 = static_cast (collapse_tree(tree->first)); + bigint ivalue2 = static_cast (collapse_tree(tree->second)); + bigint ivalue3 = static_cast (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 (collapse_tree(tree->first)); - int ivalue2 = static_cast (collapse_tree(tree->second)); - int ivalue3 = static_cast (collapse_tree(tree->extra[0])); + bigint ivalue1 = static_cast (collapse_tree(tree->first)); + bigint ivalue2 = static_cast (collapse_tree(tree->second)); + bigint ivalue3 = static_cast (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 (collapse_tree(tree->first)); - int ivalue2 = static_cast (collapse_tree(tree->second)); - int ivalue3 = static_cast (collapse_tree(tree->extra[0])); - int ivalue4 = static_cast (collapse_tree(tree->extra[1])); - int ivalue5 = static_cast (collapse_tree(tree->extra[2])); - int ivalue6 = static_cast (collapse_tree(tree->extra[3])); + bigint ivalue1 = static_cast (collapse_tree(tree->first)); + bigint ivalue2 = static_cast (collapse_tree(tree->second)); + bigint ivalue3 = static_cast (collapse_tree(tree->extra[0])); + bigint ivalue4 = static_cast (collapse_tree(tree->extra[1])); + bigint ivalue5 = static_cast (collapse_tree(tree->extra[2])); + bigint ivalue6 = static_cast (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; } From 4a40a708706ed3b73d945ac90c18699da07cc171 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 1 Oct 2020 09:48:54 -0400 Subject: [PATCH 03/37] avoid overflow of timestep related computations --- src/fix_ave_histo.cpp | 4 ++-- src/fix_ave_histo_weight.cpp | 2 +- src/fix_ave_time.cpp | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/fix_ave_histo.cpp b/src/fix_ave_histo.cpp index 4d1cd5b2dd..5d5abdc9ac 100644 --- a/src/fix_ave_histo.cpp +++ b/src/fix_ave_histo.cpp @@ -760,7 +760,7 @@ void FixAveHisto::end_of_step() } irepeat = 0; - nvalid = ntimestep + nfreq - (nrepeat-1)*nevery; + nvalid = ntimestep + nfreq - static_cast(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(nrepeat-1)*nevery; if (nvalid < update->ntimestep) nvalid += nfreq; return nvalid; } diff --git a/src/fix_ave_histo_weight.cpp b/src/fix_ave_histo_weight.cpp index 586c36af8a..08ec3632b4 100644 --- a/src/fix_ave_histo_weight.cpp +++ b/src/fix_ave_histo_weight.cpp @@ -403,7 +403,7 @@ void FixAveHistoWeight::end_of_step() } irepeat = 0; - nvalid = ntimestep + nfreq - (nrepeat-1)*nevery; + nvalid = ntimestep + nfreq - static_cast(nrepeat-1)*nevery; modify->addstep_compute(nvalid); // merge histogram stats across procs if necessary diff --git a/src/fix_ave_time.cpp b/src/fix_ave_time.cpp index b40a7eb009..4a25cca6e5 100644 --- a/src/fix_ave_time.cpp +++ b/src/fix_ave_time.cpp @@ -640,7 +640,7 @@ void FixAveTime::invoke_scalar(bigint ntimestep) } irepeat = 0; - nvalid = ntimestep + nfreq - (nrepeat-1)*nevery; + nvalid = ntimestep + nfreq - static_cast(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(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(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(nrepeat-1)*nevery; if (nvalid < update->ntimestep) nvalid += nfreq; return nvalid; } From 774ac8b2d9b1cd96882f7d6655761d49597e3796 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 1 Oct 2020 09:49:28 -0400 Subject: [PATCH 04/37] avoid overflow of per-local-atom computation --- src/min.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/min.cpp b/src/min.cpp index ea07820e53..7474025c1a 100644 --- a/src/min.cpp +++ b/src/min.cpp @@ -244,7 +244,7 @@ void Min::setup(int flag) bigint ndofme = 3 * static_cast(atom->nlocal); for (int m = 0; m < nextra_atom; m++) - ndofme += extra_peratom[m]*atom->nlocal; + ndofme += extra_peratom[m]*static_cast(atom->nlocal); MPI_Allreduce(&ndofme,&ndoftotal,1,MPI_LMP_BIGINT,MPI_SUM,world); ndoftotal += nextra_global; From 243a81e9d883050ec6e899c30db5d773a2c4291b Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 1 Oct 2020 14:49:23 -0400 Subject: [PATCH 05/37] must initialize eflag_atom and vflag_atom to zero in constructor --- src/update.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/update.cpp b/src/update.cpp index 492db2bd7c..41a0910556 100644 --- a/src/update.cpp +++ b/src/update.cpp @@ -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; From 48c45767f9ff9deb804ced678ce9ffd7de62ad77 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 1 Oct 2020 18:11:08 -0400 Subject: [PATCH 06/37] remove dead code --- src/USER-DIFFRACTION/fix_saed_vtk.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/USER-DIFFRACTION/fix_saed_vtk.cpp b/src/USER-DIFFRACTION/fix_saed_vtk.cpp index 00cfcbf91a..b39bc7ab99 100644 --- a/src/USER-DIFFRACTION/fix_saed_vtk.cpp +++ b/src/USER-DIFFRACTION/fix_saed_vtk.cpp @@ -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); From 2ea61b21f87eb9560a0ef1e1bb4266c225012c94 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 1 Oct 2020 18:11:19 -0400 Subject: [PATCH 07/37] fix small memory leaks --- src/USER-MISC/compute_viscosity_cos.cpp | 4 +++- src/compute_slice.cpp | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/USER-MISC/compute_viscosity_cos.cpp b/src/USER-MISC/compute_viscosity_cos.cpp index 4a798eb158..383fa17be2 100644 --- a/src/USER-MISC/compute_viscosity_cos.cpp +++ b/src/USER-MISC/compute_viscosity_cos.cpp @@ -53,8 +53,10 @@ ComputeViscosityCos::ComputeViscosityCos(LAMMPS *lmp, int narg, char **arg) : /* ---------------------------------------------------------------------- */ ComputeViscosityCos::~ComputeViscosityCos() { - if (!copymode) + if (!copymode) { delete[] vector; + delete[] extlist; + } } /* ---------------------------------------------------------------------- */ diff --git a/src/compute_slice.cpp b/src/compute_slice.cpp index 036a9bb289..7c56f07582 100644 --- a/src/compute_slice.cpp +++ b/src/compute_slice.cpp @@ -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); From 946a49662f8307c4ec93b142856037a9bbce6380 Mon Sep 17 00:00:00 2001 From: Jacob Gissinger Date: Fri, 2 Oct 2020 18:43:35 -0400 Subject: [PATCH 08/37] bond/react: rmsd constraint bugfix previously, eligible reactions could have been temporarily prevented, at the edge of the box, in serial --- src/USER-REACTION/fix_bond_react.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/USER-REACTION/fix_bond_react.cpp b/src/USER-REACTION/fix_bond_react.cpp index 814f8a0fcf..28a7ca92e7 100644 --- a/src/USER-REACTION/fix_bond_react.cpp +++ b/src/USER-REACTION/fix_bond_react.cpp @@ -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]; } } From 22cbac0b013f2746358a1e1fc76683d59903b6dd Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sat, 3 Oct 2020 09:48:54 -0400 Subject: [PATCH 09/37] initial version of LAMMPS shell. without build system support (yet). --- src/library.cpp | 8 + src/library.h | 8 + tools/lammps-shell/lammps-shell.cpp | 300 ++++++++++++++++++++++++++++ 3 files changed, 316 insertions(+) create mode 100644 tools/lammps-shell/lammps-shell.cpp diff --git a/src/library.cpp b/src/library.cpp index 90a71beb0c..4c759fd91c 100644 --- a/src/library.cpp +++ b/src/library.cpp @@ -4044,6 +4044,14 @@ int lammps_style_name(void *handle, const char *category, int idx, return 0; } + +int lammps_has_group(void *, const char *); +int lammps_group_count(void *); +int lammps_group_name(void *, 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); /* ---------------------------------------------------------------------- */ /** This function is used to query whether LAMMPS was compiled with diff --git a/src/library.h b/src/library.h index 2ddad86baa..2ac0997487 100644 --- a/src/library.h +++ b/src/library.h @@ -183,6 +183,14 @@ 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_group(void *, const char *); +int lammps_group_count(void *); +int lammps_group_name(void *, 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 * ---------------------------------------------------------------------- */ diff --git a/tools/lammps-shell/lammps-shell.cpp b/tools/lammps-shell/lammps-shell.cpp new file mode 100644 index 0000000000..a7f2c594f9 --- /dev/null +++ b/tools/lammps-shell/lammps-shell.cpp @@ -0,0 +1,300 @@ +// LAMMPS Shell. An improved interactive LAMMPS session with +// command line editing, history, TAB expansion and shell escapes + +// Copyright (c) 2020 Axel Kohlmeyer + +#include "library.h" +#include "utils.h" + +#include +#include +#include +#include +#include +#include +#include + +#if !defined(_WIN32) +#include +#else +#if !defined(WIN32_LEAN_AND_MEAN) +#define WIN32_LEAN_AND_MEAN +#endif +#include +#include +#define isatty(x) _isatty(x) +#endif + +#include +#include + +using namespace LAMMPS_NS; + +const int buflen = 512; +char buf[buflen]; + +std::vector 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; +} + +extern "C" { +static char *cmd_generator(const char *text, int state) +{ + static std::size_t idx; + if (!state) idx = 0; + + do { + if (commands[idx].substr(0, strlen(text)) == text) + return dupstring(commands[idx++]); + else + ++idx; + } while (idx < commands.size()); + return nullptr; +} + +static char **cmd_completion(const char *text, int start, int) +{ + char **matches = nullptr; + + 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 + auto words = utils::split_words(std::string(rl_line_buffer).substr(0, start)); + + // these commands have a group id as 3rd word + if ((words.size() == 2) && + ((words[0] == "fix") || (words[0] == "compute") || (words[0] == "dump"))) { + std::cout << "#words: " << words.size() << "\n"; + } + } + return matches; +} +} // end of extern "C" + +static void init_commands(void *lmp) +{ + // 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"; + + // attempt completions only if we have are connected to 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"); +} + +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 lammps_end(void *&lmp) +{ + write_history(".lammps_history"); + if (lmp) lammps_close(lmp); + lmp = nullptr; + return 0; +} + +static int lammps_cmd(void *&lmp, 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 lammps_end(lmp); + } 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; + + void *lmp = lammps_open_no_mpi(argc, argv, nullptr); + if (lmp == nullptr) return 1; + + using_history(); + init_commands(lmp); + + // 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) { + lammps_cmd(lmp, trimmed); + } + free(line); + } + + return lammps_end(lmp); +} From b231fa8a1612e40e90cd13cf707a4af4427af065 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sat, 3 Oct 2020 11:32:56 -0400 Subject: [PATCH 10/37] add completion for force style names --- tools/lammps-shell/lammps-shell.cpp | 155 +++++++++++++++++++++++++--- 1 file changed, 140 insertions(+), 15 deletions(-) diff --git a/tools/lammps-shell/lammps-shell.cpp b/tools/lammps-shell/lammps-shell.cpp index a7f2c594f9..2c0a8b0360 100644 --- a/tools/lammps-shell/lammps-shell.cpp +++ b/tools/lammps-shell/lammps-shell.cpp @@ -32,6 +32,25 @@ using namespace LAMMPS_NS; const int buflen = 512; char buf[buflen]; +void *lmp = nullptr; +enum { + ATOM, + INTEGRATE, + MINIMIZE, + PAIR, + BOND, + ANGLE, + DIHEDRAL, + IMPROPER, + KSPACE, + FIX, + COMPUTE, + REGION, + DUMP +}; +const char *lmp_style[] = {"atom", "integrate", "minimize", "pair", "bond", + "angle", "dihedral", "improper", "kspace", "fix", + "compute", "region", "dump"}; std::vector commands; @@ -116,14 +135,32 @@ static char *dupstring(const std::string &text) return copy; } +template 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; +} + extern "C" { static char *cmd_generator(const char *text, int state) { - static std::size_t idx; + static std::size_t idx, len; if (!state) idx = 0; + len = strlen(text); do { - if (commands[idx].substr(0, strlen(text)) == text) + if ((len == 0) || (commands[idx].substr(0, len) == text)) return dupstring(commands[idx++]); else ++idx; @@ -131,10 +168,78 @@ static char *cmd_generator(const char *text, int state) return nullptr; } +static char *atom_generator(const char *text, int state) +{ + return style_generator(text, state); +} + +static char *integrate_generator(const char *text, int state) +{ + return style_generator(text, state); +} + +static char *minimize_generator(const char *text, int state) +{ + return style_generator(text, state); +} + +static char *pair_generator(const char *text, int state) +{ + return style_generator(text, state); +} + +static char *bond_generator(const char *text, int state) +{ + return style_generator(text, state); +} + +static char *angle_generator(const char *text, int state) +{ + return style_generator(text, state); +} + +static char *dihedral_generator(const char *text, int state) +{ + return style_generator(text, state); +} + +static char *improper_generator(const char *text, int state) +{ + return style_generator(text, state); +} + +static char *kspace_generator(const char *text, int state) +{ + return style_generator(text, state); +} + +static char *fix_generator(const char *text, int state) +{ + return style_generator(text, state); +} + +static char *compute_generator(const char *text, int state) +{ + return style_generator(text, state); +} + +static char *region_generator(const char *text, int state) +{ + return style_generator(text, state); +} + +static char *dump_generator(const char *text, int state) +{ + return style_generator(text, state); +} + 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); @@ -143,17 +248,37 @@ static char **cmd_completion(const char *text, int start, int) // first split the already completed text auto words = utils::split_words(std::string(rl_line_buffer).substr(0, start)); - // these commands have a group id as 3rd word - if ((words.size() == 2) && - ((words[0] == "fix") || (words[0] == "compute") || (words[0] == "dump"))) { - std::cout << "#words: " << words.size() << "\n"; + 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.size() == 2) { // expand third word + + // these commands have a group name as 3rd word + if ((words[0] == "fix") || (words[0] == "compute") || (words[0] == "dump")) { + std::cout << "#words: " << words.size() << "\n"; + } } } + return matches; } + } // end of extern "C" -static void init_commands(void *lmp) +static void init_commands() { // store internal commands int ncmds = sizeof(cmdlist) / sizeof(const char *); @@ -175,7 +300,7 @@ static void init_commands(void *lmp) // set name so there can be specific entries in ~/.inputrc rl_readline_name = "lammps-shell"; - // attempt completions only if we have are connected to tty, + // 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; @@ -200,7 +325,7 @@ static int help_cmd() return 0; } -static int lammps_end(void *&lmp) +static int shell_end() { write_history(".lammps_history"); if (lmp) lammps_close(lmp); @@ -208,7 +333,7 @@ static int lammps_end(void *&lmp) return 0; } -static int lammps_cmd(void *&lmp, const std::string &cmd) +static int shell_cmd(const std::string &cmd) { char *expansion; char *text = dupstring(cmd); @@ -249,7 +374,7 @@ static int lammps_cmd(void *&lmp, const std::string &cmd) return help_cmd(); } else if (words[0] == "exit") { free(text); - return lammps_end(lmp); + return shell_end(); } else if (words[0] == "history") { free(text); HIST_ENTRY **list = history_list(); @@ -273,11 +398,11 @@ int main(int argc, char **argv) char *line; std::string trimmed; - void *lmp = lammps_open_no_mpi(argc, argv, nullptr); + lmp = lammps_open_no_mpi(argc, argv, nullptr); if (lmp == nullptr) return 1; using_history(); - init_commands(lmp); + init_commands(); // pre-load an input file that was provided on the command line for (int i = 0; i < argc; ++i) { @@ -291,10 +416,10 @@ int main(int argc, char **argv) if (!line) break; trimmed = utils::trim(line); if (trimmed.size() > 0) { - lammps_cmd(lmp, trimmed); + shell_cmd(trimmed); } free(line); } - return lammps_end(lmp); + return shell_end(); } From 01c85a3032d3676f37f2cf1adfa0743ce7027d47 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sat, 3 Oct 2020 12:25:56 -0400 Subject: [PATCH 11/37] correct embedded docs --- src/library.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/library.cpp b/src/library.cpp index 4c759fd91c..25fec98b5c 100644 --- a/src/library.cpp +++ b/src/library.cpp @@ -4013,18 +4013,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 From a2f7aae6db1a1b49f1811460eed72bbc70c0623b Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sat, 3 Oct 2020 12:26:17 -0400 Subject: [PATCH 12/37] add API to query group names --- src/library.cpp | 75 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 72 insertions(+), 3 deletions(-) diff --git a/src/library.cpp b/src/library.cpp index 25fec98b5c..585f293f58 100644 --- a/src/library.cpp +++ b/src/library.cpp @@ -4043,10 +4043,79 @@ int lammps_style_name(void *handle, const char *category, int idx, return 0; } +/* ---------------------------------------------------------------------- */ -int lammps_has_group(void *, const char *); -int lammps_group_count(void *); -int lammps_group_name(void *, int, char *, int); +/** Check if a group with a given name has been defined + * +\verbatim embed:rst +This function checks if a group with the provided *name* is defined +in the current LAMMPS instance. +\endverbatim + * + * \param handle pointer to a previously created LAMMPS instance cast to ``void *``. + * \param name name of the style + * \return 1 if defined, 0 if not. + */ +int lammps_has_group(void *handle, const char *name) +{ + LAMMPS *lmp = (LAMMPS *)handle; + + 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; + + return 0; +} + +/* ---------------------------------------------------------------------- */ + +/** Count the number of currently defined groups + * + * This function counts how many groups are defined in the + * current LAMMPS instance. + * + * \param handle pointer to a previously created LAMMPS instance cast to ``void *``. + * \return number of styles in category + */ +int lammps_group_count(void *handle) +{ + LAMMPS *lmp = (LAMMPS *)handle; + + return lmp->group->ngroup; +} + +/* ---------------------------------------------------------------------- */ + +/** Look up the name of a group by index in the list of groups. + * + * This function copies the name of the group 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 group 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 is returned. + * + * \param handle pointer to a previously created LAMMPS instance cast to ``void *``. + * \param idx index of the group in the list of groups (0 <= idx < group 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_group_name(void *handle, int idx, char *buffer, int buf_size) { + LAMMPS *lmp = (LAMMPS *)handle; + + int ngroup = lmp->group->ngroup; + char **groups = lmp->group->names; + if ((idx >=0) && (idx < ngroup)) { + strncpy(buffer, groups[idx], buf_size); + return 1; + } + + buffer[0] = '\0'; + return 0; +} int lammps_has_id(void *, const char *, const char *); int lammps_id_count(void *, const char *); From acf53ff55e229272f71c9f0fc373e80dc728a8be Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sat, 3 Oct 2020 12:26:40 -0400 Subject: [PATCH 13/37] add a few more context aware matcher functions --- tools/lammps-shell/lammps-shell.cpp | 35 ++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/tools/lammps-shell/lammps-shell.cpp b/tools/lammps-shell/lammps-shell.cpp index 2c0a8b0360..b9bb753e78 100644 --- a/tools/lammps-shell/lammps-shell.cpp +++ b/tools/lammps-shell/lammps-shell.cpp @@ -233,6 +233,23 @@ static char *dump_generator(const char *text, int state) return style_generator(text, state); } +char *group_generator(const char *text, int state) +{ + static int idx, num, len; + if (!state) { + idx = 0; + num = lammps_group_count(lmp); + len = strlen(text); + } + + while (idx < num) { + lammps_group_name(lmp, 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; @@ -263,12 +280,28 @@ static char **cmd_completion(const char *text, int start, int) 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.size() == 2) { // expand third word // these commands have a group name as 3rd word if ((words[0] == "fix") || (words[0] == "compute") || (words[0] == "dump")) { - std::cout << "#words: " << words.size() << "\n"; + 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); } } } From 4e8feff52c3db6c40f0be91e00428c4dc0388a90 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sat, 3 Oct 2020 22:01:57 -0400 Subject: [PATCH 14/37] add support for building the LAMMPS shell in CMake --- cmake/CMakeLists.txt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 0d041b2aa9..daa2a7d90a 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -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_SHELL "Build and install the LAMMPS shell" OFF) include(GNUInstallDirs) file(GLOB ALL_SOURCES ${LAMMPS_SOURCE_DIR}/[^.]*.cpp) @@ -642,6 +643,23 @@ if(BUILD_TOOLS) install(FILES ${LAMMPS_DOC_DIR}/msi2lmp.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1) endif() +if(BUILD_SHELL) + include(FindPkgConfig) + pkg_check_modules(READLINE IMPORTED_TARGET readline) + if(PKG_CONFIG_FOUND AND READLINE_FOUND) + if(NOT LAMMPS_EXCEPTIONS) + message(FATAL_ERROR "The LAMMPS shell requires LAMMPS_EXCEPTIONS enabled") + 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) + target_link_libraries(lammps-shell PRIVATE PkgConfig::READLINE) + install(TARGETS lammps-shell DESTINATION ${CMAKE_INSTALL_BINDIR}) + else() + message(WARNING "PkgConfig info for readline library not found, skipping build of 'lammps-shell'") + endif() +endif() + include(Documentation) ############################################################################### From c5514c0a36bcad0fddd2cebcb1afd6d9ac450045 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sat, 3 Oct 2020 22:02:13 -0400 Subject: [PATCH 15/37] windows portability fix --- tools/lammps-shell/lammps-shell.cpp | 52 ++++++++++++++--------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/tools/lammps-shell/lammps-shell.cpp b/tools/lammps-shell/lammps-shell.cpp index b9bb753e78..1ae548e4f5 100644 --- a/tools/lammps-shell/lammps-shell.cpp +++ b/tools/lammps-shell/lammps-shell.cpp @@ -34,19 +34,19 @@ const int buflen = 512; char buf[buflen]; void *lmp = nullptr; enum { - ATOM, - INTEGRATE, - MINIMIZE, - PAIR, - BOND, - ANGLE, - DIHEDRAL, - IMPROPER, - KSPACE, - FIX, - COMPUTE, - REGION, - DUMP + 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", @@ -170,67 +170,67 @@ static char *cmd_generator(const char *text, int state) static char *atom_generator(const char *text, int state) { - return style_generator(text, state); + return style_generator(text, state); } static char *integrate_generator(const char *text, int state) { - return style_generator(text, state); + return style_generator(text, state); } static char *minimize_generator(const char *text, int state) { - return style_generator(text, state); + return style_generator(text, state); } static char *pair_generator(const char *text, int state) { - return style_generator(text, state); + return style_generator(text, state); } static char *bond_generator(const char *text, int state) { - return style_generator(text, state); + return style_generator(text, state); } static char *angle_generator(const char *text, int state) { - return style_generator(text, state); + return style_generator(text, state); } static char *dihedral_generator(const char *text, int state) { - return style_generator(text, state); + return style_generator(text, state); } static char *improper_generator(const char *text, int state) { - return style_generator(text, state); + return style_generator(text, state); } static char *kspace_generator(const char *text, int state) { - return style_generator(text, state); + return style_generator(text, state); } static char *fix_generator(const char *text, int state) { - return style_generator(text, state); + return style_generator(text, state); } static char *compute_generator(const char *text, int state) { - return style_generator(text, state); + return style_generator(text, state); } static char *region_generator(const char *text, int state) { - return style_generator(text, state); + return style_generator(text, state); } static char *dump_generator(const char *text, int state) { - return style_generator(text, state); + return style_generator(text, state); } char *group_generator(const char *text, int state) From 1988e4c24c4ab250b9299733bcf843ff4a4243c7 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sat, 3 Oct 2020 23:38:02 -0400 Subject: [PATCH 16/37] add introspection for various kinds of IDs --- src/library.cpp | 141 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 138 insertions(+), 3 deletions(-) diff --git a/src/library.cpp b/src/library.cpp index 585f293f58..6c8d643453 100644 --- a/src/library.cpp +++ b/src/library.cpp @@ -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,8 +32,10 @@ #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 "universe.h" @@ -4117,9 +4120,141 @@ int lammps_group_name(void *handle, int idx, char *buffer, int buf_size) { return 0; } -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); +/* ---------------------------------------------------------------------- */ + +/** 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*\ , *molecule*\ , and *region*\ . +\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,"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; + } + } + 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,"molecule") == 0) { + return lmp->atom->nmolecule; + } else if (strcmp(category,"region") == 0) { + return lmp->domain->nregion; + } + 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,"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; + } + } + buffer[0] = '\0'; + return 0; +} + /* ---------------------------------------------------------------------- */ /** This function is used to query whether LAMMPS was compiled with From b1cc9949e4fbec2fb224c74d6fa8f917c51e77cd Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sat, 3 Oct 2020 23:38:22 -0400 Subject: [PATCH 17/37] include added introspection into docs --- doc/src/Library_config.rst | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/doc/src/Library_config.rst b/doc/src/Library_config.rst index 0c07896ff6..532bd5cfa0 100644 --- a/doc/src/Library_config.rst +++ b/doc/src/Library_config.rst @@ -15,6 +15,12 @@ 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_group` +- :cpp:func:`lammps_group_count` +- :cpp:func:`lammps_group_name` +- :cpp:func:`lammps_has_id` +- :cpp:func:`lammps_id_count` +- :cpp:func:`lammps_id_name` -------------------- @@ -124,3 +130,33 @@ a safer approach. .. doxygenfunction:: lammps_style_name :project: progguide +----------------------- + +.. doxygenfunction:: lammps_has_group + :project: progguide + +----------------------- + +.. doxygenfunction:: lammps_group_count + :project: progguide + +----------------------- + +.. doxygenfunction:: lammps_group_name + :project: progguide + +----------------------- + +.. doxygenfunction:: lammps_has_id + :project: progguide + +----------------------- + +.. doxygenfunction:: lammps_id_count + :project: progguide + +----------------------- + +.. doxygenfunction:: lammps_id_name + :project: progguide + From 9dfb715296c2752c6bce5984240d5ca94d426003 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sun, 4 Oct 2020 06:01:26 -0400 Subject: [PATCH 18/37] add support for variable names to id introspection in library interface --- src/library.cpp | 15 ++++++++++++++- src/variable.h | 6 ++++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/library.cpp b/src/library.cpp index 6c8d643453..d8ec849f49 100644 --- a/src/library.cpp +++ b/src/library.cpp @@ -4127,7 +4127,7 @@ int lammps_group_name(void *handle, int idx, char *buffer, int buf_size) { \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*\ , *molecule*\ , and *region*\ . +*fix*\ , *molecule*\ , *region*\ , and *variable*\ . \endverbatim * * \param handle pointer to a previously created LAMMPS instance cast to ``void *``. @@ -4168,6 +4168,12 @@ int lammps_has_id(void *handle, const char *category, const char *name) { 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; } @@ -4199,6 +4205,8 @@ int lammps_id_count(void *handle, const char *category) { 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; } @@ -4250,6 +4258,11 @@ int lammps_id_name(void *handle, const char *category, int idx, 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; diff --git a/src/variable.h b/src/variable.h index 58548bc276..2519bc7ac9 100644 --- a/src/variable.h +++ b/src/variable.h @@ -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 From 2eb07f74271fca945e47ea0765fc273d577ca960 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sun, 4 Oct 2020 06:02:14 -0400 Subject: [PATCH 19/37] add expansions of IDs and references to IDs --- tools/lammps-shell/lammps-shell.cpp | 113 +++++++++++++++++++++++++++- 1 file changed, 111 insertions(+), 2 deletions(-) diff --git a/tools/lammps-shell/lammps-shell.cpp b/tools/lammps-shell/lammps-shell.cpp index 1ae548e4f5..3dd80482d2 100644 --- a/tools/lammps-shell/lammps-shell.cpp +++ b/tools/lammps-shell/lammps-shell.cpp @@ -52,6 +52,9 @@ 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 commands; // this list of commands is generated by: @@ -152,6 +155,46 @@ template char *style_generator(const char *text, int state) return nullptr; } +template 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 char *ref_generator(const char *text, int state) +{ + char prefix[] = "X_"; + prefix[0] = PREFIX; + + if (strncmp(text, prefix, 2) == 0) { + char *id = id_generator(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" { static char *cmd_generator(const char *text, int state) { @@ -168,6 +211,57 @@ static char *cmd_generator(const char *text, int state) return nullptr; } +static char *compute_id_generator(const char *text, int state) +{ + return id_generator(text, state); +} + +static char *compute_ref_generator(const char *text, int state) +{ + return ref_generator(text, state); +} + +static char *dump_id_generator(const char *text, int state) +{ + return id_generator(text, state); +} + +static char *fix_id_generator(const char *text, int state) +{ + return id_generator(text, state); +} + +static char *fix_ref_generator(const char *text, int state) +{ + return ref_generator(text, state); +} + +static char *variable_ref_generator(const char *text, int state) +{ + return ref_generator(text, state); +} + +static char *variable_expand_generator(const char *text, int state) +{ + if (strncmp(text, "${", 2) == 0) { + char *id = id_generator(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(text, state); @@ -262,10 +356,18 @@ static char **cmd_completion(const char *text, int start, int) matches = rl_completion_matches(text, cmd_generator); } else { // try to provide context specific matches - // first split the already completed text + // 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 (words.size() == 1) { // expand second word + 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") { @@ -284,6 +386,12 @@ static char **cmd_completion(const char *text, int start, int) 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 @@ -431,6 +539,7 @@ int main(int argc, char **argv) char *line; std::string trimmed; + std::cout << "LAMMPS Shell version 1.0\n"; lmp = lammps_open_no_mpi(argc, argv, nullptr); if (lmp == nullptr) return 1; From 9353004e3e7e34346db9c21d15b0d1478fce6c0b Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sun, 4 Oct 2020 11:23:49 -0400 Subject: [PATCH 20/37] add APIs to determine of LAMMPS is running and to interrupt a run cleanly --- src/library.cpp | 28 ++++++++++++++++++++++++++++ src/library.h | 3 +++ 2 files changed, 31 insertions(+) diff --git a/src/library.cpp b/src/library.cpp index d8ec849f49..ebbebff2c1 100644 --- a/src/library.cpp +++ b/src/library.cpp @@ -38,6 +38,7 @@ #include "region.h" #include "output.h" #include "thermo.h" +#include "timer.h" #include "universe.h" #include "update.h" #include "variable.h" @@ -4619,6 +4620,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 // ---------------------------------------------------------------------- diff --git a/src/library.h b/src/library.h index 2ac0997487..c365bd9210 100644 --- a/src/library.h +++ b/src/library.h @@ -226,6 +226,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); From f1ed6a9782ee24857e10c0a36cbd0ddc607f4cad Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sun, 4 Oct 2020 11:25:05 -0400 Subject: [PATCH 21/37] change word break characters to make direct variable expansion completion work --- tools/lammps-shell/lammps-shell.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/lammps-shell/lammps-shell.cpp b/tools/lammps-shell/lammps-shell.cpp index 3dd80482d2..d79e580ca2 100644 --- a/tools/lammps-shell/lammps-shell.cpp +++ b/tools/lammps-shell/lammps-shell.cpp @@ -439,7 +439,8 @@ static void init_commands() commands.push_back("clear_history"); // set name so there can be specific entries in ~/.inputrc - rl_readline_name = "lammps-shell"; + 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. From ecb5078ba75f0937ebf0f3014b8424f6e46db8d4 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sun, 4 Oct 2020 11:25:37 -0400 Subject: [PATCH 22/37] add signal handler to smoothly interrupt ongoing runs. non-windows only. --- tools/lammps-shell/lammps-shell.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tools/lammps-shell/lammps-shell.cpp b/tools/lammps-shell/lammps-shell.cpp index d79e580ca2..eba89b0a84 100644 --- a/tools/lammps-shell/lammps-shell.cpp +++ b/tools/lammps-shell/lammps-shell.cpp @@ -25,6 +25,11 @@ #define isatty(x) _isatty(x) #endif +#if !defined(_WIN32) +#include +#else +#endif + #include #include @@ -196,6 +201,16 @@ template char *ref_generator(const char *text, int state) } extern "C" { + +#if !defined(_WIN32) +static void ctrl_c_handler(int) +{ + if (lmp) + if (lammps_is_running(lmp)) lammps_force_timeout(lmp); +} +#else +#endif + static char *cmd_generator(const char *text, int state) { static std::size_t idx, len; @@ -452,6 +467,11 @@ static void init_commands() // read old history read_history(".lammps_history"); + +#if !defined(_WIN32) + signal(SIGINT, ctrl_c_handler); +#else +#endif } static int help_cmd() From cc14bae2400e778aa46785495588b0bb42d2592e Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sun, 4 Oct 2020 12:22:37 -0400 Subject: [PATCH 23/37] add LAMMPS shell to README --- tools/README | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/README b/tools/README index bed062f918..e98e552b61 100644 --- a/tools/README +++ b/tools/README @@ -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 From e71806196f334dd1f60c2d6ef738abdf51271e5c Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sun, 4 Oct 2020 12:26:26 -0400 Subject: [PATCH 24/37] ignore LAMMPS shell history files --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 5c90b0f39c..0f1b01775d 100644 --- a/.gitignore +++ b/.gitignore @@ -37,6 +37,7 @@ vgcore.* ehthumbs.db Thumbs.db .clang-format +.lammps_history #cmake /build* From e360219a8a2b6b2823f863fdad7541c9555a9a86 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sun, 4 Oct 2020 12:28:01 -0400 Subject: [PATCH 25/37] add readme and makefile for LAMMPS shell --- tools/lammps-shell/.gitignore | 1 + tools/lammps-shell/Makefile | 14 +++++ tools/lammps-shell/README | 108 ++++++++++++++++++++++++++++++++++ 3 files changed, 123 insertions(+) create mode 100644 tools/lammps-shell/.gitignore create mode 100644 tools/lammps-shell/Makefile create mode 100644 tools/lammps-shell/README diff --git a/tools/lammps-shell/.gitignore b/tools/lammps-shell/.gitignore new file mode 100644 index 0000000000..f6c4ad00fa --- /dev/null +++ b/tools/lammps-shell/.gitignore @@ -0,0 +1 @@ +/lammps-shell diff --git a/tools/lammps-shell/Makefile b/tools/lammps-shell/Makefile new file mode 100644 index 0000000000..434fc471aa --- /dev/null +++ b/tools/lammps-shell/Makefile @@ -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 diff --git a/tools/lammps-shell/README b/tools/lammps-shell/README new file mode 100644 index 0000000000..568d5a1d9e --- /dev/null +++ b/tools/lammps-shell/README @@ -0,0 +1,108 @@ +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 categrory (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 + +For all other + +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 customised +with an .inputrc file in the home directory. For application specific +customizations, 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 +- | execute 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 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. From ffcd905bf1f59984008fdea0c776ed2ce8bf1a58 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sun, 4 Oct 2020 14:03:34 -0400 Subject: [PATCH 26/37] complete LAMMPS shell docs interation. Warn if exceptions are missing but don't fail --- cmake/CMakeLists.txt | 9 +- doc/src/Build_basics.rst | 6 +- doc/src/Howto_cmake.rst | 2 + doc/src/Tools.rst | 123 +++++++++++++++++++++++++++- tools/lammps-shell/README | 11 ++- tools/lammps-shell/lammps-shell.cpp | 6 ++ 6 files changed, 144 insertions(+), 13 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index daa2a7d90a..f6b1f204b4 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -643,20 +643,19 @@ if(BUILD_TOOLS) install(FILES ${LAMMPS_DOC_DIR}/msi2lmp.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1) endif() -if(BUILD_SHELL) +if(BUILD_LAMMPS_SHELL) include(FindPkgConfig) pkg_check_modules(READLINE IMPORTED_TARGET readline) if(PKG_CONFIG_FOUND AND READLINE_FOUND) if(NOT LAMMPS_EXCEPTIONS) - message(FATAL_ERROR "The LAMMPS shell requires LAMMPS_EXCEPTIONS enabled") + 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) - target_link_libraries(lammps-shell PRIVATE PkgConfig::READLINE) + target_link_libraries(lammps-shell PRIVATE lammps;PkgConfig::READLINE) install(TARGETS lammps-shell DESTINATION ${CMAKE_INSTALL_BINDIR}) else() - message(WARNING "PkgConfig info for readline library not found, skipping build of 'lammps-shell'") + message(FATAL_ERROR "pkg-config and readline library not found. Cannot build LAMMPS shell") endif() endif() diff --git a/doc/src/Build_basics.rst b/doc/src/Build_basics.rst index 87863e3042..74b6023c3e 100644 --- a/doc/src/Build_basics.rst +++ b/doc/src/Build_basics.rst @@ -541,7 +541,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). @@ -557,6 +558,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: diff --git a/doc/src/Howto_cmake.rst b/doc/src/Howto_cmake.rst index 9176600820..30d71edd87 100644 --- a/doc/src/Howto_cmake.rst +++ b/doc/src/Howto_cmake.rst @@ -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`` diff --git a/doc/src/Tools.rst b/doc/src/Tools.rst index e3e6b344c0..96c49623d8 100644 --- a/doc/src/Tools.rst +++ b/doc/src/Tools.rst @@ -92,6 +92,7 @@ Miscellaneous tools * :ref:`emacs ` * :ref:`i-pi ` * :ref:`kate ` + * :ref:`LAMMPS shell ` * :ref:`singularity ` * :ref:`vim ` @@ -397,10 +398,130 @@ 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 categrory (e.g. pair styles after a + :doc:`pair_style ` command). + +- For :doc:`compute `, :doc:`fix `, or :doc:`dump ` + it will also expand only to already defined groups for the group-ID + keyword. + +- For commands like :doc:`compute_modify `, + :doc:`fix_modify `, or :doc:`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 customised +with an .inputrc file in the home directory. For application specific +customizations, 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: + +.. 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 + \| execute 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 diff --git a/tools/lammps-shell/README b/tools/lammps-shell/README index 568d5a1d9e..8a0ec73734 100644 --- a/tools/lammps-shell/README +++ b/tools/lammps-shell/README @@ -48,9 +48,7 @@ available in that executable. 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 - -For all other +- In all other cases, expansion will be performed on filenames. Command line editing and history ================================ @@ -95,8 +93,8 @@ regular LAMMPS commands: Compilation =========== -Compilation of the LAMMPS shell can be enabled by setting the -CMake variable LAMMPS_SHELL to on or using the makefile in the +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 @@ -105,4 +103,5 @@ compiling LAMMPS. Limitations =========== -The LAMMPS shell was not designed for use with MPI parallelization. +The LAMMPS shell was not designed for use with MPI parallelization +via "mpirun" or "mpiexec" or "srun". diff --git a/tools/lammps-shell/lammps-shell.cpp b/tools/lammps-shell/lammps-shell.cpp index eba89b0a84..cfae8ad50b 100644 --- a/tools/lammps-shell/lammps-shell.cpp +++ b/tools/lammps-shell/lammps-shell.cpp @@ -3,6 +3,8 @@ // Copyright (c) 2020 Axel Kohlmeyer +// This software is distributed under the GNU General Public License. + #include "library.h" #include "utils.h" @@ -561,6 +563,10 @@ int main(int argc, char **argv) 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: Some features will not work as expected\n"; + lmp = lammps_open_no_mpi(argc, argv, nullptr); if (lmp == nullptr) return 1; From d1e76068e86ebdb65ae8405246da1d96c57907c3 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sun, 4 Oct 2020 14:10:18 -0400 Subject: [PATCH 27/37] add new APIs to library docs --- doc/src/Library_utility.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/doc/src/Library_utility.rst b/doc/src/Library_utility.rst index 3d2fae53d3..5fbb3efd89 100644 --- a/doc/src/Library_utility.rst +++ b/doc/src/Library_utility.rst @@ -9,6 +9,8 @@ some utility functions that are not directly calling LAMMPS: - :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 @@ some utility functions that are not directly calling LAMMPS: ----------------------- +.. doxygenfunction:: lammps_is_running + :project: progguide + +----------------------- + +.. doxygenfunction:: lammps_force_timeout + :project: progguide + +----------------------- + .. doxygenfunction:: lammps_has_error :project: progguide From f3b33ea0c63da9f2aba27c276353a994a65b138c Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sun, 4 Oct 2020 14:10:35 -0400 Subject: [PATCH 28/37] address spelling issues --- doc/src/Tools.rst | 13 +++++++------ tools/lammps-shell/README | 8 ++++---- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/doc/src/Tools.rst b/doc/src/Tools.rst index 96c49623d8..483c77038e 100644 --- a/doc/src/Tools.rst +++ b/doc/src/Tools.rst @@ -439,7 +439,7 @@ 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 categrory (e.g. pair styles after a + corresponding category (e.g. pair styles after a :doc:`pair_style ` command). - For :doc:`compute `, :doc:`fix `, or :doc:`dump ` @@ -479,17 +479,18 @@ On exit the LAMMPS shell will write the history list to a file 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 customised -with an .inputrc file in the home directory. For application specific -customizations, the LAMMPS shell uses the name "lammps-shell". +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 followind commands are added to the LAMMPS shell on top of the +The following commands are added to the LAMMPS shell on top of the regular LAMMPS commands: .. parsed-literal:: diff --git a/tools/lammps-shell/README b/tools/lammps-shell/README index 8a0ec73734..efa19236ce 100644 --- a/tools/lammps-shell/README +++ b/tools/lammps-shell/README @@ -35,7 +35,7 @@ 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 categrory (e.g. pair styles after a pair_style command). + 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. @@ -71,9 +71,9 @@ On exit the LAMMPS shell will write the history list to a file 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 customised -with an .inputrc file in the home directory. For application specific -customizations, the LAMMPS shell uses the name "lammps-shell". +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 From d500ffa7841d3e7186a21d5dd45072d4d2138e9c Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sun, 4 Oct 2020 16:42:29 -0400 Subject: [PATCH 29/37] implement handler for CTRL-C on windows. --- tools/lammps-shell/lammps-shell.cpp | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/tools/lammps-shell/lammps-shell.cpp b/tools/lammps-shell/lammps-shell.cpp index cfae8ad50b..6dd03cd5bf 100644 --- a/tools/lammps-shell/lammps-shell.cpp +++ b/tools/lammps-shell/lammps-shell.cpp @@ -29,7 +29,6 @@ #if !defined(_WIN32) #include -#else #endif #include @@ -206,12 +205,21 @@ extern "C" { #if !defined(_WIN32) static void ctrl_c_handler(int) -{ - if (lmp) - if (lammps_is_running(lmp)) lammps_force_timeout(lmp); -} #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) { @@ -473,6 +481,7 @@ static void init_commands() #if !defined(_WIN32) signal(SIGINT, ctrl_c_handler); #else + SetConsoleCtrlHandler(ctrl_c_handler, TRUE); #endif } @@ -493,6 +502,7 @@ static int shell_end() { write_history(".lammps_history"); if (lmp) lammps_close(lmp); + lammps_mpi_finalize(); lmp = nullptr; return 0; } From e08d9055043a69e7074f7a6e1a28b0a21c954cda Mon Sep 17 00:00:00 2001 From: mrcdr Date: Mon, 5 Oct 2020 22:32:15 +0900 Subject: [PATCH 30/37] make a small change to math_eigen_impl.h --- src/math_eigen_impl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/math_eigen_impl.h b/src/math_eigen_impl.h index 80502b1701..7d6f0385ae 100644 --- a/src/math_eigen_impl.h +++ b/src/math_eigen_impl.h @@ -935,7 +935,7 @@ run(real_t& eigvalue, std::vector& eigvec) const //assert(matrix_size > 0); //assert(0 < this->tridiag_eps_ratio && this->tridiag_eps_ratio < 1); - std::vector> u; // Lanczos vectors + std::vector> u; // Lanczos vectors std::vector> alpha; // Diagonal elements of an approximated tridiagonal matrix std::vector> beta; // Subdiagonal elements of an approximated tridiagonal matrix From b6d333535ce4bf30a78ec390d28bf0c4fdf579e7 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Mon, 5 Oct 2020 11:43:43 -0400 Subject: [PATCH 31/37] correct variable name --- cmake/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index f6b1f204b4..dec20095ca 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -90,7 +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_SHELL "Build and install the LAMMPS shell" OFF) +option(BUILD_LAMMPS_SHELL "Build and install the LAMMPS shell" OFF) include(GNUInstallDirs) file(GLOB ALL_SOURCES ${LAMMPS_SOURCE_DIR}/[^.]*.cpp) From bd206dca101bff400899efb46170f5d98becf94d Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Mon, 5 Oct 2020 11:44:19 -0400 Subject: [PATCH 32/37] simplify based on suggestions from @junghans --- cmake/CMakeLists.txt | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index dec20095ca..6a0b6b7cc9 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -644,19 +644,15 @@ if(BUILD_TOOLS) endif() if(BUILD_LAMMPS_SHELL) - include(FindPkgConfig) - pkg_check_modules(READLINE IMPORTED_TARGET readline) - if(PKG_CONFIG_FOUND AND READLINE_FOUND) - 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 DESTINATION ${CMAKE_INSTALL_BINDIR}) - else() - message(FATAL_ERROR "pkg-config and readline library not found. Cannot 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) From 68cca6d31a56976fa4745dc92d54126791b0d4e0 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Mon, 5 Oct 2020 12:51:42 -0400 Subject: [PATCH 33/37] make warning about lack of exception handling more specific --- tools/lammps-shell/lammps-shell.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/lammps-shell/lammps-shell.cpp b/tools/lammps-shell/lammps-shell.cpp index 6dd03cd5bf..7fa1e0f931 100644 --- a/tools/lammps-shell/lammps-shell.cpp +++ b/tools/lammps-shell/lammps-shell.cpp @@ -575,7 +575,7 @@ int main(int argc, char **argv) std::cout << "LAMMPS Shell version 1.0\n"; if (!lammps_config_has_exceptions()) std::cout << "WARNING: LAMMPS was compiled without exceptions\n" - "WARNING: Some features will not work as expected\n"; + "WARNING: The shell will terminate on errors.\n"; lmp = lammps_open_no_mpi(argc, argv, nullptr); if (lmp == nullptr) return 1; From 113db3ac7321176bc8e02f6d4ae915b6c008d1a2 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Mon, 5 Oct 2020 13:39:34 -0400 Subject: [PATCH 34/37] fold group specific query functions into the more generic ID query functions --- doc/src/Library_config.rst | 18 ------ src/library.cpp | 89 +++++------------------------ src/library.h | 4 -- tools/lammps-shell/lammps-shell.cpp | 4 +- 4 files changed, 16 insertions(+), 99 deletions(-) diff --git a/doc/src/Library_config.rst b/doc/src/Library_config.rst index 532bd5cfa0..0c1e254537 100644 --- a/doc/src/Library_config.rst +++ b/doc/src/Library_config.rst @@ -15,9 +15,6 @@ 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_group` -- :cpp:func:`lammps_group_count` -- :cpp:func:`lammps_group_name` - :cpp:func:`lammps_has_id` - :cpp:func:`lammps_id_count` - :cpp:func:`lammps_id_name` @@ -132,21 +129,6 @@ a safer approach. ----------------------- -.. doxygenfunction:: lammps_has_group - :project: progguide - ------------------------ - -.. doxygenfunction:: lammps_group_count - :project: progguide - ------------------------ - -.. doxygenfunction:: lammps_group_name - :project: progguide - ------------------------ - .. doxygenfunction:: lammps_has_id :project: progguide diff --git a/src/library.cpp b/src/library.cpp index ebbebff2c1..3192cf4eef 100644 --- a/src/library.cpp +++ b/src/library.cpp @@ -4049,86 +4049,12 @@ int lammps_style_name(void *handle, const char *category, int idx, /* ---------------------------------------------------------------------- */ -/** Check if a group with a given name has been defined - * -\verbatim embed:rst -This function checks if a group with the provided *name* is defined -in the current LAMMPS instance. -\endverbatim - * - * \param handle pointer to a previously created LAMMPS instance cast to ``void *``. - * \param name name of the style - * \return 1 if defined, 0 if not. - */ -int lammps_has_group(void *handle, const char *name) -{ - LAMMPS *lmp = (LAMMPS *)handle; - - 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; - - return 0; -} - -/* ---------------------------------------------------------------------- */ - -/** Count the number of currently defined groups - * - * This function counts how many groups are defined in the - * current LAMMPS instance. - * - * \param handle pointer to a previously created LAMMPS instance cast to ``void *``. - * \return number of styles in category - */ -int lammps_group_count(void *handle) -{ - LAMMPS *lmp = (LAMMPS *)handle; - - return lmp->group->ngroup; -} - -/* ---------------------------------------------------------------------- */ - -/** Look up the name of a group by index in the list of groups. - * - * This function copies the name of the group 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 group 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 is returned. - * - * \param handle pointer to a previously created LAMMPS instance cast to ``void *``. - * \param idx index of the group in the list of groups (0 <= idx < group 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_group_name(void *handle, int idx, char *buffer, int buf_size) { - LAMMPS *lmp = (LAMMPS *)handle; - - int ngroup = lmp->group->ngroup; - char **groups = lmp->group->names; - if ((idx >=0) && (idx < ngroup)) { - strncpy(buffer, groups[idx], buf_size); - return 1; - } - - buffer[0] = '\0'; - return 0; -} - -/* ---------------------------------------------------------------------- */ - /** 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*\ , *molecule*\ , *region*\ , and *variable*\ . +*fix*\ , *group*\ , *molecule*\ , *region*\ , and *variable*\ . \endverbatim * * \param handle pointer to a previously created LAMMPS instance cast to ``void *``. @@ -4157,6 +4083,12 @@ int lammps_has_id(void *handle, const char *category, const char *name) { 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; @@ -4202,6 +4134,8 @@ int lammps_id_count(void *handle, const char *category) { 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) { @@ -4249,6 +4183,11 @@ int lammps_id_name(void *handle, const char *category, int idx, 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); diff --git a/src/library.h b/src/library.h index c365bd9210..8089e51ade 100644 --- a/src/library.h +++ b/src/library.h @@ -183,10 +183,6 @@ 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_group(void *, const char *); -int lammps_group_count(void *); -int lammps_group_name(void *, 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); diff --git a/tools/lammps-shell/lammps-shell.cpp b/tools/lammps-shell/lammps-shell.cpp index 7fa1e0f931..c1f8182535 100644 --- a/tools/lammps-shell/lammps-shell.cpp +++ b/tools/lammps-shell/lammps-shell.cpp @@ -357,12 +357,12 @@ char *group_generator(const char *text, int state) static int idx, num, len; if (!state) { idx = 0; - num = lammps_group_count(lmp); + num = lammps_id_count(lmp, "group"); len = strlen(text); } while (idx < num) { - lammps_group_name(lmp, idx, buf, buflen); + lammps_id_name(lmp, "group", idx, buf, buflen); ++idx; if ((len == 0) || (strncmp(text, buf, len) == 0)) return dupstring(buf); } From 6933233c565690f300948c798488007c61398283 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Mon, 5 Oct 2020 13:41:25 -0400 Subject: [PATCH 35/37] add tests for the new library APIs --- unittest/c-library/test_library_config.cpp | 77 +++++++++++++++++++++- 1 file changed, 76 insertions(+), 1 deletion(-) diff --git a/unittest/c-library/test_library_config.cpp b/unittest/c-library/test_library_config.cpp index 0e81683159..55ca1f84ac 100644 --- a/unittest/c-library/test_library_config.cpp +++ b/unittest/c-library/test_library_config.cpp @@ -2,6 +2,7 @@ #include "lammps.h" #include "library.h" +#include "timer.h" #include #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); From 18023ad9dc0dfa68b82fe0790f4d7785122e1ac3 Mon Sep 17 00:00:00 2001 From: Richard Berger Date: Tue, 6 Oct 2020 10:39:14 -0400 Subject: [PATCH 36/37] Update fix_wall_gran_region.cpp Don't store atom tag, just if there is a contact. Fixes #2306 --- src/GRANULAR/fix_wall_gran_region.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/GRANULAR/fix_wall_gran_region.cpp b/src/GRANULAR/fix_wall_gran_region.cpp index f91bac2c9b..d795d1bc37 100644 --- a/src/GRANULAR/fix_wall_gran_region.cpp +++ b/src/GRANULAR/fix_wall_gran_region.cpp @@ -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; From 7dd244a828ebd6d0e2e78c7b15613253a57a20a4 Mon Sep 17 00:00:00 2001 From: Richard Berger Date: Tue, 6 Oct 2020 10:45:23 -0400 Subject: [PATCH 37/37] Correct fix wall/gran and wall/gran/region docs --- doc/src/fix_wall_gran.rst | 6 +++--- doc/src/fix_wall_gran_region.rst | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/src/fix_wall_gran.rst b/doc/src/fix_wall_gran.rst index 4ebbf35ba1..bc59fd71a7 100644 --- a/doc/src/fix_wall_gran.rst +++ b/doc/src/fix_wall_gran.rst @@ -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 | +-------+----------------------------------------------------+----------------+ diff --git a/doc/src/fix_wall_gran_region.rst b/doc/src/fix_wall_gran_region.rst index 7d62d71a1d..bedf1165c1 100644 --- a/doc/src/fix_wall_gran_region.rst +++ b/doc/src/fix_wall_gran_region.rst @@ -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 | +-------+----------------------------------------------------+----------------+