Merge pull request #3248 from akohlmey/add_set_time

Add time option to the "reset_timestep" command and make the "time" property restartable
This commit is contained in:
Axel Kohlmeyer
2022-05-04 18:43:07 -04:00
committed by GitHub
11 changed files with 107 additions and 66 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

View File

@ -8,9 +8,16 @@ Syntax
.. code-block:: LAMMPS
reset_timestep N
reset_timestep N keyword values ...
* N = timestep number
* zero or more keyword/value pairs may be appended
* keyword = *time*
.. parsed-literal::
*time* value = atime
atime = accumulated simulation time
Examples
""""""""
@ -19,48 +26,56 @@ Examples
reset_timestep 0
reset_timestep 4000000
reset_timestep 1000 time 100.0
Description
"""""""""""
Set the timestep counter to the specified value. This command
normally comes after the timestep has been set by reading a restart
usually comes after the timestep has been set by reading a restart
file via the :doc:`read_restart <read_restart>` command, or a previous
simulation advanced the timestep.
simulation run or minimization advanced the timestep.
The optional *time* keyword allows to also set the accumulated
simulation time. This is usually the number of timesteps times
the size of the timestep, but when using variable size timesteps
with :doc:`fix dt/reset <fix_dt_reset>` it can differ.
The :doc:`read_data <read_data>` and :doc:`create_box <create_box>`
commands set the timestep to 0; the :doc:`read_restart <read_restart>`
command sets the timestep to the value it had when the restart file
was written.
was written. The same applies to the accumulated simulation time.
Restrictions
""""""""""""
none
This command cannot be used when any fixes are defined that keep track
of elapsed time to perform certain kinds of time-dependent operations.
Examples are the :doc:`fix deposit <fix_deposit>` and :doc:`fix dt/reset <fix_dt_reset>` commands. The former adds atoms on
specific timesteps. The latter keeps track of accumulated time.
Examples are the :doc:`fix deposit <fix_deposit>` and :doc:`fix dt/reset
<fix_dt_reset>` commands. The former adds atoms on specific timesteps.
The latter keeps track of accumulated time.
Various fixes use the current timestep to calculate related
quantities. If the timestep is reset, this may produce unexpected
behavior, but LAMMPS allows the fixes to be defined even if the
timestep is reset. For example, commands which thermostat the system,
e.g. :doc:`fix nvt <fix_nh>`, allow you to specify a target temperature
which ramps from Tstart to Tstop which may persist over several runs.
If you change the timestep, you may induce an instantaneous change in
the target temperature.
Various fixes use the current timestep to calculate related quantities.
If the timestep is reset, this may produce unexpected behavior, but
LAMMPS allows the fixes to be defined even if the timestep is reset.
For example, commands which thermostat the system, e.g. :doc:`fix nvt
<fix_nh>`, allow you to specify a target temperature which ramps from
Tstart to Tstop which may persist over several runs. If you change the
timestep, you may induce an instantaneous change in the target
temperature.
Resetting the timestep clears flags for :doc:`computes <compute>` that
may have calculated some quantity from a previous run. This means
these quantity cannot be accessed by a variable in between runs until
a new run is performed. See the :doc:`variable <variable>` command for
more details.
may have calculated some quantity from a previous run. This means these
quantity cannot be accessed by a variable in between runs until a new
run is performed. See the :doc:`variable <variable>` command for more
details.
Related commands
""""""""""""""""
:doc:`rerun <rerun>`
:doc:`rerun <rerun>`, :doc:`timestep <timestep>`,
:doc:`fix dt/reset <fix_dt_reset>`
Default
"""""""

View File

@ -39,8 +39,9 @@ Description
Calculate the third order force constant tensor by finite difference of the selected group,
.. image:: JPG/third_order_force_constant.png
:align: center
.. math::
\Phi^{\alpha\beta\gamma}_{ijk} = \frac{\partial^3 U}{\partial x_{i,\alpha} \partial x_{j,\beta} \partial x_{k, \gamma}}
where Phi is the third order force constant tensor.

View File

@ -17,7 +17,7 @@
#define MAGIC_STRING "LammpS RestartT"
#define ENDIAN 0x0001
#define ENDIANSWAP 0x1000
#define FORMAT_REVISION 2
#define FORMAT_REVISION 3
enum{VERSION,SMALLINT,TAGINT,BIGINT,
UNITS,NTIMESTEP,DIMENSION,NPROCS,PROCGRID,
@ -37,7 +37,8 @@ enum{VERSION,SMALLINT,TAGINT,BIGINT,
COMM_MODE,COMM_CUTOFF,COMM_VEL,NO_PAIR,
EXTRA_BOND_PER_ATOM,EXTRA_ANGLE_PER_ATOM,EXTRA_DIHEDRAL_PER_ATOM,
EXTRA_IMPROPER_PER_ATOM,EXTRA_SPECIAL_PER_ATOM,ATOM_MAXSPECIAL,
NELLIPSOIDS,NLINES,NTRIS,NBODIES};
NELLIPSOIDS,NLINES,NTRIS,NBODIES,
ATIME,ATIMESTEP};
#define LB_FACTOR 1.1

