Skip to content

Commit

Permalink
Some rearrangements since all universe def stuff in single limb.
Browse files Browse the repository at this point in the history
Also, almost done with docs.
  • Loading branch information
dotsdl committed Apr 1, 2016
1 parent d8eb039 commit d37cd4f
Show file tree
Hide file tree
Showing 8 changed files with 197 additions and 54 deletions.
31 changes: 14 additions & 17 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,20 @@ MDSynthesis: a persistence engine for molecular dynamics data

|zen| |docs| |build| |cov|

Although the raw data for any study involving molecular dynamics simulations are
the full trajectories themselves, often we are most interested in
lower-dimensional measures of what is happening. These measures may be as simple
as the distance between two specific atoms, or as complex as the percentage of
contacts relative to some native structure. In any case, it may be time-consuming
to obtain these lower-dimensional intermediate data, and so it is useful to store
them.

Stay organized
==============
MDSynthesis is designed to perform the logistics of medium-to-large-scale
analysis of many trajectories, individually or as entire groups. It should
allow the scientist to operate at a high level when working with the data,
while MDSynthesis handles the details of storing and recalling this data.

In other words, MDSynthesis lets the computer do the boring work of keeping
track of where things are and how they are stored.
As computing power increases, it is now possible to produce hundreds of
molecular dynamics simulation trajectories that vary widely in length,
system size, composition, starting conditions, and other parameters. Managing
this complexity in ways that allow use of the data to answer scientific
questions has itself become a bottleneck. MDSynthesis is an answer to this
problem.

Built on top of `datreant`_, MDSynthesis gives a Pythonic interface to
molecular dynamics trajectories using `MDAnalysis`_, giving the ability to work
with the data from many simulations scattered throughout the filesystem
with ease. It makes it possible to write analysis code that can work across
many varieties of simulation, but even more importantly, MDSynthesis allows
interactive work with the results from hundreds of simulations at once without
much effort.

Efficiently store intermediate data from individual simulations for easy recall
-------------------------------------------------------------------------------
Expand Down
8 changes: 4 additions & 4 deletions docs/api_sims.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ The class :class:`mdsynthesis.Sim` is the central object of ``mdsynthesis``.

.. _Selections_api:

Udef
````
The class :class:`mdsynthesis.limbs.Udef` is the interface used by a Sim to
UniverseDefinition
``````````````````
The class :class:`mdsynthesis.limbs.UniverseDefinition` is the interface used by a Sim to
define its :class:`MDAnalysis.Universe`.

.. autoclass:: mdsynthesis.limbs.Udef
.. autoclass:: mdsynthesis.limbs.UniverseDefinition
:members:
:inherited-members:

Expand Down
4 changes: 3 additions & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
'sphinx.ext.intersphinx',
'sphinx.ext.todo',
'sphinx.ext.coverage',
'sphinx.ext.autosummary',
'sphinx.ext.napoleon',
]

Expand Down Expand Up @@ -298,6 +299,7 @@
# intersphinx mapping to datreant.core docs and others
intersphinx_mapping = {'http://docs.python.org/': None,
'datreantcore': ('http://datreant.readthedocs.org/en/master/', None),
'datreantdata': ('http://datreantdata.readthedocs.org/en/master/', None)}
'datreantdata': ('http://datreantdata.readthedocs.org/en/master/', None),
'MDAnalysis': ('http://pythonhosted.org/MDAnalysis/', None)}


30 changes: 30 additions & 0 deletions docs/datreant.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
====================================
Using Sims with ``datreant`` objects
====================================
Since MDSynthesis is built on top of `datreant`_, many datreant components are
exposed in the MDSynthesis namespace.

.. currentmodule:: datreant.core

Functions
=========
.. autosummary::
discover

Classes
=======
.. autosummary::
Treant
Tree
Leaf
View
Bundle
Group

Learning more
=============
See the `datreant docs`_ for details on how to put these
objects to work with your Sims.

