Merge pull request #3440 from lammps/dump-step-post-minimize

Enforce dump snapshots on multiples of N steps in a run after minimize
This commit is contained in:
Axel Kohlmeyer
2022-09-09 16:30:35 -04:00
committed by GitHub
3 changed files with 426 additions and 366 deletions

View File

@ -12,7 +12,7 @@ Syntax
restart N root keyword value ... restart N root keyword value ...
restart N file1 file2 keyword value ... restart N file1 file2 keyword value ...
* N = write a restart file every this many timesteps * N = write a restart file on timesteps which are multipls of N
* N can be a variable (see below) * N can be a variable (see below)
* root = filename to which timestep # is appended * root = filename to which timestep # is appended
* file1,file2 = two full filenames, toggle between them when writing file * file1,file2 = two full filenames, toggle between them when writing file
@ -42,13 +42,14 @@ Description
""""""""""" """""""""""
Write out a binary restart file with the current state of the Write out a binary restart file with the current state of the
simulation every so many timesteps, in either or both of two modes, as simulation on timesteps which are a multiple of N. A value of N = 0
a run proceeds. A value of 0 means do not write out any restart means do not write out any restart files, which is the default.
files. The two modes are as follows. If one filename is specified, a Restart files are written in one (or both) of two modes as a run
series of filenames will be created which include the timestep in the proceeds. If one filename is specified, a series of filenames will be
filename. If two filenames are specified, only 2 restart files will created which include the timestep in the filename. If two filenames
be created, with those names. LAMMPS will toggle between the 2 names are specified, only 2 restart files will be created, with those names.
as it writes successive restart files. LAMMPS will toggle between the 2 names as it writes successive restart
files.
Note that you can specify the restart command twice, once with a Note that you can specify the restart command twice, once with a
single filename and once with two filenames. This would allow you, single filename and once with two filenames. This would allow you,

View File

