Skip to content

Commit

Permalink
add intra stuff
Browse files Browse the repository at this point in the history
  • Loading branch information
lilyminium committed Apr 7, 2021
1 parent 20dbe88 commit f37d148
Show file tree
Hide file tree
Showing 11 changed files with 85 additions and 103 deletions.
56 changes: 3 additions & 53 deletions package/CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ The rules for this file:
* 2.0.0

Fixes
<<<<<<< HEAD
* A Universe created from an ROMol with no atoms returns now a Universe
with 0 atoms (Issue #3142)
* ValueError raised when empty atomgroup is given to DensityAnalysis
Expand All @@ -39,55 +38,6 @@ Fixes
* PDB writer now uses elements attribute instead of guessing elements from
atom name (Issue #2423)
* Cleanup and parametrization of test_atomgroup.py (Issue #2995)
=======
* Removes use of absolute paths in setup.py to avoid Windows installation
failures (Issue #3129)
* Adds test for crashes caused by small box NSGrid searches (Issue #2670)
* Replaces decreated NumPy type aliases and fixes NEP 34 explicit ragged
array warnings (PR #3139, backports PRs #2845 and #2834)
* Fixed several issues with NSGrid and triclinic boxes not finding some pairs.
(Issues #2229 #2345 #2919, PR #2937).

Changes
* Maximum pinned versions in setup.py removed for python 3.6+ (PR #3139)

Deprecations
* ParmEdConverter no longer accepts Timestep objects at all
(Issue #3031, PR #3172)
* NCDFWriter `scale_factor` writing will change in version 2.0 to
better match AMBER outputs (Issue #2327)
* Deprecated using the last letter of the segid as the
chainID when writing PDB files (Issue #3144)
* Deprecated tempfactors and bfactors being separate
TopologyAttrs, with a warning (PR #3161)
* hbonds.WaterBridgeAnalysis will be removed in 2.0.0 and
replaced with hydrogenbonds.WaterBridgeAnalysis (#3111)
* TPRParser indexing resids from 0 by default is deprecated.
From 2.0 TPRParser will index resids from 1 by default.


Enhancements
* Added `get_connections` method to get bonds, angles, dihedrals, etc.
with or without atoms outside the group (Issues #1264, #2821, PR #3160)
* Added `tpr_resid_from_one` keyword to select whether TPRParser
indexes resids from 0 or 1 (Issue #2364, PR #3153)


01/17/21 richardjgowers, IAlibay, orbeckst, tylerjereddy, jbarnoud,
yuxuanzhuang, lilyminium, VOD555, p-j-smith, bieniekmateusz,
calcraven, ianmkenney, rcrehuet, manuel.nuno.melo, hanatok

* 1.0.1

Fixes
* Due to issues with the reliability/accuracy of `nsgrid`, this method is
currently not recommended for use. It has also been removed as an option
from lib.capped_distance and lib.self_capped_distance. Please use PKDTree
instead (Issue #2930)
* Development status changed from beta to mature (Issue #2773)
* pip installation only requests Python 2.7-compatible packages (#2736)
* Testsuite does not use any more matplotlib.use('agg') (#2191)
>>>>>>> c58d2d370... undo half of PR 3160
* The methods provided by topology attributes now appear in the
documentation (Issue #1845)
* AtomGroup.center now works correctly for compounds + unwrapping
Expand Down Expand Up @@ -137,6 +87,9 @@ Fixes
* Fix syntax warning over comparison of literals using is (Issue #3066)

Enhancements
* Added intra_bonds, intra_angles, intra_dihedrals etc. to return only
the connections involving atoms within the AtomGroup, instead of
including atoms outside the AtomGroup (Issue #1264, #2821, PR #3200)
* Added a ValueError raised when not given a gridcenter while
providing grid dimensions to DensityAnalysis, also added
check for NaN in the input (Issue #3148, PR #3154)
Expand Down Expand Up @@ -191,9 +144,6 @@ Enhancements


Changes
* AtomGroup.bonds, .angles, .dihedrals, .impropers etc. now return only
the connections involving atoms within the AtomGroup, instead of
including atoms outside the AtomGroup (Issue #1264, #2821, PR #3200)
* TPRParser now loads TPR files with `tpr_resid_from_one=True` by default,
which starts TPR resid indexing from 1 (instead of 0 as in 1.x) (Issue #2364, PR #3152)
* Introduces encore specific C compiler arguments to allow for lowering of
Expand Down
2 changes: 1 addition & 1 deletion package/MDAnalysis/coordinates/MOL2.py
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ def encode_block(self, obj):
if hasattr(obj, "bonds"):
# Grab only bonds between atoms in the obj
# ie none that extend out of it
bondgroup = obj.bonds
bondgroup = obj.intra_bonds
bonds = sorted((b[0], b[1], b.order) for b in bondgroup)
bond_lines = ["@<TRIPOS>BOND"]
bls = ["{0:>5} {1:>5} {2:>5} {3:>2}".format(bid,
Expand Down
2 changes: 1 addition & 1 deletion package/MDAnalysis/coordinates/ParmEd.py
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ def convert(self, obj):

# bonds
try:
params = ag_or_ts.bonds
params = ag_or_ts.intra_bonds
except AttributeError:
pass
else:
Expand Down
5 changes: 2 additions & 3 deletions package/MDAnalysis/core/selection.py
Original file line number Diff line number Diff line change
Expand Up @@ -525,15 +525,14 @@ def __init__(self, parser, tokens):
def apply(self, group):
grp = self.sel.apply(group)
# Check if we have bonds
bonds = group.get_connections("bonds", outside=True)
if not bonds:
if not group.bonds:
warnings.warn("Bonded selection has 0 bonds")
return group[[]]

grpidx = grp.indices

# (n, 2) array of bond indices
bix = np.array(bonds.to_indices())
bix = np.array(group.bonds.to_indices())

idx = []
# left side
Expand Down
22 changes: 17 additions & 5 deletions package/MDAnalysis/core/topologyattrs.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,19 @@
These are usually read by the TopologyParser.
"""

import Bio.Seq
import Bio.SeqRecord
from collections import defaultdict
import copy
import functools
import itertools
import numbers
import numpy as np
from inspect import signature as inspect_signature
import warnings
import textwrap
from inspect import signature as inspect_signature
from types import MethodType

import Bio.Seq
import Bio.SeqRecord
import numpy as np

from ..lib.util import (cached, convert_aa_code, iterable, warn_if_not_unique,
unique_int_1d)
Expand Down Expand Up @@ -263,6 +265,11 @@ def _attach_transplant_stubs(attribute_name, topology_attribute_class):
setattr(dest_class, method_name, stub)


def intra_connection(self, ag):
"""Get connections only within this AtomGroup
"""
return ag.get_connections(self.attrname, outside=False)

class _TopologyAttrMeta(type):
r"""Register TopologyAttrs on class creation
Expand Down Expand Up @@ -291,6 +298,12 @@ def __init__(cls, name, bases, classdict):
if attrname is None:
attrname = singular

# add intra connections
if any("Connection" in x.__name__ for x in cls.__bases__):
method = MethodType(intra_connection, cls)
prop = property(method, None, None, method.__doc__)
cls.transplants[AtomGroup].append((f"intra_{attrname}", prop))

if singular:
_TOPOLOGY_ATTRS[singular] = _TOPOLOGY_ATTRS[attrname] = cls
_singular = singular.lower().replace('_', '')
Expand Down Expand Up @@ -2310,7 +2323,6 @@ def get_atoms(self, ag):
except TypeError:
# maybe we got passed an Atom
unique_bonds = self._bondDict[ag.ix]
outside = True
unique_bonds = np.array(sorted(unique_bonds), dtype=object)
bond_idx, types, guessed, order = np.hsplit(unique_bonds, 4)
bond_idx = np.array(bond_idx.ravel().tolist(), dtype=np.int32)
Expand Down
22 changes: 22 additions & 0 deletions testsuite/MDAnalysisTests/core/test_groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -1585,3 +1585,25 @@ def test_get_empty_group(self, tpr, outside):
cxns = ag.get_connections("impropers", outside=outside)
assert len(imp) == 0
assert len(cxns) == 0

@pytest.mark.parametrize("typename, n_inside", [
("intra_bonds", 9),
("intra_angles", 15),
("intra_dihedrals", 12),
])
def test_topologygroup_gets_connections_inside(tpr, typename, n_inside):
ag = tpr.atoms[:10]
cxns = getattr(ag, typename)
assert len(cxns) == n_inside
indices = np.ravel(cxns.to_indices())
assert np.all(np.in1d(indices, ag.indices))

@pytest.mark.parametrize("typename, n_outside", [
("bonds", 13),
("angles", 27),
("dihedrals", 38),
])
def test_topologygroup_gets_connections_outside(tpr, typename, n_outside):
ag = tpr.atoms[:10]
cxns = getattr(ag, typename)
assert len(cxns) == n_outside
15 changes: 7 additions & 8 deletions testsuite/MDAnalysisTests/core/test_topologyobjects.py
Original file line number Diff line number Diff line change
Expand Up @@ -278,8 +278,7 @@ def test_td_universe(self, b_td, PSFDCD):
def test_bonds_types(self, PSFDCD, res1):
"""Tests TopologyDict for bonds"""
assert len(PSFDCD.atoms.bonds.types()) == 57
assert len(res1.atoms.get_connections("bonds").types()) == 12
assert len(res1.atoms.bonds.types()) == 11
assert len(res1.atoms.bonds.types()) == 12

def test_bonds_contains(self, b_td):
assert ('57', '2') in b_td
Expand Down Expand Up @@ -426,8 +425,8 @@ def test_TG_loose_intersection(self, PSFDCD, attr):
"""Pull bonds from a TG which are at least partially in an AG"""
ag = PSFDCD.atoms[10:60]

TG = PSFDCD.atoms.get_connections(attr, outside=True)
ref = ag.get_connections(attr, outside=True)
TG = getattr(PSFDCD.atoms, attr)
ref = getattr(ag, attr)
newTG = TG.atomgroup_intersection(ag)

assert newTG == ref
Expand Down Expand Up @@ -613,22 +612,22 @@ class TestTopologyGroup_Cython(object):
@staticmethod
@pytest.fixture
def bgroup(PSFDCD):
return PSFDCD.atoms[:5].get_connections("bonds", outside=True)
return PSFDCD.atoms[:5].bonds

@staticmethod
@pytest.fixture
def agroup(PSFDCD):
return PSFDCD.atoms[:5].get_connections("angles", outside=True)
return PSFDCD.atoms[:5].angles

@staticmethod
@pytest.fixture
def dgroup(PSFDCD):
return PSFDCD.atoms[:5].get_connections("dihedrals", outside=True)
return PSFDCD.atoms[:5].dihedrals

@staticmethod
@pytest.fixture
def igroup(PSFDCD):
return PSFDCD.atoms[:5].get_connections("impropers", outside=True)
return PSFDCD.atoms[:5].impropers

# bonds
def test_wrong_type_bonds(self, agroup, dgroup, igroup):
Expand Down
18 changes: 9 additions & 9 deletions testsuite/MDAnalysisTests/topology/test_itp.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@ class TestITP(BaseITP):


def test_bonds_atom_counts(self, universe):
assert len(universe.atoms[0].bonds) == 3
assert len(universe.atoms[42].bonds) == 1
assert len(universe.atoms[[0]].bonds) == 3
assert len(universe.atoms[[42]].bonds) == 1

def test_bonds_values(self, top):
vals = top.bonds.values
Expand All @@ -99,8 +99,8 @@ def test_bonds_type(self, universe):
assert universe.bonds[0].type == 2

def test_angles_atom_counts(self, universe):
assert len(universe.atoms[0].angles) == 5
assert len(universe.atoms[42].angles) == 2
assert len(universe.atoms[[0]].angles) == 5
assert len(universe.atoms[[42]].angles) == 2

def test_angles_values(self, top):
vals = top.angles.values
Expand All @@ -111,7 +111,7 @@ def test_angles_type(self, universe):
assert universe.angles[0].type == 2

def test_dihedrals_atom_counts(self, universe):
assert len(universe.atoms[0].dihedrals) == 2
assert len(universe.atoms[[0]].dihedrals) == 2

def test_dihedrals_multiple_types(self, universe):
ag = universe.atoms[[0, 3, 5, 7]]
Expand All @@ -128,7 +128,7 @@ def test_dihedrals_type(self, universe):


def test_impropers_atom_counts(self, universe):
assert len(universe.atoms[0].impropers) == 1
assert len(universe.atoms[[0]].impropers) == 1

def test_impropers_values(self, top):
vals = top.impropers.values
Expand Down Expand Up @@ -174,11 +174,11 @@ def test_no_extra_angles(self, top):
assert a not in top.angles.values

def test_bonds_atom_counts(self, universe):
assert len(universe.atoms[0].bonds) == 5
assert len(universe.atoms[42].bonds) == 5
assert len(universe.atoms[[0]].bonds) == 5
assert len(universe.atoms[[42]].bonds) == 5

def test_dihedrals_atom_counts(self, universe):
assert len(universe.atoms[0].dihedrals) == 1
assert len(universe.atoms[[0]].dihedrals) == 1

def test_dihedrals_identity(self, universe):
assert universe.dihedrals[0].type == (1, 1)
Expand Down
20 changes: 10 additions & 10 deletions testsuite/MDAnalysisTests/topology/test_parmed.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,8 @@ class TestParmedParserPSF(BaseTestParmedParser):
expected_elems = (np.array(['' for i in range(3341)], dtype=object),)

def test_bonds_atom_counts(self, universe):
assert len(universe.atoms[0].bonds) == 4
assert len(universe.atoms[42].bonds) == 1
assert len(universe.atoms[[0]].bonds) == 4
assert len(universe.atoms[[42]].bonds) == 1

@pytest.mark.parametrize('value', (
(0, 1),
Expand All @@ -145,8 +145,8 @@ def test_bond_types(self, universe):
assert b1.type.type is None

def test_angles_atom_counts(self, universe):
assert len(universe.atoms[0].angles), 9
assert len(universe.atoms[42].angles), 2
assert len(universe.atoms[[0]].angles), 9
assert len(universe.atoms[[42]].angles), 2

@pytest.mark.parametrize('value', (
(1, 0, 2),
Expand All @@ -158,7 +158,7 @@ def test_angles_identity(self, top, value):
assert value in vals or value[::-1] in vals

def test_dihedrals_atom_counts(self, universe):
assert len(universe.atoms[0].dihedrals) == 14
assert len(universe.atoms[[0]].dihedrals) == 14

@pytest.mark.parametrize('value', (
(0, 4, 6, 7),
Expand Down Expand Up @@ -195,8 +195,8 @@ class TestParmedParserPRM(BaseTestParmedParser):
dtype=object))

def test_bonds_atom_counts(self, universe):
assert len(universe.atoms[0].bonds) == 4
assert len(universe.atoms[42].bonds) == 1
assert len(universe.atoms[[0]].bonds) == 4
assert len(universe.atoms[[42]].bonds) == 1

@pytest.mark.parametrize('value', (
(10, 11),
Expand All @@ -217,8 +217,8 @@ def test_bond_types(self, universe):
assert b1.type.type.req == 1.010

def test_angles_atom_counts(self, universe):
assert len(universe.atoms[0].angles), 9
assert len(universe.atoms[42].angles), 2
assert len(universe.atoms[[0]].angles), 9
assert len(universe.atoms[[42]].angles), 2

@pytest.mark.parametrize('value', (
(11, 10, 12),
Expand All @@ -231,7 +231,7 @@ def test_angles_identity(self, top, value):
assert value in vals or value[::-1] in vals

def test_dihedrals_atom_counts(self, universe):
assert len(universe.atoms[0].dihedrals) == 14
assert len(universe.atoms[[0]].dihedrals) == 14

@pytest.mark.parametrize('value', (
(11, 10, 12, 14),
Expand Down
10 changes: 5 additions & 5 deletions testsuite/MDAnalysisTests/topology/test_psf.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,8 @@ def test_bonds_total_counts(self, top):

def test_bonds_atom_counts(self, filename):
u = mda.Universe(filename)
assert len(u.atoms[0].bonds) == 4
assert len(u.atoms[42].bonds) == 1
assert len(u.atoms[[0]].bonds) == 4
assert len(u.atoms[[42]].bonds) == 1

def test_bonds_identity(self, top):
vals = top.bonds.values
Expand All @@ -85,8 +85,8 @@ def test_angles_total_counts(self, top):

def test_angles_atom_counts(self, filename):
u = mda.Universe(filename)
assert len(u.atoms[0].angles), 9
assert len(u.atoms[42].angles), 2
assert len(u.atoms[[0]].angles), 9
assert len(u.atoms[[42]].angles), 2

def test_angles_identity(self, top):
vals = top.angles.values
Expand All @@ -98,7 +98,7 @@ def test_dihedrals_total_counts(self, top):

def test_dihedrals_atom_counts(self, filename):
u = mda.Universe(filename)
assert len(u.atoms[0].dihedrals) == 14
assert len(u.atoms[[0]].dihedrals) == 14

def test_dihedrals_identity(self, top):
vals = top.dihedrals.values
Expand Down
Loading

0 comments on commit f37d148

Please sign in to comment.