Merge branch 'develop' into plugin-add-run-min-style
This commit is contained in:
@ -5,18 +5,28 @@ LAMMPS has several commands which can be used to invoke Python
|
||||
code directly from an input script:
|
||||
|
||||
* :doc:`python <python>`
|
||||
* :doc:`variable python <variable>`
|
||||
* :doc:`python-style variables <variable>`
|
||||
* :doc:`equal-style and atom-style variables with formulas containing Python function wrappers <variable>`
|
||||
* :doc:`fix python/invoke <fix_python_invoke>`
|
||||
* :doc:`pair_style python <pair_python>`
|
||||
|
||||
The :doc:`python <python>` command which can be used to define and
|
||||
execute a Python function that you write the code for. The Python
|
||||
function can also be assigned to a LAMMPS python-style variable via
|
||||
the :doc:`variable <variable>` command. Each time the variable is
|
||||
The :doc:`python <python>` command can be used to define and execute a
|
||||
Python function that you write the code for. The Python function can
|
||||
also be assigned to a LAMMPS python-style variable via the
|
||||
:doc:`variable <variable>` command. Each time the variable is
|
||||
evaluated, either in the LAMMPS input script itself, or by another
|
||||
LAMMPS command that uses the variable, this will trigger the Python
|
||||
function to be invoked.
|
||||
|
||||
The Python function can also be referenced in the formula used to
|
||||
define an :doc:`equal-style or atom-style variable <variable>`, using
|
||||
the syntax for a :doc:`Python function wrapper <variable>`. This make
|
||||
it easy to pass LAMMPS-related arguments to the Python function, as
|
||||
well as to invoke it whenever the equal- or atom-style variable is
|
||||
evaluated. For an atom-style variable it means the Python function
|
||||
can be invoked once per atom, using per-atom properties as arguments
|
||||
to the function.
|
||||
|
||||
The Python code for the function can be included directly in the input
|
||||
script or in an auxiliary file. The function can have arguments which
|
||||
are mapped to LAMMPS variables (also defined in the input script) and
|
||||
|
||||
@ -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)
|
||||
|
||||
|
||||
@ -130,13 +130,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
|
||||
@ -144,7 +146,6 @@ output the statistics in various ways:
|
||||
|
||||
.. code-block:: LAMMPS
|
||||
|
||||
variable d internal 0.0
|
||||
variable dsq equal v_d*v_d
|
||||
|
||||
compute 1 all property/local batom1 batom2 btype
|
||||
|
||||
@ -45,30 +45,31 @@ interactions. The number of datums generated, aggregated across all
|
||||
processors, equals the number of dihedral angles in the system, modified
|
||||
by the group parameter as explained below.
|
||||
|
||||
The value *phi* (:math:`\phi`) is the dihedral angle, as defined in the diagram
|
||||
on the :doc:`dihedral_style <dihedral_style>` doc page.
|
||||
The value *phi* (:math:`\phi`) is the dihedral angle, as defined in
|
||||
the diagram on the :doc:`dihedral_style <dihedral_style>` doc page.
|
||||
|
||||
The value *v_name* can be used together with the *set* keyword to compute a
|
||||
user-specified function of the dihedral angle :math:`\phi`. The *name*
|
||||
specified for the *v_name* value is the name of an
|
||||
:doc:`equal-style variable <variable>` which should evaluate a formula based on
|
||||
a variable which will store the angle :math:`\phi`. This other variable must
|
||||
be an :doc:`internal-style variable <variable>` defined in the input
|
||||
script; its initial numeric value can be anything. It must be an
|
||||
internal-style variable, because this command resets its value
|
||||
directly. The *set* keyword is used to identify the name of this
|
||||
other variable associated with :math:`\phi`.
|
||||
The value *v_name* can be used together with the *set* keyword to
|
||||
compute a user-specified function of the dihedral angle :math:`\phi`.
|
||||
The *name* specified for the *v_name* value is the name of an
|
||||
:doc:`equal-style variable <variable>` which should evaluate a formula
|
||||
based on a variable which will store the angle :math:`\phi`. This
|
||||
other variable must be an :doc:`internal-style variable <variable>`
|
||||
specified by the *set* keyword. It is an internal-style variable,
|
||||
because this command resets its value directly. The internal-style
|
||||
variable does not need to be defined in the input script (though it
|
||||
can be); if it is not defined, then the *set* option creates an
|
||||
:doc:`internal-style variable <variable>` with the specified name.
|
||||
|
||||
Note that the value of :math:`\phi` for each angle which stored in the internal
|
||||
variable is in radians, not degrees.
|
||||
Note that the value of :math:`\phi` for each angle which stored in the
|
||||
internal variable is in radians, not degrees.
|
||||
|
||||
As an example, these commands can be added to the bench/in.rhodo
|
||||
script to compute the :math:`\cos\phi` and :math:`\cos^2\phi` of every dihedral
|
||||
angle in the system and output the statistics in various ways:
|
||||
script to compute the :math:`\cos\phi` and :math:`\cos^2\phi` of every
|
||||
dihedral angle in the system and output the statistics in various
|
||||
ways:
|
||||
|
||||
.. code-block:: LAMMPS
|
||||
|
||||
variable p internal 0.0
|
||||
variable cos equal cos(v_p)
|
||||
variable cossq equal cos(v_p)*cos(v_p)
|
||||
|
||||
@ -100,10 +101,10 @@ no consistent ordering of the entries within the local vector or array
|
||||
from one timestep to the next. The only consistency that is
|
||||
guaranteed is that the ordering on a particular timestep will be the
|
||||
same for local vectors or arrays generated by other compute commands.
|
||||
For example, dihedral output from the
|
||||
:doc:`compute property/local <compute_property_local>` command can be combined
|
||||
with data from this command and output by the :doc:`dump local <dump>`
|
||||
command in a consistent way.
|
||||
For example, dihedral output from the :doc:`compute property/local
|
||||
<compute_property_local>` command can be combined with data from this
|
||||
command and output by the :doc:`dump local <dump>` command in a
|
||||
consistent way.
|
||||
|
||||
Here is an example of how to do this:
|
||||
|
||||
|
||||
@ -416,24 +416,23 @@ atom, based on its coordinates. They apply to all styles except
|
||||
*single*. The *name* specified for the *var* keyword is the name of
|
||||
an :doc:`equal-style variable <variable>` that should evaluate to a
|
||||
zero or non-zero value based on one or two or three variables that
|
||||
will store the *x*, *y*, or *z* coordinates of an atom (one variable per
|
||||
coordinate). If used, these other variables must be
|
||||
:doc:`internal-style variables <variable>` defined in the input
|
||||
script; their initial numeric value can be anything. They must be
|
||||
internal-style variables, because this command resets their values
|
||||
directly. The *set* keyword is used to identify the names of these
|
||||
other variables, one variable for the *x*-coordinate of a created atom,
|
||||
one for *y*, and one for *z*.
|
||||
will store the *x*, *y*, or *z* coordinates of an atom (one variable
|
||||
per coordinate). If used, these other variables must be specified by
|
||||
the *set* keyword. They are internal-style variable, because this
|
||||
command resets their values directly. The internal-style variables do
|
||||
not need to be defined in the input script (though they can be); if
|
||||
one (or more) is not defined, then the *set* option creates an
|
||||
:doc:`internal-style variable <variable>` with the specified name.
|
||||
|
||||
.. figure:: img/sinusoid.jpg
|
||||
:figwidth: 50%
|
||||
:align: right
|
||||
:target: _images/sinusoid.jpg
|
||||
|
||||
When an atom is created, its :math:`(x,y,z)` coordinates become the values for
|
||||
any *set* variable that is defined. The *var* variable is then
|
||||
evaluated. If the returned value is 0.0, the atom is not created. If
|
||||
it is non-zero, the atom is created.
|
||||
When an atom is about to be created, its :math:`(x,y,z)` coordinates
|
||||
become the values for any *set* variable that is defined. The *var*
|
||||
variable is then evaluated. If the returned value is 0.0, the atom is
|
||||
not created. If it is non-zero, the atom is created.
|
||||
|
||||
As an example, these commands can be used in a 2d simulation, to
|
||||
create a sinusoidal surface. Note that the surface is "rough" due to
|
||||
@ -456,8 +455,6 @@ converts lattice spacings to distance.
|
||||
region box block 0 $x 0 $y -0.5 0.5
|
||||
create_box 1 box
|
||||
|
||||
variable xx internal 0.0
|
||||
variable yy internal 0.0
|
||||
variable v equal "(0.2*v_y*ylat * cos(v_xx/xlat * 2.0*PI*4.0/v_x) + 0.5*v_y*ylat - v_yy) > 0.0"
|
||||
create_atoms 1 box var v set x xx set y yy
|
||||
write_dump all atom sinusoid.lammpstrj
|
||||
|
||||
@ -98,52 +98,53 @@ the following dynamic equation:
|
||||
|
||||
\frac{dc}{dt} = -\alpha (K_p e + K_i \int_0^t e \, dt + K_d \frac{de}{dt} )
|
||||
|
||||
where *c* is the continuous time analog of the control variable,
|
||||
*e* =\ *pvar*\ -\ *setpoint* is the error in the process variable, and
|
||||
:math:`\alpha`, :math:`K_p`, :math:`K_i` , and :math:`K_d` are constants
|
||||
set by the corresponding
|
||||
keywords described above. The discretized version of this equation is:
|
||||
where *c* is the continuous time analog of the control variable, *e*
|
||||
=\ *pvar*\ -\ *setpoint* is the error in the process variable, and
|
||||
:math:`\alpha`, :math:`K_p`, :math:`K_i` , and :math:`K_d` are
|
||||
constants set by the corresponding keywords described above. The
|
||||
discretized version of this equation is:
|
||||
|
||||
.. math::
|
||||
|
||||
c_n = c_{n-1} -\alpha \left( K_p \tau e_n + K_i \tau^2 \sum_{i=1}^n e_i + K_d (e_n - e_{n-1}) \right)
|
||||
|
||||
where :math:`\tau = \mathtt{Nevery} \cdot \mathtt{timestep}` is the time
|
||||
interval between updates,
|
||||
and the subscripted variables indicate the values of *c* and *e* at
|
||||
successive updates.
|
||||
where :math:`\tau = \mathtt{Nevery} \cdot \mathtt{timestep}` is the
|
||||
time interval between updates, and the subscripted variables indicate
|
||||
the values of *c* and *e* at successive updates.
|
||||
|
||||
From the first equation, it is clear that if the three gain values
|
||||
:math:`K_p`, :math:`K_i`, :math:`K_d` are dimensionless constants,
|
||||
then :math:`\alpha` must have
|
||||
units of [unit *cvar*\ ]/[unit *pvar*\ ]/[unit time] e.g. [ eV/K/ps
|
||||
]. The advantage of this unit scheme is that the value of the
|
||||
constants should be invariant under a change of either the MD timestep
|
||||
size or the value of *Nevery*\ . Similarly, if the LAMMPS :doc:`unit style <units>` is changed, it should only be necessary to change
|
||||
the value of :math:`\alpha` to reflect this, while leaving :math:`K_p`,
|
||||
:math:`K_i`, and :math:`K_d` unaltered.
|
||||
then :math:`\alpha` must have units of [unit *cvar*\ ]/[unit *pvar*\
|
||||
]/[unit time] e.g. [ eV/K/ps ]. The advantage of this unit scheme is
|
||||
that the value of the constants should be invariant under a change of
|
||||
either the MD timestep size or the value of *Nevery*\ . Similarly, if
|
||||
the LAMMPS :doc:`unit style <units>` is changed, it should only be
|
||||
necessary to change the value of :math:`\alpha` to reflect this, while
|
||||
leaving :math:`K_p`, :math:`K_i`, and :math:`K_d` unaltered.
|
||||
|
||||
When choosing the values of the four constants, it is best to first
|
||||
pick a value and sign for :math:`\alpha` that is consistent with the
|
||||
magnitudes and signs of *pvar* and *cvar*\ . The magnitude of :math:`K_p`
|
||||
should then be tested over a large positive range keeping :math:`K_i = K_d =0`.
|
||||
A good value for :math:`K_p` will produce a fast response in *pvar*,
|
||||
without overshooting the *setpoint*\ . For many applications, proportional
|
||||
feedback is sufficient, and so :math:`K_i = K_d =0` can be used. In cases
|
||||
where there is a substantial lag time in the response of *pvar* to a change
|
||||
in *cvar*, this can be counteracted by increasing :math:`K_d`. In situations
|
||||
magnitudes and signs of *pvar* and *cvar*\ . The magnitude of
|
||||
:math:`K_p` should then be tested over a large positive range keeping
|
||||
:math:`K_i = K_d =0`. A good value for :math:`K_p` will produce a
|
||||
fast response in *pvar*, without overshooting the *setpoint*\ . For
|
||||
many applications, proportional feedback is sufficient, and so
|
||||
:math:`K_i = K_d =0` can be used. In cases where there is a
|
||||
substantial lag time in the response of *pvar* to a change in *cvar*,
|
||||
this can be counteracted by increasing :math:`K_d`. In situations
|
||||
where *pvar* plateaus without reaching *setpoint*, this can be
|
||||
counteracted by increasing :math:`K_i`. In the language of Charles Dickens,
|
||||
:math:`K_p` represents the error of the present, :math:`K_i` the error of
|
||||
the past, and :math:`K_d` the error yet to come.
|
||||
counteracted by increasing :math:`K_i`. In the language of Charles
|
||||
Dickens, :math:`K_p` represents the error of the present, :math:`K_i`
|
||||
the error of the past, and :math:`K_d` the error yet to come.
|
||||
|
||||
Because this fix updates *cvar*, but does not initialize its value,
|
||||
the initial value :math:`c_0` is that assigned by the user in the input script via
|
||||
the :doc:`internal-style variable <variable>` command. This value is
|
||||
used (by every other LAMMPS command that uses the variable) until this
|
||||
fix performs its first update of *cvar* after *Nevery* timesteps. On
|
||||
the first update, the value of the derivative term is set to zero,
|
||||
because the value of :math:`e_{n-1}` is not yet defined.
|
||||
the initial value :math:`c_0` is that assigned by the user in the
|
||||
input script via the :doc:`internal-style variable <variable>`
|
||||
command. This value is used (by every other LAMMPS command that uses
|
||||
the variable) until this fix performs its first update of *cvar* after
|
||||
*Nevery* timesteps. On the first update, the value of the derivative
|
||||
term is set to zero, because the value of :math:`e_{n-1}` is not yet
|
||||
defined.
|
||||
|
||||
----------
|
||||
|
||||
@ -154,21 +155,23 @@ must produce a global quantity, not a per-atom or local quantity.
|
||||
|
||||
If *pvar* begins with "c\_", a compute ID must follow which has been
|
||||
previously defined in the input script and which generates a global
|
||||
scalar or vector. See the individual :doc:`compute <compute>` doc page
|
||||
for details. If no bracketed integer is appended, the scalar
|
||||
scalar or vector. See the individual :doc:`compute <compute>` doc
|
||||
page for details. If no bracketed integer is appended, the scalar
|
||||
calculated by the compute is used. If a bracketed integer is
|
||||
appended, the Ith value of the vector calculated by the compute is
|
||||
used. Users can also write code for their own compute styles and :doc:`add them to LAMMPS <Modify>`.
|
||||
used. Users can also write code for their own compute styles and
|
||||
:doc:`add them to LAMMPS <Modify>`.
|
||||
|
||||
If *pvar* begins with "f\_", a fix ID must follow which has been
|
||||
previously defined in the input script and which generates a global
|
||||
scalar or vector. See the individual :doc:`fix <fix>` page for
|
||||
details. Note that some fixes only produce their values on certain
|
||||
timesteps, which must be compatible with when fix controller
|
||||
references the values, or else an error results. If no bracketed integer
|
||||
is appended, the scalar calculated by the fix is used. If a bracketed
|
||||
integer is appended, the Ith value of the vector calculated by the fix
|
||||
is used. Users can also write code for their own fix style and :doc:`add them to LAMMPS <Modify>`.
|
||||
references the values, or else an error results. If no bracketed
|
||||
integer is appended, the scalar calculated by the fix is used. If a
|
||||
bracketed integer is appended, the Ith value of the vector calculated
|
||||
by the fix is used. Users can also write code for their own fix style
|
||||
and :doc:`add them to LAMMPS <Modify>`.
|
||||
|
||||
If *pvar* begins with "v\_", a variable name must follow which has been
|
||||
previously defined in the input script. Only equal-style variables
|
||||
@ -182,19 +185,21 @@ variable.
|
||||
The target value *setpoint* for the process variable must be a numeric
|
||||
value, in whatever units *pvar* is defined for.
|
||||
|
||||
The control variable *cvar* must be the name of an :doc:`internal-style variable <variable>` previously defined in the input script. Note
|
||||
that it is not specified with a "v\_" prefix, just the name of the
|
||||
variable. It must be an internal-style variable, because this fix
|
||||
updates its value directly. Note that other commands can use an
|
||||
equal-style versus internal-style variable interchangeably.
|
||||
The control variable *cvar* must be the name of an
|
||||
:doc:`internal-style variable <variable>` previously defined in the
|
||||
input script. Note that it is not specified with a "v\_" prefix, just
|
||||
the name of the variable. It must be an internal-style variable,
|
||||
because this fix updates its value directly. Note that other commands
|
||||
can use an equal-style versus internal-style variable interchangeably.
|
||||
|
||||
----------
|
||||
|
||||
Restart, fix_modify, output, run start/stop, minimize info
|
||||
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
|
||||
|
||||
Currently, no information about this fix is written to :doc:`binary restart files <restart>`. None of the :doc:`fix_modify <fix_modify>` options
|
||||
are relevant to this fix.
|
||||
Currently, no information about this fix is written to :doc:`binary
|
||||
restart files <restart>`. None of the :doc:`fix_modify <fix_modify>`
|
||||
options are relevant to this fix.
|
||||
|
||||
This fix produces a global vector with 3 values which can be accessed
|
||||
by various :doc:`output commands <Howto_output>`. The values can be
|
||||
@ -211,7 +216,8 @@ variable is in. The vector values calculated by this fix are
|
||||
"extensive".
|
||||
|
||||
No parameter of this fix can be used with the *start/stop* keywords of
|
||||
the :doc:`run <run>` command. This fix is not invoked during :doc:`energy minimization <minimize>`.
|
||||
the :doc:`run <run>` command. This fix is not invoked during
|
||||
:doc:`energy minimization <minimize>`.
|
||||
|
||||
Restrictions
|
||||
""""""""""""
|
||||
|
||||
@ -225,22 +225,25 @@ rotated configuration of the molecule.
|
||||
|
||||
.. versionadded:: 21Nov2023
|
||||
|
||||
The *var* and *set* keywords can be used together to provide a criterion
|
||||
for accepting or rejecting the addition of an individual atom, based on its
|
||||
coordinates. The *name* specified for the *var* keyword is the name of an
|
||||
:doc:`equal-style variable <variable>` that should evaluate to a zero or
|
||||
non-zero value based on one or two or three variables that will store the
|
||||
*x*, *y*, or *z* coordinates of an atom (one variable per coordinate). If
|
||||
used, these other variables must be :doc:`internal-style variables
|
||||
<variable>` defined in the input script; their initial numeric value can be
|
||||
anything. They must be internal-style variables, because this command
|
||||
resets their values directly. The *set* keyword is used to identify the
|
||||
names of these other variables, one variable for the *x*-coordinate of a
|
||||
created atom, one for *y*, and one for *z*. When an atom is created, its
|
||||
:math:`(x,y,z)` coordinates become the values for any *set* variable that
|
||||
is defined. The *var* variable is then evaluated. If the returned value
|
||||
is 0.0, the atom is not created. If it is non-zero, the atom is created.
|
||||
For an example of how to use these keywords, see the
|
||||
The *var* and *set* keywords can be used together to provide a
|
||||
criterion for accepting or rejecting the addition of an individual
|
||||
atom, based on its coordinates. The *name* specified for the *var*
|
||||
keyword is the name of an :doc:`equal-style variable <variable>` that
|
||||
should evaluate to a zero or non-zero value based on one or two or
|
||||
three variables that will store the *x*, *y*, or *z* coordinates of an
|
||||
atom (one variable per coordinate). If used, these other variables
|
||||
must be :doc:`internal-style variables <variable>` specified by the
|
||||
*set* keyword. They must be internal-style variables, because this
|
||||
command resets their values directly. The internal-style variables do
|
||||
not need to be defined in the input script (though they can be); if
|
||||
one (or more) is not defined, then the *set* option creates an
|
||||
:doc:`internal-style variable <variable>` with the specified name.
|
||||
|
||||
When an atom is about to be created, its :math:`(x,y,z)` coordinates
|
||||
become the values for any *set* variable that is defined. The *var*
|
||||
variable is then evaluated. If the returned value is 0.0, the atom is
|
||||
not created. If it is non-zero, the atom is created. For an example
|
||||
of how to use the set/var keywords in a similar context, see the
|
||||
:doc:`create_atoms <create_atoms>` command.
|
||||
|
||||
The *rate* option moves the insertion volume in the z direction (3d)
|
||||
@ -304,12 +307,13 @@ units of distance or velocity.
|
||||
Restart, fix_modify, output, run start/stop, minimize info
|
||||
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
|
||||
|
||||
This fix writes the state of the deposition to :doc:`binary restart files <restart>`. This includes information about how many
|
||||
particles have been deposited, the random number generator seed, the
|
||||
next timestep for deposition, etc. See the
|
||||
:doc:`read_restart <read_restart>` command for info on how to re-specify
|
||||
a fix in an input script that reads a restart file, so that the
|
||||
operation of the fix continues in an uninterrupted fashion.
|
||||
This fix writes the state of the deposition to :doc:`binary restart
|
||||
files <restart>`. This includes information about how many particles
|
||||
have been deposited, the random number generator seed, the next
|
||||
timestep for deposition, etc. See the :doc:`read_restart
|
||||
<read_restart>` command for info on how to re-specify a fix in an
|
||||
input script that reads a restart file, so that the operation of the
|
||||
fix continues in an uninterrupted fashion.
|
||||
|
||||
.. note::
|
||||
|
||||
|
||||
@ -10,43 +10,46 @@ 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
|
||||
*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 = invoke the previously-defined Python function
|
||||
logreturn = log return value of the invoked python function, if defined (optional)
|
||||
*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
|
||||
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
|
||||
|
||||
@ -56,7 +59,7 @@ Examples
|
||||
.. code-block:: LAMMPS
|
||||
|
||||
python pForce input 2 v_x 20.0 return v_f format fff file force.py
|
||||
python pForce invoke
|
||||
python pForce invoke logreturn
|
||||
|
||||
python factorial input 1 myN return v_fac format ii here """
|
||||
def factorial(n):
|
||||
@ -87,37 +90,42 @@ 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, 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 function
|
||||
name, and specifies arguments to pass to the function.
|
||||
|
||||
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
|
||||
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,69 +133,128 @@ 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
|
||||
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, 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.
|
||||
If the *invoke* keyword is used, only the optional *logreturn* keyword
|
||||
can be used. A previous *python* command must have registered the
|
||||
Python function referenced by this command. The command invokes the
|
||||
Python function with the previously defined arguments. A return value
|
||||
of the Python function will be ignored unless the Python function is
|
||||
linked to a :doc:`python style variable <variable>` with the *return*
|
||||
keyword. This return value can be logged to the screen and logfile by
|
||||
adding the *logreturn* keyword to the *invoke* command. In that case a
|
||||
message with the name of the python command and the return value is
|
||||
printed. Return values of python functions are otherwise only
|
||||
accessible when the function is invoked indirectly by expanding a
|
||||
:doc:`python style variable <variable>`. You can invoke a registered
|
||||
function as many times as you wish in your input script.
|
||||
|
||||
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. 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
|
||||
<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
|
||||
Python function defined by this command, by including a Python function
|
||||
wrapper with arguments in its formula. Each of the arguments must be
|
||||
specified as an internal-style variable via the *input* keyword.
|
||||
|
||||
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 sub-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; thus 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). Note that the Python
|
||||
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 <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* 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.
|
||||
This return value is *only* accessible when expanding the python-style
|
||||
variable. When the *invoke* keyword is used, the return value of
|
||||
the python function is ignored.
|
||||
|
||||
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 +263,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 +310,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 +378,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 +395,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 +419,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 +436,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 +487,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 +520,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 +534,128 @@ 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, vector-style, or atom-style variable. This means the
|
||||
Python function will be invoked whenever the 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:
|
||||
|
||||
.. 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 a vector-style
|
||||
variable which invokes the same Python ``truncate`` function:
|
||||
|
||||
.. code-block:: LAMMPS
|
||||
|
||||
compute ke all temp
|
||||
variable ke vector c_ke
|
||||
variable ketrunc vector py_foo(v_ke)
|
||||
thermo_style custom step temp epair v_ketrunc[*6]
|
||||
|
||||
The vector-style variable ``ketrunc`` invokes the Python ``truncate``
|
||||
function on each of the 6 components of the global kinetic energy tensor
|
||||
calculated by the :doc:`compute ke <compute_ke>` command. The 6
|
||||
truncated values will be printed with thermo output to the screen and
|
||||
log file.
|
||||
|
||||
Or the last 2 lines of the equal-style variable example can be replaced
|
||||
by these to define atom-style variables 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
|
||||
|
||||
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 variable formula or
|
||||
by *input* keyword to the :doc:`python command <python>`. 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_flag &
|
||||
format fffffsf here """
|
||||
def mixedargs(a,b,x,y,z,flag):
|
||||
...
|
||||
return result
|
||||
"""
|
||||
variable flag 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 arguments ``(7.5,v_myValue,v_flag)`` 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 each 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 +742,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
|
||||
"""""""
|
||||
|
||||
@ -45,7 +45,8 @@ Syntax
|
||||
*universe* args = one or more strings
|
||||
*world* args = one string for each partition of processors
|
||||
|
||||
*equal* or *vector* or *atom* args = one formula containing numbers, thermo keywords, math operations, built-in functions, atom values and vectors, compute/fix/variable references
|
||||
*equal* or *vector* or *atom* args = one formula containing numbers, thermo keywords,
|
||||
math operations, built-in functions, atom values and vectors, compute/fix/variable references
|
||||
numbers = 0.0, 100, -5.4, 2.8e-4, etc
|
||||
constants = PI, version, on, off, true, false, yes, no
|
||||
thermo keywords = vol, ke, press, etc from :doc:`thermo_style <thermo_style>`
|
||||
@ -67,8 +68,12 @@ Syntax
|
||||
bound(group,dir,region), gyration(group,region), ke(group,reigon),
|
||||
angmom(group,dim,region), torque(group,dim,region),
|
||||
inertia(group,dimdim,region), omega(group,dim,region)
|
||||
special functions = sum(x), min(x), max(x), ave(x), trap(x), slope(x), sort(x), rsort(x), gmask(x), rmask(x), grmask(x,y), next(x), is_file(name), is_os(name), extract_setting(name), label2type(kind,label), is_typelabel(kind,label), is_timeout()
|
||||
feature functions = is_available(category,feature), is_active(category,feature), is_defined(category,id)
|
||||
special functions = sum(x), min(x), max(x), ave(x), trap(x), slope(x), sort(x), rsort(x), \ gmask(x), rmask(x), grmask(x,y), next(x), is_file(name), is_os(name),
|
||||
extract_setting(name), label2type(kind,label),
|
||||
is_typelabel(kind,label), is_timeout()
|
||||
feature functions = is_available(category,feature), is_active(category,feature),
|
||||
is_defined(category,id)
|
||||
python function wrapper = py_varname(x,y,z,...)
|
||||
atom value = id[i], mass[i], type[i], mol[i], x[i], y[i], z[i], vx[i], vy[i], vz[i], fx[i], fy[i], fz[i], q[i]
|
||||
atom vector = id, mass, type, mol, radius, q, x, y, z, vx, vy, vz, fx, fy, fz
|
||||
custom atom property = i_name, d_name, i_name[i], d_name[i], i2_name[i], d2_name[i], i2_name[i][j], d2_name[i][j]
|
||||
@ -127,18 +132,21 @@ command), or used as input to an averaging fix (see the :doc:`fix
|
||||
ave/time <fix_ave_time>` command). Variables of style *vector* store
|
||||
a formula which produces a vector of such values which can be used as
|
||||
input to various averaging fixes, or elements of which can be part of
|
||||
thermodynamic output. Variables of style *atom* store a formula which
|
||||
when evaluated produces one numeric value per atom which can be output
|
||||
to a dump file (see the :doc:`dump custom <dump>` command) or used as
|
||||
input to an averaging fix (see the :doc:`fix ave/chunk
|
||||
<fix_ave_chunk>` and :doc:`fix ave/atom <fix_ave_atom>` commands).
|
||||
Variables of style *atomfile* can be used anywhere in an input script
|
||||
that atom-style variables are used; they get their per-atom values
|
||||
from a file rather than from a formula. Variables of style *python*
|
||||
can be hooked to Python functions using code you provide, so that the
|
||||
variable gets its value from the evaluation of the Python code.
|
||||
Variables of style *internal* are used by a few commands which set
|
||||
their value directly.
|
||||
thermodynamic output.
|
||||
|
||||
Variables of style *atom* store a formula which when evaluated
|
||||
produces one numeric value per atom which can be output to a dump file
|
||||
(see the :doc:`dump custom <dump>` command) or used as input to an
|
||||
averaging fix (see the :doc:`fix ave/chunk <fix_ave_chunk>` and
|
||||
:doc:`fix ave/atom <fix_ave_atom>` commands). Variables of style
|
||||
*atomfile* can be used anywhere in an input script that atom-style
|
||||
variables are used; they get their per-atom values from a file rather
|
||||
than from a formula.
|
||||
|
||||
Variables of style *python* can be hooked to Python functions using
|
||||
Python code you provide, so that the variable gets its value from the
|
||||
evaluation of the Python code. Variables of style *internal* are used
|
||||
by a few commands which set their value directly.
|
||||
|
||||
.. note::
|
||||
|
||||
@ -166,15 +174,16 @@ simulation.
|
||||
|
||||
.. note::
|
||||
|
||||
When an input script line is encountered that defines a variable
|
||||
of style *equal* or *vector* or *atom* or *python* that contains a
|
||||
formula or Python code, the formula is NOT immediately evaluated. It
|
||||
will be evaluated every time when the variable is **used** instead. If
|
||||
you simply want to evaluate a formula in place you can use as
|
||||
so-called. See the section below about "Immediate Evaluation of
|
||||
Variables" for more details on the topic. This is also true of a
|
||||
*format* style variable since it evaluates another variable when it is
|
||||
invoked.
|
||||
When an input script line is encountered that defines a variable of
|
||||
style *equal* or *vector* or *atom* or *python* that contains a
|
||||
formula or links to Python code, the formula or Python code is NOT
|
||||
immediately evaluated. Instead, it is evaluated each time the
|
||||
variable is **used**. If you simply want to evaluate a formula in
|
||||
place you can use a so-called immediate variable. as described in
|
||||
the preceding note. Or see the section below about "Immediate
|
||||
Evaluation of Variables" for more details on the topic. This is
|
||||
also true of a *format* style variable since it evaluates another
|
||||
variable when it is invoked.
|
||||
|
||||
Variables of style *equal* and *vector* and *atom* can be used as
|
||||
inputs to various other commands which evaluate their formulas as
|
||||
@ -183,12 +192,12 @@ this context, variables of style *timer* or *internal* or *python* can
|
||||
be used in place of an equal-style variable, with the following two
|
||||
caveats.
|
||||
|
||||
First, internal-style variables can be used except by commands that
|
||||
set the value stored by the internal variable. When the LAMMPS
|
||||
command evaluates the internal-style variable, it will use the value
|
||||
set (internally) by another command. Second, python-style variables
|
||||
can be used so long as the associated Python function, as defined by
|
||||
the :doc:`python <python>` command, returns a numeric value. When the
|
||||
First, internal-style variables require their values be set by code
|
||||
elsewhere in LAMMPS. When a LAMMPS input script or command evaluates
|
||||
an internal-style variable, it must have a current value set
|
||||
(internally) via that mechanism. Second, python-style variables can
|
||||
be used so long as the associated Python function, as defined by the
|
||||
:doc:`python <python>` command, returns a numeric value. When the
|
||||
LAMMPS command evaluates the python-style variable, the Python
|
||||
function will be executed.
|
||||
|
||||
@ -388,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.
|
||||
|
||||
----------
|
||||
|
||||
@ -439,6 +459,15 @@ python-style variable can be used in place of an equal-style variable
|
||||
anywhere in an input script, e.g. as an argument to another command
|
||||
that allows for equal-style variables.
|
||||
|
||||
A python-style variable can also be used within the formula for an
|
||||
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.
|
||||
|
||||
----------
|
||||
|
||||
For the *string* style, a single string is assigned to the variable.
|
||||
@ -528,9 +557,9 @@ 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, atom values, atom
|
||||
vectors, custom atom properties, compute references, fix references, and references to other
|
||||
variables.
|
||||
functions, special functions, feature functions, Python function
|
||||
wrappers, atom values, atom vectors, custom atom properties, compute
|
||||
references, fix references, and references to other variables.
|
||||
|
||||
+------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Number | 0.2, 100, 1.0e20, -15.4, etc |
|
||||
@ -551,6 +580,8 @@ variables.
|
||||
+------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Feature functions | is_available(category,feature), is_active(category,feature), is_defined(category,id) |
|
||||
+------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| 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] |
|
||||
+------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Atom vectors | id, mass, type, mol, x, y, z, vx, vy, vz, fx, fy, fz, q |
|
||||
@ -1161,6 +1192,84 @@ variable name.
|
||||
|
||||
----------
|
||||
|
||||
Python Function wrapper
|
||||
------------------------
|
||||
|
||||
A Python function wrapper enables the formula for an equal-style or
|
||||
atom-style variable to invoke functions coded in Python. In the case
|
||||
of an equal-style variable, the Python-coded function will be invoked
|
||||
once. In the case of an atom-style variable, it can be invoked once
|
||||
per atom, if one or more of its arguments include a per-atom quantity,
|
||||
e.g. the position of an atom. As illustrated below, the reason to use
|
||||
a Python function wrapper is to make it easy to pass LAMMPS-related
|
||||
arguments to the Python-coded function associated with a python-style
|
||||
variable.
|
||||
|
||||
The syntax for defining a Python function wrapper is
|
||||
|
||||
.. code-block:: LAMMPS
|
||||
|
||||
py_varname(arg1,arg2,...argN)
|
||||
|
||||
where *varname* is the name of a python-style variable which couples
|
||||
to a Python-coded function. The function will be passed the zero or
|
||||
more arguments listed in parentheses: *arg1*, *arg2*, ... *argN*. As
|
||||
with Math Functions, each argument can itself be an arbitrarily
|
||||
complex formula.
|
||||
|
||||
A Python function wrapper can be used in the following manner by an
|
||||
input script:
|
||||
|
||||
.. code-block:: LAMMPS
|
||||
|
||||
variable foo python truncate
|
||||
python truncate return v_foo input 1 v_arg format fi here """
|
||||
def truncate(x):
|
||||
return int(x)
|
||||
"""
|
||||
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
|
||||
|
||||
The first two commands define a python-style variable *foo* and couple
|
||||
it to the Python-coded function *truncate()* which takes a single
|
||||
floating point argument, and returns its truncated integer value. In
|
||||
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 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
|
||||
variable *xtrunc* will invoke the python-style variable *foo*, which
|
||||
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 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
|
||||
-----------------------
|
||||
|
||||
|
||||
@ -3129,6 +3129,7 @@ Pxy
|
||||
pxz
|
||||
py
|
||||
Py
|
||||
pyargs
|
||||
pydir
|
||||
pylammps
|
||||
PyLammps
|
||||
@ -4080,6 +4081,7 @@ Vanduyfhuys
|
||||
varargs
|
||||
varavg
|
||||
variational
|
||||
varname
|
||||
Varshalovich
|
||||
Varshney
|
||||
vashishta
|
||||
|
||||
234
examples/python/dump.1May25.python.wrap.g++.1
Normal file
234
examples/python/dump.1May25.python.wrap.g++.1
Normal file
@ -0,0 +1,234 @@
|
||||
ITEM: TIMESTEP
|
||||
0
|
||||
ITEM: NUMBER OF ATOMS
|
||||
108
|
||||
ITEM: BOX BOUNDS pp pp pp
|
||||
0.0000000000000000e+00 5.0387885741475218e+00
|
||||
0.0000000000000000e+00 5.0387885741475218e+00
|
||||
0.0000000000000000e+00 5.0387885741475218e+00
|
||||
ITEM: ATOMS id x y z v_xtrunc v_ytrunc v_ztrunc
|
||||
1 0 0 0 0 0 0
|
||||
2 0.839798 0.839798 0 0 0 0
|
||||
3 0.839798 0 0.839798 0 0 0
|
||||
4 0 0.839798 0.839798 0 0 0
|
||||
5 1.6796 0 0 1 0 0
|
||||
6 2.51939 0.839798 0 2 0 0
|
||||
7 2.51939 0 0.839798 2 0 0
|
||||
8 1.6796 0.839798 0.839798 1 0 0
|
||||
9 3.35919 0 0 3 0 0
|
||||
10 4.19899 0.839798 0 4 0 0
|
||||
11 4.19899 0 0.839798 4 0 0
|
||||
12 3.35919 0.839798 0.839798 3 0 0
|
||||
13 0 1.6796 0 0 1 0
|
||||
14 0.839798 2.51939 0 0 2 0
|
||||
15 0.839798 1.6796 0.839798 0 1 0
|
||||
16 0 2.51939 0.839798 0 2 0
|
||||
17 1.6796 1.6796 0 1 1 0
|
||||
18 2.51939 2.51939 0 2 2 0
|
||||
19 2.51939 1.6796 0.839798 2 1 0
|
||||
20 1.6796 2.51939 0.839798 1 2 0
|
||||
21 3.35919 1.6796 0 3 1 0
|
||||
22 4.19899 2.51939 0 4 2 0
|
||||
23 4.19899 1.6796 0.839798 4 1 0
|
||||
24 3.35919 2.51939 0.839798 3 2 0
|
||||
25 0 3.35919 0 0 3 0
|
||||
26 0.839798 4.19899 0 0 4 0
|
||||
27 0.839798 3.35919 0.839798 0 3 0
|
||||
28 0 4.19899 0.839798 0 4 0
|
||||
29 1.6796 3.35919 0 1 3 0
|
||||
30 2.51939 4.19899 0 2 4 0
|
||||
31 2.51939 3.35919 0.839798 2 3 0
|
||||
32 1.6796 4.19899 0.839798 1 4 0
|
||||
33 3.35919 3.35919 0 3 3 0
|
||||
34 4.19899 4.19899 0 4 4 0
|
||||
35 4.19899 3.35919 0.839798 4 3 0
|
||||
36 3.35919 4.19899 0.839798 3 4 0
|
||||
37 0 0 1.6796 0 0 1
|
||||
38 0.839798 0.839798 1.6796 0 0 1
|
||||
39 0.839798 0 2.51939 0 0 2
|
||||
40 0 0.839798 2.51939 0 0 2
|
||||
41 1.6796 0 1.6796 1 0 1
|
||||
42 2.51939 0.839798 1.6796 2 0 1
|
||||
43 2.51939 0 2.51939 2 0 2
|
||||
44 1.6796 0.839798 2.51939 1 0 2
|
||||
45 3.35919 0 1.6796 3 0 1
|
||||
46 4.19899 0.839798 1.6796 4 0 1
|
||||
47 4.19899 0 2.51939 4 0 2
|
||||
48 3.35919 0.839798 2.51939 3 0 2
|
||||
49 0 1.6796 1.6796 0 1 1
|
||||
50 0.839798 2.51939 1.6796 0 2 1
|
||||
51 0.839798 1.6796 2.51939 0 1 2
|
||||
52 0 2.51939 2.51939 0 2 2
|
||||
53 1.6796 1.6796 1.6796 1 1 1
|
||||
54 2.51939 2.51939 1.6796 2 2 1
|
||||
55 2.51939 1.6796 2.51939 2 1 2
|
||||
56 1.6796 2.51939 2.51939 1 2 2
|
||||
57 3.35919 1.6796 1.6796 3 1 1
|
||||
58 4.19899 2.51939 1.6796 4 2 1
|
||||
59 4.19899 1.6796 2.51939 4 1 2
|
||||
60 3.35919 2.51939 2.51939 3 2 2
|
||||
61 0 3.35919 1.6796 0 3 1
|
||||
62 0.839798 4.19899 1.6796 0 4 1
|
||||
63 0.839798 3.35919 2.51939 0 3 2
|
||||
64 0 4.19899 2.51939 0 4 2
|
||||
65 1.6796 3.35919 1.6796 1 3 1
|
||||
66 2.51939 4.19899 1.6796 2 4 1
|
||||
67 2.51939 3.35919 2.51939 2 3 2
|
||||
68 1.6796 4.19899 2.51939 1 4 2
|
||||
69 3.35919 3.35919 1.6796 3 3 1
|
||||
70 4.19899 4.19899 1.6796 4 4 1
|
||||
71 4.19899 3.35919 2.51939 4 3 2
|
||||
72 3.35919 4.19899 2.51939 3 4 2
|
||||
73 0 0 3.35919 0 0 3
|
||||
74 0.839798 0.839798 3.35919 0 0 3
|
||||
75 0.839798 0 4.19899 0 0 4
|
||||
76 0 0.839798 4.19899 0 0 4
|
||||
77 1.6796 0 3.35919 1 0 3
|
||||
78 2.51939 0.839798 3.35919 2 0 3
|
||||
79 2.51939 0 4.19899 2 0 4
|
||||
80 1.6796 0.839798 4.19899 1 0 4
|
||||
81 3.35919 0 3.35919 3 0 3
|
||||
82 4.19899 0.839798 3.35919 4 0 3
|
||||
83 4.19899 0 4.19899 4 0 4
|
||||
84 3.35919 0.839798 4.19899 3 0 4
|
||||
85 0 1.6796 3.35919 0 1 3
|
||||
86 0.839798 2.51939 3.35919 0 2 3
|
||||
87 0.839798 1.6796 4.19899 0 1 4
|
||||
88 0 2.51939 4.19899 0 2 4
|
||||
89 1.6796 1.6796 3.35919 1 1 3
|
||||
90 2.51939 2.51939 3.35919 2 2 3
|
||||
91 2.51939 1.6796 4.19899 2 1 4
|
||||
92 1.6796 2.51939 4.19899 1 2 4
|
||||
93 3.35919 1.6796 3.35919 3 1 3
|
||||
94 4.19899 2.51939 3.35919 4 2 3
|
||||
95 4.19899 1.6796 4.19899 4 1 4
|
||||
96 3.35919 2.51939 4.19899 3 2 4
|
||||
97 0 3.35919 3.35919 0 3 3
|
||||
98 0.839798 4.19899 3.35919 0 4 3
|
||||
99 0.839798 3.35919 4.19899 0 3 4
|
||||
100 0 4.19899 4.19899 0 4 4
|
||||
101 1.6796 3.35919 3.35919 1 3 3
|
||||
102 2.51939 4.19899 3.35919 2 4 3
|
||||
103 2.51939 3.35919 4.19899 2 3 4
|
||||
104 1.6796 4.19899 4.19899 1 4 4
|
||||
105 3.35919 3.35919 3.35919 3 3 3
|
||||
106 4.19899 4.19899 3.35919 4 4 3
|
||||
107 4.19899 3.35919 4.19899 4 3 4
|
||||
108 3.35919 4.19899 4.19899 3 4 4
|
||||
ITEM: TIMESTEP
|
||||
100
|
||||
ITEM: NUMBER OF ATOMS
|
||||
108
|
||||
ITEM: BOX BOUNDS pp pp pp
|
||||
0.0000000000000000e+00 5.0387885741475218e+00
|
||||
0.0000000000000000e+00 5.0387885741475218e+00
|
||||
0.0000000000000000e+00 5.0387885741475218e+00
|
||||
ITEM: ATOMS id x y z v_xtrunc v_ytrunc v_ztrunc
|
||||
1 4.97801 0.0605812 4.88474 4 0 4
|
||||
2 0.800305 0.813213 0.0576603 0 0 0
|
||||
3 0.6485 5.00484 0.836947 0 5 0
|
||||
4 5.01236 0.786108 0.77507 5 0 0
|
||||
5 1.50261 4.9277 4.9755 1 4 4
|
||||
6 2.46756 0.653742 5.0003 2 0 5
|
||||
7 2.55699 4.96491 0.926671 2 4 0
|
||||
8 1.62464 0.676882 0.777822 1 0 0
|
||||
9 3.57018 0.00324557 4.76943 3 0 4
|
||||
10 4.24909 0.985667 5.01613 4 0 5
|
||||
11 4.13124 0.178555 0.700886 4 0 0
|
||||
12 3.22537 0.963341 0.639686 3 0 0
|
||||
13 4.90815 1.75715 0.0826318 4 1 0
|
||||
14 1.00239 2.45421 0.0111309 1 2 0
|
||||
15 0.88902 1.62097 0.874547 0 1 0
|
||||
16 0.269512 2.41383 0.844638 0 2 0
|
||||
17 1.54513 1.51174 0.0869798 1 1 0
|
||||
18 2.0637 2.5991 0.0826392 2 2 0
|
||||
19 2.44634 1.71869 0.918144 2 1 0
|
||||
20 1.57997 2.52559 1.04361 1 2 1
|
||||
21 3.26063 2.10027 0.0160498 3 2 0
|
||||
22 4.21774 2.61172 0.0367453 4 2 0
|
||||
23 4.32215 1.8333 0.925663 4 1 0
|
||||
24 3.38151 2.6788 0.906258 3 2 0
|
||||
25 0.275459 3.26838 0.21932 0 3 0
|
||||
26 0.675354 4.14887 4.94054 0 4 4
|
||||
27 0.867201 3.35405 1.17655 0 3 1
|
||||
28 4.78788 4.34273 0.478103 4 4 0
|
||||
29 1.42014 3.50181 0.191388 1 3 0
|
||||
30 2.39935 4.14279 0.0726977 2 4 0
|
||||
31 2.68157 3.57418 0.921633 2 3 0
|
||||
32 1.77965 4.13041 0.925765 1 4 0
|
||||
33 3.10555 3.22911 5.00703 3 3 5
|
||||
34 4.24908 3.67507 4.83053 4 3 4
|
||||
35 4.2444 3.59428 0.837193 4 3 0
|
||||
36 3.52155 4.21032 0.423884 3 4 0
|
||||
37 0.00881412 4.90616 1.74242 0 4 1
|
||||
38 0.800033 0.812556 1.72553 0 0 1
|
||||
39 0.929754 0.0251285 2.53734 0 0 2
|
||||
40 0.0189933 0.897729 2.4272 0 0 2
|
||||
41 1.77025 0.0864618 1.69637 1 0 1
|
||||
42 2.6077 0.984882 1.7897 2 0 1
|
||||
43 2.55819 4.95626 2.45373 2 4 2
|
||||
44 1.77963 0.875522 2.5056 1 0 2
|
||||
45 3.50499 0.0189748 1.5186 3 0 1
|
||||
46 4.47856 0.849521 1.59138 4 0 1
|
||||
47 3.99 0.309367 2.42507 3 0 2
|
||||
48 3.06373 0.748905 2.87477 3 0 2
|
||||
49 0.149175 1.72252 1.81302 0 1 1
|
||||
50 0.963279 2.42412 1.76899 0 2 1
|
||||
51 0.879984 1.74899 2.55389 0 1 2
|
||||
52 0.211736 2.57456 2.48446 0 2 2
|
||||
53 1.75238 1.7433 1.79028 1 1 1
|
||||
54 2.61023 2.6802 1.55816 2 2 1
|
||||
55 2.55259 1.72904 2.60295 2 1 2
|
||||
56 1.7903 2.56204 2.41895 1 2 2
|
||||
57 3.43857 1.71819 1.54054 3 1 1
|
||||
58 4.20455 2.5331 1.87607 4 2 1
|
||||
59 4.12961 1.48438 2.40107 4 1 2
|
||||
60 3.36606 2.52455 2.67203 3 2 2
|
||||
61 0.0138563 3.23504 1.76147 0 3 1
|
||||
62 0.968224 4.42746 1.67526 0 4 1
|
||||
63 0.965745 3.43479 2.52674 0 3 2
|
||||
64 0.144542 4.27264 2.61793 0 4 2
|
||||
65 1.7741 3.32184 1.66819 1 3 1
|
||||
66 2.4878 4.29352 1.69069 2 4 1
|
||||
67 2.56992 3.44579 2.4534 2 3 2
|
||||
68 1.72356 4.2344 2.49376 1 4 2
|
||||
69 3.43363 3.36417 1.87451 3 3 1
|
||||
70 4.32623 4.1046 1.69102 4 4 1
|
||||
71 4.22927 3.23505 2.64208 4 3 2
|
||||
72 3.41086 4.28362 2.42553 3 4 2
|
||||
73 4.85349 0.0953155 3.14546 4 0 3
|
||||
74 0.833593 0.840282 3.27238 0 0 3
|
||||
75 0.578712 4.99093 3.85234 0 4 3
|
||||
76 0.119704 1.00404 4.09942 0 1 4
|
||||
77 1.78347 4.95586 3.31184 1 4 3
|
||||
78 2.34318 0.736887 3.54475 2 0 3
|
||||
79 2.34858 4.82316 4.28272 2 4 4
|
||||
80 1.55893 0.765128 4.31112 1 0 4
|
||||
81 3.13128 0.0257347 3.70936 3 0 3
|
||||
82 4.10851 0.877375 3.36388 4 0 3
|
||||
83 4.30691 4.69041 4.14081 4 4 4
|
||||
84 3.48471 1.07347 4.35888 3 1 4
|
||||
85 0.0668209 1.77975 3.29313 0 1 3
|
||||
86 0.894798 2.5043 3.34172 0 2 3
|
||||
87 0.743432 1.71961 4.3483 0 1 4
|
||||
88 0.135168 2.69084 4.12098 0 2 4
|
||||
89 1.73749 1.5259 3.46692 1 1 3
|
||||
90 2.47391 2.57508 3.27574 2 2 3
|
||||
91 2.4825 1.46064 4.38907 2 1 4
|
||||
92 1.67786 2.47309 4.03082 1 2 4
|
||||
93 3.34694 1.70248 3.44784 3 1 3
|
||||
94 4.20676 2.29697 3.23228 4 2 3
|
||||
95 4.31748 1.76411 4.20898 4 1 4
|
||||
96 3.1135 2.59262 4.08996 3 2 4
|
||||
97 0.0727406 3.44797 3.30247 0 3 3
|
||||
98 1.0752 4.05296 3.38036 1 4 3
|
||||
99 1.0085 3.35058 4.3598 1 3 4
|
||||
100 0.054939 4.00087 4.11831 0 4 4
|
||||
101 1.72259 3.24691 3.19685 1 3 3
|
||||
102 2.54324 4.21582 3.29642 2 4 3
|
||||
103 2.33008 3.38603 4.27885 2 3 4
|
||||
104 1.65617 4.10852 4.3491 1 4 4
|
||||
105 3.14646 3.43756 3.28105 3 3 3
|
||||
106 4.09781 4.10691 3.24439 4 4 3
|
||||
107 4.1529 3.22538 3.79605 4 3 3
|
||||
108 3.16394 3.96553 4.31023 3 3 4
|
||||
234
examples/python/dump.1May25.python.wrap.g++.4
Normal file
234
examples/python/dump.1May25.python.wrap.g++.4
Normal file
@ -0,0 +1,234 @@
|
||||
ITEM: TIMESTEP
|
||||
0
|
||||
ITEM: NUMBER OF ATOMS
|
||||
108
|
||||
ITEM: BOX BOUNDS pp pp pp
|
||||
0.0000000000000000e+00 5.0387885741475218e+00
|
||||
0.0000000000000000e+00 5.0387885741475218e+00
|
||||
0.0000000000000000e+00 5.0387885741475218e+00
|
||||
ITEM: ATOMS id x y z v_xtrunc v_ytrunc v_ztrunc
|
||||
1 0 0 0 0 0 0
|
||||
2 0.839798 0.839798 0 0 0 0
|
||||
3 0.839798 0 0.839798 0 0 0
|
||||
4 0 0.839798 0.839798 0 0 0
|
||||
13 0 1.6796 0 0 1 0
|
||||
14 0.839798 1.6796 0.839798 0 1 0
|
||||
19 0 0 1.6796 0 0 1
|
||||
20 0.839798 0.839798 1.6796 0 0 1
|
||||
25 0 1.6796 1.6796 0 1 1
|
||||
5 1.6796 0 0 1 0 0
|
||||
6 2.51939 0.839798 0 2 0 0
|
||||
7 2.51939 0 0.839798 2 0 0
|
||||
8 1.6796 0.839798 0.839798 1 0 0
|
||||
15 1.6796 1.6796 0 1 1 0
|
||||
16 2.51939 1.6796 0.839798 2 1 0
|
||||
21 1.6796 0 1.6796 1 0 1
|
||||
22 2.51939 0.839798 1.6796 2 0 1
|
||||
26 1.6796 1.6796 1.6796 1 1 1
|
||||
9 3.35919 0 0 3 0 0
|
||||
10 4.19899 0.839798 0 4 0 0
|
||||
11 4.19899 0 0.839798 4 0 0
|
||||
12 3.35919 0.839798 0.839798 3 0 0
|
||||
17 3.35919 1.6796 0 3 1 0
|
||||
18 4.19899 1.6796 0.839798 4 1 0
|
||||
23 3.35919 0 1.6796 3 0 1
|
||||
24 4.19899 0.839798 1.6796 4 0 1
|
||||
27 3.35919 1.6796 1.6796 3 1 1
|
||||
28 0.839798 0 2.51939 0 0 2
|
||||
29 0 0.839798 2.51939 0 0 2
|
||||
34 0.839798 1.6796 2.51939 0 1 2
|
||||
37 0 0 3.35919 0 0 3
|
||||
38 0.839798 0.839798 3.35919 0 0 3
|
||||
39 0.839798 0 4.19899 0 0 4
|
||||
40 0 0.839798 4.19899 0 0 4
|
||||
49 0 1.6796 3.35919 0 1 3
|
||||
50 0.839798 1.6796 4.19899 0 1 4
|
||||
30 2.51939 0 2.51939 2 0 2
|
||||
31 1.6796 0.839798 2.51939 1 0 2
|
||||
35 2.51939 1.6796 2.51939 2 1 2
|
||||
41 1.6796 0 3.35919 1 0 3
|
||||
42 2.51939 0.839798 3.35919 2 0 3
|
||||
43 2.51939 0 4.19899 2 0 4
|
||||
44 1.6796 0.839798 4.19899 1 0 4
|
||||
51 1.6796 1.6796 3.35919 1 1 3
|
||||
52 2.51939 1.6796 4.19899 2 1 4
|
||||
32 4.19899 0 2.51939 4 0 2
|
||||
33 3.35919 0.839798 2.51939 3 0 2
|
||||
36 4.19899 1.6796 2.51939 4 1 2
|
||||
45 3.35919 0 3.35919 3 0 3
|
||||
46 4.19899 0.839798 3.35919 4 0 3
|
||||
47 4.19899 0 4.19899 4 0 4
|
||||
48 3.35919 0.839798 4.19899 3 0 4
|
||||
53 3.35919 1.6796 3.35919 3 1 3
|
||||
54 4.19899 1.6796 4.19899 4 1 4
|
||||
55 0.839798 2.51939 0 0 2 0
|
||||
56 0 2.51939 0.839798 0 2 0
|
||||
61 0 3.35919 0 0 3 0
|
||||
62 0.839798 4.19899 0 0 4 0
|
||||
63 0.839798 3.35919 0.839798 0 3 0
|
||||
64 0 4.19899 0.839798 0 4 0
|
||||
73 0.839798 2.51939 1.6796 0 2 1
|
||||
76 0 3.35919 1.6796 0 3 1
|
||||
77 0.839798 4.19899 1.6796 0 4 1
|
||||
57 2.51939 2.51939 0 2 2 0
|
||||
58 1.6796 2.51939 0.839798 1 2 0
|
||||
65 1.6796 3.35919 0 1 3 0
|
||||
66 2.51939 4.19899 0 2 4 0
|
||||
67 2.51939 3.35919 0.839798 2 3 0
|
||||
68 1.6796 4.19899 0.839798 1 4 0
|
||||
74 2.51939 2.51939 1.6796 2 2 1
|
||||
78 1.6796 3.35919 1.6796 1 3 1
|
||||
79 2.51939 4.19899 1.6796 2 4 1
|
||||
59 4.19899 2.51939 0 4 2 0
|
||||
60 3.35919 2.51939 0.839798 3 2 0
|
||||
69 3.35919 3.35919 0 3 3 0
|
||||
70 4.19899 4.19899 0 4 4 0
|
||||
71 4.19899 3.35919 0.839798 4 3 0
|
||||
72 3.35919 4.19899 0.839798 3 4 0
|
||||
75 4.19899 2.51939 1.6796 4 2 1
|
||||
80 3.35919 3.35919 1.6796 3 3 1
|
||||
81 4.19899 4.19899 1.6796 4 4 1
|
||||
82 0 2.51939 2.51939 0 2 2
|
||||
85 0.839798 3.35919 2.51939 0 3 2
|
||||
86 0 4.19899 2.51939 0 4 2
|
||||
91 0.839798 2.51939 3.35919 0 2 3
|
||||
92 0 2.51939 4.19899 0 2 4
|
||||
97 0 3.35919 3.35919 0 3 3
|
||||
98 0.839798 4.19899 3.35919 0 4 3
|
||||
99 0.839798 3.35919 4.19899 0 3 4
|
||||
100 0 4.19899 4.19899 0 4 4
|
||||
83 1.6796 2.51939 2.51939 1 2 2
|
||||
87 2.51939 3.35919 2.51939 2 3 2
|
||||
88 1.6796 4.19899 2.51939 1 4 2
|
||||
93 2.51939 2.51939 3.35919 2 2 3
|
||||
94 1.6796 2.51939 4.19899 1 2 4
|
||||
101 1.6796 3.35919 3.35919 1 3 3
|
||||
102 2.51939 4.19899 3.35919 2 4 3
|
||||
103 2.51939 3.35919 4.19899 2 3 4
|
||||
104 1.6796 4.19899 4.19899 1 4 4
|
||||
84 3.35919 2.51939 2.51939 3 2 2
|
||||
89 4.19899 3.35919 2.51939 4 3 2
|
||||
90 3.35919 4.19899 2.51939 3 4 2
|
||||
95 4.19899 2.51939 3.35919 4 2 3
|
||||
96 3.35919 2.51939 4.19899 3 2 4
|
||||
105 3.35919 3.35919 3.35919 3 3 3
|
||||
106 4.19899 4.19899 3.35919 4 4 3
|
||||
107 4.19899 3.35919 4.19899 4 3 4
|
||||
108 3.35919 4.19899 4.19899 3 4 4
|
||||
ITEM: TIMESTEP
|
||||
100
|
||||
ITEM: NUMBER OF ATOMS
|
||||
108
|
||||
ITEM: BOX BOUNDS pp pp pp
|
||||
0.0000000000000000e+00 5.0387885741475218e+00
|
||||
0.0000000000000000e+00 5.0387885741475218e+00
|
||||
0.0000000000000000e+00 5.0387885741475218e+00
|
||||
ITEM: ATOMS id x y z v_xtrunc v_ytrunc v_ztrunc
|
||||
27 3.43857 1.71819 1.54054 3 1 1
|
||||
55 1.00239 2.45421 0.0111309 1 2 0
|
||||
24 4.47856 0.849521 1.59138 4 0 1
|
||||
4 5.01236 0.786108 0.77507 5 0 0
|
||||
13 4.90815 1.75715 0.0826318 4 1 0
|
||||
14 0.88902 1.62097 0.874547 0 1 0
|
||||
23 3.50499 0.0189748 1.5186 3 0 1
|
||||
20 0.800033 0.812556 1.72553 0 0 1
|
||||
25 0.149175 1.72252 1.81302 0 1 1
|
||||
18 4.32215 1.8333 0.925663 4 1 0
|
||||
2 0.800305 0.813213 0.0576603 0 0 0
|
||||
11 4.13124 0.178555 0.700886 4 0 0
|
||||
8 1.62464 0.676882 0.777822 1 0 0
|
||||
15 1.54513 1.51174 0.0869798 1 1 0
|
||||
16 2.44634 1.71869 0.918144 2 1 0
|
||||
21 1.77025 0.0864618 1.69637 1 0 1
|
||||
22 2.6077 0.984882 1.7897 2 0 1
|
||||
26 1.75238 1.7433 1.79028 1 1 1
|
||||
56 0.269512 2.41383 0.844638 0 2 0
|
||||
73 0.963279 2.42412 1.76899 0 2 1
|
||||
12 3.22537 0.963341 0.639686 3 0 0
|
||||
29 0.0189933 0.897729 2.4272 0 0 2
|
||||
36 4.12961 1.48438 2.40107 4 1 2
|
||||
31 1.77963 0.875522 2.5056 1 0 2
|
||||
17 3.26063 2.10027 0.0160498 3 2 0
|
||||
32 3.99 0.309367 2.42507 3 0 2
|
||||
10 4.24909 0.985667 5.01613 4 0 5
|
||||
9 3.57018 0.00324557 4.76943 3 0 4
|
||||
34 0.879984 1.74899 2.55389 0 1 2
|
||||
54 4.31748 1.76411 4.20898 4 1 4
|
||||
38 0.833593 0.840282 3.27238 0 0 3
|
||||
53 3.34694 1.70248 3.44784 3 1 3
|
||||
40 0.119704 1.00404 4.09942 0 1 4
|
||||
49 0.0668209 1.77975 3.29313 0 1 3
|
||||
50 0.743432 1.71961 4.3483 0 1 4
|
||||
1 4.97801 0.0605812 4.88474 4 0 4
|
||||
28 0.929754 0.0251285 2.53734 0 0 2
|
||||
94 1.67786 2.47309 4.03082 1 2 4
|
||||
48 3.48471 1.07347 4.35888 3 1 4
|
||||
42 2.34318 0.736887 3.54475 2 0 3
|
||||
46 4.10851 0.877375 3.36388 4 0 3
|
||||
44 1.55893 0.765128 4.31112 1 0 4
|
||||
51 1.73749 1.5259 3.46692 1 1 3
|
||||
52 2.4825 1.46064 4.38907 2 1 4
|
||||
45 3.13128 0.0257347 3.70936 3 0 3
|
||||
33 3.06373 0.748905 2.87477 3 0 2
|
||||
37 4.85349 0.0953155 3.14546 4 0 3
|
||||
95 4.20676 2.29697 3.23228 4 2 3
|
||||
91 0.894798 2.5043 3.34172 0 2 3
|
||||
6 2.46756 0.653742 5.0003 2 0 5
|
||||
35 2.55259 1.72904 2.60295 2 1 2
|
||||
75 4.20455 2.5331 1.87607 4 2 1
|
||||
83 1.7903 2.56204 2.41895 1 2 2
|
||||
90 3.41086 4.28362 2.42553 3 4 2
|
||||
7 2.55699 4.96491 0.926671 2 4 0
|
||||
63 0.867201 3.35405 1.17655 0 3 1
|
||||
64 4.78788 4.34273 0.478103 4 4 0
|
||||
81 4.32623 4.1046 1.69102 4 4 1
|
||||
76 0.0138563 3.23504 1.76147 0 3 1
|
||||
77 0.968224 4.42746 1.67526 0 4 1
|
||||
57 2.0637 2.5991 0.0826392 2 2 0
|
||||
80 3.43363 3.36417 1.87451 3 3 1
|
||||
65 1.42014 3.50181 0.191388 1 3 0
|
||||
58 1.57997 2.52559 1.04361 1 2 1
|
||||
67 2.68157 3.57418 0.921633 2 3 0
|
||||
68 1.77965 4.13041 0.925765 1 4 0
|
||||
74 2.61023 2.6802 1.55816 2 2 1
|
||||
78 1.7741 3.32184 1.66819 1 3 1
|
||||
79 2.4878 4.29352 1.69069 2 4 1
|
||||
59 4.21774 2.61172 0.0367453 4 2 0
|
||||
72 3.52155 4.21032 0.423884 3 4 0
|
||||
19 0.00881412 4.90616 1.74242 0 4 1
|
||||
71 4.2444 3.59428 0.837193 4 3 0
|
||||
60 3.38151 2.6788 0.906258 3 2 0
|
||||
88 1.72356 4.2344 2.49376 1 4 2
|
||||
87 2.56992 3.44579 2.4534 2 3 2
|
||||
61 0.275459 3.26838 0.21932 0 3 0
|
||||
3 0.6485 5.00484 0.836947 0 5 0
|
||||
66 2.39935 4.14279 0.0726977 2 4 0
|
||||
82 0.211736 2.57456 2.48446 0 2 2
|
||||
30 2.55819 4.95626 2.45373 2 4 2
|
||||
108 3.16394 3.96553 4.31023 3 3 4
|
||||
62 0.675354 4.14887 4.94054 0 4 4
|
||||
47 4.30691 4.69041 4.14081 4 4 4
|
||||
107 4.1529 3.22538 3.79605 4 3 3
|
||||
92 0.135168 2.69084 4.12098 0 2 4
|
||||
97 0.0727406 3.44797 3.30247 0 3 3
|
||||
98 1.0752 4.05296 3.38036 1 4 3
|
||||
99 1.0085 3.35058 4.3598 1 3 4
|
||||
100 0.054939 4.00087 4.11831 0 4 4
|
||||
106 4.09781 4.10691 3.24439 4 4 3
|
||||
70 4.24908 3.67507 4.83053 4 3 4
|
||||
43 2.34858 4.82316 4.28272 2 4 4
|
||||
105 3.14646 3.43756 3.28105 3 3 3
|
||||
96 3.1135 2.59262 4.08996 3 2 4
|
||||
101 1.72259 3.24691 3.19685 1 3 3
|
||||
102 2.54324 4.21582 3.29642 2 4 3
|
||||
103 2.33008 3.38603 4.27885 2 3 4
|
||||
104 1.65617 4.10852 4.3491 1 4 4
|
||||
84 3.36606 2.52455 2.67203 3 2 2
|
||||
89 4.22927 3.23505 2.64208 4 3 2
|
||||
41 1.78347 4.95586 3.31184 1 4 3
|
||||
93 2.47391 2.57508 3.27574 2 2 3
|
||||
39 0.578712 4.99093 3.85234 0 4 3
|
||||
86 0.144542 4.27264 2.61793 0 4 2
|
||||
5 1.50261 4.9277 4.9755 1 4 4
|
||||
69 3.10555 3.22911 5.00703 3 3 5
|
||||
85 0.965745 3.43479 2.52674 0 3 2
|
||||
60
examples/python/in.python.wrap
Normal file
60
examples/python/in.python.wrap
Normal file
@ -0,0 +1,60 @@
|
||||
# 3d Lennard-Jones melt with equal- and atom-style variables which
|
||||
# use a Python function wrapper in their formulas
|
||||
|
||||
variable x index 3
|
||||
variable y index 3
|
||||
variable z index 3
|
||||
|
||||
units lj
|
||||
atom_style atomic
|
||||
|
||||
lattice fcc 0.8442
|
||||
region box block 0 $x 0 $y 0 $z
|
||||
create_box 1 box
|
||||
create_atoms 1 box
|
||||
mass 1 1.0
|
||||
|
||||
velocity all create 1.44 87287 loop geom
|
||||
|
||||
pair_style lj/cut 2.5
|
||||
pair_coeff 1 1 1.0 1.0 2.5
|
||||
|
||||
neighbor 0.3 bin
|
||||
neigh_modify delay 0 every 20 check no
|
||||
|
||||
fix 1 all nve
|
||||
|
||||
# define Python truncate() function
|
||||
|
||||
variable foo python truncate
|
||||
python truncate return v_foo input 1 iv_arg format fi here """
|
||||
def truncate(x):
|
||||
return int(x)
|
||||
"""
|
||||
|
||||
# use in equal-style variable
|
||||
|
||||
variable scalar equal py_foo(4.5)
|
||||
print "TRUNCATE ${scalar}"
|
||||
|
||||
# use in atom-style variable
|
||||
# examine dump file to see truncated xyz coords of each atom
|
||||
|
||||
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
|
||||
|
||||
# use in vector-style variable
|
||||
|
||||
compute ke all temp
|
||||
variable ke vector c_ke
|
||||
variable ketrunc vector py_foo(v_ke)
|
||||
thermo_style custom step temp epair v_ketrunc[*6]
|
||||
|
||||
run 100
|
||||
|
||||
print "KE TENSOR ${ketrunc}"
|
||||
|
||||
|
||||
116
examples/python/log.1May25.python.wrap.g++.1
Normal file
116
examples/python/log.1May25.python.wrap.g++.1
Normal file
@ -0,0 +1,116 @@
|
||||
LAMMPS (2 Apr 2025 - Development - patch_2Apr2025-270-g2351418c94-modified)
|
||||
# 3d Lennard-Jones melt with equal- and atom-style variables which
|
||||
# use a Python function wrapper in their formulas
|
||||
|
||||
variable x index 3
|
||||
variable y index 3
|
||||
variable z index 3
|
||||
|
||||
units lj
|
||||
atom_style atomic
|
||||
|
||||
lattice fcc 0.8442
|
||||
Lattice spacing in x,y,z = 1.6795962 1.6795962 1.6795962
|
||||
region box block 0 $x 0 $y 0 $z
|
||||
region box block 0 3 0 $y 0 $z
|
||||
region box block 0 3 0 3 0 $z
|
||||
region box block 0 3 0 3 0 3
|
||||
create_box 1 box
|
||||
Created orthogonal box = (0 0 0) to (5.0387886 5.0387886 5.0387886)
|
||||
1 by 1 by 1 MPI processor grid
|
||||
create_atoms 1 box
|
||||
Created 108 atoms
|
||||
using lattice units in orthogonal box = (0 0 0) to (5.0387886 5.0387886 5.0387886)
|
||||
create_atoms CPU = 0.000 seconds
|
||||
mass 1 1.0
|
||||
|
||||
velocity all create 1.44 87287 loop geom
|
||||
|
||||
pair_style lj/cut 2.5
|
||||
pair_coeff 1 1 1.0 1.0 2.5
|
||||
|
||||
neighbor 0.3 bin
|
||||
neigh_modify delay 0 every 20 check no
|
||||
|
||||
fix 1 all nve
|
||||
|
||||
# define Python truncate() function
|
||||
|
||||
variable foo python truncate
|
||||
python truncate return v_foo input 1 iv_arg format fi here """
|
||||
def truncate(x):
|
||||
return int(x)
|
||||
"""
|
||||
|
||||
# use in equal-style variable
|
||||
|
||||
variable scalar equal py_foo(4.5)
|
||||
print "TRUNCATE ${scalar}"
|
||||
TRUNCATE 4
|
||||
|
||||
# use in atom-style variable
|
||||
# examine dump file to see truncated xyz coords of each atom
|
||||
|
||||
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
|
||||
|
||||
# use in vector-style variable
|
||||
|
||||
compute ke all temp
|
||||
variable ke vector c_ke
|
||||
variable ketrunc vector py_foo(v_ke)
|
||||
thermo_style custom step temp epair v_ketrunc[*6]
|
||||
|
||||
run 100
|
||||
Generated 0 of 0 mixed pair_coeff terms from geometric mixing rule
|
||||
Neighbor list info ...
|
||||
update: every = 20 steps, delay = 0 steps, check = no
|
||||
max neighbors/atom: 2000, page size: 100000
|
||||
master list distance cutoff = 2.8
|
||||
ghost atom cutoff = 2.8
|
||||
binsize = 1.4, bins = 4 4 4
|
||||
1 neighbor lists, perpetual/occasional/extra = 1 0 0
|
||||
(1) pair lj/cut, perpetual
|
||||
attributes: half, newton on
|
||||
pair build: half/bin/atomonly/newton
|
||||
stencil: half/bin/3d
|
||||
bin: standard
|
||||
Per MPI rank memory allocation (min/avg/max) = 2.598 | 2.598 | 2.598 Mbytes
|
||||
Step Temp E_pair v_ketrunc[1] v_ketrunc[2] v_ketrunc[3] v_ketrunc[4] v_ketrunc[5] v_ketrunc[6]
|
||||
0 1.44 -6.7733681 155 152 154 -10 -4 -6
|
||||
100 0.82217015 -5.8614684 113 65 84 7 -1 -12
|
||||
Loop time of 0.00278186 on 1 procs for 100 steps with 108 atoms
|
||||
|
||||
Performance: 15529161.573 tau/day, 35947.133 timesteps/s, 3.882 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.0018161 | 0.0018161 | 0.0018161 | 0.0 | 65.29
|
||||
Neigh | 0.00057543 | 0.00057543 | 0.00057543 | 0.0 | 20.68
|
||||
Comm | 0.00019634 | 0.00019634 | 0.00019634 | 0.0 | 7.06
|
||||
Output | 0.00012056 | 0.00012056 | 0.00012056 | 0.0 | 4.33
|
||||
Modify | 4.8221e-05 | 4.8221e-05 | 4.8221e-05 | 0.0 | 1.73
|
||||
Other | | 2.516e-05 | | | 0.90
|
||||
|
||||
Nlocal: 108 ave 108 max 108 min
|
||||
Histogram: 1 0 0 0 0 0 0 0 0 0
|
||||
Nghost: 980 ave 980 max 980 min
|
||||
Histogram: 1 0 0 0 0 0 0 0 0 0
|
||||
Neighs: 4071 ave 4071 max 4071 min
|
||||
Histogram: 1 0 0 0 0 0 0 0 0 0
|
||||
|
||||
Total # of neighbors = 4071
|
||||
Ave neighs/atom = 37.694444
|
||||
Neighbor list builds = 5
|
||||
Dangerous builds not checked
|
||||
|
||||
print "KE TENSOR ${ketrunc}"
|
||||
KE TENSOR [113,65,84,7,-1,-12]
|
||||
|
||||
|
||||
Total wall time: 0:00:00
|
||||
116
examples/python/log.1May25.python.wrap.g++.4
Normal file
116
examples/python/log.1May25.python.wrap.g++.4
Normal file
@ -0,0 +1,116 @@
|
||||
LAMMPS (2 Apr 2025 - Development - patch_2Apr2025-270-g2351418c94-modified)
|
||||
# 3d Lennard-Jones melt with equal- and atom-style variables which
|
||||
# use a Python function wrapper in their formulas
|
||||
|
||||
variable x index 3
|
||||
variable y index 3
|
||||
variable z index 3
|
||||
|
||||
units lj
|
||||
atom_style atomic
|
||||
|
||||
lattice fcc 0.8442
|
||||
Lattice spacing in x,y,z = 1.6795962 1.6795962 1.6795962
|
||||
region box block 0 $x 0 $y 0 $z
|
||||
region box block 0 3 0 $y 0 $z
|
||||
region box block 0 3 0 3 0 $z
|
||||
region box block 0 3 0 3 0 3
|
||||
create_box 1 box
|
||||
Created orthogonal box = (0 0 0) to (5.0387886 5.0387886 5.0387886)
|
||||
1 by 2 by 2 MPI processor grid
|
||||
create_atoms 1 box
|
||||
Created 108 atoms
|
||||
using lattice units in orthogonal box = (0 0 0) to (5.0387886 5.0387886 5.0387886)
|
||||
create_atoms CPU = 0.000 seconds
|
||||
mass 1 1.0
|
||||
|
||||
velocity all create 1.44 87287 loop geom
|
||||
|
||||
pair_style lj/cut 2.5
|
||||
pair_coeff 1 1 1.0 1.0 2.5
|
||||
|
||||
neighbor 0.3 bin
|
||||
neigh_modify delay 0 every 20 check no
|
||||
|
||||
fix 1 all nve
|
||||
|
||||
# define Python truncate() function
|
||||
|
||||
variable foo python truncate
|
||||
python truncate return v_foo input 1 iv_arg format fi here """
|
||||
def truncate(x):
|
||||
return int(x)
|
||||
"""
|
||||
|
||||
# use in equal-style variable
|
||||
|
||||
variable scalar equal py_foo(4.5)
|
||||
print "TRUNCATE ${scalar}"
|
||||
TRUNCATE 4
|
||||
|
||||
# use in atom-style variable
|
||||
# examine dump file to see truncated xyz coords of each atom
|
||||
|
||||
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
|
||||
|
||||
# use in vector-style variable
|
||||
|
||||
compute ke all temp
|
||||
variable ke vector c_ke
|
||||
variable ketrunc vector py_foo(v_ke)
|
||||
thermo_style custom step temp epair v_ketrunc[*6]
|
||||
|
||||
run 100
|
||||
Generated 0 of 0 mixed pair_coeff terms from geometric mixing rule
|
||||
Neighbor list info ...
|
||||
update: every = 20 steps, delay = 0 steps, check = no
|
||||
max neighbors/atom: 2000, page size: 100000
|
||||
master list distance cutoff = 2.8
|
||||
ghost atom cutoff = 2.8
|
||||
binsize = 1.4, bins = 4 4 4
|
||||
1 neighbor lists, perpetual/occasional/extra = 1 0 0
|
||||
(1) pair lj/cut, perpetual
|
||||
attributes: half, newton on
|
||||
pair build: half/bin/atomonly/newton
|
||||
stencil: half/bin/3d
|
||||
bin: standard
|
||||
Per MPI rank memory allocation (min/avg/max) = 2.59 | 2.59 | 2.59 Mbytes
|
||||
Step Temp E_pair v_ketrunc[1] v_ketrunc[2] v_ketrunc[3] v_ketrunc[4] v_ketrunc[5] v_ketrunc[6]
|
||||
0 1.44 -6.7733681 155 152 154 -10 -4 -6
|
||||
100 0.82217015 -5.8614684 113 65 84 7 -1 -12
|
||||
Loop time of 0.00268845 on 4 procs for 100 steps with 108 atoms
|
||||
|
||||
Performance: 16068745.964 tau/day, 37196.171 timesteps/s, 4.017 Matom-step/s
|
||||
66.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.00043389 | 0.00051695 | 0.00061255 | 0.0 | 19.23
|
||||
Neigh | 0.00017121 | 0.00018976 | 0.00019891 | 0.0 | 7.06
|
||||
Comm | 0.0017423 | 0.0018487 | 0.0019509 | 0.2 | 68.76
|
||||
Output | 6.7449e-05 | 6.9998e-05 | 7.5195e-05 | 0.0 | 2.60
|
||||
Modify | 2.1329e-05 | 2.2855e-05 | 2.4821e-05 | 0.0 | 0.85
|
||||
Other | | 4.018e-05 | | | 1.49
|
||||
|
||||
Nlocal: 27 ave 30 max 25 min
|
||||
Histogram: 1 0 1 0 1 0 0 0 0 1
|
||||
Nghost: 614 ave 616 max 612 min
|
||||
Histogram: 1 0 1 0 0 0 0 1 0 1
|
||||
Neighs: 1017.75 ave 1149 max 894 min
|
||||
Histogram: 1 1 0 0 0 0 0 1 0 1
|
||||
|
||||
Total # of neighbors = 4071
|
||||
Ave neighs/atom = 37.694444
|
||||
Neighbor list builds = 5
|
||||
Dangerous builds not checked
|
||||
|
||||
print "KE TENSOR ${ketrunc}"
|
||||
KE TENSOR [113,65,84,7,-1,-12]
|
||||
|
||||
|
||||
Total wall time: 0:00:00
|
||||
@ -17,6 +17,7 @@
|
||||
|
||||
#include "python_impl.h"
|
||||
|
||||
#include "comm.h"
|
||||
#include "error.h"
|
||||
#include "input.h"
|
||||
#include "memory.h"
|
||||
@ -62,6 +63,7 @@
|
||||
using namespace LAMMPS_NS;
|
||||
|
||||
enum { NONE, INT, DOUBLE, STRING, PTR };
|
||||
enum { VALUE, VARIABLE, INTERNALVAR };
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
@ -94,20 +96,27 @@ PythonImpl::PythonImpl(LAMMPS *lmp) : Pointers(lmp)
|
||||
// Inform python intialization scheme of the mliappy module.
|
||||
// This -must- happen before python is initialized.
|
||||
int err = PyImport_AppendInittab("mliap_model_python_couple", PyInit_mliap_model_python_couple);
|
||||
if (err) error->all(FLERR, "Could not register MLIAPPY embedded python module.");
|
||||
if (err)
|
||||
error->all(FLERR, Error::NOLASTLINE, "Could not register MLIAPPY embedded python module.");
|
||||
|
||||
err = PyImport_AppendInittab("mliap_unified_couple", PyInit_mliap_unified_couple);
|
||||
if (err) error->all(FLERR, "Could not register MLIAPPY unified embedded python module.");
|
||||
if (err)
|
||||
error->all(FLERR, Error::NOLASTLINE,
|
||||
"Could not register MLIAPPY unified embedded python module.");
|
||||
|
||||
#ifdef LMP_KOKKOS
|
||||
// Inform python intialization scheme of the mliappy module.
|
||||
// This -must- happen before python is initialized.
|
||||
err = PyImport_AppendInittab("mliap_model_python_couple_kokkos",
|
||||
PyInit_mliap_model_python_couple_kokkos);
|
||||
if (err) error->all(FLERR, "Could not register MLIAPPY embedded python KOKKOS module.");
|
||||
if (err)
|
||||
error->all(FLERR, Error::NOLASTLINE,
|
||||
"Could not register MLIAPPY embedded python KOKKOS module.");
|
||||
|
||||
err = PyImport_AppendInittab("mliap_unified_couple_kokkos", PyInit_mliap_unified_couple_kokkos);
|
||||
if (err) error->all(FLERR, "Could not register MLIAPPY unified embedded python KOKKOS module.");
|
||||
if (err)
|
||||
error->all(FLERR, Error::NOLASTLINE,
|
||||
"Could not register MLIAPPY unified embedded python KOKKOS module.");
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
@ -129,7 +138,7 @@ PythonImpl::PythonImpl(LAMMPS *lmp) : Pointers(lmp)
|
||||
PyUtils::GIL lock;
|
||||
|
||||
PyObject *pModule = PyImport_AddModule("__main__");
|
||||
if (!pModule) error->all(FLERR, "Could not initialize embedded Python");
|
||||
if (!pModule) error->all(FLERR, Error::NOLASTLINE, "Could not initialize embedded Python");
|
||||
|
||||
pyMain = (void *) pModule;
|
||||
}
|
||||
@ -158,23 +167,31 @@ void PythonImpl::command(int narg, char **arg)
|
||||
{
|
||||
if (narg < 2) utils::missing_cmd_args(FLERR, "python", error);
|
||||
|
||||
// if invoke is only keyword, invoke the previously defined function
|
||||
// if invoke keyword is used, invoke the previously defined function
|
||||
|
||||
if (narg == 2 && strcmp(arg[1], "invoke") == 0) {
|
||||
if (strcmp(arg[1], "invoke") == 0) {
|
||||
int ifunc = find(arg[0]);
|
||||
if (ifunc < 0) error->all(FLERR, "Python invoke of unknown function: {}", arg[0]);
|
||||
if (ifunc < 0)
|
||||
error->all(FLERR, Error::ARGZERO, "Python invoke of unknown function: {}", arg[0]);
|
||||
|
||||
char *str = nullptr;
|
||||
if (pfuncs[ifunc].noutput) {
|
||||
str = input->variable->pythonstyle(pfuncs[ifunc].ovarname, pfuncs[ifunc].name);
|
||||
if (!str)
|
||||
error->all(FLERR,
|
||||
"Python variable {} does not match variable {} "
|
||||
"registered with Python function {}",
|
||||
error->all(
|
||||
FLERR, Error::ARGZERO,
|
||||
"Python variable {} does not match variable {} registered with Python function {}",
|
||||
arg[0], pfuncs[ifunc].ovarname, pfuncs[ifunc].name);
|
||||
}
|
||||
|
||||
invoke_function(ifunc, str);
|
||||
bool logreturn = false;
|
||||
if (narg == 3 && strcmp(arg[2], "logreturn") == 0) logreturn = true;
|
||||
|
||||
invoke_function(ifunc, str, nullptr);
|
||||
|
||||
if (logreturn && str && (comm->me == 0))
|
||||
utils::logmesg(lmp, "Invoked python function {} returned {}\n", arg[0], str);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -189,7 +206,7 @@ void PythonImpl::command(int narg, char **arg)
|
||||
if (platform::file_is_readable(arg[1]))
|
||||
err = execute_file(arg[1]);
|
||||
else
|
||||
error->all(FLERR, "Could not open python source file {} for processing", arg[1]);
|
||||
error->all(FLERR, 1, "Could not open python source file {} for processing", arg[1]);
|
||||
}
|
||||
if (err) error->all(FLERR, "Failure in python source command");
|
||||
|
||||
@ -213,7 +230,8 @@ void PythonImpl::command(int narg, char **arg)
|
||||
if (strcmp(arg[iarg], "input") == 0) {
|
||||
if (iarg + 2 > narg) utils::missing_cmd_args(FLERR, "python input", error);
|
||||
ninput = utils::inumeric(FLERR, arg[iarg + 1], false, lmp);
|
||||
if (ninput < 0) error->all(FLERR, "Invalid number of python input arguments: {}", ninput);
|
||||
if (ninput < 0)
|
||||
error->all(FLERR, iarg + 1, "Invalid number of python input arguments: {}", ninput);
|
||||
iarg += 2;
|
||||
delete[] istr;
|
||||
istr = new char *[ninput];
|
||||
@ -232,7 +250,8 @@ void PythonImpl::command(int narg, char **arg)
|
||||
} else if (strcmp(arg[iarg], "length") == 0) {
|
||||
if (iarg + 2 > narg) utils::missing_cmd_args(FLERR, "python length", error);
|
||||
length_longstr = utils::inumeric(FLERR, arg[iarg + 1], false, lmp);
|
||||
if (length_longstr <= 0) error->all(FLERR, "Invalid python return value length");
|
||||
if (length_longstr <= 0)
|
||||
error->all(FLERR, iarg + 1, "Invalid python return value length {}", length_longstr);
|
||||
iarg += 2;
|
||||
} else if (strcmp(arg[iarg], "file") == 0) {
|
||||
if (iarg + 2 > narg) utils::missing_cmd_args(FLERR, "python file", error);
|
||||
@ -247,15 +266,18 @@ void PythonImpl::command(int narg, char **arg)
|
||||
existflag = 1;
|
||||
iarg++;
|
||||
} else
|
||||
error->all(FLERR, "Unknown python command keyword: {}", arg[iarg]);
|
||||
error->all(FLERR, iarg, "Unknown python command keyword: {}", arg[iarg]);
|
||||
}
|
||||
|
||||
if (pyfile && herestr)
|
||||
error->all(FLERR, "Must not use python 'file' and 'here' keywords at the same time");
|
||||
error->all(FLERR, Error::NOLASTLINE,
|
||||
"Must not use python 'file' and 'here' keywords at the same time");
|
||||
if (pyfile && existflag)
|
||||
error->all(FLERR, "Must not use python 'file' and 'exists' keywords at the same time");
|
||||
error->all(FLERR, Error::NOLASTLINE,
|
||||
"Must not use python 'file' and 'exists' keywords at the same time");
|
||||
if (herestr && existflag)
|
||||
error->all(FLERR, "Must not use python 'here' and 'exists' keywords at the same time");
|
||||
error->all(FLERR, Error::NOLASTLINE,
|
||||
"Must not use python 'here' and 'exists' keywords at the same time");
|
||||
|
||||
// create or overwrite entry in pfuncs vector with name = arg[0]
|
||||
|
||||
@ -273,13 +295,13 @@ void PythonImpl::command(int narg, char **arg)
|
||||
|
||||
if (fp == nullptr) {
|
||||
PyUtils::Print_Errors();
|
||||
error->all(FLERR, "Could not open Python file: {}", pyfile);
|
||||
error->all(FLERR, Error::NOLASTLINE, "Could not open Python file: {}", pyfile);
|
||||
}
|
||||
|
||||
int err = PyRun_SimpleFile(fp, pyfile);
|
||||
if (err) {
|
||||
PyUtils::Print_Errors();
|
||||
error->all(FLERR, "Could not process Python file: {}", pyfile);
|
||||
error->all(FLERR, Error::NOLASTLINE, "Could not process Python file: {}", pyfile);
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
@ -287,7 +309,7 @@ void PythonImpl::command(int narg, char **arg)
|
||||
int err = PyRun_SimpleString(herestr);
|
||||
if (err) {
|
||||
PyUtils::Print_Errors();
|
||||
error->all(FLERR, "Could not process Python string: {}", herestr);
|
||||
error->all(FLERR, Error::NOLASTLINE, "Could not process Python string: {}", herestr);
|
||||
}
|
||||
}
|
||||
|
||||
@ -298,12 +320,12 @@ void PythonImpl::command(int narg, char **arg)
|
||||
|
||||
if (!pFunc) {
|
||||
PyUtils::Print_Errors();
|
||||
error->all(FLERR, "Could not find Python function {}", pfuncs[ifunc].name);
|
||||
error->all(FLERR, Error::NOLASTLINE, "Could not find Python function {}", pfuncs[ifunc].name);
|
||||
}
|
||||
|
||||
if (!PyCallable_Check(pFunc)) {
|
||||
PyUtils::Print_Errors();
|
||||
error->all(FLERR, "Python function {} is not callable", pfuncs[ifunc].name);
|
||||
error->all(FLERR, Error::NOLASTLINE, "Python function {} is not callable", pfuncs[ifunc].name);
|
||||
}
|
||||
|
||||
pfuncs[ifunc].pFunc = (void *) pFunc;
|
||||
@ -317,7 +339,7 @@ void PythonImpl::command(int narg, char **arg)
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
void PythonImpl::invoke_function(int ifunc, char *result)
|
||||
void PythonImpl::invoke_function(int ifunc, char *result, double *dvalue)
|
||||
{
|
||||
PyUtils::GIL lock;
|
||||
PyObject *pValue;
|
||||
@ -331,36 +353,46 @@ void PythonImpl::invoke_function(int ifunc, char *result)
|
||||
PyObject *pArgs = PyTuple_New(ninput);
|
||||
|
||||
if (!pArgs)
|
||||
error->all(FLERR, "Could not prepare arguments for Python function {}", pfuncs[ifunc].name);
|
||||
error->all(FLERR, Error::NOLASTLINE, "Could not prepare arguments for Python function {}",
|
||||
pfuncs[ifunc].name);
|
||||
|
||||
for (int i = 0; i < ninput; i++) {
|
||||
int itype = pfuncs[ifunc].itype[i];
|
||||
if (itype == INT) {
|
||||
if (pfuncs[ifunc].ivarflag[i]) {
|
||||
if (pfuncs[ifunc].ivarflag[i] == VARIABLE) {
|
||||
str = input->variable->retrieve(pfuncs[ifunc].svalue[i]);
|
||||
if (!str)
|
||||
error->all(FLERR, "Could not evaluate Python function {} input variable: {}",
|
||||
pfuncs[ifunc].name, pfuncs[ifunc].svalue[i]);
|
||||
error->all(FLERR, Error::NOLASTLINE,
|
||||
"Could not evaluate Python function {} input variable: {}", pfuncs[ifunc].name,
|
||||
pfuncs[ifunc].svalue[i]);
|
||||
pValue = PY_INT_FROM_LONG(PY_LONG_FROM_STRING(str));
|
||||
} else if (pfuncs[ifunc].ivarflag[i] == INTERNALVAR) {
|
||||
double value = input->variable->compute_equal(pfuncs[ifunc].internal_var[i]);
|
||||
pValue = PyLong_FromDouble(value);
|
||||
} else {
|
||||
pValue = PY_INT_FROM_LONG(pfuncs[ifunc].ivalue[i]);
|
||||
}
|
||||
} else if (itype == DOUBLE) {
|
||||
if (pfuncs[ifunc].ivarflag[i]) {
|
||||
if (pfuncs[ifunc].ivarflag[i] == VARIABLE) {
|
||||
str = input->variable->retrieve(pfuncs[ifunc].svalue[i]);
|
||||
if (!str)
|
||||
error->all(FLERR, "Could not evaluate Python function {} input variable: {}",
|
||||
pfuncs[ifunc].name, pfuncs[ifunc].svalue[i]);
|
||||
error->all(FLERR, Error::NOLASTLINE,
|
||||
"Could not evaluate Python function {} input variable: {}", pfuncs[ifunc].name,
|
||||
pfuncs[ifunc].svalue[i]);
|
||||
pValue = PyFloat_FromDouble(std::stod(str));
|
||||
} else if (pfuncs[ifunc].ivarflag[i] == INTERNALVAR) {
|
||||
double value = input->variable->compute_equal(pfuncs[ifunc].internal_var[i]);
|
||||
pValue = PyFloat_FromDouble(value);
|
||||
} else {
|
||||
pValue = PyFloat_FromDouble(pfuncs[ifunc].dvalue[i]);
|
||||
}
|
||||
} else if (itype == STRING) {
|
||||
if (pfuncs[ifunc].ivarflag[i]) {
|
||||
if (pfuncs[ifunc].ivarflag[i] == VARIABLE) {
|
||||
str = input->variable->retrieve(pfuncs[ifunc].svalue[i]);
|
||||
if (!str)
|
||||
error->all(FLERR, "Could not evaluate Python function {} input variable: {}",
|
||||
pfuncs[ifunc].name, pfuncs[ifunc].svalue[i]);
|
||||
error->all(FLERR, Error::NOLASTLINE,
|
||||
"Could not evaluate Python function {} input variable: {}", pfuncs[ifunc].name,
|
||||
pfuncs[ifunc].svalue[i]);
|
||||
pValue = PyUnicode_FromString(str);
|
||||
} else {
|
||||
pValue = PyUnicode_FromString(pfuncs[ifunc].svalue[i]);
|
||||
@ -368,7 +400,7 @@ void PythonImpl::invoke_function(int ifunc, char *result)
|
||||
} else if (itype == PTR) {
|
||||
pValue = PyCapsule_New((void *) lmp, nullptr, nullptr);
|
||||
} else {
|
||||
error->all(FLERR, "Unsupported variable type: {}", itype);
|
||||
error->all(FLERR, Error::NOLASTLINE, "Unsupported variable type: {}", itype);
|
||||
}
|
||||
PyTuple_SetItem(pArgs, i, pValue);
|
||||
}
|
||||
@ -381,29 +413,37 @@ void PythonImpl::invoke_function(int ifunc, char *result)
|
||||
|
||||
if (!pValue) {
|
||||
PyUtils::Print_Errors();
|
||||
error->one(FLERR, "Python evaluation of function {} failed", pfuncs[ifunc].name);
|
||||
error->one(FLERR, Error::NOLASTLINE, "Python evaluation of function {} failed",
|
||||
pfuncs[ifunc].name);
|
||||
}
|
||||
|
||||
// function returned a value
|
||||
// assign it to result string stored by python-style variable
|
||||
// or if user specified a length, assign it to longstr
|
||||
// if result is non-NULL, assign to result string stored by python-style variable
|
||||
// or if value is string and user specified a length, assign it to longstr
|
||||
// if dvalue is non-NULL, assign numeric value directly to dvalue
|
||||
|
||||
if (pfuncs[ifunc].noutput) {
|
||||
int otype = pfuncs[ifunc].otype;
|
||||
if (otype == INT) {
|
||||
if (dvalue) *dvalue = (double) PY_INT_AS_LONG(pValue);
|
||||
if (result) {
|
||||
auto value = fmt::format("{}", PY_INT_AS_LONG(pValue));
|
||||
strncpy(result, value.c_str(), Variable::VALUELENGTH - 1);
|
||||
}
|
||||
} else if (otype == DOUBLE) {
|
||||
if (dvalue) *dvalue = PyFloat_AsDouble(pValue);
|
||||
if (result) {
|
||||
auto value = fmt::format("{:.15g}", PyFloat_AsDouble(pValue));
|
||||
strncpy(result, value.c_str(), Variable::VALUELENGTH - 1);
|
||||
}
|
||||
} else if (otype == STRING) {
|
||||
const char *pystr = PyUnicode_AsUTF8(pValue);
|
||||
if (pfuncs[ifunc].longstr)
|
||||
strncpy(pfuncs[ifunc].longstr, pystr, pfuncs[ifunc].length_longstr);
|
||||
else
|
||||
strncpy(result, pystr, Variable::VALUELENGTH - 1);
|
||||
if (result) strncpy(result, pystr, Variable::VALUELENGTH - 1);
|
||||
}
|
||||
}
|
||||
|
||||
Py_CLEAR(pValue);
|
||||
}
|
||||
|
||||
@ -416,15 +456,80 @@ int PythonImpl::find(const char *name)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* ---------------------------------------------------------------------
|
||||
called by Variable class when a python-style variable is evaluated
|
||||
this will call invoke_function() in this class
|
||||
either via Variable::retrieve() or Variable::equalstyle
|
||||
retrieve calls with numeric = 0, equalstyle with numeric = 1
|
||||
ensure name matches a Python function
|
||||
ensure the Python function produces an output
|
||||
ensure the Python function outputs to the matching python-style variable
|
||||
ensure a string is returned only if retrieve() is the caller
|
||||
--------------------------------------------------------------------- */
|
||||
|
||||
int PythonImpl::variable_match(const char *name, const char *varname, int numeric)
|
||||
int PythonImpl::function_match(const char *name, const char *varname, int numeric, Error *error)
|
||||
{
|
||||
int ifunc = find(name);
|
||||
if (ifunc < 0) return -1;
|
||||
if (pfuncs[ifunc].noutput == 0) return -2;
|
||||
if (strcmp(pfuncs[ifunc].ovarname, varname) != 0) return -3;
|
||||
if (numeric && pfuncs[ifunc].otype == STRING) return -4;
|
||||
|
||||
if (ifunc < 0)
|
||||
error->all(FLERR, Error::NOLASTLINE, "Python function {} specified by variable {} not found",
|
||||
name, varname);
|
||||
if (pfuncs[ifunc].noutput == 0)
|
||||
error->all(FLERR, Error::NOLASTLINE,
|
||||
"Python function {} for variable {} does not return a value", name, varname);
|
||||
if (strcmp(pfuncs[ifunc].ovarname, varname) != 0)
|
||||
error->all(FLERR, Error::NOLASTLINE,
|
||||
"Python function {} and variable {} do not link to each other", name, varname);
|
||||
if (numeric && pfuncs[ifunc].otype == STRING)
|
||||
error->all(FLERR, Error::NOLASTLINE, "Python function {} for variable {} returns a string",
|
||||
name, varname);
|
||||
|
||||
return ifunc;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
called by Variable class when evaluating a Python wrapper function
|
||||
which will call invoke_function()
|
||||
either via equal-style or atom-style variable formula
|
||||
the latter calls invoke_function() once per atom
|
||||
same error checks as function_match() plus 2 new ones
|
||||
ensure match of number of Python function args mapped to internal-style variables
|
||||
ensure each internal-style variable still exists
|
||||
must check now in case user input script deleted variables between runs
|
||||
which could invalidate indices set in create_event()
|
||||
other classes avoid this issue by setting variable indices in their init() method
|
||||
--------------------------------------------------------------------- */
|
||||
|
||||
int PythonImpl::wrapper_match(const char *name, const char *varname, int narg, int *argvars,
|
||||
Error *error)
|
||||
{
|
||||
int ifunc = function_match(name, varname, 1, error);
|
||||
if (ifunc < 0) return ifunc;
|
||||
|
||||
int internal_count = 0;
|
||||
for (int i = 0; i < pfuncs[ifunc].ninput; i++)
|
||||
if (pfuncs[ifunc].ivarflag[i] == INTERNALVAR) internal_count++;
|
||||
if (internal_count != narg)
|
||||
error->all(FLERR, Error::NOLASTLINE,
|
||||
"Python function {} does not use {} internal variable args", name, narg);
|
||||
|
||||
// set argvars of internal-style variables for use by Variable class
|
||||
// in Python wrapper functions
|
||||
// also set internal_var for use by invoke_function()
|
||||
// so that invoke_function() is as fast as possible for args which are internal-style vars
|
||||
|
||||
int j = 0;
|
||||
for (int i = 0; i < pfuncs[ifunc].ninput; i++) {
|
||||
if (pfuncs[ifunc].ivarflag[i] == INTERNALVAR) {
|
||||
int ivar = input->variable->find(pfuncs[ifunc].svalue[i]);
|
||||
if (ivar < 0)
|
||||
error->all(FLERR, Error::NOLASTLINE, "Python function {} cannot find internal variable {}",
|
||||
name, pfuncs[ifunc].svalue[i]);
|
||||
pfuncs[ifunc].internal_var[i] = ivar;
|
||||
argvars[j++] = ivar;
|
||||
}
|
||||
}
|
||||
|
||||
return ifunc;
|
||||
}
|
||||
|
||||
@ -457,9 +562,10 @@ int PythonImpl::create_entry(char *name, int ninput, int noutput, int length_lon
|
||||
pfuncs[ifunc].noutput = noutput;
|
||||
|
||||
if (!format && ninput + noutput)
|
||||
error->all(FLERR, "Missing python format keyword");
|
||||
error->all(FLERR, Error::NOLASTLINE, "Missing python format keyword");
|
||||
else if (format && ((int) strlen(format) != ninput + noutput))
|
||||
error->all(FLERR, "Input/output arguments ({}) and format characters ({}) are inconsistent",
|
||||
error->all(FLERR, Error::NOLASTLINE,
|
||||
"Input/output arguments ({}) and format characters ({}) are inconsistent",
|
||||
(ninput + noutput), strlen(format));
|
||||
|
||||
// process inputs as values or variables
|
||||
@ -469,6 +575,7 @@ int PythonImpl::create_entry(char *name, int ninput, int noutput, int length_lon
|
||||
pfuncs[ifunc].ivalue = new int[ninput];
|
||||
pfuncs[ifunc].dvalue = new double[ninput];
|
||||
pfuncs[ifunc].svalue = new char *[ninput];
|
||||
pfuncs[ifunc].internal_var = new int[ninput];
|
||||
|
||||
for (int i = 0; i < ninput; i++) {
|
||||
pfuncs[ifunc].svalue[i] = nullptr;
|
||||
@ -476,37 +583,64 @@ int PythonImpl::create_entry(char *name, int ninput, int noutput, int length_lon
|
||||
if (type == 'i') {
|
||||
pfuncs[ifunc].itype[i] = INT;
|
||||
if (utils::strmatch(istr[i], "^v_")) {
|
||||
pfuncs[ifunc].ivarflag[i] = 1;
|
||||
pfuncs[ifunc].ivarflag[i] = VARIABLE;
|
||||
pfuncs[ifunc].svalue[i] = utils::strdup(istr[i] + 2);
|
||||
} else if (utils::strmatch(istr[i], "^iv_")) {
|
||||
pfuncs[ifunc].ivarflag[i] = INTERNALVAR;
|
||||
pfuncs[ifunc].svalue[i] = utils::strdup(istr[i] + 3);
|
||||
char *vname = pfuncs[ifunc].svalue[i];
|
||||
int ivar = input->variable->find(vname);
|
||||
if (ivar < 0) { // create internal variable if does not exist
|
||||
input->variable->internal_create(vname, 0.0);
|
||||
ivar = input->variable->find(vname);
|
||||
}
|
||||
if (!input->variable->internalstyle(ivar))
|
||||
error->all(FLERR, Error::NOLASTLINE, "Variable {} for python command is invalid style",
|
||||
vname);
|
||||
} else {
|
||||
pfuncs[ifunc].ivarflag[i] = 0;
|
||||
pfuncs[ifunc].ivarflag[i] = VALUE;
|
||||
pfuncs[ifunc].ivalue[i] = utils::inumeric(FLERR, istr[i], false, lmp);
|
||||
}
|
||||
} else if (type == 'f') {
|
||||
pfuncs[ifunc].itype[i] = DOUBLE;
|
||||
if (utils::strmatch(istr[i], "^v_")) {
|
||||
pfuncs[ifunc].ivarflag[i] = 1;
|
||||
pfuncs[ifunc].ivarflag[i] = VARIABLE;
|
||||
pfuncs[ifunc].svalue[i] = utils::strdup(istr[i] + 2);
|
||||
} else if (utils::strmatch(istr[i], "^iv_")) {
|
||||
pfuncs[ifunc].ivarflag[i] = INTERNALVAR;
|
||||
pfuncs[ifunc].svalue[i] = utils::strdup(istr[i] + 3);
|
||||
char *vname = pfuncs[ifunc].svalue[i];
|
||||
int ivar = input->variable->find(vname);
|
||||
if (ivar < 0) { // create internal variable if does not exist
|
||||
input->variable->internal_create(vname, 0.0);
|
||||
ivar = input->variable->find(vname);
|
||||
}
|
||||
if (!input->variable->internalstyle(ivar))
|
||||
error->all(FLERR, Error::NOLASTLINE, "Variable {} for python command is invalid style",
|
||||
vname);
|
||||
} else {
|
||||
pfuncs[ifunc].ivarflag[i] = 0;
|
||||
pfuncs[ifunc].ivarflag[i] = VALUE;
|
||||
pfuncs[ifunc].dvalue[i] = utils::numeric(FLERR, istr[i], false, lmp);
|
||||
}
|
||||
} else if (type == 's') {
|
||||
pfuncs[ifunc].itype[i] = STRING;
|
||||
if (utils::strmatch(istr[i], "^v_")) {
|
||||
pfuncs[ifunc].ivarflag[i] = 1;
|
||||
pfuncs[ifunc].ivarflag[i] = VARIABLE;
|
||||
pfuncs[ifunc].svalue[i] = utils::strdup(istr[i] + 2);
|
||||
} else if (utils::strmatch(istr[i], "^iv_")) {
|
||||
error->all(FLERR, Error::NOLASTLINE,
|
||||
"Input argument {} cannot be internal variable with string format", istr[i]);
|
||||
} else {
|
||||
pfuncs[ifunc].ivarflag[i] = 0;
|
||||
pfuncs[ifunc].ivarflag[i] = VALUE;
|
||||
pfuncs[ifunc].svalue[i] = utils::strdup(istr[i]);
|
||||
}
|
||||
} else if (type == 'p') {
|
||||
pfuncs[ifunc].ivarflag[i] = 0;
|
||||
pfuncs[ifunc].ivarflag[i] = VALUE;
|
||||
pfuncs[ifunc].itype[i] = PTR;
|
||||
if (strcmp(istr[i], "SELF") != 0) error->all(FLERR, "Invalid python command");
|
||||
|
||||
} else
|
||||
error->all(FLERR, "Invalid python format character: {}", type);
|
||||
error->all(FLERR, Error::NOLASTLINE, "Invalid python format character: {}", type);
|
||||
}
|
||||
|
||||
// process output as value or variable
|
||||
@ -523,17 +657,19 @@ int PythonImpl::create_entry(char *name, int ninput, int noutput, int length_lon
|
||||
else if (type == 's')
|
||||
pfuncs[ifunc].otype = STRING;
|
||||
else
|
||||
error->all(FLERR, "Invalid python return format character: {}", type);
|
||||
error->all(FLERR, Error::NOLASTLINE, "Invalid python return format character: {}", type);
|
||||
|
||||
if (length_longstr) {
|
||||
if (pfuncs[ifunc].otype != STRING)
|
||||
error->all(FLERR, "Python command length keyword cannot be used unless output is a string");
|
||||
error->all(FLERR, Error::NOLASTLINE,
|
||||
"Python command length keyword cannot be used unless output is a string");
|
||||
pfuncs[ifunc].length_longstr = length_longstr;
|
||||
pfuncs[ifunc].longstr = new char[length_longstr + 1];
|
||||
pfuncs[ifunc].longstr[length_longstr] = '\0';
|
||||
}
|
||||
|
||||
if (strstr(ostr, "v_") != ostr) error->all(FLERR, "Invalid python command");
|
||||
if (strstr(ostr, "v_") != ostr)
|
||||
error->all(FLERR, Error::NOLASTLINE, "Invalid python output variable name {}", ostr);
|
||||
pfuncs[ifunc].ovarname = utils::strdup(ostr + 2);
|
||||
|
||||
return ifunc;
|
||||
@ -574,6 +710,7 @@ void PythonImpl::deallocate(int i)
|
||||
delete[] pfuncs[i].dvalue;
|
||||
for (int j = 0; j < pfuncs[i].ninput; j++) delete[] pfuncs[i].svalue[j];
|
||||
delete[] pfuncs[i].svalue;
|
||||
delete[] pfuncs[i].internal_var;
|
||||
delete[] pfuncs[i].ovarname;
|
||||
delete[] pfuncs[i].longstr;
|
||||
}
|
||||
|
||||
@ -25,9 +25,10 @@ class PythonImpl : protected Pointers, public PythonInterface {
|
||||
PythonImpl(class LAMMPS *);
|
||||
~PythonImpl() override;
|
||||
void command(int, char **) override;
|
||||
void invoke_function(int, char *) override;
|
||||
void invoke_function(int, char *, double *) override;
|
||||
int find(const char *) override;
|
||||
int variable_match(const char *, const char *, int) override;
|
||||
int function_match(const char *, const char *, int, Error *) override;
|
||||
int wrapper_match(const char *, const char *, int, int *, Error *) override;
|
||||
char *long_string(int) override;
|
||||
int execute_string(char *) override;
|
||||
int execute_file(char *) override;
|
||||
@ -44,6 +45,7 @@ class PythonImpl : protected Pointers, public PythonInterface {
|
||||
int *ivalue;
|
||||
double *dvalue;
|
||||
char **svalue;
|
||||
int *internal_var; // stores per-arg index of internal variable
|
||||
int otype;
|
||||
char *ovarname;
|
||||
char *longstr;
|
||||
|
||||
@ -3109,7 +3109,7 @@ void FixBondReact::update_everything()
|
||||
update_num_mega++;
|
||||
}
|
||||
MPI_Allreduce(MPI_IN_PLACE, &noccur[0], nreacts, MPI_INT, MPI_SUM, world);
|
||||
reaction_count_total[rxnID] += noccur[rxnID];
|
||||
for (rxnID = 0; rxnID < nreacts; rxnID++) reaction_count_total[rxnID] += noccur[rxnID];
|
||||
} else if (pass == 1) {
|
||||
for (int i = 0; i < global_megasize; i++) {
|
||||
rxnID = (int) global_mega_glove[0][i];
|
||||
|
||||
@ -108,7 +108,10 @@ ComputeAngleLocal::ComputeAngleLocal(LAMMPS *lmp, int narg, char **arg) :
|
||||
|
||||
if (tstr) {
|
||||
tvar = input->variable->find(tstr);
|
||||
if (tvar < 0) error->all(FLERR, "Variable name for compute angle/local does not exist");
|
||||
if (tvar < 0) {
|
||||
input->variable->internal_create(tstr,0.0);
|
||||
tvar = input->variable->find(tstr);
|
||||
}
|
||||
if (!input->variable->internalstyle(tvar))
|
||||
error->all(FLERR, "Variable for compute angle/local is invalid style");
|
||||
}
|
||||
|
||||
@ -154,7 +154,10 @@ ComputeBondLocal::ComputeBondLocal(LAMMPS *lmp, int narg, char **arg) :
|
||||
|
||||
if (dstr) {
|
||||
dvar = input->variable->find(dstr);
|
||||
if (dvar < 0) error->all(FLERR, "Variable name for compute bond/local does not exist");
|
||||
if (dvar < 0) {
|
||||
input->variable->internal_create(dstr,0.0);
|
||||
dvar = input->variable->find(dstr);
|
||||
}
|
||||
if (!input->variable->internalstyle(dvar))
|
||||
error->all(FLERR, "Variable for compute bond/local is invalid style");
|
||||
}
|
||||
|
||||
@ -102,7 +102,10 @@ ComputeDihedralLocal::ComputeDihedralLocal(LAMMPS *lmp, int narg, char **arg) :
|
||||
|
||||
if (pstr) {
|
||||
pvar = input->variable->find(pstr);
|
||||
if (pvar < 0) error->all(FLERR, "Variable name for compute dihedral/local does not exist");
|
||||
if (pvar < 0) {
|
||||
input->variable->internal_create(pstr,0.0);
|
||||
pvar = input->variable->find(pstr);
|
||||
}
|
||||
if (!input->variable->internalstyle(pvar))
|
||||
error->all(FLERR, "Variable for compute dihedral/local is invalid style");
|
||||
}
|
||||
|
||||
@ -390,28 +390,23 @@ void CreateAtoms::command(int narg, char **arg)
|
||||
if (!input->variable->equalstyle(vvar))
|
||||
error->all(FLERR, Error::NOLASTLINE, "Variable {} for create_atoms is invalid style", vstr);
|
||||
|
||||
if (xstr) {
|
||||
xvar = input->variable->find(xstr);
|
||||
if (xvar < 0)
|
||||
error->all(FLERR, Error::NOLASTLINE, "Variable {} for create_atoms does not exist", xstr);
|
||||
if (!input->variable->internalstyle(xvar))
|
||||
error->all(FLERR, Error::NOLASTLINE, "Variable {} for create_atoms is invalid style", xstr);
|
||||
}
|
||||
if (ystr) {
|
||||
yvar = input->variable->find(ystr);
|
||||
if (yvar < 0)
|
||||
error->all(FLERR, Error::NOLASTLINE, "Variable {} for create_atoms does not exist", ystr);
|
||||
if (!input->variable->internalstyle(yvar))
|
||||
error->all(FLERR, Error::NOLASTLINE, "Variable {} for create_atoms is invalid style", ystr);
|
||||
}
|
||||
if (zstr) {
|
||||
zvar = input->variable->find(zstr);
|
||||
if (zvar < 0)
|
||||
error->all(FLERR, Error::NOLASTLINE, "Variable {} for create_atoms does not exist", zstr);
|
||||
if (!input->variable->internalstyle(zvar))
|
||||
error->all(FLERR, Error::NOLASTLINE, "Variable {} for create_atoms is invalid style", zstr);
|
||||
#define SETUP_XYZ_VAR(str,var) \
|
||||
if (str) { \
|
||||
var = input->variable->find(str); \
|
||||
if (var < 0) { \
|
||||
input->variable->internal_create(str, 0.0); \
|
||||
var = input->variable->find(str); \
|
||||
} \
|
||||
if (!input->variable->internalstyle(var)) \
|
||||
error->all(FLERR, Error::NOLASTLINE, \
|
||||
"Variable {} for create_atoms is invalid style", str); \
|
||||
}
|
||||
|
||||
SETUP_XYZ_VAR(xstr, xvar);
|
||||
SETUP_XYZ_VAR(ystr, yvar);
|
||||
SETUP_XYZ_VAR(zstr, zvar);
|
||||
}
|
||||
#undef SETUP_XYZ_VAR
|
||||
|
||||
// require non-none lattice be defined for BOX or REGION styles
|
||||
|
||||
|
||||
@ -868,19 +868,28 @@ void FixDeposit::options(int narg, char **arg)
|
||||
|
||||
if (xstr) {
|
||||
xvar = input->variable->find(xstr);
|
||||
if (xvar < 0) error->all(FLERR, "Variable {} for fix deposit does not exist", xstr);
|
||||
if (xvar < 0) {
|
||||
input->variable->internal_create(xstr,0.0);
|
||||
xvar = input->variable->find(xstr);
|
||||
}
|
||||
if (!input->variable->internalstyle(xvar))
|
||||
error->all(FLERR, "Variable for fix deposit is invalid style");
|
||||
}
|
||||
if (ystr) {
|
||||
yvar = input->variable->find(ystr);
|
||||
if (yvar < 0) error->all(FLERR, "Variable {} for fix deposit does not exist", ystr);
|
||||
if (yvar < 0) {
|
||||
input->variable->internal_create(ystr,0.0);
|
||||
yvar = input->variable->find(ystr);
|
||||
}
|
||||
if (!input->variable->internalstyle(yvar))
|
||||
error->all(FLERR, "Variable for fix deposit is invalid style");
|
||||
}
|
||||
if (zstr) {
|
||||
zvar = input->variable->find(zstr);
|
||||
if (zvar < 0) error->all(FLERR, "Variable {} for fix deposit does not exist", zstr);
|
||||
if (zvar < 0) {
|
||||
input->variable->internal_create(zstr,0.0);
|
||||
zvar = input->variable->find(zstr);
|
||||
}
|
||||
if (!input->variable->internalstyle(zvar))
|
||||
error->all(FLERR, "Variable for fix deposit is invalid style");
|
||||
}
|
||||
|
||||
@ -14,9 +14,8 @@
|
||||
#include "lmppython.h"
|
||||
#if defined(LMP_PYTHON)
|
||||
#include "python_impl.h"
|
||||
#else
|
||||
#include "error.h"
|
||||
#endif
|
||||
#include "error.h"
|
||||
|
||||
using namespace LAMMPS_NS;
|
||||
|
||||
@ -43,7 +42,7 @@ void Python::init()
|
||||
#if defined(LMP_PYTHON)
|
||||
if (!impl) impl = new PythonImpl(lmp);
|
||||
#else
|
||||
error->all(FLERR, "Python support missing! Compile with PYTHON package installed!");
|
||||
error->all(FLERR, Error::NOLASTLINE, "Python support missing! Compile with PYTHON package installed!");
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -67,10 +66,10 @@ void Python::command(int narg, char **arg)
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
void Python::invoke_function(int ifunc, char *result)
|
||||
void Python::invoke_function(int ifunc, char *result, double *dvalue)
|
||||
{
|
||||
init();
|
||||
impl->invoke_function(ifunc, result);
|
||||
impl->invoke_function(ifunc, result, dvalue);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
@ -83,10 +82,19 @@ int Python::find(const char *name)
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
int Python::variable_match(const char *name, const char *varname, int numeric)
|
||||
int Python::function_match(const char *name, const char *varname, int numeric, Error *errptr)
|
||||
{
|
||||
init();
|
||||
return impl->variable_match(name, varname, numeric);
|
||||
return impl->function_match(name, varname, numeric, errptr);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
int Python::wrapper_match(const char *name, const char *varname, int narg, int *argvars,
|
||||
Error *errptr)
|
||||
{
|
||||
init();
|
||||
return impl->wrapper_match(name, varname, narg, argvars, errptr);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
@ -22,9 +22,10 @@ class PythonInterface {
|
||||
public:
|
||||
virtual ~PythonInterface() noexcept(false) {}
|
||||
virtual void command(int, char **) = 0;
|
||||
virtual void invoke_function(int, char *) = 0;
|
||||
virtual void invoke_function(int, char *, double *) = 0;
|
||||
virtual int find(const char *) = 0;
|
||||
virtual int variable_match(const char *, const char *, int) = 0;
|
||||
virtual int function_match(const char *, const char *, int, Error *) = 0;
|
||||
virtual int wrapper_match(const char *, const char *, int, int *, Error *) = 0;
|
||||
virtual char *long_string(int ifunc) = 0;
|
||||
virtual int execute_string(char *) = 0;
|
||||
virtual int execute_file(char *) = 0;
|
||||
@ -37,9 +38,10 @@ class Python : protected Pointers {
|
||||
~Python() override;
|
||||
|
||||
void command(int, char **);
|
||||
void invoke_function(int, char *);
|
||||
void invoke_function(int, char *, double *);
|
||||
int find(const char *);
|
||||
int variable_match(const char *, const char *, int);
|
||||
int function_match(const char *, const char *, int, Error *);
|
||||
int wrapper_match(const char *, const char *, int, int *, Error *);
|
||||
char *long_string(int ifunc);
|
||||
int execute_string(char *);
|
||||
int execute_file(char *);
|
||||
|
||||
176
src/variable.cpp
176
src/variable.cpp
@ -81,6 +81,7 @@ enum{DONE,ADD,SUBTRACT,MULTIPLY,DIVIDE,CARAT,MODULO,UNARY,
|
||||
RAMP,STAGGER,LOGFREQ,LOGFREQ2,LOGFREQ3,STRIDE,STRIDE2,
|
||||
VDISPLACE,SWIGGLE,CWIGGLE,SIGN,GMASK,RMASK,
|
||||
GRMASK,IS_ACTIVE,IS_DEFINED,IS_AVAILABLE,IS_FILE,EXTRACT_SETTING,
|
||||
PYWRAPPER,
|
||||
VALUE,ATOMARRAY,TYPEARRAY,INTARRAY,BIGINTARRAY,VECTORARRAY};
|
||||
|
||||
// customize by adding a special function
|
||||
@ -116,6 +117,7 @@ Variable::Variable(LAMMPS *lmp) : Pointers(lmp)
|
||||
num = nullptr;
|
||||
which = nullptr;
|
||||
pad = nullptr;
|
||||
pyindex = nullptr;
|
||||
reader = nullptr;
|
||||
data = nullptr;
|
||||
dvalue = nullptr;
|
||||
@ -162,6 +164,7 @@ Variable::~Variable()
|
||||
memory->destroy(num);
|
||||
memory->destroy(which);
|
||||
memory->destroy(pad);
|
||||
memory->destroy(pyindex);
|
||||
memory->sfree(reader);
|
||||
memory->sfree(data);
|
||||
memory->sfree(dvalue);
|
||||
@ -594,6 +597,7 @@ void Variable::set(int narg, char **arg)
|
||||
num[nvar] = 2;
|
||||
which[nvar] = 1;
|
||||
pad[nvar] = 0;
|
||||
pyindex[nvar] = -1;
|
||||
data[nvar] = new char *[num[nvar]];
|
||||
data[nvar][0] = utils::strdup(arg[2]);
|
||||
data[nvar][1] = new char[VALUELENGTH];
|
||||
@ -956,13 +960,12 @@ void Variable::python_command(int narg, char **arg)
|
||||
|
||||
int Variable::equalstyle(int ivar)
|
||||
{
|
||||
if (style[ivar] == EQUAL || style[ivar] == TIMER ||
|
||||
style[ivar] == INTERNAL) return 1;
|
||||
if (style[ivar] == EQUAL || style[ivar] == TIMER || style[ivar] == INTERNAL) return 1;
|
||||
if (style[ivar] == PYTHON) {
|
||||
int ifunc = python->variable_match(data[ivar][0],names[ivar],1);
|
||||
if (ifunc < 0) return 0;
|
||||
else return 1;
|
||||
pyindex[ivar] = python->function_match(data[ivar][0], names[ivar], 1, error);
|
||||
if (pyindex[ivar] >= 0) return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -989,7 +992,7 @@ int Variable::vectorstyle(int ivar)
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
check if variable with name is PYTHON and matches funcname
|
||||
check if variable with name is PYTHON style and matches funcname
|
||||
called by Python class before it invokes a Python function
|
||||
return data storage so Python function can return a value for this variable
|
||||
return nullptr if not a match
|
||||
@ -1006,7 +1009,7 @@ char *Variable::pythonstyle(char *name, char *funcname)
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
return 1 if variable is INTERNAL style, 0 if not
|
||||
this is checked before call to set_internal() to assure it can be set
|
||||
this is checked before call to internal_set() to ensure it can be set
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
int Variable::internalstyle(int ivar)
|
||||
@ -1082,23 +1085,8 @@ char *Variable::retrieve(const char *name)
|
||||
str = data[ivar][1] = utils::strdup(result);
|
||||
|
||||
} else if (style[ivar] == PYTHON) {
|
||||
int ifunc = python->variable_match(data[ivar][0],name,0);
|
||||
if (ifunc < 0) {
|
||||
if (ifunc == -1) {
|
||||
error->all(FLERR, "Could not find Python function {} linked to variable {}",
|
||||
data[ivar][0], name);
|
||||
} else if (ifunc == -2) {
|
||||
error->all(FLERR, "Python function {} for variable {} does not have a return value",
|
||||
data[ivar][0], name);
|
||||
} else if (ifunc == -3) {
|
||||
error->all(FLERR,"Python variable {} does not match variable name registered with "
|
||||
"Python function {}", name, data[ivar][0]);
|
||||
} else {
|
||||
error->all(FLERR, "Unknown error verifying function {} linked to python style variable {}",
|
||||
data[ivar][0],name);
|
||||
}
|
||||
}
|
||||
python->invoke_function(ifunc,data[ivar][1]);
|
||||
int ifunc = python->function_match(data[ivar][0],name,0,error);
|
||||
python->invoke_function(ifunc,data[ivar][1],nullptr);
|
||||
str = data[ivar][1];
|
||||
|
||||
// if Python func returns a string longer than VALUELENGTH
|
||||
@ -1157,17 +1145,7 @@ double Variable::compute_equal(int ivar)
|
||||
if (style[ivar] == EQUAL) value = evaluate(data[ivar][0],nullptr,ivar);
|
||||
else if (style[ivar] == TIMER) value = dvalue[ivar];
|
||||
else if (style[ivar] == INTERNAL) value = dvalue[ivar];
|
||||
else if (style[ivar] == PYTHON) {
|
||||
int ifunc = python->find(data[ivar][0]);
|
||||
if (ifunc < 0)
|
||||
print_var_error(FLERR,fmt::format("cannot find python function {}",data[ivar][0]),ivar);
|
||||
python->invoke_function(ifunc,data[ivar][1]);
|
||||
try {
|
||||
value = std::stod(data[ivar][1]);
|
||||
} catch (std::exception &e) {
|
||||
print_var_error(FLERR,"has an invalid value", ivar);
|
||||
}
|
||||
}
|
||||
else if (style[ivar] == PYTHON) python->invoke_function(pyindex[ivar],nullptr,&value);
|
||||
|
||||
// round to zero on underflow
|
||||
if (fabs(value) < std::numeric_limits<double>::min()) value = 0.0;
|
||||
@ -1334,6 +1312,30 @@ void Variable::internal_set(int ivar, double value)
|
||||
dvalue[ivar] = value;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
create an INTERNAL style variable with name, set to value
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
void Variable::internal_create(char *name, double value)
|
||||
{
|
||||
if (find(name) >= 0)
|
||||
error->all(FLERR,"Creation of internal-style variable {} which already exists", name);
|
||||
|
||||
if (nvar == maxvar) grow();
|
||||
style[nvar] = INTERNAL;
|
||||
num[nvar] = 1;
|
||||
which[nvar] = 0;
|
||||
pad[nvar] = 0;
|
||||
data[nvar] = new char *[num[nvar]];
|
||||
data[nvar][0] = new char[VALUELENGTH];
|
||||
dvalue[nvar] = value;
|
||||
|
||||
if (!utils::is_id(name))
|
||||
error->all(FLERR, "Variable name '{}' must have only letters, numbers, or underscores", name);
|
||||
names[nvar] = utils::strdup(name);
|
||||
nvar++;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
remove Nth variable from list and compact list
|
||||
delete reader explicitly if it exists
|
||||
@ -1381,6 +1383,7 @@ void Variable::grow()
|
||||
memory->grow(num,maxvar,"var:num");
|
||||
memory->grow(which,maxvar,"var:which");
|
||||
memory->grow(pad,maxvar,"var:pad");
|
||||
memory->grow(pyindex,maxvar,"var:pyindex");
|
||||
|
||||
reader = (VarReader **)
|
||||
memory->srealloc(reader,maxvar*sizeof(VarReader *),"var:reader");
|
||||
@ -1424,6 +1427,7 @@ void Variable::copy(int narg, char **from, char **to)
|
||||
sin(x),cos(x),tan(x),asin(x),atan2(y,x),...
|
||||
group function = count(group), mass(group), xcm(group,x), ...
|
||||
special function = sum(x),min(x), ...
|
||||
python function wrapper = py_varname(x,y,z,...) (up to MAXFUNCARG)
|
||||
atom value = x[i], y[i], vx[i], ...
|
||||
atom vector = x, y, vx, ...
|
||||
custom atom property = i/d_name, i/d_name[i], i/d2_name[i], i/d2_name[i][j]
|
||||
@ -2361,13 +2365,14 @@ double Variable::evaluate(char *str, Tree **tree, int ivar)
|
||||
}
|
||||
|
||||
// ----------------
|
||||
// math/group/special/labelmap function or atom value/vector or constant or thermo keyword
|
||||
// math/group/region/special/feature function or atom value/vector or constant or thermo keyword
|
||||
// ----------------
|
||||
|
||||
} else {
|
||||
|
||||
// ----------------
|
||||
// math or group or special function
|
||||
// math or group/region or special or feature function
|
||||
// math_function() includes Python function wrapper
|
||||
// ----------------
|
||||
|
||||
if (str[i] == '(') {
|
||||
@ -2625,7 +2630,8 @@ double Variable::evaluate(char *str, Tree **tree, int ivar)
|
||||
atan2(y,x),random(x,y,z),normal(x,y,z),ceil(),floor(),round(),ternary(x,y,z),
|
||||
ramp(x,y),stagger(x,y),logfreq(x,y,z),logfreq2(x,y,z),
|
||||
logfreq3(x,y,z),stride(x,y,z),stride2(x,y,z,a,b,c),vdisplace(x,y),swiggle(x,y,z),
|
||||
cwiggle(x,y,z),sign(x),gmask(x),rmask(x),grmask(x,y)
|
||||
cwiggle(x,y,z),sign(x),py_varname(x,y,z,...),
|
||||
gmask(x),rmask(x),grmask(x,y)
|
||||
---------------------------------------------------------------------- */
|
||||
|
||||
double Variable::collapse_tree(Tree *tree)
|
||||
@ -3183,6 +3189,30 @@ double Variable::collapse_tree(Tree *tree)
|
||||
return tree->value;
|
||||
}
|
||||
|
||||
if (tree->type == PYWRAPPER) {
|
||||
int narg = tree->argcount;
|
||||
int *argvars = tree->argvars;
|
||||
double arg;
|
||||
for (int iarg = 0; iarg < narg; iarg++) {
|
||||
if (iarg == 0) arg = collapse_tree(tree->first);
|
||||
else if (iarg == 1) arg = collapse_tree(tree->second);
|
||||
else arg = collapse_tree(tree->extra[iarg-2]);
|
||||
internal_set(argvars[iarg],arg);
|
||||
}
|
||||
for (int iarg = 0; iarg < narg; iarg++) {
|
||||
if (iarg == 0) {
|
||||
if (tree->first->type != VALUE) return 0.0;
|
||||
} else if (iarg == 1) {
|
||||
if (tree->second->type != VALUE) return 0.0;
|
||||
} else {
|
||||
if (tree->extra[iarg-2]->type != VALUE) return 0.0;
|
||||
}
|
||||
}
|
||||
tree->type = VALUE;
|
||||
tree->value = compute_equal(tree->pyvar);
|
||||
return tree->value;
|
||||
}
|
||||
|
||||
// mask functions do not become a single collapsed value
|
||||
|
||||
if (tree->type == GMASK) return 0.0;
|
||||
@ -3196,12 +3226,14 @@ double Variable::collapse_tree(Tree *tree)
|
||||
evaluate an atom-style or vector-style variable parse tree
|
||||
index I = atom I or vector index I
|
||||
tree was created by one-time parsing of formula string via evaluate()
|
||||
followed by collapse_tree() operation to streamline tree as much as possible
|
||||
customize by adding a function:
|
||||
sqrt(),exp(),ln(),log(),sin(),cos(),tan(),asin(),acos(),atan(),
|
||||
atan2(y,x),random(x,y,z),normal(x,y,z),ceil(),floor(),round(),ternary(x,y,z),
|
||||
ramp(x,y),stagger(x,y),logfreq(x,y,z),logfreq2(x,y,z),
|
||||
logfreq3(x,y,z),stride(x,y,z),stride2(x,y,z,a,b,c),vdisplace(x,y),
|
||||
swiggle(x,y,z),cwiggle(x,y,z),sign(x),gmask(x),rmask(x),grmask(x,y)
|
||||
swiggle(x,y,z),cwiggle(x,y,z),sign(x),py_varname(x,y,z,...),
|
||||
gmask(x),rmask(x),grmask(x,y)
|
||||
---------------------------------------------------------------------- */
|
||||
|
||||
double Variable::eval_tree(Tree *tree, int i)
|
||||
@ -3520,6 +3552,18 @@ double Variable::eval_tree(Tree *tree, int i)
|
||||
if (tree->type == SIGN)
|
||||
return (eval_tree(tree->first,i) >= 0.0) ? 1.0 : -1.0; // sign(eval_tree(tree->first,i));
|
||||
|
||||
if (tree->type == PYWRAPPER) {
|
||||
int narg = tree->argcount;
|
||||
for (int iarg = 0; iarg < narg; iarg++) {
|
||||
if (iarg == 0) arg = eval_tree(tree->first,i);
|
||||
else if (iarg == 1) arg = eval_tree(tree->second,i);
|
||||
else arg = eval_tree(tree->extra[iarg-2],i);
|
||||
internal_set(tree->argvars[iarg],arg);
|
||||
}
|
||||
arg = compute_equal(tree->pyvar);
|
||||
return arg;
|
||||
}
|
||||
|
||||
if (tree->type == GMASK) {
|
||||
if (atom->mask[i] & tree->ivalue) return 1.0;
|
||||
else return 0.0;
|
||||
@ -3583,6 +3627,7 @@ void Variable::free_tree(Tree *tree)
|
||||
for (int i = 0; i < tree->nextra; i++) free_tree(tree->extra[i]);
|
||||
delete[] tree->extra;
|
||||
}
|
||||
if (tree->argvars) delete[] tree->argvars;
|
||||
|
||||
if (tree->selfalloc) memory->destroy(tree->array);
|
||||
delete tree;
|
||||
@ -3685,7 +3730,7 @@ tagint Variable::int_between_brackets(char *&ptr, int varallow)
|
||||
/* ----------------------------------------------------------------------
|
||||
process a math function in formula
|
||||
push result onto tree or arg stack
|
||||
word = math function
|
||||
word = math function name
|
||||
contents = str between parentheses with comma-separated args
|
||||
return 0 if not a match, 1 if successfully processed
|
||||
customize by adding a math function:
|
||||
@ -3693,7 +3738,7 @@ tagint Variable::int_between_brackets(char *&ptr, int varallow)
|
||||
atan2(y,x),random(x,y,z),normal(x,y,z),ceil(),floor(),round(),ternary(),
|
||||
ramp(x,y),stagger(x,y),logfreq(x,y,z),logfreq2(x,y,z),
|
||||
logfreq3(x,y,z),stride(x,y,z),stride2(x,y,z,a,b,c),vdisplace(x,y),
|
||||
swiggle(x,y,z),cwiggle(x,y,z),sign(x)
|
||||
swiggle(x,y,z),cwiggle(x,y,z),sign(x),py_varname(x,y,z,...)
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
int Variable::math_function(char *word, char *contents, Tree **tree, Tree **treestack,
|
||||
@ -3711,7 +3756,8 @@ int Variable::math_function(char *word, char *contents, Tree **tree, Tree **tree
|
||||
strcmp(word,"logfreq") != 0 && strcmp(word,"logfreq2") != 0 &&
|
||||
strcmp(word,"logfreq3") != 0 && strcmp(word,"stride") != 0 &&
|
||||
strcmp(word,"stride2") != 0 && strcmp(word,"vdisplace") != 0 &&
|
||||
strcmp(word,"swiggle") != 0 && strcmp(word,"cwiggle") != 0 && strcmp(word,"sign") != 0)
|
||||
strcmp(word,"swiggle") != 0 && strcmp(word,"cwiggle") != 0 && strcmp(word,"sign") != 0 &&
|
||||
strstr(word,"py_") != word)
|
||||
return 0;
|
||||
|
||||
// parse contents for comma-separated args
|
||||
@ -4106,11 +4152,51 @@ int Variable::math_function(char *word, char *contents, Tree **tree, Tree **tree
|
||||
double value = value1 + value2*(1.0-cos(omega*delta*update->dt));
|
||||
argstack[nargstack++] = value;
|
||||
}
|
||||
|
||||
} else if (strcmp(word,"sign") == 0) {
|
||||
if (narg != 1)
|
||||
print_var_error(FLERR,"Invalid math function in variable formula",ivar);
|
||||
if (tree) newtree->type = SIGN;
|
||||
else argstack[nargstack++] = (value1 >= 0.0) ? 1.0 : -1.0; // sign(value1);
|
||||
|
||||
// Python wrapper function tied to python-style variable
|
||||
// text following py_ = python-style variable name tied to Python function
|
||||
// narg arguments are tied to internal variables defined by python command
|
||||
|
||||
} else if (strstr(word,"py_") == word) {
|
||||
|
||||
// pyvar = index of python-style variable which invokes Python function
|
||||
|
||||
int pyvar = find(&word[3]);
|
||||
if (style[pyvar] != PYTHON)
|
||||
print_var_error(FLERR,"Invalid python function variable name",ivar);
|
||||
|
||||
// check that wrapper matches Python function
|
||||
// jvars = returned indices of narg internal variables used by Python function
|
||||
|
||||
int *jvars = new int[narg];
|
||||
pyindex[pyvar] = python->wrapper_match(data[pyvar][0],names[pyvar],narg,jvars,error);
|
||||
|
||||
// if tree: store python variable and arg info in tree for later eval
|
||||
// else: one-time eval of python-coded function now via python variable
|
||||
|
||||
if (tree) {
|
||||
newtree->type = PYWRAPPER;
|
||||
newtree->pyvar = pyvar;
|
||||
newtree->argcount = narg;
|
||||
newtree->argvars = new int[narg];
|
||||
for (int iarg = 0; iarg < narg; iarg++)
|
||||
newtree->argvars[iarg] = jvars[iarg];
|
||||
} else {
|
||||
for (int iarg = 0; iarg < narg; iarg++) {
|
||||
if (iarg == 0) internal_set(jvars[iarg],value1);
|
||||
else if (iarg == 1) internal_set(jvars[iarg],value2);
|
||||
else internal_set(jvars[iarg],values[iarg-2]);
|
||||
}
|
||||
argstack[nargstack++] = compute_equal(pyvar);
|
||||
}
|
||||
|
||||
delete[] jvars;
|
||||
}
|
||||
|
||||
// delete stored args
|
||||
@ -4377,7 +4463,7 @@ Region *Variable::region_function(char *id, int ivar)
|
||||
customize by adding a special function:
|
||||
sum(x),min(x),max(x),ave(x),trap(x),slope(x),
|
||||
gmask(x),rmask(x),grmask(x,y),next(x),is_file(x),is_os(x),
|
||||
extract_setting(x),label2type(x,y),is_tpelabel(x,y)
|
||||
extract_setting(x),label2type(x,y),is_typelabel(x,y)
|
||||
is_timeout()
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
@ -5296,7 +5382,11 @@ void Variable::print_var_error(const std::string &srcfile, const int lineno,
|
||||
|
||||
void Variable::print_tree(Tree *tree, int level)
|
||||
{
|
||||
if (tree->type == VALUE) {
|
||||
printf("TREE %d: %d %g\n",level,tree->type,tree->value);
|
||||
return;
|
||||
}
|
||||
printf("TREE %d: %d\n",level,tree->type);
|
||||
if (tree->first) print_tree(tree->first,level+1);
|
||||
if (tree->second) print_tree(tree->second,level+1);
|
||||
if (tree->nextra)
|
||||
|
||||
@ -49,6 +49,7 @@ class Variable : protected Pointers {
|
||||
void compute_atom(int, int, double *, int, int);
|
||||
int compute_vector(int, double **);
|
||||
void internal_set(int, double);
|
||||
void internal_create(char *, double);
|
||||
|
||||
tagint int_between_brackets(char *&, int);
|
||||
double evaluate_boolean(char *);
|
||||
@ -87,6 +88,7 @@ class Variable : protected Pointers {
|
||||
int *num; // # of values for each variable
|
||||
int *which; // next available value for each variable
|
||||
int *pad; // 1 = pad loop/uloop variables with 0s, 0 = no pad
|
||||
int *pyindex; // indices to Python funcs for python-style vars
|
||||
class VarReader **reader; // variable that reads from file
|
||||
char ***data; // str value of each variable's values
|
||||
double *dvalue; // single numeric value for internal variables
|
||||
@ -123,9 +125,13 @@ class Variable : protected Pointers {
|
||||
Tree *first, *second; // ptrs further down tree for first 2 args
|
||||
Tree **extra; // ptrs further down tree for nextra args
|
||||
|
||||
int pyvar; // index of Python variable invoked as py_name()
|
||||
int argcount; // # of args to associated Python function
|
||||
int *argvars; // indices of internal variables for each arg
|
||||
|
||||
Tree() :
|
||||
array(nullptr), iarray(nullptr), barray(nullptr), selfalloc(0), ivalue(0), nextra(0),
|
||||
region(nullptr), first(nullptr), second(nullptr), extra(nullptr)
|
||||
region(nullptr), first(nullptr), second(nullptr), extra(nullptr), argvars(nullptr)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
@ -85,7 +85,7 @@ void WriteDump::command(int narg, char **arg)
|
||||
if (strcmp(arg[1], "image") == 0) (dynamic_cast<DumpImage *>(dump))->multifile_override = 1;
|
||||
if (strcmp(arg[1], "cfg") == 0) (dynamic_cast<DumpCFG *>(dump))->multifile_override = 1;
|
||||
if ((update->first_update == 0) && (comm->me == 0) && (noinitwarn == 0))
|
||||
error->warning(FLERR, "Calling write_dump before a full system init.");
|
||||
error->warning(FLERR, "Calling write_dump before a full system init");
|
||||
|
||||
dump->init();
|
||||
dump->write();
|
||||
|
||||
Reference in New Issue
Block a user