bug fixes to make a series of test inputs run correctly

This commit is contained in:
Steve Plimpton
2021-12-08 16:44:51 -07:00
parent 26492b13d5
commit d4149e9139
8 changed files with 342 additions and 160 deletions

View File

@ -169,11 +169,12 @@ or multiple smaller files).
.. note:: .. note::
Because periodic boundary conditions are enforced only on Because periodic boundary conditions are enforced only on timesteps
timesteps when neighbor lists are rebuilt, the coordinates of an atom when neighbor lists are rebuilt, the coordinates of an atom written
written to a dump file may be slightly outside the simulation box. to a dump file may be slightly outside the simulation box.
Re-neighbor timesteps will not typically coincide with the timesteps Re-neighbor timesteps will not typically coincide with the
dump snapshots are written. See the :doc:`dump_modify pbc <dump_modify>` command if you with to force coordinates to be timesteps dump snapshots are written. See the :doc:`dump_modify
pbc <dump_modify>` command if you with to force coordinates to be
strictly inside the simulation box. strictly inside the simulation box.
.. note:: .. note::
@ -189,20 +190,21 @@ or multiple smaller files).
multiple processors, each of which owns a subset of the atoms. multiple processors, each of which owns a subset of the atoms.
For the *atom*, *custom*, *cfg*, and *local* styles, sorting is off by For the *atom*, *custom*, *cfg*, and *local* styles, sorting is off by
default. For the *dcd*, *xtc*, *xyz*, and *molfile* styles, sorting by default. For the *dcd*, *xtc*, *xyz*, and *molfile* styles, sorting
atom ID is on by default. See the :doc:`dump_modify <dump_modify>` doc by atom ID is on by default. See the :doc:`dump_modify <dump_modify>`
page for details. doc page for details.
The *atom/gz*, *cfg/gz*, *custom/gz*, *local/gz*, and *xyz/gz* styles are identical The *atom/gz*, *cfg/gz*, *custom/gz*, *local/gz*, and *xyz/gz* styles
in command syntax to the corresponding styles without "gz", however, are identical in command syntax to the corresponding styles without
they generate compressed files using the zlib library. Thus the filename "gz", however, they generate compressed files using the zlib
suffix ".gz" is mandatory. This is an alternative approach to writing library. Thus the filename suffix ".gz" is mandatory. This is an
compressed files via a pipe, as done by the regular dump styles, which alternative approach to writing compressed files via a pipe, as done
may be required on clusters where the interface to the high-speed network by the regular dump styles, which may be required on clusters where
disallows using the fork() library call (which is needed for a pipe). the interface to the high-speed network disallows using the fork()
For the remainder of this doc page, you should thus consider the *atom* library call (which is needed for a pipe). For the remainder of this
and *atom/gz* styles (etc) to be inter-changeable, with the exception doc page, you should thus consider the *atom* and *atom/gz* styles
of the required filename suffix. (etc) to be inter-changeable, with the exception of the required
filename suffix.
Similarly, the *atom/zstd*, *cfg/zstd*, *custom/zstd*, *local/zstd*, Similarly, the *atom/zstd*, *cfg/zstd*, *custom/zstd*, *local/zstd*,
and *xyz/zstd* styles are identical to the gz styles, but use the Zstd and *xyz/zstd* styles are identical to the gz styles, but use the Zstd
@ -275,10 +277,11 @@ This bounding box is convenient for many visualization programs. The
meaning of the 6 character flags for "xx yy zz" is the same as above. meaning of the 6 character flags for "xx yy zz" is the same as above.
Note that the first two numbers on each line are now xlo_bound instead Note that the first two numbers on each line are now xlo_bound instead
of xlo, etc, since they represent a bounding box. See the :doc:`Howto triclinic <Howto_triclinic>` page for a geometric description of xlo, etc, since they represent a bounding box. See the :doc:`Howto
of triclinic boxes, as defined by LAMMPS, simple formulas for how the triclinic <Howto_triclinic>` page for a geometric description of
6 bounding box extents (xlo_bound,xhi_bound,etc) are calculated from triclinic boxes, as defined by LAMMPS, simple formulas for how the 6
the triclinic parameters, and how to transform those parameters to and bounding box extents (xlo_bound,xhi_bound,etc) are calculated from the
triclinic parameters, and how to transform those parameters to and
from other commonly used triclinic representations. from other commonly used triclinic representations.
The "ITEM: ATOMS" line in each snapshot lists column descriptors for The "ITEM: ATOMS" line in each snapshot lists column descriptors for
@ -310,23 +313,24 @@ written to the dump file. This local data is typically calculated by
each processor based on the atoms it owns, but there may be zero or each processor based on the atoms it owns, but there may be zero or
more entities per atom, e.g. a list of bond distances. An explanation more entities per atom, e.g. a list of bond distances. An explanation
of the possible dump local attributes is given below. Note that by of the possible dump local attributes is given below. Note that by
using input from the :doc:`compute property/local <compute_property_local>` command with dump local, using input from the :doc:`compute property/local
it is possible to generate information on bonds, angles, etc that can <compute_property_local>` command with dump local, it is possible to
be cut and pasted directly into a data file read by the generate information on bonds, angles, etc that can be cut and pasted
:doc:`read_data <read_data>` command. directly into a data file read by the :doc:`read_data <read_data>`
command.
Style *cfg* has the same command syntax as style *custom* and writes Style *cfg* has the same command syntax as style *custom* and writes
extended CFG format files, as used by the extended CFG format files, as used by the `AtomEye
`AtomEye <http://li.mit.edu/Archive/Graphics/A/>`_ visualization <http://li.mit.edu/Archive/Graphics/A/>`_ visualization package.
package. Since the extended CFG format uses a single snapshot of the Since the extended CFG format uses a single snapshot of the system per
system per file, a wildcard "\*" must be included in the filename, as file, a wildcard "\*" must be included in the filename, as discussed
discussed below. The list of atom attributes for style *cfg* must below. The list of atom attributes for style *cfg* must begin with
begin with either "mass type xs ys zs" or "mass type xsu ysu zsu" either "mass type xs ys zs" or "mass type xsu ysu zsu" since these
since these quantities are needed to write the CFG files in the quantities are needed to write the CFG files in the appropriate format
appropriate format (though the "mass" and "type" fields do not appear (though the "mass" and "type" fields do not appear explicitly in the
explicitly in the file). Any remaining attributes will be stored as file). Any remaining attributes will be stored as "auxiliary
"auxiliary properties" in the CFG files. Note that you will typically properties" in the CFG files. Note that you will typically want to
want to use the :doc:`dump_modify element <dump_modify>` command with use the :doc:`dump_modify element <dump_modify>` command with
CFG-formatted files, to associate element names with atom types, so CFG-formatted files, to associate element names with atom types, so
that AtomEye can render atoms appropriately. When unwrapped that AtomEye can render atoms appropriately. When unwrapped
coordinates *xsu*, *ysu*, and *zsu* are requested, the nominal AtomEye coordinates *xsu*, *ysu*, and *zsu* are requested, the nominal AtomEye

