Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds Reader.timeseries #1400

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions package/CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ mm/dd/yy

* 0.16.2

Deprecations
* deprecated core.Timeseries module (Issue #1383)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this needs to be moved up the timeline or removed right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah it's leftover from when this also did the deprecation


Enhancements

Fixes
Expand Down
2 changes: 2 additions & 0 deletions package/MDAnalysis/coordinates/DCD.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@
import os
import errno
import numpy as np
from numpy.lib.utils import deprecate
import struct
import types
import warnings
Expand Down Expand Up @@ -578,6 +579,7 @@ def timeseries(self, asel=None, start=None, stop=None, step=None, skip=None,
# XXX needs to be implemented
return self._read_timeseries(atom_numbers, start, stop, step, format)

@deprecate(message="This method will be removed in 0.17")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All the deprecations can go in now.

I somehow missed your PR and did the reST deprecations in PR #1403

def correl(self, timeseries, start=None, stop=None, step=None, skip=None):
"""Populate a :class:`~MDAnalysis.core.Timeseries.TimeseriesCollection` object
with time series computed from the trajectory.
Expand Down
4 changes: 0 additions & 4 deletions package/MDAnalysis/coordinates/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -538,10 +538,6 @@ class can choose an appropriate reader automatically.
``timeseries(atomGroup, [start[,stop[,skip[,format]]]])``
returns a subset of coordinate data

``correl(timeseriesCollection[,start[,stop[,skip]]])``
populate a :class:`MDAnalysis.core.Timeseries.TimeseriesCollection` object
with observable timeseries computed from the trajectory


Attributes
..........
Expand Down
54 changes: 54 additions & 0 deletions package/MDAnalysis/coordinates/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -1461,6 +1461,60 @@ def __repr__(self):
natoms=self.n_atoms
))

def timeseries(self, asel=None, start=None, stop=None, step=None,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a new feature for trajectory readers. It cannot go into a patch release. It has to be in 0.17.0.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I'll bump this into 0.17 then

format='fac'):
"""Return a subset of coordinate data for an AtomGroup

Parameters
----------
asel : :class:`~MDAnalysis.core.groups.AtomGroup` (optional)
The :class:`~MDAnalysis.core.groups.AtomGroup` to read the
coordinates from. Defaults to None, in which case the full set of
coordinate data is returned.
start : int (optional)
Begin reading the trajectory at frame index `start` (where 0 is the index
of the first frame in the trajectory); the default ``None`` starts
at the beginning.
stop : int (optional)
End reading the trajectory at frame index `stop`-1, i.e, `stop` is excluded.
The trajectory is read to the end with the default ``None``.
step : int (optional)
Step size for reading; the default ``None`` is equivalent to 1 and means to
read every frame.
format : str (optional)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

btw I'm for naming this option order format is confusing with the buildin

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See #1063 where this was already mooted.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See #1453 for the issue.

the order/shape of the return data array, corresponding
to (a)tom, (f)rame, (c)oordinates all six combinations
of 'a', 'f', 'c' are allowed ie "fac" - return array
where the shape is (frame, number of atoms,
coordinates)

"""
start, stop, step = self.check_slice_indices(start, stop, step)
nframes = len(range(start, stop, step))

if asel is not None:
if len(asel) == 0:
raise NoDataError(
"Timeseries requires at least one atom to analyze")
atom_numbers = asel.indices
natoms = len(atom_numbers)
else:
atom_numbers = None
natoms = self.n_atoms

if not format in ('fac', None):
# need to add swapping around axes etc
raise NotImplementedError

# allocate output array
coordinates = np.empty((nframes, natoms, 3), dtype=np.float32)
for i, ts in enumerate(self[start:stop:step]):
# if atom_number == None, this will cause view of array
# do we need copy in this case?
coordinates[i] = ts.positions[atom_numbers].copy()

return coordinates
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not implementing the format keyword argument. I guess you can copy the code I use in libdcd for this. There are also a lot of tests for it right now.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And yeah, I'll have to deal with that in this PR too

Copy link
Member

@orbeckst orbeckst Jul 4, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And we wanted to change the format kwarg to order.... #1400 (comment)


def add_auxiliary(self, auxname, auxdata, format=None, **kwargs):
"""Add auxiliary data to be read alongside trajectory.

Expand Down
12 changes: 12 additions & 0 deletions package/MDAnalysis/core/Timeseries.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,12 @@
from __future__ import division, absolute_import
import warnings

from numpy.lib.utils import deprecate

from . import groups


@deprecate(message="This class will be removed in 0.17")
class TimeseriesCollection(object):
'''A collection of timeseries objects.

Expand Down Expand Up @@ -185,6 +188,7 @@ def _getAuxData(self):
return auxData


@deprecate(message="This class will be removed in 0.17")
class Timeseries(object):
'''Base timeseries class - define subclasses for specific timeseries computations
'''
Expand Down Expand Up @@ -240,6 +244,7 @@ def getAuxData(self):
return [0.] * self.n_atoms


@deprecate(message="This class will be removed in 0.17")
class Atom(Timeseries):
'''Create a timeseries that returns coordinate data for an atom or group of atoms ::

Expand Down Expand Up @@ -276,6 +281,7 @@ def getAtomCounts(self):
return [1, ] * self.n_atoms


@deprecate(message="This class will be removed in 0.17")
class Bond(Timeseries):
'''Create a timeseries that returns a timeseries for a bond

Expand All @@ -291,6 +297,7 @@ def __init__(self, atoms):
Timeseries.__init__(self, 'r', atoms, 1)


@deprecate(message="This class will be removed in 0.17")
class Angle(Timeseries):
'''Create a timeseries that returns a timeseries for an angle

Expand All @@ -306,6 +313,7 @@ def __init__(self, atoms):
Timeseries.__init__(self, 'a', atoms, 1)


@deprecate(message="This class will be removed in 0.17")
class Dihedral(Timeseries):
'''Create a timeseries that returns a timeseries for a dihedral angle

Expand All @@ -321,6 +329,7 @@ def __init__(self, atoms):
Timeseries.__init__(self, 'h', atoms, 1)


@deprecate(message="This class will be removed in 0.17")
class Distance(Timeseries):
'''Create a timeseries that returns distances between 2 atoms

Expand All @@ -343,6 +352,7 @@ def __init__(self, code, atoms):
Timeseries.__init__(self, code, atoms, size)


@deprecate(message="This class will be removed in 0.17")
class CenterOfGeometry(Timeseries):
'''Create a timeseries that returns the center of geometry of a group of atoms

Expand All @@ -359,6 +369,7 @@ def getAuxData(self):
return [1.] * self.n_atoms


@deprecate(message="This class will be removed in 0.17")
class CenterOfMass(Timeseries):
'''Create a timeseries that returns the center of mass of a group of atoms

Expand All @@ -375,6 +386,7 @@ def getAuxData(self):
return [a.mass for a in self.atoms]


@deprecate(message="This class will be removed in 0.17")
class WaterDipole(Timeseries):
r'''Create a Timeseries that returns a timeseries for the bisector vector of a 3-site water

Expand Down
22 changes: 2 additions & 20 deletions package/MDAnalysis/core/universe.py
Original file line number Diff line number Diff line change
Expand Up @@ -467,26 +467,8 @@ def transfer_to_memory(self, start=None, stop=None, step=None,
verbose = _set_verbose(verbose, quiet, default=False)

if not isinstance(self.trajectory, MemoryReader):
# Try to extract coordinates using Timeseries object
# This is significantly faster, but only implemented for certain
# trajectory file formats
try:
coordinates = self.trajectory.timeseries(
self.atoms, start=start, stop=stop, step=step, format='fac')
# if the Timeseries extraction fails,
# fall back to a slower approach
except AttributeError:
n_frames = len(range(
*self.trajectory.check_slice_indices(start, stop, step)
))
pm_format = '{step}/{numsteps} frames copied to memory (frame {frame})'
pm = ProgressMeter(n_frames, interval=1,
verbose=verbose, format=pm_format)
coordinates = [] # TODO: use pre-allocated array
for i, ts in enumerate(self.trajectory[start:stop:step]):
coordinates.append(np.copy(ts.positions))
pm.echo(i, frame=ts.frame)
coordinates = np.array(coordinates)
coordinates = self.trajectory.timeseries(
self.atoms, start=start, stop=stop, step=step, format='fac')

# Overwrite trajectory in universe with an MemoryReader
# object, to provide fast access and allow coordinates
Expand Down