Skip to content

Commit ede6ec5

Browse files
committed
Use GROMACS potential type ids in itp file output
1 parent c638290 commit ede6ec5

File tree

5 files changed

+68
-35
lines changed

5 files changed

+68
-35
lines changed

pycgtool/bondset.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ class Bond:
3131
3232
Bond lengths, angles and dihedrals are all equivalent, distinguished by the number of atoms present.
3333
"""
34-
__slots__ = ["atoms", "atom_numbers", "values", "eqm", "fconst", "_func_form"]
34+
__slots__ = ["atoms", "atom_numbers", "values", "eqm", "fconst", "gromacs_type_id", "_func_form"]
3535

3636
def __init__(self, atoms, atom_numbers=None, func_form=None):
3737
"""
@@ -48,6 +48,7 @@ def __init__(self, atoms, atom_numbers=None, func_form=None):
4848
self.fconst = None
4949

5050
self._func_form = func_form
51+
self.gromacs_type_id = func_form.gromacs_type_id_by_natoms(len(atoms))
5152

5253
def __len__(self):
5354
return len(self.atoms)
@@ -273,10 +274,9 @@ def write_bond_angle_dih(bonds, section_header, itp, print_fconst=True, multipli
273274
if bonds:
274275
print("\n[ {0:s} ]".format(section_header), file=itp)
275276
for bond in bonds:
276-
# Factor is usually 1, unless doing correction
277277
line = " ".join(["{0:4d}".format(atnum + 1) for atnum in bond.atom_numbers])
278278
eqm = math.degrees(bond.eqm) if rad2deg else bond.eqm
279-
line += " {0:4d} {1:12.5f}".format(1, eqm)
279+
line += " {0:4d} {1:12.5f}".format(bond.gromacs_type_id, eqm)
280280
if print_fconst:
281281
line += " {0:12.5f}".format(bond.fconst)
282282
if multiplicity is not None:

pycgtool/functionalforms.py

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,6 @@ def eqm(values, temp):
6767
"""
6868
return np.nanmean(values)
6969

70-
@staticmethod
7170
@abc.abstractstaticmethod
7271
def fconst(values, temp):
7372
"""
@@ -78,10 +77,34 @@ def fconst(values, temp):
7877
:param temp: Temperature of simulation
7978
:return: Calculated force constant
8079
"""
81-
pass
80+
raise NotImplementedError
81+
82+
@abc.abstractproperty
83+
def gromacs_type_ids(self):
84+
"""
85+
Return tuple of GROMACS potential type ids when used as length, angle, dihedral.
86+
87+
:return tuple[int]: Tuple of GROMACS potential type ids
88+
"""
89+
raise NotImplementedError
90+
91+
@classmethod
92+
def gromacs_type_id_by_natoms(cls, natoms):
93+
"""
94+
Return the GROMACS potential type id for this functional form when used with natoms.
95+
96+
:param int natoms:
97+
:return int: GROMACS potential type id
98+
"""
99+
tipe = cls.gromacs_type_ids[natoms - 2]
100+
if tipe is None:
101+
raise TypeError("The functional form {0} does not have a defined GROMACS potential type when used with {1} atoms.".format(cls.__name__, natoms))
102+
return tipe
82103

83104

84105
class Harmonic(FunctionalForm):
106+
gromacs_type_ids = (1, 1, 1) # Consider whether to use improper (type 2) instead, it is actually harmonic
107+
85108
@staticmethod
86109
def fconst(values, temp):
87110
rt = 8.314 * temp / 1000.
@@ -90,6 +113,8 @@ def fconst(values, temp):
90113

91114

92115
class CosHarmonic(FunctionalForm):
116+
gromacs_type_ids = (None, 2, None)
117+
93118
@staticmethod
94119
def fconst(values, temp):
95120
rt = 8.314 * temp / 1000.
@@ -99,18 +124,24 @@ def fconst(values, temp):
99124

100125

101126
class MartiniDefaultLength(FunctionalForm):
127+
gromacs_type_ids = (1, None, None)
128+
102129
@staticmethod
103130
def fconst(values, temp):
104131
return 1250.
105132

106133

107134
class MartiniDefaultAngle(FunctionalForm):
135+
gromacs_type_ids = (None, 2, None)
136+
108137
@staticmethod
109138
def fconst(values, temp):
110139
return 25.
111140

112141

113142
class MartiniDefaultDihedral(FunctionalForm):
143+
gromacs_type_ids = (None, None, 1)
144+
114145
@staticmethod
115146
def fconst(values, temp):
116147
return 50.

test/data/sugar_out.itp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,12 @@ ALLA 1
2424
5 6 1 0.20597 55319.39933
2525

2626
[ angles ]
27-
1 2 3 1 77.88207 503.72544
28-
2 3 4 1 116.08126 838.60326
29-
3 4 5 1 111.02889 733.45020
30-
4 5 6 1 83.28583 946.13165
31-
5 6 1 1 143.48577 771.65933
32-
6 1 2 1 99.29372 800.62783
27+
1 2 3 2 77.88207 503.72544
28+
2 3 4 2 116.08126 838.60326
29+
3 4 5 2 111.02889 733.45020
30+
4 5 6 2 83.28583 946.13165
31+
5 6 1 2 143.48577 771.65933
32+
6 1 2 2 99.29372 800.62783
3333

3434
[ dihedrals ]
3535
1 2 3 4 1 -82.85912 253.69305 1

test/test_bondset.py

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -24,26 +24,26 @@ class DummyOptions:
2424

2525

2626
class BondSetTest(unittest.TestCase):
27-
# Columns are: eqm value, standard fc, defaults fc, mixed fc
27+
# Columns are: eqm value, standard fc, MARTINI defaults fc
2828
invert_test_ref_data = [
29-
( 0.220474419132, 72658.18163, 1250, 1520530.416),
30-
( 0.221844516963, 64300.01188, 1250, 1328761.015),
31-
( 0.216313356504, 67934.93368, 1250, 1474281.672),
32-
( 0.253166204438, 19545.27388, 1250, 311446.690),
33-
( 0.205958461836, 55359.06367, 1250, 1322605.992),
34-
( 0.180550961226, 139643.66601, 1250, 4334538.941),
35-
( 1.359314249473, 503.24211, 25, 481.527),
36-
( 2.026002746003, 837.76904, 25, 676.511),
37-
( 1.937848056214, 732.87969, 25, 639.007),
38-
( 1.453592079716, 945.32633, 25, 933.199),
39-
( 2.504189933347, 771.63691, 25, 273.207),
40-
( 1.733002945619, 799.82825, 25, 779.747),
41-
(-1.446051810383, 253.75691, 50, 1250),
42-
( 1.067436470329, 125.04591, 50, 1250),
43-
(-0.373528903861, 135.50927, 50, 1250),
44-
( 0.927837103158, 51.13975, 50, 1250),
45-
(-1.685096988856, 59.38162, 50, 1250),
46-
( 1.315458354592, 279.80889, 50, 1250)
29+
( 0.220474419132, 72658.18163, 1250),
30+
( 0.221844516963, 64300.01188, 1250),
31+
( 0.216313356504, 67934.93368, 1250),
32+
( 0.253166204438, 19545.27388, 1250),
33+
( 0.205958461836, 55359.06367, 1250),
34+
( 0.180550961226, 139643.66601, 1250),
35+
( 1.359314249473, 503.24211, 25),
36+
( 2.026002746003, 837.76904, 25),
37+
( 1.937848056214, 732.87969, 25),
38+
( 1.453592079716, 945.32633, 25),
39+
( 2.504189933347, 771.63691, 25),
40+
( 1.733002945619, 799.82825, 25),
41+
(-1.446051810383, 253.75691, 50),
42+
( 1.067436470329, 125.04591, 50),
43+
(-0.373528903861, 135.50927, 50),
44+
( 0.927837103158, 51.13975, 50),
45+
(-1.685096988856, 59.38162, 50),
46+
( 1.315458354592, 279.80889, 50)
4747
]
4848

4949
def test_bondset_create(self):
@@ -119,11 +119,11 @@ class DefaultOptions(DummyOptions):
119119
measure.boltzmann_invert()
120120
self.support_check_mean_fc(measure["ALLA"], 2)
121121

122-
def test_bondset_boltzmann_invert_func_forms(self):
122+
def test_bondset_boltzmann_invert_manual_default_fc(self):
123123
class FuncFormOptions(DummyOptions):
124-
length_form = "CosHarmonic"
125-
angle_form = "Harmonic"
126-
dihedral_form = "MartiniDefaultLength"
124+
length_form = "MartiniDefaultLength"
125+
angle_form = "MartiniDefaultAngle"
126+
dihedral_form = "MartiniDefaultDihedral"
127127

128128
measure = BondSet("test/data/sugar.bnd", FuncFormOptions)
129129
frame = Frame("test/data/sugar.gro", xtc="test/data/sugar.xtc")
@@ -135,7 +135,7 @@ class FuncFormOptions(DummyOptions):
135135
measure.apply(cgframe)
136136

137137
measure.boltzmann_invert()
138-
self.support_check_mean_fc(measure["ALLA"], 3)
138+
self.support_check_mean_fc(measure["ALLA"], 2)
139139

140140
@unittest.skipIf(not mdtraj_present, "MDTRAJ or Scipy not present")
141141
def test_bondset_boltzmann_invert_mdtraj(self):

test/test_functionalforms.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ def test_functional_form(self):
1313

1414
def test_functional_form_new(self):
1515
class TestFunc(FunctionalForm):
16+
gromacs_type_ids = (None, None, None)
17+
1618
@staticmethod
1719
def eqm(values, temp):
1820
return "TestResultEqm"

0 commit comments

Comments
 (0)