@ -237,12 +237,10 @@ void Output::setup(int memflag)
last_dump[idump] = ntimestep; last_dump[idump] = ntimestep;
} }
// calculate timestep and/or time for next dump // calculate timestep or time for next dump
// set next_dump and next_time_dump, 0 arg for setup() // set next_dump and next_time_dump
// only do this if dump written or dump has not been written yet
if (writeflag || last_dump[idump] < 0) calculate_next_dump(SETUP,idump,ntimestep);
calculate_next_dump(SETUP,idump,ntimestep);
// if dump not written now, use addstep_compute_all() // if dump not written now, use addstep_compute_all()
// since don't know what computes the dump will invoke // since don't know what computes the dump will invoke
@ -261,322 +259,324 @@ void Output::setup(int memflag)
} else next_dump_any = update->laststep + 1; } else next_dump_any = update->laststep + 1;
// do not write restart files at start of run // do not write restart files at start of run
// set next_restart values to multiple of every or variable value // set next_restart values to multiple of every or variable value
// wrap variable eval with clear/add // wrap variable eval with clear/add
// if no restarts, set next_restart to last+1 so will not influence next // if no restarts, set next_restart to last+1 so will not influence next
if (restart_flag && update->restrict_output == 0) { if (restart_flag && update->restrict_output == 0) {
if (restart_flag_single) { if (restart_flag_single) {
if (restart_every_single) if (restart_every_single) {
next_restart_single = next_restart_single =
(ntimestep/restart_every_single)*restart_every_single + (ntimestep/restart_every_single)*restart_every_single +
restart_every_single; restart_every_single;
else { } else {
auto nextrestart = static_cast<bigint> auto nextrestart = static_cast<bigint>
(input->variable->compute_equal(ivar_restart_single)); (input->variable->compute_equal(ivar_restart_single));
if (nextrestart <= ntimestep) if (nextrestart <= ntimestep)
error->all(FLERR,"Restart variable returned a bad timestep"); error->all(FLERR,"Restart variable returned a bad timestep");
next_restart_single = nextrestart; next_restart_single = nextrestart;
} }
} else next_restart_single = update->laststep + 1; } else next_restart_single = update->laststep + 1;
if (restart_flag_double) { if (restart_flag_double) {
if (restart_every_double) if (restart_every_double)
next_restart_double = next_restart_double =
(ntimestep/restart_every_double)*restart_every_double + (ntimestep/restart_every_double)*restart_every_double +
restart_every_double; restart_every_double;
else { else {
auto nextrestart = static_cast<bigint> auto nextrestart = static_cast<bigint>
(input->variable->compute_equal(ivar_restart_double)); (input->variable->compute_equal(ivar_restart_double));
if (nextrestart <= ntimestep) if (nextrestart <= ntimestep)
error->all(FLERR,"Restart variable returned a bad timestep"); error->all(FLERR,"Restart variable returned a bad timestep");
next_restart_double = nextrestart; next_restart_double = nextrestart;
} }
} else next_restart_double = update->laststep + 1; } else next_restart_double = update->laststep + 1;
next_restart = MIN(next_restart_single,next_restart_double); next_restart = MIN(next_restart_single,next_restart_double);
} else next_restart = update->laststep + 1; } else next_restart = update->laststep + 1;
// print memory usage unless being called between multiple runs // print memory usage unless being called between multiple runs
if (memflag) memory_usage(); if (memflag) memory_usage();
// set next_thermo to multiple of every or variable eval if var defined // set next_thermo to multiple of every or variable eval if var defined
// insure thermo output on last step of run // insure thermo output on last step of run
// thermo may invoke computes so wrap with clear/add // thermo may invoke computes so wrap with clear/add
modify->clearstep_compute(); modify->clearstep_compute();
thermo->header(); thermo->header();
thermo->compute(0); thermo->compute(0);
last_thermo = ntimestep; last_thermo = ntimestep;
if (var_thermo) { if (var_thermo) {
next_thermo = static_cast<bigint> next_thermo = static_cast<bigint>
(input->variable->compute_equal(ivar_thermo)); (input->variable->compute_equal(ivar_thermo));
if (next_thermo <= ntimestep) if (next_thermo <= ntimestep)
error->all(FLERR,"Thermo every variable returned a bad timestep"); error->all(FLERR,"Thermo every variable returned a bad timestep");
} else if (thermo_every) { } else if (thermo_every) {
next_thermo = (ntimestep/thermo_every)*thermo_every + thermo_every; next_thermo = (ntimestep/thermo_every)*thermo_every + thermo_every;
next_thermo = MIN(next_thermo,update->laststep); next_thermo = MIN(next_thermo,update->laststep);
} else next_thermo = update->laststep; } else next_thermo = update->laststep;
modify->addstep_compute(next_thermo); modify->addstep_compute(next_thermo);
// next = next timestep any output will be done // next = next timestep any output will be done
next = MIN(next_dump_any,next_restart); next = MIN(next_dump_any,next_restart);
next = MIN(next,next_thermo); next = MIN(next,next_thermo);
} }
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------
perform all output for this timestep perform all output for this timestep
only perform output if next matches current step and last output doesn't only perform output if next matches current step and last output doesn't
do dump/restart before thermo so thermo CPU time will include them do dump/restart before thermo so thermo CPU time will include them
------------------------------------------------------------------------- */ ------------------------------------------------------------------------- */
void Output::write(bigint ntimestep) void Output::write(bigint ntimestep)
{ {
// perform dump if its next_dump = current ntimestep // perform dump if its next_dump = current ntimestep
// but not if it was already written on this step // but not if it was already written on this step
// set next_dump and also next_time_dump for mode_dump = 1 // set next_dump and also next_time_dump for mode_dump = 1
// set next_dump_any to smallest next_dump // set next_dump_any to smallest next_dump
// wrap step dumps that invoke computes or do variable eval with clear/add // wrap step dumps that invoke computes or do variable eval with clear/add
// NOTE: // NOTE:
// not wrapping time dumps means that Integrate::ev_set() // not wrapping time dumps means that Integrate::ev_set()
// needs to trigger all per-atom eng/virial computes // needs to trigger all per-atom eng/virial computes
// on a timestep where any time dump will be output // on a timestep where any time dump will be output
// could wrap time dumps as well, if timestep size did not vary // could wrap time dumps as well, if timestep size did not vary
// if wrap when timestep size varies frequently, // if wrap when timestep size varies frequently,
// then can do many unneeded addstep() --> inefficient // then can do many unneeded addstep() --> inefficient
// hard to know if timestep varies, since run every could change it // hard to know if timestep varies, since run every could change it
// can't remove an uneeded addstep from a compute, b/c don't know // can't remove an uneeded addstep from a compute, b/c don't know
// what other command may have added it // what other command may have added it
if (next_dump_any == ntimestep) { if (next_dump_any == ntimestep) {
next_dump_any = next_time_dump_any = MAXBIGINT; next_dump_any = next_time_dump_any = MAXBIGINT;
for (int idump = 0; idump < ndump; idump++) { for (int idump = 0; idump < ndump; idump++) {
if (next_dump[idump] == ntimestep) { if (next_dump[idump] == ntimestep) {
if (last_dump[idump] == ntimestep) continue; if (last_dump[idump] == ntimestep) continue;
if (mode_dump[idump] == 0 && if (mode_dump[idump] == 0 &&
(dump[idump]->clearstep || var_dump[idump])) (dump[idump]->clearstep || var_dump[idump]))
modify->clearstep_compute(); modify->clearstep_compute();
// perform dump // perform dump
// reset next_dump and next_time_dump, 1 arg for write() // set next_dump and next_time_dump
dump[idump]->write(); dump[idump]->write();
last_dump[idump] = ntimestep; last_dump[idump] = ntimestep;
calculate_next_dump(WRITE,idump,ntimestep); calculate_next_dump(WRITE,idump,ntimestep);
if (mode_dump[idump] == 0 && if (mode_dump[idump] == 0 &&
(dump[idump]->clearstep || var_dump[idump])) (dump[idump]->clearstep || var_dump[idump]))
modify->addstep_compute(next_dump[idump]); modify->addstep_compute(next_dump[idump]);
} }
if (mode_dump[idump] && (dump[idump]->clearstep || var_dump[idump])) if (mode_dump[idump] && (dump[idump]->clearstep || var_dump[idump]))
next_time_dump_any = MIN(next_time_dump_any,next_dump[idump]); next_time_dump_any = MIN(next_time_dump_any,next_dump[idump]);
next_dump_any = MIN(next_dump_any,next_dump[idump]); next_dump_any = MIN(next_dump_any,next_dump[idump]);
} }
} }
// next_restart does not force output on last step of run // next_restart does not force output on last step of run
// for toggle = 0, replace "*" with current timestep in restart filename // for toggle = 0, replace "*" with current timestep in restart filename
// next restart variable may invoke computes so wrap with clear/add // next restart variable may invoke computes so wrap with clear/add
if (next_restart == ntimestep) { if (next_restart == ntimestep) {
if (next_restart_single == ntimestep) { if (next_restart_single == ntimestep) {
std::string file = restart1;
std::size_t found = file.find('*');
if (found != std::string::npos)
file.replace(found,1,fmt::format("{}",update->ntimestep));
std::string file = restart1; if (last_restart != ntimestep) restart->write(file);
std::size_t found = file.find('*');
if (found != std::string::npos)
file.replace(found,1,fmt::format("{}",update->ntimestep));
if (last_restart != ntimestep) restart->write(file); if (restart_every_single) next_restart_single += restart_every_single;
else {
modify->clearstep_compute();
auto nextrestart = static_cast<bigint>
(input->variable->compute_equal(ivar_restart_single));
if (nextrestart <= ntimestep)
error->all(FLERR,"Restart variable returned a bad timestep");
next_restart_single = nextrestart;
modify->addstep_compute(next_restart_single);
}
}
if (restart_every_single) next_restart_single += restart_every_single; if (next_restart_double == ntimestep) {
else { if (last_restart != ntimestep) {
modify->clearstep_compute(); if (restart_toggle == 0) {
auto nextrestart = static_cast<bigint> restart->write(restart2a);
(input->variable->compute_equal(ivar_restart_single)); restart_toggle = 1;
if (nextrestart <= ntimestep) } else {
error->all(FLERR,"Restart variable returned a bad timestep"); restart->write(restart2b);
next_restart_single = nextrestart; restart_toggle = 0;
modify->addstep_compute(next_restart_single); }
} }
}
if (next_restart_double == ntimestep) {
if (last_restart != ntimestep) {
if (restart_toggle == 0) {
restart->write(restart2a);
restart_toggle = 1;
} else {
restart->write(restart2b);
restart_toggle = 0;
}
}
if (restart_every_double) next_restart_double += restart_every_double;
else {
modify->clearstep_compute();
auto nextrestart = static_cast<bigint>
(input->variable->compute_equal(ivar_restart_double));
if (nextrestart <= ntimestep)
error->all(FLERR,"Restart variable returned a bad timestep");
next_restart_double = nextrestart;
modify->addstep_compute(next_restart_double);
}
}
last_restart = ntimestep;
next_restart = MIN(next_restart_single,next_restart_double);
}
// insure next_thermo forces output on last step of run if (restart_every_double) next_restart_double += restart_every_double;
// thermo may invoke computes so wrap with clear/add else {
modify->clearstep_compute();
auto nextrestart = static_cast<bigint>
(input->variable->compute_equal(ivar_restart_double));
if (nextrestart <= ntimestep)
error->all(FLERR,"Restart variable returned a bad timestep");
next_restart_double = nextrestart;
modify->addstep_compute(next_restart_double);
}
}
last_restart = ntimestep;
next_restart = MIN(next_restart_single,next_restart_double);
}
if (next_thermo == ntimestep) { // insure next_thermo forces output on last step of run
modify->clearstep_compute(); // thermo may invoke computes so wrap with clear/add
if (last_thermo != ntimestep) thermo->compute(1);
last_thermo = ntimestep;
if (var_thermo) {
next_thermo = static_cast<bigint>
(input->variable->compute_equal(ivar_thermo));
if (next_thermo <= ntimestep)
error->all(FLERR,"Thermo every variable returned a bad timestep");
} else if (thermo_every) next_thermo += thermo_every;
else next_thermo = update->laststep;
next_thermo = MIN(next_thermo,update->laststep);
modify->addstep_compute(next_thermo);
}
// next = next timestep any output will be done if (next_thermo == ntimestep) {
modify->clearstep_compute();
if (last_thermo != ntimestep) thermo->compute(1);
last_thermo = ntimestep;
if (var_thermo) {
next_thermo = static_cast<bigint>
(input->variable->compute_equal(ivar_thermo));
if (next_thermo <= ntimestep)
error->all(FLERR,"Thermo every variable returned a bad timestep");
} else if (thermo_every) next_thermo += thermo_every;
else next_thermo = update->laststep;
next_thermo = MIN(next_thermo,update->laststep);
modify->addstep_compute(next_thermo);
}
next = MIN(next_dump_any,next_restart); // next = next timestep any output will be done
next = MIN(next,next_thermo);
}
/* ---------------------------------------------------------------------- next = MIN(next_dump_any,next_restart);
force a snapshot to be written for all dumps next = MIN(next,next_thermo);
called from PRD and TAD }
------------------------------------------------------------------------- */
void Output::write_dump(bigint ntimestep) /* ----------------------------------------------------------------------
{ force a snapshot to be written for all dumps
for (int idump = 0; idump < ndump; idump++) { called from PRD and TAD
dump[idump]->write(); ------------------------------------------------------------------------- */
last_dump[idump] = ntimestep;
}
}
/* ---------------------------------------------------------------------- void Output::write_dump(bigint ntimestep)
calculate when next dump occurs for Dump instance idump {
operates in one of two modes, based on mode_dump flag for (int idump = 0; idump < ndump; idump++) {
for timestep mode, set next_dump dump[idump]->write();
for simulation time mode, set next_time_dump and next_dump last_dump[idump] = ntimestep;
which flag depends on caller }
SETUP = from setup() at start of run }
WRITE = from write() during run each time a dump file is written
RESET_DT = from reset_dt() called from fix dt/reset when it changes timestep size /* ----------------------------------------------------------------------
------------------------------------------------------------------------- */ calculate when next dump occurs for Dump instance idump
operates in one of two modes, based on mode_dump flag
for timestep mode, set next_dump
for simulation time mode, set next_time_dump and next_dump
which flag depends on caller
SETUP = from setup() at start of run
WRITE = from write() during run each time a dump file is written
RESET_DT = from reset_dt() called from fix dt/reset when it changes timestep size
------------------------------------------------------------------------- */
void Output::calculate_next_dump(int which, int idump, bigint ntimestep) void Output::calculate_next_dump(int which, int idump, bigint ntimestep)
{ {
// dump mode is by timestep // dump mode is by timestep
// just set next_dump // just set next_dump
if (mode_dump[idump] == 0) { if (mode_dump[idump] == 0) {
if (every_dump[idump]) { if (every_dump[idump]) {
// which = SETUP: nextdump = next multiple of every_dump // which = SETUP: next_dump = next multiple of every_dump
// which = WRITE: increment nextdump by every_dump // which = WRITE: increment next_dump by every_dump
// current step is already multiple of every_dump
if (which == SETUP) if (which == SETUP)
next_dump[idump] = (ntimestep/every_dump[idump])*every_dump[idump] + every_dump[idump]; next_dump[idump] = (ntimestep/every_dump[idump])*every_dump[idump] + every_dump[idump];
else if (which == WRITE) else if (which == WRITE)
next_dump[idump] += every_dump[idump]; next_dump[idump] += every_dump[idump];
} else { } else {
next_dump[idump] = static_cast<bigint> next_dump[idump] = static_cast<bigint>
(input->variable->compute_equal(ivar_dump[idump])); (input->variable->compute_equal(ivar_dump[idump]));
if (next_dump[idump] <= ntimestep) if (next_dump[idump] <= ntimestep)
error->all(FLERR,"Dump every variable returned a bad timestep"); error->all(FLERR,"Dump every variable returned a bad timestep");
} }
// dump mode is by simulation time // dump mode is by simulation time
// set next_time_dump and next_dump // set next_time_dump and next_dump
} else { } else {
bigint nextdump; bigint nextdump;
double nexttime; double nexttime;
double tcurrent = update->atime + double tcurrent = update->atime +
(ntimestep - update->atimestep) * update->dt; (ntimestep - update->atimestep) * update->dt;
if (every_time_dump[idump] > 0.0) { if (every_time_dump[idump] > 0.0) {
// which = SETUP: nexttime = next multiple of every_time_dump // which = SETUP: nexttime = next multiple of every_time_dump
// which = WRITE: increment nexttime by every_time_dump // which = WRITE: increment nexttime by every_time_dump
// which = RESET_DT: no change to previous nexttime (only timestep has changed) // which = RESET_DT: no change to previous nexttime (only timestep has changed)
switch (which) { switch (which) {
case SETUP: case SETUP:
nexttime = static_cast<bigint> (tcurrent/every_time_dump[idump]) * nexttime = static_cast<bigint> (tcurrent/every_time_dump[idump]) *
every_time_dump[idump] + every_time_dump[idump]; every_time_dump[idump] + every_time_dump[idump];
break; break;
case WRITE: case WRITE:
nexttime = next_time_dump[idump] + every_time_dump[idump]; nexttime = next_time_dump[idump] + every_time_dump[idump];
break; break;
case RESET_DT: case RESET_DT:
nexttime = next_time_dump[idump]; nexttime = next_time_dump[idump];
break; break;
default: default:
nexttime = 0; nexttime = 0;
error->all(FLERR,"Unexpected argument to calculate_next_dump"); error->all(FLERR,"Unexpected argument to calculate_next_dump");
} }
nextdump = ntimestep + nextdump = ntimestep +
static_cast<bigint> ((nexttime - tcurrent - EPSDT*update->dt) / update->dt) + 1; static_cast<bigint> ((nexttime - tcurrent - EPSDT*update->dt) / update->dt) + 1;
// if delta is too small to reach next timestep, use multiple of delta // if delta is too small to reach next timestep, use multiple of delta
if (nextdump == ntimestep) { if (nextdump == ntimestep) {
double tnext = update->atime + double tnext = update->atime +
(ntimestep+1 - update->atimestep) * update->dt; (ntimestep+1 - update->atimestep) * update->dt;
int multiple = static_cast<int> int multiple = static_cast<int>
((tnext - nexttime) / every_time_dump[idump]); ((tnext - nexttime) / every_time_dump[idump]);
nexttime = nexttime + (multiple+1)*every_time_dump[idump]; nexttime = nexttime + (multiple+1)*every_time_dump[idump];
nextdump = ntimestep + nextdump = ntimestep +
static_cast<bigint> ((nexttime - tcurrent - EPSDT*update->dt) / update->dt) + 1; static_cast<bigint> ((nexttime - tcurrent - EPSDT*update->dt) / update->dt) + 1;
} }
} else { } else {
// do not re-evaulate variable for which = RESET_DT, leave nexttime as-is // do not re-evaulate variable for which = RESET_DT, leave nexttime as-is
// unless next_time_dump < 0.0, which means variable never yet evaluated // unless next_time_dump < 0.0, which means variable never yet evaluated
if (which < RESET_DT || next_time_dump[idump] < 0.0) { if (which < RESET_DT || next_time_dump[idump] < 0.0) {
nexttime = input->variable->compute_equal(ivar_dump[idump]); nexttime = input->variable->compute_equal(ivar_dump[idump]);
} else } else
nexttime = next_time_dump[idump]; nexttime = next_time_dump[idump];
if (nexttime <= tcurrent) if (nexttime <= tcurrent)
error->all(FLERR,"Dump every/time variable returned a bad time"); error->all(FLERR,"Dump every/time variable returned a bad time");
nextdump = ntimestep + nextdump = ntimestep +
static_cast<bigint> ((nexttime - tcurrent - EPSDT*update->dt) / update->dt) + 1; static_cast<bigint> ((nexttime - tcurrent - EPSDT*update->dt) / update->dt) + 1;
if (nextdump <= ntimestep) if (nextdump <= ntimestep)
error->all(FLERR,"Dump every/time variable too small for next timestep"); error->all(FLERR,"Dump every/time variable too small for next timestep");
} }
next_time_dump[idump] = nexttime; next_time_dump[idump] = nexttime;
next_dump[idump] = nextdump; next_dump[idump] = nextdump;
} }
} }
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
@ -589,112 +589,112 @@ int Output::check_time_dumps(bigint ntimestep)
return nowflag; return nowflag;
} }
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------
force restart file(s) to be written force restart file(s) to be written
called from PRD and TAD called from PRD and TAD
------------------------------------------------------------------------- */ ------------------------------------------------------------------------- */
void Output::write_restart(bigint ntimestep) void Output::write_restart(bigint ntimestep)
{ {
if (restart_flag_single) { if (restart_flag_single) {
std::string file = restart1; std::string file = restart1;
std::size_t found = file.find('*'); std::size_t found = file.find('*');
if (found != std::string::npos) if (found != std::string::npos)
file.replace(found,1,fmt::format("{}",update->ntimestep)); file.replace(found,1,fmt::format("{}",update->ntimestep));
restart->write(file); restart->write(file);
} }
if (restart_flag_double) { if (restart_flag_double) {
if (restart_toggle == 0) { if (restart_toggle == 0) {
restart->write(restart2a); restart->write(restart2a);
restart_toggle = 1; restart_toggle = 1;
} else { } else {
restart->write(restart2b); restart->write(restart2b);
restart_toggle = 0; restart_toggle = 0;
} }
} }
last_restart = ntimestep; last_restart = ntimestep;
} }
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------
timestep is being changed, called by update->reset_timestep() timestep is being changed, called by update->reset_timestep()
for dumps, require that no dump is "active" for dumps, require that no dump is "active"
meaning that a snapshot has already been output meaning that a snapshot has already been output
reset next output values for restart and thermo reset next output values for restart and thermo
reset to smallest value >= new timestep reset to smallest value >= new timestep
if next timestep set by variable evaluation, if next timestep set by variable evaluation,
eval for ntimestep-1, so current ntimestep can be returned if needed eval for ntimestep-1, so current ntimestep can be returned if needed
no guarantee that variable can be evaluated for ntimestep-1 no guarantee that variable can be evaluated for ntimestep-1
e.g. if it depends on computes, but live with that rare case for now e.g. if it depends on computes, but live with that rare case for now
------------------------------------------------------------------------- */ ------------------------------------------------------------------------- */
void Output::reset_timestep(bigint ntimestep) void Output::reset_timestep(bigint ntimestep)
{ {
next_dump_any = MAXBIGINT; next_dump_any = MAXBIGINT;
for (int idump = 0; idump < ndump; idump++) for (int idump = 0; idump < ndump; idump++)
if ((last_dump[idump] >= 0) && !update->whichflag && !dump[idump]->multifile) if ((last_dump[idump] >= 0) && !update->whichflag && !dump[idump]->multifile)
error->all(FLERR, "Cannot reset timestep with active dump - must undump first"); error->all(FLERR, "Cannot reset timestep with active dump - must undump first");
if (restart_flag_single) { if (restart_flag_single) {
if (restart_every_single) { if (restart_every_single) {
next_restart_single = next_restart_single =
(ntimestep/restart_every_single)*restart_every_single; (ntimestep/restart_every_single)*restart_every_single;
if (next_restart_single < ntimestep) if (next_restart_single < ntimestep)
next_restart_single += restart_every_single; next_restart_single += restart_every_single;
} else { } else {
modify->clearstep_compute(); modify->clearstep_compute();
update->ntimestep--; update->ntimestep--;
auto nextrestart = static_cast<bigint> auto nextrestart = static_cast<bigint>
(input->variable->compute_equal(ivar_restart_single)); (input->variable->compute_equal(ivar_restart_single));
if (nextrestart < ntimestep) if (nextrestart < ntimestep)
error->all(FLERR,"Restart variable returned a bad timestep"); error->all(FLERR,"Restart variable returned a bad timestep");
update->ntimestep++; update->ntimestep++;
next_restart_single = nextrestart; next_restart_single = nextrestart;
modify->addstep_compute(next_restart_single); modify->addstep_compute(next_restart_single);
} }
} else next_restart_single = update->laststep + 1; } else next_restart_single = update->laststep + 1;
if (restart_flag_double) { if (restart_flag_double) {
if (restart_every_double) { if (restart_every_double) {
next_restart_double = next_restart_double =
(ntimestep/restart_every_double)*restart_every_double; (ntimestep/restart_every_double)*restart_every_double;
if (next_restart_double < ntimestep) if (next_restart_double < ntimestep)
next_restart_double += restart_every_double; next_restart_double += restart_every_double;
} else { } else {
modify->clearstep_compute(); modify->clearstep_compute();
update->ntimestep--; update->ntimestep--;
auto nextrestart = static_cast<bigint> auto nextrestart = static_cast<bigint>
(input->variable->compute_equal(ivar_restart_double)); (input->variable->compute_equal(ivar_restart_double));
if (nextrestart < ntimestep) if (nextrestart < ntimestep)
error->all(FLERR,"Restart variable returned a bad timestep"); error->all(FLERR,"Restart variable returned a bad timestep");
update->ntimestep++; update->ntimestep++;
next_restart_double = nextrestart; next_restart_double = nextrestart;
modify->addstep_compute(next_restart_double); modify->addstep_compute(next_restart_double);
} }
} else next_restart_double = update->laststep + 1; } else next_restart_double = update->laststep + 1;
next_restart = MIN(next_restart_single,next_restart_double); next_restart = MIN(next_restart_single,next_restart_double);
if (var_thermo) { if (var_thermo) {
modify->clearstep_compute(); modify->clearstep_compute();
update->ntimestep--; update->ntimestep--;
next_thermo = static_cast<bigint> next_thermo = static_cast<bigint>
(input->variable->compute_equal(ivar_thermo)); (input->variable->compute_equal(ivar_thermo));
if (next_thermo < ntimestep) if (next_thermo < ntimestep)
error->all(FLERR,"Thermo_modify every variable returned a bad timestep"); error->all(FLERR,"Thermo_modify every variable returned a bad timestep");
update->ntimestep++; update->ntimestep++;
next_thermo = MIN(next_thermo,update->laststep); next_thermo = MIN(next_thermo,update->laststep);
modify->addstep_compute(next_thermo); modify->addstep_compute(next_thermo);
} else if (thermo_every) { } else if (thermo_every) {
next_thermo = (ntimestep/thermo_every)*thermo_every; next_thermo = (ntimestep/thermo_every)*thermo_every;
if (next_thermo < ntimestep) next_thermo += thermo_every; if (next_thermo < ntimestep) next_thermo += thermo_every;
next_thermo = MIN(next_thermo,update->laststep); next_thermo = MIN(next_thermo,update->laststep);
} else next_thermo = update->laststep; } else next_thermo = update->laststep;
next = MIN(next_dump_any,next_restart); next = MIN(next_dump_any,next_restart);
next = MIN(next,next_thermo); next = MIN(next,next_thermo);
} }
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------
timestep size is being changed timestep size is being changed
@ -728,7 +728,6 @@ void Output::reset_dt()
next = MIN(next,next_thermo); next = MIN(next,next_thermo);
} }
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------
add a Dump to list of Dumps add a Dump to list of Dumps
------------------------------------------------------------------------- */ ------------------------------------------------------------------------- */