.. _`datreant`: http://datreant.org/
.. _`datreant docs`: http://datreant.readthedocs.org/
36 changes: 16 additions & 20 deletions docs/index.rst
Original file line number Diff line number Diff line change
@@ -1,29 +1,24 @@
=============================================================
MDSynthesis: a persistence engine for molecular dynamics data
=============================================================
Although the raw data for any study involving molecular dynamics simulations are
the full trajectories themselves, often we are most interested in
lower-dimensional measures of what is happening. These measures may be as simple
as the distance between two specific atoms, or as complex as the percentage of
contacts relative to some native structure. Some measures may even be
comparisons of two or more trajectories against each other. In any case, it may
be time-consuming to obtain these lower-dimensional intermediate data, and so
it is useful to store them.
As computing power increases, it is now possible to produce hundreds of
molecular dynamics simulation trajectories that vary widely in length,
system size, composition, starting conditions, and other parameters. Managing
this complexity in ways that allow use of the data to answer scientific
questions has itself become a bottleneck. MDSynthesis is an answer to this
problem.

Built on top of `datreant`_, MDSynthesis gives a Pythonic interface to
molecular dynamics trajectories using `MDAnalysis`_, giving the ability to work
with the data from many simulations scattered throughout the filesystem
with ease. It makes it possible to write analysis code that can work across
many varieties of simulation, but even more importantly, MDSynthesis allows
interactive work with the results from hundreds of simulations at once without
much effort.

.. warning:: This package is **experimental**. It is not API stable, and has
many rough edges and limitations. It is, however, usable.

Stay organized
==============
MDSynthesis is designed to perform the logistics of medium-to-large-scale
analysis of many trajectories, individually or as entire groups. It is intended
to allow the scientist to operate at a high level when working with the data,
while letting MDSynthesis handle the details of storing and recalling this
data.

In other words, MDSynthesis lets the computer do the boring work of keeping
track of where things are and how they are stored.

Efficiently store intermediate data from individual simulations for easy recall
-------------------------------------------------------------------------------
The MDSynthesis **Sim** object gives an interface to raw simulation data
Expand Down Expand Up @@ -71,5 +66,6 @@ MDSynthesis follows the development model of `datreant`_; see the
:caption: User Documentation

install
sim
sims
datreant
api
118 changes: 118 additions & 0 deletions docs/sims.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
============================================
Leveraging molecular dynamics data with Sims
============================================
A **Sim** is a :class:`~datreant.core.Treant` with specialized components for
working with molecular dynamics data. In particular, it can store a definition
for a :class:`MDAnalysis.Universe` for painless recall, as well as custom atom
selections.

.. note:: Since Sims are Treants, everything that applies to Treants applies
to Sims as well. See the `datreant documentation
<http://datreant.readthedocs.org/>`_ for how Treants work and
effectively used.

As with a normal Treant, to generate a Sim from scratch, we need only give it a
name ::

>>> from mdsynthesis import Sim
>>> s = Sim('adk')
>>> s
<Sim: 'adk'>

And we can immediately give the Sim characteristics like :ref:`tags
<datreantcore:Tags_guide>`::

>>> s.tags.add('biased', 'closed-to-open', 'mep')
>>> s.tags
<Tags(['biased', 'closed-to-open', 'MEP'])>

and :ref:`categories <datreantcore:Categories_guide>`::

>>> s.categories['sampling method'] = 'DIMS'
>>> s.categories['sampling '] = 'heay atom'
<Categories({'sampling ': 'heay atom', 'sampling method': 'DIMS'})>

These can be used later to filter and group Sims when we have many to work
with. They can also be used as switches for analysis code, since we may need to
do different things depending on e.g. the type of sampling method used to
produce the trajectory.

Defining the Universe
=====================
What makes a Sim different from a basic Treant is that it can store a
:class:`MDAnalysis.Universe` definition. We can access the Sim's Universe
directly with::

>>> s.universe

but doing so now gives back ``None``. However, if we define a topology for the
Universe with::

>>> s.udef.topology = 'path/to/topology.psf'

then we get back a Universe built with this topology instead::

>>> s.universe
<Universe with 3341 atoms and 3365 bonds>

we can also add a trajectory::

>>> s.udef.trajectory = 'path/to/trajectory.dcd'

and our Universe is re-initialized with both the defined topology and trajectory::

>>> s.universe.trajectory
<DCDReader /home/bob/research/path/to/trajectory.dcd with 98 frames of 3341 atoms>

We can define our Universe as having multiple trajectories by giving a list of
paths instead, and this will work as well. Internally, the Universe generated
will use the :class:`MDAnalysis.coordinates.base.ChainReader` for treating the
trajectories as a contiguous whole.

The Universe definition is persistent, so we can get back an identical Universe
later from another Python session with our Sim::

