Source code for mdadash.backend.analyses.energies
"""
Widgets for various simulation energies
"""
import logging
from collections import deque
from typing import ClassVar
import matplotlib.pyplot as plt
from IPython.display import display
from mdadash.backend.widgets.base import WidgetBase
logger = logging.getLogger(__name__)
[docs]
class EnergyWidgetBase:
"""
**Base class for Energy Widgets**
This is the base class for all Energy widgets.
Energy values are extracted from `MDAnalysis.coordinates.timestep.Timestep.data`_.
The following keys are used for their respective plots:
* ``temperature`` - Absolute Temperature
* ``total_energy`` - Total Energy
* ``potential_energy`` - Potential Energy
* ``coulomb_energy`` - Coulomb Interaction Energy
* ``bonds_energy`` - Bonds Energy
* ``angles_energy`` - Angles Energy
* ``dihedrals_energy`` - Dihedrals Energy
* ``improper_dihedrals_energy`` - Improper Dihedrals Energy
* ``van_der_walls_energy`` - Van Der Waals Energy
.. note::
Energies are only available in the timestep data for streaming trajectories.
The simulation engine must also be explicitly configured to send them
.. _MDAnalysis.coordinates.timestep.Timestep.data: https://docs.mdanalysis.org/stable/
documentation_pages/coordinates/timestep.html#MDAnalysis.coordinates.timestep.Timestep.data
**Inputs**
Max values
.. compound::
Max values to show in plot
Default: ``100``
Title
Title for the plot
Default: ''
X-axis
X-axis value - `time` or `step`
Default: ``time``
**Outputs**
Here is an example output plot of the **Absolute Temperature** widget:
.. figure:: /_static/images/absolute_temperature_output.jpg
:alt: Absolute Temperature output
Here is an example output plot of the **Total Energy** widget:
.. figure:: /_static/images/total_energy_output.jpg
:alt: Total Energy output
"""
name = ""
data_key = ""
y_label = "Energy ( kJ / mol )"
_doclink = (
"https://mdadash.readthedocs.io/en/latest/autosummary/"
"mdadash.backend.analyses.energies.html"
"#mdadash.backend.analyses.energies.EnergyWidgetBase"
)
_notes = (
"Energies are only available for streaming trajectories and only if the "
"simulation engine is configured to send them."
)
_inputs: ClassVar = [
{
"attribute": "maxlen",
"name": "Max values",
"description": "Max values to show in plot",
"type": "int",
},
{
"attribute": "title",
"name": "Title",
"description": "Title for the plot",
"type": "str",
},
{
"attribute": "x_type",
"name": "X-axis",
"type": "toggle",
"options": [
{"name": "Time", "value": "time"},
{"name": "Step", "value": "step"},
],
},
]
def __init__(self):
super().__init__()
self.title = self.name
self.default_maxlen = 100
self.maxlen = self.default_maxlen
self.x_type = "time"
self.x_values = None
self._setup_plot()
self._reset_plot_values()
def _setup_plot(self):
"""Setup matplotlib plot"""
self.fig, self.ax = plt.subplots()
(self.plot,) = self.ax.plot([], [])
self._set_title()
self.ax.set_ylabel(self.y_label)
self.ax.grid(True)
def _reset_plot_values(self):
"""Reset plot values"""
self.steps = deque(maxlen=self.maxlen)
self.times = deque(maxlen=self.maxlen)
self.y_values = deque(maxlen=self.maxlen)
self._set_x_values()
def _set_title(self):
"""Set plot title"""
self.ax.set_title(self.title)
def _set_x_values(self):
"""Set the values for the x-axis"""
if self.x_type == "step":
x_label = "Step"
self.x_values = self.steps
else:
x_label = "Time (ps)"
self.x_values = self.times
self.ax.set_xlabel(x_label)
[docs]
def on_post_create(self):
""":meth:`~mdadash.backend.widgets.base.WidgetBase.on_post_create` handler"""
self._set_title()
self._reset_plot_values()
[docs]
def on_input_change(self, attribute, _old_value, new_value):
""":meth:`~mdadash.backend.widgets.base.WidgetBase.on_input_change` handler"""
if attribute == "maxlen":
if new_value < 0:
self.maxlen = self.default_maxlen
self._reset_plot_values()
elif attribute == "title":
self._set_title()
elif attribute == "x_type":
self._set_x_values()
[docs]
def run_every_frame(self):
""":meth:`~mdadash.backend.widgets.base.WidgetBase.run_every_frame` handler"""
ts = self.u.trajectory.ts # pylint: disable=no-member
if self.data_key not in ts.data:
return # pragma: no cover
self.steps.append(ts.data["step"])
self.times.append(ts.data["time"])
self.y_values.append(ts.data[self.data_key])
# update plot
self.plot.set_data(self.x_values, self.y_values)
self.ax.relim()
self.ax.autoscale_view()
self.fig.canvas.draw()
display(self.fig)
[docs]
class AbsoluteTemperature(EnergyWidgetBase, WidgetBase):
"""Absolute Temperature
See :class:`EnergyWidgetBase` for more details.
"""
name = "Absolute Temperature"
description = "Plot of Absolute Temperature"
data_key = "temperature"
y_label = "Temperature ( K )"
[docs]
class TotalEnergy(EnergyWidgetBase, WidgetBase):
"""Total Energy
See :class:`EnergyWidgetBase` for more details.
"""
name = "Total Energy"
description = "Plot of Total Energy"
data_key = "total_energy"
[docs]
class PotentialEnergy(EnergyWidgetBase, WidgetBase):
"""Potential energy
See :class:`EnergyWidgetBase` for more details.
"""
name = "Potential energy"
description = "Plot of Potential Energy"
data_key = "potential_energy"
[docs]
class VanDerWaalsEnergy(EnergyWidgetBase, WidgetBase):
"""Van Der Waals Energy
See :class:`EnergyWidgetBase` for more details.
"""
name = "Van Der Waals Energy"
description = "Plot of Van Der Waals Energy"
data_key = "van_der_walls_energy"
[docs]
class CoulombInteractionEnergy(EnergyWidgetBase, WidgetBase):
"""Coulomb Interaction Energy
See :class:`EnergyWidgetBase` for more details.
"""
name = "Coulomb Interaction Energy"
description = "Plot of Coulomb Interaction Energy"
data_key = "coulomb_energy"
[docs]
class BondsEnergy(EnergyWidgetBase, WidgetBase):
"""Bonds Energy
See :class:`EnergyWidgetBase` for more details.
"""
name = "Bonds Energy"
description = "Plot of Bonds Energy"
data_key = "bonds_energy"
[docs]
class AnglesEnergy(EnergyWidgetBase, WidgetBase):
"""Angles Energy
See :class:`EnergyWidgetBase` for more details.
"""
name = "Angles Energy"
description = "Plot of Angles Energy"
data_key = "angles_energy"
[docs]
class DihedralsEnergy(EnergyWidgetBase, WidgetBase):
"""Dihedrals Energy
See :class:`EnergyWidgetBase` for more details.
"""
name = "Dihedrals Energy"
description = "Plot of Dihedrals Energy"
data_key = "dihedrals_energy"
[docs]
class ImproperDihedralsEnergy(EnergyWidgetBase, WidgetBase):
"""Improper Dihedrals Energy
See :class:`EnergyWidgetBase` for more details.
"""
name = "Improper Dihedrals Energy"
description = "Plot of Improper Dihedrals Energy"
data_key = "improper_dihedrals_energy"