"""
The central interface for reading and editing Maestro format chemical
sructures with force field data.
`FFIOStructure` is a pythonic, object oriented wrapper for the mmffio library
that provides access to sites, bonds, angles, dihedrals, exclusions, pairs,
vdwtypes, restraints, virtuals, pseudos, constraints and their properties.
It inherits from `Structure` and hence provides access to atoms, bonds and
their properties.
The default error handler for the ffiostructure module is set to
mm.error_handler. If no error handler is specified for error_handler arguments,
its value is what will be used.
Copyright Schrodinger, LLC. All rights reserved.
"""
import os
from collections.abc import MutableMapping
from schrodinger.application.desmond import constants
from schrodinger.infra import mm
from schrodinger.infra.util import CreateWhenNeeded
from schrodinger.structure import Structure
from schrodinger.structure import write_ct_to_string
__all__ = [
'FFIOStructure',
'CMSReader',
'write_cms',
]
# Dictionaries linking built-in property names of different standard force field blocks
# to thier short names(to be used to get/set from python interfaces), mmffio getter and
# setter methods. When the value is empty list, they are deduced from property names
ffio_sub_block_prop_links = {
'site': {
's_ffio_type': [
'type', mm.mmffio_site_get_type, mm.mmffio_site_set_type
],
's_ffio_site': [
'site', mm.mmffio_site_get_site_name, mm.mmffio_site_set_site_name
],
'r_ffio_charge': [
'charge', mm.mmffio_site_get_charge, mm.mmffio_site_set_charge
],
'r_ffio_mass': [
'mass', mm.mmffio_site_get_mass, mm.mmffio_site_set_mass
],
's_ffio_vdwtype': [
'vdwtype', mm.mmffio_site_get_vdwtype, mm.mmffio_site_set_vdwtype
],
'r_ffio_c1': ['c1', mm.mmffio_site_get_c1, mm.mmffio_site_set_c1],
'r_ffio_c2': ['c2', mm.mmffio_site_get_c2, mm.mmffio_site_set_c2]
},
'bond': {
'i_ffio_ai': [],
'i_ffio_aj': [],
's_ffio_funct': [],
'r_ffio_c1': [],
'r_ffio_c2': []
},
'angle': {
'i_ffio_ai': [],
'i_ffio_aj': [],
'i_ffio_ak': [],
's_ffio_funct': [],
'r_ffio_c1': [],
'r_ffio_c2': []
},
'dihedral': {
'i_ffio_ai': [],
'i_ffio_aj': [],
'i_ffio_ak': [],
'i_ffio_al': [],
's_ffio_funct': [],
'i_ffio_i1': [],
'r_ffio_c0': [],
'r_ffio_c1': [],
'r_ffio_c2': [],
'r_ffio_c3': [],
'r_ffio_c4': [],
'r_ffio_c5': [],
'r_ffio_c6': [],
'r_ffio_c7': [],
'r_ffio_t1': [],
},
'exclusion': {
'i_ffio_ai': [],
'i_ffio_aj': []
},
'pair': {
'i_ffio_ai': [],
'i_ffio_aj': [],
's_ffio_funct': [],
'r_ffio_c1': [],
'r_ffio_c2': []
},
'vdwtype': {
's_ffio_name': [],
's_ffio_funct': [],
'r_ffio_c1': [],
'r_ffio_c2': [],
'r_ffio_t1': [],
},
'vdwtypescombined': {
's_ffio_name1': [],
's_ffio_name2': [],
's_ffio_funct': [],
'r_ffio_c1': [],
'r_ffio_c2': [],
'r_ffio_t1': [],
},
'restraint': {
'i_ffio_ai': [],
's_ffio_funct': [],
'r_ffio_c1': [],
'r_ffio_c2': [],
'r_ffio_c3': [],
'r_ffio_t1': [],
'r_ffio_t2': [],
'r_ffio_t3': [],
},
'virtual': {
'i_ffio_index': [
'virtual_index', mm.mmffio_virtual_get_index,
mm.mmffio_virtual_set_index
],
'i_ffio_ai': [],
'i_ffio_aj': [],
'i_ffio_ak': [],
'i_ffio_al': [],
'i_ffio_am': [],
'i_ffio_an': [],
's_ffio_funct': [],
'r_ffio_c1': [],
'r_ffio_c2': [],
'r_ffio_c3': [],
'r_ffio_c4': [],
'r_ffio_c5': [],
'r_ffio_c6': [],
},
'pseudo': {
'r_ffio_x_coord': [
'x_coord', mm.mmffio_pseudo_get_x_coord,
mm.mmffio_pseudo_set_x_coord
],
'r_ffio_y_coord': [
'y_coord', mm.mmffio_pseudo_get_y_coord,
mm.mmffio_pseudo_set_y_coord
],
'r_ffio_z_coord': [
'z_coord', mm.mmffio_pseudo_get_z_coord,
mm.mmffio_pseudo_set_z_coord
],
'r_ffio_x_vel': [
'x_vel', mm.mmffio_pseudo_get_x_vel, mm.mmffio_pseudo_set_x_vel
],
'r_ffio_y_vel': [
'y_vel', mm.mmffio_pseudo_get_y_vel, mm.mmffio_pseudo_set_y_vel
],
'r_ffio_z_vel': [
'z_vel', mm.mmffio_pseudo_get_z_vel, mm.mmffio_pseudo_set_z_vel
],
},
'constraint': {
'i_ffio_ai': [],
'i_ffio_aj': [],
'i_ffio_ak': [],
'i_ffio_al': [],
'i_ffio_am': [],
's_ffio_funct': [],
'r_ffio_c1': [],
'r_ffio_c2': [],
'r_ffio_c3': [],
'r_ffio_c4': [],
'r_ffio_c5': [],
'r_ffio_c6': []
},
'posfbhw': {
'i_ffio_ai': [],
'r_ffio_sigma': [],
'r_ffio_fc': [],
'r_ffio_x0': [],
'r_ffio_y0': [],
'r_ffio_z0': []
},
'anglefbhw': {
'i_ffio_ai': [],
'i_ffio_aj': [],
'i_ffio_ak': [],
'r_ffio_sigma': [],
'r_ffio_fc': [],
'r_ffio_theta0': []
},
'improperfbhw': {
'i_ffio_ai': [],
'i_ffio_aj': [],
'i_ffio_ak': [],
'i_ffio_al': [],
'r_ffio_sigma': [],
'r_ffio_fc': [],
'r_ffio_phi0': []
},
'stretchfbhw': {
's_ffio_group1': [],
's_ffio_group2': [],
'r_ffio_lower': [],
'r_ffio_upper': [],
'r_ffio_sigma': [],
'r_ffio_fc': [],
'r_ffio_beta': []
}
}
ffio_block_names = {
'site': 'site',
'bond': 'bond',
'angle': 'angle',
'dihedral': 'dihed',
'exclusion': 'excl',
'pair': 'pair',
'vdwtype': 'vdwtype',
'restraint': 'restraint',
'virtual': 'virtual',
'pseudo': 'pseudo',
'constraint': 'constraint',
'posfbhw': 'posfbhw',
'anglefbhw': 'anglefbhw',
'improperfbhw': 'improperfbhw',
'stretchfbhw': 'stretchfbhw',
'vdwtypescombined': 'vdwtypescombined',
}
prop_type_names = {
"s": "string",
"i": "int",
"r": "real",
"b": "boolean",
}
[docs]def make_property(getter, setter, doc):
def _get(self):
return getter(self._ff.handle, self._index)
def _set(self, value):
setter(self._ff.handle, self._index, value)
return property(_get, _set, doc=doc)
[docs]def get_ffio_sub_block_std_prop_short_name(block_type, prop_name):
"""
Function to get short names of properties. It is picked from the
ffio_sub_block_prop_links dict if avaiable, else deduced from property name
"""
if ffio_sub_block_prop_links[block_type][prop_name] == []:
short_name = prop_name.split('_')[-1]
else:
short_name = ffio_sub_block_prop_links[block_type][prop_name][0]
return short_name
[docs]def get_ffio_sub_block_std_prop_getter(block_type, prop_name):
"""
Function to get mmffio getter method of properties. It is picked from the
ffio_sub_block_prop_links dict if avaiable, else deduced from property name
"""
if ffio_sub_block_prop_links[block_type][prop_name] == []:
short_name = prop_name.split('_')[-1]
func = getattr(
mm, "mmffio_%s_get_%s" % (ffio_block_names[block_type], short_name))
else:
func = ffio_sub_block_prop_links[block_type][prop_name][1]
return func
[docs]def get_ffio_sub_block_std_prop_setter(block_type, prop_name):
"""
Function to get mmffio setter method of properties. It is picked from the
ffio_sub_block_prop_links dict if avaiable, else deduced from property name
"""
if ffio_sub_block_prop_links[block_type][prop_name] == []:
short_name = prop_name.split('_')[-1]
func = getattr(
mm, "mmffio_%s_set_%s" % (ffio_block_names[block_type], short_name))
else:
func = ffio_sub_block_prop_links[block_type][prop_name][2]
return func
class _BlockPropertyBase(MutableMapping):
"""
Base class to override common abstract methods
"""
def __delitem__(self, item):
pass
def __iter__(self):
for k in self.keys():
yield k
def __len__(self):
return len(self.keys())
class _FFIOSubBlockProperty(_BlockPropertyBase):
"""
A dictionary of ffio sub-block properties. These can be accessed via the
property name as it appears in the maestro file.
Property names must be m2io data names, which are in the format
'<type>_<author>_<property_name>', where '<type>' is a data type prefix,
'<author>' is a source specification, and '<property_name>' is the
actual name of the data.
The data type prefix can specified as 's' for string, 'i' for integer,
'r' for real and 'b' for boolean. The author specification should be
'user' for user created properties. The property name can have embedded
underscores.
Some example m2io datanames are 'r_ffio_x_coord', which indicates a
real property named 'x coord', and 'i_user_my_count' which indicates
an integer user property named 'my count'.
"""
def __init__(self, ff, index, type):
"""Create an instance of the property dictionary. """
self._ff = ff
self._index = index
self._type = type
def __getitem__(self, item):
"""
Return the given item if it is a valid property for this item,
None if not.
"""
# Check to see if property is built-in:
builtin = ffio_sub_block_prop_links.get(self._type).get(item)
if builtin is not None:
short_name = get_ffio_sub_block_std_prop_short_name(
self._type, item)
return getattr(
getattr(self._ff, self._type)[self._index], short_name)
try:
func = getattr(
mm, "mmffio_%s_prop_get_%s" %
(ffio_block_names[self._type], prop_type_names[item[0]]))
ret = func(self._ff.handle, item, self._index)
except mm.MmException as e:
raise KeyError("%s is not the name of an %s property" %
(item, self._type))
except IndexError as e:
if item == "":
raise KeyError("The empty string is an invalid dataname.")
else:
raise
return ret
def __setitem__(self, item, value):
"""Set properties for the given item. """
builtin = ffio_sub_block_prop_links.get(self._type).get(item)
if builtin is not None:
short_name = get_ffio_sub_block_std_prop_short_name(
self._type, item)
setattr(
getattr(self._ff, self._type)[self._index], short_name, value)
return
func = getattr(
mm, "mmffio_%s_prop_set_%s" %
(ffio_block_names[self._type], prop_type_names[item[0]]))
func(self._ff.handle, item, self._index, value)
def keys(self):
"""
Return a list of all property names.
"""
func = getattr(
mm, "mmffio_%s_get_data_names" % ffio_block_names[self._type])
pnames = func(self._ff.handle, self._index, mm.M2IO_ALL_TYPES)
return list(ffio_sub_block_prop_links.get(self._type)) + pnames
class _FFIOSubBlockMeta(type):
"""
A meta-class to different ffio sub block type classses. This simplifies
adding property descriptors for different sub-block types
"""
def __init__(cls, name, bases, dict):
super(_FFIOSubBlockMeta, cls).__init__(name, bases, dict)
block_type = cls.block_type
for prop in list(ffio_sub_block_prop_links[block_type]):
prop_name = get_ffio_sub_block_std_prop_short_name(block_type, prop)
prop_getter = get_ffio_sub_block_std_prop_getter(block_type, prop)
prop_setter = get_ffio_sub_block_std_prop_setter(block_type, prop)
doc = "%s %s" % (block_type, prop_name)
setattr(cls, prop_name, make_property(prop_getter, prop_setter,
doc))
class _FFIOSubBlock:
"""
A class to make access of ffio sub-block properties more pythonic.
"""
block_type = None
def __init__(self, ff, _index):
self._ff = ff
self._index = _index
self._property = None
def __eq__(self, that):
"""
Compare on ff handle and index.
"""
if self._ff == that._ff and self._index == that._index and type(
self) == type(that):
return True
else:
return False
def __ne__(self, other):
"""
Check for inequality based on ff handle and index.
"""
return not self.__eq__(other)
def __hash__(self):
return hash(self._ff.handle) ^ self._index
def __index__(self):
return self._index
def __str__(self):
return "%s(%d)" % (self.block_type, int(self))
# index
def _getIndex(self):
return self._index
index = property(_getIndex, doc="The item index. I{Read only.}")
# property
def _getProperty(self):
if self._property is None:
self._property = _FFIOSubBlockProperty(self._ff, self._index,
self.block_type)
return self._property
property = property(_getProperty, doc="property dictionary")
class _FFIOSite(_FFIOSubBlock, metaclass=_FFIOSubBlockMeta):
"""
A class to make access of mmffio site properties more pythonic.
"""
block_type = "site"
class _FFIOBond(_FFIOSubBlock, metaclass=_FFIOSubBlockMeta):
"""
A class to make access of mmffio bond properties more pythonic.
"""
block_type = "bond"
class _FFIOAngle(_FFIOSubBlock, metaclass=_FFIOSubBlockMeta):
"""
A class to make access of mmffio angle properties more pythonic.
"""
block_type = "angle"
class _FFIODihedral(_FFIOSubBlock, metaclass=_FFIOSubBlockMeta):
"""
A class to make access of mmffio dihedral properties more pythonic.
"""
block_type = "dihedral"
class _FFIOExclusion(_FFIOSubBlock, metaclass=_FFIOSubBlockMeta):
"""
A class to make access of mmffio exclusion properties more pythonic.
"""
block_type = "exclusion"
class _FFIOPair(_FFIOSubBlock, metaclass=_FFIOSubBlockMeta):
"""
A class to make access of mmffio pair properties more pythonic.
"""
block_type = "pair"
class _FFIOVdwtype(_FFIOSubBlock, metaclass=_FFIOSubBlockMeta):
"""
A class to make access of mmffio vdwtype properties more pythonic.
"""
block_type = "vdwtype"
class _FFIOVdwtypescombined(_FFIOSubBlock, metaclass=_FFIOSubBlockMeta):
"""
A class to make access of mmffio vdwtype properties more pythonic.
"""
block_type = "vdwtypescombined"
class _FFIORestraint(_FFIOSubBlock, metaclass=_FFIOSubBlockMeta):
"""
A class to make access of mmffio restraint properties more pythonic.
"""
block_type = "restraint"
class _FFIOVirtual(_FFIOSubBlock, metaclass=_FFIOSubBlockMeta):
"""
A class to make access of mmffio virtual properties more pythonic.
"""
block_type = "virtual"
class _FFIOPseudo(_FFIOSubBlock, metaclass=_FFIOSubBlockMeta):
"""
A class to make access of mmffio pseudo properties more pythonic.
"""
block_type = "pseudo"
class _FFIOConstraint(_FFIOSubBlock, metaclass=_FFIOSubBlockMeta):
"""
A class to make access of mmffio constraint properties more pythonic.
"""
block_type = "constraint"
class _FFIOPosFBHW(_FFIOSubBlock, metaclass=_FFIOSubBlockMeta):
"""
A class to make access of mmffio position flat bottom properties more pythonic.
"""
block_type = "posfbhw"
class _FFIOAngleFBHW(_FFIOSubBlock, metaclass=_FFIOSubBlockMeta):
"""
A class to make access of mmffio angle flat bottom properties more pythonic.
"""
block_type = "anglefbhw"
class _FFIOImproperFBHW(_FFIOSubBlock, metaclass=_FFIOSubBlockMeta):
"""
A class to make access of mmffio improper flat bottom properties more pythonic.
"""
block_type = "improperfbhw"
class _FFIOStretchFBHW(_FFIOSubBlock, metaclass=_FFIOSubBlockMeta):
"""
A class to make access of mmffio stretch flat bottom properties more pythonic.
"""
block_type = "stretchfbhw"
class _FFIOSubBlockContainer:
def __init__(self, ff):
"""
Initialize the container.
"""
self._ff = ff
def _item_count_method(self):
raise NotImplementedError()
def _item_delete_method(self, index):
raise NotImplementedError()
_item_class = None
def __delitem__(self, index):
"""
Delete a ffio sub-block item from the CT. Note that this immediately updates
the CT and therefore renumbers any items following the one deleted.
"""
if index < 1 or index > len(self):
raise IndexError("Index out of range [1, %d]: %d" % (
len(self),
index,
))
self._item_delete_method(self._ff.handle, index)
def __getitem__(self, index):
"""
Return the wrapper class for ffio sub-block item based properties.
Note that the initial index is 1, as per the underlying mmffio library,
not 0 as is expected for python.
"""
if index < 1 or index > len(self):
raise IndexError("Index out of range [1, %d]: %d" % (
len(self),
index,
))
return self._item_class(self._ff, index)
def __iter__(self):
"""
Provide iteration access.
"""
for i in range(1, len(self) + 1):
yield self._item_class(self._ff, i)
def __len__(self):
"""
Return the number of items.
"""
return self._item_count_method(self._ff.handle)
class _FFIOSiteContainer(_FFIOSubBlockContainer):
_item_count_method = mm.mmffio_ff_get_num_sites
_item_delete_method = mm.mmffio_delete_site
_item_class = _FFIOSite
class _FFIOBondContainer(_FFIOSubBlockContainer):
_item_count_method = mm.mmffio_ff_get_num_bonds
_item_delete_method = mm.mmffio_delete_bond
_item_class = _FFIOBond
class _FFIOAngleContainer(_FFIOSubBlockContainer):
_item_count_method = mm.mmffio_ff_get_num_angles
_item_delete_method = mm.mmffio_delete_angle
_item_class = _FFIOAngle
class _FFIODihedralContainer(_FFIOSubBlockContainer):
_item_count_method = mm.mmffio_ff_get_num_diheds
_item_delete_method = mm.mmffio_delete_dihed
_item_class = _FFIODihedral
class _FFIOExclusionContainer(_FFIOSubBlockContainer):
_item_count_method = mm.mmffio_ff_get_num_excls
_item_delete_method = mm.mmffio_delete_excl
_item_class = _FFIOExclusion
class _FFIOPairContainer(_FFIOSubBlockContainer):
_item_count_method = mm.mmffio_ff_get_num_pairs
_item_delete_method = mm.mmffio_delete_pair
_item_class = _FFIOPair
class _FFIOVdwtypeContainer(_FFIOSubBlockContainer):
_item_count_method = mm.mmffio_ff_get_num_vdwtypes
_item_delete_method = mm.mmffio_delete_vdwtype
_item_class = _FFIOVdwtype
class _FFIOVdwtypescombinedContainer(_FFIOSubBlockContainer):
_item_count_method = mm.mmffio_ff_get_num_vdwtypescombineds
_item_delete_method = mm.mmffio_delete_vdwtypescombined
_item_class = _FFIOVdwtypescombined
class _FFIORestraintContainer(_FFIOSubBlockContainer):
_item_count_method = mm.mmffio_ff_get_num_restraints
_item_delete_method = mm.mmffio_delete_restraint
_item_class = _FFIORestraint
class _FFIOVirtualContainer(_FFIOSubBlockContainer):
_item_count_method = mm.mmffio_ff_get_num_virtuals
_item_delete_method = mm.mmffio_delete_virtual
_item_class = _FFIOVirtual
class _FFIOPseudoContainer(_FFIOSubBlockContainer):
_item_count_method = mm.mmffio_ff_get_num_pseudos
_item_delete_method = mm.mmffio_delete_pseudo
_item_class = _FFIOPseudo
class _FFIOConstraintContainer(_FFIOSubBlockContainer):
_item_count_method = mm.mmffio_ff_get_num_constraints
_item_delete_method = mm.mmffio_delete_constraint
_item_class = _FFIOConstraint
class _FFIOPosFBHWContainer(_FFIOSubBlockContainer):
_item_count_method = mm.mmffio_ff_get_num_posfbhws
_item_delete_method = mm.mmffio_delete_posfbhw
_item_class = _FFIOPosFBHW
class _FFIOAngleFBHWContainer(_FFIOSubBlockContainer):
_item_count_method = mm.mmffio_ff_get_num_anglefbhws
_item_delete_method = mm.mmffio_delete_anglefbhw
_item_class = _FFIOAngleFBHW
class _FFIOImproperFBHWContainer(_FFIOSubBlockContainer):
_item_count_method = mm.mmffio_ff_get_num_improperfbhws
_item_delete_method = mm.mmffio_delete_improperfbhw
_item_class = _FFIOImproperFBHW
class _FFIOStretchFBHWContainer(_FFIOSubBlockContainer):
_item_count_method = mm.mmffio_ff_get_num_stretchfbhws
_item_delete_method = mm.mmffio_delete_stretchfbhw
_item_class = _FFIOStretchFBHW
class _ElementProperty(_BlockPropertyBase):
"""
A dictionary of other_block element based properties. These can be accessed via
the property name as it appears in the maestro file.
Property names must be m2io data names, which are in the format
'<type>_<author>_<property_name>', where '<type>' is a data type prefix,
'<author>' is a source specification, and '<property_name>' is the
actual name of the data.
The data type prefix can specified as 's' for string, 'i' for integer,
'r' for real and 'b' for boolean. The author specification should be
'user' for user created properties. The property name can have embedded
underscores.
Some example m2io datanames are 'r_m_x_coord', which indicates a real
maestro property named 'x coord', and 'i_user_my_count' which indicates
an integer user property named 'my count'.
"""
def __init__(self, handle, block_num, index):
"""Create an instance of the property dictionary. """
self.handle = handle
self._block_num = block_num
self._index = index
def _getBoolean(self, block_num, index, name):
raise NotImplementedError()
def _getInt(self, block_num, index, name):
raise NotImplementedError()
def _getReal(self, block_num, index, name):
raise NotImplementedError()
def _getString(self, block_num, index, name):
raise NotImplementedError()
def _setBoolean(self, block_num, index, name, value):
raise NotImplementedError()
def _setInt(self, block_num, index, name, value):
raise NotImplementedError()
def _setReal(self, block_num, index, name, value):
raise NotImplementedError()
def _setString(self, block_num, index, name, value):
raise NotImplementedError()
def _data_names_method(self, block_num, index, flag):
raise NotImplementedError()
def __getitem__(self, item):
"""
Return the given item if it is a valid property for this element,
None if not.
"""
try:
if item[0] == "s":
ret = self._getString(self.handle, self._block_num, self._index,
item)
elif item[0] == "i":
ret = self._getInt(self.handle, self._block_num, self._index,
item)
elif item[0] == "r":
ret = self._getReal(self.handle, self._block_num, self._index,
item)
elif item[0] == "b":
ret = self._getBoolean(self.handle, self._block_num,
self._index, item)
else:
raise KeyError("%s is an invalid dataname" % item)
except mm.MmException as e:
raise KeyError("%s is not the name of an element property" % item)
except IndexError as e:
if item == "":
raise KeyError("The empty string is an invalid dataname.")
else:
raise
return ret
def __setitem__(self, item, value):
"""Set element properties """
if item[0] == "s":
self._setString(self.handle, self._block_num, self._index, item,
value)
elif item[0] == "i":
self._setInt(self.handle, self._block_num, self._index, item, value)
elif item[0] == "r":
self._setReal(self.handle, self._block_num, self._index, item,
value)
elif item[0] == "b":
self._setBoolean(self.handle, self._block_num, self._index, item,
value)
else:
raise KeyError(
"%s is an invalid property name; see _FFIOElementProperty documentation for details."
% item)
def keys(self):
"""
Return a list of the names of all properties.
"""
return self._data_names_method(self.handle, self._block_num,
self._index, mm.M2IO_ALL_TYPES)
class _FFIOElementProperty(_ElementProperty):
_getInt = mm.mmffio_element_prop_get_int
_getReal = mm.mmffio_element_prop_get_real
_getBoolean = mm.mmffio_element_prop_get_boolean
_getString = mm.mmffio_element_prop_get_string
_setInt = mm.mmffio_element_prop_set_int
_setReal = mm.mmffio_element_prop_set_real
_setBoolean = mm.mmffio_element_prop_set_boolean
_setString = mm.mmffio_element_prop_set_string
_data_names_method = mm.mmffio_element_get_data_names
class _Element:
def __init__(self, handle, block_num, index):
self.handle = handle
self._block_num = block_num
self._index = index
self._property = None
_property_class = None
# property
def _getElementProperty(self):
if self._property is None:
self._property = self._property_class(self.handle, self._block_num,
self._index)
return self._property
property = property(_getElementProperty, doc="Element property dictionary")
class _FFIOElement(_Element):
_property_class = _FFIOElementProperty
class _OtherBlock:
def __init__(self, handle, block_num):
self.handle = handle
self._block_num = block_num
# index
def _getIndex(self):
return self._block_num
index = property(_getIndex, doc="The block number. I{Read only.}")
def _get_name_method(self, block_num):
raise NotImplementedError()
def _set_name_method(self, block_num, value):
raise NotImplementedError()
def _num_elements_method(self, block_num):
raise NotImplementedError()
def _add_elements_method(handle, block_num, num_elements):
raise NotImplementedError()
def _delete_element_method(handle, block_num, element_num):
raise NotImplementedError()
_element_class = None
def _getName(self):
return self._get_name_method(self.handle, self._block_num)
def _setName(self, value):
self._set_name_method(self.handle, self._block_num, value)
name = property(_getName, _setName, doc="other block name.")
def __getitem__(self, index):
"""
Return the wrapper class for ffio constraint based properties. Note that
the initial index is 1, as per the underlying library, not 0 as is expected
for python.
"""
if index < 1 or index > len(self):
raise IndexError("Index out of range [1, %d]: %d" % (
len(self),
index,
))
return self._element_class(self.handle, self._block_num, index)
def __iter__(self):
"""
Provide iteration access.
"""
for i in range(1, len(self) + 1):
yield self._element_class(self.handle, self._block_num, i)
def __len__(self):
"""
Return the number of elements in this block
"""
return self._num_elements_method(self.handle, self._block_num)
def addElement(self):
"""
Add a new element to this block and return it.
"""
self._add_elements_method(self.handle, self._block_num, 1)
return self._element_class(self.handle, self._block_num, len(self))
def addElements(self, num_elements):
"""
Add the specified number of other elements to this block.
"""
self._add_elements_method(self.handle, self._block_num, num_elements)
def deleteElements(self, indices):
"""
Delete multiple elements from this block. The argument indices must be a
sequence or an iterable, and able to be interpreted as ints.
After deletion, indices are renumbered from 1 to len(self).
"""
# Be sure that deleting is done from highest index to lowest.
indices = [int(i) for i in indices]
indices.sort()
indices.reverse()
for i in indices:
self._delete_element_method(self.handle, self._block_num, i)
class _FFIOOtherBlock(_OtherBlock):
_get_name_method = mm.mmffio_other_block_get_name
_set_name_method = mm.mmffio_other_block_set_name
_element_class = _FFIOElement
_num_elements_method = mm.mmffio_ff_get_num_elements
_add_elements_method = mm.mmffio_add_elements
_delete_element_method = mm.mmffio_delete_element
class _OtherBlockContainer:
"""The class to provide access to other block instances. """
def __init__(self, handle):
"""
Initialize the container.
"""
self.handle = handle
_other_block_class = None
def _block_names_method(handle):
raise NotImplementedError()
def __getitem__(self, index):
"""
Return an other block instance
"""
if index < 0 or index > len(self):
raise IndexError("Index out of range [1, %d]: %d" % (
len(self),
index,
))
return self._other_block_class(self.handle, index)
def __iter__(self):
"""
Provide iteration access.
"""
for i in range(0, len(self)):
yield self._other_block_class(self.handle, i)
def __len__(self):
"""
Return the number of other blocks.
"""
return len(self._block_names_method(self.handle))
class _FFIOOtherBlockContainer(_OtherBlockContainer):
_other_block_class = _FFIOOtherBlock
_block_names_method = mm.mmffio_other_get_block_names
class _FFIOProperty(_BlockPropertyBase):
"""
A dictionary of ffio properties, with all dict methods.
Properties can be accessed via the m2io dataname as it appears in the
maestro file.
Property names must be m2io data names, which are in the format
'<type>_<author>_<property_name>', where '<type>' is a data type prefix,
'<author>' is a source specification, and '<property_name>' is the
actual name of the data.
The data type prefix can specified as 's' for string, 'i' for integer,
'r' for real and 'b' for boolean. The author specification should be
'user' for user created properties. The property name can have embedded
underscores.
Some example m2io datanames are 'r_m_x_coord', which indicates a real
maestro property named 'x coord', and 'i_user_my_count' which indicates
an integer user property named 'my count'.
To convert to the _FFIOProperty to a real dictionary::
d = dict(st.ffio.property)
"""
def __init__(self, handle):
"""
Create an instance of the property 'dictionary' The instance is
created when st.property is first used.
"""
self._handle = handle
def __getitem__(self, item):
if item == 's_ffio_name':
return mm.mmffio_ff_get_name(self._handle)
if item == 'i_ffio_version':
return mm.mmffio_ff_get_version(self._handle)
if item == 's_ffio_comb_rule':
return mm.mmffio_ff_get_comb_rule(self._handle)
try:
if item[0] == "s":
ret = mm.mmffio_ff_get_string_data(self._handle, item)
elif item[0] == "i":
ret = mm.mmffio_ff_get_int_data(self._handle, item)
elif item[0] == "r":
ret = mm.mmffio_ff_get_real_data(self._handle, item)
elif item[0] == "b":
ret = mm.mmffio_ff_get_boolean_data(self._handle, item)
else:
raise KeyError("%s is an invalid dataname" % item)
return ret
except mm.MmException as e:
if e.rc == mm.MMFFIO_ERR:
raise KeyError("%s is not the name of a ffio property" % item)
except IndexError as e:
if item == "":
raise KeyError("The empty string is an invalid dataname.")
else:
raise
def __setitem__(self, item, value):
"""
Set the item into the additional data handle.
Usage: st.ffio.property[<name>] = value
"""
if item == 's_ffio_name':
return mm.mmffio_ff_set_name(self._handle, value)
if item == 'i_ffio_version':
return mm.mmffio_ff_set_version(self._handle, value)
if item == 's_ffio_comb_rule':
return mm.mmffio_ff_set_comb_rule(self._handle, value)
if item[0] == "s":
mm.mmffio_ff_add_string_data(self._handle, item, value)
elif item[0] == "i":
mm.mmffio_ff_add_int_data(self._handle, item, value)
elif item[0] == "r":
mm.mmffio_ff_add_real_data(self._handle, item, value)
elif item[0] == "b":
mm.mmffio_ff_add_boolean_data(self._handle, item, value)
else:
raise KeyError(
"%s is an invalid property name; see _FFIOProperty documentation for details."
% item)
def keys(self):
"""
Return a list of the names of all properties.
"""
ret = ['s_ffio_name', 'i_ffio_version', 's_ffio_comb_rule']
pnames = mm.mmffio_ff_get_data_names(self._handle, mm.M2IO_ALL_TYPES)
return ret + pnames
class _FFIO():
"""
A class to make access of ffio block pythonic.
"""
def __init__(self, ffhandle):
self.handle = ffhandle
self._other_block = None
self._property = None
# name
def _setName(self, name):
"""
Set the name for this ffio block
"""
mm.mmffio_ff_set_name(self.handle, name)
def _getName(self):
"""
Get the name for this ffio block
"""
return mm.mmffio_ff_get_name(self.handle)
name = property(_getName, _setName, doc="ffio block name")
# version
def _setVersion(self, version):
"""
Set the version
"""
mm.mmffio_ff_set_version(self.handle, version)
def _getVersion(self):
"""
Get the version
"""
return mm.mmffio_ff_get_version(self.handle)
version = property(_getVersion, _setVersion, doc="version")
# combining rule
def _setCombiningRule(self, combining_rule):
"""
Set the combining_rule
"""
mm.mmffio_ff_set_comb_rule(self.handle, combining_rule)
def _getCombiningRule(self):
"""
Get the combining_rule
"""
return mm.mmffio_ff_get_comb_rule(self.handle)
combining_rule = property(_getCombiningRule,
_setCombiningRule,
doc="combining rule")
#
# This section of the class definition consists of attributes to create
# on the fly, to avoid the cost of constructing them up front.
#
# The CreateWhenNeeded class is a descriptor that allows an attribute
# to be created on the fly. The first time the attribute is accessed,
# the function is called; whatever it returns is stored as the
# attribute and used in all future access.
#
def _createProxy(self):
"""
A method to create a proxy to be passed to subobjects that need to
hold a reference to the parent FFIO object. This prevents cyclic
references and therefore allows FFIO instances to be deallocated by
reference counting rather than waiting for a garbage collection sweep.
"""
return _FFIO(self.handle)
_proxy = CreateWhenNeeded(_createProxy, "_proxy")
_doc = """
A list of ffio sites, each of which is a `_FFIOSite`
instance.
Example usage, where `st` is a FFIOStructure instance::
# Access an site
siteobj = st.ffio.site[n]
# Delete an site
del st.ffio.site[n]
# Find the number of sites
len(st.ffio.site)
# Iterate over all sites
for site in st.ffio.site:
take_some_action(site)
:note: As with many other collections, the contents of the site list
should not be modified through additions or deletions while you are
iterating over it.
"""
def _createSiteContainer(self):
return _FFIOSiteContainer(self._proxy)
site = CreateWhenNeeded(_createSiteContainer, "site", _doc)
_doc = """
A list of ffio bonds, each of which is a `_FFIOBond`
instance.
Example usage, where `st` is a FFIOStructure instance::
# Access an bond
bondobj = st.ffio.bond[n]
# Delete an bond
del st.ffio.bond[n]
# Find the number of bonds
len(st.ffio.bond)
# Iterate over all bonds
for bond in st.ffio.bond:
take_some_action(bond)
:note: As with many other collections, the contents of the bond list
should not be modified through additions or deletions while you are
iterating over it.
"""
def _createFFIOBondContainer(self):
return _FFIOBondContainer(self._proxy)
bond = CreateWhenNeeded(_createFFIOBondContainer, "bond", _doc)
_doc = """
A list of ffio angles, each of which is a `_FFIOAngle`
instance.
Example usage, where `st` is a FFIOStructure instance::
# Access an angle
angleobj = st.ffio.angle[n]
# Delete an angle
del st.ffio.angle[n]
# Find the number of angles
len(st.ffio.angle)
# Iterate over all angles
for angle in st.ffio.angle:
take_some_action(angle)
:note: As with many other collections, the contents of the angle list
should not be modified through additions or deletions while you are
iterating over it.
"""
def _createFFIOAngleContainer(self):
return _FFIOAngleContainer(self._proxy)
angle = CreateWhenNeeded(_createFFIOAngleContainer, "angle", _doc)
_doc = """
A list of ffio dihedrals, each of which is a `_FFIODihedral`
instance.
Example usage, where `st` is a FFIOStructure instance::
# Access an dihedral
dihedralobj = st.ffio.dihedral[n]
# Delete an dihedral
del st.ffio.dihedral[n]
# Find the number of dihedrals
len(st.ffio.dihedral)
# Iterate over all dihedrals
for dihedral in st.ffio.dihedral:
take_some_action(dihedral)
:note: As with many other collections, the contents of the dihedral list
should not be modified through additions or deletions while you are
iterating over it.
"""
def _createFFIODihedralContainer(self):
return _FFIODihedralContainer(self._proxy)
dihedral = CreateWhenNeeded(_createFFIODihedralContainer, "dihedral", _doc)
_doc = """
A list of ffio exclusions, each of which is a `_FFIOExclusion`
instance.
Example usage, where `st` is a FFIOStructure instance::
# Access an exclusion
exclusionobj = st.ffio.exclusion[n]
# Delete an exclusion
del st.ffio.exclusion[n]
# Find the number of exclusions
len(st.ffio.exclusion)
# Iterate over all exclusions
for exclusion in st.ffio.exclusion:
take_some_action(exclusion)
:note: As with many other collections, the contents of the exclusion list
should not be modified through additions or deletions while you are
iterating over it.
"""
def _createFFIOExclusionContainer(self):
return _FFIOExclusionContainer(self._proxy)
exclusion = CreateWhenNeeded(_createFFIOExclusionContainer, "exclusion",
_doc)
_doc = """
A list of ffio pairs, each of which is a `_FFIOPair`
instance.
Example usage, where `st` is a FFIOStructure instance::
# Access an pair
pairobj = st.ffio.pair[n]
# Delete an pair
del st.ffio.pair[n]
# Find the number of pairs
len(st.ffio.pair)
# Iterate over all pairs
for pair in st.ffio.pair:
take_some_action(pair)
:note: As with many other collections, the contents of the site list
should not be modified through additions or deletions while you are
iterating over it.
"""
def _createFFIOPairContainer(self):
return _FFIOPairContainer(self._proxy)
pair = CreateWhenNeeded(_createFFIOPairContainer, "pair", _doc)
_doc = """
A list of ffio vdwtypes, each of which is a `_FFIOVdwtype`
instance.
Example usage, where `st` is a FFIOStructure instance::
# Access an vdwtype
vdwtypeobj = st.ffio.vdwtype[n]
# Delete an vdwtype
del st.ffio.vdwtype[n]
# Find the number of vdwtypes
len(st.ffio.vdwtype)
# Iterate over all vdwtypes
for vdwtype in st.ffio.vdwtype:
take_some_action(vdwtype)
:note: As with many other collections, the contents of the vdwtype list
should not be modified through additions or deletions while you are
iterating over it.
"""
def _createFFIOVdwtypeContainer(self):
return _FFIOVdwtypeContainer(self._proxy)
vdwtype = CreateWhenNeeded(_createFFIOVdwtypeContainer, "vdwtype", _doc)
_doc = """
A list of ffio restraints, each of which is a `_FFIORestraint`
instance.
Example usage, where `st` is a FFIOStructure instance::
# Access an restraint
restraintobj = st.ffio.restraint[n]
# Delete an restraint
del st.ffio.restraint[n]
# Find the number of restraints
len(st.ffio.restraint)
# Iterate over all restraints
for restraint in st.ffio.restraint:
take_some_action(restraint)
:note: As with many other collections, the contents of the restraint list
should not be modified through additions or deletions while you are
iterating over it.
"""
def _createFFIOVdwtypescombinedContainer(self):
return _FFIOVdwtypescombinedContainer(self._proxy)
vdwtypescombined = CreateWhenNeeded(_createFFIOVdwtypescombinedContainer,
"vdwtypescombined", _doc)
_doc = """
A list of ffio vdwtypes in the vdwtypes_combined block, each of which is a `_FFIOVdwcombined`
instance.
"""
def _createFFIORestraintContainer(self):
return _FFIORestraintContainer(self._proxy)
restraint = CreateWhenNeeded(_createFFIORestraintContainer, "restraint",
_doc)
_doc = """
A list of ffio virtuals, each of which is a `_FFIOVirtual`
instance.
Example usage, where `st` is a FFIOStructure instance::
# Access an virtual
virtualobj = st.ffio.virtual[n]
# Delete an virtual
del st.ffio.virtual[n]
# Find the number of virtuals
len(st.ffio.virtual)
# Iterate over all virtuals
for virtual in st.ffio.virtual:
take_some_action(virtual)
:note: As with many other collections, the contents of the virtual list
should not be modified through additions or deletions while you are
iterating over it.
"""
def _createFFIOVirtualContainer(self):
return _FFIOVirtualContainer(self._proxy)
virtual = CreateWhenNeeded(_createFFIOVirtualContainer, "virtual", _doc)
_doc = """
A list of ffio pseudos, each of which is a `_FFIOPseudo`
instance.
Example usage, where `st` is a FFIOStructure instance::
# Access an pseudo
pseudoobj = st.ffio.pseudo[n]
# Delete an pseudo
del st.ffio.pseudo[n]
# Find the number of pseudos
len(st.ffio.pseudo)
# Iterate over all pseudos
for pseudo in st.ffio.pseudo:
take_some_action(pseudo)
:note: As with many other collections, the contents of the pseudo list
should not be modified through additions or deletions while you are
iterating over it.
"""
def _createFFIOPseudoContainer(self):
return _FFIOPseudoContainer(self._proxy)
pseudo = CreateWhenNeeded(_createFFIOPseudoContainer, "pseudo", _doc)
_doc = """
A list of ffio constraints, each of which is a `_FFIOConstraint`
instance.
Example usage, where `st` is a FFIOStructure instance::
# Access an constraint
constraintobj = st.ffio.constraint[n]
# Delete an constraint
del st.ffio.constraint[n]
# Find the number of constraints
len(st.ffio.constraint)
# Iterate over all constraints
for constraint in st.ffio.constraint:
take_some_action(constraint)
:note: As with many other collections, the contents of the constraint list
should not be modified through additions or deletions while you are
iterating over it.
"""
def _createFFIOConstraintContainer(self):
return _FFIOConstraintContainer(self._proxy)
constraint = CreateWhenNeeded(_createFFIOConstraintContainer, "constraint",
_doc)
_doc = """
A list of ffio position flat bottoms, each of which is a `_FFIOPosFBHW`
instance.
Example usage, where `st` is a FFIOStructure instance::
# Access an position flat bottom
posfbhwobj = st.ffio.posfbhw[n]
# Delete an position flat bottom
del st.ffio.posfbhw[n]
# Find the number of position flat bottoms
len(st.ffio.posfbhw)
# Iterate over all position flat bottoms
for posfbhw in st.ffio.posfbhw:
take_some_action(posfbhw)
"""
def _createFFIOPosFBHWContainer(self):
return _FFIOPosFBHWContainer(self._proxy)
posfbhw = CreateWhenNeeded(_createFFIOPosFBHWContainer, "posfbhw", _doc)
_doc = """
A list of ffio angle flat bottoms, each of which is a `_FFIOAngleFBHW`
instance.
Example usage, where `st` is a FFIOStructure instance::
# Access an angle flat bottom
anglefbhwobj = st.ffio.anglefbhw[n]
# Delete an angle flat bottom
del st.ffio.anglefbhw[n]
# Find the number of angle flat bottoms
len(st.ffio.anglefbhw)
# Iterate over all angle flat bottoms
for anglefbhw in st.ffio.anglefbhw:
take_some_action(anglefbhw)
"""
def _createFFIOAngleFBHWContainer(self):
return _FFIOAngleFBHWContainer(self._proxy)
anglefbhw = CreateWhenNeeded(_createFFIOAngleFBHWContainer, "anglefbhw",
_doc)
_doc = """
A list of ffio improper flat bottoms, each of which is a `_FFIOImproperFBHW`
instance.
Example usage, where `st` is a FFIOStructure instance::
# Access an improper flat bottom
improperfbhwobj = st.ffio.improperfbhw[n]
# Delete an improper flat bottom
del st.ffio.improperfbhw[n]
# Find the number of improper flat bottoms
len(st.ffio.improperfbhw)
# Iterate over all improper flat bottoms
for improperfbhw in st.ffio.improperfbhw:
take_some_action(improperfbhw)
"""
def _createFFIOImproperFBHWContainer(self):
return _FFIOImproperFBHWContainer(self._proxy)
improperfbhw = CreateWhenNeeded(_createFFIOImproperFBHWContainer,
"improperfbhw", _doc)
_doc = """
A list of ffio stretch flat bottoms, each of which is a `_FFIOStretchFBHW`
instance.
Example usage, where `st` is a FFIOStructure instance::
# Access an stretch flat bottom
stretchfbhwobj = st.ffio.stretchfbhw[n]
# Delete an stretch flat bottom
del st.ffio.stretchfbhw[n]
# Find the number of stretch flat bottoms
len(st.ffio.stretchfbhw)
# Iterate over all stretch flat bottoms
for stretchfbhw in st.ffio.stretchfbhw:
take_some_action(stretchfbhw)
"""
def _createFFIOStretchFBHWContainer(self):
return _FFIOStretchFBHWContainer(self._proxy)
stretchfbhw = CreateWhenNeeded(_createFFIOStretchFBHWContainer,
"stretchfbhw", _doc)
# other_block
_doc = """
A list of ffio other blocks, each of which is a `_FFIOOtherBlock`
instance.
Example usage, where `st` is a FFIOStructure instance::
# Access an other block
other_block = st.ffio.other_block[n]
# Delete an other block
del st.ffio.other_block[n]
# Find the number of other blocks
len(st.ffio.other_block)
# Iterate over all other_blocks
for other_block in st.ffio.other_block:
take_some_action(other_block)
:note: As with many other collections, the contents of the other block list
should not be modified through additions or deletions while you are
iterating over it.
"""
def _createFFIOOtherBlockContainer(self):
return _FFIOOtherBlockContainer(self.handle)
other_block = CreateWhenNeeded(_createFFIOOtherBlockContainer,
"other_block", _doc)
def getOtherBlockNames(self):
return mm.mmffio_other_get_block_names(self.handle)
# property
def _getFFIOProperty(self):
if self._property is None:
self._property = _FFIOProperty(self.handle)
return self._property
property = property(
_getFFIOProperty,
doc="A dictionary of ffio properties. Keys are strings of "
"the form C{type_family_name} as described in the "
"L{PropertyName} documentation and found in C{.cms} files.")
def addSite(self):
"""
Add a new site to this ffio block, and return its Site object.
"""
mm.mmffio_add_sites(self.handle, 1)
return self.site[len(self.site)]
def addBond(self):
"""
Add a new bond to this ffio block, and return its Bond object.
"""
mm.mmffio_add_bonds(self.handle, 1)
return self.bond[len(self.bond)]
def addAngle(self):
"""
Add a new angle to this ffio block, and return its Angle object.
"""
mm.mmffio_add_angles(self.handle, 1)
return self.angle[len(self.angle)]
def addDihedral(self):
"""
Add a new dihedral to this ffio block, and return its Dihedral object.
"""
mm.mmffio_add_diheds(self.handle, 1)
return self.dihedral[len(self.dihedral)]
def addExclusion(self):
"""
Add a new exclusion to this ffio block, and return its Exclusion object.
"""
mm.mmffio_add_excls(self.handle, 1)
return self.exclusion[len(self.exclusion)]
def addPair(self):
"""
Add a new pair to this ffio block, and return its Pair object.
"""
mm.mmffio_add_pairs(self.handle, 1)
return self.pair[len(self.pair)]
def addVdwtype(self):
"""
Add a new vdwtype to this ffio block, and return its Vdwtype object.
"""
mm.mmffio_add_vdwtypes(self.handle, 1)
return self.vdwtype[len(self.vdwtype)]
def addVdwtypescombined(self):
"""
Add a new vdwtypescombined item to this ffio block, and return its Vdwtypescombined object.
"""
mm.mmffio_add_vdwtypescombineds(self.handle, 1)
return self.vdwtypescombined[len(self.vdwtypescombined)]
def addRestraint(self):
"""
Add a new restraint to this ffio block, and return its Restraint object.
"""
mm.mmffio_add_restraints(self.handle, 1)
return self.restraint[len(self.restraint)]
def addVirtual(self):
"""
Add a new virtual to this ffio block, and return its Virtual object.
"""
mm.mmffio_add_virtuals(self.handle, 1)
return self.virtual[len(self.virtual)]
def addPseudo(self):
"""
Add a new pseudo to this ffio block, and return its Pseudo object.
"""
mm.mmffio_add_pseudos(self.handle, 1)
return self.pseudo[len(self.pseudo)]
def addConstraint(self):
"""
Add a new constraint to this ffio block, and return its Constraint object.
"""
mm.mmffio_add_constraints(self.handle, 1)
return self.constraint[len(self.constraint)]
def addPosfbhw(self):
mm.mmffio_add_posfbhws(self.handle, 1)
return self.posfbhw[len(self.posfbhw)]
def addAnglefbhw(self):
mm.mmffio_add_anglefbhws(self.handle, 1)
return self.anglefbhw[len(self.anglefbhw)]
def addImproperfbhw(self):
mm.mmffio_add_improperfbhws(self.handle, 1)
return self.improperfbhw[len(self.improperfbhw)]
def addStretchfbhw(self):
mm.mmffio_add_stretchfbhws(self.handle, 1)
return self.stretchfbhw[len(self.stretchfbhw)]
def addOtherBlock(self, name):
"""
Add a new other block to this ffio block, and return it.
"""
length = len(self.other_block)
mm.mmffio_add_other_blocks(self.handle, 1)
mm.mmffio_other_block_set_name(self.handle, length, name)
return self.other_block[length]
def addSites(self, num_sites):
"""
Add the specified number of sites to this ffio block.
"""
mm.mmffio_add_sites(self.handle, num_sites)
def addBonds(self, num_bonds):
"""
Add the specified number of bonds to this ffio block.
"""
mm.mmffio_add_bonds(self.handle, num_bonds)
def addAngles(self, num_angles):
"""
Add the specified number of angles to this ffio block.
"""
mm.mmffio_add_angles(self.handle, num_angles)
def addDihedrals(self, num_dihedrals):
"""
Add the specified number of dihedrals to this ffio block.
"""
mm.mmffio_add_diheds(self.handle, num_dihedrals)
def addExclusions(self, num_exclusions):
"""
Add the specified number of exclusions to this ffio block.
"""
mm.mmffio_add_excls(self.handle, num_exclusions)
def addPairs(self, num_pairs):
"""
Add the specified number of pairs to this ffio block.
"""
mm.mmffio_add_pairs(self.handle, num_pairs)
def addVdwtypes(self, num_vdwtypes):
"""
Add the specified number of vdwtypes to this ffio block.
"""
mm.mmffio_add_vdwtypes(self.handle, num_vdwtypes)
def addVdwtypescombineds(self, num_vdwtypes):
"""
Add the specified number of vdwtypes to this ffio block.
"""
mm.mmffio_add_vdwtypescombined(self.handle, num_vdwtypes)
def addRestraints(self, num_restraints):
"""
Add the specified number of restraints to this ffio block.
"""
mm.mmffio_add_restraints(self.handle, num_restraints)
def addVirtuals(self, num_virtuals):
"""
Add the specified number of virtuals to this ffio block.
"""
mm.mmffio_add_virtuals(self.handle, num_virtuals)
def addPseudos(self, num_pseudos):
"""
Add the specified number of pseudos to this ffio block.
"""
mm.mmffio_add_pseudos(self.handle, num_pseudos)
def addConstraints(self, num_constraints):
"""
Add the specified number of constraints to this ffio block.
"""
mm.mmffio_add_constraints(self.handle, num_constraints)
def addPosfbhws(self, num_posfbhws):
mm.mmffio_add_posfbhws(self.handle, num_posfbhws)
def addAnglefbhws(self, num_anglefbhws):
mm.mmffio_add_anglefbhws(self.handle, num_anglefbhws)
def addImproperfbhws(self, num_improperfbhws):
mm.mmffio_add_improperfbhws(self.handle, num_improperfbhws)
def addStretchfbhws(self, num_stretchfbhws):
mm.mmffio_add_stretchfbhws(self.handle, num_stretchfbhws)
def _deleteItems(self, indices, delete_method):
"""
Delete multiple item from ffio sub-block. The argument indices must be a
sequence or an iterable, and able to be interpreted as ints.
After deletion, indices are renumbered from 1 to len(<sub-block>).
Pre-existing references to items will not be correct, as they store index values.
"""
# Be sure that deleting is done from highest index to lowest.
indices = [int(i) for i in indices]
indices.sort()
indices.reverse()
for i in indices:
delete_method(self.handle, i)
def deleteSites(self, indices):
self._deleteItems(indices, mm.mmffio_delete_site)
def deleteBonds(self, indices):
self._deleteItems(indices, mm.mmffio_delete_bond)
def deleteAngles(self, indices):
self._deleteItems(indices, mm.mmffio_delete_angle)
def deleteDihedrals(self, indices):
self._deleteItems(indices, mm.mmffio_delete_dihed)
def deleteExclusions(self, indices):
self._deleteItems(indices, mm.mmffio_delete_excl)
def deletePairs(self, indices):
self._deleteItems(indices, mm.mmffio_delete_pair)
def deleteVdwtypes(self, indices):
self._deleteItems(indices, mm.mmffio_delete_vdwtype)
def deleteVdwtypescombined(self, indices):
self._deleteItems(indices, mm.mmffio_delete_vdwtypescombined)
def deleteRestraints(self, indices):
self._deleteItems(indices, mm.mmffio_delete_restraint)
def deleteVirtuals(self, indices):
self._deleteItems(indices, mm.mmffio_delete_virtual)
def deletePseudos(self, indices):
self._deleteItems(indices, mm.mmffio_delete_pseudo)
def deleteConstraints(self, indices):
self._deleteItems(indices, mm.mmffio_delete_constraint)
def deletePosfbhws(self, indices):
self._deleteItems(indices, mm.mmffio_delete_posfbhw)
def deleteAnglefbhws(self, indices):
self._deleteItems(indices, mm.mmffio_delete_anglefbhw)
def deleteImproperfbhws(self, indices):
self._deleteItems(indices, mm.mmffio_delete_improperfbhw)
def deleteStretchfbhws(self, indices):
self._deleteItems(indices, mm.mmffio_delete_stretchfbhw)
def deleteOtherBlocks(self, indices):
"""
Delete multiple other blocks from the ffio block. The argument indices must be a
sequence or an iterable, and able to be interpreted as ints.
After deletion, indices are renumbered from 0 to len(other_block) - 1.
"""
# Be sure that deleting is done from highest index to lowest.
indices = [int(i) for i in indices]
indices.sort()
indices.reverse()
for i in indices:
mm.mmffio_delete_other_block(self.handle, i)
"""
FEPIO related classes
"""
# Dictionaries linking built-in property names of different standard fepio blocks
# to thier short names(to be used to get/set from python interfaces), mmfepio getter and
# setter methods. When the value is empty list, they are deduced from property names
fepio_sub_block_prop_links = {
'atommap': {
'i_fepio_ai': [
'ai', mm.mmfepio_atommap_get_ai, mm.mmfepio_atommap_set_ai
],
'i_fepio_aj': [
'aj', mm.mmfepio_atommap_get_aj, mm.mmfepio_atommap_set_aj
]
},
'bondmap': {
'i_fepio_ai': [],
'i_fepio_aj': [],
'i_fepio_ti': [],
'i_fepio_tj': []
},
'anglemap': {
'i_fepio_ai': [],
'i_fepio_aj': [],
'i_fepio_ak': [],
'i_fepio_ti': [],
'i_fepio_tj': []
},
'dihedmap': {
'i_fepio_ai': [],
'i_fepio_aj': [],
'i_fepio_ak': [],
'i_fepio_al': [],
'i_fepio_ti': [],
'i_fepio_tj': []
},
'exclmap': {
'i_fepio_ai': [],
'i_fepio_aj': [],
'i_fepio_ti': [],
'i_fepio_tj': []
},
'pairmap': {
'i_fepio_ai': [],
'i_fepio_aj': [],
'i_fepio_ti': [],
'i_fepio_tj': []
}
}
class _FEPIOElementProperty(_ElementProperty):
_getInt = mm.mmfepio_element_prop_get_int
_getReal = mm.mmfepio_element_prop_get_real
_getBoolean = mm.mmfepio_element_prop_get_boolean
_getString = mm.mmfepio_element_prop_get_string
_setInt = mm.mmfepio_element_prop_set_int
_setReal = mm.mmfepio_element_prop_set_real
_setBoolean = mm.mmfepio_element_prop_set_boolean
_setString = mm.mmfepio_element_prop_set_string
_data_names_method = mm.mmfepio_element_get_data_names
class _FEPIOElement(_Element):
_property_class = _FEPIOElementProperty
class _FEPIOOtherBlock(_OtherBlock):
_get_name_method = mm.mmfepio_other_block_get_name
_set_name_method = mm.mmfepio_other_block_set_name
_element_class = _FEPIOElement
_num_elements_method = mm.mmfepio_fep_get_num_elements
_add_elements_method = mm.mmfepio_add_elements
_delete_element_method = mm.mmfepio_delete_element
class _FEPIOOtherBlockContainer(_OtherBlockContainer):
_other_block_class = _FEPIOOtherBlock
_block_names_method = mm.mmfepio_other_get_block_names
class _FEPIOSubBlockProperty(_BlockPropertyBase):
"""
A dictionary of fepio sub-block properties. These can be accessed via the
property name as it appears in the maestro file.
Property names must be m2io data names, which are in the format
'<type>_<author>_<property_name>', where '<type>' is a data type prefix,
'<author>' is a source specification, and '<property_name>' is the
actual name of the data.
The data type prefix can specified as 's' for string, 'i' for integer,
'r' for real and 'b' for boolean. The author specification should be
'user' for user created properties. The property name can have embedded
underscores.
Some example m2io datanames are 'r_fepio_x_coord', which indicates a
real property named 'x coord', and 'i_user_my_count' which indicates
an integer user property named 'my count'.
"""
def __init__(self, fep, index, type):
"""Create an instance of the property dictionary. """
self._fep = fep
self._index = index
self._type = type
def __getitem__(self, item):
"""
Return the given item if it is a valid property for this item,
None if not.
"""
# Check to see if property is built-in:
builtin = fepio_sub_block_prop_links.get(self._type).get(item)
if builtin is not None:
short_name = get_fepio_sub_block_std_prop_short_name(
self._type, item)
return getattr(
getattr(self._fep, self._type)[self._index], short_name)
try:
func = getattr(
mm, "mmfepio_%s_prop_get_%s" %
(self._type, prop_type_names[item[0]]))
ret = func(self._fep.handle, item, self._index)
except mm.MmException as e:
raise KeyError("%s is not the name of an %s property" %
(item, self._type))
except IndexError as e:
if item == "":
raise KeyError("The empty string is an invalid dataname.")
else:
raise
return ret
def __setitem__(self, item, value):
"""Set properties for the given item. """
builtin = fepio_sub_block_prop_links.get(self._type).get(item)
if builtin is not None:
short_name = get_fepio_sub_block_std_prop_short_name(
self._type, item)
setattr(
getattr(self._fep, self._type)[self._index], short_name, value)
return
func = getattr(
mm,
"mmfepio_%s_prop_set_%s" % (self._type, prop_type_names[item[0]]))
func(self._fep.handle, item, self._index, value)
def keys(self):
"""
Return a list of all property names.
"""
func = getattr(mm, "mmfepio_%s_get_data_names" % self._type)
pnames = func(self._fep.handle, self._index, mm.M2IO_ALL_TYPES)
return list(fepio_sub_block_prop_links.get(self._type)) + pnames
class _FEPIOSubBlock:
"""
A class to make access of fepio sub-block properties more pythonic.
"""
block_type = None
def __init__(self, fep, _index):
self._fep = fep
self._index = _index
self._property = None
def __eq__(self, that):
"""
Compare on fep handle and index.
"""
if self._fep == that._fep and self._index == that._index and type(
self) == type(that):
return True
else:
return False
def __ne__(self, other):
"""
Check for inequality based on fep handle and index.
"""
return not self.__eq__(other)
def __hash__(self):
return hash(self._fep.handle) ^ self._index
def __index__(self):
return self._index
def __str__(self):
return "%s(%d)" % (self.block_type, int(self))
# index
def _getIndex(self):
return self._index
index = property(_getIndex, doc="The item index. I{Read only.}")
# property
def _getProperty(self):
if self._property is None:
self._property = _FEPIOSubBlockProperty(self._fep, self._index,
self.block_type)
return self._property
property = property(_getProperty, doc="property dictionary")
[docs]def make_property_fepio(getter, setter, doc):
def _get(self):
return getter(self._fep.handle, self._index)
def _set(self, value):
setter(self._fep.handle, self._index, value)
return property(_get, _set, doc=doc)
[docs]def get_fepio_sub_block_std_prop_short_name(block_type, prop_name):
"""
Function to get short names of properties. It is picked from the
fepio_sub_block_prop_links dict if avaiable, else deduced from property name
"""
if fepio_sub_block_prop_links[block_type][prop_name] == []:
short_name = prop_name.split('_')[-1]
else:
short_name = fepio_sub_block_prop_links[block_type][prop_name][0]
return short_name
[docs]def get_fepio_sub_block_std_prop_getter(block_type, prop_name):
"""
Function to get mmfepio getter method of properties. It is picked from the
fepio_sub_block_prop_links dict if avaiable, else deduced from property name
"""
if fepio_sub_block_prop_links[block_type][prop_name] == []:
short_name = prop_name.split('_')[-1]
func = getattr(mm, "mmfepio_%s_get_%s" % (block_type, short_name))
else:
func = fepio_sub_block_prop_links[block_type][prop_name][1]
return func
[docs]def get_fepio_sub_block_std_prop_setter(block_type, prop_name):
"""
Function to get mmfepio setter method of properties. It is picked from the
fepio_sub_block_prop_links dict if avaiable, else deduced from property name
"""
if fepio_sub_block_prop_links[block_type][prop_name] == []:
short_name = prop_name.split('_')[-1]
func = getattr(mm, "mmfepio_%s_set_%s" % (block_type, short_name))
else:
func = fepio_sub_block_prop_links[block_type][prop_name][2]
return func
class _FEPIOSubBlockMeta(type):
"""
A meta-class to different fepio sub block type classses. This
simplifies adding property descriptors for different sub-block types
"""
def __init__(cls, name, bases, dict):
super(_FEPIOSubBlockMeta, cls).__init__(name, bases, dict)
block_type = cls.block_type
for prop in list(fepio_sub_block_prop_links[block_type]):
prop_name = get_fepio_sub_block_std_prop_short_name(
block_type, prop)
prop_getter = get_fepio_sub_block_std_prop_getter(block_type, prop)
prop_setter = get_fepio_sub_block_std_prop_setter(block_type, prop)
doc = "%s %s" % (block_type, prop_name)
setattr(cls, prop_name,
make_property_fepio(prop_getter, prop_setter, doc))
class _FEPIOAtomMap(_FEPIOSubBlock, metaclass=_FEPIOSubBlockMeta):
block_type = "atommap"
class _FEPIOBondMap(_FEPIOSubBlock, metaclass=_FEPIOSubBlockMeta):
block_type = "bondmap"
class _FEPIOAngleMap(_FEPIOSubBlock, metaclass=_FEPIOSubBlockMeta):
block_type = "anglemap"
class _FEPIODihedMap(_FEPIOSubBlock, metaclass=_FEPIOSubBlockMeta):
block_type = "dihedmap"
class _FEPIOExclMap(_FEPIOSubBlock, metaclass=_FEPIOSubBlockMeta):
block_type = "exclmap"
class _FEPIOPairMap(_FEPIOSubBlock, metaclass=_FEPIOSubBlockMeta):
block_type = "pairmap"
class _FEPIOSubBlockContainer:
def __init__(self, fep):
"""
Initialize the container.
"""
self._fep = fep
def _item_count_method(self):
raise NotImplementedError()
def _delete_method(self, index):
raise NotImplementedError()
_item_class = None
def __delitem__(self, index):
"""
Delete a fepio sub-block item from the CT. Note that this immediately updates
the CT and therefore renumbers any items following the one deleted.
"""
if index < 1 or index > len(self):
raise IndexError("Index out of range (starts at 1)")
self._delete_method(self._fep.handle, index)
def __getitem__(self, index):
"""
Return the wrapper class for fepio sub-block item based properties.
Note that the initial index is 1, as per the underlying mmfepio library,
not 0 as is expected for python.
"""
if index < 1 or index > len(self):
raise IndexError("Index out of range (starts at 1)")
return self._item_class(self._fep, index)
def __iter__(self):
"""
Provide iteration access.
"""
for i in range(1, len(self) + 1):
yield self._item_class(self._fep, i)
def __len__(self):
"""
Return the number of items.
"""
return self._item_count_method(self._fep.handle)
class _FEPIOAtomMapContainer(_FEPIOSubBlockContainer):
_item_count_method = mm.mmfepio_fep_get_num_atommaps
_item_delete_method = mm.mmfepio_delete_atommap
_item_class = _FEPIOAtomMap
class _FEPIOBondMapContainer(_FEPIOSubBlockContainer):
_item_count_method = mm.mmfepio_fep_get_num_bondmaps
_item_delete_method = mm.mmfepio_delete_bondmap
_item_class = _FEPIOBondMap
class _FEPIOAngleMapContainer(_FEPIOSubBlockContainer):
_item_count_method = mm.mmfepio_fep_get_num_anglemaps
_item_delete_method = mm.mmfepio_delete_anglemap
_item_class = _FEPIOAngleMap
class _FEPIODihedMapContainer(_FEPIOSubBlockContainer):
_item_count_method = mm.mmfepio_fep_get_num_dihedmaps
_item_delete_method = mm.mmfepio_delete_dihedmap
_item_class = _FEPIODihedMap
class _FEPIOExclMapContainer(_FEPIOSubBlockContainer):
_item_count_method = mm.mmfepio_fep_get_num_exclmaps
_item_delete_method = mm.mmfepio_delete_exclmap
_item_class = _FEPIOExclMap
class _FEPIOPairMapContainer(_FEPIOSubBlockContainer):
_item_count_method = mm.mmfepio_fep_get_num_pairmaps
_item_delete_method = mm.mmfepio_delete_pairmap
_item_class = _FEPIOPairMap
class _FEPIOProperty(_BlockPropertyBase):
"""
A dictionary of fepio properties, with all dict methods.
Properties can be accessed via the m2io dataname as it appears in the
maestro file.
Property names must be m2io data names, which are in the format
'<type>_<author>_<property_name>', where '<type>' is a data type prefix,
'<author>' is a source specification, and '<property_name>' is the
actual name of the data.
The data type prefix can specified as 's' for string, 'i' for integer,
'r' for real and 'b' for boolean. The author specification should be
'user' for user created properties. The property name can have embedded
underscores.
Some example m2io datanames are 'r_m_x_coord', which indicates a real
maestro property named 'x coord', and 'i_user_my_count' which indicates
an integer user property named 'my count'.
To convert to the _FEPIOProperty to a real dictionary::
d = dict(st.ffio.property)
"""
def __init__(self, handle):
"""
Create an instance of the property 'dictionary' The instance is
created when st.property is first used.
"""
self._handle = handle
def __getitem__(self, item):
if item == 's_fepio_name':
return mm.mmfepio_fep_get_name(self._handle)
if item == constants.FEPIO_STAGE:
return mm.mmfepio_fep_get_stage(self._handle)
try:
if item[0] == "s":
ret = mm.mmfepio_fep_get_string_data(self._handle, item)
elif item[0] == "i":
ret = mm.mmfepio_fep_get_int_data(self._handle, item)
elif item[0] == "r":
ret = mm.mmfepio_fep_get_real_data(self._handle, item)
elif item[0] == "b":
ret = mm.mmfepio_fep_get_boolean_data(self._handle, item)
else:
raise KeyError("%s is an invalid dataname" % item)
return ret
except mm.MmException as e:
if e.rc == mm.MMFFIO_ERR:
raise KeyError("%s is not the name of a fepio property" % item)
except IndexError as e:
if item == "":
raise KeyError("The empty string is an invalid dataname.")
else:
raise
def __setitem__(self, item, value):
"""
Set the item into the additional data handle.
Usage: st.fepio.property[<name>] = value
"""
if item == 's_fepio_name':
return mm.mmfepio_fep_set_name(self._handle, value)
if item == constants.FEPIO_STAGE:
return mm.mmfepio_fep_set_version(self._handle, value)
if item[0] == "s":
mm.mmfepio_fep_add_string_data(self._handle, item, value)
elif item[0] == "i":
mm.mmfepio_fep_add_int_data(self._handle, item, value)
elif item[0] == "r":
mm.mmfepio_fep_add_real_data(self._handle, item, value)
elif item[0] == "b":
mm.mmfepio_fep_add_boolean_data(self._handle, item, value)
else:
raise KeyError(
"%s is an invalid property name; see _FEPIOProperty documentation for details."
% item)
def keys(self):
"""
Return a list of the names of all properties.
"""
ret = ['s_fepio_name', constants.FEPIO_STAGE]
pnames = mm.mmfepio_fep_get_data_names(self._handle, mm.M2IO_ALL_TYPES)
return ret + pnames
class _FEPIO():
"""
A class to make access of fepio block pythonic.
"""
def __init__(self, handle):
self.handle = handle
self._other_block = None
self._property = None
# name
def _setName(self, name):
"""
Set the name for this fepio block
"""
mm.mmfepio_fep_set_name(self.handle, name)
def _getName(self):
"""
Get the name for this fepio block
"""
return mm.mmfepio_fep_get_name(self.handle)
name = property(_getName, _setName, doc="fepio block name")
# stage
def _setStage(self, stage):
"""
Set the stage
"""
mm.mmfepio_fep_set_stage(self.handle, stage)
def _getStage(self):
"""
Get the stage
"""
return mm.mmfepio_fep_get_stage(self.handle)
stage = property(_getStage, _setStage, doc="stage")
#
# This section of the class definition consists of attributes to create
# on the fly, to avoid the cost of constructing them up front.
#
# The CreateWhenNeeded class is a descriptor that allows an attribute
# to be created on the fly. The first time the attribute is accessed,
# the function is called; whatever it returns is stored as the
# attribute and used in all future access.
#
def _createProxy(self):
"""
A method to create a proxy to be passed to subobjects that need to
hold a reference to the parent FEPIO object. This prevents cyclic
references and therefore allows FEPIO instances to be deallocated by
reference counting rather than waiting for a garbage collection sweep.
"""
return _FEPIO(self.handle)
_proxy = CreateWhenNeeded(_createProxy, "_proxy")
def _createAtomMapContainer(self):
return _FEPIOAtomMapContainer(self._proxy)
atommap = CreateWhenNeeded(_createAtomMapContainer, "atommap")
def _createBondMapContainer(self):
return _FEPIOBondMapContainer(self._proxy)
bondmap = CreateWhenNeeded(_createBondMapContainer, "bondmap")
def _createAngleMapContainer(self):
return _FEPIOAngleMapContainer(self._proxy)
anglemap = CreateWhenNeeded(_createAngleMapContainer, "anglemap")
def _createDihedMapContainer(self):
return _FEPIODihedMapContainer(self._proxy)
dihedmap = CreateWhenNeeded(_createDihedMapContainer, "dihedmap")
def _createExclMapContainer(self):
return _FEPIOExclMapContainer(self._proxy)
exclmap = CreateWhenNeeded(_createExclMapContainer, "exclmap")
def _createPairMapContainer(self):
return _FEPIOPairMapContainer(self._proxy)
pairmap = CreateWhenNeeded(_createPairMapContainer, "pairmap")
# other_block
def _createOtherBlockContainer(self):
return _FEPIOOtherBlockContainer(self.handle)
other_block = CreateWhenNeeded(_createOtherBlockContainer, "other_block")
def getOtherBlockNames(self):
return mm.mmfepio_other_get_block_names(self.handle)
# property
def _getProperty(self):
if self._property is None:
self._property = _FEPIOProperty(self.handle)
return self._property
property = property(
_getProperty,
doc="A dictionary of fepio properties. Keys are strings of "
"the form C{type_family_name} as described in the "
"L{PropertyName} documentation and found in C{.cms} files.")
def addAtommap(self):
mm.mmfepio_add_atommaps(self.handle, 1)
return self.atommap[len(self.atommap)]
def addBondmap(self):
mm.mmfepio_add_bondmaps(self.handle, 1)
return self.bondmap[len(self.bondmap)]
def addAnglemap(self):
mm.mmfepio_add_anglemaps(self.handle, 1)
return self.anglemap[len(self.anglemap)]
def addDihedmap(self):
mm.mmfepio_add_dihedmaps(self.handle, 1)
return self.dihedmap[len(self.dihedmap)]
def addExclmap(self):
mm.mmfepio_add_exclmaps(self.handle, 1)
return self.exclmap[len(self.exclmap)]
def addPairmap(self):
mm.mmfepio_add_pairmaps(self.handle, 1)
return self.pairmap[len(self.pairmap)]
def addAtommaps(self, num_items):
mm.mmfepio_add_atommaps(self.handle, num_items)
def addBondmaps(self, num_items):
mm.mmfepio_add_bondmaps(self.handle, num_items)
def addAnglemaps(self, num_items):
mm.mmfepio_add_anglemaps(self.handle, num_items)
def addDihedmaps(self, num_items):
mm.mmfepio_add_dihedmaps(self.handle, num_items)
def addExclmaps(self, num_items):
mm.mmfepio_add_exclmaps(self.handle, num_items)
def addPairmaps(self, num_items):
mm.mmfepio_add_pairmaps(self.handle, num_items)
def addOtherBlock(self, name):
"""
Add a new other block to this fepio block, and return it.
"""
length = len(self.other_block)
mm.mmfepio_add_other_blocks(self.handle, 1)
mm.mmfepio_other_block_set_name(self.handle, length, name)
return self.other_block[length]
def _deleteItems(self, indices, delete_method):
"""
Delete multiple item from fepio sub-block. The argument indices must be a
sequence or an iterable, and able to be interpreted as ints.
After deletion, indices are renumbered from 1 to len(<sub-block>).
Pre-existing references to items will not be correct, as they store index values.
"""
# Be sure that deleting is done from highest index to lowest.
indices = [int(i) for i in indices]
indices.sort()
indices.reverse()
for i in indices:
delete_method(self.handle, i)
def deleteAtommaps(self, indices):
self._deleteItems(indices, mm.mmfepio_delete_atommap)
def deleteBondmaps(self, indices):
self._deleteItems(indices, mm.mmfepio_delete_bondmap)
def deleteAnglemaps(self, indices):
self._deleteItems(indices, mm.mmfepio_delete_anglemap)
def deleteDihedmaps(self, indices):
self._deleteItems(indices, mm.mmfepio_delete_dihedmap)
def deleteExclmaps(self, indices):
self._deleteItems(indices, mm.mmfepio_delete_exclmap)
def deletePairmaps(self, indices):
self._deleteItems(indices, mm.mmfepio_delete_pairmap)
def deleteOtherBlocks(self, indices):
"""
Delete multiple other blocks from the fepio block. The argument indices must be a
sequence or an iterable, and able to be interpreted as ints.
After deletion, indices are renumbered from 0 to len(other_block) - 1.
"""
# Be sure that deleting is done from highest index to lowest.
indices = [int(i) for i in indices]
indices.sort()
indices.reverse()
for i in indices:
mm.mmfepio_delete_other_block(self.handle, i)
[docs]class FFIOStructure(Structure):
"""
Class to create python interface to force field data. This is just a wrapper
around the mmffio/mmfepio functionality. I/O happens through the underlying libraries.
mmffio/mmfepio handles are created on demand when ffio/fepio blocks are accesssed.
"""
[docs] def __init__(self, handle, error_handler=mm.error_handler):
"""
Parent class would take care of basic CT data.
"""
Structure.__init__(self, handle, error_handler)
mm.mmffio_initialize(error_handler)
mm.mmfepio_initialize(error_handler)
self.ffhandle = None
self.fephandle = None
def _hasBlock(self, block_name):
uh = mm.mmct_ct_m2io_get_unrequested_handle(self.handle)
return mm.m2io_inquire_block_name(uh, block_name)
def _createFFIOBlock(self):
if self.ffhandle is None:
if self._hasBlock('ffio_ff'):
self.ffhandle = mm.mmffio_ff_mmct_get(self.handle)
else:
raise RuntimeError("Fail to get ffio handle.")
return _FFIO(self.ffhandle)
ffio = CreateWhenNeeded(_createFFIOBlock, "ffio")
def _createFEPIOBlock(self):
if self.fephandle is None:
if self._hasBlock('fepio_fep'):
self.fephandle = mm.mmfepio_fep_mmct_get(self.handle)
else:
raise RuntimeError("Fail to get fepio handle.")
return _FEPIO(self.fephandle)
fepio = CreateWhenNeeded(_createFEPIOBlock, "fepio")
[docs] def hasFfio(self):
"""
"""
try:
if (self.ffio):
return True
except:
pass
return False
[docs] def hasFepio(self):
"""
"""
try:
if (self.fepio):
return True
except:
pass
return False
def __copy__(self):
""" Allows the structure to be copied by copy.copy """
new_ct = mm.mmct_ct_duplicate(self.handle)
new_ffiostructure = FFIOStructure(new_ct, True)
if self.hasFfio():
new_ffiostructure.ffhandle = mm.mmffio_ff_duplicate(self.ffhandle)
if self.hasFepio():
new_ffiostructure.fephandle = mm.mmfepio_fep_duplicate(
self.fephandle)
return new_ffiostructure
[docs] def copy(self):
""" Returns a copy of the structure. """
return self.__copy__()
[docs] def write(self, filename, format=None):
"""
Write the cms structure to a file, overwriting any previous content.
Format is determined from the file suffix if None is specified.
otherwise an explicit value of maestro, sd, pdb, or smiles can be used.
Only cms format is supported as of know, if other types are choosen,
basic CT information would be written, which is taken care by the parent
class.
"""
if format == "CMS":
write_cms(self, filename, mm.M2IO_WRITE)
else:
Structure.write(self, filename, format)
[docs] def append(self, filename, format=None):
"""
Append the structure to the file.
Format is determined from the file suffix if None is specified,
otherwise an explicit value of maestro, sd, pdb, or smiles can be used.
Only cms format is supported as of know, if other types are choosen,
basic CT information would be written, which is taken care by the parent
class.
"""
if format == "CMS":
write_cms(self, filename, mm.M2IO_APPEND)
else:
Structure.append(self, filename, format)
def __del__(self,
mmffio_ff_delete=mm.mmffio_ff_delete,
mmfepio_fep_delete=mm.mmfepio_fep_delete,
mmffio_terminate=mm.mmffio_terminate,
mmfepio_terminate=mm.mmfepio_terminate):
"""
Delete the underlying mmffio, mmfepio handles
"""
if hasattr(self, 'ffhandle') and self.ffhandle is not None:
mmffio_ff_delete(self.ffhandle)
if hasattr(self, 'fephandle') and self.fephandle is not None:
mmfepio_fep_delete(self.fephandle)
mmffio_terminate()
mmfepio_terminate()
[docs]class CMSReader(object):
""" A class for reading structures from a CMS format file. """
# Make this setting a class variable so that people can set it to M2IO_READ
# if needed.
read_mode = mm.M2IO_READ_FORWARD
[docs] def __init__(self, filename, index=1, input_string=None):
"""
Initialize with a filename, an optional starting index (default of 1)
"""
self._index = index
mm.m2io_initialize(mm.error_handler)
mm.mmct_initialize(mm.error_handler)
self.error_handler = mm.error_handler
self.fh = None
self.filename = filename
self.input_string = input_string
def __del__(self):
self.close()
mm.mmct_terminate()
mm.m2io_terminate()
[docs] def close(self):
"""
Close the file.
"""
if self.fh is not None:
mm.m2io_close_file(self.fh)
self.fh = None
# required for iterator support
def __iter__(self):
return self
def __next__(self):
"""
Return the next FFIOStructure object from the file. Set
self.last_position to the file offset just before it was read.
"""
if self.fh is None:
# First iteration; open the file:
try:
if self.input_string:
self.fh = mm.m2io_open_read_from_buffer(self.input_string)
else:
self.fh = mm.m2io_open_file(self.filename, self.read_mode)
self.type = mm.m2io_get_file_type(self.fh)
except mm.MmException as e:
# If m2io_open_file returned M2IO_ERR, check to see if this is due
# to an empty file.
if e.rc == mm.M2IO_ERR and os.path.getsize(self.filename) == 0:
raise StopIteration()
else:
raise
if self._index > 1:
mm.m2io_goto_block(self.fh, mm.M2IO_BLOCK_WILDCARD_CT,
(self._index - 1))
mm.m2io_leave_block(self.fh)
if self.type == mm.M2IO_DISK_FILE:
# File position is not supported for Mmod format or "in-core" files,
# but we don't raise an exception if we're using such a file; rather,
# a NameError will arise should the user try to access
# self.last_position in this situation:
try:
self.last_position = mm.m2io_get_file_pos(self.fh)
except:
raise
try:
mm.m2io_goto_next_block(self.fh, mm.M2IO_BLOCK_WILDCARD_CT)
ct = FFIOStructure(mm.mmct_ct_m2io_get(self.fh),
error_handler=self.error_handler)
except mm.MmException as e:
if e.rc == mm.M2IO_EOF:
raise StopIteration()
else:
raise Exception("Could not read the next structure from file")
return ct
[docs]def write_cms(ct, filename, mode=mm.M2IO_WRITE):
"""
Write a CT to a Maestro format file.
"""
fh = mm.m2io_open_file(filename, mode)
if ct.ffhandle is not None:
mm.mmffio_ff_mmct_put(ct.ffhandle, ct.handle)
if ct.fephandle is not None:
mm.mmfepio_fep_mmct_put(ct.fephandle, ct.handle)
mm.mmct_ct_m2io_put(ct, fh)
mm.m2io_close_file(fh)
[docs]def write_cms_to_string(ct):
"""
Write a CT to a string.
"""
if ct.ffhandle is not None:
mm.mmffio_ff_mmct_put(ct.ffhandle, ct.handle)
if ct.fephandle is not None:
mm.mmfepio_fep_mmct_put(ct.fephandle, ct.handle)
return write_ct_to_string(ct)
[docs]def merge_ct(ct0, ct1):
"""
Returns a new ct which is the result of merging ct0 and ct1.
"""
for a in ct1.atom:
a.property["i_tmpmerge_orig_atom_index"] = int(a)
ct = ct0.merge(ct1, copy_props=True)
new_index = {} # key = orig atom index, value = new atom index
for a in ct.atom:
try:
orig_index = a.property["i_tmpmerge_orig_atom_index"]
if (orig_index):
new_index[orig_index] = int(a)
except KeyError:
pass
def migrate_ffio_subblock_item(new, old, prop_name, index_map=new_index):
for name in prop_name:
try:
if (name[:8] == "i_ffio_a"):
try:
new.property[name] = index_map[old.property[name]]
except KeyError:
new.property[name] = old.property[name]
elif (name[:12] == "s_ffio_group"):
new_indices = (
index_map[int(e)] for e in old.property[name].split())
new.property[name] = ' '.join(map(str, new_indices))
else:
new.property[name] = old.property[name]
except TypeError:
pass
subblock = {}
for e in ffio_block_names:
subblock[e] = "add" + e[0].upper() + e[1:]
ct1.ffio.site
ct1.ffio.bond
ct1.ffio.angle
ct1.ffio.dihedral
ct1.ffio.exclusion
ct1.ffio.pair
ct1.ffio.vdwtype
ct1.ffio.vdwtypescombined
ct1.ffio.restraint
ct1.ffio.virtual
ct1.ffio.pseudo
ct1.ffio.constraint
ct1.ffio.posfbhw
ct1.ffio.anglefbhw
ct1.ffio.improperfbhw
ct1.ffio.stretchfbhw
ct1.ffio.other_block
ct.ffio.site
ct.ffio.bond
ct.ffio.angle
ct.ffio.dihedral
ct.ffio.exclusion
ct.ffio.pair
ct.ffio.vdwtype
ct.ffio.vdwtypescombined
ct.ffio.restraint
ct.ffio.virtual
ct.ffio.pseudo
ct.ffio.constraint
ct.ffio.posfbhw
ct.ffio.anglefbhw
ct.ffio.improperfbhw
ct.ffio.stretchfbhw
ct.ffio.other_block
def unroll_ffio(ct, n):
# Unrolls the ffio block.
if (n > 1):
for e, f in subblock.items():
entries_in_subblock = [entry for entry in ct.ffio.__dict__[e]]
for i in range(n - 1):
for entry in entries_in_subblock:
new = _FFIO.__dict__[f].__get__(
ct.ffio,
_FFIO)() # Calls `ct.ffio.add*()' function.
migrate_ffio_subblock_item(new, entry,
ffio_sub_block_prop_links[e])
unroll_ffio(ct, ct0.atom_total // len(ct.ffio.site))
unroll_ffio(ct1, ct1.atom_total // len(ct1.ffio.site))
for e, f in subblock.items():
for old in ct1.ffio.__dict__[e]:
new = _FFIO.__dict__[f].__get__(
ct.ffio, _FFIO)() # Calls `ct.ffio.add*()' function.
i = len(ct.ffio.__dict__[e])
migrate_ffio_subblock_item(new, old, ffio_sub_block_prop_links[e])
for a in ct1.atom:
del a.property["i_tmpmerge_orig_atom_index"]
for a in ct.atom:
if ("i_tmpmerge_orig_atom_index" in a.property):
del a.property["i_tmpmerge_orig_atom_index"]
return ct
if ("__main__" == __name__):
fname = "md_test.cms"
struc = [e for e in CMSReader(fname)]
ct = merge_ct(struc[2], struc[3])
ct.write("testffiostructure.mae", "CMS")