diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 058b61dd3d..ada38138f6 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -256,6 +256,7 @@ set(STANDARD_PACKAGES DRUDE EFF ELECTRODE + EXTRA-COMMAND EXTRA-COMPUTE EXTRA-DUMP EXTRA-FIX diff --git a/cmake/presets/all_off.cmake b/cmake/presets/all_off.cmake index c82eb568bf..59ac760f6a 100644 --- a/cmake/presets/all_off.cmake +++ b/cmake/presets/all_off.cmake @@ -28,6 +28,7 @@ set(ALL_PACKAGES DRUDE ELECTRODE EFF + EXTRA-COMMAND EXTRA-COMPUTE EXTRA-DUMP EXTRA-FIX diff --git a/cmake/presets/all_on.cmake b/cmake/presets/all_on.cmake index d909b6aca7..a75ab0d9b2 100644 --- a/cmake/presets/all_on.cmake +++ b/cmake/presets/all_on.cmake @@ -30,6 +30,7 @@ set(ALL_PACKAGES DRUDE ELECTRODE EFF + EXTRA-COMMAND EXTRA-COMPUTE EXTRA-DUMP EXTRA-FIX diff --git a/cmake/presets/mingw-cross.cmake b/cmake/presets/mingw-cross.cmake index 8fdce0512f..8ca9b97e35 100644 --- a/cmake/presets/mingw-cross.cmake +++ b/cmake/presets/mingw-cross.cmake @@ -24,6 +24,7 @@ set(WIN_PACKAGES DRUDE ELECTRODE EFF + EXTRA-COMMAND EXTRA-COMPUTE EXTRA-DUMP EXTRA-FIX diff --git a/cmake/presets/most.cmake b/cmake/presets/most.cmake index 2ed7cbcaac..d01642f94d 100644 --- a/cmake/presets/most.cmake +++ b/cmake/presets/most.cmake @@ -26,6 +26,7 @@ set(ALL_PACKAGES DRUDE EFF ELECTRODE + EXTRA-COMMAND EXTRA-COMPUTE EXTRA-DUMP EXTRA-FIX diff --git a/cmake/presets/windows.cmake b/cmake/presets/windows.cmake index d47e1077e8..5e400e9de9 100644 --- a/cmake/presets/windows.cmake +++ b/cmake/presets/windows.cmake @@ -22,6 +22,7 @@ set(WIN_PACKAGES DRUDE EFF ELECTRODE + EXTRA-COMMAND EXTRA-COMPUTE EXTRA-DUMP EXTRA-FIX diff --git a/doc/src/Packages_details.rst b/doc/src/Packages_details.rst index 012da83a77..f4d641d8e3 100644 --- a/doc/src/Packages_details.rst +++ b/doc/src/Packages_details.rst @@ -52,6 +52,7 @@ page gives those details. * :ref:`DRUDE ` * :ref:`EFF ` * :ref:`ELECTRODE ` + * :ref:`EXTRA-COMMAND ` * :ref:`EXTRA-COMPUTE ` * :ref:`EXTRA-DUMP ` * :ref:`EXTRA-FIX ` @@ -893,6 +894,22 @@ This package has :ref:`specific installation instructions ` on the ---------- +.. _PKG-EXTRA-COMMAND: + +EXTRA-COMMAND package +--------------------- + +**Contents:** + +Additional command styles that are less commonly used. + +**Supporting info:** + +* src/EXTRA-COMMAND: filenames -> commands +* :doc:`general commands ` + +---------- + .. _PKG-EXTRA-COMPUTE: EXTRA-COMPUTE package diff --git a/doc/src/Packages_list.rst b/doc/src/Packages_list.rst index 2fd4086452..d1422c5f09 100644 --- a/doc/src/Packages_list.rst +++ b/doc/src/Packages_list.rst @@ -158,6 +158,11 @@ whether an extra library is needed to build and use the package: - :doc:`fix electrode/conp ` - PACKAGES/electrode - no + * - :ref:`EXTRA-COMMAND ` + - additional command styles + - :doc:`general commands ` + - n/a + - no * - :ref:`EXTRA-COMPUTE ` - additional compute styles - :doc:`compute ` diff --git a/doc/src/group2ndx.rst b/doc/src/group2ndx.rst index 077f88e3e8..19c472e109 100644 --- a/doc/src/group2ndx.rst +++ b/doc/src/group2ndx.rst @@ -34,32 +34,66 @@ Description Write or read a Gromacs style index file in text format that associates atom IDs with the corresponding group definitions. This index file can be used with in combination with Gromacs analysis tools or to import group -definitions into the :doc:`fix colvars ` input file. It can -also be used to save and restore group definitions for static groups. +definitions into the :doc:`fix colvars ` input file. + +It can also be used to save and restore group definitions for static groups +using the individual atom IDs. This may be important if the original +group definition depends on a region or otherwise on the geometry and thus +cannot be easily recreated. + +Another application would be to import atom groups defined for Gromacs +simulation into LAMMPS. When translating Gromacs topology and geometry +data to LAMMPS. The *group2ndx* command will write group definitions to an index file. -Without specifying any group IDs, all groups will be written to the index -file. When specifying group IDs, only those groups will be written to the -index file. In order to follow the Gromacs conventions, the group *all* -will be renamed to *System* in the index file. +Without specifying any group IDs, all groups will be written to the +index file. When specifying group IDs, only those groups will be +written to the index file. In order to follow the Gromacs conventions, +the group *all* will be renamed to *System* in the index file. -The *ndx2group* command will create of update group definitions from those -stored in an index file. Without specifying any group IDs, all groups except -*System* will be read from the index file and the corresponding groups -recreated. If a group of the same name already exists, it will be completely -reset. When specifying group IDs, those groups, if present, will be read -from the index file and restored. +The *ndx2group* command will create of update group definitions from +those stored in an index file. Without specifying any group IDs, all +groups except *System* will be read from the index file and the +corresponding groups recreated. If a group of the same name already +exists, it will be completely reset. When specifying group IDs, those +groups, if present, will be read from the index file and restored. + +File Format +""""""""""" + +The file format is equivalent and compatible with what is produced by +the `Gromacs make_ndx command `_. +and follows the `Gromacs definition of an ndx file `_ + +Each group definition begins with the group name in square brackets with +blanks, e.g. \[ water \] and is then followed by the list of atom +indices, which may be spread over multiple lines. Here is a small +example file: + +.. code-block:: ini + + [ Oxygen ] + 1 4 7 + [ Hydrogen ] + 2 3 5 6 + 8 9 + [ Water ] + 1 2 3 4 5 6 7 8 9 + +The index file defines 3 groups: Oxygen, Hydrogen, and Water and the +latter happens to be the union of the first two. ---------- Restrictions """""""""""" -This command requires that atoms have atom IDs, since this is the +These commands require that atoms have atom IDs, since this is the information that is written to the index file. -These commands are part of the COLVARS package. They are only -enabled if LAMMPS was built with that package. See the :doc:`Build package ` page for more info. +These commands are part of the EXTRA-COMMAND package. They are only +enabled if LAMMPS was built with that package. See the +:doc:`Build package ` page for more info. Related commands """""""""""""""" diff --git a/src/COLVARS/ndx_group.cpp b/src/COLVARS/ndx_group.cpp deleted file mode 100644 index 4170a9ea70..0000000000 --- a/src/COLVARS/ndx_group.cpp +++ /dev/null @@ -1,199 +0,0 @@ -// clang-format off -// -*- c++ -*- - -/* ---------------------------------------------------------------------- - LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator - https://www.lammps.org/, Sandia National Laboratories - LAMMPS development team: developers@lammps.org - - Copyright (2003) Sandia Corporation. Under the terms of Contract - DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains - certain rights in this software. This software is distributed under - the GNU General Public License. - - See the README file in the top-level LAMMPS directory. -------------------------------------------------------------------------- */ -/* ---------------------------------------------------------------------- - Contributing author: Axel Kohlmeyer (Temple U) -------------------------------------------------------------------------- */ - -#include "ndx_group.h" - -#include "atom.h" -#include "comm.h" -#include "error.h" -#include "group.h" -#include "tokenizer.h" - -using namespace LAMMPS_NS; -static constexpr int BUFLEN = 4096; - -// read file until next section "name" or any next section if name == "" - -static std::string find_section(FILE *fp, const std::string &name) -{ - char linebuf[BUFLEN]; - - std::string pattern = "^\\s*\\[\\s+\\S+\\s+\\]\\s*$"; - if (!name.empty()) - pattern = fmt::format("^\\s*\\[\\s+{}\\s+\\]\\s*$",name); - - fgets(linebuf,BUFLEN,fp); - while (!feof(fp)) { - if (utils::strmatch(linebuf,pattern)) - return Tokenizer(linebuf).as_vector()[1]; - fgets(linebuf,BUFLEN,fp); - } - return ""; -} - -static std::vector read_section(FILE *fp, std::string &name) -{ - char linebuf[BUFLEN]; - std::vector tagbuf; - std::string pattern = "^\\s*\\[\\s+\\S+\\s+\\]\\s*$"; - - while (fgets(linebuf,BUFLEN,fp)) { - // start of new section. we are done, update "name" - if (utils::strmatch(linebuf,pattern)) { - name = Tokenizer(linebuf).as_vector()[1]; - return tagbuf; - } - ValueTokenizer values(linebuf); - while (values.has_next()) - tagbuf.push_back(values.next_tagint()); - } - // set empty name to indicate end of file - name = ""; - return tagbuf; -} - -/* ---------------------------------------------------------------------- */ - -void Ndx2Group::command(int narg, char **arg) -{ - int len; - bigint num; - FILE *fp; - std::string name, next; - - if (narg < 1) error->all(FLERR,"Illegal ndx2group command"); - if (atom->tag_enable == 0) - error->all(FLERR,"Must have atom IDs for ndx2group command"); - if (atom->map_style == Atom::MAP_NONE) - error->all(FLERR,"Must have an atom map for ndx2group command"); - if (comm->me == 0) { - fp = fopen(arg[0], "r"); - if (fp == nullptr) - error->one(FLERR,"Cannot open index file for reading: {}", - utils::getsyserror()); - utils::logmesg(lmp,"Reading groups from index file {}:\n",arg[0]); - } - - if (narg == 1) { // restore all groups - - if (comm->me == 0) { - name = find_section(fp,""); - while (!name.empty()) { - - // skip over group "all", which is called "System" in gromacs - if (name == "System") { - name = find_section(fp,""); - continue; - } - - utils::logmesg(lmp," Processing group '{}'\n",name); - len = name.size()+1; - MPI_Bcast(&len,1,MPI_INT,0,world); - if (len > 1) { - MPI_Bcast((void *)name.c_str(),len,MPI_CHAR,0,world); - - // read tags for atoms in group and broadcast - std::vector tags = read_section(fp,next); - num = tags.size(); - MPI_Bcast(&num,1,MPI_LMP_BIGINT,0,world); - MPI_Bcast((void *)tags.data(),num,MPI_LMP_TAGINT,0,world); - create(name,tags); - name = next; - } - } - len = -1; - MPI_Bcast(&len,1,MPI_INT,0,world); - - } else { - - while (true) { - MPI_Bcast(&len,1,MPI_INT,0,world); - if (len < 0) break; - if (len > 1) { - char *buf = new char[len]; - MPI_Bcast(buf,len,MPI_CHAR,0,world); - MPI_Bcast(&num,1,MPI_LMP_BIGINT,0,world); - tagint *tbuf = new tagint[num]; - MPI_Bcast(tbuf,num,MPI_LMP_TAGINT,0,world); - create(buf,std::vector(tbuf,tbuf+num)); - delete[] buf; - delete[] tbuf; - } - } - } - - } else { // restore selected groups - - for (int idx=1; idx < narg; ++idx) { - if (comm->me == 0) { - - // find named section, search from beginning of file - rewind(fp); - name = find_section(fp,arg[idx]); - utils::logmesg(lmp," {} group '{}'\n", name.size() - ? "Processing" : "Skipping",arg[idx]); - len = name.size()+1; - MPI_Bcast(&len,1,MPI_INT,0,world); - if (len > 1) { - MPI_Bcast((void *)name.c_str(),len,MPI_CHAR,0,world); - - // read tags for atoms in group and broadcast - std::vector tags = read_section(fp,next); - num = tags.size(); - MPI_Bcast(&num,1,MPI_LMP_BIGINT,0,world); - MPI_Bcast((void *)tags.data(),num,MPI_LMP_TAGINT,0,world); - create(name,tags); - name = next; - } - } else { - MPI_Bcast(&len,1,MPI_INT,0,world); - if (len > 1) { - char *buf = new char[len]; - MPI_Bcast(buf,len,MPI_CHAR,0,world); - MPI_Bcast(&num,1,MPI_LMP_BIGINT,0,world); - tagint *tbuf = new tagint[num]; - MPI_Bcast(tbuf,num,MPI_LMP_TAGINT,0,world); - create(buf,std::vector(tbuf,tbuf+num)); - delete[] buf; - delete[] tbuf; - } - } - } - } - if (comm->me == 0) fclose(fp); -} - -/* ---------------------------------------------------------------------- */ - -void Ndx2Group::create(const std::string &name, const std::vector &tags) -{ - // wipe out all members if the group exists. gid==0 is group "all" - int gid = group->find(name); - if (gid > 0) group->assign(name + " clear"); - - // map from global to local - const int nlocal = atom->nlocal; - int *flags = (int *)calloc(nlocal,sizeof(int)); - for (bigint i=0; i < (int)tags.size(); ++i) { - const int id = atom->map(tags[i]); - if (id < nlocal && id >= 0) flags[id] = 1; - } - group->create(name,flags); - free(flags); -} diff --git a/src/COLVARS/group_ndx.cpp b/src/EXTRA-COMMAND/group_ndx.cpp similarity index 59% rename from src/COLVARS/group_ndx.cpp rename to src/EXTRA-COMMAND/group_ndx.cpp index 05a50a1596..1dc0d3af97 100644 --- a/src/COLVARS/group_ndx.cpp +++ b/src/EXTRA-COMMAND/group_ndx.cpp @@ -1,4 +1,3 @@ -// clang-format off // -*- c++ -*- /* ---------------------------------------------------------------------- @@ -34,12 +33,15 @@ using namespace LAMMPS_NS; static int cmptagint(const void *p1, const void *p2) { - const tagint i1 = * static_cast(p1); - const tagint i2 = * static_cast(p2); - if (i1 == i2) return 0; + const tagint i1 = *static_cast(p1); + const tagint i2 = *static_cast(p2); + if (i1 == i2) + return 0; else { - if (i1 < i2) return -1; - else return 1; + if (i1 < i2) + return -1; + else + return 1; } } @@ -49,27 +51,24 @@ void Group2Ndx::command(int narg, char **arg) { FILE *fp = nullptr; - if (narg < 1) error->all(FLERR,"Illegal group2ndx command"); + if (narg < 1) utils::missing_cmd_args(FLERR, "group2ndx", error); - if (atom->tag_enable == 0) - error->all(FLERR,"Must have atom IDs for group2ndx command"); + if (atom->tag_enable == 0) error->all(FLERR, "Must have atom IDs for group2ndx command"); if (comm->me == 0) { fp = fopen(arg[0], "w"); if (fp == nullptr) - error->one(FLERR,"Cannot open index file for writing: {}", utils::getsyserror()); - utils::logmesg(lmp,"Writing groups to index file {}:\n",arg[0]); + error->one(FLERR, "Cannot open index file for writing: {}", utils::getsyserror()); + utils::logmesg(lmp, "Writing groups to index file {}:\n", arg[0]); } - if (narg == 1) { // write out all groups - for (int i=0; i < group->ngroup; ++i) { - write_group(fp,i); - } - } else { // write only selected groups - for (int i=1; i < narg; ++i) { + if (narg == 1) { // write out all groups + for (int i = 0; i < group->ngroup; ++i) { write_group(fp, i); } + } else { // write only selected groups + for (int i = 1; i < narg; ++i) { int gid = group->find(arg[i]); if (gid < 0) error->all(FLERR, "Non-existing group requested"); - write_group(fp,gid); + write_group(fp, gid); } } @@ -85,22 +84,26 @@ void Group2Ndx::write_group(FILE *fp, int gid) bigint gcount = group->count(gid); int lnum, width, cols; + if (utils::strmatch(group->names[gid], "\\s+")) { + if (fp) utils::logmesg(lmp, " skipping group {}...done", group->names[gid]); + return; + } if (fp) { - utils::logmesg(lmp," writing group {}...",group->names[gid]); + utils::logmesg(lmp, " writing group {}...", group->names[gid]); // the "all" group in LAMMPS is called "System" in Gromacs if (gid == 0) { fputs("[ System ]\n", fp); } else { - fmt::print(fp,"[ {} ]\n", group->names[gid]); + fmt::print(fp, "[ {} ]\n", group->names[gid]); } - width = log10((double) atom->natoms)+2; + width = log10((double) atom->natoms) + 2; cols = 80 / width; } if (gcount > 0) { - const int * const mask = atom->mask; - const tagint * const tag = atom->tag; + const int *const mask = atom->mask; + const tagint *const tag = atom->tag; const int groupbit = group->bitmask[gid]; const int nlocal = atom->nlocal; int i; @@ -111,45 +114,45 @@ void Group2Ndx::write_group(FILE *fp, int gid) for (i = 0; i < nlocal; i++) if (mask[i] & groupbit) sendlist[lnum++] = tag[i]; - int nrecv=0; + int nrecv = 0; bigint allrecv; if (comm->me == 0) { MPI_Status status; MPI_Request request; - for (i=0; i < lnum; i++) - recvlist[i] = sendlist[i]; + for (i = 0; i < lnum; i++) recvlist[i] = sendlist[i]; allrecv = lnum; - for (i=1; i < comm->nprocs; ++i) { - MPI_Irecv(recvlist+allrecv,gcount-allrecv,MPI_LMP_TAGINT,i,0, world,&request); - MPI_Send(&nrecv,0,MPI_INT,i,0,world); // block rank "i" until we are ready to receive - MPI_Wait(&request,&status); - MPI_Get_count(&status,MPI_LMP_TAGINT,&nrecv); + for (i = 1; i < comm->nprocs; ++i) { + MPI_Irecv(recvlist + allrecv, gcount - allrecv, MPI_LMP_TAGINT, i, 0, world, &request); + // block rank "i" until we are ready to receive + MPI_Send(&nrecv, 0, MPI_INT, i, 0, world); + MPI_Wait(&request, &status); + MPI_Get_count(&status, MPI_LMP_TAGINT, &nrecv); allrecv += nrecv; } // sort received list - qsort((void *)recvlist, allrecv, sizeof(tagint), cmptagint); + qsort((void *) recvlist, allrecv, sizeof(tagint), cmptagint); } else { - MPI_Recv(&nrecv,0,MPI_INT,0,0,world,MPI_STATUS_IGNORE); - MPI_Rsend(sendlist,lnum,MPI_LMP_TAGINT,0,0,world); + MPI_Recv(&nrecv, 0, MPI_INT, 0, 0, world, MPI_STATUS_IGNORE); + MPI_Rsend(sendlist, lnum, MPI_LMP_TAGINT, 0, 0, world); } - delete [] sendlist; + delete[] sendlist; } if (fp) { int i, j; - for (i=0, j=0; i < gcount; ++i) { - fmt::print(fp,"{:>{}}",recvlist[i],width); + for (i = 0, j = 0; i < gcount; ++i) { + fmt::print(fp, "{:>{}}", recvlist[i], width); ++j; if (j == cols) { - fputs("\n",fp); + fputs("\n", fp); j = 0; } } - if (j > 0) fputs("\n",fp); - utils::logmesg(lmp,"done\n"); + if (j > 0) fputs("\n", fp); + utils::logmesg(lmp, "done\n"); } if (gcount > 0) delete[] recvlist; } diff --git a/src/COLVARS/group_ndx.h b/src/EXTRA-COMMAND/group_ndx.h similarity index 100% rename from src/COLVARS/group_ndx.h rename to src/EXTRA-COMMAND/group_ndx.h diff --git a/src/EXTRA-COMMAND/ndx_group.cpp b/src/EXTRA-COMMAND/ndx_group.cpp new file mode 100644 index 0000000000..c5b0d3cf8a --- /dev/null +++ b/src/EXTRA-COMMAND/ndx_group.cpp @@ -0,0 +1,220 @@ +// -*- c++ -*- + +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + https://www.lammps.org/, Sandia National Laboratories + LAMMPS development team: developers@lammps.org + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ +/* ---------------------------------------------------------------------- + Contributing author: Axel Kohlmeyer (Temple U) +------------------------------------------------------------------------- */ + +#include "ndx_group.h" + +#include "atom.h" +#include "comm.h" +#include "error.h" +#include "group.h" +#include "tokenizer.h" + +using namespace LAMMPS_NS; +static constexpr int BUFLEN = 4096; + +// read file until next section "name" or any next section if name == "" + +static std::string find_section(FILE *fp, const std::string &name) +{ + char linebuf[BUFLEN]; + + fgets(linebuf, BUFLEN, fp); + while (!feof(fp)) { + if (utils::strmatch(linebuf, "^\\s*\\[.*\\]\\s*$")) { + auto words = Tokenizer(linebuf).as_vector(); + if (words.size() != 3) + throw TokenizerException("Invalid group name in index file", + utils::trim(utils::strfind(linebuf, "[^\\[^\\]]+"))); + if (name.empty() || (name == words[1])) return words[1]; + } + fgets(linebuf, BUFLEN, fp); + } + return ""; +} + +static std::vector read_section(FILE *fp, std::string &name) +{ + char linebuf[BUFLEN]; + std::vector tagbuf; + + while (fgets(linebuf, BUFLEN, fp)) { + // start of new section. we are done, update "name" + if (utils::strmatch(linebuf, "^\\s*\\[.*\\]\\s*$")) { + auto words = Tokenizer(linebuf).as_vector(); + if (words.size() != 3) + throw TokenizerException("Invalid group name in index file", + utils::trim(utils::strfind(linebuf, "[^\\[^\\]]+"))); + name = words[1]; + return tagbuf; + } + ValueTokenizer values(linebuf); + while (values.has_next()) tagbuf.push_back(values.next_tagint()); + } + // set empty name to indicate end of file + name = ""; + return tagbuf; +} + +/* ---------------------------------------------------------------------- */ + +void Ndx2Group::command(int narg, char **arg) +{ + int len; + bigint num; + FILE *fp; + std::string name, next; + + if (narg < 1) utils::missing_cmd_args(FLERR, "ndx2group", error); + if (atom->tag_enable == 0) error->all(FLERR, "Must have atom IDs for ndx2group command"); + if (atom->map_style == Atom::MAP_NONE) + error->all(FLERR, "Must have an atom map for ndx2group command"); + if (comm->me == 0) { + fp = fopen(arg[0], "r"); + if (fp == nullptr) + error->one(FLERR, "Cannot open index file for reading: {}", utils::getsyserror()); + utils::logmesg(lmp, "Reading groups from index file {}:\n", arg[0]); + } + + if (narg == 1) { // restore all groups + + if (comm->me == 0) { + try { + name = find_section(fp, ""); + } catch (std::exception &e) { + error->one(FLERR, e.what()); + } + + while (!name.empty()) { + // skip over group "all", which is called "System" in gromacs + if (name == "System") { + try { + name = find_section(fp, ""); + } catch (std::exception &e) { + error->one(FLERR, e.what()); + } + continue; + } + + utils::logmesg(lmp, " Processing group '{}'\n", name); + len = name.size() + 1; + MPI_Bcast(&len, 1, MPI_INT, 0, world); + if (len > 1) { + MPI_Bcast((void *) name.c_str(), len, MPI_CHAR, 0, world); + + // read tags for atoms in group and broadcast + std::vector tags; + try { + tags = read_section(fp, next); + } catch (std::exception &e) { + error->one(FLERR, e.what()); + } + num = tags.size(); + MPI_Bcast(&num, 1, MPI_LMP_BIGINT, 0, world); + MPI_Bcast((void *) tags.data(), num, MPI_LMP_TAGINT, 0, world); + create(name, tags); + name = next; + } + } + len = -1; + MPI_Bcast(&len, 1, MPI_INT, 0, world); + + } else { + + while (true) { + MPI_Bcast(&len, 1, MPI_INT, 0, world); + if (len < 0) break; + if (len > 1) { + char *buf = new char[len]; + MPI_Bcast(buf, len, MPI_CHAR, 0, world); + MPI_Bcast(&num, 1, MPI_LMP_BIGINT, 0, world); + tagint *tbuf = new tagint[num]; + MPI_Bcast(tbuf, num, MPI_LMP_TAGINT, 0, world); + create(buf, std::vector(tbuf, tbuf + num)); + delete[] buf; + delete[] tbuf; + } + } + } + + } else { // restore selected groups + + for (int idx = 1; idx < narg; ++idx) { + if (comm->me == 0) { + + // find named section, search from beginning of file + rewind(fp); + try { + name = find_section(fp, arg[idx]); + } catch (std::exception &e) { + error->one(FLERR, e.what()); + } + utils::logmesg(lmp, " {} group '{}'\n", name.size() ? "Processing" : "Skipping", arg[idx]); + len = name.size() + 1; + MPI_Bcast(&len, 1, MPI_INT, 0, world); + if (len > 1) { + MPI_Bcast((void *) name.c_str(), len, MPI_CHAR, 0, world); + + // read tags for atoms in group and broadcast + std::vector tags; + try { + tags = read_section(fp, next); + } catch (std::exception &e) { + error->one(FLERR, e.what()); + } + num = tags.size(); + MPI_Bcast(&num, 1, MPI_LMP_BIGINT, 0, world); + MPI_Bcast((void *) tags.data(), num, MPI_LMP_TAGINT, 0, world); + create(name, tags); + name = next; + } + } else { + MPI_Bcast(&len, 1, MPI_INT, 0, world); + if (len > 1) { + char *buf = new char[len]; + MPI_Bcast(buf, len, MPI_CHAR, 0, world); + MPI_Bcast(&num, 1, MPI_LMP_BIGINT, 0, world); + tagint *tbuf = new tagint[num]; + MPI_Bcast(tbuf, num, MPI_LMP_TAGINT, 0, world); + create(buf, std::vector(tbuf, tbuf + num)); + delete[] buf; + delete[] tbuf; + } + } + } + } + if (comm->me == 0) fclose(fp); +} + +/* ---------------------------------------------------------------------- */ + +void Ndx2Group::create(const std::string &name, const std::vector &tags) +{ + // wipe out all members if the group exists. gid==0 is group "all" + int gid = group->find(name); + if (gid > 0) group->assign(name + " clear"); + + // map from global to local + const int nlocal = atom->nlocal; + int *flags = (int *) calloc(nlocal, sizeof(int)); + for (bigint i = 0; i < (int) tags.size(); ++i) { + const int id = atom->map(tags[i]); + if (id < nlocal && id >= 0) flags[id] = 1; + } + group->create(name, flags); + free(flags); +} diff --git a/src/COLVARS/ndx_group.h b/src/EXTRA-COMMAND/ndx_group.h similarity index 100% rename from src/COLVARS/ndx_group.h rename to src/EXTRA-COMMAND/ndx_group.h diff --git a/src/Makefile b/src/Makefile index 33d7012cae..805b950112 100644 --- a/src/Makefile +++ b/src/Makefile @@ -74,6 +74,7 @@ PACKAGE = \ dpd-smooth \ drude \ eff \ + extra-command \ extra-compute \ extra-dump \ extra-fix \ @@ -168,6 +169,7 @@ PACKMOST = \ dpd-smooth \ drude \ eff \ + extra-command \ extra-compute \ extra-dump \ extra-fix \