Skip to content

Commit

Permalink
Squashed 'modules/core/dependency/python-ihm/' changes from c75b4bdd9…
Browse files Browse the repository at this point in the history
…5..29985eda1e

29985eda1e Update copyright year
78b985e34c Fix use of Sphinx data::
0c3d63071b Improve cross linker docs
e2decbe80d Fix documentation of cross-linkers
b57bc554d4 Add a module with commonly-used cross-linkers
5d46a680dc Test ChemDescriptors referenced by restraints
2883917c4a Use chemical descriptors in cross link restraints
3552247632 Fix typo
826dc56f30 Add basic support for chemical descriptors
1768608ab5 Fix typo
0bb0e3a048 ihm_feature_pseudo_site -> ihm_pseudo_site_feature
6cec1809b4 Add support for pseudo sites
756ebed7d6 Use trusty for Python 2.6 builds
8b8b554ba7 Check to see if Travis works with Python 3.7 now
4c9485782e Prepare for 0.4 release

git-subtree-dir: modules/core/dependency/python-ihm
git-subtree-split: 29985eda1e1e73a27a8d75c7ed43926eed6008d2
  • Loading branch information
benmwebb committed Jan 8, 2019
1 parent f8d68fa commit 9d38a96
Show file tree
Hide file tree
Showing 19 changed files with 395 additions and 44 deletions.
7 changes: 6 additions & 1 deletion modules/core/dependency/python-ihm/.travis.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
sudo: false
language: python
dist: xenial
python:
- 2.6
- 2.7
- 3.6
- 3.7
matrix:
include:
- dist: trusty
python: 2.6
addons:
apt:
packages:
Expand Down
22 changes: 21 additions & 1 deletion modules/core/dependency/python-ihm/ChangeLog.rst
Original file line number Diff line number Diff line change
@@ -1,11 +1,31 @@
HEAD
====

- :class:`ihm.restraint.CrossLinkRestraint` now takes an
:class:`ihm.ChemDescriptor` object rather than the name of the cross-linker
used. This allows the use of novel cross-linkers (beyond those currently
listed in a fixed enumeration in the IHM dictionary).
:class:`ihm.ChemDescriptor` allows for the chemical structure of the
cross-linker to be uniquely specified, as a SMILES or INCHI string.
The :mod:`ihm.cross_linkers` module provides chemical descriptors for
some commonly-used cross-linkers.
- Pseudo sites are now supported. :class:`ihm.restraint.PseudoSiteFeature`
allows points or spheres with arbitrary coordinates to be designated as
features, which can then be used in
:class:`ihm.restraint.DerivedDistanceRestraint`.

0.4 - 2018-12-17
================
- Certain restraints can now be grouped using the
:class:`ihm.restraint.RestraintGroup` class. Due to limitations of the
underlying dictionary, this only works for some restraint types (currently
only :class:`ihm.restraint.DerivedDistanceRestraint`) and all restraints
in the group must be of the same type.
- Bugfix: the the model's representation (see :mod:`ihm.representation`)
need not be a strict subset of the model's :class:`ihm.Assembly`. However,
any :class:`ihm.model.Atom` or :class:`ihm.model.Sphere` objects must be
covered by both the representation and the model's :class:`ihm.Assembly`.
- Bugfix: the reader no longer fails to read files that contain
_entity.formula_weight.

0.3 - 2018-11-21
================
Expand Down
2 changes: 1 addition & 1 deletion modules/core/dependency/python-ihm/LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2018 IHM Working Group
Copyright (c) 2018-2019 IHM Working Group

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
2 changes: 1 addition & 1 deletion modules/core/dependency/python-ihm/docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@

# General information about the project.
project = u'Python-IHM'
copyright = u'2018, Benjamin Webb'
copyright = u'2018-2019, Benjamin Webb'
author = u'Benjamin Webb'

# The version info for the project you're documenting, acts as replacement for
Expand Down
16 changes: 16 additions & 0 deletions modules/core/dependency/python-ihm/docs/cross_linkers.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
.. highlight:: rest

.. _cross_linkers_module:

The :mod:`ihm.cross_linkers` Python module
==========================================

.. automodule:: ihm.cross_linkers

.. data:: dss

DSS cross-linker that links a primary amine with another primary amine.

.. data:: edc

EDC cross-linker that links a carboxyl group with a primary amine.
1 change: 1 addition & 0 deletions modules/core/dependency/python-ihm/docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ API Reference:
representation
geometry
restraint
cross_linkers
protocol
analysis
model
Expand Down
3 changes: 3 additions & 0 deletions modules/core/dependency/python-ihm/docs/main.rst
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,6 @@ The :mod:`ihm` Python module

.. autoclass:: Assembly
:members:

.. autoclass:: ChemDescriptor
:members:
3 changes: 3 additions & 0 deletions modules/core/dependency/python-ihm/docs/restraint.rst
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ The :mod:`ihm.restraint` Python module
.. autoclass:: NonPolyFeature
:members:

