Merge pull request #4193 from akohlmey/extra-command-package

Create new EXTRA-COMMAND package
This commit is contained in:
Axel Kohlmeyer
2024-06-19 15:06:20 -04:00
committed by GitHub
15 changed files with 342 additions and 254 deletions

View File

@ -256,6 +256,7 @@ set(STANDARD_PACKAGES
DRUDE DRUDE
EFF EFF
ELECTRODE ELECTRODE
EXTRA-COMMAND
EXTRA-COMPUTE EXTRA-COMPUTE
EXTRA-DUMP EXTRA-DUMP
EXTRA-FIX EXTRA-FIX

View File

@ -28,6 +28,7 @@ set(ALL_PACKAGES
DRUDE DRUDE
ELECTRODE ELECTRODE
EFF EFF
EXTRA-COMMAND
EXTRA-COMPUTE EXTRA-COMPUTE
EXTRA-DUMP EXTRA-DUMP
EXTRA-FIX EXTRA-FIX

View File

@ -30,6 +30,7 @@ set(ALL_PACKAGES
DRUDE DRUDE
ELECTRODE ELECTRODE
EFF EFF
EXTRA-COMMAND
EXTRA-COMPUTE EXTRA-COMPUTE
EXTRA-DUMP EXTRA-DUMP
EXTRA-FIX EXTRA-FIX

View File

@ -24,6 +24,7 @@ set(WIN_PACKAGES
DRUDE DRUDE
ELECTRODE ELECTRODE
EFF EFF
EXTRA-COMMAND
EXTRA-COMPUTE EXTRA-COMPUTE
EXTRA-DUMP EXTRA-DUMP
EXTRA-FIX EXTRA-FIX

View File

@ -26,6 +26,7 @@ set(ALL_PACKAGES
DRUDE DRUDE
EFF EFF
ELECTRODE ELECTRODE
EXTRA-COMMAND
EXTRA-COMPUTE EXTRA-COMPUTE
EXTRA-DUMP EXTRA-DUMP
EXTRA-FIX EXTRA-FIX

View File

@ -22,6 +22,7 @@ set(WIN_PACKAGES
DRUDE DRUDE
EFF EFF
ELECTRODE ELECTRODE
EXTRA-COMMAND
EXTRA-COMPUTE EXTRA-COMPUTE
EXTRA-DUMP EXTRA-DUMP
EXTRA-FIX EXTRA-FIX

View File

@ -52,6 +52,7 @@ page gives those details.
* :ref:`DRUDE <PKG-DRUDE>` * :ref:`DRUDE <PKG-DRUDE>`
* :ref:`EFF <PKG-EFF>` * :ref:`EFF <PKG-EFF>`
* :ref:`ELECTRODE <PKG-ELECTRODE>` * :ref:`ELECTRODE <PKG-ELECTRODE>`
* :ref:`EXTRA-COMMAND <PKG-EXTRA-COMMAND>`
* :ref:`EXTRA-COMPUTE <PKG-EXTRA-COMPUTE>` * :ref:`EXTRA-COMPUTE <PKG-EXTRA-COMPUTE>`
* :ref:`EXTRA-DUMP <PKG-EXTRA-DUMP>` * :ref:`EXTRA-DUMP <PKG-EXTRA-DUMP>`
* :ref:`EXTRA-FIX <PKG-EXTRA-FIX>` * :ref:`EXTRA-FIX <PKG-EXTRA-FIX>`
@ -893,6 +894,22 @@ This package has :ref:`specific installation instructions <electrode>` 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 <Commands_all>`
----------
.. _PKG-EXTRA-COMPUTE: .. _PKG-EXTRA-COMPUTE:
EXTRA-COMPUTE package EXTRA-COMPUTE package

View File

@ -158,6 +158,11 @@ whether an extra library is needed to build and use the package:
- :doc:`fix electrode/conp <fix_electrode>` - :doc:`fix electrode/conp <fix_electrode>`
- PACKAGES/electrode - PACKAGES/electrode
- no - no
* - :ref:`EXTRA-COMMAND <PKG-EXTRA-COMMAND>`
- additional command styles
- :doc:`general commands <Commands_all>`
- n/a
- no
* - :ref:`EXTRA-COMPUTE <PKG-EXTRA-COMPUTE>` * - :ref:`EXTRA-COMPUTE <PKG-EXTRA-COMPUTE>`
- additional compute styles - additional compute styles
- :doc:`compute <compute>` - :doc:`compute <compute>`

View File

@ -34,32 +34,66 @@ Description
Write or read a Gromacs style index file in text format that associates 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 atom IDs with the corresponding group definitions. This index file can be
used with in combination with Gromacs analysis tools or to import group used with in combination with Gromacs analysis tools or to import group
definitions into the :doc:`fix colvars <fix_colvars>` input file. It can definitions into the :doc:`fix colvars <fix_colvars>` input file.
also be used to save and restore group definitions for static groups.
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. The *group2ndx* command will write group definitions to an index file.
Without specifying any group IDs, all groups will be written to the index Without specifying any group IDs, all groups will be written to the
file. When specifying group IDs, only those groups will be written to the index file. When specifying group IDs, only those groups will be
index file. In order to follow the Gromacs conventions, the group *all* written to the index file. In order to follow the Gromacs conventions,
will be renamed to *System* in the index file. the group *all* will be renamed to *System* in the index file.
The *ndx2group* command will create of update group definitions from those The *ndx2group* command will create of update group definitions from
stored in an index file. Without specifying any group IDs, all groups except those stored in an index file. Without specifying any group IDs, all
*System* will be read from the index file and the corresponding groups groups except *System* will be read from the index file and the
recreated. If a group of the same name already exists, it will be completely corresponding groups recreated. If a group of the same name already
reset. When specifying group IDs, those groups, if present, will be read exists, it will be completely reset. When specifying group IDs, those
from the index file and restored. 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 <https://manual.gromacs.org/current/onlinehelp/gmx-make_ndx.html>`_.
and follows the `Gromacs definition of an ndx file <https://manual.gromacs.org/current/reference-manual/file-formats.html#ndx>`_
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 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. information that is written to the index file.
These commands are part of the COLVARS package. They are only 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 <Build_package>` page for more info. enabled if LAMMPS was built with that package. See the
:doc:`Build package <Build_package>` page for more info.
Related commands Related commands
"""""""""""""""" """"""""""""""""

View File

@ -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<tagint> read_section(FILE *fp, std::string &name)
{
char linebuf[BUFLEN];
std::vector<tagint> 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<tagint> 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<tagint>(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<tagint> 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<tagint>(tbuf,tbuf+num));
delete[] buf;
delete[] tbuf;
}
}
}
}
if (comm->me == 0) fclose(fp);
}
/* ---------------------------------------------------------------------- */
void Ndx2Group::create(const std::string &name, const std::vector<tagint> &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);
}

View File

@ -1,4 +1,3 @@
// clang-format off
// -*- c++ -*- // -*- c++ -*-
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------
@ -34,12 +33,15 @@ using namespace LAMMPS_NS;
static int cmptagint(const void *p1, const void *p2) static int cmptagint(const void *p1, const void *p2)
{ {
const tagint i1 = * static_cast<const tagint *>(p1); const tagint i1 = *static_cast<const tagint *>(p1);
const tagint i2 = * static_cast<const tagint *>(p2); const tagint i2 = *static_cast<const tagint *>(p2);
if (i1 == i2) return 0; if (i1 == i2)
return 0;
else { else {
if (i1 < i2) return -1; if (i1 < i2)
else return 1; return -1;
else
return 1;
} }
} }
@ -49,27 +51,24 @@ void Group2Ndx::command(int narg, char **arg)
{ {
FILE *fp = nullptr; 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) if (atom->tag_enable == 0) error->all(FLERR, "Must have atom IDs for group2ndx command");
error->all(FLERR,"Must have atom IDs for group2ndx command");
if (comm->me == 0) { if (comm->me == 0) {
fp = fopen(arg[0], "w"); fp = fopen(arg[0], "w");
if (fp == nullptr) if (fp == nullptr)
error->one(FLERR,"Cannot open index file for writing: {}", utils::getsyserror()); error->one(FLERR, "Cannot open index file for writing: {}", utils::getsyserror());
utils::logmesg(lmp,"Writing groups to index file {}:\n",arg[0]); utils::logmesg(lmp, "Writing groups to index file {}:\n", arg[0]);
} }
if (narg == 1) { // write out all groups if (narg == 1) { // write out all groups
for (int i=0; i < group->ngroup; ++i) { for (int i = 0; i < group->ngroup; ++i) { write_group(fp, i); }
write_group(fp,i);
}
} else { // write only selected groups } else { // write only selected groups
for (int i=1; i < narg; ++i) { for (int i = 1; i < narg; ++i) {
int gid = group->find(arg[i]); int gid = group->find(arg[i]);
if (gid < 0) error->all(FLERR, "Non-existing group requested"); 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); bigint gcount = group->count(gid);
int lnum, width, cols; 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) { 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 // the "all" group in LAMMPS is called "System" in Gromacs
if (gid == 0) { if (gid == 0) {
fputs("[ System ]\n", fp); fputs("[ System ]\n", fp);
} else { } 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; cols = 80 / width;
} }
if (gcount > 0) { if (gcount > 0) {
const int * const mask = atom->mask; const int *const mask = atom->mask;
const tagint * const tag = atom->tag; const tagint *const tag = atom->tag;
const int groupbit = group->bitmask[gid]; const int groupbit = group->bitmask[gid];
const int nlocal = atom->nlocal; const int nlocal = atom->nlocal;
int i; int i;
@ -111,45 +114,45 @@ void Group2Ndx::write_group(FILE *fp, int gid)
for (i = 0; i < nlocal; i++) for (i = 0; i < nlocal; i++)
if (mask[i] & groupbit) sendlist[lnum++] = tag[i]; if (mask[i] & groupbit) sendlist[lnum++] = tag[i];
int nrecv=0; int nrecv = 0;
bigint allrecv; bigint allrecv;
if (comm->me == 0) { if (comm->me == 0) {
MPI_Status status; MPI_Status status;
MPI_Request request; MPI_Request request;
for (i=0; i < lnum; i++) for (i = 0; i < lnum; i++) recvlist[i] = sendlist[i];
recvlist[i] = sendlist[i];
allrecv = lnum; allrecv = lnum;
for (i=1; i < comm->nprocs; ++i) { for (i = 1; i < comm->nprocs; ++i) {
MPI_Irecv(recvlist+allrecv,gcount-allrecv,MPI_LMP_TAGINT,i,0, world,&request); 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 // block rank "i" until we are ready to receive
MPI_Wait(&request,&status); MPI_Send(&nrecv, 0, MPI_INT, i, 0, world);
MPI_Get_count(&status,MPI_LMP_TAGINT,&nrecv); MPI_Wait(&request, &status);
MPI_Get_count(&status, MPI_LMP_TAGINT, &nrecv);
allrecv += nrecv; allrecv += nrecv;
} }
// sort received list // sort received list
qsort((void *)recvlist, allrecv, sizeof(tagint), cmptagint); qsort((void *) recvlist, allrecv, sizeof(tagint), cmptagint);
} else { } else {
MPI_Recv(&nrecv,0,MPI_INT,0,0,world,MPI_STATUS_IGNORE); MPI_Recv(&nrecv, 0, MPI_INT, 0, 0, world, MPI_STATUS_IGNORE);
MPI_Rsend(sendlist,lnum,MPI_LMP_TAGINT,0,0,world); MPI_Rsend(sendlist, lnum, MPI_LMP_TAGINT, 0, 0, world);
} }
delete [] sendlist; delete[] sendlist;
} }
if (fp) { if (fp) {
int i, j; int i, j;
for (i=0, j=0; i < gcount; ++i) { for (i = 0, j = 0; i < gcount; ++i) {
fmt::print(fp,"{:>{}}",recvlist[i],width); fmt::print(fp, "{:>{}}", recvlist[i], width);
++j; ++j;
if (j == cols) { if (j == cols) {
fputs("\n",fp); fputs("\n", fp);
j = 0; j = 0;
} }
} }
if (j > 0) fputs("\n",fp); if (j > 0) fputs("\n", fp);
utils::logmesg(lmp,"done\n"); utils::logmesg(lmp, "done\n");
} }
if (gcount > 0) delete[] recvlist; if (gcount > 0) delete[] recvlist;
} }

View File

@ -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<tagint> read_section(FILE *fp, std::string &name)
{
char linebuf[BUFLEN];
std::vector<tagint> 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<tagint> 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<tagint>(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<tagint> 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<tagint>(tbuf, tbuf + num));
delete[] buf;
delete[] tbuf;
}
}
}
}
if (comm->me == 0) fclose(fp);
}
/* ---------------------------------------------------------------------- */
void Ndx2Group::create(const std::string &name, const std::vector<tagint> &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);
}

View File

@ -74,6 +74,7 @@ PACKAGE = \
dpd-smooth \ dpd-smooth \
drude \ drude \
eff \ eff \
extra-command \
extra-compute \ extra-compute \
extra-dump \ extra-dump \
extra-fix \ extra-fix \
@ -168,6 +169,7 @@ PACKMOST = \
dpd-smooth \ dpd-smooth \
drude \ drude \
eff \ eff \
extra-command \
extra-compute \ extra-compute \
extra-dump \ extra-dump \
extra-fix \ extra-fix \