diff --git a/doc/src/Commands_parse.rst b/doc/src/Commands_parse.rst index efc3c5030d..497bc9e5d3 100644 --- a/doc/src/Commands_parse.rst +++ b/doc/src/Commands_parse.rst @@ -77,18 +77,19 @@ LAMMPS: so that you do not have to define (or discard) a temporary variable, "X" in this case. - Additionally, the "immediate" variable expression may be followed by - a colon, followed by a C-style format string, e.g. ":%f" or ":%.10g". - The format string must be appropriate for a double-precision - floating-point value. The format string is used to output the result - of the variable expression evaluation. If a format string is not - specified a high-precision "%.20g" is used as the default. + Additionally, the entire "immediate" variable expression may be + followed by a colon, followed by a C-style format string, + e.g. ":%f" or ":%.10g". The format string must be appropriate for + a double-precision floating-point value. The format string is used + to output the result of the variable expression evaluation. If a + format string is not specified, a high-precision "%.20g" is used as + the default format. This can be useful for formatting print output to a desired precision: .. code-block:: LAMMPS - print "Final energy per atom: $(pe/atoms:%10.3f) eV/atom" + print "Final energy per atom: $(v_ke_per_atom+v_pe_per_atom:%10.3f) eV/atom" Note that neither the curly-bracket or immediate form of variables can contain nested $ characters for other variables to substitute diff --git a/doc/src/fix_print.rst b/doc/src/fix_print.rst index c59cc4161d..ab021ab8ab 100644 --- a/doc/src/fix_print.rst +++ b/doc/src/fix_print.rst @@ -39,19 +39,35 @@ Description Print a text string every N steps during a simulation run. This can be used for diagnostic purposes or as a debugging tool to monitor some quantity during a run. The text string must be a single argument, so -it should be enclosed in double quotes if it is more than one word. -If it contains variables it must be enclosed in double quotes to -insure they are not evaluated when the input script line is read, but -will instead be evaluated each time the string is printed. +it should be enclosed in single or double quotes if it is more than +one word. If it contains variables it must be enclosed in double +quotes to insure they are not evaluated when the input script line is +read, but will instead be evaluated each time the string is printed. -Instead of a numeric value, N can be specified as an :doc:`equal-style 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** timestep at which the +.. note:: + + As discussed on the :doc:`Commands parse ` doc + page, the text string can use "immediate" variables, specified as + $(formula) with parenthesis, where the numeric formula has the same + syntax as equal-style variables described on the :doc:`variable + ` doc page. This is a convenient way to evaluate a + formula immediately without using the variable command to define a + named variable and then use that variable in the text string. The + formula can include a trailing colon and format string which + determines the precision with which the numeric value is output. + This is also explained on the :doc:`Commands parse + ` doc page. + +Instead of a numeric value, N can be specified as an :doc:`equal-style +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** timestep at which the string will be written out. On that timestep, the variable will be -evaluated again to determine the next timestep, etc. -Thus the variable should return timestep values. See the stagger() -and logfreq() and stride() math functions for :doc:`equal-style variables `, as examples of useful functions to use in -this context. For example, the following commands will print output at +evaluated again to determine the next timestep, etc. Thus the +variable should return timestep values. See the stagger() and +logfreq() and stride() math functions for :doc:`equal-style variables +`, as examples of useful functions to use in this +context. For example, the following commands will print output at timesteps 10,20,30,100,200,300,1000,2000,etc: .. code-block:: LAMMPS @@ -61,12 +77,12 @@ timesteps 10,20,30,100,200,300,1000,2000,etc: The specified group-ID is ignored by this fix. -See the :doc:`variable ` command for a description of *equal* -style variables which are the most useful ones to use with the fix -print command, since they are evaluated afresh each timestep that the -fix print line is output. Equal-style variables calculate formulas -involving mathematical operations, atom properties, group properties, -thermodynamic properties, global values calculated by a +See the :doc:`variable ` command for a description of +*equal* style variables which are the most useful ones to use with the +fix print command, since they are evaluated afresh each timestep that +the fix print line is output. Equal-style variables calculate +formulas involving mathematical operations, atom properties, group +properties, thermodynamic properties, global values calculated by a :doc:`compute ` or :doc:`fix `, or references to other :doc:`variables `. @@ -92,11 +108,13 @@ where ID is replaced with the fix-ID. Restart, fix_modify, output, run start/stop, minimize info """"""""""""""""""""""""""""""""""""""""""""""""""""""""""" -No information about this fix is written to :doc:`binary restart files `. None of the :doc:`fix_modify ` options -are relevant to this fix. No global or per-atom quantities are stored -by this fix for access by various :doc:`output commands `. +No information about this fix is written to :doc:`binary restart files +`. None of the :doc:`fix_modify ` options are +relevant to this fix. No global or per-atom quantities are stored by +this fix for access by various :doc:`output commands `. No parameter of this fix can be used with the *start/stop* keywords of -the :doc:`run ` command. This fix is not invoked during :doc:`energy minimization `. +the :doc:`run ` command. This fix is not invoked during +:doc:`energy minimization `. Restrictions """""""""""" diff --git a/doc/src/print.rst b/doc/src/print.rst index b9ed8555fa..1211fdd569 100644 --- a/doc/src/print.rst +++ b/doc/src/print.rst @@ -46,6 +46,20 @@ lines of output, the string can be enclosed in triple quotes, as in the last example above. If the text string contains variables, they will be evaluated and their current values printed. +.. note:: + + As discussed on the :doc:`Commands parse ` doc + page, the text string can use "immediate" variables, specified as + $(formula) with parenthesis, where the numeric formula has the same + syntax as equal-style variables described on the :doc:`variable + ` doc page. This is a convenient way to evaluate a + formula immediately without using the variable command to define a + named variable and then use that variable in the text string. The + formula can include a trailing colon and format string which + determines the precision with which the numeric value is output. + This is also explained on the :doc:`Commands parse + ` doc page. + If the *file* or *append* keyword is used, a filename is specified to which the output will be written. If *file* is used, then the filename is overwritten if it already exists. If *append* is used, diff --git a/doc/src/variable.rst b/doc/src/variable.rst index d0ad568cf1..8ef3e4e82f 100644 --- a/doc/src/variable.rst +++ b/doc/src/variable.rst @@ -11,7 +11,7 @@ Syntax variable name style args ... * name = name of variable to define -* style = *delete* or *index* or *loop* or *world* or *universe* or *uloop* or *string* or *format* or *getenv* or *file* or *atomfile* or *python* or *internal* or *equal* or *vector* or *atom* +* style = *delete* or *index* or *loop* or *world* or *universe* or *uloop* or *string* or *format* or *getenv* or *file* or *atomfile* or *python* or *timer* or *internal* or *equal* or *vector* or *atom* .. parsed-literal:: @@ -42,6 +42,7 @@ Syntax *file* arg = filename *atomfile* arg = filename *python* arg = function + *timer* arg = no arguments *internal* arg = numeric value *equal* or *vector* or *atom* args = one formula containing numbers, thermo keywords, math operations, group functions, atom values and vectors, compute/fix/variable references numbers = 0.0, 100, -5.4, 2.8e-4, etc @@ -96,6 +97,13 @@ Examples variable str format x %.6g variable x delete +.. code-block:: LAMMPS + + variable start timer + other commands + variable stop timer + print "Elapsed time: $(v_stop-v_start:%.6f)" + Description """"""""""" @@ -108,32 +116,38 @@ part of a new input command. For variable styles that store multiple strings, the :doc:`next ` command can be used to increment which string is assigned to the variable. Variables of style *equal* store a formula which when evaluated produces a single numeric value which -can be output either directly (see the :doc:`print `, :doc:`fix print `, and :doc:`run every ` commands) or as part -of thermodynamic output (see the :doc:`thermo_style ` -command), or used as input to an averaging fix (see the :doc:`fix ave/time ` command). Variables of style *vector* -store a formula which produces a vector of such values which can be -used as input to various averaging fixes, or elements of which can be -part of thermodynamic output. Variables of style *atom* store a -formula which when evaluated produces one numeric value per atom which -can be output to a dump file (see the :doc:`dump custom ` command) -or used as input to an averaging fix (see the :doc:`fix ave/chunk ` and :doc:`fix ave/atom ` -commands). Variables of style *atomfile* can be used anywhere in an -input script that atom-style variables are used; they get their -per-atom values from a file rather than from a formula. Variables of -style *python* can be hooked to Python functions using code you -provide, so that the variable gets its value from the evaluation of -the Python code. Variables of style *internal* are used by a few -commands which set their value directly. +can be output either directly (see the :doc:`print `, :doc:`fix +print `, and :doc:`run every ` commands) or as part of +thermodynamic output (see the :doc:`thermo_style ` +command), or used as input to an averaging fix (see the :doc:`fix +ave/time ` command). Variables of style *vector* store +a formula which produces a vector of such values which can be used as +input to various averaging fixes, or elements of which can be part of +thermodynamic output. Variables of style *atom* store a formula which +when evaluated produces one numeric value per atom which can be output +to a dump file (see the :doc:`dump custom ` command) or used as +input to an averaging fix (see the :doc:`fix ave/chunk +` and :doc:`fix ave/atom ` commands). +Variables of style *atomfile* can be used anywhere in an input script +that atom-style variables are used; they get their per-atom values +from a file rather than from a formula. Variables of style *python* +can be hooked to Python functions using code you provide, so that the +variable gets its value from the evaluation of the Python code. +Variables of style *internal* are used by a few commands which set +their value directly. .. note:: As discussed on the :doc:`Commands parse ` doc page, an input script can use "immediate" variables, specified as - $(formula) with parenthesis, where the formula has the same syntax as - equal-style variables described on this page. This is a convenient - way to evaluate a formula immediately without using the variable - command to define a named variable and then evaluate that - variable. See below for a more detailed discussion of this feature. + $(formula) with parenthesis, where the numeric formula has the same + syntax as equal-style variables described on this page. This is a + convenient way to evaluate a formula immediately without using the + variable command to define a named variable and then evaluate that + variable. The formula can include a trailing colon and format + string which determines the precision with which the numeric value + is generated. This is also explained on the :doc:`Commands parse + ` doc page. In the discussion that follows, the "name" of the variable is the arbitrary string that is the first argument in the variable command. @@ -160,22 +174,19 @@ simulation. Variables of style *equal* and *vector* and *atom* can be used as inputs to various other commands which evaluate their formulas as -needed, e.g. at different timesteps during a :doc:`run `. +needed, e.g. at different timesteps during a :doc:`run `. In +this context, variables of style *timer* or *internal* or *python* can +be used in place of an equal-style variable, with the following two +caveats. -Variables of style *internal* can be used in place of an equal-style -variable, except by commands that set the value stored by the -internal-style variable. Thus any command that states it can use an -equal-style variable as an argument, can also use an internal-style -variable. This means that when the command evaluates the variable, it -will use the value set (internally) by another command. - -Variables of style *python* can be used in place of an equal-style -variable so long as the associated Python function, as defined by the -:doc:`python ` command, returns a numeric value. Thus any -command that states it can use an equal-style variable as an argument, -can also use such a python-style variable. This means that when the -LAMMPS command evaluates the variable, the Python function will be -executed. +First, internal-style variables can be used except by commands that +set the value stored by the internal variable. When the LAMMPS +command evaluates the internal-style variable, it will use the value +set (internally) by another command. Second, python-style variables +can be used so long as the associated Python function, as defined by +the :doc:`python ` command, returns a numeric value. When the +LAMMPS command evaluates the python-style variable, the Python +function will be executed. .. note:: @@ -271,14 +282,15 @@ N1 <= N2 and N2 >= 0 is required. For the *world* style, one or more strings are specified. There must be one string for each processor partition or "world". LAMMPS can be -run with multiple partitions via the :doc:`-partition command-line switch `. This variable command assigns one string to +run with multiple partitions via the :doc:`-partition command-line +switch `. This variable command assigns one string to each world. All processors in the world are assigned the same string. The next command cannot be used with *equal* style variables, since there is only one value per world. This style of variable is useful when you wish to run different simulations on different partitions, or -when performing a parallel tempering simulation (see the -:doc:`temper ` command), to assign different temperatures to -different partitions. +when performing a parallel tempering simulation (see the :doc:`temper +` command), to assign different temperatures to different +partitions. For the *universe* style, one or more strings are specified. There must be at least as many strings as there are processor partitions or @@ -313,11 +325,12 @@ appropriate for formatting a double-precision floating-point value. The default format is "%.15g". This variable style allows an equal-style variable to be formatted precisely when it is evaluated. -If you simply wish to print a variable value with desired precision to -the screen or logfile via the :doc:`print ` or :doc:`fix print ` commands, you can also do this by specifying an -"immediate" variable with a trailing colon and format string, as part -of the string argument of those commands. This is explained on the -:doc:`Commands parse ` doc page. +Note that if you simply wish to print a variable value with desired +precision to the screen or logfile via the :doc:`print ` or +:doc:`fix print ` commands, you can also do this by +specifying an "immediate" variable with a trailing colon and format +string, as part of the string argument of those commands. This is +explained on the :doc:`Commands parse ` doc page. For the *getenv* style, a single string is assigned to the variable which should be the name of an environment variable. When the @@ -412,14 +425,25 @@ python-style variable can be used in place of an equal-style variable anywhere in an input script, e.g. as an argument to another command that allows for equal-style variables. +For the *timer* style no additional argument is specified. The value +of the variable is set by querying the current elapsed CPU time of the +simulation. This is done at the point in time the variable is defined +in the input script. If a second timer-style variable is also +defined, then a simple formula can be used to calculate the elapsed +time between the two timers, as in the example above. As mentioned +above, timer-style variables can be redefined elsewhere in the input +script, so the same pair of variables can be used in a loop or to time +a series of operations. + For the *internal* style a numeric value is provided. This value will be assigned to the variable until a LAMMPS command sets it to a new value. There are currently only two LAMMPS commands that require *internal* variables as inputs, because they reset them: -:doc:`create_atoms ` and :doc:`fix controller `. As mentioned above, an -internal-style variable can be used in place of an equal-style -variable anywhere else in an input script, e.g. as an argument to -another command that allows for equal-style variables. +:doc:`create_atoms ` and :doc:`fix controller +`. As mentioned above, an internal-style variable can +be used in place of an equal-style variable anywhere else in an input +script, e.g. as an argument to another command that allows for +equal-style variables. ---------- @@ -1383,14 +1407,15 @@ commands: 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. +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 insure diff --git a/src/variable.cpp b/src/variable.cpp index 907b8e661a..7805183424 100644 --- a/src/variable.cpp +++ b/src/variable.cpp @@ -501,20 +501,29 @@ void Variable::set(int narg, char **arg) } // TIMER - // num = listed args, which = 1st value, data = copied args + // stores current MPI_Wtime() as a string + // replace pre-existing var if also style TIMER (allows reset with current time) + // num = 1, for string representation of dvalue, set by retrieve() + // dvalue = numeric initialization via platform::cputime() } else if (strcmp(arg[1],"timer") == 0) { if (narg != 2) error->all(FLERR,"Illegal variable command"); - if (find(arg[0]) >= 0) return; - if (nvar == maxvar) grow(); - style[nvar] = TIMER; - num[nvar] = 1; - which[nvar] = 0; - pad[nvar] = 0; - data[nvar] = new char*[num[nvar]]; - copy(num[nvar],&arg[2],data[nvar]); - - // NOTE: set value to MPI_Wtime() evaulated by proc 0 + int ivar = find(arg[0]); + if (ivar >= 0) { + if (style[ivar] != TIMER) + error->all(FLERR,"Cannot redefine variable as a different style"); + dvalue[ivar] = platform::cputime(); + replaceflag = 1; + } else { + if (nvar == maxvar) grow(); + style[nvar] = TIMER; + num[nvar] = 1; + which[nvar] = 0; + pad[nvar] = 0; + data[nvar] = new char*[num[nvar]]; + data[nvar][0] = new char[VALUELENGTH]; + dvalue[nvar] = platform::cputime(); + } // INTERNAL // replace pre-existing var if also style INTERNAL (allows it to be reset) @@ -540,6 +549,8 @@ void Variable::set(int narg, char **arg) dvalue[nvar] = utils::numeric(FLERR,arg[2],false,lmp); } + // unrecognized variable style + } else error->all(FLERR,"Illegal variable command"); // set name of variable, if not replacing one flagged with replaceflag @@ -626,13 +637,14 @@ int Variable::next(int narg, char **arg) error->all(FLERR,"All variables in next command must have same style"); } - // invalid styles: STRING, EQUAL, WORLD, ATOM, VECTOR, GETENV, - // FORMAT, PYTHON, INTERNAL + // invalid styles: STRING, EQUAL, WORLD, GETENV, ATOM, VECTOR, + // FORMAT, PYTHON, TIMER, INTERNAL int istyle = style[find(arg[0])]; - if (istyle == STRING || istyle == EQUAL || istyle == WORLD || - istyle == GETENV || istyle == ATOM || istyle == VECTOR || - istyle == FORMAT || istyle == PYTHON || istyle == INTERNAL) + if (istyle == STRING || istyle == EQUAL || + istyle == WORLD || istyle == GETENV || istyle == ATOM || + istyle == VECTOR || istyle == FORMAT || istyle == PYTHON || + istyle == TIMER || istyle == INTERNAL) error->all(FLERR,"Invalid variable style with next command"); // if istyle = UNIVERSE or ULOOP, insure all such variables are incremented @@ -810,13 +822,15 @@ void Variable::python_command(int narg, char **arg) } /* ---------------------------------------------------------------------- - return 1 if variable is EQUAL or INTERNAL or PYTHON numeric style, 0 if not + return 1 if variable is EQUAL style, 0 if not + TIMER, INTERNAL, PYTHON qualify as EQUAL style this is checked before call to compute_equal() to return a double ------------------------------------------------------------------------- */ int Variable::equalstyle(int ivar) { - if (style[ivar] == EQUAL || style[ivar] == INTERNAL) return 1; + if (style[ivar] == EQUAL || style[ivar] == TIMER || + style[ivar] == INTERNAL) return 1; if (style[ivar] == PYTHON) { int ifunc = python->variable_match(data[ivar][0],names[ivar],1); if (ifunc < 0) return 0; @@ -941,7 +955,7 @@ char *Variable::retrieve(const char *name) // then the Python class stores the result, query it via long_string() char *strlong = python->long_string(ifunc); if (strlong) str = strlong; - } else if (style[ivar] == INTERNAL) { + } else if (style[ivar] == TIMER || style[ivar] == INTERNAL) { sprintf(data[ivar][0],"%.15g",dvalue[ivar]); str = data[ivar][0]; } else if (style[ivar] == ATOM || style[ivar] == ATOMFILE || @@ -954,7 +968,7 @@ char *Variable::retrieve(const char *name) /* ---------------------------------------------------------------------- return result of equal-style variable evaluation - can be EQUAL or INTERNAL style or PYTHON numeric style + can be EQUAL or TIMER or INTERNAL style or PYTHON numeric style for PYTHON, don't need to check python->variable_match() error return, since caller will have already checked via equalstyle() ------------------------------------------------------------------------- */ @@ -968,6 +982,7 @@ double Variable::compute_equal(int ivar) double value = 0.0; if (style[ivar] == EQUAL) value = evaluate(data[ivar][0],nullptr,ivar); + else if (style[ivar] == TIMER) value = dvalue[ivar]; else if (style[ivar] == INTERNAL) value = dvalue[ivar]; else if (style[ivar] == PYTHON) { int ifunc = python->find(data[ivar][0]);