==================================
Advanced topics
==================================

This section covers several advanced topics related to OVITO's scripting interface:

   * :ref:`saving_loading_pipelines`
   * :ref:`multithreading_settings`

.. _saving_loading_pipelines:

----------------------------------
Saving and loading pipelines
----------------------------------

The :py:func:`ovito.io.export_file` function lets you to save the computed output of a pipeline to disk. But how do
you save the definition of the pipeline itself, including the modifiers and their parameters, to a file? OVITO can
save the entire *scene* to a :file:`.ovito` state file using the :py:meth:`Scene.save() <ovito.Scene.save>` method.
Thus, in order to save a :py:class:`~ovito.pipeline.Pipeline` you need to first make it part of the scene by calling 
its :py:meth:`~ovito.pipeline.Pipeline.add_to_scene` method:

.. literalinclude:: ../example_snippets/saving_pipeline.py
   :lines: -9

The saved state can be restored by calling the :py:meth:`Scene.load() <ovito.Scene.load>` method. This function loads all 
saved data pipelines and makes them available in the :py:attr:`Scene.pipelines <ovito.Scene.pipelines>` list:

.. literalinclude:: ../example_snippets/saving_pipeline.py
   :lines: 13-17

Of course, it is also possible to open the .ovito state file with the graphical OVITO application, or, conversely, to use the graphical
application to create a data pipeline by hand and then save that pipeline to a .ovito file for future use. 

You can either load the state file from a script at runtime using the :py:meth:`Scene.load() <ovito.Scene.load>` method
or :py:ref:`preload the state file <preloading_program_state>` when running the script using the :program:`ovitos` interpreter.
This is done by specifying the :command:`-o` command line option:

.. code-block:: shell-session

	ovitos -o mypipeline.ovito script.py

The code in :file:`script.py` will now be executed in an environment where the :py:class:`~ovito.Scene` was already populated
with the state loaded from the .ovito scene file. Instead of setting up a new pipeline from scratch, the script can now
work with the existing pipeline(s) that were restored from the state file:

.. literalinclude:: ../example_snippets/saving_pipeline.py
   :lines: 22-

.. _multithreading_settings:

----------------------------------------------
Specifying the number of processor cores
----------------------------------------------

Some computation functions of OVITO have been parallelized in order to make use
of all available processor cores. This includes, for example, computationally expensive modifiers such as 
:py:class:`~ovito.modifiers.PolyhedralTemplateMatchingModifier`, :py:class:`~ovito.modifiers.ClusterAnalysisModifier` 
or :py:class:`~ovito.modifiers.ComputePropertyModifier`, and the software-based rendering engines 
:py:class:`~ovito.vis.TachyonRenderer` and :py:class:`~ovito.vis.OSPRayRenderer`. 

By default, these parallelized algorithms will make use of all available cores of your CPU. This default number is determined by OVITO
using the function `QThread.idealThreadCount() <https://doc.qt.io/qtforpython-5/PySide2/QtCore/QThread.html#PySide2.QtCore.PySide2.QtCore.QThread.idealThreadCount>`_,
which can be queried as follows::

  >>> from PySide2.QtCore import QThread
  >>> print(QThread.idealThreadCount())
  4

Sometimes it is desirable to restrict OVITO to a single CPU core only, for example when running multiple instances
of OVITO in parallel. This can be achieved in two ways. The graphical application :program:`ovito` and the :ref:`script interpreter <ovitos_interpreter>` :program:`ovitos` both support the :ref:`command line parameter <ovitos_nthreads_parameter>`
:command:`--nthreads`, which allows overriding the number of CPU cores used by parallel algorithms:

.. code-block:: shell

   ovitos --nthreads 1 script.py

The second option is to set the ``OVITO_THREAD_COUNT`` environment variable prior to invoking or importing OVITO. This approach 
always works: for the GUI application, the script interpreter :program:`ovitos`, but also for scripts running in an external 
Python interpreter that imports the ``ovito`` module:

.. code-block:: shell
  
   export OVITO_THREAD_COUNT=1
   python script.py
