Skip to content

Commit

Permalink
Tweaks to BondList merging (#473)
Browse files Browse the repository at this point in the history
* Docstring fixes

* Fix bug in polymer type detection

* Fix docstring

* Fix tests

* Retain bond order

* Adapt docstrings

* Do not mask atoms, as this has no effect

* Fix test
  • Loading branch information
padix-key authored Apr 25, 2023
1 parent 1966cc9 commit d908ac5
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 34 deletions.
46 changes: 34 additions & 12 deletions src/biotite/structure/bonds.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ class BondType(IntEnum):
"""
Remove aromaticity from the bond type.
:attr:`BondType.AROMATIC_<ORDER>` is converted into
:attr:`BondType.<ORDER>`.
:attr:`BondType.AROMATIC_{ORDER}` is converted into
:attr:`BondType.{ORDER}`.
Returns
-------
Expand Down Expand Up @@ -157,6 +157,8 @@ class BondList(Copyable):
sanitized: Redundant bonds are removed, and each bond entry is
sorted so that the lower one of the two atom indices is in the first
column.
If a bond appears multiple times with different bond types, the
first bond takes precedence.
Examples
--------
Expand Down Expand Up @@ -436,8 +438,8 @@ class BondList(Copyable):
"""
Remove aromaticity from the bond types.
:attr:`BondType.AROMATIC_<ORDER>` is converted into
:attr:`BondType.<ORDER>`.
:attr:`BondType.AROMATIC_{ORDER}` is converted into
:attr:`BondType.{ORDER}`.
Examples
--------
Expand Down Expand Up @@ -929,12 +931,14 @@ class BondList(Copyable):
"""
merge(bond_list)
Merge this instance with another :class:`BondList` into a new
Merge another :class:`BondList` with this instance into a new
object.
If a bond appears in both :class:`BondList`'s, the
:class:`BondType` from the given `bond_list` takes precedence.
The internal :class:`ndarray` instances containg the bonds are
simply concatenated and the new atom count is the maximum atom
count of the merged bond lists.
simply concatenated and the new atom count is the maximum of
both bond lists.
Parameters
----------
Expand All @@ -956,20 +960,38 @@ class BondList(Copyable):
>>> bond_list1 = BondList(3, np.array([(0,1),(1,2)]))
>>> bond_list2 = BondList(5, np.array([(2,3),(3,4)]))
>>> merged_list = bond_list1.merge(bond_list2)
>>> merged_list = bond_list2.merge(bond_list1)
>>> print(merged_list.get_atom_count())
5
>>> print(merged_list)
[[0 1 0]
[1 2 0]
[2 3 0]
[3 4 0]]
The BondList given as parameter takes precedence:
# Specifiy bond type to see where a bond is taken from
>>> bond_list1 = BondList(4, np.array([
... (0, 1, BondType.SINGLE),
... (1, 2, BondType.SINGLE)
... ]))
>>> bond_list2 = BondList(4, np.array([
... (1, 2, BondType.DOUBLE), # This one is a duplicate
... (2, 3, BondType.DOUBLE)
... ]))
>>> merged_list = bond_list2.merge(bond_list1)
>>> print(merged_list)
[[0 1 1]
[1 2 1]
[2 3 2]]
"""
return BondList(
max(self._atom_count, bond_list._atom_count),
np.concatenate([self.as_array(),
bond_list.as_array()],
axis=0)
np.concatenate(
[bond_list.as_array(), self.as_array()],
axis=0
)
)

def __add__(self, bond_list):
Expand Down Expand Up @@ -1688,7 +1710,7 @@ def _connect_inter_residue(atoms, residue_starts):

# Get link type for this residue from RCSB components.cif
curr_link = link_type(res_names[curr_start_i])
next_link = link_type(res_names[curr_start_i+1])
next_link = link_type(res_names[next_start_i])

if curr_link in _PEPTIDE_LINKS and next_link in _PEPTIDE_LINKS:
curr_connect_atom_name = "C"
Expand Down
21 changes: 15 additions & 6 deletions src/biotite/structure/io/pdb/convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,11 @@ def get_structure(pdb_file, model=None, altloc="first", extra_fields=[],
If set to true, a :class:`BondList` will be created for the
resulting :class:`AtomArray` containing the bond information
from the file.
All bonds have :attr:`BondType.ANY`, since the PDB format
does not support bond orders.
Bonds, whose order could not be determined from the
*Chemical Component Dictionary*
(e.g. especially inter-residue bonds),
have :attr:`BondType.ANY`, since the PDB format itself does
not support bond orders.
Returns
-------
Expand Down Expand Up @@ -191,8 +194,11 @@ def get_assembly(pdb_file, assembly_id=None, model=None, altloc="first",
If set to true, a :class:`BondList` will be created for the
resulting :class:`AtomArray` containing the bond information
from the file.
All bonds have :attr:`BondType.ANY`, since the PDB format
does not support bond orders.
Bonds, whose order could not be determined from the
*Chemical Component Dictionary*
(e.g. especially inter-residue bonds),
have :attr:`BondType.ANY`, since the PDB format itself does
not support bond orders.
Returns
-------
Expand Down Expand Up @@ -257,8 +263,11 @@ def get_symmetry_mates(pdb_file, model=None, altloc="first",
If set to true, a :class:`BondList` will be created for the
resulting :class:`AtomArray` containing the bond information
from the file.
All bonds have :attr:`BondType.ANY`, since the PDB format
does not support bond orders.
Bonds, whose order could not be determined from the
*Chemical Component Dictionary*
(e.g. especially inter-residue bonds),
have :attr:`BondType.ANY`, since the PDB format itself does
not support bond orders.
Returns
-------
Expand Down
32 changes: 17 additions & 15 deletions src/biotite/structure/io/pdb/file.py
Original file line number Diff line number Diff line change
Expand Up @@ -360,8 +360,11 @@ def get_structure(self, model=None, altloc="first", extra_fields=[],
If set to true, a :class:`BondList` will be created for the
resulting :class:`AtomArray` containing the bond information
from the file.
All bonds have :attr:`BondType.ANY`, since the PDB format
does not support bond orders.
Bonds, whose order could not be determined from the
*Chemical Component Dictionary*
(e.g. especially inter-residue bonds),
have :attr:`BondType.ANY`, since the PDB format itself does
not support bond orders.
Returns
-------
Expand Down Expand Up @@ -536,15 +539,8 @@ def get_structure(self, model=None, altloc="first", extra_fields=[],
# Read bonds
if include_bonds:
bond_list = self._get_bonds(atom_id)
bond_list = bond_list.merge(connect_via_residue_names(
array,
# The information for non-hetero residues and water
# are not part of CONECT records
(~array.hetero) | filter_solvent(array)
))
# Remove bond order from inter residue bonds for consistency
bond_list.remove_bond_order()
array.bonds = bond_list
bond_list = bond_list.merge(connect_via_residue_names(array))
array.bonds = bond_list

return array

Expand Down Expand Up @@ -794,8 +790,11 @@ def get_assembly(self, assembly_id=None, model=None, altloc="first",
If set to true, a :class:`BondList` will be created for the
resulting :class:`AtomArray` containing the bond information
from the file.
All bonds have :attr:`BondType.ANY`, since the PDB format
does not support bond orders.
Bonds, whose order could not be determined from the
*Chemical Component Dictionary*
(e.g. especially inter-residue bonds),
have :attr:`BondType.ANY`, since the PDB format itself does
not support bond orders.
Returns
-------
Expand Down Expand Up @@ -946,8 +945,11 @@ def get_symmetry_mates(self, model=None, altloc="first",
If set to true, a :class:`BondList` will be created for the
resulting :class:`AtomArray` containing the bond information
from the file.
All bonds have :attr:`BondType.ANY`, since the PDB format
does not support bond orders.
Bonds, whose order could not be determined from the
*Chemical Component Dictionary*
(e.g. especially inter-residue bonds),
have :attr:`BondType.ANY`, since the PDB format itself does
not support bond orders.
Returns
-------
Expand Down
2 changes: 1 addition & 1 deletion tests/structure/test_bonds.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ def test_merge(bond_list):
"""
Test merging two `BondList` objects on a known example.
"""
merged_list = bond_list.merge(struc.BondList(8, np.array([(4,6),(6,7)])))
merged_list = struc.BondList(8, np.array([(4,6),(6,7)])).merge(bond_list)
assert merged_list.as_array().tolist() == [[0, 1, 0],
[1, 2, 0],
[1, 3, 0],
Expand Down
1 change: 1 addition & 0 deletions tests/structure/test_pdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,7 @@ def test_bond_parsing():
atoms = pdb.get_structure(pdb_file, model=1, include_bonds=True)

test_bonds = atoms.bonds
test_bonds.remove_bond_order()

ref_bonds = struc.connect_via_residue_names(atoms)
ref_bonds.remove_bond_order()
Expand Down

0 comments on commit d908ac5

Please sign in to comment.