.. autoclass:: PseudoSiteFeature
:members:

.. autoclass:: GeometricRestraint
:members:

Expand Down
50 changes: 48 additions & 2 deletions modules/core/dependency/python-ihm/ihm/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
import urllib2
import json

__version__ = '0.3'
__version__ = '0.4'

#: A value that isn't known. Note that this is distinct from a value that
#: is deliberately omitted, which is represented by Python None.
Expand Down Expand Up @@ -64,6 +64,12 @@ def __init__(self, title=None, id='model'):
#: All asymmetric units used in the system. See :class:`AsymUnit`.
self.asym_units = []

#: All orphaned chemical descriptors in the system.
#: See :class:`ChemDescriptor`. This can be used to track descriptors
#: that are not otherwise used - normally one is assigned to a
#: :class:`ihm.restraint.CrossLinkRestraint`.
self.orphan_chem_descriptors = []

#: All orphaned assemblies in the system. See :class:`Assembly`.
#: This can be used to keep track of all assemblies that are not
#: otherwise used - normally one is assigned to a
Expand Down Expand Up @@ -194,6 +200,14 @@ def _all_restraints_in_groups():
yield r
return itertools.chain(self.restraints, _all_restraints_in_groups())

def _all_chem_descriptors(self):
"""Iterate over all ChemDescriptors in the system.
Duplicates may be present."""
return itertools.chain(self.orphan_chem_descriptors,
(restraint.linker for restraint in self.restraints
if hasattr(restraint, 'linker')
and restraint.linker))

