updated doc pages and code
This commit is contained in:
@ -53,15 +53,17 @@ The value *eng* is the interaction energy for the angle.
|
||||
|
||||
The value *v_name* can be used together with the *set* keyword to
|
||||
compute a user-specified function of the angle theta. The *name*
|
||||
specified for the *v_name* value is the name of an :doc:`equal-style variable <variable>` which should evaluate a formula based on a
|
||||
specified for the *v_name* value is the name of an :doc:`equal-style
|
||||
variable <variable>` which should evaluate a formula based on a
|
||||
variable which will store the angle theta. This other variable must
|
||||
be an :doc:`internal-style variable <variable>` defined in the input
|
||||
script; its initial numeric value can be anything. It must be an
|
||||
internal-style variable, because this command resets its value
|
||||
directly. The *set* keyword is used to identify the name of this
|
||||
other variable associated with theta.
|
||||
be an :doc:`internal-style variable <variable>` specified by the *set*
|
||||
keyword. It is an internal-style variable, because this command
|
||||
resets its value directly. The internal-style variable does not need
|
||||
to be defined in the input script (though it can be); if it is not
|
||||
defined, then the *set* option creates an :doc:`internal-style
|
||||
variable <variable>` with the specified name.
|
||||
|
||||
Note that the value of theta for each angle which stored in the
|
||||
Note that the value of theta for each angle which is stored in the
|
||||
internal variable is in radians, not degrees.
|
||||
|
||||
As an example, these commands can be added to the bench/in.rhodo
|
||||
@ -70,7 +72,6 @@ system and output the statistics in various ways:
|
||||
|
||||
.. code-block:: LAMMPS
|
||||
|
||||
variable t internal 0.0
|
||||
variable cos equal cos(v_t)
|
||||
variable cossq equal cos(v_t)*cos(v_t)
|
||||
|
||||
|
||||
@ -118,13 +118,15 @@ moving apart.
|
||||
|
||||
The value *v_name* can be used together with the *set* keyword to
|
||||
compute a user-specified function of the bond distance. The *name*
|
||||
specified for the *v_name* value is the name of an :doc:`equal-style variable <variable>` which should evaluate a formula based on a
|
||||
variable which will store the bond distance. This other variable must
|
||||
be an :doc:`internal-style variable <variable>` defined in the input
|
||||
script; its initial numeric value can be anything. It must be an
|
||||
internal-style variable, because this command resets its value
|
||||
directly. The *set* keyword is used to identify the name of this
|
||||
other variable associated with theta.
|
||||
specified for the *v_name* value is the name of an :doc:`equal-style
|
||||
variable <variable>` which should evaluate a formula based on a
|
||||
variable which stores the bond distance. This other variable must be
|
||||
the :doc:`internal-style variable <variable>` specified by the *set*
|
||||
keyword. It is an internal-style variable, because this command
|
||||
resets its value directly. The internal-style variable does not need
|
||||
to be defined in the input script (though it can be); if it is not
|
||||
defined, then the *set* option creates an :doc:`internal-style
|
||||
variable <variable>` with the specified name.
|
||||
|
||||
As an example, these commands can be added to the bench/in.rhodo
|
||||
script to compute the length\ :math:`^2` of every bond in the system and
|
||||
@ -132,7 +134,6 @@ output the statistics in various ways:
|
||||
|
||||
.. code-block:: LAMMPS
|
||||
|
||||
variable d internal 0.0
|
||||
variable dsq equal v_d*v_d
|
||||
|
||||
compute 1 all property/local batom1 batom2 btype
|
||||
|
||||
@ -45,30 +45,31 @@ interactions. The number of datums generated, aggregated across all
|
||||
processors, equals the number of dihedral angles in the system, modified
|
||||
by the group parameter as explained below.
|
||||
|
||||
The value *phi* (:math:`\phi`) is the dihedral angle, as defined in the diagram
|
||||
on the :doc:`dihedral_style <dihedral_style>` doc page.
|
||||
The value *phi* (:math:`\phi`) is the dihedral angle, as defined in
|
||||
the diagram on the :doc:`dihedral_style <dihedral_style>` doc page.
|
||||
|
||||
The value *v_name* can be used together with the *set* keyword to compute a
|
||||
user-specified function of the dihedral angle :math:`\phi`. The *name*
|
||||
specified for the *v_name* value is the name of an
|
||||
:doc:`equal-style variable <variable>` which should evaluate a formula based on
|
||||
a variable which will store the angle :math:`\phi`. This other variable must
|
||||
be an :doc:`internal-style variable <variable>` defined in the input
|
||||
script; its initial numeric value can be anything. It must be an
|
||||
internal-style variable, because this command resets its value
|
||||
directly. The *set* keyword is used to identify the name of this
|
||||
other variable associated with :math:`\phi`.
|
||||
The value *v_name* can be used together with the *set* keyword to
|
||||
compute a user-specified function of the dihedral angle :math:`\phi`.
|
||||
The *name* specified for the *v_name* value is the name of an
|
||||
:doc:`equal-style variable <variable>` which should evaluate a formula
|
||||
based on a variable which will store the angle :math:`\phi`. This
|
||||
other variable must be an :doc:`internal-style variable <variable>`
|
||||
specified by the *set* keyword. It is an internal-style variable,
|
||||
because this command resets its value directly. The internal-style
|
||||
variable does not need to be defined in the input script (though it
|
||||
can be); if it is not defined, then the *set* option creates an
|
||||
:doc:`internal-style variable <variable>` with the specified name.
|
||||
|
||||
Note that the value of :math:`\phi` for each angle which stored in the internal
|
||||
variable is in radians, not degrees.
|
||||
Note that the value of :math:`\phi` for each angle which stored in the
|
||||
internal variable is in radians, not degrees.
|
||||
|
||||
As an example, these commands can be added to the bench/in.rhodo
|
||||
script to compute the :math:`\cos\phi` and :math:`\cos^2\phi` of every dihedral
|
||||
angle in the system and output the statistics in various ways:
|
||||
script to compute the :math:`\cos\phi` and :math:`\cos^2\phi` of every
|
||||
dihedral angle in the system and output the statistics in various
|
||||
ways:
|
||||
|
||||
.. code-block:: LAMMPS
|
||||
|
||||
variable p internal 0.0
|
||||
variable cos equal cos(v_p)
|
||||
variable cossq equal cos(v_p)*cos(v_p)
|
||||
|
||||
@ -100,10 +101,10 @@ no consistent ordering of the entries within the local vector or array
|
||||
from one timestep to the next. The only consistency that is
|
||||
guaranteed is that the ordering on a particular timestep will be the
|
||||
same for local vectors or arrays generated by other compute commands.
|
||||
For example, dihedral output from the
|
||||
:doc:`compute property/local <compute_property_local>` command can be combined
|
||||
with data from this command and output by the :doc:`dump local <dump>`
|
||||
command in a consistent way.
|
||||
For example, dihedral output from the :doc:`compute property/local
|
||||
<compute_property_local>` command can be combined with data from this
|
||||
command and output by the :doc:`dump local <dump>` command in a
|
||||
consistent way.
|
||||
|
||||
Here is an example of how to do this:
|
||||
|
||||
|
||||
@ -416,24 +416,23 @@ atom, based on its coordinates. They apply to all styles except
|
||||
*single*. The *name* specified for the *var* keyword is the name of
|
||||
an :doc:`equal-style variable <variable>` that should evaluate to a
|
||||
zero or non-zero value based on one or two or three variables that
|
||||
will store the *x*, *y*, or *z* coordinates of an atom (one variable per
|
||||
coordinate). If used, these other variables must be
|
||||
:doc:`internal-style variables <variable>` defined in the input
|
||||
script; their initial numeric value can be anything. They must be
|
||||
internal-style variables, because this command resets their values
|
||||
directly. The *set* keyword is used to identify the names of these
|
||||
other variables, one variable for the *x*-coordinate of a created atom,
|
||||
one for *y*, and one for *z*.
|
||||
will store the *x*, *y*, or *z* coordinates of an atom (one variable
|
||||
per coordinate). If used, these other variables must be specified by
|
||||
the *set* keyword. They are internal-style variable, because this
|
||||
command resets their values directly. The internal-style variables do
|
||||
not need to be defined in the input script (though they can be); if
|
||||
one (or more) is not defined, then the *set* option creates an
|
||||
:doc:`internal-style variable <variable>` with the specified name.
|
||||
|
||||
.. figure:: img/sinusoid.jpg
|
||||
:figwidth: 50%
|
||||
:align: right
|
||||
:target: _images/sinusoid.jpg
|
||||
|
||||
When an atom is created, its :math:`(x,y,z)` coordinates become the values for
|
||||
any *set* variable that is defined. The *var* variable is then
|
||||
evaluated. If the returned value is 0.0, the atom is not created. If
|
||||
it is non-zero, the atom is created.
|
||||
When an atom is about to be created, its :math:`(x,y,z)` coordinates
|
||||
become the values for any *set* variable that is defined. The *var*
|
||||
variable is then evaluated. If the returned value is 0.0, the atom is
|
||||
not created. If it is non-zero, the atom is created.
|
||||
|
||||
As an example, these commands can be used in a 2d simulation, to
|
||||
create a sinusoidal surface. Note that the surface is "rough" due to
|
||||
@ -456,8 +455,6 @@ converts lattice spacings to distance.
|
||||
region box block 0 $x 0 $y -0.5 0.5
|
||||
create_box 1 box
|
||||
|
||||
variable xx internal 0.0
|
||||
variable yy internal 0.0
|
||||
variable v equal "(0.2*v_y*ylat * cos(v_xx/xlat * 2.0*PI*4.0/v_x) + 0.5*v_y*ylat - v_yy) > 0.0"
|
||||
create_atoms 1 box var v set x xx set y yy
|
||||
write_dump all atom sinusoid.lammpstrj
|
||||
|
||||
@ -98,52 +98,53 @@ the following dynamic equation:
|
||||
|
||||
\frac{dc}{dt} = -\alpha (K_p e + K_i \int_0^t e \, dt + K_d \frac{de}{dt} )
|
||||
|
||||
where *c* is the continuous time analog of the control variable,
|
||||
*e* =\ *pvar*\ -\ *setpoint* is the error in the process variable, and
|
||||
:math:`\alpha`, :math:`K_p`, :math:`K_i` , and :math:`K_d` are constants
|
||||
set by the corresponding
|
||||
keywords described above. The discretized version of this equation is:
|
||||
where *c* is the continuous time analog of the control variable, *e*
|
||||
=\ *pvar*\ -\ *setpoint* is the error in the process variable, and
|
||||
:math:`\alpha`, :math:`K_p`, :math:`K_i` , and :math:`K_d` are
|
||||
constants set by the corresponding keywords described above. The
|
||||
discretized version of this equation is:
|
||||
|
||||
.. math::
|
||||
|
||||
c_n = c_{n-1} -\alpha \left( K_p \tau e_n + K_i \tau^2 \sum_{i=1}^n e_i + K_d (e_n - e_{n-1}) \right)
|
||||
|
||||
where :math:`\tau = \mathtt{Nevery} \cdot \mathtt{timestep}` is the time
|
||||
interval between updates,
|
||||
and the subscripted variables indicate the values of *c* and *e* at
|
||||
successive updates.
|
||||
where :math:`\tau = \mathtt{Nevery} \cdot \mathtt{timestep}` is the
|
||||
time interval between updates, and the subscripted variables indicate
|
||||
the values of *c* and *e* at successive updates.
|
||||
|
||||
From the first equation, it is clear that if the three gain values
|
||||
:math:`K_p`, :math:`K_i`, :math:`K_d` are dimensionless constants,
|
||||
then :math:`\alpha` must have
|
||||
units of [unit *cvar*\ ]/[unit *pvar*\ ]/[unit time] e.g. [ eV/K/ps
|
||||
]. The advantage of this unit scheme is that the value of the
|
||||
constants should be invariant under a change of either the MD timestep
|
||||
size or the value of *Nevery*\ . Similarly, if the LAMMPS :doc:`unit style <units>` is changed, it should only be necessary to change
|
||||
the value of :math:`\alpha` to reflect this, while leaving :math:`K_p`,
|
||||
:math:`K_i`, and :math:`K_d` unaltered.
|
||||
then :math:`\alpha` must have units of [unit *cvar*\ ]/[unit *pvar*\
|
||||
]/[unit time] e.g. [ eV/K/ps ]. The advantage of this unit scheme is
|
||||
that the value of the constants should be invariant under a change of
|
||||
either the MD timestep size or the value of *Nevery*\ . Similarly, if
|
||||
the LAMMPS :doc:`unit style <units>` is changed, it should only be
|
||||
necessary to change the value of :math:`\alpha` to reflect this, while
|
||||
leaving :math:`K_p`, :math:`K_i`, and :math:`K_d` unaltered.
|
||||
|
||||
When choosing the values of the four constants, it is best to first
|
||||
pick a value and sign for :math:`\alpha` that is consistent with the
|
||||
magnitudes and signs of *pvar* and *cvar*\ . The magnitude of :math:`K_p`
|
||||
should then be tested over a large positive range keeping :math:`K_i = K_d =0`.
|
||||
A good value for :math:`K_p` will produce a fast response in *pvar*,
|
||||
without overshooting the *setpoint*\ . For many applications, proportional
|
||||
feedback is sufficient, and so :math:`K_i = K_d =0` can be used. In cases
|
||||
where there is a substantial lag time in the response of *pvar* to a change
|
||||
in *cvar*, this can be counteracted by increasing :math:`K_d`. In situations
|
||||
magnitudes and signs of *pvar* and *cvar*\ . The magnitude of
|
||||
:math:`K_p` should then be tested over a large positive range keeping
|
||||
:math:`K_i = K_d =0`. A good value for :math:`K_p` will produce a
|
||||
fast response in *pvar*, without overshooting the *setpoint*\ . For
|
||||
many applications, proportional feedback is sufficient, and so
|
||||
:math:`K_i = K_d =0` can be used. In cases where there is a
|
||||
substantial lag time in the response of *pvar* to a change in *cvar*,
|
||||
this can be counteracted by increasing :math:`K_d`. In situations
|
||||
where *pvar* plateaus without reaching *setpoint*, this can be
|
||||
counteracted by increasing :math:`K_i`. In the language of Charles Dickens,
|
||||
:math:`K_p` represents the error of the present, :math:`K_i` the error of
|
||||
the past, and :math:`K_d` the error yet to come.
|
||||
counteracted by increasing :math:`K_i`. In the language of Charles
|
||||
Dickens, :math:`K_p` represents the error of the present, :math:`K_i`
|
||||
the error of the past, and :math:`K_d` the error yet to come.
|
||||
|
||||
Because this fix updates *cvar*, but does not initialize its value,
|
||||
the initial value :math:`c_0` is that assigned by the user in the input script via
|
||||
the :doc:`internal-style variable <variable>` command. This value is
|
||||
used (by every other LAMMPS command that uses the variable) until this
|
||||
fix performs its first update of *cvar* after *Nevery* timesteps. On
|
||||
the first update, the value of the derivative term is set to zero,
|
||||
because the value of :math:`e_{n-1}` is not yet defined.
|
||||
the initial value :math:`c_0` is that assigned by the user in the
|
||||
input script via the :doc:`internal-style variable <variable>`
|
||||
command. This value is used (by every other LAMMPS command that uses
|
||||
the variable) until this fix performs its first update of *cvar* after
|
||||
*Nevery* timesteps. On the first update, the value of the derivative
|
||||
term is set to zero, because the value of :math:`e_{n-1}` is not yet
|
||||
defined.
|
||||
|
||||
----------
|
||||
|
||||
@ -154,21 +155,23 @@ must produce a global quantity, not a per-atom or local quantity.
|
||||
|
||||
If *pvar* begins with "c\_", a compute ID must follow which has been
|
||||
previously defined in the input script and which generates a global
|
||||
scalar or vector. See the individual :doc:`compute <compute>` doc page
|
||||
for details. If no bracketed integer is appended, the scalar
|
||||
scalar or vector. See the individual :doc:`compute <compute>` doc
|
||||
page for details. If no bracketed integer is appended, the scalar
|
||||
calculated by the compute is used. If a bracketed integer is
|
||||
appended, the Ith value of the vector calculated by the compute is
|
||||
used. Users can also write code for their own compute styles and :doc:`add them to LAMMPS <Modify>`.
|
||||
used. Users can also write code for their own compute styles and
|
||||
:doc:`add them to LAMMPS <Modify>`.
|
||||
|
||||
If *pvar* begins with "f\_", a fix ID must follow which has been
|
||||
previously defined in the input script and which generates a global
|
||||
scalar or vector. See the individual :doc:`fix <fix>` page for
|
||||
details. Note that some fixes only produce their values on certain
|
||||
timesteps, which must be compatible with when fix controller
|
||||
references the values, or else an error results. If no bracketed integer
|
||||
is appended, the scalar calculated by the fix is used. If a bracketed
|
||||
integer is appended, the Ith value of the vector calculated by the fix
|
||||
is used. Users can also write code for their own fix style and :doc:`add them to LAMMPS <Modify>`.
|
||||
references the values, or else an error results. If no bracketed
|
||||
integer is appended, the scalar calculated by the fix is used. If a
|
||||
bracketed integer is appended, the Ith value of the vector calculated
|
||||
by the fix is used. Users can also write code for their own fix style
|
||||
and :doc:`add them to LAMMPS <Modify>`.
|
||||
|
||||
If *pvar* begins with "v\_", a variable name must follow which has been
|
||||
previously defined in the input script. Only equal-style variables
|
||||
@ -182,19 +185,21 @@ variable.
|
||||
The target value *setpoint* for the process variable must be a numeric
|
||||
value, in whatever units *pvar* is defined for.
|
||||
|
||||
The control variable *cvar* must be the name of an :doc:`internal-style variable <variable>` previously defined in the input script. Note
|
||||
that it is not specified with a "v\_" prefix, just the name of the
|
||||
variable. It must be an internal-style variable, because this fix
|
||||
updates its value directly. Note that other commands can use an
|
||||
equal-style versus internal-style variable interchangeably.
|
||||
The control variable *cvar* must be the name of an
|
||||
:doc:`internal-style variable <variable>` previously defined in the
|
||||
input script. Note that it is not specified with a "v\_" prefix, just
|
||||
the name of the variable. It must be an internal-style variable,
|
||||
because this fix updates its value directly. Note that other commands
|
||||
can use an equal-style versus internal-style variable interchangeably.
|
||||
|
||||
----------
|
||||
|
||||
Restart, fix_modify, output, run start/stop, minimize info
|
||||
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
|
||||
|
||||
Currently, no information about this fix is written to :doc:`binary restart files <restart>`. None of the :doc:`fix_modify <fix_modify>` options
|
||||
are relevant to this fix.
|
||||
Currently, no information about this fix is written to :doc:`binary
|
||||
restart files <restart>`. None of the :doc:`fix_modify <fix_modify>`
|
||||
options are relevant to this fix.
|
||||
|
||||
This fix produces a global vector with 3 values which can be accessed
|
||||
by various :doc:`output commands <Howto_output>`. The values can be
|
||||
@ -211,7 +216,8 @@ variable is in. The vector values calculated by this fix are
|
||||
"extensive".
|
||||
|
||||
No parameter of this fix can be used with the *start/stop* keywords of
|
||||
the :doc:`run <run>` command. This fix is not invoked during :doc:`energy minimization <minimize>`.
|
||||
the :doc:`run <run>` command. This fix is not invoked during
|
||||
:doc:`energy minimization <minimize>`.
|
||||
|
||||
Restrictions
|
||||
""""""""""""
|
||||
|
||||
@ -225,22 +225,25 @@ rotated configuration of the molecule.
|
||||
|
||||
.. versionadded:: 21Nov2023
|
||||
|
||||
The *var* and *set* keywords can be used together to provide a criterion
|
||||
for accepting or rejecting the addition of an individual atom, based on its
|
||||
coordinates. The *name* specified for the *var* keyword is the name of an
|
||||
:doc:`equal-style variable <variable>` that should evaluate to a zero or
|
||||
non-zero value based on one or two or three variables that will store the
|
||||
*x*, *y*, or *z* coordinates of an atom (one variable per coordinate). If
|
||||
used, these other variables must be :doc:`internal-style variables
|
||||
<variable>` defined in the input script; their initial numeric value can be
|
||||
anything. They must be internal-style variables, because this command
|
||||
resets their values directly. The *set* keyword is used to identify the
|
||||
names of these other variables, one variable for the *x*-coordinate of a
|
||||
created atom, one for *y*, and one for *z*. When an atom is created, its
|
||||
:math:`(x,y,z)` coordinates become the values for any *set* variable that
|
||||
is defined. The *var* variable is then evaluated. If the returned value
|
||||
is 0.0, the atom is not created. If it is non-zero, the atom is created.
|
||||
For an example of how to use these keywords, see the
|
||||
The *var* and *set* keywords can be used together to provide a
|
||||
criterion for accepting or rejecting the addition of an individual
|
||||
atom, based on its coordinates. The *name* specified for the *var*
|
||||
keyword is the name of an :doc:`equal-style variable <variable>` that
|
||||
should evaluate to a zero or non-zero value based on one or two or
|
||||
three variables that will store the *x*, *y*, or *z* coordinates of an
|
||||
atom (one variable per coordinate). If used, these other variables
|
||||
must be :doc:`internal-style variables <variable>` specified by the
|
||||
*set* keyword. They must be internal-style variables, because this
|
||||
command resets their values directly. The internal-style variables do
|
||||
not need to be defined in the input script (though they can be); if
|
||||
one (or more) is not defined, then the *set* option creates an
|
||||
:doc:`internal-style variable <variable>` with the specified name.
|
||||
|
||||
When an atom is about to be created, its :math:`(x,y,z)` coordinates
|
||||
become the values for any *set* variable that is defined. The *var*
|
||||
variable is then evaluated. If the returned value is 0.0, the atom is
|
||||
not created. If it is non-zero, the atom is created. For an example
|
||||
of how to use the set/var keywords in a similar context, see the
|
||||
:doc:`create_atoms <create_atoms>` command.
|
||||
|
||||
The *rate* option moves the insertion volume in the z direction (3d)
|
||||
@ -304,12 +307,13 @@ units of distance or velocity.
|
||||
Restart, fix_modify, output, run start/stop, minimize info
|
||||
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
|
||||
|
||||
This fix writes the state of the deposition to :doc:`binary restart files <restart>`. This includes information about how many
|
||||
particles have been deposited, the random number generator seed, the
|
||||
next timestep for deposition, etc. See the
|
||||
:doc:`read_restart <read_restart>` command for info on how to re-specify
|
||||
a fix in an input script that reads a restart file, so that the
|
||||
operation of the fix continues in an uninterrupted fashion.
|
||||
This fix writes the state of the deposition to :doc:`binary restart
|
||||
files <restart>`. This includes information about how many particles
|
||||
have been deposited, the random number generator seed, the next
|
||||
timestep for deposition, etc. See the :doc:`read_restart
|
||||
<read_restart>` command for info on how to re-specify a fix in an
|
||||
input script that reads a restart file, so that the operation of the
|
||||
fix continues in an uninterrupted fashion.
|
||||
|
||||
.. note::
|
||||
|
||||
|
||||
@ -10,43 +10,45 @@ Syntax
|
||||
|
||||
python mode keyword args ...
|
||||
|
||||
* mode = *source* or name of Python function
|
||||
* mode = *source* or *name* of Python function
|
||||
|
||||
if mode is *source*:
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
keyword = *here* or name of a *Python file*
|
||||
*here* arg = inline
|
||||
inline = one or more lines of Python code which defines func
|
||||
must be a single argument, typically enclosed between triple quotes
|
||||
*here* arg = one or more lines of Python code
|
||||
must be a single argument, typically enclosed between triple quotes
|
||||
the in-lined Python code will be executed immediately
|
||||
*Python file* = name of a file with Python code which will be executed immediately
|
||||
|
||||
* if *mode* is the name of a Python function, one or more keywords with/without arguments must be appended
|
||||
* if *mode* is *name* of a Python function:
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
one or more keywords with/without arguments must be appended
|
||||
keyword = *invoke* or *input* or *return* or *format* or *length* or *file* or *here* or *exists*
|
||||
*invoke* arg = none = invoke the previously defined Python function
|
||||
*invoke* arg = none = invoke the previously-defined Python function
|
||||
*input* args = N i1 i2 ... iN
|
||||
N = # of inputs to function
|
||||
i1,...,iN = value, SELF, or LAMMPS variable name
|
||||
value = integer number, floating point number, or string
|
||||
SELF = reference to LAMMPS itself which can be accessed by Python function
|
||||
variable = v_name, where name = name of LAMMPS variable, e.g. v_abc
|
||||
SELF = reference to LAMMPS itself which can then be accessed by Python function
|
||||
variable = v_name, where name = name of a LAMMPS variable, e.g. v_abc
|
||||
internal variable = iv_name, where name = name of a LAMMPS internal-style variable, e.g. iv_xyz
|
||||
*return* arg = varReturn
|
||||
varReturn = v_name = LAMMPS variable name which the return value of the Python function will be assigned to
|
||||
*format* arg = fstring with M characters
|
||||
M = N if no return value, where N = # of inputs
|
||||
M = N+1 if there is a return value
|
||||
fstring = each character (i,f,s,p) corresponds in order to an input or return value
|
||||
'i' = integer, 'f' = floating point, 's' = string, 'p' = SELF
|
||||
fstring = each character (i,f,s,p) corresponds (in order) to an input or return value
|
||||
'i' = integer, 'f' = floating point, 's' = string, 'p' = SELF
|
||||
*length* arg = Nlen
|
||||
Nlen = max length of string returned from Python function
|
||||
*file* arg = filename
|
||||
filename = file of Python code, which defines func
|
||||
filename = file of Python code, which defines the Python function
|
||||
*here* arg = inline
|
||||
inline = one or more lines of Python code which defines func
|
||||
inline = one or more lines of Python code which defines the Python function
|
||||
must be a single argument, typically enclosed between triple quotes
|
||||
*exists* arg = none = Python code has been loaded by previous python command
|
||||
|
||||
@ -87,37 +89,43 @@ Examples
|
||||
Description
|
||||
"""""""""""
|
||||
|
||||
The *python* command allows interfacing LAMMPS with an embedded Python
|
||||
interpreter and enables either executing arbitrary python code in that
|
||||
interpreter, registering a Python function for future execution (as a
|
||||
python style variable, from a fix interfaced with python, or for direct
|
||||
invocation), or invoking such a previously registered function.
|
||||
The *python* command interfaces LAMMPS with an embedded Python
|
||||
interpreter and enables executing arbitrary python code in that
|
||||
interpreter. This can be done immediately, by using *mode* =
|
||||
*source*. Or execution can be deferred, by registering a Python
|
||||
function for later execution, by using *mode* = *name* of a Python
|
||||
function.
|
||||
|
||||
Arguments, including LAMMPS variables, can be passed to the function
|
||||
from the LAMMPS input script and a value returned by the Python function
|
||||
assigned to a LAMMPS variable. The Python code for the function can be included
|
||||
directly in the input script or in a separate Python file. The function
|
||||
can be standard Python code or it can make "callbacks" to LAMMPS through
|
||||
its library interface to query or set internal values within LAMMPS.
|
||||
This is a powerful mechanism for performing complex operations in a
|
||||
LAMMPS input script that are not possible with the simple input script
|
||||
and variable syntax which LAMMPS defines. Thus your input script can
|
||||
operate more like a true programming language.
|
||||
Later execution can be triggered in one of two ways. One is to use
|
||||
the python command again with its *invoke* keyword. The other is to
|
||||
trigger the evaluation of a python-style, equal-style, or atom-style
|
||||
variable. A python-style variable invokes its associated Python
|
||||
function; its return value becomes the value of the python-style
|
||||
variable. Equal- and atom-style variables can use a Python function
|
||||
wrapper in their formulas which encodes the Python function name, and
|
||||
specifies arguments to pass to the function.
|
||||
|
||||
Note python-style, equal-style, and atom-style variables can be used
|
||||
in many different ways within LAMMPS. They can be evaulated directly
|
||||
in an input script, effectively replacing the variable with its value.
|
||||
Or they can be passed to various commands as arguments, so that the
|
||||
variable is evaluated multiple times during a simulation run. See the
|
||||
:doc:`variable <variable>` command doc page for more details on
|
||||
variable styles which enable Python function evaluation.
|
||||
|
||||
The Python code for the function can be included directly in the input
|
||||
script or in a separate Python file. The function can be standard
|
||||
Python code or it can make "callbacks" to LAMMPS through its library
|
||||
interface to query or set internal values within LAMMPS. This is a
|
||||
powerful mechanism for performing complex operations in a LAMMPS input
|
||||
script that are not possible with the simple input script and variable
|
||||
syntax which LAMMPS defines. Thus your input script can operate more
|
||||
like a true programming language.
|
||||
|
||||
Use of this command requires building LAMMPS with the PYTHON package
|
||||
which links to the Python library so that the Python interpreter is
|
||||
embedded in LAMMPS. More details about this process are given below.
|
||||
|
||||
There are two ways to invoke a Python function once it has been
|
||||
registered. One is using the *invoke* keyword. The other is to assign
|
||||
the function to a :doc:`python-style variable <variable>` defined in
|
||||
your input script. Whenever the variable is evaluated, it will execute
|
||||
the Python function to assign a value to the variable. Note that
|
||||
variables can be evaluated in many different ways within LAMMPS. They
|
||||
can be substituted with their result directly in an input script, or
|
||||
they can be passed to various commands as arguments, so that the
|
||||
variable is evaluated during a simulation run.
|
||||
|
||||
A broader overview of how Python can be used with LAMMPS is given in the
|
||||
:doc:`Use Python with LAMMPS <Python_head>` section of the
|
||||
documentation. There also is an ``examples/python`` directory which
|
||||
@ -125,25 +133,31 @@ illustrates use of the python command.
|
||||
|
||||
----------
|
||||
|
||||
The first argument of the *python* command is either the *source*
|
||||
keyword or the name of a Python function. This defines the mode
|
||||
of the python command.
|
||||
The first argument is the *mode* setting, which is either *source* or
|
||||
the *name* of a Python function.
|
||||
|
||||
.. versionchanged:: 22Dec2022
|
||||
|
||||
If the *source* keyword is used, it is followed by either a file name or
|
||||
the *here* keyword. No other keywords can be used. The *here* keyword
|
||||
is followed by a string with python commands, either on a single line
|
||||
enclosed in quotes, or as multiple lines enclosed in triple quotes.
|
||||
These Python commands will be passed to the python interpreter and
|
||||
executed immediately without registering a Python function for future
|
||||
execution. The code will be loaded into and run in the "main" module of
|
||||
the Python interpreter. This allows running arbitrary Python code at
|
||||
any time while processing the LAMMPS input file. This can be used to
|
||||
pre-load Python modules, initialize global variables, define functions
|
||||
or classes, or perform operations using the python programming language.
|
||||
The Python code will be executed in parallel on all MPI processes. No
|
||||
arguments can be passed.
|
||||
If *source* is used, it is followed by either the *here* keyword or a
|
||||
file name containing Python code. The *here* keyword is followed by a
|
||||
string containing python commands, either on a single line enclosed in
|
||||
quotes, or as multiple lines enclosed in triple quotes. In either
|
||||
case, the in-line code or file contents are passed to the python
|
||||
interpreter and executed immediately. The code will be loaded into
|
||||
and run in the "main" module of the Python interpreter. This allows
|
||||
running arbitrary Python code at any time while processing the SPARTA
|
||||
input file. This can be used to pre-load Python modules, initialize
|
||||
global variables, define functions or classes, or perform operations
|
||||
using the Python programming language. The Python code will be
|
||||
executed in parallel on all the MPI processes being used to run
|
||||
LAMMPS. Note that no arguments can be passed to the executed Python
|
||||
code.
|
||||
|
||||
If the *mode* setting is the *name* of a Python function, then it will
|
||||
be registered with SPARTA for future execution (or already be defined,
|
||||
see the *exists* keyword). One or more keywords must follow the
|
||||
*mode* function name. One of the keywords must be *invoke*, *file*,
|
||||
*here*, or *exists*.
|
||||
|
||||
In all other cases, the first argument is the name of a Python function
|
||||
that will be registered with LAMMPS for future execution. The function
|
||||
@ -154,40 +168,79 @@ If the *invoke* keyword is used, no other keywords can be used, and a
|
||||
previous *python* command must have registered the Python function
|
||||
referenced by this command. This invokes the Python function with the
|
||||
previously defined arguments and the return value is processed as
|
||||
explained below. You can invoke the function as many times as you wish
|
||||
in your input script.
|
||||
explained below. You can invoke a registered function as many times
|
||||
as you wish in your input script.
|
||||
|
||||
NOTE: As indicated with a NOTE in python_impl.cpp, I don't think there
|
||||
is any access to a value returned by invoking a Py function in this way.
|
||||
If that is correct, I think this should be clarified in the doc page,
|
||||
with a better explanation of the utility of using the *invoke* keyword.
|
||||
|
||||
The *input* keyword defines how many arguments *N* the Python function
|
||||
expects. If it takes no arguments, then the *input* keyword should not
|
||||
be used. Each argument can be specified directly as a value, e.g. '6'
|
||||
or '3.14159' or 'abc' (a string of characters). The type of each
|
||||
argument is specified by the *format* keyword as explained below, so
|
||||
that Python will know how to interpret the value. If the word SELF is
|
||||
used for an argument it has a special meaning. A pointer is passed to
|
||||
the Python function which it can convert into a reference to LAMMPS
|
||||
expects. If it takes no arguments, then the *input* keyword should
|
||||
not be used. Each argument can be specified directly as a value,
|
||||
e.g. '6' or '3.14159' or 'abc' (a string of characters). The type of
|
||||
each argument is specified by the *format* keyword as explained below,
|
||||
so that Python will know how to interpret the value. If the word SELF
|
||||
is used for an argument it has a special meaning. A pointer is passed
|
||||
to the Python function which it can convert into a reference to LAMMPS
|
||||
itself using the :doc:`LAMMPS Python module <Python_module>`. This
|
||||
enables the function to call back to LAMMPS through its library
|
||||
interface as explained below. This allows the Python function to query
|
||||
or set values internal to LAMMPS which can affect the subsequent
|
||||
execution of the input script. A LAMMPS variable can also be used as an
|
||||
argument, specified as v_name, where "name" is the name of the variable.
|
||||
Any style of LAMMPS variable returning a scalar or a string can be used,
|
||||
as defined by the :doc:`variable <variable>` command. The *format*
|
||||
keyword must be used to set the type of data that is passed to Python.
|
||||
interface as explained below. This allows the Python function to
|
||||
query or set values internal to LAMMPS which can affect the subsequent
|
||||
execution of the input script.
|
||||
|
||||
A LAMMPS variable can also be used as an *input* argument, specified
|
||||
as v_name, where "name" is the name of the variable defined in the
|
||||
input script. Any style of LAMMPS variable returning a scalar or a
|
||||
string can be used, as defined by the :doc:`variable <variable>`
|
||||
command. The style of variable must be consistent with the *format*
|
||||
keyword specification for the type of data that is passed to Python.
|
||||
Each time the Python function is invoked, the LAMMPS variable is
|
||||
evaluated and its value is passed to the Python function.
|
||||
evaluated and its value is passed as an argument to the Python
|
||||
function.
|
||||
|
||||
A LAMMPS internal-style variable can also be used as an *input*
|
||||
argument, specified as iv_name, where "name" is the name of the
|
||||
internal-style variable. The internal-style variable does not have to
|
||||
be defined in the input script (though it can be); if it is not
|
||||
defined, this command creates an :doc:`internal-style variable
|
||||
<variable>` with the specified name.
|
||||
|
||||
An internal-style variable must be used when an equal-style or
|
||||
atom-style variable triggers the invocation of the Python function
|
||||
defined by this command, by including a Python function wrapper in its
|
||||
formula, with one or more arguments also included in the formula.
|
||||
|
||||
In brief, the syntax for a Python function wrapper in a variable
|
||||
formula is py_varname(arg1,arg2,...argN), where "varname" is the name
|
||||
of a python-style variable associated with a Python function defined
|
||||
by this command. One or more arguments to the function wrapper can
|
||||
themselves be formulas which the variable command will evaluate and
|
||||
pass as arguments to the Python function. This is done by assigning
|
||||
the numeric result for each argument to an internal-style variable;
|
||||
this the *input* keyword must specify the arguments as internal-style
|
||||
variables and their format (see below) as "f" for floating point.
|
||||
This is because LAMMPS variable formulas are calculated with floating
|
||||
point arithmetic (any integer values are converted to floating point).
|
||||
|
||||
See the :doc:`variable <variable>` command doc page for full details
|
||||
on formula syntax including for Python function wrappers. Examples
|
||||
using Python function wrappers are shown below.
|
||||
|
||||
The *return* keyword is only needed if the Python function returns a
|
||||
value. The specified *varReturn* must be of the form v_name, where
|
||||
"name" is the name of a python-style LAMMPS variable, defined by the
|
||||
value. The specified *varReturn* is of the form v_name, where "name"
|
||||
is the name of a python-style LAMMPS variable, defined by the
|
||||
:doc:`variable <variable>` command. The Python function can return a
|
||||
numeric or string value, as specified by the *format* keyword.
|
||||
|
||||
As explained on the :doc:`variable <variable>` doc page, the definition
|
||||
of a python-style variable associates a Python function name with the
|
||||
variable. This must match the *Python function name* first argument of
|
||||
the *python* command. For example these two commands would be
|
||||
consistent:
|
||||
----------
|
||||
|
||||
As explained on the :doc:`variable <variable>` doc page, the
|
||||
definition of a python-style variable associates a Python function
|
||||
name with the variable. Its specification must match the *mode*
|
||||
argument of the *python* command for the Python function name. For
|
||||
example these two commands would be consistent:
|
||||
|
||||
.. code-block:: LAMMPS
|
||||
|
||||
@ -196,43 +249,43 @@ consistent:
|
||||
|
||||
The two commands can appear in either order in the input script so
|
||||
long as both are specified before the Python function is invoked for
|
||||
the first time. Afterwards, the variable 'foo' is associated with
|
||||
the Python function 'myMultiply'.
|
||||
the first time.
|
||||
|
||||
The *format* keyword must be used if the *input* or *return* keywords
|
||||
are used. It defines an *fstring* with M characters, where M = sum of
|
||||
number of inputs and outputs. The order of characters corresponds to
|
||||
the N inputs, followed by the return value (if it exists). Each
|
||||
character must be one of the following: "i" for integer, "f" for
|
||||
floating point, "s" for string, or "p" for SELF. Each character defines
|
||||
the type of the corresponding input or output value of the Python
|
||||
function and affects the type conversion that is performed internally as
|
||||
data is passed back and forth between LAMMPS and Python. Note that it
|
||||
is permissible to use a :doc:`python-style variable <variable>` in a
|
||||
LAMMPS command that allows for an equal-style variable as an argument,
|
||||
but only if the output of the Python function is flagged as a numeric
|
||||
value ("i" or "f") via the *format* keyword.
|
||||
floating point, "s" for string, or "p" for SELF. Each character
|
||||
defines the type of the corresponding input or output value of the
|
||||
Python function and affects the type conversion that is performed
|
||||
internally as data is passed back and forth between LAMMPS and Python.
|
||||
Note that it is permissible to use a :doc:`python-style variable
|
||||
<variable>` in a LAMMPS command that allows for an equal-style
|
||||
variable as an argument, but only if the output of the Python function
|
||||
is flagged as a numeric value ("i" or "f") via the *format* keyword.
|
||||
|
||||
If the *return* keyword is used and the *format* keyword specifies the
|
||||
output as a string, then the default maximum length of that string is
|
||||
63 characters (64-1 for the string terminator). If you want to return
|
||||
a longer string, the *length* keyword can be specified with its *Nlen*
|
||||
value set to a larger number (the code allocates space for Nlen+1 to
|
||||
include the string terminator). If the Python function generates a
|
||||
value set to a larger number. LAMMPS will then allocate Nlen+1 space
|
||||
to include the string terminator. If the Python function generates a
|
||||
string longer than the default 63 or the specified *Nlen*, it will be
|
||||
truncated.
|
||||
|
||||
----------
|
||||
|
||||
Either the *file*, *here*, or *exists* keyword must be used, but only
|
||||
one of them. These keywords specify what Python code to load into the
|
||||
Python interpreter. The *file* keyword gives the name of a file
|
||||
containing Python code, which should end with a ".py" suffix. The code
|
||||
will be immediately loaded into and run in the "main" module of the
|
||||
Python interpreter. The Python code will be executed in parallel on all
|
||||
MPI processes. Note that Python code which contains a function
|
||||
definition does not "execute" the function when it is run; it simply
|
||||
defines the function so that it can be invoked later.
|
||||
As noted above, either the *invoke*, *file*, *here*, or *exists*
|
||||
keyword must be used, but only one of them. These keywords specify
|
||||
what Python code to load into the Python interpreter. The *file*
|
||||
keyword gives the name of a file containing Python code, which should
|
||||
end with a ".py" suffix. The code will be immediately loaded into and
|
||||
run in the "main" module of the Python interpreter. The Python code
|
||||
will be executed in parallel on all MPI processes. Note that Python
|
||||
code which contains a function definition does not "execute" the
|
||||
function when it is run; it simply defines the function so that it can
|
||||
be invoked later.
|
||||
|
||||
The *here* keyword does the same thing, except that the Python code
|
||||
follows as a single argument to the *here* keyword. This can be done
|
||||
@ -243,15 +296,18 @@ proper indentation, blank lines, and comments, as desired. See the
|
||||
how triple quotes can be used as part of input script syntax.
|
||||
|
||||
The *exists* keyword takes no argument. It means that Python code
|
||||
containing the required Python function with the given name has already
|
||||
been executed, for example by a *python source* command or in the same
|
||||
file that was used previously with the *file* keyword.
|
||||
containing the required Python function with the given name has
|
||||
already been executed, for example by a *python source* command or in
|
||||
the same file that was used previously with the *file* keyword. This
|
||||
allows use of a single file of Python code which contains multiple
|
||||
functions, any of which can be used in the same (or different) input
|
||||
scripts (see below).
|
||||
|
||||
Note that the Python code that is loaded and run must contain a function
|
||||
with the specified function name. To operate properly when later
|
||||
invoked, the function code must match the *input* and *return* and
|
||||
*format* keywords specified by the python command. Otherwise Python
|
||||
will generate an error.
|
||||
Note that the Python code that is loaded and run by the *file* or
|
||||
*here* keyword must contain a function with the specified function
|
||||
name. To operate properly when later invoked, the function code must
|
||||
match the *input* and *return* and *format* keywords specified by the
|
||||
python command. Otherwise Python will generate an error.
|
||||
|
||||
----------
|
||||
|
||||
@ -308,13 +364,13 @@ previous value is simply returned, without re-computing it. The
|
||||
"global" statement inside the Python function allows it to overwrite the
|
||||
global variables from within the local context of the function.
|
||||
|
||||
Note that if you load Python code multiple times (via multiple python
|
||||
commands), you can overwrite previously loaded variables and functions
|
||||
if you are not careful. E.g. if the code above were loaded twice, the
|
||||
global variables would be re-initialized, which might not be what you
|
||||
want. Likewise, if a function with the same name exists in two chunks
|
||||
of Python code you load, the function loaded second will override the
|
||||
function loaded first.
|
||||
Also note that if you load Python code multiple times (via multiple
|
||||
python commands), you can overwrite previously loaded variables and
|
||||
functions if you are not careful. E.g. if the code above were loaded
|
||||
twice, the global variables would be re-initialized, which might not
|
||||
be what you want. Likewise, if a function with the same name exists
|
||||
in two chunks of Python code you load, the function loaded second will
|
||||
override the function loaded first.
|
||||
|
||||
It's important to realize that if you are running LAMMPS in parallel,
|
||||
each MPI task will load the Python interpreter and execute a local
|
||||
@ -325,15 +381,16 @@ This implies three important things.
|
||||
First, if you put a print or other statement creating output to the
|
||||
screen in your Python function, you will see P copies of the output,
|
||||
when running on P processors. If the prints occur at (nearly) the same
|
||||
time, the P copies of the output may be mixed together. When loading
|
||||
the LAMMPS Python module into the embedded Python interpreter, it is
|
||||
possible to pass the pointer to the current LAMMPS class instance and
|
||||
via the Python interface to the LAMMPS library interface, it is possible
|
||||
to determine the MPI rank of the current process and thus adapt the
|
||||
Python code so that output will only appear on MPI rank 0. The
|
||||
following LAMMPS input demonstrates how this could be done. The text
|
||||
'Hello, LAMMPS!' should be printed only once, even when running LAMMPS
|
||||
in parallel.
|
||||
time, the P copies of the output may be mixed together.
|
||||
|
||||
It is possible to avoid this issue, by passing the pointer to the
|
||||
current LAMMPS class instance to the Python function via the {input}
|
||||
SELF argument described above. The Python function can then use the
|
||||
Python interface to the LAMMPS library interface, and determine the
|
||||
MPI rank of the current process. The Python code can then ensure
|
||||
output will only appear on MPI rank 0. The following LAMMPS input
|
||||
demonstrates how this could be done. The text 'Hello, LAMPS!' should
|
||||
be printed only once, even when running LAMMPS in parallel.
|
||||
|
||||
.. code-block:: LAMMPS
|
||||
|
||||
@ -348,13 +405,13 @@ in parallel.
|
||||
|
||||
python python_hello invoke
|
||||
|
||||
If your Python code loads Python modules that are not pre-loaded by the
|
||||
Python library, then it will load the module from disk. This may be a
|
||||
bottleneck if 1000s of processors try to load a module at the same time.
|
||||
On some large supercomputers, loading of modules from disk by Python may
|
||||
be disabled. In this case you would need to pre-build a Python library
|
||||
that has the required modules pre-loaded and link LAMMPS with that
|
||||
library.
|
||||
Second, if your Python code loads Python modules that are not
|
||||
pre-loaded by the Python library, then it will load the module from
|
||||
disk. This may be a bottleneck if 1000s of processors try to load a
|
||||
module at the same time. On some large supercomputers, loading of
|
||||
modules from disk by Python may be disabled. In this case you would
|
||||
need to pre-build a Python library that has the required modules
|
||||
pre-loaded and link LAMMPS with that library.
|
||||
|
||||
Third, if your Python code calls back to LAMMPS (discussed in the
|
||||
next section) and causes LAMMPS to perform an MPI operation requires
|
||||
@ -365,10 +422,10 @@ LAMMPS. Otherwise the code may hang.
|
||||
|
||||
----------
|
||||
|
||||
Your Python function can "call back" to LAMMPS through its
|
||||
library interface, if you use the SELF input to pass Python
|
||||
a pointer to LAMMPS. The mechanism for doing this in your
|
||||
Python function is as follows:
|
||||
As mentioned above, a Python function can "call back" to LAMMPS
|
||||
through its library interface, if the SELF input is used to pass
|
||||
Python a pointer to LAMMPS. The mechanism for doing this is as
|
||||
follows:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@ -416,7 +473,7 @@ which loads and runs the following function from ``examples/python/funcs.py``:
|
||||
|
||||
lmp.set_variable("cut",cut) # set a variable in LAMMPS
|
||||
lmp.command("pair_style lj/cut ${cut}") # LAMMPS command
|
||||
#lmp.command("pair_style lj/cut %d" % cut) # LAMMPS command option
|
||||
#lmp.command("pair_style lj/cut %d" % cut) # alternate form of LAMMPS command
|
||||
|
||||
lmp.command("pair_coeff * * 1.0 1.0") # ditto
|
||||
lmp.command("run 10") # ditto
|
||||
@ -449,9 +506,9 @@ is a useful way for a Python function to return multiple values to
|
||||
LAMMPS, more than the single value that can be passed back via a
|
||||
return statement. This cutoff value in the "cut" variable is then
|
||||
substituted (by LAMMPS) in the pair_style command that is executed
|
||||
next. Alternatively, the "LAMMPS command option" line could be used
|
||||
in place of the 2 preceding lines, to have Python insert the value
|
||||
into the LAMMPS command string.
|
||||
next. Alternatively, the "alternate form of LAMMPS command" line
|
||||
could be used in place of the 2 preceding lines, to have Python insert
|
||||
the value into the LAMMPS command string.
|
||||
|
||||
.. note::
|
||||
|
||||
@ -463,20 +520,109 @@ into the LAMMPS command string.
|
||||
file() functions, so long as the command would work if it were
|
||||
executed in the LAMMPS input script directly at the same point.
|
||||
|
||||
However, a Python function can also be invoked during a run, whenever
|
||||
an associated LAMMPS variable it is assigned to is evaluated. If the
|
||||
variable is an input argument to another LAMMPS command (e.g. :doc:`fix setforce <fix_setforce>`), then the Python function will be invoked
|
||||
inside the class for that command, in one of its methods that is
|
||||
invoked in the middle of a timestep. You cannot execute arbitrary
|
||||
input script commands from the Python function (again, via the
|
||||
command() or file() functions) at that point in the run and expect it
|
||||
to work. Other library functions such as those that invoke computes
|
||||
or other variables may have hidden side effects as well. In these
|
||||
cases, LAMMPS has no simple way to check that something illogical is
|
||||
being attempted.
|
||||
|
||||
The same applies to Python functions called during a simulation run at
|
||||
each time step using :doc:`fix python/invoke <fix_python_invoke>`.
|
||||
----------
|
||||
|
||||
A Python function can also be invoked during a run, whenever
|
||||
an associated python-style variable it is assigned to is evaluated.
|
||||
|
||||
If the variable is an input argument to another LAMMPS command
|
||||
(e.g. :doc:`fix setforce <fix_setforce>`), then the Python function
|
||||
will be invoked inside the class for that command, possibly in one of
|
||||
its methods that is invoked in the middle of a timestep. You cannot
|
||||
execute arbitrary input script commands from the Python function
|
||||
(again, via the command() or file() functions) at that point in the
|
||||
run and expect it to work. Other library functions such as those that
|
||||
invoke computes or other variables may have hidden side effects as
|
||||
well. In these cases, LAMMPS has no simple way to check that
|
||||
something illogical is being attempted.
|
||||
|
||||
The same constraints apply to Python functions called during a
|
||||
simulation run at each time step using the :doc:`fix python/invoke
|
||||
<fix_python_invoke>` command.
|
||||
|
||||
----------
|
||||
|
||||
A Python function can also be invoked within the formula for an
|
||||
equal-style or atom-style varaible. This means the Python function
|
||||
will be invoked whenever the variable is invoked. In the case of an
|
||||
atom-style varaible, the Python function can be invoked once per atom.
|
||||
|
||||
Here are two simple examples using equal- and atom-style variables to
|
||||
trigger execution of a Python function:
|
||||
|
||||
.. code-block:: LAMMPS
|
||||
|
||||
variable foo python truncate
|
||||
python truncate return v_foo input 1 iv_arg format fi here """
|
||||
def truncate(x):
|
||||
return int(x)
|
||||
"""
|
||||
variable ptrunc equal py_foo(press)
|
||||
print "TRUNCATED pressure = ${ptrunc}"
|
||||
|
||||
The Python "truncate" function simply converts a floating-point value
|
||||
to an integer value. When the LAMMPS print command evaluates the
|
||||
equal-style "ptrunc" variable, the current thermodynamic pressure is
|
||||
passed to the Python function. The truncated value is output to the
|
||||
screen and logfile by the print command. Note that the *input*
|
||||
keyword for the *python* command, specifies an internal-style variable
|
||||
named "arg" as iv_arg which is required to invoke the Python function
|
||||
from a Python function wrapper.
|
||||
|
||||
The last 2 lines can be replaced by these to define atom-style
|
||||
varaibles which invoke the same Python "truncate" function:
|
||||
|
||||
.. code-block:: LAMMPS
|
||||
|
||||
variable xtrunc atom py_foo(x)
|
||||
variable ytrunc atom py_foo(y)
|
||||
variable ztrunc atom py_foo(z)
|
||||
dump 1 all custom 100 tmp.dump id x y z v_xtrunc v_ytrunc v_ztrunc
|
||||
|
||||
Now when the dump command invokes the 3 atom-style variables, their
|
||||
arguments x,y,z to the Python function wrapper are the current
|
||||
per-atom coordinates of each atom. The Python "truncate" function is
|
||||
thus invoked 3 times for each atom, and the truncated coordinate
|
||||
values for each atom are written to the dump file.
|
||||
|
||||
Note that when using a Python function wrapper in a variable,
|
||||
arguments can be passed to the Python function either from the
|
||||
varaible formula or by *input* keyword to the *python command. For
|
||||
example, consider these (made up) commands:
|
||||
|
||||
.. code-block:: LAMMPS
|
||||
|
||||
variable foo python mixedargs
|
||||
python mixedargs return v_foo input 6 7.5 v_myValue iv_arg1 iv_argy iv_argz v_flags &
|
||||
format fffffsf here """
|
||||
def mixedargs(a,b,x,y,z,flags):
|
||||
...
|
||||
return result
|
||||
"""
|
||||
variable flags string optionABC
|
||||
variable myValue equal "2.0*temp*c_pe"
|
||||
compute pe all pe
|
||||
compute peatom all pe/atom
|
||||
variable field atom py_foo(x+3.0,sqrt(y),(z-zlo)*c_peatom)
|
||||
|
||||
They define a Python "mixedargs" function with 6 arguments. Three of
|
||||
them are internal-style variables, which the variable formula
|
||||
calculates as numeric values for each atom and passes to the function.
|
||||
In this example, these arguments are themselves small formulas
|
||||
containing the x,y,z coordinates of each atom as well as a per-atom
|
||||
compute (c_peratom) and thermodynamic keyword (zlo).
|
||||
|
||||
The other three arguements (7.5,v_myValue,v_flags) are defined by the
|
||||
*python* command. The first and last are constant values (7.5 and the
|
||||
optionABC string). The second argument (myValue) is the result of an
|
||||
equal-style variable formula which accesses the system temperature and
|
||||
potential energy.
|
||||
|
||||
The "result" returned by teach invocation of the Python "mixedargs"
|
||||
function becomes the per-atom value in the atom-style "field"
|
||||
variable, which could be output to a dump file or used elsewhere in
|
||||
the input script.
|
||||
|
||||
----------
|
||||
|
||||
@ -563,27 +709,30 @@ If you use Python code which calls back to LAMMPS, via the SELF input
|
||||
argument explained above, there is an extra step required when building
|
||||
LAMMPS. LAMMPS must also be built as a shared library and your Python
|
||||
function must be able to load the :doc:`"lammps" Python module
|
||||
<Python_module>` that wraps the LAMMPS library interface. These are the
|
||||
same steps required to use Python by itself to wrap LAMMPS. Details on
|
||||
these steps are explained on the :doc:`Python <Python_head>` doc page.
|
||||
Note that it is important that the stand-alone LAMMPS executable and the
|
||||
LAMMPS shared library be consistent (built from the same source code
|
||||
files) in order for this to work. If the two have been built at
|
||||
different times using different source files, problems may occur.
|
||||
<Python_module>` that wraps the LAMMPS library interface.
|
||||
|
||||
These are the same steps required to use Python by itself to wrap
|
||||
LAMMPS. Details on these steps are explained on the :doc:`Python
|
||||
<Python_head>` doc page. Note that it is important that the
|
||||
stand-alone LAMMPS executable and the LAMMPS shared library be
|
||||
consistent (built from the same source code files) in order for this
|
||||
to work. If the two have been built at different times using
|
||||
different source files, problems may occur.
|
||||
|
||||
Another limitation of calling back to Python from the LAMMPS module
|
||||
using the *python* command in a LAMMPS input is that both, the Python
|
||||
interpreter and LAMMPS, must be linked to the same Python runtime as a
|
||||
shared library. If the Python interpreter is linked to Python
|
||||
statically (which seems to happen with Conda) then loading the shared
|
||||
LAMMPS library will create a second python "main" module that hides the
|
||||
one from the Python interpreter and all previous defined function and
|
||||
global variables will become invisible.
|
||||
LAMMPS library will create a second python "main" module that hides
|
||||
the one from the Python interpreter and all previous defined function
|
||||
and global variables will become invisible.
|
||||
|
||||
Related commands
|
||||
""""""""""""""""
|
||||
|
||||
:doc:`shell <shell>`, :doc:`variable <variable>`, :doc:`fix python/invoke <fix_python_invoke>`
|
||||
:doc:`shell <shell>`, :doc:`variable <variable>`, :doc:`fix
|
||||
python/invoke <fix_python_invoke>`
|
||||
|
||||
Default
|
||||
"""""""
|
||||
|
||||
@ -397,13 +397,24 @@ 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.
|
||||
value.
|
||||
|
||||
Note however, that most commands which use internal-style variables do
|
||||
not require them to be defined in the input script. They create one
|
||||
or more internal-style variables if they do not already exist.
|
||||
Examples are these commands:
|
||||
|
||||
* :doc:`create_atoms <create_atoms>`
|
||||
* :doc:`fix deposit <fix_deposit>`
|
||||
* :doc:`compute bond/local <compute_bond_local>`
|
||||
* :doc:`compute angle/local <compute_angle/local>`
|
||||
* :doc:`compute dihedral/local <compute_dihedral_local>`
|
||||
* :doc:`python <python>` command in conjunction with Python function wrappers used in equal- and atom-style variable formulas
|
||||
|
||||
A command which does require an internal-style variable to be defined
|
||||
in the input script is the :doc:`fix controller <fix_controller"`
|
||||
command, because another (arbitrary) command typically also references
|
||||
the variable.
|
||||
|
||||
----------
|
||||
|
||||
@ -449,12 +460,13 @@ anywhere in an input script, e.g. as an argument to another command
|
||||
that allows for equal-style variables.
|
||||
|
||||
A python-style variable can also be used within the formula for an
|
||||
equal-style or atom-style formula with the syntax
|
||||
py_varname(arg1,arg2,...) as explained below for variable formulas.
|
||||
When used in an atom-style formula, it can the variable can be invoked
|
||||
once per atom using arguments specific to each atom. The resulting
|
||||
values in the atom-style variable can thus be calculated by Python
|
||||
code.
|
||||
equal-style or atom-style formula in a Python function wrapper, as
|
||||
explained below for variable formulas. In this context, the usage
|
||||
syntax is py_varname(arg1,arg2,...), where varname is the name of the
|
||||
python-style variable. When a Python wrapper function is used in an
|
||||
atom-style formula, it can be invoked once per atom using arguments
|
||||
specific to each atom. The resulting values in the atom-style
|
||||
variable can thus be calculated by Python code.
|
||||
|
||||
----------
|
||||
|
||||
@ -545,7 +557,7 @@ is a valid (though strange) variable formula:
|
||||
|
||||
Specifically, a formula can contain numbers, constants, thermo
|
||||
keywords, math operators, math functions, group functions, region
|
||||
functions, special functions, feature functions, python function
|
||||
functions, special functions, feature functions, Python function
|
||||
wrappers, atom values, atom vectors, custom atom properties, compute
|
||||
references, fix references, and references to other variables.
|
||||
|
||||
@ -568,7 +580,7 @@ references, fix references, and references to other variables.
|
||||
+------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Feature functions | is_available(category,feature), is_active(category,feature), is_defined(category,id) |
|
||||
+------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Python func wrappers | py_varname(x,y,z,...) |
|
||||
| Python func wrapper | py_varname(x,y,z,...) |
|
||||
+------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| 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] |
|
||||
+------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
@ -1180,7 +1192,7 @@ variable name.
|
||||
|
||||
----------
|
||||
|
||||
Python Function wrappers
|
||||
Python Function wrapper
|
||||
------------------------
|
||||
|
||||
A Python function wrapper enables the formula for an equal-style or
|
||||
@ -1211,11 +1223,10 @@ input script:
|
||||
.. code-block:: LAMMPS
|
||||
|
||||
variable foo python truncate
|
||||
python truncate return v_foo input 1 v_pyarg1 format fi here """
|
||||
python truncate return v_foo input 1 v_arg format fi here """
|
||||
def truncate(x):
|
||||
return int(x)
|
||||
"""
|
||||
variable pyarg1 internal 0.0
|
||||
variable xtrunc atom py_foo(x)
|
||||
variable ytrunc atom py_foo(y)
|
||||
variable ztrunc atom py_foo(z)
|
||||
@ -1228,12 +1239,6 @@ this case, the Python code for truncate() is included in the *python*
|
||||
command; it could also be contained in a file. See the :doc:`python
|
||||
<python>` command doc page for details.
|
||||
|
||||
The *variable pyarg1* command defines an internal-style variable. It
|
||||
MUST have the name pyarg1. If the Python function has *N* arguments,
|
||||
*N* internal-style variables MUST be defined with names *pyarg1*,
|
||||
*pyarg2*, ... *pyargN*. Note that multiple Python function wrappers
|
||||
can use the same internal-style variables.
|
||||
|
||||
The next three commands define atom-style variables *xtrunc*,
|
||||
*ytrunc*, and *ztrunc*. Each of them include the same Python function
|
||||
wrapper in their formula, with a different argument. The atom-style
|
||||
@ -1242,15 +1247,27 @@ will in turn invoke the Python-coded *truncate()* method. Because
|
||||
*xtrunc* is an atom-style variable, and the argument *x* in the Python
|
||||
function wrapper is a per-atom quantity (the x-coord of each atom),
|
||||
each processor will invoke the *truncate()* method once per atom, for
|
||||
the atoms it owns. When invoked for the Ith atom, the x-coord of the
|
||||
Ith atom becomes the value of the *pyarg1* internal-style variable.
|
||||
The call to the *truncate()* function uses the value of the *pyarg1*
|
||||
variable as its first (and only) argument.
|
||||
the atoms it owns.
|
||||
|
||||
When invoked for the Ith atom, the value of the *arg* internal-style
|
||||
variable, defined by the *python* command, is set to the x-coord of
|
||||
the Ith atom. The call via python-style variable *foo* to the Python
|
||||
*truncate()* function passes the value of the *arg* variable as its
|
||||
first (and only) argument. Likewise, the return value of the Python
|
||||
function becomes is stored by the python-style variable *foo* and used
|
||||
in the *xtrunc* atom-style variable formula for the Ith atom.
|
||||
|
||||
The resulting per-atom vector for *xtrunc* will thus contain the
|
||||
truncated x-coord of every atom in the system. The dump command
|
||||
includes the truncated xyz coords for each atom in its output.
|
||||
|
||||
See the :doc:`python <python>' command for more details on options the
|
||||
*python* command can specify as well as examples of more complex
|
||||
Python functions which can be wrapped in this manner. In particular,
|
||||
the Python function can take a variety of arguments, some generated by
|
||||
the *python* command, and others by the arguments of the Python
|
||||
function wrapper.
|
||||
|
||||
----------
|
||||
|
||||
Atom Values and Vectors
|
||||
|
||||
@ -25,11 +25,10 @@ neigh_modify delay 0 every 20 check no
|
||||
fix 1 all nve
|
||||
|
||||
variable foo python truncate
|
||||
python truncate return v_foo input 1 v_pyarg1 format fi here """
|
||||
python truncate return v_foo input 1 iv_arg format fi here """
|
||||
def truncate(x):
|
||||
return int(x)
|
||||
"""
|
||||
variable pyarg1 internal 0.0
|
||||
|
||||
variable scalar equal py_foo(4.5)
|
||||
print "TRUNCATE ${scalar}"
|
||||
@ -40,7 +39,6 @@ variable ztrunc atom py_foo(z)
|
||||
|
||||
# examine dump file to see truncated xyz coords of each atom
|
||||
|
||||
#dump 1 all custom 100 tmp.dump id x y z
|
||||
dump 1 all custom 100 tmp.dump id x y z v_xtrunc v_ytrunc v_ztrunc
|
||||
|
||||
run 100
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
LAMMPS (2 Apr 2025 - Development - patch_2Apr2025-125-g7ca493917a-modified)
|
||||
LAMMPS (2 Apr 2025 - Development - patch_2Apr2025-266-gebfb94a717-modified)
|
||||
# 3d Lennard-Jones melt with equal- and atom-style variables which
|
||||
# use a Python function wrapper in their formulas
|
||||
|
||||
@ -35,11 +35,10 @@ neigh_modify delay 0 every 20 check no
|
||||
fix 1 all nve
|
||||
|
||||
variable foo python truncate
|
||||
python truncate return v_foo input 1 v_pyarg1 format fi here """
|
||||
python truncate return v_foo input 1 iv_arg format fi here """
|
||||
def truncate(x):
|
||||
return int(x)
|
||||
"""
|
||||
variable pyarg1 internal 0.0
|
||||
|
||||
variable scalar equal py_foo(4.5)
|
||||
print "TRUNCATE ${scalar}"
|
||||
@ -49,7 +48,8 @@ variable xtrunc atom py_foo(x)
|
||||
variable ytrunc atom py_foo(y)
|
||||
variable ztrunc atom py_foo(z)
|
||||
|
||||
#dump 1 all custom 100 tmp.dump id x y z
|
||||
# examine dump file to see truncated xyz coords of each atom
|
||||
|
||||
dump 1 all custom 100 tmp.dump id x y z v_xtrunc v_ytrunc v_ztrunc
|
||||
|
||||
run 100
|
||||
@ -70,20 +70,20 @@ Per MPI rank memory allocation (min/avg/max) = 2.644 | 2.644 | 2.644 Mbytes
|
||||
Step Temp E_pair E_mol TotEng Press
|
||||
0 1.44 -6.7733681 0 -4.6176881 -5.0221006
|
||||
100 0.75627408 -5.7580082 0 -4.6258659 0.21870071
|
||||
Loop time of 0.0160255 on 1 procs for 100 steps with 500 atoms
|
||||
Loop time of 0.014627 on 1 procs for 100 steps with 500 atoms
|
||||
|
||||
Performance: 2695709.610 tau/day, 6240.069 timesteps/s, 3.120 Matom-step/s
|
||||
Performance: 2953445.899 tau/day, 6836.680 timesteps/s, 3.418 Matom-step/s
|
||||
100.0% CPU use with 1 MPI tasks x no OpenMP threads
|
||||
|
||||
MPI task timing breakdown:
|
||||
Section | min time | avg time | max time |%varavg| %total
|
||||
---------------------------------------------------------------
|
||||
Pair | 0.011326 | 0.011326 | 0.011326 | 0.0 | 70.67
|
||||
Neigh | 0.002924 | 0.002924 | 0.002924 | 0.0 | 18.25
|
||||
Comm | 0.00046255 | 0.00046255 | 0.00046255 | 0.0 | 2.89
|
||||
Output | 0.0010398 | 0.0010398 | 0.0010398 | 0.0 | 6.49
|
||||
Modify | 0.00020589 | 0.00020589 | 0.00020589 | 0.0 | 1.28
|
||||
Other | | 6.725e-05 | | | 0.42
|
||||
Pair | 0.010546 | 0.010546 | 0.010546 | 0.0 | 72.10
|
||||
Neigh | 0.0027775 | 0.0027775 | 0.0027775 | 0.0 | 18.99
|
||||
Comm | 0.00044818 | 0.00044818 | 0.00044818 | 0.0 | 3.06
|
||||
Output | 0.00060601 | 0.00060601 | 0.00060601 | 0.0 | 4.14
|
||||
Modify | 0.00018516 | 0.00018516 | 0.00018516 | 0.0 | 1.27
|
||||
Other | | 6.39e-05 | | | 0.44
|
||||
|
||||
Nlocal: 500 ave 500 max 500 min
|
||||
Histogram: 1 0 0 0 0 0 0 0 0 0
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
LAMMPS (2 Apr 2025 - Development - patch_2Apr2025-125-g7ca493917a-modified)
|
||||
LAMMPS (2 Apr 2025 - Development - patch_2Apr2025-266-gebfb94a717-modified)
|
||||
# 3d Lennard-Jones melt with equal- and atom-style variables which
|
||||
# use a Python function wrapper in their formulas
|
||||
|
||||
@ -35,11 +35,10 @@ neigh_modify delay 0 every 20 check no
|
||||
fix 1 all nve
|
||||
|
||||
variable foo python truncate
|
||||
python truncate return v_foo input 1 v_pyarg1 format fi here """
|
||||
python truncate return v_foo input 1 iv_arg format fi here """
|
||||
def truncate(x):
|
||||
return int(x)
|
||||
"""
|
||||
variable pyarg1 internal 0.0
|
||||
|
||||
variable scalar equal py_foo(4.5)
|
||||
print "TRUNCATE ${scalar}"
|
||||
@ -49,7 +48,8 @@ variable xtrunc atom py_foo(x)
|
||||
variable ytrunc atom py_foo(y)
|
||||
variable ztrunc atom py_foo(z)
|
||||
|
||||
#dump 1 all custom 100 tmp.dump id x y z
|
||||
# examine dump file to see truncated xyz coords of each atom
|
||||
|
||||
dump 1 all custom 100 tmp.dump id x y z v_xtrunc v_ytrunc v_ztrunc
|
||||
|
||||
run 100
|
||||
@ -70,20 +70,20 @@ Per MPI rank memory allocation (min/avg/max) = 2.609 | 2.609 | 2.609 Mbytes
|
||||
Step Temp E_pair E_mol TotEng Press
|
||||
0 1.44 -6.7733681 0 -4.6176881 -5.0221006
|
||||
100 0.75627408 -5.7580082 0 -4.6258659 0.21870071
|
||||
Loop time of 0.00641075 on 4 procs for 100 steps with 500 atoms
|
||||
Loop time of 0.0062374 on 4 procs for 100 steps with 500 atoms
|
||||
|
||||
Performance: 6738684.275 tau/day, 15598.806 timesteps/s, 7.799 Matom-step/s
|
||||
100.0% CPU use with 4 MPI tasks x no OpenMP threads
|
||||
Performance: 6925957.189 tau/day, 16032.308 timesteps/s, 8.016 Matom-step/s
|
||||
74.7% CPU use with 4 MPI tasks x no OpenMP threads
|
||||
|
||||
MPI task timing breakdown:
|
||||
Section | min time | avg time | max time |%varavg| %total
|
||||
---------------------------------------------------------------
|
||||
Pair | 0.0028061 | 0.0028831 | 0.0029657 | 0.1 | 44.97
|
||||
Neigh | 0.00086635 | 0.00088279 | 0.00089739 | 0.0 | 13.77
|
||||
Comm | 0.0020095 | 0.0020768 | 0.0021521 | 0.1 | 32.40
|
||||
Output | 0.00041634 | 0.00042457 | 0.00043221 | 0.0 | 6.62
|
||||
Modify | 6.2967e-05 | 6.4188e-05 | 6.5205e-05 | 0.0 | 1.00
|
||||
Other | | 7.934e-05 | | | 1.24
|
||||
Pair | 0.0027648 | 0.0028431 | 0.0029465 | 0.1 | 45.58
|
||||
Neigh | 0.00084567 | 0.00086563 | 0.00088168 | 0.0 | 13.88
|
||||
Comm | 0.0020822 | 0.0021609 | 0.0022418 | 0.1 | 34.64
|
||||
Output | 0.00021567 | 0.00022125 | 0.00022624 | 0.0 | 3.55
|
||||
Modify | 6.2567e-05 | 6.4105e-05 | 6.63e-05 | 0.0 | 1.03
|
||||
Other | | 8.241e-05 | | | 1.32
|
||||
|
||||
Nlocal: 125 ave 126 max 123 min
|
||||
Histogram: 1 0 0 0 0 0 1 0 0 2
|
||||
|
||||
@ -415,7 +415,7 @@ void PythonImpl::invoke_function(int ifunc, char *result, double *dvalue)
|
||||
strncpy(result, value.c_str(), Variable::VALUELENGTH - 1);
|
||||
}
|
||||
} else if (otype == DOUBLE) {
|
||||
if (*dvalue) *dvalue = PyFloat_AsDouble(pValue);
|
||||
if (dvalue) *dvalue = PyFloat_AsDouble(pValue);
|
||||
else {
|
||||
auto value = fmt::format("{:.15g}", PyFloat_AsDouble(pValue));
|
||||
strncpy(result, value.c_str(), Variable::VALUELENGTH - 1);
|
||||
|
||||
Reference in New Issue
Block a user