diff --git a/package/CHANGELOG b/package/CHANGELOG index d91b3b49d86..25dbcf1ebe3 100644 --- a/package/CHANGELOG +++ b/package/CHANGELOG @@ -17,6 +17,9 @@ mm/dd/yy * 0.16.2 +Deprecations + * deprecated core.Timeseries module (Issue #1383) + Enhancements Fixes diff --git a/package/MDAnalysis/coordinates/DCD.py b/package/MDAnalysis/coordinates/DCD.py index e30f52f4600..b2530501c16 100644 --- a/package/MDAnalysis/coordinates/DCD.py +++ b/package/MDAnalysis/coordinates/DCD.py @@ -81,6 +81,7 @@ import os import errno import numpy as np +from numpy.lib.utils import deprecate import struct import types import warnings @@ -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") 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. diff --git a/package/MDAnalysis/coordinates/__init__.py b/package/MDAnalysis/coordinates/__init__.py index 7410d391c2c..e1aecb925c4 100644 --- a/package/MDAnalysis/coordinates/__init__.py +++ b/package/MDAnalysis/coordinates/__init__.py @@ -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 .......... diff --git a/package/MDAnalysis/coordinates/base.py b/package/MDAnalysis/coordinates/base.py index f882eefe15c..a1cfee8d4eb 100644 --- a/package/MDAnalysis/coordinates/base.py +++ b/package/MDAnalysis/coordinates/base.py @@ -1461,6 +1461,60 @@ def __repr__(self): natoms=self.n_atoms )) + def timeseries(self, asel=None, start=None, stop=None, step=None, + 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) + 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 + def add_auxiliary(self, auxname, auxdata, format=None, **kwargs): """Add auxiliary data to be read alongside trajectory. diff --git a/package/MDAnalysis/core/Timeseries.py b/package/MDAnalysis/core/Timeseries.py index 6dc2952874b..fb0353c5c92 100644 --- a/package/MDAnalysis/core/Timeseries.py +++ b/package/MDAnalysis/core/Timeseries.py @@ -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. @@ -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 ''' @@ -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 :: @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 diff --git a/package/MDAnalysis/core/universe.py b/package/MDAnalysis/core/universe.py index 3a6e3decacc..51f99d76ea2 100644 --- a/package/MDAnalysis/core/universe.py +++ b/package/MDAnalysis/core/universe.py @@ -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