diff --git a/doc/src/labelmap.rst b/doc/src/labelmap.rst index 36c84c3e63..3fbdf07954 100644 --- a/doc/src/labelmap.rst +++ b/doc/src/labelmap.rst @@ -24,8 +24,8 @@ Examples .. code-block:: LAMMPS - labelmap atom 3 carbon - labelmap bond 1 carbonyl 2 nitrile + labelmap atom 3 carbon 4 'c3"' 5 "c1'" 6 "c#" + labelmap bond 1 carbonyl 2 nitrile 3 """ c1'-c2" """ labelmap atom $(label(carbon)) C # change type label from 'carbon' to 'C' labelmap clear labelmap write mymap.include @@ -46,29 +46,33 @@ Bond Type Labels, etc. See the :doc:`Howto type labels labels can be used. Valid type labels may contain any alphanumeric character, but must not -start with a number. They can also contain other standard ASCII -characters such as angular or square brackets '<' and '>' or '[' and -']', parenthesis '(' and ')', dash '-', underscore '_', plus '+' and -equals '=' signs and more. Note that type labels must be put in -quotation marks if they contain the '#' character when used in a context -where the '#' character would be interpreted as starting a comment like -in the LAMMPS input file. +start with a number, a '#', or a '*' character. They may contain other +standard ASCII characters such as angular or square brackets '<' and '>' +or '[' and ']', parenthesis '(' and ')', dash '-', underscore '_', plus +'+' and equals '=' signs and more. The must not contain blanks or any +other whitespace. Note that type labels must be put in single or double +quotation marks if they contain the '#' character, or a double (") or +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 (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 -type, it will be overwritten. Type labels must be unique; assigning -the same type label to multiple numeric types is not allowed. In some -cases, such as when reading and writing data files, it is required -that when type labels are used, that there is a label defined for -*every* numeric type. +pairs may follow. If a type label already exists for the same numeric +type, it will be overwritten. Type labels must be unique; assigning the +same type label to multiple numeric types is not allowed. In some +cases, such as when reading and writing data files, it is required that +when type labels are used, that there is a label defined for *every* +numeric type. The *clear* option resets the labelmap and thus discards all previous settings. 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 -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 ` command. ---------- diff --git a/src/atom.cpp b/src/atom.cpp index b1f4190002..07b5441c63 100644 --- a/src/atom.cpp +++ b/src/atom.cpp @@ -87,7 +87,7 @@ are updated by the AtomVec class as needed. * instances of classes derived from the AtomVec base * 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) { @@ -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); if (id_offset) tag[nlocal-1] += id_offset; if (mol_offset) molecule[nlocal-1] += mol_offset; - if (!isdigit(typestr[0])) { - if (!atom->labelmapflag) error->one(FLERR,"Invalid Atoms section in data file"); - type[nlocal-1] = lmap->find(typestr,Atom::ATOM); - if (type[nlocal-1] == -1) error->one(FLERR,"Invalid Atoms section in data file"); - } else { - type[nlocal-1] = utils::inumeric(FLERR,typestr.c_str(),true,lmp); - if (labelflag) type[nlocal-1] = ilabel[type[nlocal-1]-1]; + // clang-format on + switch (utils::is_type(typestr)) { + + case 0: { // numeric + int itype = utils::inumeric(FLERR, typestr.c_str(), true, lmp); + if ((itype < 1) || (itype > ntypes)) + 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[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; diff --git a/src/read_data.cpp b/src/read_data.cpp index b31e30c319..b6c4f090fe 100644 --- a/src/read_data.cpp +++ b/src/read_data.cpp @@ -82,6 +82,8 @@ enum{NONE, APPEND, VALUE, MERGE}; static const char *suffixes[] = {"/cuda", "/gpu", "/opt", "/omp", "/kk", "/coul/cut", "/coul/long", "/coul/msm", "/coul/dsf", "/coul/debye", "/coul/charmm", nullptr}; +static const char *labeltypes[] = {"Atom", "Bond", "Angle", "Dihedral", "Improper" }; + // clang-format on /* ---------------------------------------------------------------------- */ 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); if (eof) error->all(FLERR, "Unexpected end of data file"); if (tlabelflag && !lmap->is_complete(Atom::ATOM)) - error->all(FLERR, - "Label map is incomplete: " - "all types must be assigned a unique type label"); + error->all(FLERR, "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, lmap->lmap2lmap.atom); nread += nchunk; @@ -2144,21 +2144,38 @@ void ReadData::typelabels(int mode) int eof = utils::read_lines_from_file(fp, lntypes, MAXLINE, buf, me, world); if (eof) error->all(FLERR, "Unexpected end of data file"); - char *next; char *original = buf; - char *typelabel = new char[MAXLINE]; + char *next; for (int i = 0; i < lntypes; i++) { next = strchr(buf, '\n'); *next = '\0'; - int rv = sscanf(buf, "%*d %s", typelabel); - if (rv != 1) error->all(FLERR, "Invalid data file section: Type Labels"); - if (isdigit(typelabel[0])) error->all(FLERR, "Type labels cannot start with a number"); - (*labels)[i] = typelabel; - (*labels_map)[typelabel] = i + 1; + auto values = Tokenizer(buf).as_vector(); + int nwords = values.size(); + for (std::size_t ii = 0; ii < values.size(); ++ii) { + if (utils::strmatch(values[ii],"^#")) { + 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; } 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 // determine mapping to let labels override numeric types diff --git a/unittest/commands/test_labelmap.cpp b/unittest/commands/test_labelmap.cpp index bea5aa9a1d..dcb2559550 100644 --- a/unittest/commands/test_labelmap.cpp +++ b/unittest/commands/test_labelmap.cpp @@ -49,42 +49,6 @@ protected: } 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) diff --git a/unittest/commands/test_set_property.cpp b/unittest/commands/test_set_property.cpp index f482463060..f5e290c671 100644 --- a/unittest/commands/test_set_property.cpp +++ b/unittest/commands/test_set_property.cpp @@ -316,7 +316,7 @@ TEST_F(SetTest, SpinPackage) constexpr double vx = 0.1; constexpr double vy = 0.5; 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][1], vy * norm); ASSERT_EQ(atom->sp[0][2], vz * norm);