Source code for mosaic.molecular_structure
# -*- coding: utf-8 -*-
"""Molecular structure utilities
.. moduleauthor:: Konrad Hinsen
Utilities for working with hierarchical molecular structures.
"""
#-----------------------------------------------------------------------------
# Copyright (C) 2014 The Mosaic Development Team
#
# Distributed under the terms of the BSD License. The full license is in
# the file LICENSE.txt, distributed as part of this software.
#-----------------------------------------------------------------------------
[docs]class FragmentIterator(object):
"""Iterator over fragments that match some predicate
Usage example for iterating over peptide chains:
def peptide_predicate(fragment):
return fragment.is_polymer and fragment.polymer_type == 'polypeptide'
for chain, atom_index, site_index in FragmentIterator(universe, peptide_predicate):
...
"""
class PseudoFragment(object):
def __init__(self, universe, template=False):
if template:
self.fragments = [f for f, c in universe.molecules]
else:
self.fragments = sum([c*[f]
for f, c in universe.molecules],
[])
self.atoms = ()
is_polymer = False
def __init__(self, universe, predicate,
descend_on_match=False, template=False):
"""
:parameter universe: a universe
:type universe: :class:`mosaic.api.MosaicUniverse`
:parameter predicate: an object called with the fragment as its only
argument and expected to return True or False
:type predicate: callable
:parameter descend_on_match: if True, iterate over the subfragments
of fragments that match the predicate
:type descend_on_match: bool
:parameter template: if True, iterate over template fragments,
otherwise iterate over molecules
:type template: bool
"""
self.predicate = predicate
self.descend_on_match = descend_on_match
self.stack = [FragmentIterator.PseudoFragment(universe, template)]
self.atom_index = 0
self.site_index = 0
def __iter__(self):
return self
def __next__(self):
while self.stack:
item = self.stack.pop(0)
if isinstance(item, tuple):
a, s = item
self.atom_index += a
self.site_index += s
else:
match = None
push = []
if not isinstance(item, FragmentIterator.PseudoFragment) \
and self.predicate(item):
match = (item, self.atom_index, self.site_index)
if self.descend_on_match:
push.extend(item.fragments)
else:
for f in item.fragments:
push.append((f.number_of_atoms, f.number_of_sites))
else:
push.extend(item.fragments)
push.append((len(item.atoms),
sum(a.number_of_sites
for a in item.atoms)))
for new_item in reversed(push):
self.stack.insert(0, new_item)
if match is not None:
return match
raise StopIteration
next = __next__