From d1a13c116947288865c39ad1b7a30febd85d4b9b Mon Sep 17 00:00:00 2001 From: Richard Gowers Date: Thu, 15 Jun 2017 13:21:01 +0100 Subject: [PATCH 1/2] Addde timeseries to ReaderBase --- package/MDAnalysis/coordinates/base.py | 54 ++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/package/MDAnalysis/coordinates/base.py b/package/MDAnalysis/coordinates/base.py index d29b741fd75..159ba0ecb42 100644 --- a/package/MDAnalysis/coordinates/base.py +++ b/package/MDAnalysis/coordinates/base.py @@ -1692,6 +1692,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. From 1913f73407dfb6941b9d64277046b17787d56ec0 Mon Sep 17 00:00:00 2001 From: Oliver Beckstein Date: Wed, 5 Jun 2019 12:01:17 -0700 Subject: [PATCH 2/2] timeseries for all readers (from PR #1400) - updated format -> order kwarg - updated docs - note: general reader.timeseries only supports order="FAC" at the moment - CHANGELOG --- package/CHANGELOG | 6 ++-- package/MDAnalysis/coordinates/base.py | 20 +++++++++--- package/MDAnalysis/coordinates/memory.py | 39 +++++++++++++++--------- 3 files changed, 43 insertions(+), 22 deletions(-) diff --git a/package/CHANGELOG b/package/CHANGELOG index 5e312a18c65..0c55b2a16b4 100644 --- a/package/CHANGELOG +++ b/package/CHANGELOG @@ -55,8 +55,10 @@ Enhancements * added functionality to write files in compressed form(gz,bz2). (Issue #2216, PR #2221) * survival probability additions: residues, intermittency, step with performance, - (PR #2226) - + (PR #2226) + * add timeseries() method to all readers to extract all coordinates into + a numpy array (see PR #1400) + Changes * added official support for Python 3.7 (PR #1963) * stopped official support of Python 3.4 (#2066, PR #2174) diff --git a/package/MDAnalysis/coordinates/base.py b/package/MDAnalysis/coordinates/base.py index 159ba0ecb42..b6f2d445239 100644 --- a/package/MDAnalysis/coordinates/base.py +++ b/package/MDAnalysis/coordinates/base.py @@ -1693,14 +1693,14 @@ def __repr__(self): )) def timeseries(self, asel=None, start=None, stop=None, step=None, - format='fac'): + order='fac'): """Return a subset of coordinate data for an AtomGroup Parameters ---------- - asel : :class:`~MDAnalysis.core.groups.AtomGroup` (optional) + asel : AtomGroup (optional) The :class:`~MDAnalysis.core.groups.AtomGroup` to read the - coordinates from. Defaults to None, in which case the full set of + 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 @@ -1712,13 +1712,22 @@ def timeseries(self, asel=None, start=None, stop=None, step=None, step : int (optional) Step size for reading; the default ``None`` is equivalent to 1 and means to read every frame. - format : str (optional) + order : 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) + .. note:: Only `"fac"` implemented. + + + See Also + -------- + MDAnalysis.coordinates.memory + + + .. versionadded:: 0.20.0 """ start, stop, step = self.check_slice_indices(start, stop, step) nframes = len(range(start, stop, step)) @@ -1733,8 +1742,9 @@ def timeseries(self, asel=None, start=None, stop=None, step=None, atom_numbers = None natoms = self.n_atoms - if not format in ('fac', None): + if not order in ('fac', None): # need to add swapping around axes etc + # see MemoryReader.timeseries() and lib.formats.libdcd.DCDfile.readframe() raise NotImplementedError # allocate output array diff --git a/package/MDAnalysis/coordinates/memory.py b/package/MDAnalysis/coordinates/memory.py index 2ce79adf93a..42a438f97c6 100644 --- a/package/MDAnalysis/coordinates/memory.py +++ b/package/MDAnalysis/coordinates/memory.py @@ -90,21 +90,32 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The :class:`MemoryReader` provides great flexibility because it -becomes possible to create a :class:`~MDAnalysis.core.universe.Universe` directly -from a numpy array. +becomes possible to create a +:class:`~MDAnalysis.core.universe.Universe` directly from a numpy +array. Using the :class:`MemoryReader` is signified by providing a +coordinate array instead of a trajectory file and setting the +``format`` keyword to "MEMORY" (or to the :class:`MemoryReader` class +itself): either :: + + u = Universe(..., array, format="MEMORY") + +or :: + + from MDAnalysis.coordinates.memory import MemoryReader + u = Universe(..., array, format=MemoryReader) + +will work. A simple example consists of a new universe created from the array -extracted from a DCD -:meth:`~MDAnalysis.coordinates.DCD.DCDReader.timeseries`:: +extracted from a :meth:`~MDAnalysis.coordinates.base.ProtoReader.timeseries`:: import MDAnalysis as mda from MDAnalysisTests.datafiles import DCD, PSF - from MDAnalysis.coordinates.memory import MemoryReader universe = mda.Universe(PSF, DCD) coordinates = universe.trajectory.timeseries(universe.atoms) - universe2 = mda.Universe(PSF, coordinates, format=MemoryReader, order='afc') + universe2 = mda.Universe(PSF, coordinates, format="MEMORY", order='afc') .. _create-in-memory-trajectory-with-AnalysisFromFunction: @@ -112,23 +123,22 @@ .. rubric:: Creating an in-memory trajectory with :func:`~MDAnalysis.analysis.base.AnalysisFromFunction` -The :meth:`~MDAnalysis.coordinates.DCD.DCDReader.timeseries` is -currently only implemented for the -:class:`~MDAnalysis.coordinates.DCD.DCDReader`. However, the +The :meth:`~MDAnalysis.coordinates.base.ProtoReader.timeseries` is +available for all formats. However, as an alternative the :func:`MDAnalysis.analysis.base.AnalysisFromFunction` can provide the -same functionality for any supported trajectory format:: +same functionality and the example shows how one can manually extract +coordinates and load them into a new universe:: import MDAnalysis as mda from MDAnalysis.tests.datafiles import PDB, XTC - from MDAnalysis.coordinates.memory import MemoryReader from MDAnalysis.analysis.base import AnalysisFromFunction u = mda.Universe(PDB, XTC) coordinates = AnalysisFromFunction(lambda ag: ag.positions.copy(), u.atoms).run().results - u2 = mda.Universe(PDB, coordinates, format=MemoryReader) + u2 = mda.Universe(PDB, coordinates, format="MEMORY") .. _creating-in-memory-trajectory-label: @@ -147,7 +157,6 @@ import MDAnalysis as mda from MDAnalysis.tests.datafiles import PDB, XTC - from MDAnalysis.coordinates.memory import MemoryReader from MDAnalysis.analysis.base import AnalysisFromFunction u = mda.Universe(PDB, XTC) @@ -156,7 +165,7 @@ coordinates = AnalysisFromFunction(lambda ag: ag.positions.copy(), protein).run().results u2 = mda.Merge(protein) # create the protein-only Universe - u2.load_new(coordinates, format=MemoryReader) + u2.load_new(coordinates, format="MEMORY") The protein coordinates are extracted into ``coordinates`` and then the in-memory trajectory is loaded from these coordinates. In @@ -165,7 +174,7 @@ u2 = mda.Merge(protein).load_new( AnalysisFromFunction(lambda ag: ag.positions.copy(), protein).run().results, - format=MemoryReader) + format="MEMORY") The new :class:`~MDAnalysis.core.universe.Universe` ``u2`` can be used to, for instance, write out a new trajectory or perform fast analysis