diff --git a/.github/workflows/unittest-macos.yml b/.github/workflows/unittest-macos.yml index a65db7636b..f62b3046c9 100644 --- a/.github/workflows/unittest-macos.yml +++ b/.github/workflows/unittest-macos.yml @@ -24,7 +24,9 @@ jobs: shell: bash working-directory: ${{github.workspace}}/build run: | - cmake -C $GITHUB_WORKSPACE/cmake/presets/most.cmake $GITHUB_WORKSPACE/cmake \ + cmake -C $GITHUB_WORKSPACE/cmake/presets/clang.cmake \ + -C $GITHUB_WORKSPACE/cmake/presets/most.cmake \ + $GITHUB_WORKSPACE/cmake \ -DENABLE_TESTING=ON -DBUILD_SHARED_LIBS=ON -DLAMMPS_EXCEPTIONS=ON cmake --build . --parallel 2 diff --git a/doc/src/Developer_unittest.rst b/doc/src/Developer_unittest.rst index 4487dff11c..52753ee1b4 100644 --- a/doc/src/Developer_unittest.rst +++ b/doc/src/Developer_unittest.rst @@ -4,10 +4,10 @@ Adding tests for unit testing This section discusses adding or expanding tests for the unit test infrastructure included into the LAMMPS source code distribution. Unlike example inputs, unit tests focus on testing the "local" behavior -of individual features, tend to run very fast, and should be set up to -cover as much of the added code as possible. When contributing code to -the distribution, the LAMMPS developers will appreciate if additions -to the integrated unit test facility are included. +of individual features, tend to run fast, and should be set up to cover +as much of the added code as possible. When contributing code to the +distribution, the LAMMPS developers will appreciate if additions to the +integrated unit test facility are included. Given the complex nature of MD simulations where many operations can only be performed when suitable "real" simulation environment has been @@ -50,6 +50,9 @@ available: * - File name: - Test name: - Description: + * - ``test_argutils.cpp`` + - ArgInfo + - Tests for ``ArgInfo`` class used by LAMMPS * - ``test_fmtlib.cpp`` - FmtLib - Tests for ``fmtlib::`` functions used by LAMMPS @@ -155,23 +158,27 @@ have the desired effect: { ASSERT_EQ(lmp->update->ntimestep, 0); - if (!verbose) ::testing::internal::CaptureStdout(); - lmp->input->one("reset_timestep 10"); - if (!verbose) ::testing::internal::GetCapturedStdout(); + BEGIN_HIDE_OUTPUT(); + command("reset_timestep 10"); + END_HIDE_OUTPUT(); ASSERT_EQ(lmp->update->ntimestep, 10); - if (!verbose) ::testing::internal::CaptureStdout(); - lmp->input->one("reset_timestep 0"); - if (!verbose) ::testing::internal::GetCapturedStdout(); + BEGIN_HIDE_OUTPUT(); + command("reset_timestep 0"); + END_HIDE_OUTPUT(); ASSERT_EQ(lmp->update->ntimestep, 0); + + TEST_FAILURE(".*ERROR: Timestep must be >= 0.*", command("reset_timestep -10");); + TEST_FAILURE(".*ERROR: Illegal reset_timestep .*", command("reset_timestep");); + TEST_FAILURE(".*ERROR: Illegal reset_timestep .*", command("reset_timestep 10 10");); + TEST_FAILURE(".*ERROR: Expected integer .*", command("reset_timestep xxx");); } -Please note the use of the (global) verbose variable to control whether -the LAMMPS command will be silent by capturing the output or not. In -the default case, verbose == false, the test output will be compact and -not mixed with LAMMPS output. However setting the verbose flag (via -setting the ``TEST_ARGS`` environment variable, ``TEST_ARGS=-v``) can be -helpful to understand why tests fail unexpectedly. +Please note the use of the ``BEGIN_HIDE_OUTPUT`` and ``END_HIDE_OUTPUT`` +functions that will capture output from running LAMMPS. This is normally +discarded but by setting the verbose flag (via setting the ``TEST_ARGS`` +environment variable, ``TEST_ARGS=-v``) it can be printed and used to +understand why tests fail unexpectedly. Another complexity of these tests stems from the need to capture situations where LAMMPS will stop with an error, i.e. handle so-called @@ -210,6 +217,12 @@ The following test programs are currently available: * - ``test_lattice_region.cpp`` - LatticeRegion - Tests to validate the :doc:`lattice ` and :doc:`region ` commands + * - ``test_groups.cpp`` + - GroupTest + - Tests to validate the :doc:`group ` command + * - ``test_variables.cpp`` + - VariableTest + - Tests to validate the :doc:`variable ` command * - ``test_kim_commands.cpp`` - KimCommands - Tests for several commands from the :ref:`KIM package ` diff --git a/doc/src/Packages_standard.rst b/doc/src/Packages_standard.rst index ab9be69ab3..81623c8d4a 100644 --- a/doc/src/Packages_standard.rst +++ b/doc/src/Packages_standard.rst @@ -71,6 +71,8 @@ package: +----------------------------------+--------------------------------------+----------------------------------------------------+------------------------------------------------------+---------+ | :ref:`PERI ` | Peridynamics models | :doc:`pair_style peri ` | peri | no | +----------------------------------+--------------------------------------+----------------------------------------------------+------------------------------------------------------+---------+ +| :ref:`PLUGIN ` | Plugin loader command | :doc:`plugin ` | plugins | no | ++----------------------------------+--------------------------------------+----------------------------------------------------+------------------------------------------------------+---------+ | :ref:`POEMS ` | coupled rigid body motion | :doc:`fix poems ` | rigid | int | +----------------------------------+--------------------------------------+----------------------------------------------------+------------------------------------------------------+---------+ | :ref:`PYTHON ` | embed Python code in an input script | :doc:`python ` | python | sys | diff --git a/doc/src/rerun.rst b/doc/src/rerun.rst index 7d51fba868..e9e23afba8 100644 --- a/doc/src/rerun.rst +++ b/doc/src/rerun.rst @@ -15,7 +15,7 @@ Syntax .. parsed-literal:: - keyword = *first* or *last* or *every* or *skip* or *start* or *stop* or *dump* + keyword = *first* or *last* or *every* or *skip* or *start* or *stop* or *post* or *dump* *first* args = Nfirst Nfirst = dump timestep to start on *last* args = Nlast @@ -28,6 +28,7 @@ Syntax Nstart = timestep on which pseudo run will start *stop* args = Nstop Nstop = timestep to which pseudo run will end + *post* value = *yes* or *no* *dump* args = same as :doc:`read_dump ` command starting with its field arguments Examples @@ -154,6 +155,10 @@ Also note that an error will occur if you read a snapshot from the dump file with a timestep value larger than the *stop* setting you have specified. +The *post* keyword can be used to minimize the output to the screen that +happens after a *rerun* command, similar to the post keyword of the +:doc:`run command `. It is set to *no* by default. + The *dump* keyword is required and must be the last keyword specified. Its arguments are passed internally to the :doc:`read_dump ` command. The first argument following the *dump* keyword should be @@ -226,4 +231,4 @@ Default The option defaults are first = 0, last = a huge value (effectively infinity), start = same as first, stop = same as last, every = 0, skip -= 1; += 1, post = no; diff --git a/src/KSPACE/pair_lj_cut_coul_long.cpp b/src/KSPACE/pair_lj_cut_coul_long.cpp index fcb39b8c6e..5d04fd1cfb 100644 --- a/src/KSPACE/pair_lj_cut_coul_long.cpp +++ b/src/KSPACE/pair_lj_cut_coul_long.cpp @@ -17,21 +17,21 @@ #include "pair_lj_cut_coul_long.h" -#include -#include #include "atom.h" #include "comm.h" +#include "error.h" #include "force.h" #include "kspace.h" -#include "update.h" -#include "respa.h" -#include "neighbor.h" -#include "neigh_list.h" -#include "neigh_request.h" #include "math_const.h" #include "memory.h" -#include "error.h" +#include "neigh_list.h" +#include "neigh_request.h" +#include "neighbor.h" +#include "respa.h" +#include "update.h" +#include +#include using namespace LAMMPS_NS; using namespace MathConst; diff --git a/src/USER-REAXC/reaxc_tool_box.cpp b/src/USER-REAXC/reaxc_tool_box.cpp index f0171d2108..abab3f2b43 100644 --- a/src/USER-REAXC/reaxc_tool_box.cpp +++ b/src/USER-REAXC/reaxc_tool_box.cpp @@ -25,10 +25,11 @@ ----------------------------------------------------------------------*/ #include "reaxc_tool_box.h" +#include "reaxc_defs.h" + #include #include #include -#include "reaxc_defs.h" #include "error.h" @@ -49,62 +50,58 @@ int Tokenize( char* s, char*** tok ) return count; } - - /* safe malloc */ void *smalloc( LAMMPS_NS::Error *error_ptr, rc_bigint n, const char *name ) { void *ptr; - char errmsg[256]; if (n <= 0) { - snprintf(errmsg, 256, "Trying to allocate %ld bytes for array %s. " - "returning NULL.", n, name); + auto errmsg = fmt::format("Trying to allocate {} bytes for array {}. " + "returning NULL.", n, name); if (error_ptr) error_ptr->one(FLERR,errmsg); - else fputs(errmsg,stderr); + else fputs(errmsg.c_str(),stderr); return nullptr; } ptr = malloc( n ); if (ptr == nullptr) { - snprintf(errmsg, 256, "Failed to allocate %ld bytes for array %s", n, name); + auto errmsg = fmt::format("Failed to allocate {} bytes for array {}", + n, name); if (error_ptr) error_ptr->one(FLERR,errmsg); - else fputs(errmsg,stderr); + else fputs(errmsg.c_str(),stderr); } return ptr; } - /* safe calloc */ void *scalloc( LAMMPS_NS::Error *error_ptr, rc_bigint n, rc_bigint size, const char *name ) { void *ptr; - char errmsg[256]; if (n <= 0) { - snprintf(errmsg, 256, "Trying to allocate %ld elements for array %s. " - "returning NULL.\n", n, name ); + auto errmsg = fmt::format("Trying to allocate {} elements for array {}. " + "returning NULL.\n", n, name); if (error_ptr) error_ptr->one(FLERR,errmsg); - else fputs(errmsg,stderr); + else fputs(errmsg.c_str(),stderr); return nullptr; } if (size <= 0) { - snprintf(errmsg, 256, "Elements size for array %s is %ld. " - "returning NULL", name, size ); + auto errmsg = fmt::format("Elements size for array {} is {}. " + "returning NULL", name, size); if (error_ptr) error_ptr->one(FLERR,errmsg); - else fputs(errmsg,stderr); + else fputs(errmsg.c_str(),stderr); return nullptr; } ptr = calloc( n, size ); if (ptr == nullptr) { - char errmsg[256]; - snprintf(errmsg, 256, "Failed to allocate %ld bytes for array %s", n*size, name); + auto errmsg = fmt::format("Failed to allocate {} bytes for array {}", + n*size, name); if (error_ptr) error_ptr->one(FLERR,errmsg); - else fputs(errmsg,stderr); + else fputs(errmsg.c_str(),stderr); } return ptr; @@ -115,14 +112,14 @@ void *scalloc( LAMMPS_NS::Error *error_ptr, rc_bigint n, rc_bigint size, const c void sfree( LAMMPS_NS::Error* error_ptr, void *ptr, const char *name ) { if (ptr == nullptr) { - char errmsg[256]; - snprintf(errmsg, 256, "Trying to free the already NULL pointer %s", name ); + auto errmsg = fmt::format("Trying to free the already free()'d pointer {}", + name); if (error_ptr) error_ptr->one(FLERR,errmsg); - else fputs(errmsg,stderr); + else fputs(errmsg.c_str(),stderr); return; } - free( ptr ); + free(ptr); ptr = nullptr; } diff --git a/src/USER-REAXC/reaxc_traj.h b/src/USER-REAXC/reaxc_traj.h index 4966bf11d8..2ff5995204 100644 --- a/src/USER-REAXC/reaxc_traj.h +++ b/src/USER-REAXC/reaxc_traj.h @@ -36,14 +36,18 @@ #define HEADER_LINE_LEN 62 #define STR_LINE "%-37s%-24s\n" #define INT_LINE "%-37s%-24d\n" -#define BIGINT_LINE "%-37s%-24ld\n" +#if defined(LAMMPS_SMALLSMALL) +#define BIGINT_LINE "%-37s%-24d\n" +#else +#define BIGINT_LINE "%-37s%-24lld\n" +#endif #define INT2_LINE "%-36s%-12d,%-12d\n" #define REAL_LINE "%-37s%-24.3f\n" #define SCI_LINE "%-37s%-24g\n" #define REAL3_LINE "%-32s%9.3f,%9.3f,%9.3f\n" #if defined(LAMMPS_BIGBIG) -#define INIT_DESC "%9ld%3d%9s%10.3f\n" //AtomID - AtomType, AtomName, AtomMass +#define INIT_DESC "%9lld%3d%9s%10.3f\n" //AtomID - AtomType, AtomName, AtomMass #else #define INIT_DESC "%9d%3d%9s%10.3f\n" //AtomID - AtomType, AtomName, AtomMass #endif @@ -56,7 +60,7 @@ #define SIZE_INFO_LEN3 31 #if defined(LAMMPS_BIGBIG) -#define ATOM_BASIC "%9ld%10.3f%10.3f%10.3f%10.3f\n" //AtomID AtomType (X Y Z) Charge +#define ATOM_BASIC "%9lld%10.3f%10.3f%10.3f%10.3f\n" //AtomID AtomType (X Y Z) Charge #define ATOM_wV "%9ld%10.3f%10.3f%10.3f%10.3f%10.3f%10.3f%10.3f\n" //AtomID (X Y Z) (Vx Vy Vz) Charge #define ATOM_wF "%9ld%10.3f%10.3f%10.3f%10.3f%10.3f%10.3f%10.3f\n" //AtomID (X Y Z) (Fx Fy Fz) Charge #define ATOM_FULL "%9ld%10.3f%10.3f%10.3f%10.3f%10.3f%10.3f%10.3f%10.3f%10.3f%10.3f\n" //AtomID (X Y Z) (Vx Vy Vz) (Fx Fy Fz) Charge @@ -72,9 +76,9 @@ #define ATOM_FULL_LEN 110 #if defined(LAMMPS_BIGBIG) -#define BOND_BASIC "%9ld%9ld%10.3f%10.3f\n" // Atom1 Atom2 Dist Total_BO -#define BOND_FULL "%9ld%9ld%10.3f%10.3f%10.3f%10.3f%10.3f\n" // Atom1 Atom2 Dist Total_BO BOs BOpi BOpi2 -#define ANGLE_BASIC "%9ld%9ld%9ld%10.3f\n" // Atom1 Atom2 Atom3 Theta +#define BOND_BASIC "%9lld%9lld%10.3f%10.3f\n" // Atom1 Atom2 Dist Total_BO +#define BOND_FULL "%9lld%9lld%10.3f%10.3f%10.3f%10.3f%10.3f\n" // Atom1 Atom2 Dist Total_BO BOs BOpi BOpi2 +#define ANGLE_BASIC "%9lld%9lld%9lld%10.3f\n" // Atom1 Atom2 Atom3 Theta #else #define BOND_BASIC "%9d%9d%10.3f%10.3f\n" // Atom1 Atom2 Dist Total_BO #define BOND_FULL "%9d%9d%10.3f%10.3f%10.3f%10.3f%10.3f\n" // Atom1 Atom2 Dist Total_BO BOs BOpi BOpi2 diff --git a/src/USER-YAFF/pair_lj_switch3_coulgauss_long.cpp b/src/USER-YAFF/pair_lj_switch3_coulgauss_long.cpp index 6e4c0587f7..2247a9467c 100644 --- a/src/USER-YAFF/pair_lj_switch3_coulgauss_long.cpp +++ b/src/USER-YAFF/pair_lj_switch3_coulgauss_long.cpp @@ -106,6 +106,7 @@ void PairLJSwitch3CoulGaussLong::compute(int eflag, int vflag) firstneigh = list->firstneigh; // loop over neighbors of my atoms + for (ii = 0; ii < inum; ii++) { i = ilist[ii]; qtmp = q[i]; @@ -193,7 +194,7 @@ void PairLJSwitch3CoulGaussLong::compute(int eflag, int vflag) offset[itype][jtype]; } else evdwl = 0.0; - // Truncation, see Yaff Switch33 + // Truncation, see Yaff Switch3 if (truncw>0) { if (rsq < cut_ljsq[itype][jtype]) { if (r>cut_lj[itype][jtype]-truncw) { @@ -262,19 +263,18 @@ void PairLJSwitch3CoulGaussLong::allocate() void PairLJSwitch3CoulGaussLong::settings(int narg, char **arg) { - if (narg < 2 || narg > 3) error->all(FLERR,"Illegal pair_style command"); + if (narg < 2 || narg > 3) error->all(FLERR,"Illegal pair_style command"); cut_lj_global = utils::numeric(FLERR,arg[0],false,lmp); + if (narg == 2) { cut_coul = cut_lj_global; truncw = utils::numeric(FLERR,arg[1],false,lmp); - } - else { + } else { cut_coul = utils::numeric(FLERR,arg[1],false,lmp); truncw = utils::numeric(FLERR,arg[2],false,lmp); } - if (truncw>0.0) truncwi = 1.0/truncw; - else truncwi = 0.0; + // reset cutoffs that have been explicitly set if (allocated) { @@ -332,6 +332,9 @@ void PairLJSwitch3CoulGaussLong::init_style() cut_coulsq = cut_coul * cut_coul; + if (truncw>0.0) truncwi = 1.0/truncw; + else truncwi = 0.0; + // insure use of KSpace long-range solver, set g_ewald if (force->kspace == nullptr) @@ -375,8 +378,7 @@ double PairLJSwitch3CoulGaussLong::init_one(int i, int j) double r6inv = r2inv*r2inv*r2inv; double r12inv = r6inv*r6inv; offset[i][j] = lj3[i][j]*r12inv-lj4[i][j]*r6inv; - } - else {offset[i][j] = 0.0;} + } else {offset[i][j] = 0.0;} } else offset[i][j] = 0.0; cut_ljsq[j][i] = cut_ljsq[i][j]; @@ -431,8 +433,7 @@ double PairLJSwitch3CoulGaussLong::init_one(int i, int j) double t71 = -0.4e1 * cg * (0.2e1 * t10 * t11 - 0.2e1 * t10 * t14 + (cg5 - 0.2e1 * cg1) * t58 * cg5) * t26 / t4 / t41 / t9; etail_ij = 2.0*MY_PI*all[0]*all[1]*t71; ptail_ij = 2.0*MY_PI*all[0]*all[1]*t71; - } - else { + } else { double t1 = pow(cg3, 0.2e1); double t2 = t1 * t1; double t3 = t2 * t1; @@ -618,6 +619,7 @@ double PairLJSwitch3CoulGaussLong::single(int i, int j, int itype, int jtype, expn2 = 0.0; erfc2 = 0.0; forcecoul2 = 0.0; + prefactor2 = 0.0; } else { r = sqrt(rsq); rrij = lj2[itype][jtype]*r; diff --git a/src/USER-YAFF/pair_mm3_switch3_coulgauss_long.cpp b/src/USER-YAFF/pair_mm3_switch3_coulgauss_long.cpp index 67a322ca24..c7fcac855a 100644 --- a/src/USER-YAFF/pair_mm3_switch3_coulgauss_long.cpp +++ b/src/USER-YAFF/pair_mm3_switch3_coulgauss_long.cpp @@ -106,6 +106,7 @@ void PairMM3Switch3CoulGaussLong::compute(int eflag, int vflag) firstneigh = list->firstneigh; // loop over neighbors of my atoms + for (ii = 0; ii < inum; ii++) { i = ilist[ii]; qtmp = q[i]; @@ -170,6 +171,7 @@ void PairMM3Switch3CoulGaussLong::compute(int eflag, int vflag) expn2 = 0.0; erfc2 = 0.0; forcecoul2 = 0.0; + prefactor2 = 0.0; } else { rrij = lj2[itype][jtype]*r; expn2 = exp(-rrij*rrij); @@ -263,19 +265,18 @@ void PairMM3Switch3CoulGaussLong::allocate() void PairMM3Switch3CoulGaussLong::settings(int narg, char **arg) { - if (narg < 2 || narg > 3) error->all(FLERR,"Illegal pair_style command"); + if (narg < 2 || narg > 3) error->all(FLERR,"Illegal pair_style command"); cut_lj_global = utils::numeric(FLERR,arg[0],false,lmp); + if (narg == 2) { cut_coul = cut_lj_global; truncw = utils::numeric(FLERR,arg[1],false,lmp); - } - else { + } else { cut_coul = utils::numeric(FLERR,arg[1],false,lmp); truncw = utils::numeric(FLERR,arg[2],false,lmp); } - if (truncw>0.0) truncwi = 1.0/truncw; - else truncwi = 0.0; + // reset cutoffs that have been explicitly set if (allocated) { @@ -333,6 +334,9 @@ void PairMM3Switch3CoulGaussLong::init_style() cut_coulsq = cut_coul * cut_coul; + if (truncw>0.0) truncwi = 1.0/truncw; + else truncwi = 0.0; + // insure use of KSpace long-range solver, set g_ewald if (force->kspace == nullptr) @@ -375,8 +379,7 @@ double PairMM3Switch3CoulGaussLong::init_one(int i, int j) double r6inv = r2inv*r2inv*r2inv; double expb = lj3[i][j]*exp(-lj1[i][j]*r); offset[i][j] = expb-lj4[i][j]*r6inv; - } - else {offset[i][j] = 0.0;} + } else {offset[i][j] = 0.0;} } else offset[i][j] = 0.0; cut_ljsq[j][i] = cut_ljsq[i][j]; @@ -426,8 +429,7 @@ double PairMM3Switch3CoulGaussLong::init_one(int i, int j) double t64 = cg * (0.6388888889e3 * ((-t3 + (0.7e1 / 0.36e2 * cg5 - t5) * t1 - 0.2e1 / 0.3e1 * t8 * (cg5 - cg1 / 0.4e1) * cg3 + cg5 * t14) * t20 + t3 + (cg5 / 0.12e2 + t5) * t1 + (cg5 + cg1 / 0.3e1) * cg1 * cg3 / 0.2e1 + t30 * cg5) * t2 * t36 * t39 - 0.225e1 * (0.2e1 * t43 * t44 - 0.2e1 * t43 * t47 + cg5 * (cg5 - 0.2e1 * cg1)) * t54 * t1 / cg1 / t8 * t39); etail_ij = 2.0*MY_PI*all[0]*all[1]*t64; ptail_ij = 2.0*MY_PI*all[0]*all[1]*t64; - } - else { + } else { double t2 = pow(cg3, 0.2e1); double t3 = t2 * t2; double t7 = 0.12e2 / cg3 * cg1; diff --git a/src/random_mars.cpp b/src/random_mars.cpp index 621d7d3008..78c6f93ba4 100644 --- a/src/random_mars.cpp +++ b/src/random_mars.cpp @@ -136,13 +136,16 @@ double RanMars::gaussian(double mu, double sigma) double RanMars::rayleigh(double sigma) { - double first,v1; + double v1; - if (sigma <= 0) error->all(FLERR,"Invalid Rayleigh parameter"); + if (sigma <= 0.0) error->all(FLERR,"Invalid Rayleigh parameter"); v1 = uniform(); - first = sigma*sqrt(-2.0*log(v1)); - return first; + // avoid a floating point exception due to log(0.0) + // and just return a very big number + if (v1 == 0.0) return 1.0e300; + + return sigma*sqrt(-2.0*log(v1)); } /* ---------------------------------------------------------------------- diff --git a/src/rerun.cpp b/src/rerun.cpp index 648874420a..8615b02d95 100644 --- a/src/rerun.cpp +++ b/src/rerun.cpp @@ -51,6 +51,7 @@ void Rerun::command(int narg, char **arg) if (strcmp(arg[iarg],"start") == 0) break; if (strcmp(arg[iarg],"stop") == 0) break; if (strcmp(arg[iarg],"dump") == 0) break; + if (strcmp(arg[iarg],"post") == 0) break; iarg++; } int nfile = iarg; @@ -65,6 +66,7 @@ void Rerun::command(int narg, char **arg) int nskip = 1; int startflag = 0; int stopflag = 0; + int postflag = 0; bigint start = -1; bigint stop = -1; @@ -101,6 +103,14 @@ void Rerun::command(int narg, char **arg) stop = utils::bnumeric(FLERR,arg[iarg+1],false,lmp); if (stop < 0) error->all(FLERR,"Illegal rerun command"); iarg += 2; + } else if (strcmp(arg[iarg],"post") == 0) { + if (iarg+2 > narg) error->all(FLERR,"Illegal rerun command"); + if (strcmp(arg[iarg+1],"yes") == 0) { + postflag = 1; + } else if (strcmp(arg[iarg+1],"no") == 0) { + postflag = 0; + } else error->all(FLERR,"Illegal rerun command"); + iarg += 2; } else if (strcmp(arg[iarg],"dump") == 0) { break; } else error->all(FLERR,"Illegal rerun command"); @@ -182,7 +192,7 @@ void Rerun::command(int narg, char **arg) update->nsteps = ndump; Finish finish(lmp); - finish.end(1); + finish.end(postflag); update->whichflag = 0; update->firststep = update->laststep = 0; diff --git a/src/tokenizer.h b/src/tokenizer.h index 2db9870866..b3bbf05296 100644 --- a/src/tokenizer.h +++ b/src/tokenizer.h @@ -41,7 +41,7 @@ public: Tokenizer& operator=(Tokenizer&&) = default; void reset(); - void skip(int n); + void skip(int n=1); bool has_next() const; bool contains(const std::string &str) const; std::string next(); @@ -104,7 +104,7 @@ public: bool has_next() const; bool contains(const std::string &value) const; - void skip(int ntokens); + void skip(int ntokens=1); size_t count(); }; diff --git a/src/velocity.cpp b/src/velocity.cpp index b8d2e5229a..f4483074aa 100644 --- a/src/velocity.cpp +++ b/src/velocity.cpp @@ -108,7 +108,7 @@ void Velocity::command(int narg, char **arg) int initcomm = 0; if (style == ZERO && rfix >= 0 && - utils::strmatch(modify->fix[rfix]->style,"^rigid/small")) initcomm = 1; + utils::strmatch(modify->fix[rfix]->style,"^rigid.*/small.*")) initcomm = 1; if ((style == CREATE || style == SET) && temperature && strcmp(temperature->style,"temp/cs") == 0) initcomm = 1; diff --git a/unittest/commands/test_simple_commands.cpp b/unittest/commands/test_simple_commands.cpp index 9173909806..9bd6e74c9b 100644 --- a/unittest/commands/test_simple_commands.cpp +++ b/unittest/commands/test_simple_commands.cpp @@ -328,11 +328,7 @@ TEST_F(SimpleCommandsTest, Units) #if defined(LMP_PLUGIN) TEST_F(SimpleCommandsTest, Plugin) { -#if defined(__APPLE__) - std::string loadfmt("plugin load {}plugin.dylib"); -#else std::string loadfmt("plugin load {}plugin.so"); -#endif ::testing::internal::CaptureStdout(); lmp->input->one(fmt::format(loadfmt, "hello")); auto text = ::testing::internal::GetCapturedStdout(); diff --git a/unittest/force-styles/tests/fix-timestep-adapt_coul.yaml b/unittest/force-styles/tests/fix-timestep-adapt_coul.yaml index 4bf25f3b33..f0ec2f1292 100644 --- a/unittest/force-styles/tests/fix-timestep-adapt_coul.yaml +++ b/unittest/force-styles/tests/fix-timestep-adapt_coul.yaml @@ -1,7 +1,7 @@ --- lammps_version: 10 Mar 2021 date_generated: Thu Mar 25 14:07:45 202 -epsilon: 1e-14 +epsilon: 5e-13 prerequisites: ! | atom full fix adapt diff --git a/unittest/formats/test_dump_atom.cpp b/unittest/formats/test_dump_atom.cpp index 46c6b7dfa7..5161eece3e 100644 --- a/unittest/formats/test_dump_atom.cpp +++ b/unittest/formats/test_dump_atom.cpp @@ -15,6 +15,8 @@ #include "../testing/systems/melt.h" #include "../testing/utils.h" #include "fmt/format.h" +#include "output.h" +#include "thermo.h" #include "utils.h" #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -24,7 +26,7 @@ using ::testing::Eq; char *BINARY2TXT_BINARY = nullptr; -bool verbose = false; +bool verbose = false; class DumpAtomTest : public MeltTest { std::string dump_style = "atom"; @@ -46,7 +48,14 @@ public: command(fmt::format("dump_modify id {}", dump_modify_options)); } - command(fmt::format("run {}", ntimesteps)); + command(fmt::format("run {} post no", ntimesteps)); + END_HIDE_OUTPUT(); + } + + void continue_dump(int ntimesteps) + { + BEGIN_HIDE_OUTPUT(); + command(fmt::format("run {} pre no post no", ntimesteps)); END_HIDE_OUTPUT(); } @@ -62,7 +71,7 @@ public: command(fmt::format("dump_modify id1 {}", dump_modify_options)); } - command(fmt::format("run {}", ntimesteps)); + command(fmt::format("run {} post no", ntimesteps)); END_HIDE_OUTPUT(); } @@ -446,13 +455,16 @@ TEST_F(DumpAtomTest, binary_triclinic_with_image_run0) delete_file(converted_file); } -TEST_F(DumpAtomTest, run1) +TEST_F(DumpAtomTest, run1plus1) { - auto dump_file = "dump_run1.melt"; + auto dump_file = "dump_run1plus1.melt"; generate_dump(dump_file, "", 1); ASSERT_FILE_EXISTS(dump_file); ASSERT_EQ(count_lines(dump_file), 82); + continue_dump(1); + ASSERT_FILE_EXISTS(dump_file); + ASSERT_EQ(count_lines(dump_file), 123); delete_file(dump_file); } @@ -466,6 +478,34 @@ TEST_F(DumpAtomTest, run2) delete_file(dump_file); } +TEST_F(DumpAtomTest, rerun) +{ + auto dump_file = "dump_rerun.melt"; + HIDE_OUTPUT([&] { + command("fix 1 all nve"); + }); + generate_dump(dump_file, "format line \"%d %d %20.15g %20.15g %20.15g\"", 1); + double pe_1, pe_2, pe_rerun; + lmp->output->thermo->evaluate_keyword("pe", &pe_1); + ASSERT_FILE_EXISTS(dump_file); + ASSERT_EQ(count_lines(dump_file), 82); + continue_dump(1); + lmp->output->thermo->evaluate_keyword("pe", &pe_2); + ASSERT_FILE_EXISTS(dump_file); + ASSERT_EQ(count_lines(dump_file), 123); + HIDE_OUTPUT([&] { + command(fmt::format("rerun {} first 1 last 1 every 1 post no dump x y z", dump_file)); + }); + lmp->output->thermo->evaluate_keyword("pe", &pe_rerun); + ASSERT_DOUBLE_EQ(pe_1, pe_rerun); + HIDE_OUTPUT([&] { + command(fmt::format("rerun {} first 2 last 2 every 1 post yes dump x y z", dump_file)); + }); + lmp->output->thermo->evaluate_keyword("pe", &pe_rerun); + ASSERT_DOUBLE_EQ(pe_2, pe_rerun); + delete_file(dump_file); +} + TEST_F(DumpAtomTest, multi_file_run1) { auto dump_file = "dump_run1_*.melt"; diff --git a/unittest/formats/test_dump_custom.cpp b/unittest/formats/test_dump_custom.cpp index b90d77e966..f8a55bb2fb 100644 --- a/unittest/formats/test_dump_custom.cpp +++ b/unittest/formats/test_dump_custom.cpp @@ -15,6 +15,8 @@ #include "../testing/systems/melt.h" #include "../testing/utils.h" #include "fmt/format.h" +#include "output.h" +#include "thermo.h" #include "utils.h" #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -22,7 +24,7 @@ using ::testing::Eq; char *BINARY2TXT_BINARY = nullptr; -bool verbose = false; +bool verbose = false; class DumpCustomTest : public MeltTest { std::string dump_style = "custom"; @@ -45,7 +47,14 @@ public: command(fmt::format("dump_modify id {}", dump_modify_options)); } - command(fmt::format("run {}", ntimesteps)); + command(fmt::format("run {} post no", ntimesteps)); + END_HIDE_OUTPUT(); + } + + void continue_dump(int ntimesteps) + { + BEGIN_HIDE_OUTPUT(); + command(fmt::format("run {} pre no post no", ntimesteps)); END_HIDE_OUTPUT(); } @@ -62,7 +71,7 @@ public: command(fmt::format("dump_modify id1 {}", dump_modify_options)); } - command(fmt::format("run {}", ntimesteps)); + command(fmt::format("run {} post no", ntimesteps)); END_HIDE_OUTPUT(); } @@ -262,6 +271,64 @@ TEST_F(DumpCustomTest, with_variable_run1) delete_file(dump_file); } +TEST_F(DumpCustomTest, run1plus1) +{ + auto dump_file = "dump_custom_run1plus1.melt"; + auto fields = "id type x y z"; + + generate_dump(dump_file, fields, "units yes", 1); + + ASSERT_FILE_EXISTS(dump_file); + auto lines = read_lines(dump_file); + ASSERT_EQ(lines.size(), 84); + continue_dump(1); + ASSERT_FILE_EXISTS(dump_file); + lines = read_lines(dump_file); + ASSERT_EQ(lines.size(), 125); + delete_file(dump_file); +} + +TEST_F(DumpCustomTest, run2) +{ + auto dump_file = "dump_custom_run2.melt"; + auto fields = "id type x y z"; + generate_dump(dump_file, fields, "", 2); + + ASSERT_FILE_EXISTS(dump_file); + ASSERT_EQ(count_lines(dump_file), 123); + delete_file(dump_file); +} + +TEST_F(DumpCustomTest, rerun) +{ + auto dump_file = "dump_rerun.melt"; + auto fields = "id type xs ys zs"; + + HIDE_OUTPUT([&] { + command("fix 1 all nve"); + }); + generate_dump(dump_file, fields, "format float %20.15g", 1); + double pe_1, pe_2, pe_rerun; + lmp->output->thermo->evaluate_keyword("pe", &pe_1); + ASSERT_FILE_EXISTS(dump_file); + ASSERT_EQ(count_lines(dump_file), 82); + continue_dump(1); + lmp->output->thermo->evaluate_keyword("pe", &pe_2); + ASSERT_FILE_EXISTS(dump_file); + ASSERT_EQ(count_lines(dump_file), 123); + HIDE_OUTPUT([&] { + command(fmt::format("rerun {} first 1 last 1 every 1 post no dump x y z", dump_file)); + }); + lmp->output->thermo->evaluate_keyword("pe", &pe_rerun); + ASSERT_DOUBLE_EQ(pe_1, pe_rerun); + HIDE_OUTPUT([&] { + command(fmt::format("rerun {} first 2 last 2 every 1 post yes dump x y z", dump_file)); + }); + lmp->output->thermo->evaluate_keyword("pe", &pe_rerun); + ASSERT_DOUBLE_EQ(pe_2, pe_rerun); + delete_file(dump_file); +} + int main(int argc, char **argv) { MPI_Init(&argc, &argv); diff --git a/unittest/formats/test_potential_file_reader.cpp b/unittest/formats/test_potential_file_reader.cpp index 1e3d96d6d7..f270f6e1f1 100644 --- a/unittest/formats/test_potential_file_reader.cpp +++ b/unittest/formats/test_potential_file_reader.cpp @@ -28,6 +28,7 @@ #include "potential_file_reader.h" #include "gmock/gmock.h" #include "gtest/gtest.h" + #include "../testing/core.h" #include @@ -257,6 +258,67 @@ TEST_F(PotentialFileReaderTest, UnitConvert) delete reader; } +class OpenPotentialTest : public LAMMPSTest { +}; + +// open for native units +TEST_F(OpenPotentialTest, Sw_native) +{ + int convert_flag = utils::get_supported_conversions(utils::ENERGY); + BEGIN_CAPTURE_OUTPUT(); + command("units metal"); + FILE *fp = utils::open_potential("Si.sw", lmp, &convert_flag); + auto text = END_CAPTURE_OUTPUT(); + double conv = utils::get_conversion_factor(utils::ENERGY, convert_flag); + + ASSERT_NE(fp, nullptr); + ASSERT_DOUBLE_EQ(conv, 1.0); + fclose(fp); +} + +// open with supported conversion enabled +TEST_F(OpenPotentialTest, Sw_conv) +{ + int convert_flag = utils::get_supported_conversions(utils::ENERGY); + ASSERT_EQ(convert_flag, utils::METAL2REAL | utils::REAL2METAL); + BEGIN_HIDE_OUTPUT(); + command("units real"); + FILE *fp = utils::open_potential("Si.sw", lmp, &convert_flag); + auto text = END_CAPTURE_OUTPUT(); + double conv = utils::get_conversion_factor(utils::ENERGY, convert_flag); + + ASSERT_NE(fp, nullptr); + ASSERT_EQ(convert_flag, utils::METAL2REAL); + ASSERT_DOUBLE_EQ(conv, 23.060549); + fclose(fp); +} + +// open with conversion disabled +TEST_F(OpenPotentialTest, Sw_noconv) +{ + BEGIN_HIDE_OUTPUT(); + command("units real"); + END_HIDE_OUTPUT(); + TEST_FAILURE(".*potential.*requires metal units but real.*", + utils::open_potential("Si.sw", lmp, nullptr);); + BEGIN_HIDE_OUTPUT(); + command("units lj"); + END_HIDE_OUTPUT(); + int convert_flag = utils::get_supported_conversions(utils::UNKNOWN); + ASSERT_EQ(convert_flag, utils::NOCONVERT); +} + +// open non-existing potential +TEST_F(OpenPotentialTest, No_file) +{ + int convert_flag = utils::get_supported_conversions(utils::ENERGY); + BEGIN_HIDE_OUTPUT(); + command("units metal"); + FILE *fp = utils::open_potential("Unknown.sw", lmp, &convert_flag); + END_HIDE_OUTPUT(); + ASSERT_EQ(fp,nullptr); +} + int main(int argc, char **argv) { MPI_Init(&argc, &argv); diff --git a/unittest/utils/test_tokenizer.cpp b/unittest/utils/test_tokenizer.cpp index 69ec7a55d2..ec097abf62 100644 --- a/unittest/utils/test_tokenizer.cpp +++ b/unittest/utils/test_tokenizer.cpp @@ -43,6 +43,18 @@ TEST(Tokenizer, two_words) ASSERT_EQ(t.count(), 2); } +TEST(Tokenizer, skip) +{ + Tokenizer t("test word", " "); + ASSERT_TRUE(t.has_next()); + t.skip(); + ASSERT_TRUE(t.has_next()); + t.skip(1); + ASSERT_FALSE(t.has_next()); + ASSERT_EQ(t.count(), 2); + ASSERT_THROW(t.skip(), TokenizerException); +} + TEST(Tokenizer, prefix_separators) { Tokenizer t(" test word", " "); @@ -63,6 +75,18 @@ TEST(Tokenizer, iterate_words) ASSERT_EQ(t.count(), 2); } +TEST(Tokenizer, copy_constructor) +{ + Tokenizer t(" test word ", " "); + ASSERT_THAT(t.next(), Eq("test")); + ASSERT_THAT(t.next(), Eq("word")); + ASSERT_EQ(t.count(), 2); + Tokenizer u(t); + ASSERT_THAT(u.next(), Eq("test")); + ASSERT_THAT(u.next(), Eq("word")); + ASSERT_EQ(u.count(), 2); +} + TEST(Tokenizer, no_separator_path) { Tokenizer t("one", ":"); @@ -139,6 +163,26 @@ TEST(ValueTokenizer, empty_string) ASSERT_FALSE(values.has_next()); } +TEST(ValueTokenizer, two_words) +{ + ValueTokenizer t("test word", " "); + ASSERT_THAT(t.next_string(), Eq("test")); + ASSERT_THAT(t.next_string(), Eq("word")); + ASSERT_THROW(t.next_string(), TokenizerException); +} + +TEST(ValueTokenizer, skip) +{ + ValueTokenizer t("test word", " "); + ASSERT_TRUE(t.has_next()); + t.skip(); + ASSERT_TRUE(t.has_next()); + t.skip(1); + ASSERT_FALSE(t.has_next()); + ASSERT_EQ(t.count(), 2); + ASSERT_THROW(t.skip(), TokenizerException); +} + TEST(ValueTokenizer, bad_integer) { ValueTokenizer values("f10"); diff --git a/unittest/utils/test_utils.cpp b/unittest/utils/test_utils.cpp index 81dda11615..0c6e38e342 100644 --- a/unittest/utils/test_utils.cpp +++ b/unittest/utils/test_utils.cpp @@ -331,6 +331,11 @@ TEST(Utils, valid_id7) ASSERT_TRUE(utils::is_id("___")); } +TEST(Utils, empty_id) +{ + ASSERT_FALSE(utils::is_id("")); +} + TEST(Utils, invalid_id1) { ASSERT_FALSE(utils::is_id("+abc")); @@ -780,6 +785,11 @@ TEST(Utils, unit_conversion) ASSERT_DOUBLE_EQ(factor, 1.0 / 23.060549); } +TEST(Utils, timespec2seconds_off) +{ + ASSERT_DOUBLE_EQ(utils::timespec2seconds("off"), -1.0); +} + TEST(Utils, timespec2seconds_ss) { ASSERT_DOUBLE_EQ(utils::timespec2seconds("45"), 45.0); @@ -795,6 +805,11 @@ TEST(Utils, timespec2seconds_hhmmss) ASSERT_DOUBLE_EQ(utils::timespec2seconds("2:10:45"), 7845.0); } +TEST(Utils, timespec2seconds_invalid) +{ + ASSERT_DOUBLE_EQ(utils::timespec2seconds("2:aa:45"), -1.0); +} + TEST(Utils, date2num) { ASSERT_EQ(utils::date2num("1Jan05"), 20050101); @@ -810,3 +825,32 @@ TEST(Utils, date2num) ASSERT_EQ(utils::date2num("30November 02"), 20021130); ASSERT_EQ(utils::date2num("31December100"), 1001231); } + +static int compare(int a, int b, void *) +{ + if (a < b) + return -1; + else if (a > b) + return 1; + else + return 0; +} + +TEST(Utils, merge_sort) +{ + int data[] = {773, 405, 490, 830, 632, 96, 428, 728, 912, 840, 878, 745, 213, 219, 249, 380, + 894, 758, 575, 690, 61, 849, 19, 577, 338, 569, 898, 873, 448, 940, 431, 780, + 472, 289, 65, 491, 641, 37, 367, 33, 407, 854, 594, 611, 845, 136, 107, 592, + 275, 865, 158, 626, 399, 703, 686, 734, 188, 559, 781, 558, 737, 281, 638, 664, + 533, 529, 62, 969, 595, 661, 837, 463, 624, 568, 615, 936, 206, 637, 91, 694, + 214, 872, 468, 66, 775, 949, 486, 576, 255, 961, 480, 138, 177, 509, 333, 705, + 10, 375, 321, 952, 210, 111, 475, 268, 708, 864, 244, 121, 988, 540, 942, 682, + 750, 473, 478, 714, 955, 911, 482, 384, 144, 757, 697, 791, 420, 605, 447, 320}; + + const int num = sizeof(data) / sizeof(int); + utils::merge_sort(data, num, nullptr, &compare); + bool sorted = true; + for (int i = 1; i < num; ++i) + if (data[i - 1] > data[i]) sorted = false; + ASSERT_TRUE(sorted); +}