View File

@ -17,7 +17,7 @@ Syntax
* one or more keyword/value pairs may be appended * one or more keyword/value pairs may be appended
* these keywords apply to various dump styles * these keywords apply to various dump styles
* keyword = *append* or *at* or *buffer* or *delay* or *element* or *every* or *fileper* or *first* or *flush* or *format* or *header* or *image* or *label* or *maxfiles* or *nfile* or *pad* or *pbc* or *precision* or *region* or *refresh* or *scale* or *sfactor* or *sort* or *tfactor* or *thermo* or *thresh* or *time* or *units* or *unwrap* * keyword = *append* or *at* or *buffer* or *delay* or *element* or *every* or *every/time* or *fileper* or *first* or *flush* or *format* or *header* or *image* or *label* or *maxfiles* or *nfile* or *pad* or *pbc* or *precision* or *region* or *refresh* or *scale* or *sfactor* or *sort* or *tfactor* or *thermo* or *thresh* or *time* or *units* or *unwrap*
.. parsed-literal:: .. parsed-literal::
@ -32,6 +32,9 @@ Syntax
*every* arg = N *every* arg = N
N = dump every this many timesteps N = dump every this many timesteps
N can be a variable (see below) N can be a variable (see below)
*every/time* arg = Delta
Delta = dump every this interval in simulation time (time units)
Delta can be a variable (see below)
*fileper* arg = Np *fileper* arg = Np
Np = write one file for every this many processors Np = write one file for every this many processors
*first* arg = *yes* or *no* *first* arg = *yes* or *no*
@ -197,11 +200,18 @@ will be accepted.
---------- ----------
The *every* keyword changes the dump frequency originally specified by The *every* keyword does two things. It specifies that the interval
the :doc:`dump <dump>` command to a new value. The every keyword can be between dump snapshots will be specified in timesteps, which is the
specified in one of two ways. It can be a numeric value in which case default if the *every* or *every/time* keywords are not used. See the
it must be > 0. Or it can be an :doc:`equal-style variable <variable>`, *every/time* keyword for how to specify the interval in simulation
which should be specified as v_name, where name is the variable name. time, i.e. in time units of the :doc:`units <units>` command. This
command also sets the interval value, which overrides the dump
frequency originally specified by the :doc:`dump <dump>` command.
The every keyword can be specified in one of two ways. It can be a
numeric value in which case it must be > 0. Or it can be an
:doc:`equal-style variable <variable>`, which should be specified as
v_name, where name is the variable name.
In this case, the variable is evaluated at the beginning of a run to In this case, the variable is evaluated at the beginning of a run to
determine the next timestep at which a dump snapshot will be written determine the next timestep at which a dump snapshot will be written
@ -210,11 +220,12 @@ determine the next timestep, etc. Thus the variable should return
timestep values. See the stagger() and logfreq() and stride() math timestep values. See the stagger() and logfreq() and stride() math
functions for :doc:`equal-style variables <variable>`, as examples of functions for :doc:`equal-style variables <variable>`, as examples of
useful functions to use in this context. Other similar math functions useful functions to use in this context. Other similar math functions
could easily be added as options for :doc:`equal-style variables <variable>`. Also see the next() function, which allows could easily be added as options for :doc:`equal-style variables
use of a file-style variable which reads successive values from a <variable>`. Also see the next() function, which allows use of a
file, each time the variable is evaluated. Used with the *every* file-style variable which reads successive values from a file, each
keyword, if the file contains a list of ascending timesteps, you can time the variable is evaluated. Used with the *every* keyword, if the
output snapshots whenever you wish. file contains a list of ascending timesteps, you can output snapshots
whenever you wish.
Note that when using the variable option with the *every* keyword, you Note that when using the variable option with the *every* keyword, you
need to use the *first* option if you want an initial snapshot written need to use the *first* option if you want an initial snapshot written
@ -255,14 +266,95 @@ in file tmp.times:
---------- ----------
The *every/time* keyword does two things. It specifies that the
interval between dump snapshots will be specified in simulation time,
i.e. in time units of the :doc:`units <units>` command. This can be
useful when the timestep size varies during a simulation run, e.g. by
use of the :doc:`fix dt/reset <fix_dt_reset>` command. The default is
to specify the interval in timesteps; see the *every* keyword. This
command also sets the interval value.
Note that since snapshots are output on simulation steps, each
snapshot will be written on the first timestep whose associated
simulation time is >= the exact snapshot time value.
As with the *every* option, the *Delta* value can be specified in one
of two ways. It can be a numeric value in which case it must be >
0.0. Or it can be an :doc:`equal-style variable <variable>`, which
should be specified as v_name, where name is the variable name.
In this case, the variable is evaluated at the beginning of a run to
determine the next simulation time at which a dump snapshot will be
written out. On that timestep the variable will be evaluated again to
determine the next simulation time, etc. Thus the variable should
return values in time units. Note the current timestep or simulation
time can be used in an :doc:`equal-style variables <variable>` since
they are both thermodynamic keywords. Also see the next() function,
which allows use of a file-style variable which reads successive
values from a file, each time the variable is evaluated. Used with
the *every/time* keyword, if the file contains a list of ascending
simulation times, you can output snapshots whenever you wish.
Note that when using the variable option with the *every/time*
keyword, you need to use the *first* option if you want an initial
snapshot written to the dump file. The *every/time* keyword cannot be
used with the dump *dcd* style.
For example, the following commands will write snapshots at successive
simulation times which grow by a factor of 1.5 with each interval.
The dt value used in the variable is to avoid a zero result when the
initial simulation time is 0.0.
.. code-block:: LAMMPS
variable increase equal 1.5*(time+dt)
dump 1 all atom 100 tmp.dump
dump_modify 1 every/time v_increase first yes
The following commands would write snapshots at the times listed in
file tmp.times:
.. code-block:: LAMMPS
variable f file tmp.times
variable s equal next(f)
dump 1 all atom 100 tmp.dump
dump_modify 1 every/time v_s
.. note::
When using a file-style variable with the *every* keyword, the file
of timesteps must list a first times that is beyond the time
associated with the current timestep (e.g. it cannot be 0.0). And
it must list one or more times beyond the length of the run you
perform. This is because the dump command will generate an error
if the next time it reads from the file is not a value greater than
the current time. Thus if you wanted output at times 0,15,100 of a
run of length 100 in simulation time, the file should contain the
values 15,100,101 and you should also use the dump_modify first
command. Any final value > 100 could be used in place of 101.
----------
The *first* keyword determines whether a dump snapshot is written on The *first* keyword determines whether a dump snapshot is written on
the very first timestep after the dump command is invoked. This will the very first timestep after the dump command is invoked. This will
always occur if the current timestep is a multiple of N, the frequency always occur if the current timestep is a multiple of $N$, the
specified in the :doc:`dump <dump>` command, including timestep 0. But frequency specified in the :doc:`dump <dump>` command or
if this is not the case, a dump snapshot will only be written if the :doc:`dump_modify every <dump_modify>` command, including timestep 0.
setting of this keyword is *yes*\ . If it is *no*, which is the It will also always occur if the current simulation time is a multiple
of *Delta*, the time interval specified in the doc:`dump_modify every/time
<dump_modify>` command.
But if this is not the case, a dump snapshot will only be written if
the setting of this keyword is *yes*\ . If it is *no*, which is the
default, then it will not be written. default, then it will not be written.
Note that if the argument to the :doc:`dump_modify every
<dump_modify>` doc:`dump_modify every/time <dump_modify>` commands is
a variable and not a numeric value, then specifying *first yes* is the
only way to write a dump snapshot on the first timestep after the dump
command is invoked.
---------- ----------
The *flush* keyword determines whether a flush operation is invoked The *flush* keyword determines whether a flush operation is invoked
@ -342,10 +434,10 @@ The *fileper* keyword is documented below with the *nfile* keyword.
---------- ----------
The *header* keyword toggles whether the dump file will include a header. The *header* keyword toggles whether the dump file will include a
Excluding a header will reduce the size of the dump file for fixes such as header. Excluding a header will reduce the size of the dump file for
:doc:`fix pair/tracker <fix_pair_tracker>` which do not require the information fixes such as :doc:`fix pair/tracker <fix_pair_tracker>` which do not
typically written to the header. require the information typically written to the header.
---------- ----------

