Skip to content

Commit 264df84

Browse files
Add batching and parallelization documentation (#67)
1 parent 7310196 commit 264df84

5 files changed

Lines changed: 176 additions & 2 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ The rules for this file:
3333
- Added batching and parallel support for com distance widget (PR #64)
3434
- Minor widget enhancements (PR #65)
3535
- Added custom widgets documentation (PR #66)
36+
- Added batching and parallelization documentation (PR #67)
3637

3738
### Fixed
3839

docs/source/adding_custom_widgets.rst

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ These available run methods are:
8484
A Widget can make the ``_run_frequency`` and ``_run_mode`` attributes dynamically
8585
changeable at runtime as well by making them as `Inputs`_.
8686

87+
.. _run-frequency:
88+
8789
_run_frequency
8890
~~~~~~~~~~~~~~
8991

@@ -108,6 +110,8 @@ If the ``_run_mode`` is ``serial``:
108110
* and ``_run_frequency`` is ``batch``,
109111
:meth:`~mdadash.backend.widgets.base.WidgetBase.run_batch` method is invoked.
110112

113+
.. _run-mode:
114+
111115
_run_mode
112116
~~~~~~~~~
113117

@@ -117,7 +121,7 @@ If the ``_run_mode`` is ``parallel`` for a given widget instance, a
117121
:meth:`~mdadash.backend.widgets.base.WidgetBase.get_parallel_job` method is invoked to
118122
retrieve the parallel job (a ``joblib.delayed`` tuple). A global "Parallel Jobs" under
119123
"Settings > Dashboard Configuration" in the dasboard controls the total number of jobs
120-
run in parallel during each iteration (``n_jobs`` param for ``joblib.Parallel`` call).
124+
run in parallel during each iteration (``n_jobs`` param for `joblib.Parallel`_ call).
121125

122126
If a widget has ``_run_mode`` as ``parallel``, after the parallel job is completed, a
123127
:meth:`~mdadash.backend.widgets.base.WidgetBase.apply_parallel_results` method is invoked
@@ -336,3 +340,5 @@ for these are examples of more complex use cases.
336340
If you are adding a custom Widget that could be useful for others in the community, you can
337341
create a `pull request <https://github.com/MDAnalysis/mdadash/pulls>`_ to make it part of the
338342
:doc:`built_in_widgets`.
343+
344+
.. _joblib.Parallel: https://joblib.readthedocs.io/en/stable/generated/joblib.Parallel.html

docs/source/batching.rst

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
Batching
2+
========
3+
4+
`IMDReader`_ provides support for reading MD simulation data via the `IMDv3 Protocol`_
5+
in MDAnalysis since `Release 2.10.0`_.
6+
7+
Since IMD streams data in real-time from a running simulation, it has fundamental constraints
8+
that differ from traditional trajectory readers and this leads to some `Important Limitations`_
9+
in `IMDReader`_.
10+
11+
Buffered Access
12+
---------------
13+
14+
To support buffered, time-dependent analyses in ``mdadash``, a
15+
:class:`~mdadash.backend.kernel.core.BufferedTrajectory` is introduced.
16+
17+
The original trajectory is wrapped by the :class:`~mdadash.backend.kernel.core.BufferedTrajectory`
18+
to provide buffered access to the last ``n`` timesteps, where ``n`` is the configured batch size.
19+
20+
.. code-block:: python
21+
22+
u.trajectory = BufferedTrajectory(u.trajectory, config["batch_size"])
23+
24+
``trajectory[index]`` can be used to access individual frames. Index values can range from 0 to the
25+
configured batch size ``n``. The batch size ``n`` is available via the ``trajectory.buffer_size``
26+
attribute.
27+
28+
When a Widget class supports :ref:`batching <run-frequency>` and implements the
29+
:meth:`~mdadash.backend.widgets.base.WidgetBase.run_batch` method, the trajectory can be iterated
30+
this way to access the last ``n`` timesteps.
31+
32+
Here is a typical compute batch block used in the code for :doc:`built_in_widgets`:
33+
34+
.. code-block:: python
35+
36+
def _compute_batch(self):
37+
"""Compute for current batch"""
38+
values = []
39+
for i in range(self.u.trajectory.buffer_size):
40+
_ = self.u.trajectory[i] # set the trajectory to frame i
41+
values.append(self._compute_current_frame())
42+
return values
43+
44+
45+
AnalysisBase support
46+
--------------------
47+
48+
MDAnalysis provides an `AnalysisBase`_, which is the base class for defining multi-frame analysis.
49+
50+
A lot of built-in MDAnalysis `Analysis modules`_ derive from `AnalysisBase`_.
51+
52+
The :class:`~mdadash.backend.kernel.core.BufferedTrajectory` enables using these analysis
53+
modules in the Widget classes, which are not possible with `IMDReader`_.
54+
55+
.. note::
56+
57+
The total number of frames as seen by the `AnalysisBase`_-based classes will be the
58+
configured Buffer / batch size during a full ``analysis.run()`` invocation.
59+
60+
Here is an example of using an `AnalysisBase`_-based class within the Widget code by the
61+
:mod:`Native Contacts <mdadash.backend.analyses.native_contacts>` built-in Widget.
62+
63+
.. code-block:: python
64+
65+
from MDAnalysis.analysis import contacts
66+
.....
67+
68+
def _create_contacts(self):
69+
"""Update atom groups when selection phrases change"""
70+
self.contacts = contacts.Contacts(
71+
self.u,
72+
.....
73+
74+
def _compute_batch(self):
75+
"""Compute values for current batch"""
76+
self.contacts.run()
77+
values = []
78+
for i, (_, q) in enumerate(self.contacts.results.timeseries):
79+
.....
80+
81+
82+
`AnalysisBase`_-based classes can also be used per-frame by passing the current frame as
83+
shown in this example:
84+
85+
.. code-block:: python
86+
87+
def _compute_current_frame(self):
88+
"""Compute values for current frame"""
89+
self.contacts.run(frames=[self.u.trajectory.frame])
90+
.....
91+
92+
93+
----
94+
95+
The list of all the Widgets that support batching can be found on the
96+
:doc:`built_in_widgets` page.
97+
98+
99+
.. _IMDReader: https://docs.mdanalysis.org/stable/
100+
documentation_pages/coordinates/IMD.html
101+
102+
.. _Important Limitations: https://docs.mdanalysis.org/stable/
103+
documentation_pages/coordinates/IMD.html#important-limitations
104+
105+
.. _IMDv3 Protocol: https://imdclient.readthedocs.io/en/latest/protocol_v3.html
106+
107+
.. _Release 2.10.0: https://www.mdanalysis.org/2025/10/26/release-2.10.0/
108+
109+
.. _AnalysisBase: https://docs.mdanalysis.org/stable/
110+
documentation_pages/analysis/base.html#MDAnalysis.analysis.base.AnalysisBase
111+
112+
.. _Analysis modules: https://docs.mdanalysis.org/stable/
113+
documentation_pages/analysis_modules.html
114+

docs/source/index.rst

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
contain the root `toctree` directive.
55
66
Welcome to ``mdadash`` documentation!
7-
=========================================================
7+
=====================================
88

99
Source code and contributing instructions for this project can be found in the `GitHub Repository <https://github.com/MDAnalysis/mdadash>`_.
1010

@@ -15,6 +15,8 @@ Source code and contributing instructions for this project can be found in the `
1515
getting_started
1616
built_in_widgets
1717
adding_custom_widgets
18+
batching
19+
parallelization
1820
api
1921

2022

docs/source/parallelization.rst

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
Parallelization
2+
===============
3+
4+
``mdadash`` supports running Widgets in parallel. It uses `Joblib`_ with the default
5+
``loky`` backend to run the parallel jobs as separate processes. A global "Parallel Jobs"
6+
under "Settings > Dashboard Configuration" in the dasboard controls the total number of jobs
7+
that can run in parallel (``n_jobs`` param for `joblib.Parallel`_ call).
8+
9+
All the analyses that run in ``mdadash`` are CPU-bound and hence a Process-based parallelism
10+
is chosen instead of Thread-based parallelism.
11+
12+
`IMDReader`_ uses `imdclient`_ to connect to a live MD simulation. Because of the use of a
13+
network socket within `imdclient`_, this is not serializable by default. ``mdadash`` patches
14+
`IMDReader`_ to remove `imdclient`_ from the serialization state since the trajectory is never
15+
iterated using `imdclient`_ within a parallel job. This makes parallelization possible within
16+
``mdadash`` for streaming trajectories.
17+
18+
A Widget class that supports a ``parallel`` :ref:`_run_mode <run-mode>` must implement
19+
:meth:`~mdadash.backend.widgets.base.WidgetBase.get_parallel_job` and
20+
:meth:`~mdadash.backend.widgets.base.WidgetBase.apply_parallel_results` methods.
21+
22+
As mentioned in the docs for the
23+
:meth:`~mdadash.backend.widgets.base.WidgetBase.get_parallel_job` and
24+
:meth:`~mdadash.backend.widgets.base.WidgetBase.apply_parallel_results` methods, everything
25+
needed by the Widget class (ouputs, updated internal state, etc) must be explicitly returned
26+
back as return values from the parallel job and applied back to the Widget.
27+
28+
Given the choice of Process-based parallelism, there will be serialization and de-serialization
29+
overheads involved when Widgets run in parallel mode. The type of analysis and the use of
30+
batching should be considered when choosing the ``parallel`` :ref:`_run_mode <run-mode>` for
31+
Widgets.
32+
33+
.. tip::
34+
35+
:doc:`batching` can be used with Parallelization to limit the impact of the
36+
serialization and de-serialization overhead.
37+
38+
----
39+
40+
The list of all the Widgets that can be run in parallel can be found on the
41+
:doc:`built_in_widgets` page.
42+
43+
44+
.. _Joblib: https://joblib.readthedocs.io/en/stable/
45+
46+
.. _joblib.Parallel: https://joblib.readthedocs.io/en/stable/generated/joblib.Parallel.html
47+
48+
.. _IMDReader: https://docs.mdanalysis.org/stable/
49+
documentation_pages/coordinates/IMD.html
50+
51+
.. _imdclient: https://imdclient.readthedocs.io/en/latest/

0 commit comments

Comments
 (0)