Skip to content

Commit 9eb6c8d

Browse files
chrisjonesBSUpre-commit-ci[bot]daico007
authored
Add attribute that tracks number of bonds a particle is involved in. (#1024)
* add direct bond attribute that is updated anytime add_bond and remove_bond is called * add _direct_bonds update when cloning a compound * fix index error, adjust direct bonds attr when using force_overlap * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * fix doc string typo * add a couple more unit tests, fix double counting bonds when cloning * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * check for num particle bonds via bond_graph. Remove _direct_bonds attr * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * change doc strings back to original * create direct_bonds function, update unit tests * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * clarify doc strings * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * split direct_bonds into 2 functions * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * update unit tests with new changes * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * turn direct_bonds into a generator) * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * fix conditional statements in n_direct_bonds) * fix unit tests * fix remove unit tests * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * fixing doc strings per pre-commit * Update mbuild/compound.py update docstring Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Co Quach <43968221+daico007@users.noreply.github.com>
1 parent b0e0807 commit 9eb6c8d

File tree

2 files changed

+94
-7
lines changed

2 files changed

+94
-7
lines changed

mbuild/compound.py

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -932,6 +932,29 @@ def available_ports(self):
932932
if isinstance(p, Port) and not p.used
933933
]
934934

935+
def direct_bonds(self):
936+
"""Return a list of particles that this particle bonds to.
937+
938+
Returns
939+
-------
940+
List of mb.Compound
941+
942+
See Also
943+
--------
944+
bond_graph.edges_iter : Iterations over all edges in a BondGraph
945+
Compound.n_direct_bonds() : Returns the number of bonds a particle contains
946+
"""
947+
if list(self.particles()) != [self]:
948+
raise MBuildError(
949+
"The direct_bonds method can only "
950+
"be used on compounds at the bottom of their hierarchy."
951+
)
952+
if not self.root.bond_graph:
953+
return iter(())
954+
elif self.root.bond_graph.has_node(self):
955+
for i in self.root.bond_graph._adj[self]:
956+
yield i
957+
935958
def bonds(self):
936959
"""Return all bonds in the Compound and sub-Compounds.
937960
@@ -943,6 +966,8 @@ def bonds(self):
943966
See Also
944967
--------
945968
bond_graph.edges_iter : Iterates over all edges in a BondGraph
969+
Compound.n_bonds() : Returns the total number of bonds in the Compound
970+
and sub-Compounds
946971
"""
947972
if self.root.bond_graph:
948973
if self.root == self:
@@ -954,15 +979,40 @@ def bonds(self):
954979
else:
955980
return iter(())
956981