def _all_model_groups(self, only_in_states=True):
"""Iterate over all ModelGroups in the system.
If only_in_states is True, only return ModelGroups referenced
Expand Down Expand Up @@ -537,7 +551,7 @@ class ChemComp(object):
:param str code_canonical: Canonical version of `code` (which need not
be unique).
:param str name: A longer human-readable name for the component.
:param str formula: The chemical formula. This is a spaced-separated
:param str formula: The chemical formula. This is a space-separated
list of the element symbols in the component, each followed
by an optional count (if omitted, 1 is assumed). The formula
is terminated with the formal charge (if not zero). The element
Expand Down Expand Up @@ -1037,3 +1051,35 @@ class Assembly(list):
def __init__(self, elements=(), name=None, description=None):
super(Assembly, self).__init__(elements)
self.name, self.description = name, description


class ChemDescriptor(object):
"""Description of a non-polymeric chemical component used in the experiment.
For example, this might be a fluorescent probe or cross-linking agent.
This class describes the chemical structure of the component, for
example with a SMILES or INCHI descriptor, so that it is uniquely
defined. A descriptor is typically assigned to a
:class:`ihm.restraint.CrossLinkRestraint`.
See :mod:`ihm.cross_linkers` for chemical descriptors of some
commonly-used cross-linking agents.
:param str auth_name: Author-provided name
:param str chem_comp_id: If this chemical is listed in the Chemical
Component Dictionary, its three-letter identifier
:param str chemical_name: The systematic (IUPAC) chemical name
:param str common_name: Common name for the component
:param str smiles: SMILES string
:param str smiles_canonical: Canonical SMILES string
:param str inchi: IUPAC INCHI descriptor
:param str inchi_key: Hashed INCHI key
See also :attr:`System.orphan_chem_descriptors`.
"""
def __init__(self, auth_name, chem_comp_id=None, chemical_name=None,
common_name=None, smiles=None, smiles_canonical=None,
inchi=None, inchi_key=None):
self.auth_name, self.chem_comp_id = auth_name, chem_comp_id
self.chemical_name, self.common_name = chemical_name, common_name
self.smiles, self.smiles_canonical = smiles, smiles_canonical
self.inchi, self.inchi_key = inchi, inchi_key
20 changes: 20 additions & 0 deletions modules/core/dependency/python-ihm/ihm/cross_linkers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
"""Chemical descriptors of commonly-used cross-linkers.
Each of these is an instance of the :class:`ihm.ChemDescriptor` class,
and so can be used anywhere these objects are required, generally for
:class:`ihm.restraint.CrossLinkRestraint`.
"""

import ihm

dss = ihm.ChemDescriptor('DSS', chemical_name='disuccinimidyl suberate',
smiles='C1CC(=O)N(C1=O)OC(=O)CCCCCCC(=O)ON2C(=O)CCC2=O',
inchi='1S/C16H20N2O8/c19-11-7-8-12(20)17(11)25-15(23)5-'
'3-1-2-4-6-16(24)26-18-13(21)9-10-14(18)22/h1-10H2',
inchi_key='ZWIBGKZDAWNIFC-UHFFFAOYSA-N')

edc = ihm.ChemDescriptor('EDC',
chemical_name='1-ethyl-3-(3-dimethylaminopropyl)carbodiimide',
smiles='CCN=C=NCCCN(C)C',
inchi='1S/C8H17N3/c1-4-9-8-10-6-5-7-11(2)3/h4-7H2,1-3H3',
inchi_key='LMDZBCPBFSXMTL-UHFFFAOYSA-N')
47 changes: 42 additions & 5 deletions modules/core/dependency/python-ihm/ihm/dumper.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,30 @@ def dump(self, system, writer):
formula_weight=comp.formula_weight)


class _ChemDescriptorDumper(_Dumper):
def finalize(self, system):
seen_desc = {}
# Assign IDs to all descriptors
self._descriptor_by_id = []
for d in system._all_chem_descriptors():
util._remove_id(d)
for d in system._all_chem_descriptors():
util._assign_id(d, seen_desc, self._descriptor_by_id)

def dump(self, system, writer):
with writer.loop("_ihm_chemical_descriptor",
["id", "auth_name", "chem_comp_id", "chemical_name",
"common_name", "smiles", "smiles_canonical", "inchi",
"inchi_key"]) as l:
for d in self._descriptor_by_id:
l.write(id=d._id, auth_name=d.auth_name,
chem_comp_id=d.chem_comp_id,
chemical_name=d.chemical_name,
common_name=d.common_name, smiles=d.smiles,
smiles_canonical=d.smiles_canonical, inchi=d.inchi,
inchi_key=d.inchi_key)


class _EntityDumper(_Dumper):
def finalize(self, system):
# Assign IDs and check for duplicates
Expand Down Expand Up @@ -1346,6 +1370,7 @@ def dump(self, system, writer):
self.dump_poly_residue(writer)
self.dump_poly_atom(writer)
self.dump_non_poly(writer)
self.dump_pseudo_site(writer)

def dump_list(self, writer):
with writer.loop("_ihm_feature_list",
Expand Down Expand Up @@ -1417,6 +1442,16 @@ def dump_non_poly(self, writer):
atom_id=None)
ordinal += 1

def dump_pseudo_site(self, writer):
with writer.loop("_ihm_pseudo_site_feature",
["feature_id", "Cartn_x", "Cartn_y",
"Cartn_z", "radius", "description"]) as l:
for f in self._features_by_id:
if not isinstance(f, restraint.PseudoSiteFeature):
continue
l.write(feature_id=f._id, Cartn_x=f.x, Cartn_y=f.y,
Cartn_z=f.z, radius=f.radius, description=f.description)


class _CrossLinkDumper(_Dumper):
def _all_restraints(self, system):
Expand All @@ -1438,7 +1473,7 @@ def finalize_experimental(self, system):
# Assign identical cross-links the same ID and group ID
sig = (xl.residue1.entity, xl.residue1.seq_id,
xl.residue2.entity, xl.residue2.seq_id,
r.linker_type)
r.linker)
if sig in seen_cross_links:
xl._id, xl._group_id = seen_cross_links[sig]
else:
Expand All @@ -1461,7 +1496,7 @@ def finalize_modeling(self, system):
ex_xl = xl.experimental_cross_link
sig = (xl.asym1._id, ex_xl.residue1.seq_id, xl.atom1,
xl.asym2._id, ex_xl.residue2.seq_id, xl.atom2,
r.linker_type)
r.linker)
if sig in seen_cross_links:
xl._id = seen_cross_links[sig]
else:
Expand All @@ -1481,7 +1516,8 @@ def dump_list(self, system, writer):
"entity_id_1", "seq_id_1", "comp_id_1",
"entity_description_2",
"entity_id_2", "seq_id_2", "comp_id_2",
"linker_type", "dataset_list_id"]) as l:
"linker_descriptor_id", "linker_type",
"dataset_list_id"]) as l:
for r, xl in self._ex_xls_by_id:
entity1 = xl.residue1.entity
entity2 = xl.residue2.entity
Expand All @@ -1496,7 +1532,8 @@ def dump_list(self, system, writer):
entity_id_2=entity2._id,
seq_id_2=xl.residue2.seq_id,
comp_id_2=seq2[xl.residue2.seq_id-1].id,
linker_type=r.linker_type,
linker_descriptor_id=r.linker._id,
linker_type=r.linker.auth_name,
dataset_list_id=r.dataset._id)

def dump_restraint(self, system, writer):
Expand Down Expand Up @@ -1794,7 +1831,7 @@ def write(fh, systems, format='mmCIF'):
_AuditConformDumper(), _SoftwareDumper(),
_CitationDumper(),
_AuditAuthorDumper(),
_ChemCompDumper(),
_ChemCompDumper(), _ChemDescriptorDumper(),
_EntityDumper(),
_EntityPolyDumper(),
_EntityNonPolyDumper(),
Expand Down
Loading

0 comments on commit 9d38a96

Please sign in to comment.