diff --git a/doc/src/Modify_style.rst b/doc/src/Modify_style.rst index 9b394f23a9..ad2cb656d0 100644 --- a/doc/src/Modify_style.rst +++ b/doc/src/Modify_style.rst @@ -359,6 +359,12 @@ you are uncertain, please ask. - I/O is done via the C-style stdio library and **not** iostreams. +- Do not use so-called "alternative tokens" like ``and``, ``or``, + ``not`` and similar, but rather use the corresponding operators + ``&&``, ``||``, and ``!``. The alternative tokens are not available + by default on all compilers, and also we want to maintain a consistent + programming style. + - Output to the screen and the logfile should be using the corresponding FILE pointers and only be done on MPI rank 0. Use the :cpp:func:`utils::logmesg` convenience function where possible. diff --git a/doc/src/thermo_modify.rst b/doc/src/thermo_modify.rst index 2600b337bc..1bee26c289 100644 --- a/doc/src/thermo_modify.rst +++ b/doc/src/thermo_modify.rst @@ -28,6 +28,7 @@ Syntax *format* values = *line* string, *int* string, *float* string, ID string, or *none* string = C-style format string ID = integer from 1 to N, or integer from -1 to -N, where N = # of quantities being output + *or* an integer range such as 2*6 (negative values are not allowed) *or* a thermo keyword or reference to compute, fix, property or variable. *temp* value = compute ID that calculates a temperature *press* value = compute ID that calculates a pressure @@ -65,10 +66,10 @@ atom can be "lost" if it moves across a non-periodic simulation box :doc:`boundary ` or if it moves more than a box length outside the simulation domain (or more than a processor sub-domain length) before reneighboring occurs. The latter case is typically due to bad -dynamics, e.g. too large a timestep or huge forces and velocities. If +dynamics (e.g., too large a time step and/or huge forces and velocities). If the value is *ignore*, LAMMPS does not check for lost atoms. If the value is *error* or *warn*, LAMMPS checks and either issues an error or -warning. The code will exit with an error and continue with a warning. +warning. The simulation will exit with an error and continue with a warning. A warning will only be issued once, the first time an atom is lost. This can be a useful debugging option. @@ -89,10 +90,10 @@ that should be investigated, but LAMMPS cannot determine for certain whether they are an indication of an error. Some warning messages are printed during a run (or immediately before) -each time a specific MPI rank encounters the issue, e.g. bonds that are -stretched too far or dihedrals in extreme configurations. These number +each time a specific MPI rank encounters the issue (e.g., bonds that are +stretched too far or dihedrals in extreme configurations). These number of these can quickly blow up the size of the log file and screen output. -Thus a limit of 100 warning messages is applied by default. The warning +Thus, a limit of 100 warning messages is applied by default. The warning count is applied to the entire input unless reset with a ``thermo_modify warn reset`` command. If there are more warnings than the limit, LAMMPS will print one final warning that it will not print any additional @@ -160,8 +161,8 @@ for a column or field of thermodynamic output. The setting for *ID string* replaces the default text with the provided string. *ID* can be a positive integer when it represents the column number counting from the left, a negative integer when it represents the column number from -the right (i.e. -1 is the last column/keyword), or a thermo keyword (or -compute, fix, property, or variable reference) and then it replaces the +the right (i.e., :math:`-1` is the last column/keyword), or a thermo keyword +(or compute, fix, property, or variable reference) and then it replaces the string for that specific thermo keyword. The *colname* keyword can be used multiple times. If multiple *colname* @@ -171,19 +172,22 @@ to their default values. The *format* keyword can be used to change the default numeric format of any of quantities the :doc:`thermo_style ` command -outputs. All the specified format strings are C-style formats, e.g. as -used by the C/C++ printf() command. The *line* keyword takes a single +outputs. All the specified format strings are C-style formats (i.e., as +used by the C/C++ printf() command). The *line* keyword takes a single argument which is the format string for the entire line of thermo -output, with N fields, which you must enclose in quotes if it is more +output, with :math:`N` fields, which you must enclose in quotes if it is more than one field. The *int* and *float* keywords take a single format argument and are applied to all integer or floating-point quantities output. The setting for *ID string* also takes a single format argument -which is used for the indexed value in each line. The interpretation is -the same as for *colname*, i.e. a positive integer is the n-th value +that is used for the indexed value in each line. The interpretation is +the same as for *colname* (i.e., a positive integer is the n-th value corresponding to the n-th thermo keyword, a negative integer is counting -backwards, and a string matches the entry with the thermo keyword., -e.g. the fifth column is output in high precision for "format 5 %20.15g" -and the pair energy for "format epair %20.15g". +backwards, and a string matches the entry with the thermo keyword). +For example, the fifth column is output in high precision for +"format 5 %20.15g", and the pair energy for "format epair %20.15g". +The *ID* field can be a range, such as "3\*6", "*", "2*", or "\*3"; +in such cases, all fields in the range (inclusive) are set to the specified +format string. Ranges containing negative numbers are not supported. The *format* keyword can be used multiple times. The precedence is that for each value in a line of output, the *ID* format (if specified) @@ -201,8 +205,8 @@ settings, reverting all values to their default format. to the corresponding 8-byte form when it is applied to those keywords. However, when specifying the *line* option or *format ID string* option for *step* and *natoms*, you should specify a format - string appropriate for an 8-byte signed integer, e.g. one with "%ld" - or "%lld" depending on the platform. + string appropriate for an 8-byte signed integer (i.e., one with "%ld" + or "%lld", depending on the platform). The *temp* keyword is used to determine how thermodynamic temperature is calculated, which is used by all thermo quantities that require a diff --git a/src/thermo.cpp b/src/thermo.cpp index c3dd7d84d5..8dccceae8d 100644 --- a/src/thermo.cpp +++ b/src/thermo.cpp @@ -678,6 +678,19 @@ void Thermo::modify_params(int narg, char **arg) format_int_user.replace(found, 1, std::string(BIGINT_FORMAT).substr(1)); } else if (strcmp(arg[iarg + 1], "float") == 0) { format_float_user = arg[iarg + 2]; + } else if (utils::strmatch(arg[iarg + 1], "^\\d*\\*\\d*$")) { + // handles cases such as 2*6; currently doesn't allow negatives + int nlo, nhi; + utils::bounds(FLERR, arg[iarg + 1], 1, nfield_initial, nlo, nhi, error); + int icol = -1; + for (int i = nlo - 1; i < nhi; i++) { + if (i < 0) icol = nfield_initial + i + 1; // doesn't happen currently + else icol = i; + if (icol < 0 || (icol >= nfield_initial)) + error->all(FLERR, "Invalid thermo_modify format argument: {}", + arg[iarg + 1]); + format_column_user[icol] = arg[iarg + 2]; + } } else { int icol = -1; if (utils::is_integer(arg[iarg + 1])) { diff --git a/unittest/utils/test_utils.cpp b/unittest/utils/test_utils.cpp index f52bc479f3..bd734bbcfd 100644 --- a/unittest/utils/test_utils.cpp +++ b/unittest/utils/test_utils.cpp @@ -631,6 +631,18 @@ TEST(Utils, strmatch_whitespace_nonwhitespace) ASSERT_TRUE(utils::strmatch(" 5.0 angles\n", "^\\s*\\S+\\s+\\S+\\s")); } +TEST(Utils, strmatch_range) +{ + ASSERT_TRUE(utils::strmatch("*11", "^\\d*\\*\\d*$")); + ASSERT_TRUE(utils::strmatch("2*11", "^\\d*\\*\\d*$")); + ASSERT_TRUE(utils::strmatch("5*", "^\\d*\\*\\d*$")); + ASSERT_TRUE(utils::strmatch("*", "^\\d*\\*\\d*$")); + ASSERT_FALSE(utils::strmatch("x5*", "^\\d*\\*\\d*$")); + ASSERT_FALSE(utils::strmatch("x*", "^\\d*\\*\\d*$")); + ASSERT_FALSE(utils::strmatch("*a", "^\\d*\\*\\d*$")); + ASSERT_FALSE(utils::strmatch("1*2d", "^\\d*\\*\\d*$")); +} + TEST(Utils, strfind_beg) { ASSERT_THAT(utils::strfind("rigid/small/omp", "^rigid"), StrEq("rigid"));