revise/refacor Type Label section parsing and Atoms section parsing

- do not ignore numeric type in Type Label sections
- refuse invalid numeric types that will overflow arrays
- check for duplicate numeric type entries or non-unique labels
- better error messages
- use Tokenizer class instead of sscanf()
This commit is contained in:
Axel Kohlmeyer
2022-09-04 01:01:36 -04:00
parent 389c87ab7e
commit ad8a931fe4
5 changed files with 77 additions and 73 deletions

View File

@ -24,8 +24,8 @@ Examples
.. code-block:: LAMMPS .. code-block:: LAMMPS
labelmap atom 3 carbon labelmap atom 3 carbon 4 'c3"' 5 "c1'" 6 "c#"
labelmap bond 1 carbonyl 2 nitrile labelmap bond 1 carbonyl 2 nitrile 3 """ c1'-c2" """
labelmap atom $(label(carbon)) C # change type label from 'carbon' to 'C' labelmap atom $(label(carbon)) C # change type label from 'carbon' to 'C'
labelmap clear labelmap clear
labelmap write mymap.include labelmap write mymap.include
@ -46,29 +46,33 @@ Bond Type Labels, etc. See the :doc:`Howto type labels
labels can be used. labels can be used.
Valid type labels may contain any alphanumeric character, but must not Valid type labels may contain any alphanumeric character, but must not
start with a number. They can also contain other standard ASCII start with a number, a '#', or a '*' character. They may contain other
characters such as angular or square brackets '<' and '>' or '[' and standard ASCII characters such as angular or square brackets '<' and '>'
']', parenthesis '(' and ')', dash '-', underscore '_', plus '+' and or '[' and ']', parenthesis '(' and ')', dash '-', underscore '_', plus
equals '=' signs and more. Note that type labels must be put in '+' and equals '=' signs and more. The must not contain blanks or any
quotation marks if they contain the '#' character when used in a context other whitespace. Note that type labels must be put in single or double
where the '#' character would be interpreted as starting a comment like quotation marks if they contain the '#' character, or a double (") or
in the LAMMPS input file. single quotation mark ("). If the label contains both, single and double
quotes, triple quotation (""") must be used. When using quotation
marks, the LAMMPS input parser may require adding leading or trailing
blanks so it can identify the quotation marks. Those blanks will be
removed when defining the label.
A *labelmap* command can only modify the label map for one type-kind A *labelmap* command can only modify the label map for one type-kind
(atom types, bond types, etc). Any number of numeric-type/type-label (atom types, bond types, etc). Any number of numeric-type/type-label
pairs may follow. If a type label already exists for a given numeric pairs may follow. If a type label already exists for the same numeric
type, it will be overwritten. Type labels must be unique; assigning type, it will be overwritten. Type labels must be unique; assigning the
the same type label to multiple numeric types is not allowed. In some same type label to multiple numeric types is not allowed. In some
cases, such as when reading and writing data files, it is required cases, such as when reading and writing data files, it is required that
that when type labels are used, that there is a label defined for when type labels are used, that there is a label defined for *every*
*every* numeric type. numeric type.
The *clear* option resets the labelmap and thus discards all previous The *clear* option resets the labelmap and thus discards all previous
settings. settings.
The *write* option takes a filename as argument and writes the current The *write* option takes a filename as argument and writes the current
label mappings to a file as labelmap commands, so the file can be copied label mappings to a file as labelmap commands, so the file can be copied
into a different LAMMPS input file or read using the :doc:`include into a new LAMMPS input file or read in using the :doc:`include
<include>` command. <include>` command.
---------- ----------

View File

@ -87,7 +87,7 @@ are updated by the AtomVec class as needed.
* instances of classes derived from the AtomVec base * instances of classes derived from the AtomVec base
* class, which correspond to the selected atom style. * class, which correspond to the selected atom style.
* *
* \param lmp pointer to the base LAMMPS class */ * \param _lmp pointer to the base LAMMPS class */
Atom::Atom(LAMMPS *_lmp) : Pointers(_lmp) Atom::Atom(LAMMPS *_lmp) : Pointers(_lmp)
{ {
@ -1186,17 +1186,36 @@ void Atom::data_atoms(int n, char *buf, tagint id_offset, tagint mol_offset,
avec->data_atom(xdata,imagedata,values,typestr); avec->data_atom(xdata,imagedata,values,typestr);
if (id_offset) tag[nlocal-1] += id_offset; if (id_offset) tag[nlocal-1] += id_offset;
if (mol_offset) molecule[nlocal-1] += mol_offset; if (mol_offset) molecule[nlocal-1] += mol_offset;
if (!isdigit(typestr[0])) { // clang-format on
if (!atom->labelmapflag) error->one(FLERR,"Invalid Atoms section in data file"); switch (utils::is_type(typestr)) {
type[nlocal-1] = lmap->find(typestr,Atom::ATOM);
if (type[nlocal-1] == -1) error->one(FLERR,"Invalid Atoms section in data file"); case 0: { // numeric
} else { int itype = utils::inumeric(FLERR, typestr.c_str(), true, lmp);
type[nlocal-1] = utils::inumeric(FLERR,typestr.c_str(),true,lmp); if ((itype < 1) || (itype > ntypes))
if (labelflag) type[nlocal-1] = ilabel[type[nlocal-1]-1]; error->one(FLERR, "Invalid atom type {} in Atoms section of data file: {}", itype,
buf);
type[nlocal - 1] = itype;
if (labelflag) type[nlocal - 1] = ilabel[itype - 1];
break;
}
case 1: { // type label
if (!atom->labelmapflag)
error->one(FLERR, "Invalid Atoms section line in data file: {}", buf);
type[nlocal - 1] = lmap->find(typestr, Atom::ATOM);
if (type[nlocal - 1] == -1)
error->one(FLERR, "Invalid Atoms section line in data file: {}", buf);
break;
}
default: // invalid
error->one(FLERR, "Invalid Atoms section line in data file: {}", buf);
break;
} }
// clang-format off
if (type_offset) type[nlocal-1] += type_offset; if (type_offset) type[nlocal-1] += type_offset;
if (type[nlocal-1] <= 0 || type[nlocal-1] > ntypes) if (type[nlocal-1] <= 0 || type[nlocal-1] > ntypes)
error->one(FLERR,"Invalid atom type in Atoms section of data file"); error->one(FLERR,"Invalid atom type {} in Atoms section of data file", typestr);
} }
} }
buf = next + 1; buf = next + 1;

View File

@ -82,6 +82,8 @@ enum{NONE, APPEND, VALUE, MERGE};
static const char *suffixes[] = {"/cuda", "/gpu", "/opt", "/omp", "/kk", "/coul/cut", "/coul/long", static const char *suffixes[] = {"/cuda", "/gpu", "/opt", "/omp", "/kk", "/coul/cut", "/coul/long",
"/coul/msm", "/coul/dsf", "/coul/debye", "/coul/charmm", nullptr}; "/coul/msm", "/coul/dsf", "/coul/debye", "/coul/charmm", nullptr};
static const char *labeltypes[] = {"Atom", "Bond", "Angle", "Dihedral", "Improper" };
// clang-format on // clang-format on
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
ReadData::ReadData(LAMMPS *_lmp) : Command(_lmp), fp(nullptr), coeffarg(nullptr), lmap(nullptr) ReadData::ReadData(LAMMPS *_lmp) : Command(_lmp), fp(nullptr), coeffarg(nullptr), lmap(nullptr)
@ -1322,9 +1324,7 @@ void ReadData::atoms()
eof = utils::read_lines_from_file(fp, nchunk, MAXLINE, buffer, me, world); eof = utils::read_lines_from_file(fp, nchunk, MAXLINE, buffer, me, world);
if (eof) error->all(FLERR, "Unexpected end of data file"); if (eof) error->all(FLERR, "Unexpected end of data file");
if (tlabelflag && !lmap->is_complete(Atom::ATOM)) if (tlabelflag && !lmap->is_complete(Atom::ATOM))
error->all(FLERR, error->all(FLERR, "Label map is incomplete: all types must be assigned a unique type label");
"Label map is incomplete: "
"all types must be assigned a unique type label");
atom->data_atoms(nchunk, buffer, id_offset, mol_offset, toffset, shiftflag, shift, tlabelflag, atom->data_atoms(nchunk, buffer, id_offset, mol_offset, toffset, shiftflag, shift, tlabelflag,
lmap->lmap2lmap.atom); lmap->lmap2lmap.atom);
nread += nchunk; nread += nchunk;
@ -2144,21 +2144,38 @@ void ReadData::typelabels(int mode)
int eof = utils::read_lines_from_file(fp, lntypes, MAXLINE, buf, me, world); int eof = utils::read_lines_from_file(fp, lntypes, MAXLINE, buf, me, world);
if (eof) error->all(FLERR, "Unexpected end of data file"); if (eof) error->all(FLERR, "Unexpected end of data file");
char *next;
char *original = buf; char *original = buf;
char *typelabel = new char[MAXLINE]; char *next;
for (int i = 0; i < lntypes; i++) { for (int i = 0; i < lntypes; i++) {
next = strchr(buf, '\n'); next = strchr(buf, '\n');
*next = '\0'; *next = '\0';
int rv = sscanf(buf, "%*d %s", typelabel); auto values = Tokenizer(buf).as_vector();
if (rv != 1) error->all(FLERR, "Invalid data file section: Type Labels"); int nwords = values.size();
if (isdigit(typelabel[0])) error->all(FLERR, "Type labels cannot start with a number"); for (std::size_t ii = 0; ii < values.size(); ++ii) {
(*labels)[i] = typelabel; if (utils::strmatch(values[ii],"^#")) {
(*labels_map)[typelabel] = i + 1; nwords = ii;
break;
}
}
if (nwords != 2)
error->all(FLERR, "Invalid format in section: {} Type Labels: {}", labeltypes[mode], buf);
if (utils::is_type(values[1]) != 1) error->all(FLERR, "Invalid type label {}", values[1]);
int itype = utils::inumeric(FLERR, values[0], false, lmp);
if ((itype < 1) || (itype > lntypes))
error->all(FLERR, "Invalid type {} in section: {} Type Labels: {}", labeltypes[mode], buf);
(*labels)[itype - 1] = values[1];
(*labels_map)[values[1]] = itype;
buf = next + 1; buf = next + 1;
} }
delete[] original; delete[] original;
delete[] typelabel;
for (int i = 0; i < lntypes; ++i) {
if ((*labels)[i].empty())
error->all(FLERR, "{} Type Labels map is incomplete", labeltypes[mode]);
}
if ((int)(*labels_map).size() != lntypes)
error->all(FLERR, "{} Type Labels map is incomplete", labeltypes[mode]);
// merge this read_data label map to atom class // merge this read_data label map to atom class
// determine mapping to let labels override numeric types // determine mapping to let labels override numeric types

View File

@ -49,42 +49,6 @@ protected:
} }
void TearDown() override { LAMMPSTest::TearDown(); } void TearDown() override { LAMMPSTest::TearDown(); }
void atomic_system(const std::string &atom_style, const std::string units = "real")
{
BEGIN_HIDE_OUTPUT();
command("atom_style " + atom_style);
command("atom_modify map array");
command("units " + units);
command("lattice sc 1.0 origin 0.125 0.125 0.125");
command("region box block 0 2 0 2 0 2");
command("create_box 8 box");
command("create_atoms 1 box");
command("mass * 1.0");
command("region left block 0.0 1.0 INF INF INF INF");
command("region right block 1.0 2.0 INF INF INF INF");
command("region top block INF INF 0.0 1.0 INF INF");
command("region bottom block INF INF 1.0 2.0 INF INF");
command("region front block INF INF INF INF 0.0 1.0");
command("region back block INF INF INF 1.0 2.0 INF");
command("group top region top");
command("group bottom region bottom");
END_HIDE_OUTPUT();
}
bool molecular_system()
{
if (info->has_style("atom", "full")) {
BEGIN_HIDE_OUTPUT();
command("variable input_dir index \"" STRINGIFY(TEST_INPUT_FOLDER) "\"");
command("include \"${input_dir}/in.fourmol\"");
command("group allwater molecule 3:6");
command("region half block 0.0 INF INF INF INF INF");
END_HIDE_OUTPUT();
return true;
} else
return false;
}
}; };
TEST_F(SetTest, NoBoxAtoms) TEST_F(SetTest, NoBoxAtoms)

View File

@ -316,7 +316,7 @@ TEST_F(SetTest, SpinPackage)
constexpr double vx = 0.1; constexpr double vx = 0.1;
constexpr double vy = 0.5; constexpr double vy = 0.5;
constexpr double vz = -0.1; constexpr double vz = -0.1;
constexpr double norm = 1.0 / sqrt(vx * vx + vy * vy + vz * vz); const double norm = 1.0 / sqrt(vx * vx + vy * vy + vz * vz);
ASSERT_EQ(atom->sp[0][0], vx * norm); ASSERT_EQ(atom->sp[0][0], vx * norm);
ASSERT_EQ(atom->sp[0][1], vy * norm); ASSERT_EQ(atom->sp[0][1], vy * norm);
ASSERT_EQ(atom->sp[0][2], vz * norm); ASSERT_EQ(atom->sp[0][2], vz * norm);