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
EFF
ELECTRODE
EXTRA-COMMAND
EXTRA-COMPUTE
EXTRA-DUMP
EXTRA-FIX

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -52,6 +52,7 @@ page gives those details.
* :ref:`DRUDE <PKG-DRUDE>`
* :ref:`EFF <PKG-EFF>`
* :ref:`ELECTRODE <PKG-ELECTRODE>`
* :ref:`EXTRA-COMMAND <PKG-EXTRA-COMMAND>`
* :ref:`EXTRA-COMPUTE <PKG-EXTRA-COMPUTE>`
* :ref:`EXTRA-DUMP <PKG-EXTRA-DUMP>`
* :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:
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>`
- PACKAGES/electrode
- no
* - :ref:`EXTRA-COMMAND <PKG-EXTRA-COMMAND>`
- additional command styles
- :doc:`general commands <Commands_all>`
- n/a
- no
* - :ref:`EXTRA-COMPUTE <PKG-EXTRA-COMPUTE>`
- additional compute styles
- :doc:`compute <compute>`

View File

@ -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 <fix_colvars>` input file. It can
also be used to save and restore group definitions for static groups.
definitions into the :doc:`fix colvars <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 <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
""""""""""""
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 <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 <Build_package>` page for more info.
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++ -*-
/* ----------------------------------------------------------------------
@ -34,12 +33,15 @@ using namespace LAMMPS_NS;
static int cmptagint(const void *p1, const void *p2)
{
const tagint i1 = * static_cast<const tagint *>(p1);
const tagint i2 = * static_cast<const tagint *>(p2);
if (i1 == i2) return 0;
const tagint i1 = *static_cast<const tagint *>(p1);
const tagint i2 = *static_cast<const tagint *>(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;
}

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 \
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 \