View File

@ -744,11 +744,11 @@ void Output::add_dump(int narg, char **arg)
for (int idump = 0; idump < ndump; idump++)
if (strcmp(arg[0],dump[idump]->id) == 0)
error->all(FLERR,"Reuse of dump ID");
error->all(FLERR,"Reuse of dump ID: {}", arg[0]);
int igroup = group->find(arg[1]);
if (igroup == -1) error->all(FLERR,"Could not find dump group ID");
if (igroup == -1) error->all(FLERR,"Could not find dump group ID: {}", arg[1]);
if (utils::inumeric(FLERR,arg[3],false,lmp) <= 0)
error->all(FLERR,"Invalid dump frequency");
error->all(FLERR,"Invalid dump frequency {}", arg[3]);
// extend Dump list if necessary
@ -794,14 +794,14 @@ void Output::add_dump(int narg, char **arg)
void Output::modify_dump(int narg, char **arg)
{
if (narg < 1) error->all(FLERR,"Illegal dump_modify command");
if (narg < 1) utils::missing_cmd_args(FLERR, "dump_modify",error);
// find which dump it is
int idump;
for (idump = 0; idump < ndump; idump++)
if (strcmp(arg[0],dump[idump]->id) == 0) break;
if (idump == ndump) error->all(FLERR,"Cound not find dump_modify ID");
if (idump == ndump) error->all(FLERR,"Could not find dump_modify ID: {}", arg[0]);
dump[idump]->modify_params(narg-1,&arg[1]);
}
@ -817,7 +817,7 @@ void Output::delete_dump(char *id)
int idump;
for (idump = 0; idump < ndump; idump++)
if (strcmp(id,dump[idump]->id) == 0) break;
if (idump == ndump) error->all(FLERR,"Could not find undump ID");
if (idump == ndump) error->all(FLERR,"Could not find undump ID: {}", id);
delete dump[idump];
delete[] var_dump[idump];
@ -871,7 +871,7 @@ void Output::set_thermo(int narg, char **arg)
var_thermo = utils::strdup(arg[0]+2);
} else {
thermo_every = utils::inumeric(FLERR,arg[0],false,lmp);
if (thermo_every < 0) error->all(FLERR,"Illegal thermo command");
if (thermo_every < 0) error->all(FLERR,"Illegal thermo output frequency {}", thermo_every);
}
}
@ -881,7 +881,7 @@ void Output::set_thermo(int narg, char **arg)
void Output::create_thermo(int narg, char **arg)
{
if (narg < 1) error->all(FLERR,"Illegal thermo_style command");
if (narg < 1) utils::missing_cmd_args(FLERR, "thermo_style", error);
// don't allow this so that dipole style can safely allocate inertia vector
@ -891,8 +891,7 @@ void Output::create_thermo(int narg, char **arg)
// warn if previous thermo had been modified via thermo_modify command
if (thermo->modified && comm->me == 0)
error->warning(FLERR,"New thermo_style command, "
"previous thermo_modify settings will be lost");
error->warning(FLERR,"New thermo_style command, previous thermo_modify settings will be lost");
// set thermo = nullptr in case new Thermo throws an error
@ -908,7 +907,7 @@ void Output::create_thermo(int narg, char **arg)
void Output::create_restart(int narg, char **arg)
{
if (narg < 1) error->all(FLERR,"Illegal restart command");
if (narg < 1) utils::missing_cmd_args(FLERR, "restart", error);
int every = 0;
int varflag = 0;

View File

@ -284,7 +284,7 @@ void Pair::init()
if (!manybody_flag && (comm->me == 0)) {
const int num_mixed_pairs = atom->ntypes * (atom->ntypes - 1) / 2;
utils::logmesg(lmp," generated {} of {} mixed pair_coeff terms from {} mixing rule\n",
utils::logmesg(lmp,"Generated {} of {} mixed pair_coeff terms from {} mixing rule\n",
mixed_count, num_mixed_pairs, mixing_rule_names[mix_flag]);
}
}

View File

@ -594,21 +594,18 @@ void ReadRestart::header()
if (flag == VERSION) {
char *version = read_string();
if (me == 0)
utils::logmesg(lmp," restart file = {}, LAMMPS = {}\n",
version,lmp->version);
utils::logmesg(lmp," restart file = {}, LAMMPS = {}\n", version, lmp->version);
delete[] version;
// we have no forward compatibility, thus exit with error
if (revision > FORMAT_REVISION)
error->all(FLERR,"Restart file format revision incompatible "
"with current LAMMPS version");
error->all(FLERR,"Restart file format revision incompatible with current LAMMPS version");
// warn when attempting to read older format revision
if ((me == 0) && (revision < FORMAT_REVISION))
error->warning(FLERR,"Old restart file format revision. "
"Switching to compatibility mode.");
error->warning(FLERR,"Old restart file format revision. Switching to compatibility mode.");
// check lmptype.h sizes, error if different
@ -654,8 +651,8 @@ void ReadRestart::header()
} else if (flag == NPROCS) {
nprocs_file = read_int();
if (nprocs_file != comm->nprocs && me == 0)
error->warning(FLERR,"Restart file used different # of processors: "
"{} vs. {}",nprocs_file,comm->nprocs);
error->warning(FLERR,"Restart file used different # of processors: {} vs. {}",
nprocs_file,comm->nprocs);
// don't set procgrid, warn if different
@ -681,16 +678,14 @@ void ReadRestart::header()
int newton_pair_file = read_int();
if (force->newton_pair != 1) {
if (newton_pair_file != force->newton_pair && me == 0)
error->warning(FLERR,
"Restart file used different newton pair setting, "
error->warning(FLERR, "Restart file used different newton pair setting, "
"using input script value");
}
} else if (flag == NEWTON_BOND) {
int newton_bond_file = read_int();
if (force->newton_bond != 1) {
if (newton_bond_file != force->newton_bond && me == 0)
error->warning(FLERR,
"Restart file used different newton bond setting, "
error->warning(FLERR, "Restart file used different newton bond setting, "
"using restart file value");
}
force->newton_bond = newton_bond_file;
@ -721,8 +716,7 @@ void ReadRestart::header()
boundary[2][0] != domain->boundary[2][0] ||
boundary[2][1] != domain->boundary[2][1]) {
if (me == 0)
error->warning(FLERR,
"Restart file used different boundary settings, "
error->warning(FLERR, "Restart file used different boundary settings, "
"using restart file values");
}
}
@ -864,6 +858,13 @@ void ReadRestart::header()
} else if (flag == NBODIES) {
atom->nbodies = read_bigint();
} else if (flag == ATIMESTEP) {
update->atimestep = read_bigint();
} else if (flag == ATIME) {
update->atime = read_double();
// set dimension from restart file
// for backward compatibility
} else if (flag == EXTRA_SPECIAL_PER_ATOM) {
force->special_extra = read_int();

View File

@ -457,9 +457,18 @@ void Update::new_minimize(char *style, int /* narg */, char ** /* arg */, int tr
void Update::reset_timestep(int narg, char **arg)
{
if (narg != 1) error->all(FLERR, "Illegal reset_timestep command");
bigint newstep = utils::bnumeric(FLERR, arg[0], false, lmp);
reset_timestep(newstep, true);
if (narg < 1) utils::missing_cmd_args(FLERR, "reset_timestep", error);
reset_timestep(utils::bnumeric(FLERR, arg[0], false, lmp), true);
if (narg > 1) {
if (strcmp(arg[1], "time") == 0) {
if (narg < 3) utils::missing_cmd_args(FLERR, "reset_timestep time", error);
atimestep = ntimestep;
atime = utils::numeric(FLERR, arg[2], false, lmp);
} else
error->all(FLERR, "Unknown reset_timestep option {}", arg[1]);
}
}
/* ----------------------------------------------------------------------

View File

@ -27,7 +27,7 @@ class Update : protected Pointers {
bigint ntimestep; // current step (dynamics or min iterations)
int nsteps; // # of steps to run (dynamics or min iter)
int whichflag; // 0 for unset, 1 for dynamics, 2 for min
double atime; // simulation time at atime_step
double atime; // simulation time at atimestep
bigint atimestep; // last timestep atime was updated
bigint firststep, laststep; // 1st & last step of this run
bigint beginstep, endstep; // 1st and last step of multiple runs

View File

@ -118,8 +118,7 @@ void WriteRestart::command(int narg, char **arg)
/* ---------------------------------------------------------------------- */
void WriteRestart::multiproc_options(int multiproc_caller, int mpiioflag_caller,
int narg, char **arg)
void WriteRestart::multiproc_options(int multiproc_caller, int mpiioflag_caller, int narg, char **arg)
{
multiproc = multiproc_caller;
mpiioflag = mpiioflag_caller;
@ -127,14 +126,12 @@ void WriteRestart::multiproc_options(int multiproc_caller, int mpiioflag_caller,
// error checks
if (multiproc && mpiioflag)
error->all(FLERR,
"Restart file MPI-IO output not allowed with % in filename");
error->all(FLERR,"Restart file MPI-IO output not allowed with % in filename");
if (mpiioflag) {
mpiio = new RestartMPIIO(lmp);
if (!mpiio->mpiio_exists)
error->all(FLERR,"Writing to MPI-IO filename when "
"MPIIO package is not installed");
error->all(FLERR,"Writing to MPI-IO filename when MPIIO package is not installed");
}
// defaults for multiproc file writing
@ -158,8 +155,7 @@ void WriteRestart::multiproc_options(int multiproc_caller, int mpiioflag_caller,
if (strcmp(arg[iarg],"fileper") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal write_restart command");
if (!multiproc)
error->all(FLERR,"Cannot use write_restart fileper "
"without % in restart file name");
error->all(FLERR,"Cannot use write_restart fileper without % in restart file name");
int nper = utils::inumeric(FLERR,arg[iarg+1],false,lmp);
if (nper <= 0) error->all(FLERR,"Illegal write_restart command");
@ -176,8 +172,7 @@ void WriteRestart::multiproc_options(int multiproc_caller, int mpiioflag_caller,
} else if (strcmp(arg[iarg],"nfile") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal write_restart command");
if (!multiproc)
error->all(FLERR,"Cannot use write_restart nfile "
"without % in restart file name");
error->all(FLERR,"Cannot use write_restart nfile without % in restart file name");
int nfile = utils::inumeric(FLERR,arg[iarg+1],false,lmp);
if (nfile <= 0) error->all(FLERR,"Illegal write_restart command");
nfile = MIN(nfile,nprocs);
@ -510,6 +505,11 @@ void WriteRestart::header()
write_bigint(NTRIS,atom->ntris);
write_bigint(NBODIES,atom->nbodies);
// write out current simulation time. added 3 May 2022
write_bigint(ATIMESTEP,update->atimestep);
write_double(ATIME,update->atime);
// -1 flag signals end of header
int flag = -1;

View File

@ -224,20 +224,35 @@ TEST_F(SimpleCommandsTest, Quit)
TEST_F(SimpleCommandsTest, ResetTimestep)
{
ASSERT_EQ(lmp->update->ntimestep, 0);
ASSERT_EQ(lmp->update->atimestep, 0);
ASSERT_DOUBLE_EQ(lmp->update->atime, 0.0);
BEGIN_HIDE_OUTPUT();
command("reset_timestep 10");
END_HIDE_OUTPUT();
ASSERT_EQ(lmp->update->ntimestep, 10);
ASSERT_EQ(lmp->update->atimestep, 10);
ASSERT_DOUBLE_EQ(lmp->update->atime, lmp->update->dt * 10);
BEGIN_HIDE_OUTPUT();
command("reset_timestep 0");
END_HIDE_OUTPUT();
ASSERT_EQ(lmp->update->ntimestep, 0);
ASSERT_EQ(lmp->update->atimestep, 0);
ASSERT_DOUBLE_EQ(lmp->update->atime, 0.0);
BEGIN_HIDE_OUTPUT();
command("reset_timestep 10 time 100.0");
END_HIDE_OUTPUT();
ASSERT_EQ(lmp->update->ntimestep, 10);
ASSERT_EQ(lmp->update->atimestep, 10);
ASSERT_DOUBLE_EQ(lmp->update->atime, 100.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: Unknown reset_timestep option 10.*", command("reset_timestep 10 10"););
TEST_FAILURE(".*ERROR: Illegal reset_timestep .*", command("reset_timestep 10 time"););
TEST_FAILURE(".*ERROR: Expected floating .**", command("reset_timestep 10 time xxx"););
TEST_FAILURE(".*ERROR: Expected integer .*", command("reset_timestep xxx"););
}
@ -325,7 +340,7 @@ TEST_F(SimpleCommandsTest, Thermo)
ASSERT_EQ(lmp->output->var_thermo, nullptr);
TEST_FAILURE(".*ERROR: Illegal thermo command.*", command("thermo"););
TEST_FAILURE(".*ERROR: Illegal thermo command.*", command("thermo -1"););
TEST_FAILURE(".*ERROR: Illegal thermo output frequency.*", command("thermo -1"););
TEST_FAILURE(".*ERROR: Expected integer.*", command("thermo xxx"););
}