Merge pull request #3767 from lammps/vector-variable
Vector-style variable enhancements
This commit is contained in:
@ -44,6 +44,20 @@ one word. If it contains variables it must be enclosed in double
|
||||
quotes to ensure they are not evaluated when the input script line is
|
||||
read, but will instead be evaluated each time the string is printed.
|
||||
|
||||
.. versionadded:: TBD
|
||||
|
||||
support for vector style variables
|
||||
|
||||
See the :doc:`variable <variable>` command for a description of
|
||||
*equal* and *vector* style variables which are typically the most
|
||||
useful ones to use with the print command. Equal- and vector-style
|
||||
variables can calculate formulas involving mathematical operations,
|
||||
atom properties, group properties, thermodynamic properties, global
|
||||
values calculated by a :doc:`compute <compute>` or :doc:`fix <fix>`,
|
||||
or references to other :doc:`variables <variable>`. Vector-style
|
||||
variables are printed in a bracketed, comma-separated format,
|
||||
e.g. [1,2,3,4] or [12.5,2,4.6,10.1].
|
||||
|
||||
.. note::
|
||||
|
||||
As discussed on the :doc:`Commands parse <Commands_parse>` doc
|
||||
@ -77,15 +91,6 @@ timesteps 10,20,30,100,200,300,1000,2000,etc:
|
||||
|
||||
The specified group-ID is ignored by this fix.
|
||||
|
||||
See the :doc:`variable <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 <compute>` or :doc:`fix <fix>`, or references to other
|
||||
:doc:`variables <variable>`.
|
||||
|
||||
If the *file* or *append* keyword is used, a filename is specified to
|
||||
which the output generated by this fix will be written. If *file* is
|
||||
used, then the filename is overwritten if it already exists. If
|
||||
|
||||
@ -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.
|
||||
|
||||
.. versionadded:: TBD
|
||||
|
||||
support for vector style variables
|
||||
|
||||
See the :doc:`variable <variable>` command for a description of
|
||||
*equal* and *vector* style variables which are typically the most
|
||||
useful ones to use with the print command. Equal- and vector-style
|
||||
variables can calculate formulas involving mathematical operations,
|
||||
atom properties, group properties, thermodynamic properties, global
|
||||
values calculated by a :doc:`compute <compute>` or :doc:`fix <fix>`,
|
||||
or references to other :doc:`variables <variable>`. Vector-style
|
||||
variables are printed in a bracketed, comma-separated format,
|
||||
e.g. [1,2,3,4] or [12.5,2,4.6,10.1].
|
||||
|
||||
.. note::
|
||||
|
||||
As discussed on the :doc:`Commands parse <Commands_parse>` doc
|
||||
@ -60,6 +74,15 @@ will be evaluated and their current values printed.
|
||||
This is also explained on the :doc:`Commands parse
|
||||
<Commands_parse>` doc page.
|
||||
|
||||
If you want the print command to be executed multiple times (with
|
||||
changing variable values), there are 3 options. First, consider using
|
||||
the :doc:`fix print <fix_print>` command, which will print a string
|
||||
periodically during a simulation. Second, the print command can be
|
||||
used as an argument to the *every* option of the :doc:`run <run>`
|
||||
command. Third, the print command could appear in a section of the
|
||||
input script that is looped over (see the :doc:`jump <jump>` and
|
||||
:doc:`next <next>` commands).
|
||||
|
||||
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,
|
||||
@ -74,23 +97,6 @@ logfile can be turned on or off as desired. In multi-partition
|
||||
calculations, the *screen* option and the corresponding output only
|
||||
apply to the screen and logfile of the individual partition.
|
||||
|
||||
If you want the print command to be executed multiple times (with
|
||||
changing variable values), there are 3 options. First, consider using
|
||||
the :doc:`fix print <fix_print>` command, which will print a string
|
||||
periodically during a simulation. Second, the print command can be
|
||||
used as an argument to the *every* option of the :doc:`run <run>`
|
||||
command. Third, the print command could appear in a section of the
|
||||
input script that is looped over (see the :doc:`jump <jump>` and
|
||||
:doc:`next <next>` commands).
|
||||
|
||||
See the :doc:`variable <variable>` command for a description of *equal*
|
||||
style variables which are typically the most useful ones to use with
|
||||
the print command. Equal-style variables can calculate formulas
|
||||
involving mathematical operations, atom properties, group properties,
|
||||
thermodynamic properties, global values calculated by a
|
||||
:doc:`compute <compute>` or :doc:`fix <fix>`, or references to other
|
||||
:doc:`variables <variable>`.
|
||||
|
||||
Restrictions
|
||||
""""""""""""
|
||||
none
|
||||
|
||||
@ -11,12 +11,19 @@ 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 *timer* or *internal* or *equal* or *vector* or *atom*
|
||||
* style = *delete* or *atomfile* or *file* or *format* or *getenv* or *index* or *internal* or *loop* or *python* or *string* or *timer* or *uloop* or *universe* or *world* or *equal* or *vector* or *atom*
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
*delete* = no args
|
||||
*atomfile* arg = filename
|
||||
*file* arg = filename
|
||||
*format* args = vname fstr
|
||||
vname = name of equal-style variable to evaluate
|
||||
fstr = C-style format string
|
||||
*getenv* arg = one string
|
||||
*index* args = one or more strings
|
||||
*internal* arg = numeric value
|
||||
*loop* args = N
|
||||
N = integer size of loop, loop from 1 to N inclusive
|
||||
*loop* args = N pad
|
||||
@ -27,24 +34,18 @@ Syntax
|
||||
*loop* args = N1 N2 pad
|
||||
N1,N2 = loop from N1 to N2 inclusive
|
||||
pad = all values will be same length, e.g. 050, 051, ..., 100
|
||||
*world* args = one string for each partition of processors
|
||||
*universe* args = one or more strings
|
||||
*python* arg = function
|
||||
*string* arg = one string
|
||||
*timer* arg = no arguments
|
||||
*uloop* args = N
|
||||
N = integer size of loop
|
||||
*uloop* args = N pad
|
||||
N = integer size of loop
|
||||
pad = all values will be same length, e.g. 001, 002, ..., 100
|
||||
*string* arg = one string
|
||||
*format* args = vname fstr
|
||||
vname = name of equal-style variable to evaluate
|
||||
fstr = C-style format string
|
||||
*getenv* arg = one string
|
||||
*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
|
||||
*universe* args = one or more strings
|
||||
*world* args = one string for each partition of processors
|
||||
|
||||
*equal* or *vector* or *atom* args = one formula containing numbers, thermo keywords, math operations, built-in functions, atom values and vectors, compute/fix/variable references
|
||||
numbers = 0.0, 100, -5.4, 2.8e-4, etc
|
||||
constants = PI, version, on, off, true, false, yes, no
|
||||
thermo keywords = vol, ke, press, etc from :doc:`thermo_style <thermo_style>`
|
||||
@ -67,12 +68,13 @@ Syntax
|
||||
angmom(group,dim,region), torque(group,dim,region),
|
||||
inertia(group,dimdim,region), omega(group,dim,region)
|
||||
special functions = sum(x), min(x), max(x), ave(x), trap(x), slope(x), gmask(x), rmask(x), grmask(x,y), next(x), is_file(name), is_os(name), extract_setting(name), label2type(kind,label)
|
||||
feature functions = is_active(category,feature), is_available(category,feature), is_defined(category,id)
|
||||
feature functions = is_available(category,feature), is_active(category,feature), is_defined(category,id)
|
||||
atom value = id[i], mass[i], type[i], mol[i], x[i], y[i], z[i], vx[i], vy[i], vz[i], fx[i], fy[i], fz[i], q[i]
|
||||
atom vector = id, mass, type, mol, radius, q, x, y, z, vx, vy, vz, fx, fy, fz
|
||||
compute references = c_ID, c_ID[i], c_ID[i][j], C_ID, C_ID[i]
|
||||
fix references = f_ID, f_ID[i], f_ID[i][j], F_ID, F_ID[i]
|
||||
variable references = v_name, v_name[i]
|
||||
vector initialization = [1,3,7,10] (for *vector* variables only)
|
||||
|
||||
Examples
|
||||
""""""""
|
||||
@ -95,6 +97,7 @@ Examples
|
||||
variable x universe 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
||||
variable x uloop 15 pad
|
||||
variable str format x %.6g
|
||||
variable myvec vector [1,3,7,10]
|
||||
variable x delete
|
||||
|
||||
.. code-block:: LAMMPS
|
||||
@ -252,9 +255,10 @@ commands before the variable would become exhausted. For example,
|
||||
|
||||
----------
|
||||
|
||||
This section describes how all the various variable styles are defined
|
||||
and what they store. Except for the *equal* and *vector* and *atom*
|
||||
styles, which are explained in the next section.
|
||||
The next sections describe in how all the various variable styles are
|
||||
defined and what they store. The styles are listed alphabetically,
|
||||
except for the *equal* and *vector* and *atom* styles, which are
|
||||
explained together after all the others.
|
||||
|
||||
Many of the styles store one or more strings. Note that a single
|
||||
string can contain spaces (multiple words), if it is enclosed in
|
||||
@ -262,111 +266,7 @@ quotes in the variable command. When the variable is substituted for
|
||||
in another input script command, its returned string will then be
|
||||
interpreted as multiple arguments in the expanded command.
|
||||
|
||||
For the *index* style, one or more strings are specified. Initially,
|
||||
the first string is assigned to the variable. Each time a
|
||||
:doc:`next <next>` command is used with the variable name, the next
|
||||
string is assigned. All processors assign the same string to the
|
||||
variable.
|
||||
|
||||
Index-style variables with a single string value can also be set by
|
||||
using the :doc:`command-line switch -var <Run_options>`.
|
||||
|
||||
The *loop* style is identical to the *index* style except that the
|
||||
strings are the integers from 1 to N inclusive, if only one argument N
|
||||
is specified. This allows generation of a long list of runs
|
||||
(e.g. 1000) without having to list N strings in the input script.
|
||||
Initially, the string "1" is assigned to the variable. Each time a
|
||||
:doc:`next <next>` command is used with the variable name, the next
|
||||
string ("2", "3", etc) is assigned. All processors assign the same
|
||||
string to the variable. The *loop* style can also be specified with
|
||||
two arguments N1 and N2. In this case the loop runs from N1 to N2
|
||||
inclusive, and the string N1 is initially assigned to the variable.
|
||||
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 <Run_options>`. 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
|
||||
<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
|
||||
"worlds". LAMMPS can be run with multiple partitions via the
|
||||
:doc:`-partition command-line switch <Run_options>`. This variable
|
||||
command initially assigns one string to each world. When a
|
||||
:doc:`next <next>` command is encountered using this variable, the first
|
||||
processor partition to encounter it, is assigned the next available
|
||||
string. This continues until all the variable strings are consumed.
|
||||
Thus, this command can be used to run 50 simulations on 8 processor
|
||||
partitions. The simulations will be run one after the other on
|
||||
whatever partition becomes available, until they are all finished.
|
||||
Universe-style variables are incremented using the files
|
||||
"tmp.lammps.variable" and "tmp.lammps.variable.lock" which you will
|
||||
see in your directory during such a LAMMPS run.
|
||||
|
||||
The *uloop* style is identical to the *universe* style except that the
|
||||
strings are the integers from 1 to N. This allows generation of long
|
||||
list of runs (e.g. 1000) without having to list N strings in the input
|
||||
script.
|
||||
|
||||
For the *string* style, a single string is assigned to the variable.
|
||||
Two differences between this style and using the *index* style exist:
|
||||
a variable with *string* style can be redefined, e.g. by another command later
|
||||
in the input script, or if the script is read again in a loop. The other
|
||||
difference is that *string* performs variable substitution even if the
|
||||
string parameter is quoted.
|
||||
|
||||
For the *format* style, an equal-style or compatible variable is
|
||||
specified along with a C-style format string, e.g. "%f" or "%.10g",
|
||||
which must be appropriate for formatting a double-precision
|
||||
floating-point value and may not have extra characters. The default
|
||||
format is "%.15g". This variable style allows an equal-style variable
|
||||
to be formatted precisely when it is evaluated.
|
||||
|
||||
Note that if you simply wish to print a variable value with desired
|
||||
precision to the screen or logfile via the :doc:`print <print>` or
|
||||
:doc:`fix print <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 <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
|
||||
variable is evaluated, it returns the value of the environment
|
||||
variable, or an empty string if it not defined. This style of
|
||||
variable can be used to adapt the behavior of LAMMPS input scripts via
|
||||
environment variable settings, or to retrieve information that has
|
||||
been previously stored with the :doc:`shell putenv <shell>` command.
|
||||
Note that because environment variable settings are stored by the
|
||||
operating systems, they persist even if the corresponding *getenv*
|
||||
style variable is deleted, and also are set for sub-shells executed
|
||||
by the :doc:`shell <shell>` command.
|
||||
|
||||
For the *file* style, a filename is provided which contains a list of
|
||||
strings to assign to the variable, one per line. The strings can be
|
||||
numeric values if desired. See the discussion of the next() function
|
||||
below for equal-style variables, which will convert the string of a
|
||||
file-style variable into a numeric value in a formula.
|
||||
|
||||
When a file-style variable is defined, the file is opened and the
|
||||
string on the first line is read and stored with the variable. This
|
||||
means the variable can then be evaluated as many times as desired and
|
||||
will return that string. There are two ways to cause the next string
|
||||
from the file to be read: use the :doc:`next <next>` command or the
|
||||
next() function in an equal- or atom-style variable, as discussed
|
||||
below.
|
||||
|
||||
The rules for formatting the file are as follows. A comment character
|
||||
"#" can be used anywhere on a line; text starting with the comment
|
||||
character is stripped. Blank lines are skipped. The first "word" of
|
||||
a non-blank line, delimited by white-space, is the "string" assigned
|
||||
to the variable.
|
||||
----------
|
||||
|
||||
For the *atomfile* style, a filename is provided which contains one or
|
||||
more sets of values, to assign on a per-atom basis to the variable.
|
||||
@ -406,6 +306,97 @@ will be assigned to that atom. IDs can be listed in any order.
|
||||
atoms is first set to 0.0. Thus values for atoms whose ID does not
|
||||
appear in the set, will remain 0.0.
|
||||
|
||||
----------
|
||||
|
||||
For the *file* style, a filename is provided which contains a list of
|
||||
strings to assign to the variable, one per line. The strings can be
|
||||
numeric values if desired. See the discussion of the next() function
|
||||
below for equal-style variables, which will convert the string of a
|
||||
file-style variable into a numeric value in a formula.
|
||||
|
||||
When a file-style variable is defined, the file is opened and the
|
||||
string on the first line is read and stored with the variable. This
|
||||
means the variable can then be evaluated as many times as desired and
|
||||
will return that string. There are two ways to cause the next string
|
||||
from the file to be read: use the :doc:`next <next>` command or the
|
||||
next() function in an equal- or atom-style variable, as discussed
|
||||
below.
|
||||
|
||||
The rules for formatting the file are as follows. A comment character
|
||||
"#" can be used anywhere on a line; text starting with the comment
|
||||
character is stripped. Blank lines are skipped. The first "word" of
|
||||
a non-blank line, delimited by white-space, is the "string" assigned
|
||||
to the variable.
|
||||
|
||||
----------
|
||||
|
||||
For the *format* style, an equal-style or compatible variable is
|
||||
specified along with a C-style format string, e.g. "%f" or "%.10g",
|
||||
which must be appropriate for formatting a double-precision
|
||||
floating-point value and may not have extra characters. The default
|
||||
format is "%.15g". This variable style allows an equal-style variable
|
||||
to be formatted precisely when it is evaluated.
|
||||
|
||||
Note that if you simply wish to print a variable value with desired
|
||||
precision to the screen or logfile via the :doc:`print <print>` or
|
||||
:doc:`fix print <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 <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
|
||||
variable is evaluated, it returns the value of the environment
|
||||
variable, or an empty string if it not defined. This style of
|
||||
variable can be used to adapt the behavior of LAMMPS input scripts via
|
||||
environment variable settings, or to retrieve information that has
|
||||
been previously stored with the :doc:`shell putenv <shell>` command.
|
||||
Note that because environment variable settings are stored by the
|
||||
operating systems, they persist even if the corresponding *getenv*
|
||||
style variable is deleted, and also are set for sub-shells executed
|
||||
by the :doc:`shell <shell>` command.
|
||||
|
||||
----------
|
||||
|
||||
For the *index* style, one or more strings are specified. Initially,
|
||||
the first string is assigned to the variable. Each time a
|
||||
:doc:`next <next>` command is used with the variable name, the next
|
||||
string is assigned. All processors assign the same string to the
|
||||
variable.
|
||||
|
||||
Index-style variables with a single string value can also be set by
|
||||
using the :doc:`command-line switch -var <Run_options>`.
|
||||
|
||||
----------
|
||||
|
||||
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 <create_atoms>` and :doc:`fix controller
|
||||
<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.
|
||||
|
||||
----------
|
||||
|
||||
The *loop* style is identical to the *index* style except that the
|
||||
strings are the integers from 1 to N inclusive, if only one argument N
|
||||
is specified. This allows generation of a long list of runs
|
||||
(e.g. 1000) without having to list N strings in the input script.
|
||||
Initially, the string "1" is assigned to the variable. Each time a
|
||||
:doc:`next <next>` command is used with the variable name, the next
|
||||
string ("2", "3", etc) is assigned. All processors assign the same
|
||||
string to the variable. The *loop* style can also be specified with
|
||||
two arguments N1 and N2. In this case the loop runs from N1 to N2
|
||||
inclusive, and the string N1 is initially assigned to the variable.
|
||||
N1 <= N2 and N2 >= 0 is required.
|
||||
|
||||
----------
|
||||
|
||||
For the *python* style a Python function name is provided. This needs
|
||||
to match a function name specified in a :doc:`python <python>` command
|
||||
which returns a value to this variable as defined by its *return*
|
||||
@ -433,25 +424,52 @@ 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 wall time of the
|
||||
simulation. This is done at the point in time when 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 at the top of this manual
|
||||
entry. 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 <create_atoms>` and :doc:`fix controller
|
||||
<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.
|
||||
For the *string* style, a single string is assigned to the variable.
|
||||
Two differences between this style and using the *index* style exist:
|
||||
a variable with *string* style can be redefined, e.g. by another command later
|
||||
in the input script, or if the script is read again in a loop. The other
|
||||
difference is that *string* performs variable substitution even if the
|
||||
string parameter is quoted.
|
||||
|
||||
----------
|
||||
|
||||
The *uloop* style is identical to the *universe* style except that the
|
||||
strings are the integers from 1 to N. This allows generation of long
|
||||
list of runs (e.g. 1000) without having to list N strings in the input
|
||||
script.
|
||||
|
||||
----------
|
||||
|
||||
For the *universe* style, one or more strings are specified. There
|
||||
must be at least as many strings as there are processor partitions or
|
||||
"worlds". LAMMPS can be run with multiple partitions via the
|
||||
:doc:`-partition command-line switch <Run_options>`. This variable
|
||||
command initially assigns one string to each world. When a
|
||||
:doc:`next <next>` command is encountered using this variable, the first
|
||||
processor partition to encounter it, is assigned the next available
|
||||
string. This continues until all the variable strings are consumed.
|
||||
Thus, this command can be used to run 50 simulations on 8 processor
|
||||
partitions. The simulations will be run one after the other on
|
||||
whatever partition becomes available, until they are all finished.
|
||||
Universe-style variables are incremented using the files
|
||||
"tmp.lammps.variable" and "tmp.lammps.variable.lock" which you will
|
||||
see in your directory during such a LAMMPS run.
|
||||
|
||||
----------
|
||||
|
||||
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 <Run_options>`. 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
|
||||
<temper>` command), to assign different temperatures to different
|
||||
partitions.
|
||||
|
||||
----------
|
||||
|
||||
@ -495,36 +513,39 @@ is a valid (though strange) variable formula:
|
||||
|
||||
Specifically, a formula can contain numbers, constants, thermo
|
||||
keywords, math operators, math functions, group functions, region
|
||||
functions, atom values, atom vectors, compute references, fix
|
||||
references, and references to other variables.
|
||||
functions, special functions, feature functions, atom values, atom
|
||||
vectors, compute references, fix references, and references to other
|
||||
variables.
|
||||
|
||||
+--------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Number | 0.2, 100, 1.0e20, -15.4, etc |
|
||||
+--------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Constant | PI, version, on, off, true, false, yes, no |
|
||||
+--------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Thermo keywords | vol, pe, ebond, etc |
|
||||
+--------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Math operators | (), -x, x+y, x-y, x\*y, x/y, x\^y, x%y, x == y, x != y, x < y, x <= y, x > y, x >= y, x && y, x \|\| y, x \|\^ y, !x |
|
||||
+--------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Math functions | sqrt(x), exp(x), ln(x), log(x), abs(x), sin(x), cos(x), tan(x), asin(x), acos(x), atan(x), atan2(y,x), random(x,y,z), normal(x,y,z), ceil(x), floor(x), round(x), ramp(x,y), stagger(x,y), logfreq(x,y,z), logfreq2(x,y,z), logfreq3(x,y,z), stride(x,y,z), stride2(x,y,z,a,b,c), vdisplace(x,y), swiggle(x,y,z), cwiggle(x,y,z) |
|
||||
+--------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Group functions | count(ID), mass(ID), charge(ID), xcm(ID,dim), vcm(ID,dim), fcm(ID,dim), bound(ID,dir), gyration(ID), ke(ID), angmom(ID,dim), torque(ID,dim), inertia(ID,dimdim), omega(ID,dim) |
|
||||
+--------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Region functions | count(ID,IDR), mass(ID,IDR), charge(ID,IDR), xcm(ID,dim,IDR), vcm(ID,dim,IDR), fcm(ID,dim,IDR), bound(ID,dir,IDR), gyration(ID,IDR), ke(ID,IDR), angmom(ID,dim,IDR), torque(ID,dim,IDR), inertia(ID,dimdim,IDR), omega(ID,dim,IDR) |
|
||||
+--------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Special functions | sum(x), min(x), max(x), ave(x), trap(x), slope(x), gmask(x), rmask(x), grmask(x,y), next(x), label2type(kind,label) |
|
||||
+--------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Atom values | id[i], mass[i], type[i], mol[i], x[i], y[i], z[i], vx[i], vy[i], vz[i], fx[i], fy[i], fz[i], q[i] |
|
||||
+--------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Atom vectors | id, mass, type, mol, x, y, z, vx, vy, vz, fx, fy, fz, q |
|
||||
+--------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Compute references | c_ID, c_ID[i], c_ID[i][j], C_ID, C_ID[i] |
|
||||
+--------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Fix references | f_ID, f_ID[i], f_ID[i][j], F_ID, F_ID[i] |
|
||||
+--------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Other variables | v_name, v_name[i] |
|
||||
+--------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
+--------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Number | 0.2, 100, 1.0e20, -15.4, etc |
|
||||
+--------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Constant | PI, version, on, off, true, false, yes, no |
|
||||
+--------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Thermo keywords | vol, pe, ebond, etc |
|
||||
+--------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Math operators | (), -x, x+y, x-y, x\*y, x/y, x\^y, x%y, x == y, x != y, x < y, x <= y, x > y, x >= y, x && y, x \|\| y, x \|\^ y, !x |
|
||||
+--------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Math functions | sqrt(x), exp(x), ln(x), log(x), abs(x), sin(x), cos(x), tan(x), asin(x), acos(x), atan(x), atan2(y,x), random(x,y,z), normal(x,y,z), ceil(x), floor(x), round(x), ramp(x,y), stagger(x,y), logfreq(x,y,z), logfreq2(x,y,z), logfreq3(x,y,z), stride(x,y,z), stride2(x,y,z,a,b,c), vdisplace(x,y), swiggle(x,y,z), cwiggle(x,y,z) |
|
||||
+--------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Group functions | count(ID), mass(ID), charge(ID), xcm(ID,dim), vcm(ID,dim), fcm(ID,dim), bound(ID,dir), gyration(ID), ke(ID), angmom(ID,dim), torque(ID,dim), inertia(ID,dimdim), omega(ID,dim) |
|
||||
+--------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Region functions | count(ID,IDR), mass(ID,IDR), charge(ID,IDR), xcm(ID,dim,IDR), vcm(ID,dim,IDR), fcm(ID,dim,IDR), bound(ID,dir,IDR), gyration(ID,IDR), ke(ID,IDR), angmom(ID,dim,IDR), torque(ID,dim,IDR), inertia(ID,dimdim,IDR), omega(ID,dim,IDR) |
|
||||
+--------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Special functions | sum(x), min(x), max(x), ave(x), trap(x), slope(x), gmask(x), rmask(x), grmask(x,y), next(x), is_file(name), is_os(name), extract_setting(name), label2type(kind,label) |
|
||||
+--------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Feature functions | is_available(category,feature), is_active(category,feature), is_defined(category,id) |
|
||||
+--------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Atom values | id[i], mass[i], type[i], mol[i], x[i], y[i], z[i], vx[i], vy[i], vz[i], fx[i], fy[i], fz[i], q[i] |
|
||||
+--------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Atom vectors | id, mass, type, mol, x, y, z, vx, vy, vz, fx, fy, fz, q |
|
||||
+--------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Compute references | c_ID, c_ID[i], c_ID[i][j], C_ID, C_ID[i] |
|
||||
+--------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Fix references | f_ID, f_ID[i], f_ID[i][j], F_ID, F_ID[i] |
|
||||
+--------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Other variables | v_name, v_name[i] |
|
||||
+--------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
|
||||
Most of the formula elements produce a scalar value. Some produce a
|
||||
global or per-atom vector of values. Global vectors can be produced
|
||||
@ -574,9 +595,9 @@ will not work, since the *version* has been introduced more recently):
|
||||
if $(version<20140513) then "communicate vel yes" else "comm_modify vel yes"
|
||||
|
||||
The thermo keywords allowed in a formula are those defined by the
|
||||
:doc:`thermo_style custom <thermo_style>` command. Thermo keywords that
|
||||
require a :doc:`compute <compute>` to calculate their values such as
|
||||
"temp" or "press", use computes stored and invoked by the
|
||||
:doc:`thermo_style custom <thermo_style>` command. Thermo keywords
|
||||
that require a :doc:`compute <compute>` to calculate their values such
|
||||
as "temp" or "press", use computes stored and invoked by the
|
||||
:doc:`thermo_style <thermo_style>` command. This means that you can
|
||||
only use those keywords in a variable if the style you are using with
|
||||
the thermo_style command (and the thermo keywords associated with that
|
||||
@ -714,10 +735,12 @@ new timestep. X,y,z > 0 and y < z are required. The generated
|
||||
timesteps are on a base-z logarithmic scale, starting with x, and the
|
||||
y value is how many of the z-1 possible timesteps within one
|
||||
logarithmic interval are generated. I.e. the timesteps follow the
|
||||
sequence x,2x,3x,...y\*x,x\*z,2x\*z,3x\*z,...y\*x\*z,x\*z\^2,2x\*z\^2,etc. For
|
||||
sequence
|
||||
x,2x,3x,...y\*x,x\*z,2x\*z,3x\*z,...y\*x\*z,x\*z\^2,2x\*z\^2,etc. For
|
||||
any current timestep, the next timestep in the sequence is returned.
|
||||
Thus if logfreq(100,4,10) is used in a variable by the :doc:`dump_modify every <dump_modify>` command, it will generate this sequence of
|
||||
output timesteps:
|
||||
Thus if logfreq(100,4,10) is used in a variable by the
|
||||
:doc:`dump_modify every <dump_modify>` command, it will generate this
|
||||
sequence of output timesteps:
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
@ -726,9 +749,10 @@ output timesteps:
|
||||
The logfreq2(x,y,z) function is similar to logfreq, except a single
|
||||
logarithmic interval is divided into y equally-spaced timesteps and
|
||||
all of them are output. Y < z is not required. Thus, if
|
||||
logfreq2(100,18,10) is used in a variable by the :doc:`dump_modify every <dump_modify>` command, then the interval between 100 and
|
||||
1000 is divided as 900/18 = 50 steps, and it will generate the
|
||||
sequence of output timesteps:
|
||||
logfreq2(100,18,10) is used in a variable by the :doc:`dump_modify
|
||||
every <dump_modify>` command, then the interval between 100 and 1000
|
||||
is divided as 900/18 = 50 steps, and it will generate the sequence of
|
||||
output timesteps:
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
@ -970,53 +994,87 @@ types, bond types and so on. For the full list of available keywords
|
||||
*name* and their meaning, see the documentation for extract_setting()
|
||||
via the link in this paragraph.
|
||||
|
||||
The label2type() function converts type labels into numeric types, using label
|
||||
maps created by the :doc:`labelmap <labelmap>` or :doc:`read_data <read_data>`
|
||||
commands. The first argument is the label map kind (atom, bond, angle,
|
||||
dihedral, or improper) and the second argument is the label. The function
|
||||
returns the corresponding numeric type.
|
||||
The label2type(kind,label) function converts type labels into numeric
|
||||
types, using label maps created by the :doc:`labelmap <labelmap>` or
|
||||
:doc:`read_data <read_data>` commands. The first argument is the
|
||||
label map kind (atom, bond, angle, dihedral, or improper) and the
|
||||
second argument is the label. The function returns the corresponding
|
||||
numeric type.
|
||||
|
||||
----------
|
||||
|
||||
Feature Functions
|
||||
-----------------
|
||||
|
||||
Feature functions allow to probe the running LAMMPS executable for
|
||||
whether specific features are either active, defined, or available. The
|
||||
functions take two arguments, a *category* and a corresponding
|
||||
*argument*\ . The arguments are strings and thus cannot be formulas
|
||||
Feature functions allow probing of the running LAMMPS executable for
|
||||
whether specific features are available, active, or defined. All 3 of
|
||||
the functions take two arguments, a *category* and a category-specific
|
||||
second argument. Both are strings and thus cannot be formulas
|
||||
themselves; only $-style immediate variable expansion is possible.
|
||||
Return value is either 1.0 or 0.0 depending on whether the function
|
||||
evaluates to true or false, respectively.
|
||||
The return value of the functions is either 1.0 or 0.0 depending on
|
||||
whether the function evaluates to true or false, respectively.
|
||||
|
||||
The *is_active(category,feature)* function allows to query for active
|
||||
settings which are grouped by categories. Currently supported categories
|
||||
and arguments are:
|
||||
The *is_available(category,name)* function queries whether a specific
|
||||
feature is available in the LAMMPS executable that is being run, i.e
|
||||
whether it was included or enabled at compile time.
|
||||
|
||||
* *package*\ : argument = *gpu* or *intel* or *kokkos* or *omp*
|
||||
* *newton*\ : argument = *pair* or *bond* or *any*
|
||||
* *pair*\ : argument = *single* or *respa* or *manybody* or *tail* or *shift*
|
||||
* *comm_style*\ : argument = *brick* or *tiled*
|
||||
* *min_style*\ : argument = any of the compiled in minimizer styles
|
||||
* *run_style*\ : argument = any of the compiled in run styles
|
||||
* *atom_style*\ : argument = any of the compiled in atom style)
|
||||
* *pair_style*\ : argument = any of the compiled in pair styles
|
||||
* *bond_style*\ : argument = any of the compiled in bond styles
|
||||
* *angle_style*\ : argument = any of the compiled in angle styles
|
||||
* *dihedral_style*\ : argument = any of the compiled in dihedral styles
|
||||
* *improper_style*\ : argument = any of the compiled in improper styles
|
||||
* *kspace_style*\ : argument = any of the compiled in kspace styles
|
||||
This supports the following categories: *command*, *compute*, *fix*,
|
||||
*pair_style* and *feature*\ . For all the categories except *feature*
|
||||
the *name* is a style name, e.g. *nve* for the *fix* category. Note
|
||||
that many LAMMPS input script commands such as *create_atoms* are
|
||||
actually instances of a command style which LAMMPS defines, as opposed
|
||||
to built-in commands. For all of these styles except *command*,
|
||||
appending of active suffixes is also tried before reporting failure.
|
||||
|
||||
Most of the settings are self-explanatory, the *single* argument in the
|
||||
*pair* category allows to check whether a pair style supports a
|
||||
Pair::single() function as needed by compute group/group and others
|
||||
features or LAMMPS, *respa* allows to check whether the inner/middle/outer
|
||||
mode of r-RESPA is supported. In the various style categories,
|
||||
the checking is also done using suffix flags, if available and enabled.
|
||||
The *feature* category checks the availability of the following
|
||||
compile-time enabled features: GZIP support, PNG support, JPEG
|
||||
support, FFMPEG support, and C++ exceptions for error
|
||||
handling. Corresponding names are *gzip*, *png*, *jpeg*, *ffmpeg* and
|
||||
*exceptions*\ .
|
||||
|
||||
Example 1: disable use of suffix for pppm when using GPU package
|
||||
(i.e. run it on the CPU concurrently to running the pair style on the
|
||||
GPU), but do use the suffix otherwise (e.g. with OPENMP).
|
||||
Example: Only dump in a given format if the compiled binary supports it.
|
||||
|
||||
.. code-block:: LAMMPS
|
||||
|
||||
if "$(is_available(feature,png))" then "print 'PNG supported'" else "print 'PNG not supported'"
|
||||
if "$(is_available(feature,ffmpeg)" then "dump 3 all movie 25 movie.mp4 type type zoom 1.6 adiam 1.0"
|
||||
|
||||
The *is_active(category,feature)* function queries whether a specific
|
||||
feature is currently active within LAMMPS. The features are grouped
|
||||
by categories. Supported categories and features are:
|
||||
|
||||
* *package*\ : features = *gpu* or *intel* or *kokkos* or *omp*
|
||||
* *newton*\ : features = *pair* or *bond* or *any*
|
||||
* *pair*\ : features = *single* or *respa* or *manybody* or *tail* or *shift*
|
||||
* *comm_style*\ : features = *brick* or *tiled*
|
||||
* *min_style*\ : features = a minimizer style name
|
||||
* *run_style*\ : features = a run style name
|
||||
* *atom_style*\ : features = an atom style name
|
||||
* *pair_style*\ : features = a pair style name
|
||||
* *bond_style*\ : features = a bond style name
|
||||
* *angle_style*\ : features = an angle style name
|
||||
* *dihedral_style*\ : features = a dihedral style name
|
||||
* *improper_style*\ : features = an improper style name
|
||||
* *kspace_style*\ : features = a kspace style name
|
||||
|
||||
Most of the settings are self-explanatory. For the *package*
|
||||
category, a package may have been included in the LAMMPS build, but
|
||||
not have enabled by any input script command, and hence be inactive.
|
||||
The *single* feature in the *pair* category checks whether the
|
||||
currently defined pair style supports a Pair::single() function as
|
||||
needed by compute group/group and others features or LAMMPS.
|
||||
Similarly, the *respa* feature checks whether the inner/middle/outer
|
||||
mode of r-RESPA is supported by the current pair style.
|
||||
|
||||
For the categories with *style* in their name, only a single instance
|
||||
of the style is ever active at any time in a LAMMPS simulation. Thus
|
||||
the check is whether the currently active style matches the specified
|
||||
name. This check is also done using suffix flags, if available and
|
||||
enabled.
|
||||
|
||||
Example 1: Disable use of suffix for PPPM when using GPU package
|
||||
(i.e. run it on the CPU concurrently while running the pair style on
|
||||
the GPU), but do use the suffix otherwise (e.g. with OPENMP).
|
||||
|
||||
.. code-block:: LAMMPS
|
||||
|
||||
@ -1024,39 +1082,23 @@ GPU), but do use the suffix otherwise (e.g. with OPENMP).
|
||||
if $(is_active(package,gpu)) then "suffix off"
|
||||
kspace_style pppm
|
||||
|
||||
Example 2: use r-RESPA with inner/outer cutoff, if supported by pair
|
||||
style, otherwise fall back to using pair and reducing the outer time
|
||||
step
|
||||
Example 2: Use r-RESPA with inner/outer cutoff, if supported by the
|
||||
current pair style, otherwise fall back to using r-RESPA with simply
|
||||
the pair keyword and reducing the outer time step.
|
||||
|
||||
.. code-block:: LAMMPS
|
||||
|
||||
timestep $(2.0*(1.0+2.0*is_active(pair,respa)))
|
||||
if $(is_active(pair,respa)) then "run_style respa 4 3 2 2 improper 1 inner 2 5.5 7.0 outer 3 kspace 4" else "run_style respa 3 3 2 improper 1 pair 2 kspace 3"
|
||||
if $(is_active(pair,respa)) then "run_style respa 4 3 2 2 improper 1 inner 2 5.5 7.0 outer 3 kspace 4" else "run_style respa 3 3 2 improper 1 pair 2 kspace 3"
|
||||
|
||||
The *is_available(category,name)* function allows to query whether
|
||||
a specific optional feature is available, i.e. compiled in.
|
||||
This currently works for the following categories: *command*,
|
||||
*compute*, *fix*, *pair_style* and *feature*\ . For all categories
|
||||
except *command* and *feature* also appending active suffixes is
|
||||
tried before reporting failure.
|
||||
|
||||
The *feature* category is used to check the availability of compiled in
|
||||
features such as GZIP support, PNG support, JPEG support, FFMPEG support,
|
||||
and C++ exceptions for error handling. Corresponding values for name are
|
||||
*gzip*, *png*, *jpeg*, *ffmpeg* and *exceptions*\ .
|
||||
|
||||
This enables writing input scripts which only dump using a given format if
|
||||
the compiled binary supports it.
|
||||
|
||||
.. code-block:: LAMMPS
|
||||
|
||||
if "$(is_available(feature,png))" then "print 'PNG supported'" else "print 'PNG not supported'"
|
||||
|
||||
if "$(is_available(feature,ffmpeg)" then "dump 3 all movie 25 movie.mp4 type type zoom 1.6 adiam 1.0"
|
||||
|
||||
The *is_defined(categoy,id)* function allows to query categories like
|
||||
*compute*, *dump*, *fix*, *group*, *region*, and *variable* whether an
|
||||
entry with the provided name or id is defined.
|
||||
The *is_defined(category,id)* function checks whether an instance of a
|
||||
style or variable with a specific ID or name is currently defined
|
||||
within LAMMPS. The supported categories are *compute*, *dump*,
|
||||
*fix*, *group*, *region*, and *variable*. Each of these styles (as
|
||||
well as the variable command) can be specified multiple times within
|
||||
LAMMPS, each with a unique *id*. This function checks whether the
|
||||
specified *id* exists. For category *variable", the *id* is the
|
||||
variable name.
|
||||
|
||||
----------
|
||||
|
||||
@ -1268,6 +1310,35 @@ Vectors" discussion above.
|
||||
|
||||
----------
|
||||
|
||||
Vector Initialization
|
||||
---------------------
|
||||
|
||||
.. versionadded:: TBD
|
||||
|
||||
*Vector*-style variables only can be initialized with a special
|
||||
syntax, instead of using a formula. The syntax is a bracketed,
|
||||
comma-separated syntax like the following:
|
||||
|
||||
.. code-block:: LAMMPS
|
||||
|
||||
variable myvec vector [1,3.5,7,10.2]
|
||||
|
||||
The 3rd argument formula is replaced by the vector values in brackets,
|
||||
separated by commas. This example creates a 4-length vector with
|
||||
specific numeric values, each of which can be specified as an integer
|
||||
or floating point value. Note that while whitespace can be added
|
||||
before or after individual values, no other mathematical operations
|
||||
can be specified. E.g. "3*10" or "3*v_abc" are not valid vector
|
||||
elements, nor is "10*[1,2,3,4]" valid for the entire vector.
|
||||
|
||||
Unlike vector variables specified with formulas, this vector variable
|
||||
is static; its length and values never changes. Its values can be
|
||||
used in other commands (including vector-style variables specified
|
||||
with formulas) via the usual syntax for accessing individual vector
|
||||
elements or the entire vector.
|
||||
|
||||
----------
|
||||
|
||||
Immediate Evaluation of Variables
|
||||
"""""""""""""""""""""""""""""""""
|
||||
|
||||
@ -1285,18 +1356,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 <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
|
||||
<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 <fix_ave_chunk>` or :doc:`dump custom <dump>` or
|
||||
:doc:`thermo_style <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
|
||||
<fix_ave_chunk>` or :doc:`dump custom <dump>` or :doc:`thermo_style
|
||||
<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 +1381,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 <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
|
||||
<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:
|
||||
|
||||
336
src/variable.cpp
336
src/variable.cpp
@ -38,6 +38,8 @@
|
||||
#include "universe.h"
|
||||
#include "update.h"
|
||||
|
||||
#include "fmt/ranges.h"
|
||||
|
||||
#include <cctype>
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
@ -72,10 +74,10 @@ enum{DONE,ADD,SUBTRACT,MULTIPLY,DIVIDE,CARAT,MODULO,UNARY,
|
||||
|
||||
enum{SUM,XMIN,XMAX,AVE,TRAP,SLOPE};
|
||||
|
||||
|
||||
static constexpr double BIG = 1.0e20;
|
||||
|
||||
// INT64_MAX cannot be represented with a double. reduce to avoid overflow when casting back.
|
||||
// INT64_MAX cannot be represented with a double. reduce to avoid overflow when casting back
|
||||
|
||||
#if defined(LAMMPS_SMALLBIG) || defined(LAMMPS_BIGBIG)
|
||||
static constexpr double MAXBIGINT_DOUBLE = (double) (MAXBIGINT-512);
|
||||
#else
|
||||
@ -477,8 +479,10 @@ void Variable::set(int narg, char **arg)
|
||||
|
||||
// VECTOR
|
||||
// replace pre-existing var if also style VECTOR (allows it to be reset)
|
||||
// num = 1, which = 1st value
|
||||
// data = 1 value, string to eval
|
||||
// num = 2, which = 1st value
|
||||
// data = 2 values, 1st is string to eval, 2nd is formatted output string [1,2,3]
|
||||
// if formula string is [value,value,...] then
|
||||
// immediately store it as N-length vector and set dynamic flag to 0
|
||||
|
||||
} else if (strcmp(arg[1],"vector") == 0) {
|
||||
if (narg != 3) error->all(FLERR,"Illegal variable command: expected 3 arguments but found {}", narg);
|
||||
@ -487,16 +491,34 @@ void Variable::set(int narg, char **arg)
|
||||
if (style[ivar] != VECTOR)
|
||||
error->all(FLERR,"Cannot redefine variable as a different style");
|
||||
delete[] data[ivar][0];
|
||||
delete[] data[ivar][1];
|
||||
data[ivar][0] = utils::strdup(arg[2]);
|
||||
if (data[ivar][0][0] != '[')
|
||||
vecs[ivar].dynamic = 1;
|
||||
else {
|
||||
vecs[ivar].dynamic = 0;
|
||||
parse_vector(ivar,data[ivar][0]);
|
||||
std::vector <double> vec(vecs[ivar].values,vecs[ivar].values + vecs[ivar].n);
|
||||
data[ivar][1] = utils::strdup(fmt::format("[{}]", fmt::join(vec,",")));
|
||||
}
|
||||
replaceflag = 1;
|
||||
} else {
|
||||
if (nvar == maxvar) grow();
|
||||
style[nvar] = VECTOR;
|
||||
num[nvar] = 1;
|
||||
num[nvar] = 2;
|
||||
which[nvar] = 0;
|
||||
pad[nvar] = 0;
|
||||
data[nvar] = new char*[num[nvar]];
|
||||
data[nvar][0] = utils::strdup(arg[2]);
|
||||
if (data[nvar][0][0] != '[') {
|
||||
vecs[nvar].dynamic = 1;
|
||||
data[nvar][1] = nullptr;
|
||||
} else {
|
||||
vecs[nvar].dynamic = 0;
|
||||
parse_vector(nvar,data[nvar][0]);
|
||||
std::vector <double> vec(vecs[nvar].values,vecs[nvar].values + vecs[nvar].n);
|
||||
data[nvar][1] = utils::strdup(fmt::format("[{}]", fmt::join(vec,",")));
|
||||
}
|
||||
}
|
||||
|
||||
// PYTHON
|
||||
@ -935,8 +957,9 @@ int Variable::internalstyle(int ivar)
|
||||
if GETENV, query environment and put result in str
|
||||
if PYTHON, evaluate Python function, it will put result in str
|
||||
if INTERNAL, convert dvalue and put result in str
|
||||
if ATOM or ATOMFILE or VECTOR, return nullptr
|
||||
return nullptr if no variable with name, or which value is bad,
|
||||
if VECTOR, return str = [value,value,...]
|
||||
if ATOM or ATOMFILE, return nullptr
|
||||
return nullptr if no variable with name or if which value is bad,
|
||||
caller must respond
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
@ -956,17 +979,21 @@ char *Variable::retrieve(const char *name)
|
||||
style[ivar] == UNIVERSE || style[ivar] == STRING ||
|
||||
style[ivar] == SCALARFILE) {
|
||||
str = data[ivar][which[ivar]];
|
||||
|
||||
} else if (style[ivar] == LOOP || style[ivar] == ULOOP) {
|
||||
|
||||
std::string result;
|
||||
if (pad[ivar] == 0) result = std::to_string(which[ivar]+1);
|
||||
else result = fmt::format("{:0>{}d}",which[ivar]+1, pad[ivar]);
|
||||
delete[] data[ivar][0];
|
||||
str = data[ivar][0] = utils::strdup(result);
|
||||
|
||||
} else if (style[ivar] == EQUAL) {
|
||||
double answer = evaluate(data[ivar][0],nullptr,ivar);
|
||||
delete[] data[ivar][1];
|
||||
data[ivar][1] = utils::strdup(fmt::format("{:.15g}",answer));
|
||||
str = data[ivar][1];
|
||||
|
||||
} else if (style[ivar] == FORMAT) {
|
||||
int jvar = find(data[ivar][0]);
|
||||
if (jvar < 0)
|
||||
@ -977,11 +1004,13 @@ char *Variable::retrieve(const char *name)
|
||||
double answer = compute_equal(jvar);
|
||||
sprintf(data[ivar][2],data[ivar][1],answer);
|
||||
str = data[ivar][2];
|
||||
|
||||
} else if (style[ivar] == GETENV) {
|
||||
const char *result = getenv(data[ivar][0]);
|
||||
if (result == nullptr) result = (const char *) "";
|
||||
delete[] data[ivar][1];
|
||||
str = data[ivar][1] = utils::strdup(result);
|
||||
|
||||
} else if (style[ivar] == PYTHON) {
|
||||
int ifunc = python->variable_match(data[ivar][0],name,0);
|
||||
if (ifunc < 0) {
|
||||
@ -1001,16 +1030,39 @@ char *Variable::retrieve(const char *name)
|
||||
}
|
||||
python->invoke_function(ifunc,data[ivar][1]);
|
||||
str = data[ivar][1];
|
||||
|
||||
// if Python func returns a string longer than VALUELENGTH
|
||||
// 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] == TIMER || style[ivar] == INTERNAL) {
|
||||
delete[] data[ivar][0];
|
||||
data[ivar][0] = utils::strdup(fmt::format("{:.15g}",dvalue[ivar]));
|
||||
str = data[ivar][0];
|
||||
} else if (style[ivar] == ATOM || style[ivar] == ATOMFILE ||
|
||||
style[ivar] == VECTOR) return nullptr;
|
||||
|
||||
} else if (style[ivar] == VECTOR) {
|
||||
|
||||
// check if vector variable needs to be re-computed
|
||||
// if no, just return previously formatted string in data[ivar][1]
|
||||
// if yes, invoke compute_vector() and convert vector to formatted string
|
||||
// must also turn off eval_in_progress b/c compute_vector() checks it
|
||||
|
||||
if (vecs[ivar].dynamic || vecs[ivar].currentstep != update->ntimestep) {
|
||||
eval_in_progress[ivar] = 0;
|
||||
double *result;
|
||||
int nvec = compute_vector(ivar,&result);
|
||||
delete[] data[ivar][1];
|
||||
std::vector <double> vectmp(vecs[ivar].values,vecs[ivar].values + vecs[ivar].n);
|
||||
std::string str = fmt::format("[{}]", fmt::join(vectmp,","));
|
||||
data[ivar][1] = utils::strdup(str);
|
||||
}
|
||||
|
||||
str = data[ivar][1];
|
||||
|
||||
} else if (style[ivar] == ATOM || style[ivar] == ATOMFILE)
|
||||
return nullptr;
|
||||
|
||||
eval_in_progress[ivar] = 0;
|
||||
|
||||
@ -1137,18 +1189,30 @@ void Variable::compute_atom(int ivar, int igroup, double *result, int stride, in
|
||||
compute result of vector-style variable evaluation
|
||||
return length of vector and result pointer to vector values
|
||||
if length == 0 or -1 (mismatch), generate an error
|
||||
if variable already computed on this timestep, just return
|
||||
else evaluate the formula and its length, store results in VecVar entry
|
||||
if necessary, evaluate the formula and its length,
|
||||
store results in VecVar entry and return them
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
int Variable::compute_vector(int ivar, double **result)
|
||||
{
|
||||
Tree *tree = nullptr;
|
||||
|
||||
// if vector is not dynamic, just return stored values
|
||||
|
||||
if (!vecs[ivar].dynamic) {
|
||||
*result = vecs[ivar].values;
|
||||
return vecs[ivar].n;
|
||||
}
|
||||
|
||||
// if vector already computed on this timestep, just return stored values
|
||||
|
||||
if (vecs[ivar].currentstep == update->ntimestep) {
|
||||
*result = vecs[ivar].values;
|
||||
return vecs[ivar].n;
|
||||
}
|
||||
|
||||
// evaluate vector variable afresh
|
||||
|
||||
if (eval_in_progress[ivar])
|
||||
print_var_error(FLERR,"has a circular dependency",ivar);
|
||||
|
||||
@ -1246,7 +1310,8 @@ void Variable::grow()
|
||||
|
||||
vecs = (VecVar *) memory->srealloc(vecs,maxvar*sizeof(VecVar),"var:vecvar");
|
||||
for (int i = old; i < maxvar; i++) {
|
||||
vecs[i].nmax = 0;
|
||||
vecs[i].n = vecs[i].nmax = 0;
|
||||
vecs[i].dynamic = 1;
|
||||
vecs[i].currentstep = -1;
|
||||
vecs[i].values = nullptr;
|
||||
}
|
||||
@ -2031,7 +2096,8 @@ double Variable::evaluate(char *str, Tree **tree, int ivar)
|
||||
if (math_function(word,contents,tree,treestack,ntreestack,argstack,nargstack,ivar));
|
||||
else if (group_function(word,contents,tree,treestack,ntreestack,argstack,nargstack,ivar));
|
||||
else if (special_function(word,contents,tree,treestack,ntreestack,argstack,nargstack,ivar));
|
||||
else print_var_error(FLERR,fmt::format("Invalid math/group/special function '{}()' "
|
||||
else if (feature_function(word,contents,tree,treestack,ntreestack,argstack,nargstack,ivar));
|
||||
else print_var_error(FLERR,fmt::format("Invalid math/group/special/feature function '{}()' "
|
||||
"in variable formula", word),ivar);
|
||||
delete[] contents;
|
||||
|
||||
@ -2247,7 +2313,7 @@ double Variable::evaluate(char *str, Tree **tree, int ivar)
|
||||
|
||||
if (nopstack) print_var_error(FLERR,"Invalid syntax in variable formula",ivar);
|
||||
|
||||
// for atom-style variable, return remaining tree
|
||||
// for atom-style and vector-style variable, return remaining tree
|
||||
// for equal-style variable, return remaining arg
|
||||
|
||||
if (tree) {
|
||||
@ -3979,11 +4045,12 @@ Region *Variable::region_function(char *id, int ivar)
|
||||
process a special function in formula
|
||||
push result onto tree or arg stack
|
||||
word = special function
|
||||
contents = str between parentheses with one,two,three args
|
||||
contents = str between parentheses with one or more args
|
||||
return 0 if not a match, 1 if successfully processed
|
||||
customize by adding a special function:
|
||||
sum(x),min(x),max(x),ave(x),trap(x),slope(x),
|
||||
gmask(x),rmask(x),grmask(x,y),next(x)
|
||||
gmask(x),rmask(x),grmask(x,y),next(x),
|
||||
is_file(x),is_ox(x),extract_setting(x),label2type(x,y)
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
int Variable::special_function(char *word, char *contents, Tree **tree, Tree **treestack,
|
||||
@ -3992,20 +4059,66 @@ int Variable::special_function(char *word, char *contents, Tree **tree, Tree **t
|
||||
double sx,sxx;
|
||||
double value,sy,sxy;
|
||||
|
||||
// word not a match to any special function
|
||||
// word is not a match to any special function
|
||||
|
||||
if (strcmp(word,"sum") != 0 && strcmp(word,"min") && strcmp(word,"max") != 0 && strcmp(word,"ave") != 0 &&
|
||||
strcmp(word,"trap") != 0 && strcmp(word,"slope") != 0 && strcmp(word,"gmask") != 0 && strcmp(word,"rmask") != 0 &&
|
||||
strcmp(word,"grmask") != 0 && strcmp(word,"next") != 0 && strcmp(word,"is_active") != 0 &&
|
||||
strcmp(word,"is_defined") != 0 && strcmp(word,"is_available") != 0 && strcmp(word,"is_file") != 0 &&
|
||||
strcmp(word,"is_os") != 0 && strcmp(word,"extract_setting") != 0 && strcmp(word,"label2type") != 0)
|
||||
if (strcmp(word,"sum") != 0 && strcmp(word,"min") && strcmp(word,"max") != 0 &&
|
||||
strcmp(word,"ave") != 0 && strcmp(word,"trap") != 0 && strcmp(word,"slope") != 0 &&
|
||||
strcmp(word,"gmask") != 0 && strcmp(word,"rmask") != 0 && strcmp(word,"grmask") != 0 &&
|
||||
strcmp(word,"next") != 0 && strcmp(word,"is_file") != 0 && strcmp(word,"is_os") != 0 &&
|
||||
strcmp(word,"extract_setting") != 0 && strcmp(word,"label2type") != 0)
|
||||
return 0;
|
||||
|
||||
// process label2type() separately b/c its label arg can have commas in it
|
||||
|
||||
if (strcmp(word,"label2type") == 0) {
|
||||
if (!atom->labelmapflag)
|
||||
print_var_error(FLERR,"Cannot use label2type() function without a labelmap",ivar);
|
||||
|
||||
std::string contents_copy(contents);
|
||||
auto pos = contents_copy.find_first_of(',');
|
||||
if (pos == std::string::npos)
|
||||
print_var_error(FLERR, fmt::format("Invalid label2type({}) function in variable formula",
|
||||
contents_copy), ivar);
|
||||
std::string typestr = contents_copy.substr(pos+1);
|
||||
std::string kind = contents_copy.substr(0, pos);
|
||||
|
||||
int value = -1;
|
||||
if (kind == "atom") {
|
||||
value = atom->lmap->find(typestr,Atom::ATOM);
|
||||
} else if (kind == "bond") {
|
||||
value = atom->lmap->find(typestr,Atom::BOND);
|
||||
} else if (kind == "angle") {
|
||||
value = atom->lmap->find(typestr,Atom::ANGLE);
|
||||
} else if (kind == "dihedral") {
|
||||
value = atom->lmap->find(typestr,Atom::DIHEDRAL);
|
||||
} else if (kind == "improper") {
|
||||
value = atom->lmap->find(typestr,Atom::IMPROPER);
|
||||
} else {
|
||||
print_var_error(FLERR, fmt::format("Invalid kind {} in label2type() in variable",kind),ivar);
|
||||
}
|
||||
|
||||
if (value == -1)
|
||||
print_var_error(FLERR, fmt::format("Invalid {} type label {} in label2type() in variable",
|
||||
kind, typestr), ivar);
|
||||
|
||||
// save value in tree or on argstack
|
||||
|
||||
if (tree) {
|
||||
Tree *newtree = new Tree();
|
||||
newtree->type = VALUE;
|
||||
newtree->value = value;
|
||||
newtree->first = newtree->second = nullptr;
|
||||
newtree->nextra = 0;
|
||||
treestack[ntreestack++] = newtree;
|
||||
} else argstack[nargstack++] = value;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// process other special functions
|
||||
// parse contents for comma-separated args
|
||||
// narg = number of args, args = strings between commas
|
||||
|
||||
std::string contents_copy(contents); // for label2type
|
||||
|
||||
char *args[MAXFUNCARG];
|
||||
int narg = parse_args(contents,args);
|
||||
|
||||
@ -4333,54 +4446,6 @@ int Variable::special_function(char *word, char *contents, Tree **tree, Tree **t
|
||||
|
||||
} else print_var_error(FLERR,"Invalid variable style in special function next",ivar);
|
||||
|
||||
} else if (strcmp(word,"is_active") == 0) {
|
||||
if (narg != 2)
|
||||
print_var_error(FLERR,"Invalid is_active() function in variable formula",ivar);
|
||||
|
||||
Info info(lmp);
|
||||
value = (info.is_active(args[0],args[1])) ? 1.0 : 0.0;
|
||||
|
||||
// save value in tree or on argstack
|
||||
|
||||
if (tree) {
|
||||
auto newtree = new Tree();
|
||||
newtree->type = VALUE;
|
||||
newtree->value = value;
|
||||
treestack[ntreestack++] = newtree;
|
||||
} else argstack[nargstack++] = value;
|
||||
|
||||
} else if (strcmp(word,"is_available") == 0) {
|
||||
if (narg != 2)
|
||||
print_var_error(FLERR,"Invalid is_available() function in variable formula",ivar);
|
||||
|
||||
Info info(lmp);
|
||||
value = (info.is_available(args[0],args[1])) ? 1.0 : 0.0;
|
||||
|
||||
// save value in tree or on argstack
|
||||
|
||||
if (tree) {
|
||||
auto newtree = new Tree();
|
||||
newtree->type = VALUE;
|
||||
newtree->value = value;
|
||||
treestack[ntreestack++] = newtree;
|
||||
} else argstack[nargstack++] = value;
|
||||
|
||||
} else if (strcmp(word,"is_defined") == 0) {
|
||||
if (narg != 2)
|
||||
print_var_error(FLERR,"Invalid is_defined() function in variable formula",ivar);
|
||||
|
||||
Info info(lmp);
|
||||
value = (info.is_defined(args[0],args[1])) ? 1.0 : 0.0;
|
||||
|
||||
// save value in tree or on argstack
|
||||
|
||||
if (tree) {
|
||||
auto newtree = new Tree();
|
||||
newtree->type = VALUE;
|
||||
newtree->value = value;
|
||||
treestack[ntreestack++] = newtree;
|
||||
} else argstack[nargstack++] = value;
|
||||
|
||||
} else if (strcmp(word,"is_file") == 0) {
|
||||
if (narg != 1)
|
||||
print_var_error(FLERR,"Invalid is_file() function in variable formula",ivar);
|
||||
@ -4412,7 +4477,7 @@ int Variable::special_function(char *word, char *contents, Tree **tree, Tree **t
|
||||
} else argstack[nargstack++] = value;
|
||||
|
||||
} else if (strcmp(word,"extract_setting") == 0) {
|
||||
if (narg != 1) print_var_error(FLERR,"Invalid extract_setting() function syntax in variable formula",ivar);
|
||||
if (narg != 1) print_var_error(FLERR,"Invalid extract_setting() function in variable formula",ivar);
|
||||
|
||||
value = lammps_extract_setting(lmp, args[0]);
|
||||
if (value < 0) {
|
||||
@ -4428,45 +4493,87 @@ int Variable::special_function(char *word, char *contents, Tree **tree, Tree **t
|
||||
newtree->value = value;
|
||||
treestack[ntreestack++] = newtree;
|
||||
} else argstack[nargstack++] = value;
|
||||
}
|
||||
|
||||
} else if (strcmp(word,"label2type") == 0) {
|
||||
if (!atom->labelmapflag)
|
||||
print_var_error(FLERR,"Cannot use label2type() function without a labelmap",ivar);
|
||||
// delete stored args
|
||||
|
||||
auto pos = contents_copy.find_first_of(',');
|
||||
if (pos == std::string::npos)
|
||||
print_var_error(FLERR, fmt::format("Invalid label2type({}) function in variable formula",
|
||||
contents_copy), ivar);
|
||||
std::string typestr = contents_copy.substr(pos+1);
|
||||
std::string kind = contents_copy.substr(0, pos);
|
||||
for (int i = 0; i < narg; i++) delete[] args[i];
|
||||
|
||||
int value = -1;
|
||||
if (kind == "atom") {
|
||||
value = atom->lmap->find(typestr,Atom::ATOM);
|
||||
} else if (kind == "bond") {
|
||||
value = atom->lmap->find(typestr,Atom::BOND);
|
||||
} else if (kind == "angle") {
|
||||
value = atom->lmap->find(typestr,Atom::ANGLE);
|
||||
} else if (kind == "dihedral") {
|
||||
value = atom->lmap->find(typestr,Atom::DIHEDRAL);
|
||||
} else if (kind == "improper") {
|
||||
value = atom->lmap->find(typestr,Atom::IMPROPER);
|
||||
} else {
|
||||
print_var_error(FLERR, fmt::format("Invalid type kind {} in variable formula",kind), ivar);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (value == -1)
|
||||
print_var_error(FLERR, fmt::format("Invalid {} type label {} in variable formula",
|
||||
kind, typestr), ivar);
|
||||
/* ----------------------------------------------------------------------
|
||||
process a feature function in formula
|
||||
push result onto tree or arg stack
|
||||
word = special function
|
||||
contents = str between parentheses with one or more args
|
||||
return 0 if not a match, 1 if successfully processed
|
||||
customize by adding a feature function:
|
||||
is_available(x,y),is_active(x,y),is_defined(x,y),
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
int Variable::feature_function(char *word, char *contents, Tree **tree, Tree **treestack,
|
||||
int &ntreestack, double *argstack, int &nargstack, int ivar)
|
||||
{
|
||||
double value;
|
||||
|
||||
// word is not a match to any feature function
|
||||
|
||||
if (strcmp(word,"is_available") && strcmp(word,"is_active") && strcmp(word,"is_defined") != 0)
|
||||
return 0;
|
||||
|
||||
// process feature functions
|
||||
// parse contents for comma-separated args
|
||||
// narg = number of args, args = strings between commas
|
||||
|
||||
char *args[MAXFUNCARG];
|
||||
int narg = parse_args(contents,args);
|
||||
|
||||
if (strcmp(word,"is_available") == 0) {
|
||||
if (narg != 2)
|
||||
print_var_error(FLERR,"Invalid is_available() function in variable formula",ivar);
|
||||
|
||||
Info info(lmp);
|
||||
value = (info.is_available(args[0],args[1])) ? 1.0 : 0.0;
|
||||
|
||||
// save value in tree or on argstack
|
||||
|
||||
if (tree) {
|
||||
Tree *newtree = new Tree();
|
||||
auto newtree = new Tree();
|
||||
newtree->type = VALUE;
|
||||
newtree->value = value;
|
||||
treestack[ntreestack++] = newtree;
|
||||
} else argstack[nargstack++] = value;
|
||||
|
||||
} else if (strcmp(word,"is_active") == 0) {
|
||||
if (narg != 2)
|
||||
print_var_error(FLERR,"Invalid is_active() function in variable formula",ivar);
|
||||
|
||||
Info info(lmp);
|
||||
value = (info.is_active(args[0],args[1])) ? 1.0 : 0.0;
|
||||
|
||||
// save value in tree or on argstack
|
||||
|
||||
if (tree) {
|
||||
auto newtree = new Tree();
|
||||
newtree->type = VALUE;
|
||||
newtree->value = value;
|
||||
treestack[ntreestack++] = newtree;
|
||||
} else argstack[nargstack++] = value;
|
||||
|
||||
} else if (strcmp(word,"is_defined") == 0) {
|
||||
if (narg != 2)
|
||||
print_var_error(FLERR,"Invalid is_defined() function in variable formula",ivar);
|
||||
|
||||
Info info(lmp);
|
||||
value = (info.is_defined(args[0],args[1])) ? 1.0 : 0.0;
|
||||
|
||||
// save value in tree or on argstack
|
||||
|
||||
if (tree) {
|
||||
auto newtree = new Tree();
|
||||
newtree->type = VALUE;
|
||||
newtree->value = value;
|
||||
newtree->first = newtree->second = nullptr;
|
||||
newtree->nextra = 0;
|
||||
treestack[ntreestack++] = newtree;
|
||||
} else argstack[nargstack++] = value;
|
||||
}
|
||||
@ -4656,6 +4763,30 @@ void Variable::atom_vector(char *word, Tree **tree, Tree **treestack, int &ntree
|
||||
else if (strcmp(word,"fz") == 0) newtree->array = &atom->f[0][2];
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
parse vector string with format [value,value,...] for vector-style variable
|
||||
store numeric values in vecs[ivar]
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
void Variable::parse_vector(int ivar, char *str)
|
||||
{
|
||||
// check for square brackets, remove them, and split into vector
|
||||
int nstr = strlen(str)-1;
|
||||
if ((str[0] != '[') || (str[nstr] != ']'))
|
||||
error->all(FLERR,"Vector variable formula lacks opening or closing brace: {}", str);
|
||||
std::vector<std::string> args = Tokenizer(std::string(str+1, str+nstr), ",").as_vector();
|
||||
|
||||
int nvec = args.size();
|
||||
vecs[ivar].n = nvec;
|
||||
vecs[ivar].nmax = nvec;
|
||||
vecs[ivar].currentstep = -1;
|
||||
memory->destroy(vecs[ivar].values);
|
||||
memory->create(vecs[ivar].values,vecs[ivar].nmax,"variable:values");
|
||||
|
||||
for (int i = 0; i < nvec; i++)
|
||||
vecs[ivar].values[i] = utils::numeric(FLERR, utils::trim(args[i]), false, lmp);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
parse string for comma-separated args
|
||||
store copy of each arg in args array
|
||||
@ -4698,7 +4829,6 @@ char *Variable::find_next_comma(char *str)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
helper routine for printing variable name with error message
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
@ -90,6 +90,7 @@ class Variable : protected Pointers {
|
||||
|
||||
struct VecVar {
|
||||
int n, nmax;
|
||||
int dynamic;
|
||||
bigint currentstep;
|
||||
double *values;
|
||||
};
|
||||
@ -141,10 +142,12 @@ class Variable : protected Pointers {
|
||||
int group_function(char *, char *, Tree **, Tree **, int &, double *, int &, int);
|
||||
Region *region_function(char *, int);
|
||||
int special_function(char *, char *, Tree **, Tree **, int &, double *, int &, int);
|
||||
int feature_function(char *, char *, Tree **, Tree **, int &, double *, int &, int);
|
||||
void peratom2global(int, char *, double *, int, tagint, Tree **, Tree **, int &, double *, int &);
|
||||
int is_atom_vector(char *);
|
||||
void atom_vector(char *, Tree **, Tree **, int &);
|
||||
int parse_args(char *, char **);
|
||||
void parse_vector(int, char *);
|
||||
char *find_next_comma(char *);
|
||||
void print_var_error(const std::string &, int, const std::string &, int, int global = 1);
|
||||
void print_tree(Tree *, int);
|
||||
|
||||
@ -140,16 +140,18 @@ TEST_F(VariableTest, CreateDelete)
|
||||
command("variable ten1 universe 1 2 3 4");
|
||||
command("variable ten2 uloop 4");
|
||||
command("variable ten3 uloop 4 pad");
|
||||
command("variable ten4 vector [0,1,2,3,5,7,11]");
|
||||
command("variable ten5 vector [0.5,1.25]");
|
||||
command("variable dummy index 0");
|
||||
command("variable file equal is_file(MYFILE)");
|
||||
command("variable iswin equal is_os(^Windows)");
|
||||
command("variable islin equal is_os(^Linux)");
|
||||
END_HIDE_OUTPUT();
|
||||
ASSERT_EQ(variable->nvar, 20);
|
||||
ASSERT_EQ(variable->nvar, 22);
|
||||
BEGIN_HIDE_OUTPUT();
|
||||
command("variable dummy delete");
|
||||
END_HIDE_OUTPUT();
|
||||
ASSERT_EQ(variable->nvar, 19);
|
||||
ASSERT_EQ(variable->nvar, 21);
|
||||
ASSERT_THAT(variable->retrieve("three"), StrEq("three"));
|
||||
variable->set_string("three", "four");
|
||||
ASSERT_THAT(variable->retrieve("three"), StrEq("four"));
|
||||
@ -160,6 +162,8 @@ TEST_F(VariableTest, CreateDelete)
|
||||
ASSERT_THAT(variable->retrieve("eight"), StrEq(""));
|
||||
variable->internal_set(variable->find("ten"), 2.5);
|
||||
ASSERT_THAT(variable->retrieve("ten"), StrEq("2.5"));
|
||||
EXPECT_THAT(variable->retrieve("ten4"), StrEq("[0,1,2,3,5,7,11]"));
|
||||
EXPECT_THAT(variable->retrieve("ten5"), StrEq("[0.5,1.25]"));
|
||||
ASSERT_THAT(variable->retrieve("file"), StrEq("0"));
|
||||
FILE *fp = fopen("MYFILE", "w");
|
||||
fputs(" ", fp);
|
||||
@ -217,7 +221,7 @@ TEST_F(VariableTest, CreateDelete)
|
||||
TEST_FAILURE(".*ERROR: World variable count doesn't match # of partitions.*",
|
||||
command("variable ten10 world xxx xxx"););
|
||||
TEST_FAILURE(".*ERROR: All universe/uloop variables must have same # of values.*",
|
||||
command("variable ten4 uloop 2"););
|
||||
command("variable ten6 uloop 2"););
|
||||
TEST_FAILURE(".*ERROR: Incorrect conversion in format string.*",
|
||||
command("variable ten11 format two \"%08x\""););
|
||||
TEST_FAILURE(".*ERROR: Variable name 'ten@12' must have only letters, numbers, or undersc.*",
|
||||
@ -321,6 +325,9 @@ TEST_F(VariableTest, Expressions)
|
||||
command("variable err1 equal v_one/v_ten7");
|
||||
command("variable err2 equal v_one%v_ten7");
|
||||
command("variable err3 equal v_ten7^-v_one");
|
||||
command("variable vec1 vector \"[-2, 0, 1,2 ,3, 5 , 7\n]\"");
|
||||
command("variable vec2 vector v_vec1*0.5");
|
||||
command("variable vec3 equal v_vec2[3]");
|
||||
variable->set("dummy index 1 2");
|
||||
END_HIDE_OUTPUT();
|
||||
|
||||
@ -347,6 +354,9 @@ TEST_F(VariableTest, Expressions)
|
||||
ASSERT_DOUBLE_EQ(variable->compute_equal("v_ten10"), 100);
|
||||
ASSERT_DOUBLE_EQ(variable->compute_equal("v_ten11"), 1);
|
||||
ASSERT_DOUBLE_EQ(variable->compute_equal("v_ten12"), 3);
|
||||
EXPECT_THAT(variable->retrieve("vec1"), StrEq("[-2,0,1,2,3,5,7]"));
|
||||
EXPECT_THAT(variable->retrieve("vec2"), StrEq("[-1,0,0.5,1,1.5,2.5,3.5]"));
|
||||
ASSERT_DOUBLE_EQ(variable->compute_equal("v_vec3"), 0.5);
|
||||
|
||||
TEST_FAILURE(".*ERROR: Variable six: Invalid thermo keyword 'XXX' in variable formula.*",
|
||||
command("print \"${six}\""););
|
||||
@ -402,7 +412,7 @@ TEST_F(VariableTest, Functions)
|
||||
command("print \"$(extract_setting()\""););
|
||||
TEST_FAILURE(".*ERROR on proc 0: Invalid immediate variable.*",
|
||||
command("print \"$(extract_setting()\""););
|
||||
TEST_FAILURE(".*ERROR: Invalid extract_setting.. function syntax in variable formula.*",
|
||||
TEST_FAILURE(".*ERROR: Invalid extract_setting.. function in variable formula.*",
|
||||
command("print \"$(extract_setting(one,two))\""););
|
||||
TEST_FAILURE(
|
||||
".*ERROR: Unknown setting nprocs for extract_setting.. function in variable formula.*",
|
||||
@ -599,9 +609,9 @@ TEST_F(VariableTest, Label2TypeAtomic)
|
||||
ASSERT_DOUBLE_EQ(variable->compute_equal("label2type(atom,O1)"), 3.0);
|
||||
ASSERT_DOUBLE_EQ(variable->compute_equal("label2type(atom,H1)"), 4.0);
|
||||
|
||||
TEST_FAILURE(".*ERROR: Variable t1: Invalid atom type label C1 in variable formula.*",
|
||||
TEST_FAILURE(".*ERROR: Variable t1: Invalid atom type label C1 in label2type.. in variable.*",
|
||||
command("print \"${t1}\""););
|
||||
TEST_FAILURE(".*ERROR: Invalid bond type label H1 in variable formula.*",
|
||||
TEST_FAILURE(".*ERROR: Invalid bond type label H1 in label2type.. in variable.*",
|
||||
variable->compute_equal("label2type(bond,H1)"););
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user