==================================
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 output data computed by a pipeline to disk. But how do
you save the definition of the pipeline itself, including all the modifiers, to a file? The current version of OVITO can
save the entire *scene* to a .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 using its :py:meth:`~ovito.pipeline.Pipeline.add_to_scene`
method:

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

Unfortunately, there currently exists no corresponding Python function for loading a scene back into memory from a .ovito state file.
The only way to restore the scene state is to :py:ref:`preload the .ovito file <preloading_program_state>` when executing a batch script.
This is done by using the :command:`-o` command line option of the :program:`ovitos` script interpreter:

.. code-block:: shell-session

	ovitos -o mypipeline.ovito script.py

The code in :file:`script.py` will now be executed in a context where the :py:class:`~ovito.Scene` was already initialized
with the state loaded from the .ovito scene file. Instead of setting up a completely new pipeline, the script can therefore
work with the existing pipeline that was restored from the state file:

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

.. _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/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
