Skip to content

Commit 4201b26

Browse files
CalCravenpre-commit-ci[bot]chrisjonesBSU
authored
Bonds and Angles handle wildcards for bonds and sites. (#928)
* Add bond/angle wildcard handling * change dihedral sample value so that c5 is 0 and rb torsion conversion is allowed * Add tests for reversed version of wildcard ordering * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Change get_forcefield methods and parameterizations to apply wildcard parameters * Add classes and types to gmso xsd schema, proprely get mbuild bond_orders * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Add doc strings for connections bonds functions, remove bonds setter, and dynamically set bonds based on connection_members when initialized with set_dependent_value_default * rename some of the utility functions used in identifying connections via masking, remove unused functions * pin openmm to less than 8.4 * Use equivalents for _get_improper_type strings --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Chris Jones <[email protected]>
1 parent e054116 commit 4201b26

24 files changed

+704
-378
lines changed

environment-dev.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ dependencies:
1818
- pytest
1919
- garnett>=0.7.1
2020
- openff-toolkit-base>0.16.7
21-
- openmm
21+
- openmm<8.4.0
2222
- gsd>=2.9
2323
- freud>=3.2
2424
- parmed>=3.4.3

gmso/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,4 +138,4 @@ def print_level(self, level: str):
138138

139139
# Example usage in __init__.py
140140
gmso_logger = GMSOLogger()
141-
gmso_logger.library_logger.setLevel(logging.INFO)
141+
gmso_logger.library_logger.setLevel(logging.WARNING)

gmso/abc/abstract_connection.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import itertools
12
from typing import Optional, Sequence
23

34
from pydantic import ConfigDict, Field, model_validator
@@ -111,3 +112,16 @@ def __repr__(self):
111112

112113
def __str__(self):
113114
return f"<{self.__class__.__name__} {self.name}, id: {id(self)}> "
115+
116+
def get_connection_identifiers(self):
117+
borderDict = {1: "-", 2: "=", 3: "#", 0: "~", None: "~", 1.5: ":"}
118+
choices = [
119+
(site.atom_type.name, site.atom_type.atomclass, "*")
120+
for site in self.connection_members
121+
]
122+
if not getattr(self, "bonds", None):
123+
bond_identifiers = [borderDict[self.bond_order]]
124+
else:
125+
bond_identifiers = [borderDict[b.bond_order] for b in self.bonds]
126+
choices += [(val, "~") for val in bond_identifiers]
127+
return itertools.product(*choices)

gmso/core/angle.py

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@
22

33
from typing import Callable, ClassVar, Optional, Tuple
44

5-
from pydantic import ConfigDict, Field
5+
from pydantic import ConfigDict, Field, model_validator
66

77
from gmso.abc.abstract_connection import Connection
88
from gmso.core.angle_type import AngleType
99
from gmso.core.atom import Atom
10+
from gmso.core.bond import Bond
1011

1112

1213
class Angle(Connection):
@@ -22,16 +23,30 @@ class Angle(Connection):
2223
__eq__, __repr__, _validate methods
2324
2425
Additional _validate methods are presented.
26+
27+
self.connectivity is the associated indices that defines the way connection_members are bonded to match self.bonds.
2528
"""
2629

2730
__members_creator__: ClassVar[Callable] = Atom.model_validate
2831

32+
connectivity: ClassVar[Tuple[Tuple[int]]] = ((0, 1), (1, 2))
33+
2934
connection_members_: Tuple[Atom, Atom, Atom] = Field(
3035
...,
3136
description="The 3 atoms involved in the angle.",
3237
alias="connection_members",
3338
)
3439

40+
bonds_: Tuple[Bond, Bond] = Field(
41+
default=None,
42+
description="""
43+
List of connection bonds.
44+
Ordered to align with connection_members, such that self.bonds_[0] is
45+
the bond between (self.connection_members[0], self.connection_members[1]).
46+
""",
47+
alias="bonds",
48+
)
49+
3550
angle_type_: Optional[AngleType] = Field(
3651
default=None,
3752
description="AngleType of this angle.",
@@ -48,6 +63,7 @@ class Angle(Connection):
4863
""",
4964
alias="restraint",
5065
)
66+
5167
model_config = ConfigDict(
5268
alias_to_fields=dict(
5369
**Connection.model_config["alias_to_fields"],
@@ -73,6 +89,16 @@ def restraint(self):
7389
"""Return the restraint of this angle."""
7490
return self.__dict__.get("restraint_")
7591

92+
@property
93+
def bonds(self):
94+
"""Return a tuple of gmso.core.Bond objects that correspond to this angle."""
95+
return self.__dict__.get("bonds_")
96+
97+
@property
98+
def bonds_orders(self):
99+
"""Return the bond_order strings of this angle."""
100+
return "".join([str(b.bond_order) for b in self.bonds])
101+
76102
def equivalent_members(self):
77103
"""Return a set of the equivalent connection member tuples.
78104
@@ -99,3 +125,15 @@ def __setattr__(self, key, value):
99125
super(Angle, self).__setattr__("angle_type", value)
100126
else:
101127
super(Angle, self).__setattr__(key, value)
128+
129+
@model_validator(mode="before")
130+
@classmethod
131+
def set_dependent_value_default(cls, data):
132+
"""Automatically set bonds for this angle if connection_members is defined."""
133+
if "bonds" not in data and "connection_members" in data:
134+
atoms = data["connection_members"]
135+
data["bonds"] = (
136+
Bond(connection_members=(atoms[0], atoms[1])),
137+
Bond(connection_members=(atoms[1], atoms[2])),
138+
)
139+
return data

gmso/core/bond.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ class Bond(Connection):
2626

2727
__members_creator__: ClassVar[Callable] = Atom.model_validate
2828

29+
connectivity: ClassVar[Tuple[Tuple[int]]] = ((0, 1),)
30+
2931
connection_members_: Tuple[Atom, Atom] = Field(
3032
...,
3133
description="The 2 atoms involved in the bond.",
@@ -46,12 +48,20 @@ class Bond(Connection):
4648
""",
4749
alias="restraint",
4850
)
51+
52+
bond_order_: Optional[float] = Field(
53+
default=None,
54+
description="Bond order of this bond.",
55+
alias="bond_order",
56+
)
57+
4958
model_config = ConfigDict(
5059
alias_to_fields=dict(
5160
**Connection.model_config["alias_to_fields"],
5261
**{
5362
"bond_type": "bond_type_",
5463
"restraint": "restraint_",
64+
"bond_order": "bond_order_",
5565
},
5666
)
5767
)
@@ -71,6 +81,16 @@ def restraint(self):
7181
"""Return the restraint of this bond."""
7282
return self.__dict__.get("restraint_")
7383

84+
@property
85+
def bond_order(self):
86+
"""Return the bond_order of this bond."""
87+
return self.__dict__.get("bond_order_")
88+
89+
@bond_order.setter
90+
def bond_order(self, order):
91+
"""Set the bond_order of this bond."""
92+
self._bond_order = order
93+
7494
def equivalent_members(self):
7595
"""Get a set of the equivalent connection member tuples.
7696

gmso/core/dihedral.py

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
from typing import Callable, ClassVar, Optional, Tuple
22

3-
from pydantic import ConfigDict, Field
3+
from pydantic import ConfigDict, Field, model_validator
44

55
from gmso.abc.abstract_connection import Connection
66
from gmso.core.atom import Atom
7+
from gmso.core.bond import Bond
78
from gmso.core.dihedral_type import DihedralType
89

910

@@ -28,12 +29,24 @@ class Dihedral(Connection):
2829

2930
__members_creator__: ClassVar[Callable] = Atom.model_validate
3031

32+
connectivity: ClassVar[Tuple[Tuple[int]]] = ((0, 1), (1, 2), (2, 3))
33+
3134
connection_members_: Tuple[Atom, Atom, Atom, Atom] = Field(
3235
...,
3336
description="The 4 atoms involved in the dihedral.",
3437
alias="connection_members",
3538
)
3639

40+
bonds_: Tuple[Bond, Bond, Bond] = Field(
41+
default=None,
42+
description="""
43+
List of connection bonds.
44+
Ordered to align with connection_members, such that self.bonds_[0] is
45+
the bond between (self.connection_members[0], self.connection_members[1]).
46+
""",
47+
alias="bonds",
48+
)
49+
3750
dihedral_type_: Optional[DihedralType] = Field(
3851
default=None,
3952
description="DihedralType of this dihedral.",
@@ -50,6 +63,7 @@ class Dihedral(Connection):
5063
""",
5164
alias="restraint",
5265
)
66+
5367
model_config = ConfigDict(
5468
alias_to_fields=dict(
5569
**Connection.model_config["alias_to_fields"],
@@ -74,6 +88,19 @@ def restraint(self):
7488
"""Return the restraint of this dihedral."""
7589
return self.__dict__.get("restraint_")
7690

91+
@property
92+
def bonds(self):
93+
"""Return the bonds that makeup this dihedral.
94+
95+
Connectivity is ((0,1), (1,2), (2,3))
96+
"""
97+
return self.__dict__.get("bonds_")
98+
99+
@property
100+
def bonds_orders(self):
101+
"""Return the bond_order strings of this dihedral."""
102+
return "".join([b.bond_order for b in self.bonds])
103+
77104
def equivalent_members(self):
78105
"""Get a set of the equivalent connection member tuples
79106
@@ -99,3 +126,16 @@ def __setattr__(self, key, value):
99126
super(Dihedral, self).__setattr__("dihedral_type_", value)
100127
else:
101128
super(Dihedral, self).__setattr__(key, value)
129+
130+
@model_validator(mode="before")
131+
@classmethod
132+
def set_dependent_value_default(cls, data):
133+
"""Automatically set bonds for this dihedral if connection_members is defined."""
134+
if "bonds" not in data and "connection_members" in data:
135+
atoms = data["connection_members"]
136+
data["bonds"] = (
137+
Bond(connection_members=(atoms[0], atoms[1])),
138+
Bond(connection_members=(atoms[1], atoms[2])),
139+
Bond(connection_members=(atoms[2], atoms[3])),
140+
)
141+
return data

0 commit comments

Comments
 (0)