From 49ac79fcdd40d9111607451f04d70ba739ff5487 Mon Sep 17 00:00:00 2001 From: Steve Plimpton Date: Mon, 8 May 2023 08:55:40 -0600 Subject: [PATCH 1/8] change error checks for computes that are not current --- src/VTK/dump_vtk.cpp | 20 ++++-------- src/dump_custom.cpp | 20 ++++-------- src/dump_grid.cpp | 20 ++++-------- src/dump_image.cpp | 18 ++++------- src/dump_local.cpp | 20 ++++-------- src/thermo.cpp | 42 +++++++++--------------- src/variable.cpp | 77 +++++++++++++++++++------------------------- 7 files changed, 83 insertions(+), 134 deletions(-) diff --git a/src/VTK/dump_vtk.cpp b/src/VTK/dump_vtk.cpp index 75033684ae..3667180bc9 100644 --- a/src/VTK/dump_vtk.cpp +++ b/src/VTK/dump_vtk.cpp @@ -294,21 +294,15 @@ int DumpVTK::count() } // invoke Computes for per-atom quantities - // only if within a run or minimize - // else require that computes are current - // this prevents a compute from being invoked by the WriteDump class + // cannot invoke before first run, otherwise invoke if necessary if (ncompute) { - if (update->whichflag == 0) { - for (i = 0; i < ncompute; i++) - if (compute[i]->invoked_peratom != update->ntimestep) - error->all(FLERR,"Compute used in dump between runs is not current"); - } else { - for (i = 0; i < ncompute; i++) { - if (!(compute[i]->invoked_flag & Compute::INVOKED_PERATOM)) { - compute[i]->compute_peratom(); - compute[i]->invoked_flag |= Compute::INVOKED_PERATOM; - } + if (update->first_update == 0) + error->all(FLERR,"Dump compute cannot be invoked before first run"); + for (i = 0; i < ncompute; i++) { + if (!(compute[i]->invoked_flag & Compute::INVOKED_PERATOM)) { + compute[i]->compute_peratom(); + compute[i]->invoked_flag |= Compute::INVOKED_PERATOM; } } } diff --git a/src/dump_custom.cpp b/src/dump_custom.cpp index 415bc4c7f0..517956caf1 100644 --- a/src/dump_custom.cpp +++ b/src/dump_custom.cpp @@ -556,21 +556,15 @@ int DumpCustom::count() } // invoke Computes for per-atom quantities - // only if within a run or minimize - // else require that computes are current - // this prevents a compute from being invoked by the WriteDump class + // cannot invoke before first run, otherwise invoke if necessary if (ncompute) { - if (update->whichflag == 0) { - for (i = 0; i < ncompute; i++) - if (compute[i]->invoked_peratom != update->ntimestep) - error->all(FLERR,"Compute used in dump between runs is not current"); - } else { - for (i = 0; i < ncompute; i++) { - if (!(compute[i]->invoked_flag & Compute::INVOKED_PERATOM)) { - compute[i]->compute_peratom(); - compute[i]->invoked_flag |= Compute::INVOKED_PERATOM; - } + if (update->first_update == 0) + error->all(FLERR,"Dump compute cannot be invoked before first run"); + for (i = 0; i < ncompute; i++) { + if (!(compute[i]->invoked_flag & Compute::INVOKED_PERATOM)) { + compute[i]->compute_peratom(); + compute[i]->invoked_flag |= Compute::INVOKED_PERATOM; } } } diff --git a/src/dump_grid.cpp b/src/dump_grid.cpp index 2ca4f6c5d4..056cac1095 100644 --- a/src/dump_grid.cpp +++ b/src/dump_grid.cpp @@ -522,21 +522,15 @@ int DumpGrid::count() } // invoke Computes for per-grid quantities - // only if within a run or minimize - // else require that computes are current - // this prevents a compute from being invoked by the WriteDump class + // cannot invoke before first run, otherwise invoke if necessary if (ncompute) { - if (update->whichflag == 0) { - for (i = 0; i < ncompute; i++) - if (compute[i]->invoked_pergrid != update->ntimestep) - error->all(FLERR,"Compute {} used in dump between runs is not current", compute[i]->id); - } else { - for (i = 0; i < ncompute; i++) { - if (!(compute[i]->invoked_flag & Compute::INVOKED_PERGRID)) { - compute[i]->compute_pergrid(); - compute[i]->invoked_flag |= Compute::INVOKED_PERGRID; - } + if (update->first_update == 0) + error->all(FLERR,"Dump compute cannot be invoked before first run"); + for (i = 0; i < ncompute; i++) { + if (!(compute[i]->invoked_flag & Compute::INVOKED_PERGRID)) { + compute[i]->compute_pergrid(); + compute[i]->invoked_flag |= Compute::INVOKED_PERGRID; } } } diff --git a/src/dump_image.cpp b/src/dump_image.cpp index aea052046e..ff1c540d3f 100644 --- a/src/dump_image.cpp +++ b/src/dump_image.cpp @@ -664,20 +664,14 @@ void DumpImage::write() } // invoke Compute for per-grid quantities - // only if within a run or minimize - // else require the compute is current - // this prevents the compute from being invoked by the WriteDump class + // cannot invoke before first run, otherwise invoke if necessary if (grid_compute) { - if (update->whichflag == 0) { - if (grid_compute->invoked_pergrid != update->ntimestep) - error->all(FLERR,"Grid compute {} used in dump image between runs is not current", - grid_compute->id); - } else { - if (!(grid_compute->invoked_flag & Compute::INVOKED_PERGRID)) { - grid_compute->compute_pergrid(); - grid_compute->invoked_flag |= Compute::INVOKED_PERGRID; - } + if (update->first_update == 0) + error->all(FLERR,"Grid compute used in dump image cannot be invoked before first run"); + if (!(grid_compute->invoked_flag & Compute::INVOKED_PERGRID)) { + grid_compute->compute_pergrid(); + grid_compute->invoked_flag |= Compute::INVOKED_PERGRID; } } diff --git a/src/dump_local.cpp b/src/dump_local.cpp index 9c18b7f94f..097589ea41 100644 --- a/src/dump_local.cpp +++ b/src/dump_local.cpp @@ -325,21 +325,15 @@ int DumpLocal::count() int i; // invoke Computes for local quantities - // only if within a run or minimize - // else require that computes are current - // this prevents a compute from being invoked by the WriteDump class + // cannot invoke before first run, otherwise invoke if necessary if (ncompute) { - if (update->whichflag == 0) { - for (i = 0; i < ncompute; i++) - if (compute[i]->invoked_local != update->ntimestep) - error->all(FLERR,"Compute used in dump between runs is not current"); - } else { - for (i = 0; i < ncompute; i++) { - if (!(compute[i]->invoked_flag & Compute::INVOKED_LOCAL)) { - compute[i]->compute_local(); - compute[i]->invoked_flag |= Compute::INVOKED_LOCAL; - } + if (update->first_update == 0) + error->all(FLERR,"Dump compute cannot be invoked before first run"); + for (i = 0; i < ncompute; i++) { + if (!(compute[i]->invoked_flag & Compute::INVOKED_LOCAL)) { + compute[i]->compute_local(); + compute[i]->invoked_flag |= Compute::INVOKED_LOCAL; } } } diff --git a/src/thermo.cpp b/src/thermo.cpp index 302bf566d2..0503018a3a 100644 --- a/src/thermo.cpp +++ b/src/thermo.cpp @@ -1118,7 +1118,7 @@ int Thermo::add_variable(const char *id) } /* ---------------------------------------------------------------------- - check whether temperature compute is defined, available, and current + check whether temperature compute is defined, active, and needs invoking ------------------------------------------------------------------------- */ void Thermo::check_temp(const std::string &keyword) @@ -1126,18 +1126,16 @@ void Thermo::check_temp(const std::string &keyword) if (!temperature) error->all(FLERR, "Thermo keyword {} in variable requires thermo to use/init temperature", keyword); - if (update->whichflag == 0) { - if (temperature->invoked_scalar != update->ntimestep) - error->all(FLERR, "Compute {} {} used in variable thermo keyword between runs is not current", - temperature->style, temperature->id); - } else if (!(temperature->invoked_flag & Compute::INVOKED_SCALAR)) { + if (update->first_update == 0) + error->all(FLERR,"Thermo keyword {} cannot be invoked before first run",keyword); + if (!(temperature->invoked_flag & Compute::INVOKED_SCALAR)) { temperature->compute_scalar(); temperature->invoked_flag |= Compute::INVOKED_SCALAR; } } /* ---------------------------------------------------------------------- - check whether potential energy compute is defined, available, and current + check whether potential energy compute is defined, active, and needs invoking ------------------------------------------------------------------------- */ void Thermo::check_pe(const std::string &keyword) @@ -1147,47 +1145,41 @@ void Thermo::check_pe(const std::string &keyword) if (!pe) error->all(FLERR, "Thermo keyword {} in variable requires thermo to use/init potential energy", keyword); - if (update->whichflag == 0) { - if (pe->invoked_scalar != update->ntimestep) - error->all(FLERR, "Compute {} {} used in variable thermo keyword between runs is not current", - pe->style, pe->id); - } else { + if (update->first_update == 0) + error->all(FLERR,"Thermo keyword {} cannot be invoked before first run",keyword); + if (!(pe->invoked_flag & Compute::INVOKED_SCALAR)) { pe->compute_scalar(); pe->invoked_flag |= Compute::INVOKED_SCALAR; } } /* ---------------------------------------------------------------------- - check whether scalar pressure compute is defined, available, and current + check whether scalar pressure compute is defined, active, and needs invoking ------------------------------------------------------------------------- */ void Thermo::check_press_scalar(const std::string &keyword) { if (!pressure) error->all(FLERR, "Thermo keyword {} in variable requires thermo to use/init press", keyword); - if (update->whichflag == 0) { - if (pressure->invoked_scalar != update->ntimestep) - error->all(FLERR, "Compute {} {} used in variable thermo keyword between runs is not current", - pressure->style, pressure->id); - } else if (!(pressure->invoked_flag & Compute::INVOKED_SCALAR)) { + if (update->first_update == 0) + error->all(FLERR,"Thermo keyword {} cannot be invoked before first run",keyword); + if (!(pressure->invoked_flag & Compute::INVOKED_SCALAR)) { pressure->compute_scalar(); pressure->invoked_flag |= Compute::INVOKED_SCALAR; } } /* ---------------------------------------------------------------------- - check whether pressure tensor compute is defined, available, and current + check whether tensor pressure compute is defined, active, and needs invoking ------------------------------------------------------------------------- */ void Thermo::check_press_vector(const std::string &keyword) { if (!pressure) error->all(FLERR, "Thermo keyword {} in variable requires thermo to use/init press", keyword); - if (update->whichflag == 0) { - if (pressure->invoked_vector != update->ntimestep) - error->all(FLERR, "Compute {} {} used in variable thermo keyword between runs is not current", - pressure->style, pressure->id); - } else if (!(pressure->invoked_flag & Compute::INVOKED_VECTOR)) { + if (update->first_update == 0) + error->all(FLERR,"Thermo keyword {} cannot be invoked before first run",keyword); + if (!(pressure->invoked_flag & Compute::INVOKED_VECTOR)) { pressure->compute_vector(); pressure->invoked_flag |= Compute::INVOKED_VECTOR; } @@ -1214,8 +1206,6 @@ int Thermo::evaluate_keyword(const std::string &word, double *answer) // invoke a lo-level thermo routine to compute the variable value // if keyword requires a compute, error if thermo doesn't use the compute - // if inbetween runs and needed compute is not current, error - // if in middle of run and needed compute is not current, invoke it // for keywords that use energy (evdwl, ebond, etc): // check if energy was tallied on this timestep and set pe->invoked_flag // this will trigger next timestep for energy tallying via addstep() diff --git a/src/variable.cpp b/src/variable.cpp index b9b3661af8..24b20f41db 100644 --- a/src/variable.cpp +++ b/src/variable.cpp @@ -1440,10 +1440,9 @@ double Variable::evaluate(char *str, Tree **tree, int ivar) if (nbracket == 0 && compute->scalar_flag && lowercase) { - if (update->whichflag == 0) { - if (compute->invoked_scalar != update->ntimestep) - print_var_error(FLERR,"Compute used in variable between runs is not current",ivar); - } else if (!(compute->invoked_flag & Compute::INVOKED_SCALAR)) { + if (update->first_update == 0) + print_var_error(FLERR,"Variable formula compute cannot be invoked before first run",ivar); + if (!(compute->invoked_flag & Compute::INVOKED_SCALAR)) { compute->compute_scalar(); compute->invoked_flag |= Compute::INVOKED_SCALAR; } @@ -1463,10 +1462,9 @@ double Variable::evaluate(char *str, Tree **tree, int ivar) if (index1 > compute->size_vector && compute->size_vector_variable == 0) print_var_error(FLERR,"Variable formula compute vector is accessed out-of-range",ivar,0); - if (update->whichflag == 0) { - if (compute->invoked_vector != update->ntimestep) - print_var_error(FLERR,"Compute used in variable between runs is not current",ivar); - } else if (!(compute->invoked_flag & Compute::INVOKED_VECTOR)) { + if (update->first_update == 0) + print_var_error(FLERR,"Variable formula compute cannot be invoked before first run",ivar); + if (!(compute->invoked_flag & Compute::INVOKED_VECTOR)) { compute->compute_vector(); compute->invoked_flag |= Compute::INVOKED_VECTOR; } @@ -1490,10 +1488,9 @@ double Variable::evaluate(char *str, Tree **tree, int ivar) print_var_error(FLERR,"Variable formula compute array is accessed out-of-range",ivar,0); if (index2 > compute->size_array_cols) print_var_error(FLERR,"Variable formula compute array is accessed out-of-range",ivar,0); - if (update->whichflag == 0) { - if (compute->invoked_array != update->ntimestep) - print_var_error(FLERR,"Compute used in variable between runs is not current",ivar); - } else if (!(compute->invoked_flag & Compute::INVOKED_ARRAY)) { + if (update->first_update == 0) + print_var_error(FLERR,"Variable formula compute cannot be invoked before first run",ivar); + if (!(compute->invoked_flag & Compute::INVOKED_ARRAY)) { compute->compute_array(); compute->invoked_flag |= Compute::INVOKED_ARRAY; } @@ -1518,10 +1515,9 @@ double Variable::evaluate(char *str, Tree **tree, int ivar) print_var_error(FLERR,"Compute global vector in atom-style variable formula",ivar); if (compute->size_vector == 0) print_var_error(FLERR,"Variable formula compute vector is zero length",ivar); - if (update->whichflag == 0) { - if (compute->invoked_vector != update->ntimestep) - print_var_error(FLERR,"Compute used in variable between runs is not current",ivar); - } else if (!(compute->invoked_flag & Compute::INVOKED_VECTOR)) { + if (update->first_update == 0) + print_var_error(FLERR,"Variable formula compute cannot be invoked before first run",ivar); + if (!(compute->invoked_flag & Compute::INVOKED_VECTOR)) { compute->compute_vector(); compute->invoked_flag |= Compute::INVOKED_VECTOR; } @@ -1543,10 +1539,9 @@ double Variable::evaluate(char *str, Tree **tree, int ivar) print_var_error(FLERR,"Compute global vector in atom-style variable formula",ivar); if (compute->size_array_rows == 0) print_var_error(FLERR,"Variable formula compute array is zero length",ivar); - if (update->whichflag == 0) { - if (compute->invoked_array != update->ntimestep) - print_var_error(FLERR,"Compute used in variable between runs is not current",ivar); - } else if (!(compute->invoked_flag & Compute::INVOKED_ARRAY)) { + if (update->first_update == 0) + print_var_error(FLERR,"Variable formula compute cannot be invoked before first run",ivar); + if (!(compute->invoked_flag & Compute::INVOKED_ARRAY)) { compute->compute_array(); compute->invoked_flag |= Compute::INVOKED_ARRAY; } @@ -1563,10 +1558,9 @@ double Variable::evaluate(char *str, Tree **tree, int ivar) } else if (nbracket == 1 && compute->peratom_flag && compute->size_peratom_cols == 0) { - if (update->whichflag == 0) { - if (compute->invoked_peratom != update->ntimestep) - print_var_error(FLERR,"Compute used in variable between runs is not current",ivar); - } else if (!(compute->invoked_flag & Compute::INVOKED_PERATOM)) { + if (update->first_update == 0) + print_var_error(FLERR,"Variable formula compute cannot be invoked before first run",ivar); + if (!(compute->invoked_flag & Compute::INVOKED_PERATOM)) { compute->compute_peratom(); compute->invoked_flag |= Compute::INVOKED_PERATOM; } @@ -1581,10 +1575,9 @@ double Variable::evaluate(char *str, Tree **tree, int ivar) if (index2 > compute->size_peratom_cols) print_var_error(FLERR,"Variable formula compute array is accessed out-of-range",ivar,0); - if (update->whichflag == 0) { - if (compute->invoked_peratom != update->ntimestep) - print_var_error(FLERR,"Compute used in variable between runs is not current",ivar); - } else if (!(compute->invoked_flag & Compute::INVOKED_PERATOM)) { + if (update->first_update == 0) + print_var_error(FLERR,"Variable formula compute cannot be invoked before first run",ivar); + if (!(compute->invoked_flag & Compute::INVOKED_PERATOM)) { compute->compute_peratom(); compute->invoked_flag |= Compute::INVOKED_PERATOM; } @@ -1605,10 +1598,9 @@ double Variable::evaluate(char *str, Tree **tree, int ivar) print_var_error(FLERR,"Per-atom compute in equal-style variable formula",ivar); if (treetype == VECTOR) print_var_error(FLERR,"Per-atom compute in vector-style variable formula",ivar); - if (update->whichflag == 0) { - if (compute->invoked_peratom != update->ntimestep) - print_var_error(FLERR,"Compute used in variable between runs is not current",ivar); - } else if (!(compute->invoked_flag & Compute::INVOKED_PERATOM)) { + if (update->first_update == 0) + print_var_error(FLERR,"Variable formula compute cannot be invoked before first run",ivar); + if (!(compute->invoked_flag & Compute::INVOKED_PERATOM)) { compute->compute_peratom(); compute->invoked_flag |= Compute::INVOKED_PERATOM; } @@ -1630,10 +1622,9 @@ double Variable::evaluate(char *str, Tree **tree, int ivar) print_var_error(FLERR,"Per-atom compute in vector-style variable formula",ivar); if (index1 > compute->size_peratom_cols) print_var_error(FLERR,"Variable formula compute array is accessed out-of-range",ivar,0); - if (update->whichflag == 0) { - if (compute->invoked_peratom != update->ntimestep) - print_var_error(FLERR,"Compute used in variable between runs is not current",ivar); - } else if (!(compute->invoked_flag & Compute::INVOKED_PERATOM)) { + if (update->first_update == 0) + print_var_error(FLERR,"Variable formula compute cannot be invoked before first run",ivar); + if (!(compute->invoked_flag & Compute::INVOKED_PERATOM)) { compute->compute_peratom(); compute->invoked_flag |= Compute::INVOKED_PERATOM; } @@ -4050,10 +4041,9 @@ int Variable::special_function(char *word, char *contents, Tree **tree, Tree **t print_var_error(FLERR,mesg,ivar); } if (index == 0 && compute->vector_flag) { - if (update->whichflag == 0) { - if (compute->invoked_vector != update->ntimestep) - print_var_error(FLERR,"Compute used in variable between runs is not current",ivar); - } else if (!(compute->invoked_flag & Compute::INVOKED_VECTOR)) { + if (update->first_update == 0) + print_var_error(FLERR,"Variable formula compute cannot be invoked before first run",ivar); + if (!(compute->invoked_flag & Compute::INVOKED_VECTOR)) { compute->compute_vector(); compute->invoked_flag |= Compute::INVOKED_VECTOR; } @@ -4062,10 +4052,9 @@ int Variable::special_function(char *word, char *contents, Tree **tree, Tree **t } else if (index && compute->array_flag) { if (index > compute->size_array_cols) print_var_error(FLERR,"Variable formula compute array is accessed out-of-range",ivar,0); - if (update->whichflag == 0) { - if (compute->invoked_array != update->ntimestep) - print_var_error(FLERR,"Compute used in variable between runs is not current",ivar); - } else if (!(compute->invoked_flag & Compute::INVOKED_ARRAY)) { + if (update->first_update == 0) + print_var_error(FLERR,"Variable formula compute cannot be invoked before first run",ivar); + if (!(compute->invoked_flag & Compute::INVOKED_ARRAY)) { compute->compute_array(); compute->invoked_flag |= Compute::INVOKED_ARRAY; } From 200f740c0690914d5ea8f8dc10caf363284c6c4a Mon Sep 17 00:00:00 2001 From: Steve Plimpton Date: Mon, 8 May 2023 09:48:27 -0600 Subject: [PATCH 2/8] update variable doc page to explain new behavior --- doc/src/variable.rst | 208 ++++++++++++++++--------------------------- 1 file changed, 77 insertions(+), 131 deletions(-) diff --git a/doc/src/variable.rst b/doc/src/variable.rst index 8bd33218ac..d594b89859 100644 --- a/doc/src/variable.rst +++ b/doc/src/variable.rst @@ -1285,18 +1285,19 @@ with a leading $ sign (e.g. $x or ${abc}) versus with a leading "v\_" (e.g. v_x or v_abc). The former can be used in any input script command, including a variable command. The input script parser evaluates the reference variable immediately and substitutes its value -into the command. As explained on the :doc:`Commands parse ` doc page, you can also use un-named -"immediate" variables for this purpose. For example, a string like -this $((xlo+xhi)/2+sqrt(v_area)) in an input script command evaluates -the string between the parenthesis as an equal-style variable formula. +into the command. As explained on the :doc:`Commands parse +` doc page, you can also use un-named "immediate" +variables for this purpose. For example, a string like this +$((xlo+xhi)/2+sqrt(v_area)) in an input script command evaluates the +string between the parenthesis as an equal-style variable formula. Referencing a variable with a leading "v\_" is an optional or required -kind of argument for some commands (e.g. the :doc:`fix ave/chunk ` or :doc:`dump custom ` or -:doc:`thermo_style ` commands) if you wish it to evaluate -a variable periodically during a run. It can also be used in a -variable formula if you wish to reference a second variable. The -second variable will be evaluated whenever the first variable is -evaluated. +kind of argument for some commands (e.g. the :doc:`fix ave/chunk +` or :doc:`dump custom ` or :doc:`thermo_style +` commands) if you wish it to evaluate a variable +periodically during a run. It can also be used in a variable formula +if you wish to reference a second variable. The second variable will +be evaluated whenever the first variable is evaluated. As an example, suppose you use this command in your input script to define the variable "v" as @@ -1309,8 +1310,9 @@ before a run where the simulation box size changes. You might think this will assign the initial volume to the variable "v". That is not the case. Rather it assigns a formula which evaluates the volume (using the thermo_style keyword "vol") to the variable "v". If you -use the variable "v" in some other command like :doc:`fix ave/time ` then the current volume of the box will be -evaluated continuously during the run. +use the variable "v" in some other command like :doc:`fix ave/time +` then the current volume of the box will be evaluated +continuously during the run. If you want to store the initial volume of the system, you can do it this way: @@ -1347,132 +1349,75 @@ will occur when the formula for "vratio" is evaluated later. Variable Accuracy """"""""""""""""" -Obviously, LAMMPS attempts to evaluate variables containing formulas -(\ *equal* and *atom* style variables) accurately whenever the -evaluation is performed. Depending on what is included in the -formula, this may require invoking a :doc:`compute `, either -directly or indirectly via a thermo keyword, or accessing a value -previously calculated by a compute, or accessing a value calculated -and stored by a :doc:`fix `. If the compute is one that calculates -the pressure or energy of the system, then these quantities need to be -tallied during the evaluation of the interatomic potentials (pair, -bond, etc) on timesteps that the variable will need the values. +Obviously, LAMMPS attempts to evaluate variables which contain +formulas (\ *equal* and *vector* and *atom* style variables) +accurately whenever the evaluation is performed. Depending on what is +included in the formula, this may require invoking a :doc:`compute +`, either directly or indirectly via a thermo keyword, or +accessing a value previously calculated by a compute, or accessing a +value calculated and stored by a :doc:`fix `. If the compute is +one that calculates the energy or pressure of the system, then the +corresponding energy or virial quantities need to be tallied during +the evaluation of the interatomic potentials (pair, bond, etc) on any +timestep that the variable needs the tallies. An input script can +also request variables be evaluated before or after or in between +runs, e.g. by including them in a :doc:`print ` command. -LAMMPS keeps track of all of this during a :doc:`run ` or :doc:`energy minimization `. An error will be generated if you -attempt to evaluate a variable on timesteps when it cannot produce -accurate values. For example, if a :doc:`thermo_style custom ` command prints a variable which accesses -values stored by a :doc:`fix ave/time ` command and the -timesteps on which thermo output is generated are not multiples of the -averaging frequency used in the fix command, then an error will occur. +LAMMPS keeps track of all of this as it performs a doc:`run ` or +:doc:`minimize ` simulation, as well as in between +simulations. An error will be generated if you attempt to evaluate a +variable when LAMMPS knows it cannot produce accurate values. For +example, if a :doc:`thermo_style custom ` command prints +a variable which accesses values stored by a :doc:`fix ave/time +` command and the timesteps on which thermo output is +generated are not multiples of the averaging frequency used in the fix +command, then an error will occur. -An input script can also request variables be evaluated before or -after or in between runs, e.g. by including them in a -:doc:`print ` command. In this case, if a compute is needed to -evaluate a variable (either directly or indirectly), LAMMPS will not -invoke the compute, but it will use a value previously calculated by -the compute, and can do this only if it was invoked on the current -timestep. Fixes will always provide a quantity needed by a variable, -but the quantity may or may not be current. This leads to one of -three kinds of behavior: +However, there are two special cases to be aware when a variable +requires invocation of a compute (directly or indirectly). The first +is if the variable is evaluated before the first doc:`run ` or +:doc:`minimize ` command in the input script. In this case, +LAMMPS will generate an error. This is because many computes require +initializations which have not yet taken place. One example is the +calculation of degrees of freedom for temperature computes. Another +example are the computes mentioned above which require tallying of +energy or virial quantities; these values are not tallied until the +first simulation begins. -(1) The variable may be evaluated accurately. If it contains -references to a compute or fix, and these values were calculated on -the last timestep of a preceding run, then they will be accessed and -used by the variable and the result will be accurate. +The second special case is when a variable that depends on a compute +is evaluated in between doc:`run ` or :doc:`minimize ` +commands. It is possible for other input script commands issued +following the previous run, but before the variable is evaluated, to +change the system. For example, the doc:`delete_atoms ` +command could be used to remove atoms. Since the compute will not +re-initialize itself until the next simulation or it may depend on +energy/virial computations performed before the system was changed, it +will potentially generate an incorrect answer when evaluated. Note +that LAMMPS will not generate an error in this case; the evaluated +variable may simply be incorrect. -(2) LAMMPS may not be able to evaluate the variable and will generate -an error message stating so. For example, if the variable requires a -quantity from a :doc:`compute ` that has not been invoked on -the current timestep, LAMMPS will generate an error. This means, for -example, that such a variable cannot be evaluated before the first run -has occurred. Likewise, in between runs, a variable containing a -compute cannot be evaluated unless the compute was invoked on the last -timestep of the preceding run, e.g. by thermodynamic output. - -One way to get around this problem is to perform a 0-timestep run -before using the variable. For example, these commands +The way to get around both of these special cases is to perform a +0-timestep run before evaluating the variable. For example, these +commands .. code-block:: LAMMPS - variable t equal temp - print "Initial temperature = $t" + # delete_atoms random fraction 0.5 yes all NULL 49839 + # run 0 + variable t equal temp # this thermo keyword invokes a temperature compute + print "Temperature of system = $t" run 1000 -will generate an error if the run is the first run specified in the -input script, because generating a value for the "t" variable requires -a compute for calculating the temperature to be invoked. +will generate an error if the "run 1000" command is the first +simulation in the input script. If there were a previous run, these +commands will print the correct temperature of the system. But if the +:doc:`delete_atoms ` command is uncommented, the printed +temperature will be incorrect, because information stored by +temperature compute is no longer valid. -However, this sequence of commands would be fine: - -.. code-block:: LAMMPS - - run 0 - variable t equal temp - print "Initial temperature = $t" - run 1000 - -The 0-timestep run initializes and invokes various computes, including -the one for temperature, so that the value it stores is current and -can be accessed by the variable "t" after the run has completed. Note -that a 0-timestep run does not alter the state of the system, so it -does not change the input state for the 1000-timestep run that -follows. Also note that the 0-timestep run must actually use and -invoke the compute in question (e.g. via :doc:`thermo ` or -:doc:`dump ` output) in order for it to enable the compute to be -used in a variable after the run. Thus if you are trying to print a -variable that uses a compute you have defined, you can ensure it is -invoked on the last timestep of the preceding run by including it in -thermodynamic output. - -Unlike computes, :doc:`fixes ` will never generate an error if -their values are accessed by a variable in between runs. They always -return some value to the variable. However, the value may not be what -you expect if the fix has not yet calculated the quantity of interest -or it is not current. For example, the :doc:`fix indent ` -command stores the force on the indenter. But this is not computed -until a run is performed. Thus if a variable attempts to print this -value before the first run, zeroes will be output. Again, performing -a 0-timestep run before printing the variable has the desired effect. - -(3) The variable may be evaluated incorrectly and LAMMPS may have no -way to detect this has occurred. Consider the following sequence of -commands: - -.. code-block:: LAMMPS - - pair_coeff 1 1 1.0 1.0 - run 1000 - pair_coeff 1 1 1.5 1.0 - variable e equal pe - print "Final potential energy = $e" - -The first run is performed using one setting for the pairwise -potential defined by the :doc:`pair_style ` and -:doc:`pair_coeff ` commands. The potential energy is -evaluated on the final timestep and stored by the :doc:`compute pe -` compute (this is done by the :doc:`thermo_style -` command). Then a pair coefficient is changed, -altering the potential energy of the system. When the potential -energy is printed via the "e" variable, LAMMPS will use the potential -energy value stored by the :doc:`compute pe ` compute, -thinking it is current. There are many other commands which could -alter the state of the system between runs, causing a variable to -evaluate incorrectly. - -The solution to this issue is the same as for case (2) above, namely -perform a 0-timestep run before the variable is evaluated to ensure -the system is up-to-date. For example, this sequence of commands -would print a potential energy that reflected the changed pairwise -coefficient: - -.. code-block:: LAMMPS - - pair_coeff 1 1 1.0 1.0 - run 1000 - pair_coeff 1 1 1.5 1.0 - run 0 - variable e equal pe - print "Final potential energy = $e" +Both these issues are resolved, if the "run 0" command is uncommented. +This is because the "run 0" simulation will initialize (or +re-initialize) the temperature compute correctly. ---------- @@ -1482,11 +1427,12 @@ Restrictions Indexing any formula element by global atom ID, such as an atom value, requires the :doc:`atom style ` to use a global mapping in order to look up the vector indices. By default, only atom styles -with molecular information create global maps. The :doc:`atom_modify map ` command can override the default, e.g. for +with molecular information create global maps. The :doc:`atom_modify +map ` command can override the default, e.g. for atomic-style atom styles. -All *universe*\ - and *uloop*\ -style variables defined in an input script -must have the same number of values. +All *universe*\ - and *uloop*\ -style variables defined in an input +script must have the same number of values. Related commands """""""""""""""" From f015aaff84d91fc8bf627e5d5fbb266c1970a1fe Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 9 May 2023 02:41:21 -0400 Subject: [PATCH 3/8] compile time compatibility with swig 4.1 --- tools/swig/lammps.i | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/swig/lammps.i b/tools/swig/lammps.i index 64f120bfb4..b7414573ba 100644 --- a/tools/swig/lammps.i +++ b/tools/swig/lammps.i @@ -18,7 +18,9 @@ %pointer_cast(void *, double *, void_p_to_double_p); %pointer_cast(void *, double **, void_p_to_double_2d_p); +#if !defined(SWIGLUA) %cstring_output_maxsize(char *buffer, int buf_size); +#endif %{ From d2361ffe7d3460a010802a8fddbfe5c9f2d3e7f3 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 10 May 2023 17:23:34 -0400 Subject: [PATCH 4/8] add workaround for reset_atoms image --- src/reset_atoms_image.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/reset_atoms_image.cpp b/src/reset_atoms_image.cpp index 56a1bf9f99..953c77f357 100644 --- a/src/reset_atoms_image.cpp +++ b/src/reset_atoms_image.cpp @@ -22,6 +22,7 @@ #include "group.h" #include "input.h" #include "modify.h" +#include "update.h" #include "variable.h" #include @@ -62,7 +63,10 @@ void ResetAtomsImage::command(int narg, char **arg) // initialize system since comm->borders() will be invoked + int old_whichflag = update->whichflag; + update->whichflag = 1; lmp->init(); + update->whichflag = old_whichflag; // setup domain, communication // exchange will clear map, borders will reset From a92e0030e81739b745c187bf5b92670daa975571 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 10 May 2023 17:24:29 -0400 Subject: [PATCH 5/8] whitespace --- doc/src/variable.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/src/variable.rst b/doc/src/variable.rst index d594b89859..26c5f0d445 100644 --- a/doc/src/variable.rst +++ b/doc/src/variable.rst @@ -1402,7 +1402,7 @@ commands .. code-block:: LAMMPS - # delete_atoms random fraction 0.5 yes all NULL 49839 + # delete_atoms random fraction 0.5 yes all NULL 49839 # run 0 variable t equal temp # this thermo keyword invokes a temperature compute print "Temperature of system = $t" From 54b2a5c17af4ef5818cfa80d51851862f1f24a41 Mon Sep 17 00:00:00 2001 From: Steve Plimpton Date: Fri, 12 May 2023 09:04:42 -0600 Subject: [PATCH 6/8] allow internal variables in reset_atoms to be used before first run --- src/reset_atoms_image.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/reset_atoms_image.cpp b/src/reset_atoms_image.cpp index 953c77f357..d6f5acdeee 100644 --- a/src/reset_atoms_image.cpp +++ b/src/reset_atoms_image.cpp @@ -63,10 +63,7 @@ void ResetAtomsImage::command(int narg, char **arg) // initialize system since comm->borders() will be invoked - int old_whichflag = update->whichflag; - update->whichflag = 1; lmp->init(); - update->whichflag = old_whichflag; // setup domain, communication // exchange will clear map, borders will reset @@ -96,6 +93,13 @@ void ResetAtomsImage::command(int narg, char **arg) "c_ifmax_r_i_f[*] c_ifmin_r_i_f[*]"); // trigger computes + // need to ensure update->first_update = 1, even if prior to first run/minimize + // b/c variables internal to this command are evaulated which invoke computes + // error will be triggered unless first_update = 1 + // reset update->first_update when done + + int first_update_saved = update->first_update; + update->first_update = 1; frags->compute_peratom(); chunk->compute_peratom(); @@ -104,6 +108,8 @@ void ResetAtomsImage::command(int narg, char **arg) ifmax->compute_array(); cdist->compute_peratom(); + update->first_update = first_update_saved; + // reset image flags for atoms in group const int *const mask = atom->mask; From 9ef4d7f320d43941fbd29bc11277af9f6618d7b4 Mon Sep 17 00:00:00 2001 From: Steve Plimpton Date: Fri, 12 May 2023 09:06:29 -0600 Subject: [PATCH 7/8] allow internal variables in reset_atoms to be used before first run --- src/reset_atoms_image.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/reset_atoms_image.cpp b/src/reset_atoms_image.cpp index d6f5acdeee..b383f4a355 100644 --- a/src/reset_atoms_image.cpp +++ b/src/reset_atoms_image.cpp @@ -93,10 +93,11 @@ void ResetAtomsImage::command(int narg, char **arg) "c_ifmax_r_i_f[*] c_ifmin_r_i_f[*]"); // trigger computes - // need to ensure update->first_update = 1, even if prior to first run/minimize - // b/c variables internal to this command are evaulated which invoke computes - // error will be triggered unless first_update = 1 - // reset update->first_update when done + // need to ensure update->first_update = 1 + // to allow this input script command prior to first run/minimize + // this is b/c internal variables are evaulated which invoke computes + // that will trigger an error unless first_update = 1 + // reset update->first_update when done int first_update_saved = update->first_update; update->first_update = 1; From f1a3d0ce5a42227d85e59b3209f4dc981245745a Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 12 May 2023 11:14:34 -0400 Subject: [PATCH 8/8] whitespace --- src/reset_atoms_image.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/reset_atoms_image.cpp b/src/reset_atoms_image.cpp index b383f4a355..d39ea0fec1 100644 --- a/src/reset_atoms_image.cpp +++ b/src/reset_atoms_image.cpp @@ -98,7 +98,7 @@ void ResetAtomsImage::command(int narg, char **arg) // this is b/c internal variables are evaulated which invoke computes // that will trigger an error unless first_update = 1 // reset update->first_update when done - + int first_update_saved = update->first_update; update->first_update = 1;