Getting Started
===============
Welcome to the first tutorial of the dynsight platform.
Before start, we strongly suggest to read the `dynsight workflow page <../workflow.html>`_ where the typical
workflow of a typical ``dynsight`` usage is described. Briefly, the reccomended way to use ``dynsight`` is via loading a trajectory into a :class:`.trajectory.Trj`
object, and then using the methods of this class to compute the desired descriptors and/or analyses.
In this tutorial, we will show you a minimal example of a ``dynsight`` analysis workflow;
starting from loading a trajectory, computing a descriptor and finishing
with clustering analysis.
At the end of this tutorial, you will find links to download the full ``python`` scripts
and its relevant input files.
1. Loading a trajectory
-----------------------
The ``dynsight.trajectory`` module provides a unified set of tools that
streamline the analysis of many-body trajectories, offering a consistent and
user-friendly interface across most analysis tasks.
This is achieved through the class, :class:`.trajectory.Trj`, which corresponds to an
object that contains a trajectory, meaning the coordinates of a set of particles over a series of frames.
The first step is usually to create a :class:`.trajectory.Trj` object from
some trajectory file (e.g., `.xtc` and `.gro` files for GROMACS simulation output). In this example, we are using the water/ice
coexistence trajectory, which can be downloaded here:
.. image:: ../_static/tutorials/getting_started/wat_ice.png
:scale: 50%
:align: center
.. raw:: html
⬇️ Download the .gro file
⬇️ Download the .xtc file
We now can load the trajectory using the :class:`.trajectory.Trj.init_from_xtc()` method. All file operations
(checking existence, opening, saving, defining a path) are done using the `pathlib `_ library.
.. testcode:: getting_started_test
from pathlib import Path
from dynsight.trajectory import Trj
files_path = Path("source/_static/simulations")
trj = Trj.init_from_xtc(
traj_file=files_path / "ice_water_ox.xtc",
topo_file=files_path / "ice_water_ox.gro",
)
.. testcode:: getting_started_test
:hide:
assert trj.n_atoms == 2048
assert trj.n_frames == 1001
Other methods to load trajectories are listed `here <../_autosummary/dynsight.trajectory.Trj.html>`__ and can be simply
replaced with your format (If you need another format, please submit an issue `here `__).
2. Computing a descriptor (the LENS case)
-----------------------------------------
Now the ``trj`` variable contains the trajectory, and using the methods of the
:class:`.trajectory.Trj` class we can perform all the dynsight analyses on
this trajectory. For instance, let's say we want to compute the LENS
descriptor (`Crippa et al. `__).
This can be easily done using the :class:`.trajectory.Trj.get_lens()` method after the trajectory loading:
.. code-block:: python
# Adjust n_jobs according to your computer capabilities
lens = trj.get_lens(
r_cut=10,
n_jobs=4
)
.. important::
The units for the ``r_cut`` parameter are the same as those used in the trajectory (In this case Angstroms).
The method :class:`.trajectory.Trj.get_lens()` returns a
:class:`.trajectory.Insight` object (``lens``), which in its ``.dataset`` attribute
contains the LENS values computed on the ``trj`` trajectory. Moreover, its
``.meta`` attribute stores all the parameters relevant to this descriptor
computation, in this case:
.. code-block:: python
print(lens.meta)
outputs:
.. code-block:: bash
{'name': 'lens', 'r_cut': 10, 'delay': 1, 'centers': 'all', 'selection': 'all'}
3. Clustering analysis using Onion Clustering
----------------------------------------------
The :class:`.trajectory.Insight` objects can directly be used to perform post-processing such as smoothing (see the other `tutorials pages <../tutorials_menu.html>`_).
But they can also be used to perform clustering analysis. In this example, we will show how to use the
``Onion Clustering`` method (`Becchi et al. `__) to cluster the LENS values computed above.
We can perform clustering on the ``lens`` object, using for
instance the :class:`Insight.get_onion_smooth()` method with a time window of 10 frames:
.. code-block:: python
lens_onion = lens.get_onion_smooth(delta_t=10)
``lens_onion`` is a :class:`.trajectory.OnionSmoothInsight` object,
which stores the clustering output (similarly to a normal ``Insight`` object), and offers several methods to visualize
the results. Here we show some examples of visualization:
.. code-block:: python
lens_onion.plot_output(
file_path=files_path / "output_plot.png",
data_insight=lens,
)
lens_onion.plot_one_trj(
file_path=files_path / "single_trj.png",
data_insight=lens,
particle_id=1234,
)
The output plot:
.. image:: ../_static/tutorials/getting_started/output_plot.png
:scale: 13%
:align: center
The single particle trajectory plot:
.. image:: ../_static/tutorials/getting_started/single_trj.png
:scale: 15%
:align: center
It is also possible to save a copy of the trajectory where each particle is labeled
according to its cluster assignment, using the ``dump_colored_trj()`` method. Notice that,
differently from other descriptors, which are computed for every frame, LENS
is computed for every pair of frames. Thus, the LENS dataset has shape
``(n_particles, n_frames - 1)``. Consequently, if you need to match the LENS
values with the particles along the trajectory, you will need to use a sliced
trajectory (removing the last frame). The easiest way to do this is:
.. testcode:: getting_started_test
trajslice = slice(0, -1, 1)
sliced_trj = trj.with_slice(trajslice=trajslice)
.. testcode:: getting_started_test
:hide:
assert isinstance(sliced_trj, Trj)
assert sliced_trj.n_atoms == 2048
assert sliced_trj.n_frames == trj.n_frames - 1
Then we can dump the colored trajectory:
.. code-block:: python
lens_onion.dump_colored_trj(
trj=sliced_trj,
file_path=files_path / "colored_trj.xyz",
)
This allows to create visualizations of the clustering results using external software such as VMD or Ovito:
.. image:: ../_static/tutorials/getting_started/colored_wat_ice_lens_10.png
:scale: 45%
:align: center
Full scripts and input files
----------------------------
.. raw:: html
⬇️ Download the .gro file
⬇️ Download the .xtc file
⬇️ Download Python Script
.. testcode:: getting_started_test
:hide:
import numpy as np
from dynsight.trajectory import OnionSmoothInsight
trj_test = trj.with_slice(slice(0, 4, 1))
expected_tests = Path("source/_static/tutorials/getting_started/doctests")
lens_test = trj_test.get_lens(r_cut=10, n_jobs=1)
reference_lens = np.load(expected_tests / "test_lens.npy")
assert np.allclose(lens_test.dataset, reference_lens, atol=1e-6)
lens_onion = lens_test.get_onion_smooth(delta_t=10)
assert isinstance(lens_onion, OnionSmoothInsight)