Skip to content

Commit 802185d

Browse files
authored
Merge branch 'master' into 561-layered-dihedrals
2 parents c6c3242 + 0f2ef1e commit 802185d

File tree

11 files changed

+228
-27
lines changed

11 files changed

+228
-27
lines changed

azure-pipelines.yml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,13 @@ stages:
8383
8484
- bash: |
8585
source activate gmso-dev
86-
bash <(curl -s https://codecov.io/bash) -C $(Build.SourceVersion)
87-
condition: and( eq( variables['Agent.OS'], 'Linux' ), eq( variables['python.version'], '3.7' ) )
86+
curl -Os https://uploader.codecov.io/latest/linux/codecov
87+
chmod +x codecov
88+
./codecov -t ${CODECOV_UPLOAD_TOKEN} -C $(Build.SourceVersion)
89+
condition: and( eq( variables['Agent.OS'], 'Linux' ), eq( variables['python.version'], '3.7' ) )
8890
displayName: Upload coverage report to codecov.io
91+
env:
92+
CODECOV_UPLOAD_TOKEN: $(codecovUploadToken)
8993
9094
- task: PublishCodeCoverageResults@1
9195
inputs:

gmso/abc/abstract_connection.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,40 @@ def connection_members(self):
3131
def name(self):
3232
return self.__dict__.get("name_")
3333

34+
@property
35+
def member_types(self):
36+
"""Return the atomtype of the connection members as a list of string."""
37+
return self._get_members_types_or_classes("member_types_")
38+
39+
@property
40+
def member_classes(self):
41+
"""Return the class of the connection members as a list of string."""
42+
return self._get_members_types_or_classes("member_classes_")
43+
44+
def _has_typed_members(self):
45+
"""Check if all the members of this connection are typed."""
46+
return all(
47+
member.atom_type
48+
for member in self.__dict__.get("connection_members_")
49+
)
50+
51+
def _get_members_types_or_classes(self, to_return):
52+
"""Return types or classes for connection members if they exist."""
53+
assert to_return in {"member_types_", "member_classes_"}
54+
ctype = getattr(self, "connection_type")
55+
ctype_attr = getattr(ctype, to_return) if ctype else None
56+
57+
if ctype_attr:
58+
return list(ctype_attr)
59+
elif self._has_typed_members():
60+
tc = [
61+
member.atom_type.name
62+
if to_return == "member_types_"
63+
else member.atom_type.atomclass
64+
for member in self.__dict__.get("connection_members_")
65+
]
66+
return tc if all(tc) else None
67+
3468
@root_validator(pre=True)
3569
def validate_fields(cls, values):
3670
connection_members = values.get("connection_members", [])

gmso/core/angle_type.py

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,13 @@ class AngleType(ParametricPotential):
2626

2727
member_types_: Optional[Tuple[str, str, str]] = Field(
2828
None,
29-
description="List-like of gmso.AtomType.name or gmso.AtomType.atomclass "
29+
description="List-like of gmso.AtomType.name "
30+
"defining the members of this angle type",
31+
)
32+
33+
member_classes_: Optional[Tuple[str, str, str]] = Field(
34+
None,
35+
description="List-like of gmso.AtomType.atomclass "
3036
"defining the members of this angle type",
3137
)
3238

@@ -38,6 +44,7 @@ def __init__(
3844
independent_variables=None,
3945
potential_expression=None,
4046
member_types=None,
47+
member_classes=None,
4148
topology=None,
4249
tags=None,
4350
):
@@ -61,6 +68,7 @@ def __init__(
6168
potential_expression=potential_expression,
6269
topology=topology,
6370
member_types=member_types,
71+
member_classes=member_classes,
6472
set_ref=ANGLE_TYPE_DICT,
6573
tags=tags,
6674
)
@@ -69,7 +77,17 @@ def __init__(
6977
def member_types(self):
7078
return self.__dict__.get("member_types_")
7179

80+
@property
81+
def member_classes(self):
82+
return self.__dict__.get("member_classes_")
83+
7284
class Config:
73-
fields = {"member_types_": "member_types"}
85+
fields = {
86+
"member_types_": "member_types",
87+
"member_classes_": "member_classes",
88+
}
7489

75-
alias_to_fields = {"member_types": "member_types_"}
90+
alias_to_fields = {
91+
"member_types": "member_types_",
92+
"member_classes": "member_classes_",
93+
}

gmso/core/bond_type.py

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,13 @@ class BondType(ParametricPotential):
2727

2828
member_types_: Optional[Tuple[str, str]] = Field(
2929
None,
30-
description="List-like of of gmso.AtomType.name or gmso.AtomType.atomclass "
30+
description="List-like of of gmso.AtomType.name "
31+
"defining the members of this bond type",
32+
)
33+
34+
member_classes_: Optional[Tuple[str, str]] = Field(
35+
None,
36+
description="List-like of of gmso.AtomType.atomclass "
3137
"defining the members of this bond type",
3238
)
3339

@@ -39,6 +45,7 @@ def __init__(
3945
independent_variables=None,
4046
potential_expression=None,
4147
member_types=None,
48+
member_classes=None,
4249
topology=None,
4350
tags=None,
4451
):
@@ -62,6 +69,7 @@ def __init__(
6269
potential_expression=potential_expression,
6370
topology=topology,
6471
member_types=member_types,
72+
member_classes=member_classes,
6573
set_ref=BOND_TYPE_DICT,
6674
tags=tags,
6775
)
@@ -71,9 +79,19 @@ def member_types(self):
7179
"""Return the members involved in this bondtype."""
7280
return self.__dict__.get("member_types_")
7381

82+
@property
83+
def member_classes(self):
84+
return self.__dict__.get("member_classes_")
85+
7486
class Config:
7587
"""Pydantic configuration for class attributes."""
7688

77-
fields = {"member_types_": "member_types"}
89+
fields = {
90+
"member_types_": "member_types",
91+
"member_classes_": "member_classes",
92+
}
7893

79-
alias_to_fields = {"member_types": "member_types_"}
94+
alias_to_fields = {
95+
"member_types": "member_types_",
96+
"member_classes": "member_classes_",
97+
}

gmso/core/dihedral_type.py

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,16 @@ class DihedralType(ParametricPotential):
3232

3333
member_types_: Optional[Tuple[str, str, str, str]] = Field(
3434
None,
35-
description="List-like of of gmso.AtomType.name or gmso.AtomType.atomclass "
35+
description="List-like of of gmso.AtomType.name "
3636
"defining the members of this dihedral type",
3737
)
3838

39+
member_classes_: Optional[Tuple[str, str, str, str]] = Field(
40+
None,
41+
description="List-like of of gmso.AtomType.atomclass defining the "
42+
"members of this dihedral type",
43+
)
44+
3945
def __init__(
4046
self,
4147
name="DihedralType",
@@ -44,6 +50,7 @@ def __init__(
4450
independent_variables=None,
4551
potential_expression=None,
4652
member_types=None,
53+
member_classes=None,
4754
topology=None,
4855
tags=None,
4956
):
@@ -68,6 +75,7 @@ def __init__(
6875
potential_expression=potential_expression,
6976
topology=topology,
7077
member_types=member_types,
78+
member_classes=member_classes,
7179
set_ref=DIHEDRAL_TYPE_DICT,
7280
tags=tags,
7381
)
@@ -76,7 +84,17 @@ def __init__(
7684
def member_types(self):
7785
return self.__dict__.get("member_types_")
7886

79-
class Config:
80-
fields = {"member_types_": "member_types"}
87+
@property
88+
def member_classes(self):
89+
return self.__dict__.get("member_classes_")
8190

82-
alias_to_fields = {"member_types": "member_types_"}
91+
class Config:
92+
fields = {
93+
"member_types_": "member_types",
94+
"member_classes_": "member_classes",
95+
}
96+
97+
alias_to_fields = {
98+
"member_types": "member_types_",
99+
"member_classes": "member_classes_",
100+
}

gmso/core/improper_type.py

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,13 @@ class ImproperType(ParametricPotential):
3838

3939
member_types_: Optional[Tuple[str, str, str, str]] = Field(
4040
None,
41-
description="List-like of of gmso.AtomType.name or gmso.AtomType.atomclass "
41+
description="List-like of gmso.AtomType.name "
42+
"defining the members of this improper type",
43+
)
44+
45+
member_classes_: Optional[Tuple[str, str, str, str]] = Field(
46+
None,
47+
description="List-like of gmso.AtomType.atomclass "
4248
"defining the members of this improper type",
4349
)
4450

@@ -50,6 +56,7 @@ def __init__(
5056
independent_variables=None,
5157
potential_expression=None,
5258
member_types=None,
59+
member_classes=None,
5360
topology=None,
5461
tags=None,
5562
):
@@ -74,6 +81,7 @@ def __init__(
7481
potential_expression=potential_expression,
7582
topology=topology,
7683
member_types=member_types,
84+
member_classes=member_classes,
7785
set_ref=IMPROPER_TYPE_DICT,
7886
tags=tags,
7987
)
@@ -83,9 +91,19 @@ def member_types(self):
8391
"""Return member information for this ImproperType."""
8492
return self.__dict__.get("member_types_")
8593

94+
@property
95+
def member_classes(self):
96+
return self.__dict__.get("member_classes_")
97+
8698
class Config:
8799
"""Pydantic configuration for attributes."""
88100

89-
fields = {"member_types_": "member_types"}
101+
fields = {
102+
"member_types_": "member_types",
103+
"member_classes_": "member_classes",
104+
}
90105

91-
alias_to_fields = {"member_types": "member_types_"}
106+
alias_to_fields = {
107+
"member_types": "member_types_",
108+
"member_classes": "member_classes_",
109+
}

gmso/exceptions.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,9 @@ class MissingAtomTypesError(ForceFieldParseError):
2626
"""Error for missing AtomTypes when creating a ForceField from an XML file."""
2727

2828

29+
class MixedClassAndTypesError(ForceFieldParseError):
30+
"""Error for missing AtomTypes when creating a ForceField from an XML file."""
31+
32+
2933
class MissingPotentialError(ForceFieldError):
3034
"""Error for missing Potential when searching for Potentials in a ForceField."""

gmso/tests/files/ff-example0.xml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,13 @@
3131
<BondTypes expression="0.5 * k * (r-r_eq)**2">
3232
<ParametersUnitDef parameter="r_eq" unit="nm"/>
3333
<ParametersUnitDef parameter="k" unit="kJ/mol"/>
34-
<BondType name="BondType1" class1='Ar' type2='Ar'>
34+
<BondType name="BondType1" type1='Ar' type2='Ar'>
3535
<Parameters>
3636
<Parameter name='r_eq' value="10.0"/>
3737
<Parameter name='k' value="10000"/>
3838
</Parameters>
3939
</BondType>
40-
<BondType name="BondType2" type1='Xe' class2="Xe">
40+
<BondType name="BondType2" type1='Xe' type2="Xe">
4141
<Parameters>
4242
<Parameter name='r_eq' value="10"/>
4343
<Parameter name='k' value="20000"/>
@@ -65,7 +65,7 @@
6565
<DihedralTypes expression="0.5 * z * (r-r_eq)**2">
6666
<ParametersUnitDef parameter="r_eq" unit="nm"/>
6767
<ParametersUnitDef parameter="z" unit="kJ/mol"/>
68-
<DihedralType name="DihedralType1" class1='Ar' class2='Ar' type3="Ar" type4="Ar">
68+
<DihedralType name="DihedralType1" class1='Ar' class2='Ar' class3="Ar" class4="Ar">
6969
<Parameters>
7070
<Parameter name='r_eq' value="10.0"/>
7171
<Parameter name='z' value="100"/>

gmso/tests/test_bond.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,3 +100,36 @@ def test_equivalent_members_set(self):
100100

101101
assert tuple(bond_eq.connection_members) in bond.equivalent_members()
102102
assert tuple(bond.connection_members) in bond_eq.equivalent_members()
103+
104+
def test_bond_member_classes_none(self, typed_ethane):
105+
bonds = typed_ethane.bonds
106+
assert bonds[0].member_classes is None
107+
108+
def test_bond_member_types(self, typed_ethane):
109+
bonds = typed_ethane.bonds
110+
assert set(bonds[0].member_types) == set(["opls_135", "opls_140"])
111+
112+
def test_bond_member_classes_from_connection_members(self):
113+
atype1 = AtomType(atomclass="CT", name="t1")
114+
115+
atype2 = AtomType(atomclass="CK", name="t2")
116+
117+
bond = Bond(
118+
connection_members=[Atom(atom_type=atype1), Atom(atom_type=atype2)]
119+
)
120+
assert set(bond.member_classes) == set(["CT", "CK"])
121+
assert set(bond.member_types) == set(["t1", "t2"])
122+
123+
def test_bond_member_types_classes_from_bond_type(self):
124+
atom_type = AtomType()
125+
atom1 = Atom(atom_type=atom_type)
126+
atom2 = Atom(atom_type=atom_type)
127+
128+
btype = BondType(
129+
name="atom1-atom2-bond",
130+
member_types=["at1", "at2"],
131+
member_classes=["XE", "XE"],
132+
)
133+
bond = Bond(connection_members=[atom1, atom2], bond_type=btype)
134+
assert set(bond.member_classes) == set(["XE", "XE"])
135+
assert set(bond.member_types) == set(["at1", "at2"])

gmso/tests/test_forcefield.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ def test_ff_angletypes_from_xml(self, ff):
137137
assert ff.angle_types["Xe~Xe~Xe"].parameters["z"] == u.unyt_quantity(
138138
20, u.kJ / u.mol
139139
)
140-
assert ff.angle_types["Xe~Xe~Xe"].member_types == ("Xe", "Xe", "Xe")
140+
assert ff.angle_types["Xe~Xe~Xe"].member_classes == ("Xe", "Xe", "Xe")
141141

142142
def test_ff_dihedraltypes_from_xml(self, ff):
143143
assert len(ff.dihedral_types) == 2
@@ -154,7 +154,7 @@ def test_ff_dihedraltypes_from_xml(self, ff):
154154
assert ff.dihedral_types["Ar~Ar~Ar~Ar"].parameters[
155155
"z"
156156
] == u.unyt_quantity(100, u.kJ / u.mol)
157-
assert ff.dihedral_types["Ar~Ar~Ar~Ar"].member_types == (
157+
assert ff.dihedral_types["Ar~Ar~Ar~Ar"].member_classes == (
158158
"Ar",
159159
"Ar",
160160
"Ar",
@@ -171,7 +171,7 @@ def test_ff_dihedraltypes_from_xml(self, ff):
171171
assert ff.dihedral_types["Xe~Xe~Xe~Xe"].parameters[
172172
"z"
173173
] == u.unyt_quantity(20, u.kJ / u.mol)
174-
assert ff.dihedral_types["Xe~Xe~Xe~Xe"].member_types == (
174+
assert ff.dihedral_types["Xe~Xe~Xe~Xe"].member_classes == (
175175
"Xe",
176176
"Xe",
177177
"Xe",

0 commit comments

Comments
 (0)