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

Refactor pmda after universe can be serialized #132

Open
wants to merge 34 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
1e3d27b
refactor parallel.py
yuxuanzhuang Jul 15, 2020
4435f29
refactor custom
yuxuanzhuang Jul 15, 2020
1981673
pep8
yuxuanzhuang Jul 15, 2020
0a70857
refactor rmsd
yuxuanzhuang Jul 15, 2020
cafe65f
refactor rmsf
yuxuanzhuang Jul 15, 2020
185d19a
refactor contacts
yuxuanzhuang Jul 15, 2020
ef86b9d
refactor density
yuxuanzhuang Jul 15, 2020
c0b0bd6
refactor rdf
yuxuanzhuang Jul 15, 2020
bfa629c
refactor HBonds
yuxuanzhuang Jul 15, 2020
495033f
leaflet broken
yuxuanzhuang Jul 15, 2020
8700223
build mdanalysis on serialize_io
yuxuanzhuang Jul 16, 2020
c8e9973
build mdanalysis on serialize_io fix
yuxuanzhuang Jul 16, 2020
356cfb9
push leaflet fix back
yuxuanzhuang Jul 16, 2020
58fea5d
travis fix
yuxuanzhuang Jul 16, 2020
dfd3588
travis fix
yuxuanzhuang Jul 16, 2020
0921882
test parallel
yuxuanzhuang Jul 16, 2020
49288e8
timing test
yuxuanzhuang Jul 16, 2020
9a0e0c5
leaflet fix
yuxuanzhuang Jul 16, 2020
187463b
pep8
yuxuanzhuang Jul 17, 2020
8a42040
make sure universe before atomgroup
yuxuanzhuang Jul 17, 2020
053225b
change travis back
yuxuanzhuang Aug 9, 2020
83becd7
travis to develop
yuxuanzhuang Aug 13, 2020
f9c89e6
remove getstate
yuxuanzhuang Aug 19, 2020
61bce8f
pep8
yuxuanzhuang Aug 19, 2020
cb99fc8
update setup.py
yuxuanzhuang Aug 19, 2020
d95add1
pep8 warning
yuxuanzhuang Aug 19, 2020
a505282
travis
yuxuanzhuang Aug 19, 2020
608a803
setup reverse
yuxuanzhuang Aug 19, 2020
18988c5
pep
yuxuanzhuang Aug 19, 2020
61a34c7
setup py3
yuxuanzhuang Aug 19, 2020
7bf68f5
rewind doc
yuxuanzhuang Aug 19, 2020
5ceaebf
doc
yuxuanzhuang Aug 20, 2020
d424f6d
merge to develop
yuxuanzhuang Aug 23, 2020
b649c04
Merge branch 'master' into refactor_pmda
orbeckst May 12, 2021
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
11 changes: 5 additions & 6 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,15 @@ env:
- SETUP_CMD="pmda --cov pmda"
# mdanalysis develop from source (see below), which needs
# minimal CONDA_MDANALYSIS_DEPENDENCIES
#- CONDA_DEPENDENCIES="mdanalysis mdanalysistests dask joblib mock codecov cython hypothesis sphinx"
#- CONDA_MDANALYSIS_DEPENDENCIES="cython mmtf-python six biopython networkx scipy griddataformats gsd hypothesis"
- CONDA_MDANALYSIS_DEPENDENCIES="mdanalysis mdanalysistests"
# pin to matplotlib 3.2 should be removed once mda > 1.0.0 is available.
- CONDA_DEPENDENCIES="${CONDA_MDANALYSIS_DEPENDENCIES} dask distributed joblib mock codecov matplotlib=3.2"
# - CONDA_DEPENDENCIES="mdanalysis mdanalysistests dask joblib pytest-pep8 mock codecov cython hypothesis sphinx"
# - CONDA_MDANALYSIS_DEPENDENCIES="cython mmtf-python six biopython networkx scipy griddataformats gsd hypothesis"
- CONDA_MDANALYSIS_DEPENDENCIES="mmtf-python biopython networkx cython matplotlib scipy griddataformats hypothesis gsd"
- CONDA_DEPENDENCIES="${CONDA_MDANALYSIS_DEPENDENCIES} dask distributed joblib pytest-pep8 mock codecov"
- CONDA_CHANNELS='conda-forge'
- CONDA_CHANNEL_PRIORITY=True
# install development version of MDAnalysis (needed until the test
# files for analysis.rdf are available in release 0.19.0)
Copy link
Member