>>> import mdsynthesis as mds
>>> s = mds.Sim('adk')
>>> s.universe
<Universe with 3341 atoms and 3365 bonds>

.. note:: Changing the topology or trajectory definition will reload the
Universe automatically. This means that any AtomGroups you are
working with will not point to the new Universe, but perhaps the old
one, so it's generally best to regenerate them manually.

Storing keyword arguments
-------------------------
If the Universe needed requires keyword arguments on initialization, these can
be stored as well. For example, if our topology was a PDB file and we wanted
bonds to be guessed upfront, we could make this happen every time::

>>> s.udef.kwargs = {'guess_bonds': True}

Reinitializing the Universe
---------------------------
If you make modifications to the Universe but you want to restore the original
from its definition, you can force it to reload with::

>>> s.udef.reload()


Storing custom atom selections
==============================
MDAnalysis includes its own selection language for extracting
:class:`~MDAnalysis.core.AtomGroup.AtomGroup` objects, which function as an
ordered list of atoms from the system. The selection strings needed to specify
these can be long and complex, and sometimes multiple selection strings are
required in a particular order to extract a given AtomGroup from all the atoms
in the Universe. What's more, for different simulation systems the same
selection of atoms, e.g. the "solvent", might require a different set of
strings.

To make this more manageable, we can store custom atom selections within our
Sim. Say we want all the


API Reference: Sim
==================
See the :ref:`Sim_api` API reference for more details.
20 changes: 10 additions & 10 deletions src/mdsynthesis/limbs.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def __init__(self, treant):

subitems = {'topology': dict,
'trajectory': list,
'universe_kwargs': dict}
'kwargs': dict}

# init state if for udef not already there;
# if read-only, check that it is there,
Expand Down Expand Up @@ -80,10 +80,10 @@ def _activate(self):
trajectory = paths['traj']

if not trajectory:
self._treant._universe = Universe(topology, **self.universe_kwargs)
self._treant._universe = Universe(topology, **self.kwargs)
else:
self._treant._universe = Universe(topology, *trajectory,
**self.universe_kwargs)
**self.kwargs)

self._apply_resnums()

Expand All @@ -98,7 +98,7 @@ def _activate(self):
"Cannot update paths for universe; "
" state file is read-only.")

def reload_universe(self):
def reload(self):
"""Re-load the universe from its stored definition.
"""
Expand Down Expand Up @@ -277,7 +277,7 @@ def _define(self, pathtype='abs'):
return outtop[pathtype], outtraj[pathtype]

@property
def universe_kwargs(self):
def kwargs(self):
"""The keyword arguments applied to the Sim's universe when building
it.
Expand All @@ -288,16 +288,16 @@ def universe_kwargs(self):
"""
with self._treant._read:
mdsdict = self._treant._state['mdsynthesis']
return mdsdict['udef']['universe_kwargs']
return mdsdict['udef']['kwargs']

@universe_kwargs.setter
def universe_kwargs(self, kwargs):
@kwargs.setter
def kwargs(self, kwargs):
if not isinstance(kwargs, dict):
raise TypeError("Must be a dictionary")

with self._treant._write:
simdict = self._treant._state['mdsynthesis']['udef']
simdict['universe_kwargs'] = kwargs
simdict['kwargs'] = kwargs


class AtomSelections(Limb):
Expand Down Expand Up @@ -331,7 +331,7 @@ def __init__(self, treant):
self._treant.filepath)))

def __repr__(self):
return "<Selections({})>".format(
return "<AtomSelections({})>".format(
{x: self.define(x) for x in self.keys()})

def __str__(self):
Expand Down
4 changes: 2 additions & 2 deletions src/mdsynthesis/tests/test_treants.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ def test_set_resnums(self, treant):

treant.udef._set_resnums(treant.universe.residues.resnums)

treant.udef.reload_universe()
treant.udef.reload()

protein = treant.universe.select_atoms('protein')
assert (resids + 3 == protein.residues.resnums).all()
Expand All @@ -91,7 +91,7 @@ def test_set_resnums(self, treant):
assert (protein.residues.resnums == resids + 6).all()
treant.udef._set_resnums(treant.universe.residues.resnums)

treant.udef.reload_universe()
treant.udef.reload()

protein = treant.universe.select_atoms('protein')
assert (resids + 6 == protein.residues.resnums).all()
Expand Down

0 comments on commit d37cd4f

Please sign in to comment.