982+
@property
983+
def n_direct_bonds(self):
984+
"""Return the number of bonds a particle is directly involved in.
985+
986+
This method should only be used on on compounds at the bottom
987+
of their hierarchy (i.e. a particle).
988+
989+
Returns
990+
-------
991+
int
992+
The number of compounds this compound is directly bonded to.
993+
"""
994+
if list(self.particles()) != [self]:
995+
raise MBuildError(
996+
"The direct_bonds method can only "
997+
"be used on compounds at the bottom of their hierarchy."
998+
)
999+
return sum(1 for _ in self.direct_bonds())
1000+
9571001
@property
9581002
def n_bonds(self):
959-
"""Return the number of bonds in the Compound.
1003+
"""Return the total number of bonds in the Compound.
9601004
9611005
Returns
9621006
-------
9631007
int
9641008
The number of bonds in the Compound
9651009
"""
1010+
if list(self.particles()) == [self]:
1011+
raise MBuildError(
1012+
"n_bonds cannot be used on Compounds "
1013+
"at the bottom of their hierarchy (particles). "
1014+
"Use n_direct_bonds instead."
1015+
)
9661016
return sum(1 for _ in self.bonds())
9671017

9681018
def add_bond(self, particle_pair):
@@ -2704,6 +2754,7 @@ def __repr__(self):
27042754

27052755
if self.children:
27062756
descr.append("{:d} particles, ".format(self.n_particles))
2757+
descr.append("{:d} bonds, ".format(self.n_bonds))
27072758
if self.box is not None:
27082759
descr.append("System box: {}, ".format(self.box))
27092760
else:
@@ -2712,8 +2763,7 @@ def __repr__(self):
27122763
descr.append(
27132764
"pos=({}), ".format(np.array2string(self.pos, precision=4))
27142765
)
2715-
2716-
descr.append("{:d} bonds, ".format(self.n_bonds))
2766+
descr.append("{:d} bonds, ".format(self.n_direct_bonds))
27172767

27182768
descr.append("id: {}>".format(id(self)))
27192769
return "".join(descr)

mbuild/tests/test_compound.py

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,43 @@ def __init__(self):
100100
def test_update_from_file(self, ch3):
101101
ch3.update_coordinates(get_fn("methyl.pdb"))
102102

103+
def test_n_bonds_particle(self):
104+
comp = mb.Compound(name="A", pos=[0, 0, 0])
105+
with pytest.raises(MBuildError):
106+
comp.n_bonds
107+
108+
def test_direct_bonds_parent(self, methane):
109+
with pytest.raises(MBuildError):
110+
bond_particles = [i for i in methane.direct_bonds()]
111+
112+
def test_direct_bonds(self, methane):
113+
bond_particles = [i for i in methane[0].direct_bonds()]
114+
for H in methane.particles_by_name("H"):
115+
assert H in bond_particles
116+
117+
def test_n_direct_bonds_parent(self, ethane):
118+
with pytest.raises(MBuildError):
119+
ethane.n_direct_bonds
120+
121+
def test_n_direct_bonds(self, ethane):
122+
assert ethane[0].n_direct_bonds == 4
123+
assert ethane[-1].n_direct_bonds == 1
124+
hydrogens = [p for p in ethane.particles_by_name("H")]
125+
for p in hydrogens:
126+
ethane.remove(p)
127+
assert ethane[0].n_direct_bonds == 1
128+
ethane.remove(ethane[-1])
129+
assert ethane[0].n_direct_bonds == 0
130+
131+
def test_n_direct_bonds_no_graph(self):
132+
comp = mb.Compound(name="A", pos=[0, 0, 0])
133+
assert comp.n_direct_bonds == 0
134+
135+
def test_direct_bonds_cloning(self, ethane):
136+
ethane_clone = mb.clone(ethane)
137+
for p1, p2 in zip(ethane.particles(), ethane_clone.particles()):
138+
assert p1.n_direct_bonds == p2.n_direct_bonds
139+
103140
def test_load_protein(self):
104141
# Testing the loading function with complicated protein,
105142
# The protein file is taken from RCSB protein data bank
@@ -548,7 +585,7 @@ def test_remove(self, ethane):
548585
carbons = ethane1.particles_by_name("C")
549586
ethane1.remove(carbons)
550587
assert ethane1.n_particles == 1 # left with the highest Compound
551-
assert ethane1.n_bonds == 0
588+
assert ethane1.n_direct_bonds == 0
552589
assert len(ethane1.children) == 0 # left with highest Compound
553590

554591
# Test remove all particles belong to a single child of an Ethane
@@ -568,7 +605,7 @@ def test_remove(self, ethane):
568605
ethane4 = mb.clone(ethane)
569606
ethane4.remove(ethane4)
570607
assert ethane4.n_particles == 1 # left with the highest Compound
571-
assert ethane4.n_bonds == 0
608+
assert ethane4.n_direct_bonds == 0
572609
assert len(ethane4.children) == 0 # left with highest Compound
573610

574611
# Test remove one subcompound and part of another
@@ -587,7 +624,7 @@ def test_remove_many(self, ethane):
587624

588625
assert ethane.n_particles == 1
589626
assert ethane._n_particles() == 0
590-
assert ethane.n_bonds == 0
627+
assert ethane.n_direct_bonds == 0
591628
for part in ethane.children:
592629
assert isinstance(part, Port)
593630

@@ -606,7 +643,7 @@ def test_remove_subcompound(self, ethane):
606643

607644
assert ethane.n_particles == 1
608645
assert ethane._n_particles() == 0
609-
assert ethane.n_bonds == 0
646+
assert ethane.n_direct_bonds == 0
610647
assert len(ethane.children) == 0
611648

612649
def test_remove_no_bond_graph(self):

0 commit comments

Comments
 (0)