View File

@ -699,6 +699,66 @@ TEST_F(DumpAtomTest, binary_write_dump)
delete_file(dump_file); delete_file(dump_file);
} }
TEST_F(DumpAtomTest, frequency)
{
auto dump_file = dump_filename("frequency");
BEGIN_HIDE_OUTPUT();
command("dump id all atom 5 " + dump_file);
command("run 15 post no");
command("run 12 post no");
END_HIDE_OUTPUT();
// NOTE: must reset to current timestep (27) to avoid unexpected issues with following
TEST_FAILURE(".*ERROR: Cannot reset timestep with active dump - must undump first.*",
command("reset_timestep 27"););
BEGIN_HIDE_OUTPUT();
command("run 3 post no");
command("undump id");
command("reset_timestep 5");
command("dump id all atom 10 " + dump_file);
command("dump_modify id append yes");
command("run 20 post no");
command("undump id");
END_HIDE_OUTPUT();
std::vector<std::string> expected, values;
values = extract_items(dump_file, "TIMESTEP");
expected = {"0", "5", "10", "15", "20", "25", "30", "10", "20"};
ASSERT_EQ(values.size(), expected.size());
for (int i = 0; i < expected.size(); ++i)
ASSERT_THAT(values[i], Eq(expected[i]));
BEGIN_HIDE_OUTPUT();
command("reset_timestep 10");
command("dump id all atom 10 " + dump_file);
command("run 20 post no");
command("undump id");
END_HIDE_OUTPUT();
values = extract_items(dump_file, "TIMESTEP");
expected = {"10", "20", "30"};
ASSERT_EQ(values.size(), expected.size());
for (int i = 0; i < expected.size(); ++i)
ASSERT_THAT(values[i], Eq(expected[i]));
BEGIN_HIDE_OUTPUT();
command("reset_timestep 0");
command("dump id all atom 10 " + dump_file);
command("minimize 0.0 0.0 15 30");
command("run 20 post no");
command("undump id");
END_HIDE_OUTPUT();
values = extract_items(dump_file, "TIMESTEP");
expected = {"0", "10", "15", "20", "30"};
ASSERT_EQ(values.size(), expected.size());
for (int i = 0; i < expected.size(); ++i)
ASSERT_THAT(values[i], Eq(expected[i]));
delete_file(dump_file);
}
//------------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------------
// dump_modify // dump_modify
//------------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------------