Choose a reason for hiding this comment

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

the comment is outdated

#- PIP_DEPENDENCIES="git+https://github.com/MDAnalysis/mdanalysis#egg=mdanalysis&subdirectory=package git+https://github.com/MDAnalysis/mdanalysis#egg=mdanalysistests&subdirectory=testsuite"
- PIP_DEPENDENCIES="git+https://github.com/MDAnalysis/mdanalysis#egg=mdanalysis&subdirectory=package git+https://github.com/MDAnalysis/mdanalysis#egg=mdanalysistests&subdirectory=testsuite"
- NUMPY_VERSION=stable
- BUILD_CMD='python setup.py develop'
- CODECOV=false
Expand Down
8 changes: 8 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,14 @@ Fixes
Changes
* requires MDAnalysis >= 1.0.0 (#122)
* dropped official support for Python 3.5 (2.7 and >= 3.6 are supported)
* requires MDAnalysis >= 2.0.0 (#132)
* dropped official support for Python<=3.5 (#132)
* with support of serialization of Universe, in ParallelAnalysisBase: (#132)
- we pickle/unpickle Universes, instead of creating new ones.
- __init__ only takes Universe as then argument.
- _single_frame takes no argument.
- timing for generating universe is ditched.
- timing for creating dask graph is added.


10/14/2019 VOD555, nawtrey
Expand Down
11 changes: 5 additions & 6 deletions pmda/contacts.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,8 +182,6 @@ def is_any_closer(r, r0, dist=2.5):
:inherited-members:

"""
from __future__ import absolute_import, division

import MDAnalysis as mda
from MDAnalysis.analysis.contacts import (contact_matrix, hard_cut_q,
radius_cut_q, soft_cut_q)
Expand Down Expand Up @@ -237,7 +235,8 @@ def __init__(self,
respective functions for reasonable values.
"""
universe = mobiles[0].universe
super(Contacts, self).__init__(universe, mobiles)
super().__init__(universe)
self._mobiles = mobiles

if method == 'hard_cut':
self.fraction_contacts = hard_cut_q
Expand Down Expand Up @@ -267,13 +266,13 @@ def __init__(self,
def _prepare(self):
self.timeseries = None

def _single_frame(self, ts, atomgroups):
grA, grB = atomgroups
def _single_frame(self):
grA, grB = self._mobiles
# compute distance array for a frame
d = distance_array(grA.positions, grB.positions)

y = np.empty(len(self.r0) + 1)
y[0] = ts.frame
y[0] = self._ts.frame
for i, (initial_contacts,
r0) in enumerate(zip(self.initial_contacts, self.r0)):
# select only the contacts that were formed in the reference state
Expand Down
52 changes: 17 additions & 35 deletions pmda/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,6 @@
same universe and return a value.

"""
from __future__ import absolute_import

from MDAnalysis.core.groups import AtomGroup
from MDAnalysis.core.universe import Universe
from MDAnalysis.coordinates.base import ProtoReader
import numpy as np
Expand All @@ -44,7 +41,7 @@ class AnalysisFromFunction(ParallelAnalysisBase):
>>> return mda.analysis.align.rotation_matrix(mobile, ref)[0]
>>> # now run an analysis using the standalone function
>>> rot = AnalysisFromFunction(rotation_matrix,
trajectory, mobile, ref).run()
universe, mobile, ref).run()
>>> print(rot.results)

Raises
Expand All @@ -64,40 +61,24 @@ def __init__(self, function, universe, *args, **kwargs):
to be 'mobile' Atomgroups if they belong to the same universe. All
other Atomgroups are assumed to be reference. Here 'mobile' means
they will be iterated over.
Universe : :class:`~MDAnalysis.core.groups.Universe`
universe : :class:`~MDAnalysis.core.groups.Universe`
a :class:`MDAnalysis.core.groups.Universe` (the
`atomgroups` must belong to this Universe)
`atomgroups` in other args must belong to this Universe)
*args : list
arguments for ``function``
**kwargs : dict
keyword arguments for ``function``. keyword arguments with name
'universe' or 'atomgroups' will be ignored! Mobile atomgroups to
analyze can not be passed as keyword arguments currently.

keyword arguments for ``function``.
"""

self.function = function

# collect all atomgroups with the same trajectory object as universe
trajectory = universe.trajectory
arg_ags = []
self.other_args = []
for arg in args:
if isinstance(arg,
AtomGroup) and arg.universe.trajectory == trajectory:
arg_ags.append(arg)
else:
self.other_args.append(arg)

super(AnalysisFromFunction, self).__init__(universe, arg_ags)
super().__init__(universe)
self.args = args
self.kwargs = kwargs

def _prepare(self):
self.results = []

def _single_frame(self, ts, atomgroups):
Copy link
Member

Choose a reason for hiding this comment

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

Hm, cool that this works.

args = atomgroups + self.other_args
return self.function(*args, **self.kwargs)
def _single_frame(self):
return self.function(*self.args, **self.kwargs)

def _conclude(self):
self.results = np.concatenate(self._results)
Expand Down Expand Up @@ -132,7 +113,7 @@ def analysis_class(function):
>>> def RotationMatrix(mobile, ref):
>>> return mda.analysis.align.rotation_matrix(mobile, ref)[0]

>>> rot = RotationMatrix(u.trajectory, mobile, ref, step=2).run()
>>> rot = RotationMatrix(u, mobile, ref, step=2).run()
>>> print(rot.results)

See Also
Expand All @@ -144,13 +125,14 @@ def analysis_class(function):
class WrapperClass(AnalysisFromFunction):
"""Custom Analysis Function"""

def __init__(self, trajectory=None, *args, **kwargs):
if not (isinstance(trajectory, ProtoReader) or isinstance(
trajectory, Universe)):
print(type(trajectory))
def __init__(self, universe=None, *args, **kwargs):
if not isinstance(universe, Universe):
print(type(universe))
raise ValueError(
"First argument needs to be an MDAnalysis reader object.")
super(WrapperClass, self).__init__(function, trajectory, *args,
**kwargs)
"First argument needs to be an MDAnalysis Universe.")
super().__init__(function,
universe,
*args,
**kwargs)

return WrapperClass
30 changes: 11 additions & 19 deletions pmda/density.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,6 @@
MDAnalysis.analysis.density.density_from_Universe

"""

from __future__ import absolute_import

import numpy as np

from MDAnalysis.lib.util import fixedwidth_bins
Expand Down Expand Up @@ -241,7 +238,7 @@ def __init__(self, atomgroup, delta=1.0, atomselection=None,
parameters=None, gridcenter=None, xdim=None, ydim=None,
zdim=None):
u = atomgroup.universe
super(DensityAnalysis, self).__init__(u, (atomgroup, ))
super().__init__(u)
self._atomgroup = atomgroup
self._delta = delta
self._atomselection = atomselection
Expand All @@ -259,10 +256,14 @@ def __init__(self, atomgroup, delta=1.0, atomselection=None,
elif not updating and atomselection is not None:
raise ValueError("""With updating=False, the atomselection='{}' is
not used and should be None""".format(atomselection))
elif updating and atomselection is not None:
self._select_atomgroup = atomgroup.select_atoms(atomselection,
updating=True)
Copy link
Member

Choose a reason for hiding this comment

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

Do updating AtomGroups work with the serialization?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes! Thanks to what has already been implemented by Richard:)

else:
self._select_atomgroup = atomgroup

def _prepare(self):
coord = self.current_coordinates(self._atomgroup, self._atomselection,
self._updating)
coord = self._select_atomgroup.positions
if self._gridcenter is not None:
# Generate a copy of smin/smax from coords to later check if the
# defined box might be too small for the selection
Expand Down Expand Up @@ -294,10 +295,10 @@ def _prepare(self):
self._arange = arange
self._bins = bins

def _single_frame(self, ts, atomgroups):
coord = self.current_coordinates(atomgroups[0], self._atomselection,
self._updating)
result = np.histogramdd(coord, bins=self._bins, range=self._arange,
def _single_frame(self):
result = np.histogramdd(self._select_atomgroup.positions,
bins=self._bins,
range=self._arange,
normed=False)
return result[0]

Expand Down Expand Up @@ -330,12 +331,3 @@ def _reduce(res, result_single_frame):
else:
res += result_single_frame
return res

@staticmethod
def current_coordinates(atomgroup, atomselection, updating):
"""Retrieves the current coordinates of all atoms in the chosen atom
selection.
Note: currently required to allow for updating selections"""
ag = atomgroup if not updating else atomgroup.select_atoms(
atomselection)
return ag.positions
34 changes: 12 additions & 22 deletions pmda/hbond_analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@
:members:

"""
from __future__ import absolute_import, division

import numpy as np

from MDAnalysis.lib.distances import capped_distance, calc_angles
Expand Down Expand Up @@ -174,7 +172,8 @@ def __init__(self, universe, donors_sel=None, hydrogens_sel=None,
"""

ag = universe.atoms
super(HydrogenBondAnalysis, self).__init__(universe, (ag, ))
super().__init__(universe)
self._atomgroup = ag
self.donors_sel = donors_sel
self.hydrogens_sel = hydrogens_sel
self.acceptors_sel = acceptors_sel
Expand Down Expand Up @@ -220,7 +219,7 @@ def guess_hydrogens(self, selection='all', max_mass=1.1, min_charge=0.3):
:attr:`hydrogens_sel`.
"""

u = self._universe()
u = self._universe
ag = u.select_atoms(selection)
hydrogens_ag = ag[
np.logical_and(
Expand Down Expand Up @@ -284,7 +283,7 @@ def guess_donors(self, selection='all', max_charge=-0.5):
hydrogens_sel = self.guess_hydrogens()
else:
hydrogens_sel = self.hydrogens_sel
u = self._universe()
u = self._universe
hydrogens_ag = u.select_atoms(hydrogens_sel)

ag = hydrogens_ag.residues.atoms.select_atoms(
Expand Down Expand Up @@ -337,7 +336,7 @@ def guess_acceptors(self, selection='all', max_charge=-0.5):
attribute :attr:`acceptors_sel`.
"""

u = self._universe()
u = self._universe
ag = u.select_atoms(selection)
acceptors_ag = ag[ag.charges < max_charge]
acceptors_list = np.unique(
Expand Down Expand Up @@ -395,7 +394,7 @@ def _get_dh_pairs(self, u):
return donors, hydrogens

def _prepare(self):
u = mda.Universe(self._top, self._traj)
u = self._universe
self.hbonds = []
self.frames = np.arange(self.start, self.stop, self.step)
self.timesteps = (self.frames*u.trajectory.dt) + u.trajectory[0].time
Expand All @@ -412,10 +411,9 @@ def _prepare(self):
self._donors_ids = donors.ids
self._hydrogens_ids = hydrogens.ids

def _single_frame(self, ts, atomgroups):
u = atomgroups[0].universe

box = ts.dimensions
def _single_frame(self):
u = self._universe
box = self._ts.dimensions

# Update donor-hydrogen pairs if necessary
if self.update_selections:
Expand Down Expand Up @@ -461,7 +459,7 @@ def _single_frame(self, ts, atomgroups):

# Store data on hydrogen bonds found at this frame
hbonds = [[], [], [], [], [], []]
hbonds[0].extend(np.full_like(hbond_donors, ts.frame))
hbonds[0].extend(np.full_like(hbond_donors, self._ts.frame))
hbonds[1].extend(hbond_donors.ids)
hbonds[2].extend(hbond_hydrogens.ids)
hbonds[3].extend(hbond_acceptors.ids)
Expand Down Expand Up @@ -510,7 +508,7 @@ def count_by_type(self):
resname and atom type of the donor and acceptor atoms in a hydrogen
bond.
"""
u = self._universe()
u = self._universe
d = u.atoms[self.hbonds[:, 1].astype(np.int)]
a = u.atoms[self.hbonds[:, 3].astype(np.int)]

Expand Down Expand Up @@ -543,7 +541,7 @@ def count_by_ids(self):
hydrogen atom id and acceptor atom id in a hydrogen bond.
"""

u = self._universe()
u = self._universe
d = u.atoms[self.hbonds[:, 1].astype(np.int)]
h = u.atoms[self.hbonds[:, 2].astype(np.int)]
a = u.atoms[self.hbonds[:, 3].astype(np.int)]
Expand All @@ -560,14 +558,6 @@ def count_by_ids(self):

return unique_hbonds

def _universe(self):
# A Universe containing position information is needed for guessing
# donors and acceptors.
u = mda.Universe(self._top)
if not hasattr(u.atoms, 'positions'):
u.load_new(self._positions)
return u

@staticmethod
def _reduce(res, result_single_frame):
""" Use numpy array append to combine results"""
Expand Down
Loading