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

92 calculate trajectory profiles #98

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
2 changes: 2 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ python:
- "3.7"
- "3.6"

cache: pip

env: PYTHONPATH=$PYTHONPATH:$TRAVIS_BUILD_DIR/tests

before_install:
Expand Down
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