Merge branch 'develop' into molecule-refactor-for-json

This commit is contained in:
Axel Kohlmeyer
2025-06-12 14:23:32 -04:00
2 changed files with 250 additions and 247 deletions

View File

@ -17,9 +17,9 @@ Syntax
.. parsed-literal:: .. parsed-literal::
keyword = *here* or name of a *Python file* keyword = *here* or name of a *Python file*
*here* arg = one or more lines of Python code *here* arg = inline
inline = one or more lines of Python code which will be executed immediately
must be a single argument, typically enclosed between triple quotes 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 *Python file* = name of a file with Python code which will be executed immediately
* if *mode* is *name* of a Python function: * if *mode* is *name* of a Python function:
@ -28,8 +28,9 @@ Syntax
one or more keywords with/without arguments must be appended 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* keyword = *invoke* or *input* or *return* or *format* or *length* or *file* or *here* or *exists*
*invoke* arg = invoke the previously-defined Python function *invoke* arg = logreturn (optional)
logreturn = log return value of the invoked python function, if defined (optional) invoke the previously-defined Python function
if logreturn is specified, print the return value of the invoked function to the screen and logfile
*input* args = N i1 i2 ... iN *input* args = N i1 i2 ... iN
N = # of inputs to function N = # of inputs to function
i1,...,iN = value, SELF, or LAMMPS variable name i1,...,iN = value, SELF, or LAMMPS variable name
@ -102,8 +103,25 @@ the evaluation of a python-style, equal-style, vector-style, or
atom-style variable. A python-style variable invokes its associated atom-style variable. A python-style variable invokes its associated
Python function; its return value becomes the value of the python-style Python function; its return value becomes the value of the python-style
variable. Equal-, vector-, and atom-style variables can use a Python variable. Equal-, vector-, and atom-style variables can use a Python
function wrapper in their formulas which encodes the Python function function wrapper in their formulas which encodes the python-style
name, and specifies arguments to pass to the function. variable name, and specifies arguments (which themselves can be numeric
formulas) to pass to the Python function associated with the
python-style variable.
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
variable foo python myMultiply
python myMultiply return v_foo format f file funcs.py
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.
Note that python-style, equal-style, vector-style, and atom-style Note that python-style, equal-style, vector-style, and atom-style
variables can be used in many different ways within LAMMPS. They can be variables can be used in many different ways within LAMMPS. They can be
@ -113,8 +131,8 @@ arguments, so that the variable is evaluated multiple times during a
simulation run. See the :doc:`variable <variable>` command doc page for simulation run. See the :doc:`variable <variable>` command doc page for
more details on variable styles which enable Python function evaluation. more details on variable styles which enable Python function evaluation.
The Python code for the function can be included directly in the input The Python code for a Python function can be included directly in the
script or in a separate Python file. The function can be standard 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 Python code or it can make "callbacks" to LAMMPS through its library
interface to query or set internal values within LAMMPS. This is a interface to query or set internal values within LAMMPS. This is a
powerful mechanism for performing complex operations in a LAMMPS input powerful mechanism for performing complex operations in a LAMMPS input
@ -128,88 +146,126 @@ embedded in LAMMPS. More details about this process are given below.
A broader overview of how Python can be used with LAMMPS is given in the 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 :doc:`Use Python with LAMMPS <Python_head>` section of the
documentation. There also is an ``examples/python`` directory which documentation. There is also an ``examples/python`` directory which
illustrates use of the python command. illustrates use of the python command.
---------- ----------
The first argument is the *mode* setting, which is either *source* or The first argument to the *python* command is the *mode* setting, which
the *name* of a Python function. is either *source* or the *name* of a Python function.
.. versionchanged:: 22Dec2022 .. versionchanged:: 22Dec2022
If *source* is used, it is followed by either the *here* keyword or a 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 file name containing Python code. The *here* keyword is followed by a
string containing python commands, either on a single line enclosed in single *inline* argument which is a string containing one or more python
quotes, or as multiple lines enclosed in triple quotes. In either commands. The string can either be on the same line as the *python*
case, the in-line code or file contents are passed to the python command, enclosed in quotes, or it can be multiple lines enclosed in
interpreter and executed immediately. The code will be loaded into triple quotes.
and run in the "main" module of the Python interpreter. This allows
running arbitrary Python code at any time while processing the SPARTA In either case, the in-line code or the file contents are passed to the
input file. This can be used to pre-load Python modules, initialize python interpreter and executed immediately. The code will be loaded
global variables, define functions or classes, or perform operations into and run in the "main" module of the Python interpreter. This
using the Python programming language. The Python code will be allows running arbitrary Python code at any time while processing the
executed in parallel on all the MPI processes being used to run 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 the MPI processes being used to run
LAMMPS. Note that no arguments can be passed to the executed Python LAMMPS. Note that no arguments can be passed to the executed Python
code. code.
If the *mode* setting is the *name* of a Python function, then it will 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, be registered with LAMMPS for future execution (or can already be
see the *exists* keyword). One or more keywords must follow the defined, see the *exists* keyword). One or more keywords must follow
*mode* function name. One of the keywords must be *invoke*, *file*, the *mode* function name. One of the keywords must be *invoke*, *file*,
*here*, or *exists*. *here*, or *exists*, which specifies what Python code to load into the
Python interpreter. Note that only one of those 4 keywords is allowed
since their operations are mutually exclusive.
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
may already be defined (see *exists* keyword) or must be defined using
the *file* or *here* keywords as explained below.
If the *invoke* keyword is used, only the optional *logreturn* keyword If the *invoke* keyword is used, no other keywords can be used. A
can be used. A previous *python* command must have registered the previous *python* command must have registered the Python function
Python function referenced by this command. The command invokes the referenced by this command, which can then be invoked multiple times in
Python function with the previously defined arguments. A return value an input script via the *invoke* keyword. Each invocation passes
of the Python function will be ignored unless the Python function is current values for arguments to the Python function. A return value of
linked to a :doc:`python style variable <variable>` with the *return* the Python function will be ignored unless the Python function is linked
keyword. This return value can be logged to the screen and logfile by to a :doc:`python style variable <variable>` with the *return* keyword.
adding the *logreturn* keyword to the *invoke* command. In that case a This return value can be logged to the screen and logfile by adding the
optional *logreturn* argument to the *invoke* keyword. In that case a
message with the name of the python command and the return value is message with the name of the python command and the return value is
printed. Return values of python functions are otherwise only printed. Note that return values of python functions are otherwise
accessible when the function is invoked indirectly by expanding a *only* accessible when the function is invoked indirectly by evaluating
:doc:`python style variable <variable>`. You can invoke a registered its associated :doc:`python style variable <variable>`, as described
function as many times as you wish in your input script. below.
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
using triple quotes as delimiters, as in the examples above and below.
This allows Python code to be listed verbatim in your input script, with
proper indentation, blank lines, and comments, as desired. See the
:doc:`Commands parse <Commands_parse>` doc page, for an explanation of
how triple quotes can be used as part of input script syntax.
The *exists* keyword takes no argument. It simply means that Python
code containing the needed Python function has already been loaded into
the LAMMPS Python interpreter, for example by previous *python source*
command or in a file that was loaded 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 by the *file* or *here*
keyword must contain a function with the specified function *name*. To
operate properly when the function is later invoked, the code for the
function must match the *input* and *return* and *format* keywords
specified by the python command. Otherwise Python will generate an
error.
----------
The other keywords which can be used with the *python* command are
*input*, *return*, *format*, and *length*.
The *input* keyword defines how many arguments *N* the Python function The *input* keyword defines how many arguments *N* the Python function
expects. If it takes no arguments, then the *input* keyword should expects. If it takes no arguments, then the *input* keyword should not
not be used. Each argument can be specified directly as a value, be used. Each argument can be specified directly as a value, e.g. '6'
e.g. '6' or '3.14159' or 'abc' (a string of characters). The type of or '3.14159' or 'abc' (a string of characters). The type of each
each argument is specified by the *format* keyword as explained below, argument is specified by the *format* keyword as explained below, so
so that Python will know how to interpret the value. If the word SELF that Python will know how to interpret the value. If the word SELF is
is used for an argument it has a special meaning. A pointer is passed used for an argument it has a special meaning. A pointer is passed to
to the Python function which it can convert into a reference to LAMMPS the Python function which it can convert into a reference to LAMMPS
itself using the :doc:`LAMMPS Python module <Python_module>`. This itself using the :doc:`LAMMPS Python module <Python_module>`. This
enables the function to call back to LAMMPS through its library enables the function to call back to LAMMPS through its library
interface as explained below. This allows the Python function to interface as explained below. This allows the Python function to query
query or set values internal to LAMMPS which can affect the subsequent or set values internal to LAMMPS which can affect the subsequent
execution of the input script. execution of the input script.
A LAMMPS variable can also be used as an *input* argument, specified A LAMMPS variable can also be used as an *input* argument, specified as
as v_name, where "name" is the name of the variable defined in the v_name, where "name" is the name of the variable defined in the input
input script. Any style of LAMMPS variable returning a scalar or a script. Any style of LAMMPS variable returning a scalar or a string can
string can be used, as defined by the :doc:`variable <variable>` be used, as defined by the :doc:`variable <variable>` command. The
command. The style of variable must be consistent with the *format* style of variable must be consistent with the *format* keyword
keyword specification for the type of data that is passed to Python. specification for the type of data that is passed to Python. Each time
Each time the Python function is invoked, the LAMMPS variable is the Python function is invoked, the LAMMPS variable is evaluated and its
evaluated and its value is passed as an argument to the Python value is passed as an argument to the Python function. Note that a
function. Note that a python-style variable can be used as an python-style variable can be used as an argument, which means that the a
argument, which means that the a Python function can use arguments Python function can use arguments which invoke other Python functions.
which invoke other Python functions.
A LAMMPS internal-style variable can also be used as an *input* A LAMMPS internal-style variable can also be used as an *input*
argument, specified as iv_name, where "name" is the name of the argument, specified as iv_name, where "name" is the name of the
internal-style variable. The internal-style variable does not have to 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 be defined in the input script (though it can be); if it is not defined,
defined, this command creates an :doc:`internal-style variable this command creates an :doc:`internal-style variable <variable>` with
<variable>` with the specified name. the specified name.
An internal-style variable must be used when an equal-style, An internal-style variable must be used when an equal-style,
vector-style, or atom-style variable triggers the invocation of the vector-style, or atom-style variable triggers the invocation of the
@ -232,99 +288,48 @@ function can also have additional inputs, also specified by the *input*
keyword, which are NOT arguments in the Python function wrapper. See keyword, which are NOT arguments in the Python function wrapper. See
the example below for the ``mixedargs`` Python function. the example below for the ``mixedargs`` Python function.
See the :doc:`variable <variable>` command doc page for full details See the :doc:`variable <variable>` command doc page for full details on
on formula syntax including for Python function wrappers. Examples formula syntax including for Python function wrappers. Examples using
using Python function wrappers are shown below. Note that as Python function wrappers are shown below. Note that as explained above
explained above with python-style variables, Python function wrappers with python-style variables, Python function wrappers can be nested; a
can be nested; a sub-formula for an argument can contain its own sub-formula for an argument can contain its own Python function wrapper
Python function wrapper which invokes another Python function. which invokes another Python function.
The *return* keyword is only needed if the Python function returns a The *return* keyword is only needed if the Python function returns a
value. The specified *varReturn* is of the form v_name, where "name" value. The specified *varReturn* is of the form v_name, where "name" is
is the name of a python-style LAMMPS variable, defined by the the name of a python-style LAMMPS variable, defined by the
:doc:`variable <variable>` command. The Python function can return a :doc:`variable <variable>` command. The Python function can return a
numeric or string value, as specified by the *format* keyword. numeric or string value, as specified by the *format* keyword. This
This return value is *only* accessible when expanding the python-style return value is *only* accessible when its associated python-style
variable. When the *invoke* keyword is used, the return value of variable is evaluated. When the *invoke* keyword is used, the return
the python function is ignored. value of the python function is ignored unless the optional *logreturn*
argument is specified.
----------
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
variable foo python myMultiply
python myMultiply return v_foo format f file funcs.py
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.
The *format* keyword must be used if the *input* or *return* keywords 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 are used. It defines an *fstring* with M characters, where M = sum of
number of inputs and outputs. The order of characters corresponds to number of inputs and outputs. The order of characters corresponds to
the N inputs, followed by the return value (if it exists). Each the N inputs, followed by the return value (if it exists). Each
character must be one of the following: "i" for integer, "f" for character must be one of the following: "i" for integer, "f" for
floating point, "s" for string, or "p" for SELF. Each character floating point, "s" for string, or "p" for SELF. Each character defines
defines the type of the corresponding input or output value of the the type of the corresponding input or output value of the Python
Python function and affects the type conversion that is performed function and affects the type conversion that is performed internally as
internally as data is passed back and forth between LAMMPS and Python. data is passed back and forth between LAMMPS and Python. Note that it
Note that it is permissible to use a :doc:`python-style variable is permissible to use a :doc:`python-style variable <variable>` in a
<variable>` in a LAMMPS command that allows for an equal-style LAMMPS command that allows for an equal-style variable as an argument,
variable as an argument, but only if the output of the Python function but only if the output of the Python function is flagged as a numeric
is flagged as a numeric value ("i" or "f") via the *format* keyword. value ("i" or "f") via the *format* keyword.
If the *return* keyword is used and the *format* keyword specifies the 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 output as a string, then the default maximum length of that string is 63
63 characters (64-1 for the string terminator). If you want to return characters (64-1 for the string terminator). If you want to return a
a longer string, the *length* keyword can be specified with its *Nlen* longer string, the *length* keyword can be specified with its *Nlen*
value set to a larger number. LAMMPS will then allocate Nlen+1 space value set to a larger number. LAMMPS will then allocate Nlen+1 space to
to include the string terminator. If the Python function generates a include the string terminator. If the Python function generates a
string longer than the default 63 or the specified *Nlen*, it will be string longer than the default 63 or the specified *Nlen*, it will be
truncated. truncated.
---------- ----------
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
using triple quotes as delimiters, as in the examples above. This
allows Python code to be listed verbatim in your input script, with
proper indentation, blank lines, and comments, as desired. See the
:doc:`Commands parse <Commands_parse>` doc page, for an explanation of
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. 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 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.
----------
This section describes how Python code can be written to work with This section describes how Python code can be written to work with
LAMMPS. LAMMPS.
@ -345,16 +350,16 @@ keyword once to load several functions, and the *exists* keyword
thereafter in subsequent python commands to register the other functions thereafter in subsequent python commands to register the other functions
that were previously loaded with LAMMPS. that were previously loaded with LAMMPS.
A Python function you define (or more generally, the code you load) A Python function you define (or more generally, the code you load) can
can import other Python modules or classes, it can make calls to other import other Python modules or classes, it can make calls to other
system functions or functions you define, and it can access or modify system functions or functions you define, and it can access or modify
global variables (in the "main" module) which will persist between global variables (in the "main" module) which will persist between
successive function calls. The latter can be useful, for example, to successive function calls. The latter can be useful, for example, to
prevent a function from being invoke multiple times per timestep by prevent a function from being invoke multiple times per timestep by
different commands in a LAMMPS input script that access the returned different commands in a LAMMPS input script that access the returned
python-style variable associated with the function. For example, python-style variable associated with the function. For example,
consider this function loaded with two global variables defined consider this function loaded with two global variables defined outside
outside the function: the function:
.. code-block:: python .. code-block:: python
@ -381,16 +386,16 @@ global variables from within the local context of the function.
Also note that if you load Python code multiple times (via multiple Also note that if you load Python code multiple times (via multiple
python commands), you can overwrite previously loaded variables and python commands), you can overwrite previously loaded variables and
functions if you are not careful. E.g. if the code above were loaded 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 twice, the global variables would be re-initialized, which might not be
be what you want. Likewise, if a function with the same name exists what you want. Likewise, if a function with the same name exists in two
in two chunks of Python code you load, the function loaded second will chunks of Python code you load, the function loaded second will override
override the function loaded first. the function loaded first.
It's important to realize that if you are running LAMMPS in parallel, 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 each MPI task will load the Python interpreter and execute a local copy
copy of the Python function(s) you define. There is no connection of the Python function(s) you define. There is no connection between
between the Python interpreters running on different processors. the Python interpreters running on different processors. This implies
This implies three important things. three important things.
First, if you put a print or other statement creating output to the 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, screen in your Python function, you will see P copies of the output,
@ -400,11 +405,11 @@ time, the P copies of the output may be mixed together.
It is possible to avoid this issue, by passing the pointer to the It is possible to avoid this issue, by passing the pointer to the
current LAMMPS class instance to the Python function via the {input} current LAMMPS class instance to the Python function via the {input}
SELF argument described above. The Python function can then use the SELF argument described above. The Python function can then use the
Python interface to the LAMMPS library interface, and determine the Python interface to the LAMMPS library interface, and determine the MPI
MPI rank of the current process. The Python code can then ensure rank of the current process. The Python code can then ensure output
output will only appear on MPI rank 0. The following LAMMPS input will only appear on MPI rank 0. The following LAMMPS input demonstrates
demonstrates how this could be done. The text 'Hello, LAMPS!' should how this could be done. The text 'Hello, LAMPS!' should be printed only
be printed only once, even when running LAMMPS in parallel. once, even when running LAMMPS in parallel.
.. code-block:: LAMMPS .. code-block:: LAMMPS
@ -419,27 +424,26 @@ be printed only once, even when running LAMMPS in parallel.
python python_hello invoke python python_hello invoke
Second, if your Python code loads Python modules that are not Second, if your Python code loads Python modules that are not pre-loaded
pre-loaded by the Python library, then it will load the module from by the Python library, then it will load the module from disk. This may
disk. This may be a bottleneck if 1000s of processors try to load a be a bottleneck if 1000s of processors try to load a module at the same
module at the same time. On some large supercomputers, loading of time. On some large supercomputers, loading of modules from disk by
modules from disk by Python may be disabled. In this case you would Python may be disabled. In this case you would need to pre-build a
need to pre-build a Python library that has the required modules Python library that has the required modules pre-loaded and link LAMMPS
pre-loaded and link LAMMPS with that library. with that library.
Third, if your Python code calls back to LAMMPS (discussed in the Third, if your Python code calls back to LAMMPS (discussed in the next
next section) and causes LAMMPS to perform an MPI operation requires section) and causes LAMMPS to perform an MPI operation requires global
global communication (e.g. via MPI_Allreduce), such as computing the communication (e.g. via MPI_Allreduce), such as computing the global
global temperature of the system, then you must ensure all your Python temperature of the system, then you must ensure all your Python
functions (running independently on different processors) call back to functions (running independently on different processors) call back to
LAMMPS. Otherwise the code may hang. LAMMPS. Otherwise the code may hang.
---------- ----------
As mentioned above, a Python function can "call back" to LAMMPS As mentioned above, a Python function can "call back" to LAMMPS through
through its library interface, if the SELF input is used to pass its library interface, if the SELF input is used to pass Python a
Python a pointer to LAMMPS. The mechanism for doing this is as pointer to LAMMPS. The mechanism for doing this is as follows:
follows:
.. code-block:: python .. code-block:: python
@ -464,15 +468,15 @@ appeared in your input script. In this case, LAMMPS should output
Hello from inside Python Hello from inside Python
to the screen and log file. Note that since the LAMMPS print command to the screen and log file. Note that since the LAMMPS print command
itself takes a string in quotes as its argument, the Python string itself takes a string in quotes as its argument, the Python string must
must be delimited with a different style of quotes. be delimited with a different style of quotes.
The :doc:`Python_head` page describes the syntax The :doc:`Python_head` page describes the syntax for how Python wraps
for how Python wraps the various functions included in the LAMMPS the various functions included in the LAMMPS library interface.
library interface.
A more interesting example is in the ``examples/python/in.python`` script A more interesting example is in the ``examples/python/in.python``
which loads and runs the following function from ``examples/python/funcs.py``: script which loads and runs the following function from
``examples/python/funcs.py``:
.. code-block:: python .. code-block:: python
@ -503,53 +507,54 @@ with these input script commands:
python loop invoke python loop invoke
This has the effect of looping over a series of 10 short runs (10 This has the effect of looping over a series of 10 short runs (10
timesteps each) where the pair style cutoff is increased from a value timesteps each) where the pair style cutoff is increased from a value of
of 1.0 in distance units, in increments of 0.1. The looping stops 1.0 in distance units, in increments of 0.1. The looping stops when the
when the per-atom potential energy falls below a threshold of -4.0 in per-atom potential energy falls below a threshold of -4.0 in energy
energy units. More generally, Python can be used to implement a loop units. More generally, Python can be used to implement a loop with
with complex logic, much more so than can be created using the LAMMPS complex logic, much more so than can be created using the LAMMPS
:doc:`jump <jump>` and :doc:`if <if>` commands. :doc:`jump <jump>` and :doc:`if <if>` commands.
Several LAMMPS library functions are called from the loop function. Several LAMMPS library functions are called from the loop function.
Get_natoms() returns the number of atoms in the simulation, so that it Get_natoms() returns the number of atoms in the simulation, so that it
can be used to normalize the potential energy that is returned by can be used to normalize the potential energy that is returned by
extract_compute() for the "thermo_pe" compute that is defined by extract_compute() for the "thermo_pe" compute that is defined by default
default for LAMMPS thermodynamic output. Set_variable() sets the for LAMMPS thermodynamic output. Set_variable() sets the value of a
value of a string variable defined in LAMMPS. This library function string variable defined in LAMMPS. This library function is a useful
is a useful way for a Python function to return multiple values to way for a Python function to return multiple values to LAMMPS, more than
LAMMPS, more than the single value that can be passed back via a the single value that can be passed back via a return statement. This
return statement. This cutoff value in the "cut" variable is then cutoff value in the "cut" variable is then substituted (by LAMMPS) in
substituted (by LAMMPS) in the pair_style command that is executed the pair_style command that is executed next. Alternatively, the
next. Alternatively, the "alternate form of LAMMPS command" line "alternate form of LAMMPS command" line could be used in place of the 2
could be used in place of the 2 preceding lines, to have Python insert preceding lines, to have Python insert the value into the LAMMPS command
the value into the LAMMPS command string. string.
.. note:: .. note::
When using the callback mechanism just described, recognize that When using the callback mechanism just described, recognize that
there are some operations you should not attempt because LAMMPS cannot there are some operations you should not attempt because LAMMPS
execute them correctly. If the Python function is invoked between cannot execute them correctly. If the Python function is invoked
runs in the LAMMPS input script, then it should be OK to invoke any between runs in the LAMMPS input script, then it should be OK to
LAMMPS input script command via the library interface command() or invoke any LAMMPS input script command via the library interface
file() functions, so long as the command would work if it were command() or file() functions, so long as the command would work if
executed in the LAMMPS input script directly at the same point. it were executed in the LAMMPS input script directly at the same
point.
---------- ----------
A Python function can also be invoked during a run, whenever As noted above, a Python function can be invoked during a run, whenever
an associated python-style variable it is assigned to is evaluated. an associated python-style variable it is assigned to is evaluated.
If the variable is an input argument to another LAMMPS command If the variable is an input argument to another LAMMPS command
(e.g. :doc:`fix setforce <fix_setforce>`), then the Python function (e.g. :doc:`fix setforce <fix_setforce>`), then the Python function will
will be invoked inside the class for that command, possibly in one of be invoked inside the class for that command, possibly in one of its
its methods that is invoked in the middle of a timestep. You cannot methods that is invoked in the middle of a timestep. You cannot execute
execute arbitrary input script commands from the Python function arbitrary input script commands from the Python function (again, via the
(again, via the command() or file() functions) at that point in the command() or file() functions) at that point in the run and expect it to
run and expect it to work. Other library functions such as those that work. Other library functions such as those that invoke computes or
invoke computes or other variables may have hidden side effects as other variables may have hidden side effects as well. In these cases,
well. In these cases, LAMMPS has no simple way to check that LAMMPS has no simple way to check that something illogical is being
something illogical is being attempted. attempted.
The same constraints apply to Python functions called during a The same constraints apply to Python functions called during a
simulation run at each time step using the :doc:`fix python/invoke simulation run at each time step using the :doc:`fix python/invoke
@ -557,12 +562,12 @@ simulation run at each time step using the :doc:`fix python/invoke
---------- ----------
A Python function can also be invoked within the formula for an As noted above, a Python function can also be invoked within the formula
equal-style, vector-style, or atom-style variable. This means the for an equal-style, vector-style, or atom-style variable. This means
Python function will be invoked whenever the variable is invoked. In the Python function will be invoked whenever that variable is invoked.
the case of a vector-style variable, the Python function can be invoked In the case of a vector-style variable, the Python function can be
once per element of the global vector. In the case of an atom-style invoked once per element of the global vector. In the case of an
variable, the Python function can be invoked once per atom. atom-style variable, the Python function can be invoked once per atom.
Here are three simple examples using equal-, vector-, and atom-style Here are three simple examples using equal-, vector-, and atom-style
variables to trigger execution of a Python function: variables to trigger execution of a Python function:
@ -581,10 +586,10 @@ The Python ``truncate`` function simply converts a floating-point value
to an integer value. When the LAMMPS print command evaluates the to an integer value. When the LAMMPS print command evaluates the
equal-style ``ptrunc`` variable, the current thermodynamic pressure is equal-style ``ptrunc`` variable, the current thermodynamic pressure is
passed to the Python function. The truncated value is output to the passed to the Python function. The truncated value is output to the
screen and logfile by the print command. Note that the *input* screen and logfile by the print command. Note that the *input* keyword
keyword for the *python* command, specifies an internal-style variable for the *python* command, specifies an internal-style variable named
named "arg" as iv_arg which is required to invoke the Python function "arg" as iv_arg which is required to invoke the Python function from a
from a Python function wrapper. Python function wrapper.
The last 2 lines can be replaced by these to define a vector-style The last 2 lines can be replaced by these to define a vector-style
variable which invokes the same Python ``truncate`` function: variable which invokes the same Python ``truncate`` function:
@ -664,12 +669,11 @@ interactively or by using Python to launch a Python script stored in a
file, and your code has an error, you will typically see informative file, and your code has an error, you will typically see informative
error messages. That is not the case when you run Python code from error messages. That is not the case when you run Python code from
LAMMPS using an embedded Python interpreter. The code will typically LAMMPS using an embedded Python interpreter. The code will typically
fail silently. LAMMPS will catch some errors but cannot tell you fail silently. LAMMPS will catch some errors but cannot tell you where
where in the Python code the problem occurred. For example, if the in the Python code the problem occurred. For example, if the Python
Python code cannot be loaded and run because it has syntax or other code cannot be loaded and run because it has syntax or other logic
logic errors, you may get an error from Python pointing to the errors, you may get an error from Python pointing to the offending line,
offending line, or you may get one of these generic errors from or you may get one of these generic errors from LAMMPS:
LAMMPS:
.. parsed-literal:: .. parsed-literal::
@ -683,16 +687,16 @@ you will typically get this generic error from LAMMPS:
Python function evaluation failed Python function evaluation failed
Here are three suggestions for debugging your Python code while Here are three suggestions for debugging your Python code while running
running it under LAMMPS. it under LAMMPS.
First, don't run it under LAMMPS, at least to start with! Debug it First, don't run it under LAMMPS, at least to start with! Debug it
using plain Python. Load and invoke your function, pass it arguments, using plain Python. Load and invoke your function, pass it arguments,
check return values, etc. check return values, etc.
Second, add Python print statements to the function to check how far Second, add Python print statements to the function to check how far it
it gets and intermediate values it calculates. See the discussion gets and intermediate values it calculates. See the discussion above
above about printing from Python when running in parallel. about printing from Python when running in parallel.
Third, use Python exception handling. For example, say this statement Third, use Python exception handling. For example, say this statement
in your Python function is failing, because you have not initialized the in your Python function is failing, because you have not initialized the
@ -702,8 +706,7 @@ variable foo:
foo += 1 foo += 1
If you put one (or more) statements inside a "try" statement, If you put one (or more) statements inside a "try" statement, like this:
like this:
.. code-block:: python .. code-block:: python
@ -746,20 +749,20 @@ function must be able to load the :doc:`"lammps" Python module
These are the same steps required to use Python by itself to wrap These are the same steps required to use Python by itself to wrap
LAMMPS. Details on these steps are explained on the :doc:`Python LAMMPS. Details on these steps are explained on the :doc:`Python
<Python_head>` doc page. Note that it is important that the <Python_head>` doc page. Note that it is important that the stand-alone
stand-alone LAMMPS executable and the LAMMPS shared library be LAMMPS executable and the LAMMPS shared library be consistent (built
consistent (built from the same source code files) in order for this from the same source code files) in order for this to work. If the two
to work. If the two have been built at different times using have been built at different times using different source files,
different source files, problems may occur. problems may occur.
Another limitation of calling back to Python from the LAMMPS module Another limitation of calling back to Python from the LAMMPS module
using the *python* command in a LAMMPS input is that both, the Python 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 interpreter and LAMMPS, must be linked to the same Python runtime as a
shared library. If the Python interpreter is linked to Python shared library. If the Python interpreter is linked to Python
statically (which seems to happen with Conda) then loading the shared statically (which seems to happen with Conda) then loading the shared
LAMMPS library will create a second python "main" module that hides LAMMPS library will create a second python "main" module that hides the
the one from the Python interpreter and all previous defined function one from the Python interpreter and all previous defined function and
and global variables will become invisible. global variables will become invisible.
Related commands Related commands
"""""""""""""""" """"""""""""""""

View File

@ -1252,10 +1252,10 @@ the atoms it owns.
When invoked for the Ith atom, the value of the *arg* internal-style 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 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 the Ith atom. The call via python-style variable *foo* to the Python
*truncate()* function passes the value of the *arg* variable as its *truncate()* function passes the value of the *arg* variable as the
first (and only) argument. Likewise, the return value of the Python function's first (and only) argument. Likewise, the return value of
function becomes is stored by the python-style variable *foo* and used the Python function is stored by the python-style variable *foo* and
in the *xtrunc* atom-style variable formula for the Ith atom. used in the *xtrunc* atom-style variable formula for the Ith atom.
The resulting per-atom vector for *xtrunc* will thus contain the The resulting per-atom vector for *xtrunc* will thus contain the
truncated x-coord of every atom in the system. The dump command truncated x-coord of every atom in the system. The dump command