View File

@ -78,13 +78,20 @@ outer loop (largest) timestep, which is the same timestep that the
Note that the cumulative simulation time (in time units), which Note that the cumulative simulation time (in time units), which
accounts for changes in the timestep size as a simulation proceeds, accounts for changes in the timestep size as a simulation proceeds,
can be accessed by the :doc:`thermo_style time <thermo_style>` keyword. can be accessed by the :doc:`thermo_style time <thermo_style>`
keyword.
Also note that the :doc:`dump_modify every/time <dump_modify>` option
allows dump files to be written at intervals specified by simulation
time, rather than by timesteps. Simulation time is in time units;
see the :doc:`units <units>` doc page for details.
Restart, fix_modify, output, run start/stop, minimize info Restart, fix_modify, output, run start/stop, minimize info
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" """""""""""""""""""""""""""""""""""""""""""""""""""""""""""
No information about this fix is written to :doc:`binary restart files <restart>`. None of the :doc:`fix_modify <fix_modify>` options No information about this fix is written to :doc:`binary restart files
are relevant to this fix. <restart>`. None of the :doc:`fix_modify <fix_modify>` options are
relevant to this fix.
This fix computes a global scalar which can be accessed by various This fix computes a global scalar which can be accessed by various
:doc:`output commands <Howto_output>`. The scalar stores the last :doc:`output commands <Howto_output>`. The scalar stores the last
@ -93,7 +100,8 @@ timestep on which the timestep was reset to a new value.
The scalar value calculated by this fix is "intensive". The scalar value calculated by this fix is "intensive".
No parameter of this fix can be used with the *start/stop* keywords of No parameter of this fix can be used with the *start/stop* keywords of
the :doc:`run <run>` command. This fix is not invoked during :doc:`energy minimization <minimize>`. the :doc:`run <run>` command. This fix is not invoked during
:doc:`energy minimization <minimize>`.
Restrictions Restrictions
"""""""""""" """"""""""""
@ -102,7 +110,7 @@ Restrictions
Related commands Related commands
"""""""""""""""" """"""""""""""""
:doc:`timestep <timestep>` :doc:`timestep <timestep>`, :doc:`dump_modify every/time <dump_modify>`
Default Default
""""""" """""""

View File

@ -918,24 +918,6 @@ void Dump::modify_params(int narg, char **arg)
else delay_flag = 0; else delay_flag = 0;
iarg += 2; iarg += 2;
} else if (strcmp(arg[iarg],"delta") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal dump_modify command");
int idump;
for (idump = 0; idump < output->ndump; idump++)
if (strcmp(id,output->dump[idump]->id) == 0) break;
double delta;
if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) {
delete [] output->var_dump[idump];
output->var_dump[idump] = utils::strdup(&arg[iarg+1][2]);
delta = 0.0;
} else {
delta = utils::numeric(FLERR,arg[iarg+1],false,lmp);
if (delta <= 0.0) error->all(FLERR,"Illegal dump_modify command");
}
output->mode_dump[idump] = 1;
output->delta_dump[idump] = delta;
iarg += 2;
} else if (strcmp(arg[iarg],"every") == 0) { } else if (strcmp(arg[iarg],"every") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal dump_modify command"); if (iarg+2 > narg) error->all(FLERR,"Illegal dump_modify command");
int idump; int idump;
@ -954,6 +936,24 @@ void Dump::modify_params(int narg, char **arg)
output->every_dump[idump] = n; output->every_dump[idump] = n;
iarg += 2; iarg += 2;
} else if (strcmp(arg[iarg],"every/time") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal dump_modify command");
int idump;
for (idump = 0; idump < output->ndump; idump++)
if (strcmp(id,output->dump[idump]->id) == 0) break;
double delta;
if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) {
delete [] output->var_dump[idump];
output->var_dump[idump] = utils::strdup(&arg[iarg+1][2]);
delta = 0.0;
} else {
delta = utils::numeric(FLERR,arg[iarg+1],false,lmp);
if (delta <= 0.0) error->all(FLERR,"Illegal dump_modify command");
}
output->mode_dump[idump] = 1;
output->every_time_dump[idump] = delta;
iarg += 2;
} else if (strcmp(arg[iarg],"fileper") == 0) { } else if (strcmp(arg[iarg],"fileper") == 0) {
if (iarg+2 > narg) error->all(FLERR,"Illegal dump_modify command"); if (iarg+2 > narg) error->all(FLERR,"Illegal dump_modify command");
if (!multiproc) if (!multiproc)

View File

@ -197,12 +197,15 @@ void FixDtReset::end_of_step()
laststep = update->ntimestep; laststep = update->ntimestep;
// calls to other classes that need to know timestep size changed
update->update_time(); update->update_time();
update->dt = dt; update->dt = dt;
update->dt_default = 0; update->dt_default = 0;
if (respaflag) update->integrate->reset_dt(); if (respaflag) update->integrate->reset_dt();
if (force->pair) force->pair->reset_dt(); if (force->pair) force->pair->reset_dt();
for (int i = 0; i < modify->nfix; i++) modify->fix[i]->reset_dt(); for (int i = 0; i < modify->nfix; i++) modify->fix[i]->reset_dt();
output->reset_dt();
} }
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */

View File

@ -29,6 +29,7 @@
#include "variable.h" #include "variable.h"
#include "write_restart.h" #include "write_restart.h"
#include <cmath>
#include <cstring> #include <cstring>
using namespace LAMMPS_NS; using namespace LAMMPS_NS;
@ -62,7 +63,7 @@ Output::Output(LAMMPS *lmp) : Pointers(lmp)
max_dump = 0; max_dump = 0;
mode_dump = nullptr; mode_dump = nullptr;
every_dump = nullptr; every_dump = nullptr;
delta_dump = nullptr; every_time_dump = nullptr;
next_dump = nullptr; next_dump = nullptr;
next_time_dump = nullptr; next_time_dump = nullptr;
last_dump = nullptr; last_dump = nullptr;
@ -98,7 +99,7 @@ Output::~Output()
memory->destroy(mode_dump); memory->destroy(mode_dump);
memory->destroy(every_dump); memory->destroy(every_dump);
memory->destroy(delta_dump); memory->destroy(every_time_dump);
memory->destroy(next_dump); memory->destroy(next_dump);
memory->destroy(next_time_dump); memory->destroy(next_time_dump);
memory->destroy(last_dump); memory->destroy(last_dump);
@ -134,7 +135,7 @@ void Output::init()
for (int i = 0; i < ndump; i++) dump[i]->init(); for (int i = 0; i < ndump; i++) dump[i]->init();
for (int i = 0; i < ndump; i++) for (int i = 0; i < ndump; i++)
if ((mode_dump[i] == 0 && every_dump[i] == 0) || if ((mode_dump[i] == 0 && every_dump[i] == 0) ||
(mode_dump[i] == 1 && delta_dump[i] == 0.0)) { (mode_dump[i] == 1 && every_time_dump[i] == 0.0)) {
ivar_dump[i] = input->variable->find(var_dump[i]); ivar_dump[i] = input->variable->find(var_dump[i]);
if (ivar_dump[i] < 0) if (ivar_dump[i] < 0)
error->all(FLERR,"Variable name for dump every or delta does not exist"); error->all(FLERR,"Variable name for dump every or delta does not exist");
@ -169,42 +170,61 @@ void Output::setup(int memflag)
{ {
bigint ntimestep = update->ntimestep; bigint ntimestep = update->ntimestep;
// perform dump at start of run only if: // consider all dumps
// current timestep is multiple of every and last dump not >= this step // decide whether to write snapshot and/or calculate next step for dump
// this is first run after dump created and firstflag is set
// note that variable freq will not write unless triggered by firstflag
// set next_dump, and also next_time_dump for mode_dump = 1
// set next_dump_any to smallest next_dump
// wrap dumps that invoke computes or do variable eval with clear/add
// if dump not written now, use addstep_compute_all() since don't know
// what computes the dump write would invoke
// if no dumps, set next_dump_any to last+1 so will not influence next
int writeflag;
if (ndump && update->restrict_output == 0) { if (ndump && update->restrict_output == 0) {
for (int idump = 0; idump < ndump; idump++) { for (int idump = 0; idump < ndump; idump++) {
// wrap dumps that invoke computes or do variable eval with clear/add
if (dump[idump]->clearstep || var_dump[idump]) if (dump[idump]->clearstep || var_dump[idump])
modify->clearstep_compute(); modify->clearstep_compute();
writeflag = 0; // write a snapshot at setup only if any of these 3 conditions hold
if (mode_dump[idump] == 0) { // (1) this is first run since dump was created and its first_flag = 0
if (every_dump[idump] && (ntimestep % every_dump[idump] == 0) && // (2) mode_dump = 0 and timestep is multiple of every_dump
last_dump[idump] != ntimestep) writeflag = 1; // (3) mode_dump = 1 and time is multiple of every_time_dump (within EPSDT)
} else { // (2) and (3) only apply for non-variable dump intervals
if (delta_dump[idump] >= 0.0 && last_dump[idump] != ntimestep) // finally, do not write if same snapshot written previously,
writeflag = 1; // i.e. on last timestep of previous run
}
int writeflag = 0;
if (last_dump[idump] < 0 && dump[idump]->first_flag == 1) writeflag = 1; if (last_dump[idump] < 0 && dump[idump]->first_flag == 1) writeflag = 1;
if (mode_dump[idump] == 0) {
if (every_dump[idump] && (ntimestep % every_dump[idump] == 0))
writeflag = 1;
} else {
if (every_time_dump[idump] > 0.0) {
double tcurrent = update->atime +
(ntimestep - update->atimestep) * update->dt;
double remainder = fmod(tcurrent,every_time_dump[idump]);
if ((remainder < EPSDT*update->dt) ||
(every_time_dump[idump] - remainder < EPSDT*update->dt))
writeflag = 1;
}
}
if (last_dump[idump] == ntimestep) writeflag = 0;
// perform dump
if (writeflag) { if (writeflag) {
dump[idump]->write(); dump[idump]->write();
last_dump[idump] = ntimestep; last_dump[idump] = ntimestep;
} }
// calculate timestep and/or time for next dump
// set next_dump and next_time_dump, 0 arg for setup() // set next_dump and next_time_dump, 0 arg for setup()
// only do this if dump written or dump has not been written yet
calculate_next_dump(0,idump,ntimestep); if (writeflag || last_dump[idump] < 0)
calculate_next_dump(0,idump,ntimestep);
// if dump not written now, use addstep_compute_all()
// since don't know what computes the dump will invoke
if (dump[idump]->clearstep || var_dump[idump]) { if (dump[idump]->clearstep || var_dump[idump]) {
if (writeflag) modify->addstep_compute(next_dump[idump]); if (writeflag) modify->addstep_compute(next_dump[idump]);
@ -214,6 +234,9 @@ void Output::setup(int memflag)
if (idump) next_dump_any = MIN(next_dump_any,next_dump[idump]); if (idump) next_dump_any = MIN(next_dump_any,next_dump[idump]);
else next_dump_any = next_dump[0]; else next_dump_any = next_dump[0];
} }
// if no dumps, set next_dump_any to last+1 so will not influence next
} 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
@ -296,33 +319,26 @@ void Output::write(bigint ntimestep)
// 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 dumps that invoke computes or do variable eval with clear/add // wrap dumps that invoke computes or do variable eval with clear/add
// if dump not written now, use addstep_compute_all() since don't know
// what computes the dump write would invoke
int writeflag; int writeflag;
if (next_dump_any == ntimestep) { if (next_dump_any == ntimestep) {
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 (dump[idump]->clearstep || var_dump[idump]) if (dump[idump]->clearstep || var_dump[idump])
modify->clearstep_compute(); modify->clearstep_compute();
writeflag = 0; // perform dump
if (last_dump[idump] != ntimestep) writeflag = 1; // reset next_dump and next_time_dump, 1 arg for write()
if (writeflag) { dump[idump]->write();
dump[idump]->write(); last_dump[idump] = ntimestep;
last_dump[idump] = ntimestep;
}
// set next_dump and next_time_dump, 1 arg for write()
calculate_next_dump(1,idump,ntimestep); calculate_next_dump(1,idump,ntimestep);
if (dump[idump]->clearstep || var_dump[idump]) { if (dump[idump]->clearstep || var_dump[idump])
if (writeflag) modify->addstep_compute(next_dump[idump]); modify->addstep_compute(next_dump[idump]);
else modify->addstep_compute_all(next_dump[idump]);
}
} }
if (idump) next_dump_any = MIN(next_dump_any,next_dump[idump]); if (idump) next_dump_any = MIN(next_dump_any,next_dump[idump]);
@ -422,6 +438,10 @@ void Output::write_dump(bigint ntimestep)
operates in one of two modes, based on mode_dump flag operates in one of two modes, based on mode_dump flag
for timestep mode, set next_dump for timestep mode, set next_dump
for simulation time mode, set next_time_dump and next_dump for simulation time mode, set next_time_dump and next_dump
which flag depends on caller
0 = from setup() at start of run
1 = from write() during run each time a dump file is written
2 = 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)
@ -431,13 +451,17 @@ void Output::write_dump(bigint ntimestep)
if (mode_dump[idump] == 0) { if (mode_dump[idump] == 0) {
// for setup, make next_dump a multiple of every_dump
if (every_dump[idump]) { if (every_dump[idump]) {
if (which == 1) next_dump[idump] += every_dump[idump];
else // which = 0: nextdump = next multiple of every_dump
// which = 1: increment nextdump by every_dump
if (which == 0)
next_dump[idump] = next_dump[idump] =
(ntimestep/every_dump[idump])*every_dump[idump] + every_dump[idump]; (ntimestep/every_dump[idump])*every_dump[idump] + every_dump[idump];
else if (which == 1)
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]));
@ -449,22 +473,29 @@ void Output::write_dump(bigint ntimestep)
// 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;
// for setup, make nexttime a multiple of delta_dump if (every_time_dump[idump] > 0.0) {
if (delta_dump[idump] > 0.0) { // which = 0: nexttime = next multiple of every_time_dump
if (which == 1) nexttime = next_time_dump[idump] + delta_dump[idump]; // which = 1: increment nexttime by every_time_dump
else // which = 2: no change to previous nexttime (only timestep has changed)
nexttime = static_cast<bigint> (tcurrent/delta_dump[idump]) *
delta_dump[idump] + delta_dump[idump]; if (which == 0)
nexttime = static_cast<bigint> (tcurrent/every_time_dump[idump]) *
every_time_dump[idump] + every_time_dump[idump];
else if (which == 1)
nexttime = next_time_dump[idump] + every_time_dump[idump];
else if (which == 2)
nexttime = next_time_dump[idump];
nextdump = ntimestep + nextdump = ntimestep +
static_cast<bigint> ((nexttime - tcurrent + EPSDT*update->dt) / static_cast<bigint> ((nexttime - tcurrent - EPSDT*update->dt) /
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
@ -472,30 +503,35 @@ void Output::write_dump(bigint 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) / delta_dump[idump]); ((tnext - nexttime) / every_time_dump[idump]);
nexttime = nexttime + (multiple+1)*delta_dump[idump]; nexttime = nexttime + (multiple+1)*every_time_dump[idump];
nextdump = ntimestep + nextdump = ntimestep +
static_cast<bigint> ((nexttime - tcurrent + EPSDT*update->dt) / static_cast<bigint> ((nexttime - tcurrent - EPSDT*update->dt) /
update->dt); update->dt) + 1;
} }
} else { } else {
nexttime = input->variable->compute_equal(ivar_dump[idump]);
// do not re-evaulate variable for which = 2, leave nexttime as-is
// unless next_time_dump < 0.0, which means variable never yet evaluated
if (which < 2 || next_time_dump[idump] < 0.0)
nexttime = input->variable->compute_equal(ivar_dump[idump]);
else
nexttime = next_time_dump[idump];
if (nexttime <= tcurrent) if (nexttime <= tcurrent)
error->all(FLERR,"Dump delta 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) / static_cast<bigint> ((nexttime - tcurrent - EPSDT*update->dt) /
update->dt); update->dt) + 1;
if (nextdump <= ntimestep) if (nextdump <= ntimestep)
error->all(FLERR,"Dump delta 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;
//printf("END time %20.16g step %ld ratio %g\n",
// next_time_dump[idump],next_dump[idump],
// next_time_dump[idump]/update->dt/(next_dump[idump]+1));
} }
} }
@ -529,7 +565,7 @@ void Output::write_restart(bigint ntimestep)
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------
timestep is being changed, called by update->reset_timestep() timestep is being changed, called by update->reset_timestep()
reset next timestep values for dumps, restart, thermo output reset next output values for dumps, restart, thermo output
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
@ -626,6 +662,35 @@ void Output::reset_timestep(bigint ntimestep)
next = MIN(next,next_thermo); next = MIN(next,next_thermo);
} }
/* ----------------------------------------------------------------------
timestep size is being changed, called by fix dt/reset (at end of step)
reset next output values for dumps which have mode_dump=1
------------------------------------------------------------------------- */
void Output::reset_dt()
{
next_dump_any = MAXBIGINT;
for (int idump = 0; idump < ndump; idump++) {
if (mode_dump[idump] == 1) {
// reset next_dump for unchanged next_time_dump, 2 arg for reset_dt()
calculate_next_dump(2,idump,update->ntimestep);
// use compute_all() b/c don't know what computes will be needed
if (dump[idump]->clearstep || var_dump[idump])
modify->addstep_compute_all(next_dump[idump]);
}
next_dump_any = MIN(next_dump_any,next_dump[idump]);
}
next = MIN(next_dump_any,next_restart);
next = MIN(next,next_thermo);
}
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------
add a Dump to list of Dumps add a Dump to list of Dumps
------------------------------------------------------------------------- */ ------------------------------------------------------------------------- */
@ -652,7 +717,7 @@ void Output::add_dump(int narg, char **arg)
memory->srealloc(dump,max_dump*sizeof(Dump *),"output:dump"); memory->srealloc(dump,max_dump*sizeof(Dump *),"output:dump");
memory->grow(mode_dump,max_dump,"output:mode_dump"); memory->grow(mode_dump,max_dump,"output:mode_dump");
memory->grow(every_dump,max_dump,"output:every_dump"); memory->grow(every_dump,max_dump,"output:every_dump");
memory->grow(delta_dump,max_dump,"output:delta_dump"); memory->grow(every_time_dump,max_dump,"output:every_time_dump");
memory->grow(next_dump,max_dump,"output:next_dump"); memory->grow(next_dump,max_dump,"output:next_dump");
memory->grow(next_time_dump,max_dump,"output:next_time_dump"); memory->grow(next_time_dump,max_dump,"output:next_time_dump");
memory->grow(last_dump,max_dump,"output:last_dump"); memory->grow(last_dump,max_dump,"output:last_dump");
@ -673,7 +738,8 @@ void Output::add_dump(int narg, char **arg)
mode_dump[ndump] = 0; mode_dump[ndump] = 0;
every_dump[ndump] = utils::inumeric(FLERR,arg[3],false,lmp); every_dump[ndump] = utils::inumeric(FLERR,arg[3],false,lmp);
if (every_dump[ndump] <= 0) error->all(FLERR,"Illegal dump command"); if (every_dump[ndump] <= 0) error->all(FLERR,"Illegal dump command");
delta_dump[ndump] = 0.0; every_time_dump[ndump] = 0.0;
next_time_dump[ndump] = -1.0;
last_dump[ndump] = -1; last_dump[ndump] = -1;
var_dump[ndump] = nullptr; var_dump[ndump] = nullptr;
ivar_dump[ndump] = -1; ivar_dump[ndump] = -1;
@ -731,7 +797,7 @@ void Output::delete_dump(char *id)
dump[i-1] = dump[i]; dump[i-1] = dump[i];
mode_dump[i-1] = mode_dump[i]; mode_dump[i-1] = mode_dump[i];
every_dump[i-1] = every_dump[i]; every_dump[i-1] = every_dump[i];
delta_dump[i-1] = delta_dump[i]; every_time_dump[i-1] = every_time_dump[i];
next_dump[i-1] = next_dump[i]; next_dump[i-1] = next_dump[i];
next_time_dump[i-1] = next_time_dump[i]; next_time_dump[i-1] = next_time_dump[i];
last_dump[i-1] = last_dump[i]; last_dump[i-1] = last_dump[i];

View File

@ -37,8 +37,8 @@ class Output : protected Pointers {
int max_dump; // max size of Dump list int max_dump; // max size of Dump list
bigint next_dump_any; // next timestep for any Dump bigint next_dump_any; // next timestep for any Dump
int *mode_dump; // 0/1 if write every N timesteps or Delta in sim time int *mode_dump; // 0/1 if write every N timesteps or Delta in sim time
int *every_dump; // dump every this many timesteps, 0 if variable int *every_dump; // dump every N timesteps, 0 if variable
double *delta_dump; // dump every this delta sim time, 0.0 if variable double *every_time_dump; // dump every Delta of sim time, 0.0 if variable
bigint *next_dump; // next timestep to perform dump bigint *next_dump; // next timestep to perform dump
double *next_time_dump; // next simulation time to perform dump (mode = 1) double *next_time_dump; // next simulation time to perform dump (mode = 1)
bigint *last_dump; // last timestep each snapshot was output bigint *last_dump; // last timestep each snapshot was output
@ -75,7 +75,8 @@ class Output : protected Pointers {
void write(bigint); // output for current timestep void write(bigint); // output for current timestep
void write_dump(bigint); // force output of dump snapshots void write_dump(bigint); // force output of dump snapshots
void write_restart(bigint); // force output of a restart file void write_restart(bigint); // force output of a restart file
void reset_timestep(bigint); // reset next timestep for all output void reset_timestep(bigint); // reset output which depeneds on timestep
void reset_dt(); // reset output which depends on dt
void add_dump(int, char **); // add a Dump to Dump list void add_dump(int, char **); // add a Dump to Dump list
void modify_dump(int, char **); // modify a Dump void modify_dump(int, char **); // modify a Dump

View File

@ -458,7 +458,7 @@ Min *Update::minimize_creator(LAMMPS *lmp)
} }
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------
reset timestep as called from input script reset timestep called from input script
------------------------------------------------------------------------- */ ------------------------------------------------------------------------- */
void Update::reset_timestep(int narg, char **arg) void Update::reset_timestep(int narg, char **arg)
@ -470,24 +470,32 @@ void Update::reset_timestep(int narg, char **arg)
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------
reset timestep reset timestep
called from rerun command and input script (indirectly) called from input script (indirectly) or rerun command
------------------------------------------------------------------------- */ ------------------------------------------------------------------------- */
void Update::reset_timestep(bigint newstep) void Update::reset_timestep(bigint newstep)
{ {
if (newstep < 0) error->all(FLERR,"Timestep must be >= 0");
bigint oldstep = ntimestep;
ntimestep = newstep; ntimestep = newstep;
if (ntimestep < 0) error->all(FLERR,"Timestep must be >= 0");
// set atimestep to new timestep // if newstep >= oldstep, update simulation time accordingly
// so future update_time() calls will be correct // if newstep < oldstep, zero simulation time
atimestep = ntimestep; if (newstep >= oldstep) update_time();
// trigger reset of timestep for output if (newstep < oldstep) {
// do not allow any timestep-dependent fixes to be already defined atime = 0.0;
atimestep = newstep;
}
// changes to output that depend on timestep
output->reset_timestep(ntimestep); output->reset_timestep(ntimestep);
// do not allow timestep-dependent fixes to be defined
for (const auto &ifix : modify->get_fix_list()) for (const auto &ifix : modify->get_fix_list())
if (ifix->time_depend) if (ifix->time_depend)
error->all(FLERR, "Cannot reset timestep with time-dependent fix {} defined",ifix->style); error->all(FLERR, "Cannot reset timestep with time-dependent fix {} defined",ifix->style);
@ -508,7 +516,7 @@ void Update::reset_timestep(bigint newstep)
if (icompute->timeflag) icompute->clearstep(); if (icompute->timeflag) icompute->clearstep();
} }
// Neighbor Bin/Stencil/Pair classes store timestamps that need to be cleared // neighbor Bin/Stencil/Pair classes store timestamps that need to be cleared
neighbor->reset_timestep(ntimestep); neighbor->reset_timestep(ntimestep);
} }