updated doc pages and code

This commit is contained in:
Steve Plimpton
2025-05-19 14:34:22 -06:00
parent ebfb94a717
commit c3b25c8c27
12 changed files with 512 additions and 338 deletions

View File

@ -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)

View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -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
""""""""""""

View File

@ -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::

View File

@ -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
"""""""

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);