Skip to content

Commit

Permalink
Closes #92 by calculating trajectories for entire profiles.
Browse files Browse the repository at this point in the history
  • Loading branch information
ConnorPigg committed Jun 12, 2019
1 parent e8efe5f commit ba7ee0c
Show file tree
Hide file tree
Showing 6 changed files with 1,086 additions and 8 deletions.
2 changes: 2 additions & 0 deletions idpflex/properties.py
Original file line number Diff line number Diff line change
Expand Up @@ -1372,6 +1372,7 @@ class SansProperty(ProfileProperty, SansLoaderMixin):

def __init__(self, *args, **kwargs):
ProfileProperty.__init__(self, *args, **kwargs)
self.from_pdb = self.from_cryson_pdb
if self.name is None:
self.name = SansProperty.default_name

Expand Down Expand Up @@ -1510,6 +1511,7 @@ class SaxsProperty(ProfileProperty, SaxsLoaderMixin):

def __init__(self, *args, **kwargs):
ProfileProperty.__init__(self, *args, **kwargs)
self.from_pdb = self.from_crysol_pdb
if self.name is None:
self.name = SaxsProperty.default_name

Expand Down
62 changes: 56 additions & 6 deletions idpflex/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,34 @@
from contextlib import contextmanager
import tempfile
import functools
import multiprocessing
from collections import namedtuple, Mapping

import MDAnalysis as mda


def write_frame(a_universe, iframe, file_name):
def write_frame(atom_group, iframe, file_name):
r"""Write a single trajectory frame to file.
Format is guessed from the file's extension.
Parameters
----------
a_universe : :class:`~MDAnalysis.core.universe.Universe`
Universe describing the simulation
atom_group : :class:`~MDAnalysis.AtomGroup`
Atoms from the universe describing the simulation
iframe : int
Trajectory frame index (indexes begin with zero)
file_name : str
Name of the file to create
"""
a_universe.trajectory[iframe]
atom_group.universe.trajectory[iframe]
# Create directory if not existing
dir_name = os.path.dirname(file_name)
if dir_name and not os.path.isdir(dir_name):
os.makedirs(dir_name)

with mda.Writer(file_name) as writer:
writer.write(a_universe)
writer.write(atom_group)


@contextmanager
Expand Down Expand Up @@ -58,7 +59,7 @@ def namedtuplefy(func):
Parameters
----------
func: Function
func: function
Function to be decorated
name: str
Class name for the namedtuple. If None, the name of the function
Expand All @@ -78,3 +79,52 @@ def wrapper(*args, **kwargs):
return wrapper.nt(**res)
wrapper.nt = None
return wrapper


def generate_profile_for_frame(atom_group, iframe, profile_class):
r"""
Utility function to generate profile properties for a frame in a trajectory.
Parameters
----------
atom_group: :class:`MDAnalysis.AtomGroup`
The atom group representing the structure to calculate the profile for.
iframe: int
The index of a trajectory for which to calculate profiles of the associated atom_group.
profile_class:
The profile class to use for the properties to be returned and calculated. Must implement a `from_pdb` method.
Returns
-------
Profile for the selected frame
""" # noqa: E501
with temporary_file(suffix='.pdb') as fname:
# Copy the atom group to a new universe to avoid
# changing frames upon writing
u = atom_group.universe
u2 = mda.Universe(u.filename, u.trajectory.filename)
atoms2 = u2.atoms[atom_group.atoms.indices]
write_frame(atoms2, iframe, fname)
return profile_class().from_pdb(fname)


def generate_trajectory_profiles(atom_group, iframes, profile_class):
r"""
Utility function to generate profile properties for each frame in a trajectory.
Parameters
----------
atom_group: :class:`MDAnalysis.AtomGroup`
The atom group representing the structure to calculate the profile for.
iframes: List[int]
The indices of a trajectory for which to calculate profiles of the associated atom_group.
profile_class:
The profile class to use for the properties to be returned and calculated. Must implement a `from_pdb` method.
Returns
-------
List of the profiles.
""" # noqa: E501
with multiprocessing.Pool() as p:
return p.starmap(generate_profile_for_frame,
[(atom_group, i, profile_class) for i in iframes])
10 changes: 8 additions & 2 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,14 +106,17 @@ def saxs_benchmark():
'crysol_pdb': absolute path to file.
'crysol_int': absolute path to file.
'crysol_xtc': absolute path to file.
'frame_profile': absolute path to file.
"""

crysol_file = os.path.join(data_dir, 'saxs', 'crysol.dat')
crysol_pdb = os.path.join(data_dir, 'saxs', 'md_0_1.pdb')
crysol_int = os.path.join(data_dir, 'saxs', 'md_0_100.int')
crysol_xtc = os.path.join(data_dir, 'saxs', 'md_0_1_noPBC.xtc')
frame_profile = os.path.join(data_dir, 'saxs', 'trajectory_3_profile.dat')
return dict(crysol_file=crysol_file, crysol_pdb=crysol_pdb,
crysol_int=crysol_int, crysol_xtc=crysol_xtc)
crysol_int=crysol_int, crysol_xtc=crysol_xtc,
frame_profile=frame_profile)


@pytest.fixture(scope='session')
Expand All @@ -130,6 +133,7 @@ def sans_benchmark(request):
'cryson_pdb': absolute path to file.
'cryson_int': absolute path to file.
'cryson_xtc': absolute path to file.
'frame_profile': absolute path to file.
"""

# setup or initialization
Expand All @@ -153,13 +157,15 @@ def sans_benchmark(request):
cryson_pdb = os.path.join(data_dir, 'saxs', 'md_0_1.pdb')
cryson_int = os.path.join(data_dir, 'sans', 'md_0_100.int')
cryson_xtc = os.path.join(data_dir, 'saxs', 'md_0_1_noPBC.xtc')
frame_profile = os.path.join(data_dir, 'sans', 'trajectory_3_profile.dat')

def teardown():
handle.close()
request.addfinalizer(teardown)
return dict(profiles=handle, property_list=values,
tree_with_no_property=tree, cryson_pdb=cryson_pdb,
cryson_int=cryson_int, cryson_xtc=cryson_xtc)
cryson_int=cryson_int, cryson_xtc=cryson_xtc,
frame_profile=frame_profile)


@pytest.fixture(scope='session')
Expand Down
Loading

0 comments on commit ba7ee0c

Please sign in to comment.