.. _particles.modifiers.python_script:

Python script |ovito-pro|
-------------------------

.. image:: /images/modifiers/python_script_panel.png
  :width: 30%
  :align: right

This :ref:`modifier <particles.modifiers>` type lets you write your own user-defined modifier function in the Python language. Your Python function runs within the graphical user interface 
just like a normal OVITO modifier and can manipulate, analyze or amend the simulation data in exactly the way you need it.
Such user-defined modifier functions are useful whenever the standard tool set of :ref:`built-in modifiers <particles.modifiers>` of OVITO is insufficient 
to solve your specific problem.

What is a Python script modifier?
"""""""""""""""""""""""""""""""""

.. highlight:: python

A script modifier consists of the definition of a Python function, which you enter into the integrated code editor window 
of OVITO Pro. For instance::

  def modify(frame, data):
      print("Number of particles:", data.particles.count)
      data.attributes['Time'] = 0.002 * frame

This function prints the current number of particles to the log window and generates a new dynamic :ref:`attribute <usage.global_attributes>` named ``Time`` by computing its value based on the current
animation frame number. OVITO takes care of executing your Python function at the right times, e.g.,
whenever you drag the animation time slider and the results of the :ref:`data pipeline <usage.modification_pipeline>` must be recomputed.
Note that you only define an isolated Python *function* and not an entire *program*. OVITO is responsible for calling your user-defined function whenever it needs to.

Your modifier function receives the current dataset, generated by the upstream data pipeline, as input argument ``data``. 
You can then implement your own data processing algorithms in the Python function, which operate on the provided input data. 
Use OVITO's comprehensive :ref:`Python API <scripting_manual>` to access different parts of the dataset or dynamically add new data objects to it, 
which will then be visible in OVITO's interactive viewports. 

Usage
"""""

.. image:: /images/modifiers/python_script_code_editor.png
  :width: 50%
  :align: right

After inserting a new Python script modifier into the pipeline you can open the integrated code editor using the
:guilabel:`Edit script` button. The editor window lets you change the source code for the user-defined modifier function,
which initially consists of a few example statements. You should replace these statements with your own code, performing the 
computations or actions that are needed to solve your specific problem. 
See the :ref:`OVITO Scripting Reference <writing_custom_modifiers>` for further instructions on how to write user-defined modifier functions. 
Note that the Python function, which gets called by OVITO's data pipeline system, must be named ``modify()`` and have the signature shown in the example above. 
However, you are free to define additional helper functions in the same source file and invoke them as sub-routines from your main modifier function.

Once you are done writing the user-defined modifier function, press the *Commit and run script* button (the "play" icon)
in the code editor's toolbar. This will compile the code once by executing any top-level Python statements 
(this includes the function definition itself) and then request an update of the data pipeline. As part of this pipeline update, 
your ``modify()`` function will get invoked by the system.

Note that the pipeline system will typically run your ``modify()`` function repeatedly, 
for example when stepping through a simulation trajectory. That means you should always write your ``modify()`` function
in such a way that it doesn't produce any side effects on the global state of OVITO. The function should be "pure" and stateless in the sense 
that it only operates on the current data collection it receives from the system as a function parameter.
The pipeline system is free to decide whether it caches the results of your modifier function, and it may call your function 
repeatedly if necessary. In other words, you should design the function in such a way that it can process each trajectory frame in isolation. 

Making the modifier function permanently available in OVITO
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

First, you should give your modifier a meaningful name, making it easier for you to identify the modifier 
in the data pipeline. The :ref:`pipeline editor <usage.modification_pipeline.pipeline_listbox>` of
OVITO lets you to change the title of the modifier from the default label "Python script" to a more descriptive name 
that better summarizes the specific purpose of your Python function. In order to rename a modifier in the pipeline editor, make sure 
it is selected and then click the item a second time to edit its name. 

Next, you have two alternative ways of making your Python modifier permanently available in future program
sessions. One is to save the entire modifier, including the definition of the ``modify()`` function, as a :ref:`modifier template <modifier_templates>`. 
The modifier template will appear as a new entry in the list of available modifiers, allowing you to easily access the user-defined modifier and 
insert it into other data pipelines in the future.

The second option is to save just the Python code as a :file:`.py` file into one of the following directories on your computer. 
OVITO Pro automatically scans these directories at program startup and displays all :file:`.py` scripts in the list of available modifiers, 
from where you can inserted them into a pipeline with a single click.

  * All platforms: :file:`<HOME>/.config/Ovito/scripts/modifiers/*.py`
  * Linux: :file:`<INSTALLDIR>/share/ovito/scripts/modifiers/*.py`
  * Windows: :file:`<INSTALLDIR>/scripts/modifiers/*.py`
  * macOS: :file:`<INSTALLDIR>/Ovito.app/Contents/Resources/scripts/modifiers/*.py`
  * Anaconda: :file:`<INSTALLDIR>/share/ovito/scripts/modifiers/*.py`

In these paths, :file:`<HOME>` and :file:`<INSTALLDIR>` refer to your home directory and the installation location of OVITO Pro on your computer, 
respectively. The latter location already contains a bunch of predefined Python modifier files shipping with the program.

Examples
""""""""

The scripting manual contains several :ref:`code examples <modifier_script_examples>`  
demonstrating how to write a ``modify()`` function:

  * :ref:`example_msd_calculation`
  * :ref:`example_order_parameter_calculation`
  * :ref:`example_visualize_local_lattice_orientation`
  * :ref:`example_select_overlapping_particles`

.. seealso::

  :py:class:`ovito.modifiers.PythonScriptModifier` (Python API)
