From db22bdc7b972e2d8576027c19cccd7ee84760fe3 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 12 Jun 2025 11:48:37 -0400 Subject: [PATCH] rewrap doc source --- doc/src/python.rst | 482 ++++++++++++++++++++++----------------------- 1 file changed, 237 insertions(+), 245 deletions(-) diff --git a/doc/src/python.rst b/doc/src/python.rst index bea2061621..bdde9c9a78 100644 --- a/doc/src/python.rst +++ b/doc/src/python.rst @@ -93,145 +93,142 @@ Description 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. +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. -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, vector-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-, vector-, and atom-style variables can -use a Python function wrapper in their formulas which encodes the -python-style variable name, and specifies arguments (which themselves -can be numeric formulas) to pass to the Python function associated -with the python-style variable. +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, vector-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-, vector-, and atom-style variables can use a Python +function wrapper in their formulas which encodes the python-style +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 ` 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: +As explained on the :doc:`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 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 -variables can be used in many different ways within LAMMPS. They can -be evaluated directly in an input script, effectively replacing the +variables can be used in many different ways within LAMMPS. They can be +evaluated 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 ` command doc page -for more details on variable styles which enable Python function -evaluation. +simulation run. See the :doc:`variable ` command doc page for +more details on variable styles which enable Python function evaluation. The Python code for a Python 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. +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. -A broader overview of how Python can be used with LAMMPS is given in -the :doc:`Use Python with LAMMPS ` section of the +A broader overview of how Python can be used with LAMMPS is given in the +:doc:`Use Python with LAMMPS ` section of the documentation. There is also an ``examples/python`` directory which illustrates use of the python command. ---------- -The first argument to the *python* command is the *mode* setting, -which is either *source* or the *name* of a Python function. +The first argument to the *python* command is the *mode* setting, which +is either *source* or the *name* of a Python function. .. versionchanged:: 22Dec2022 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 -single *inline* argument which is a string containing one or more -python commands. The string can either be on the same line as the -*python* command, enclosed in quotes, or it can be multiple lines -enclosed in triple quotes. +single *inline* argument which is a string containing one or more python +commands. The string can either be on the same line as the *python* +command, enclosed in quotes, or it can be multiple lines enclosed in +triple quotes. -In either case, the in-line code or the 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 LAMMPS input file. This can be used to pre-load Python modules, +In either case, the in-line code or the 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 +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 code. +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 LAMMPS for future execution (or can 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*, 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. +the *mode* function name. One of the keywords must be *invoke*, *file*, +*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. ---------- If the *invoke* keyword is used, no other keywords can be used. A previous *python* command must have registered the Python function -referenced by this command, which can then be invoked multiple times -in an input script via the *invoke* keyword. Each invocation passes -current values for arguments to the Python function. A return value -of the Python function will be ignored unless the Python function is -linked to a :doc:`python style variable ` with the *return* -keyword. 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 printed. Note that return values of python functions are -otherwise *only* accessible when the function is invoked indirectly by -evaluating its associated :doc:`python style variable `, as -described below. +referenced by this command, which can then be invoked multiple times in +an input script via the *invoke* keyword. Each invocation passes +current values for arguments to the Python function. A return value of +the Python function will be ignored unless the Python function is linked +to a :doc:`python style variable ` with the *return* keyword. +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 +printed. Note that return values of python functions are otherwise +*only* accessible when the function is invoked indirectly by evaluating +its associated :doc:`python style variable `, as described +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. +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 ` doc page, for an -explanation of how triple quotes can be used as part of input script -syntax. +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 ` 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). +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. +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. ---------- @@ -239,37 +236,36 @@ 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 -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 `. 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 +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 ` -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 as an argument to the Python -function. Note that a python-style variable can be used as an -argument, which means that the a Python function can use arguments -which invoke other Python functions. +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 ` 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 as an argument to the Python function. Note that a +python-style variable can be used as an argument, which means that the a +Python function can use arguments which invoke other Python functions. 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 -` with the specified name. +be defined in the input script (though it can be); if it is not defined, +this command creates an :doc:`internal-style variable ` with +the specified name. An internal-style variable must be used when an equal-style, vector-style, or atom-style variable triggers the invocation of the @@ -292,43 +288,43 @@ function can also have additional inputs, also specified by the *input* keyword, which are NOT arguments in the Python function wrapper. See the example below for the ``mixedargs`` Python function. -See the :doc:`variable ` command doc page for full details -on formula syntax including for Python function wrappers. Examples -using Python function wrappers are shown below. Note that as -explained above with python-style variables, Python function wrappers -can be nested; a sub-formula for an argument can contain its own -Python function wrapper which invokes another Python function. +See the :doc:`variable ` command doc page for full details on +formula syntax including for Python function wrappers. Examples using +Python function wrappers are shown below. Note that as explained above +with python-style variables, Python function wrappers can be nested; a +sub-formula for an argument can contain its own Python function wrapper +which invokes another Python function. The *return* keyword is only needed if the Python function returns a -value. The specified *varReturn* is 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 ` command. The Python function can return a numeric or string value, as specified by the *format* keyword. This return value is *only* accessible when its associated python-style variable is evaluated. When the *invoke* keyword is used, the return -value of the python function is ignored unless the optional -*logreturn* argument is specified. +value of the python function is ignored unless the optional *logreturn* +argument is specified. 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 -` 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 ` 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. LAMMPS will then allocate Nlen+1 space -to include the string terminator. If the Python function generates a +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. 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. @@ -347,23 +343,23 @@ with the triple-quote parsing that the LAMMPS input script performs. All the Python code you specify via one or more python commands is loaded into the Python "main" module, i.e. ``__name__ == '__main__'``. The code can define global variables, define global functions, define -classes or execute statements that are outside of function -definitions. It can contain multiple functions, only one of which -matches the *func* setting in the python command. This means you can -use the *file* keyword once to load several functions, and the -*exists* keyword thereafter in subsequent python commands to register -the other functions that were previously loaded with LAMMPS. +classes or execute statements that are outside of function definitions. +It can contain multiple functions, only one of which matches the *func* +setting in the python command. This means you can use the *file* +keyword once to load several functions, and the *exists* keyword +thereafter in subsequent python commands to register the other functions +that were previously loaded with LAMMPS. -A Python function you define (or more generally, the code you load) -can import other Python modules or classes, it can make calls to other +A Python function you define (or more generally, the code you load) can +import other Python modules or classes, it can make calls to other system functions or functions you define, and it can access or modify global variables (in the "main" module) which will persist between successive function calls. The latter can be useful, for example, to prevent a function from being invoke multiple times per timestep by different commands in a LAMMPS input script that access the returned python-style variable associated with the function. For example, -consider this function loaded with two global variables defined -outside the function: +consider this function loaded with two global variables defined outside +the function: .. code-block:: python @@ -390,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 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. +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 -copy of the Python function(s) you define. There is no connection -between the Python interpreters running on different processors. -This implies three important things. +each MPI task will load the Python interpreter and execute a local copy +of the Python function(s) you define. There is no connection between +the Python interpreters running on different processors. 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, @@ -409,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 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. +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 @@ -428,27 +424,26 @@ be printed only once, even when running LAMMPS in parallel. python python_hello invoke -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. +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 -global communication (e.g. via MPI_Allreduce), such as computing the -global temperature of the system, then you must ensure all your Python +Third, if your Python code calls back to LAMMPS (discussed in the next +section) and causes LAMMPS to perform an MPI operation requires global +communication (e.g. via MPI_Allreduce), such as computing the global +temperature of the system, then you must ensure all your Python functions (running independently on different processors) call back to LAMMPS. Otherwise the code may hang. ---------- -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: +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 @@ -473,15 +468,15 @@ appeared in your input script. In this case, LAMMPS should output Hello from inside Python 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 -must be delimited with a different style of quotes. +itself takes a string in quotes as its argument, the Python string must +be delimited with a different style of quotes. -The :doc:`Python_head` page describes the syntax -for how Python wraps the various functions included in the LAMMPS -library interface. +The :doc:`Python_head` page describes the syntax for how Python wraps +the various functions included in the LAMMPS library interface. -A more interesting example is in the ``examples/python/in.python`` script -which loads and runs the following function from ``examples/python/funcs.py``: +A more interesting example is in the ``examples/python/in.python`` +script which loads and runs the following function from +``examples/python/funcs.py``: .. code-block:: python @@ -512,54 +507,54 @@ with these input script commands: python loop invoke 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 -of 1.0 in distance units, in increments of 0.1. The looping stops -when the per-atom potential energy falls below a threshold of -4.0 in -energy units. More generally, Python can be used to implement a loop -with complex logic, much more so than can be created using the LAMMPS +timesteps each) where the pair style cutoff is increased from a value of +1.0 in distance units, in increments of 0.1. The looping stops when the +per-atom potential energy falls below a threshold of -4.0 in energy +units. More generally, Python can be used to implement a loop with +complex logic, much more so than can be created using the LAMMPS :doc:`jump ` and :doc:`if ` commands. Several LAMMPS library functions are called from the loop function. 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 -extract_compute() for the "thermo_pe" compute that is defined by -default for LAMMPS thermodynamic output. Set_variable() sets the -value of a string variable defined in LAMMPS. This library function -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 "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. +extract_compute() for the "thermo_pe" compute that is defined by default +for LAMMPS thermodynamic output. Set_variable() sets the value of a +string variable defined in LAMMPS. This library function 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 +"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:: When using the callback mechanism just described, recognize that - there are some operations you should not attempt because LAMMPS cannot - execute them correctly. If the Python function is invoked between - runs in the LAMMPS input script, then it should be OK to invoke any - LAMMPS input script command via the library interface command() or - file() functions, so long as the command would work if it were - executed in the LAMMPS input script directly at the same point. + there are some operations you should not attempt because LAMMPS + cannot execute them correctly. If the Python function is invoked + between runs in the LAMMPS input script, then it should be OK to + invoke any LAMMPS input script command via the library interface + command() or file() functions, so long as the command would work if + it were executed in the LAMMPS input script directly at the same + point. ---------- -As noted above, a Python function can be invoked during a run, -whenever an associated python-style variable it is assigned to is -evaluated. +As noted above, a Python function can 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 `), 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. +(e.g. :doc:`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 @@ -567,13 +562,12 @@ simulation run at each time step using the :doc:`fix python/invoke ---------- -As noted above, a Python function can also be invoked within the -formula for an equal-style, vector-style, or atom-style variable. -This means the Python function will be invoked whenever that variable -is invoked. In the case of a vector-style variable, the Python -function can be invoked once per element of the global vector. In the -case of an atom-style variable, the Python function can be invoked -once per atom. +As noted above, a Python function can also be invoked within the formula +for an equal-style, vector-style, or atom-style variable. This means +the Python function will be invoked whenever that variable is invoked. +In the case of a vector-style variable, the Python function can be +invoked once per element of the global vector. In the case of an +atom-style variable, the Python function can be invoked once per atom. Here are three simple examples using equal-, vector-, and atom-style variables to trigger execution of a Python function: @@ -592,10 +586,10 @@ 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. +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 a vector-style variable which invokes the same Python ``truncate`` function: @@ -675,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 error messages. That is not the case when you run Python code from LAMMPS using an embedded Python interpreter. The code will typically -fail silently. LAMMPS will catch some errors but cannot tell you -where in the Python code the problem occurred. For example, if the -Python code cannot be loaded and run because it has syntax or other -logic errors, you may get an error from Python pointing to the -offending line, or you may get one of these generic errors from -LAMMPS: +fail silently. LAMMPS will catch some errors but cannot tell you where +in the Python code the problem occurred. For example, if the Python +code cannot be loaded and run because it has syntax or other logic +errors, you may get an error from Python pointing to the offending line, +or you may get one of these generic errors from LAMMPS: .. parsed-literal:: @@ -694,16 +687,16 @@ you will typically get this generic error from LAMMPS: Python function evaluation failed -Here are three suggestions for debugging your Python code while -running it under LAMMPS. +Here are three suggestions for debugging your Python code while running +it under LAMMPS. 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, check return values, etc. -Second, add Python print statements to the function to check how far -it gets and intermediate values it calculates. See the discussion -above about printing from Python when running in parallel. +Second, add Python print statements to the function to check how far it +gets and intermediate values it calculates. See the discussion above +about printing from Python when running in parallel. Third, use Python exception handling. For example, say this statement in your Python function is failing, because you have not initialized the @@ -713,8 +706,7 @@ variable foo: foo += 1 -If you put one (or more) statements inside a "try" statement, -like this: +If you put one (or more) statements inside a "try" statement, like this: .. code-block:: python @@ -757,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 LAMMPS. Details on these steps are explained on the :doc:`Python -` 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. +` 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 """"""""""""""""