Skip to content

Commit d3a0437

Browse files
authored
Merge pull request #50 from OpenBioSim/fix_45-48_main
Backport fixes from PR #49
2 parents 0f591c2 + 323efa7 commit d3a0437

5 files changed

Lines changed: 54 additions & 11 deletions

File tree

doc/source/tutorials/hydration_freenrg.rst

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,12 +99,25 @@ dynamics engine called SOMD. (This is a wrapper around the excellent
9999
`OpenMM <https://openmm.org>`__ package and is the default engine if no other
100100
packages are present.)
101101

102+
>>> protocol = BSS.Protocol.FreeEnergyProduction()
103+
>>> free_somd = BSS.FreeEnergy.Relative(solvated, protocol, engine="somd", work_dir="freenrg_somd/free")
104+
>>> vac_somd = BSS.FreeEnergy.Relative(merged.toSystem(), protocol, engine="somd", work_dir="freenrg_somd/vacuum")
105+
102106
.. note ::
103107
104-
It's possible to use a different protocol or molecular dynamics engine for each leg.
108+
For GROMACS, you can use :data:`BioSimSpace.Protocol.FreeEnergyMinimisation` and
109+
:data:`BioSimSpace.Protocol.FreeEnergyEquilibration` to minimise and equilibrate at each
110+
:math:`{\lambda}` value prior to setting up to the production run above. For SOMD this
111+
isn't possible, so you can either use GROMACS to prepare production input for each window,
112+
or use the regular :data:`BioSimSpace.Protocol.Minimisation` and
113+
:data:`BioSimSpace.Protocol.Equilibration` protocols to minimise and equilibrate
114+
the :math:`{\lambda=0}` and :math:`{\lambda=1}` states only using any supported
115+
engine from :data:`BioSimSpace.Process`.
105116
106-
>>> free_somd = BSS.FreeEnergy.Relative(solvated, protocol, engine="somd", work_dir="freenrg_somd/free")
107-
>>> vac_somd = BSS.FreeEnergy.Relative(merged.toSystem(), protocol, engine="somd", work_dir="freenrg_somd/vacuum")
117+
.. note ::
118+
119+
It's possible to use a different protocol or molecular dynamics engine for each leg,
120+
e.g. if you want to use a different :math:`{\lambda}` schedule.
108121
109122
When complete, BioSimSpace will have set up a folder hierarchy containing
110123
everything that is needed to run the hydration free energy calculation

python/BioSimSpace/FreeEnergy/_relative.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ def __init__(
9595
setup_only=False,
9696
ignore_warnings=False,
9797
show_errors=True,
98+
extra_options={},
99+
extra_lines=[],
98100
property_map={},
99101
):
100102
"""
@@ -139,6 +141,13 @@ def __init__(
139141
run file. This option is specific to GROMACS and will be ignored
140142
when a different molecular dynamics engine is chosen.
141143
144+
extra_options : dict
145+
A dictionary containing extra options. Overrides the defaults generated
146+
by the protocol.
147+
148+
extra_lines : [str]
149+
A list of extra lines to put at the end of the configuration file.
150+
142151
property_map : dict
143152
A dictionary that maps system "properties" to their user defined
144153
values. This allows the user to refer to properties with their
@@ -249,6 +258,23 @@ def __init__(
249258
raise ValueError("'show_errors' must be of type 'bool.")
250259
self._show_errors = show_errors
251260

261+
# Check the extra options.
262+
if not isinstance(extra_options, dict):
263+
raise TypeError("'extra_options' must be of type 'dict'.")
264+
else:
265+
keys = extra_options.keys()
266+
if not all(isinstance(k, str) for k in keys):
267+
raise TypeError("Keys of 'extra_options' must be of type 'str'.")
268+
self._extra_options = extra_options
269+
270+
# Check the extra lines.
271+
if not isinstance(extra_lines, list):
272+
raise TypeError("'extra_lines' must be of type 'list'.")
273+
else:
274+
if not all(isinstance(line, str) for line in extra_lines):
275+
raise TypeError("Lines in 'extra_lines' must be of type 'str'.")
276+
self._extra_lines = extra_lines
277+
252278
# Check that the map is valid.
253279
if not isinstance(property_map, dict):
254280
raise TypeError("'property_map' must be of type 'dict'")
@@ -856,6 +882,8 @@ def _initialise_runner(self, system):
856882
self._protocol,
857883
platform=platform,
858884
work_dir=first_dir,
885+
extra_options=self._extra_options,
886+
extra_lines=self._extra_lines,
859887
property_map=self._property_map,
860888
)
861889
if self._setup_only:
@@ -871,6 +899,9 @@ def _initialise_runner(self, system):
871899
work_dir=first_dir,
872900
ignore_warnings=self._ignore_warnings,
873901
show_errors=self._show_errors,
902+
extra_options=self._extra_options,
903+
extra_lines=self._extra_lines,
904+
property_map=self._property_map,
874905
)
875906
if self._setup_only:
876907
del first_process

python/BioSimSpace/_Config/_somd.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -232,8 +232,11 @@ def createConfig(self, extra_options={}, extra_lines=[]):
232232
% self._protocol.getStartTemperature().kelvin().value()
233233
)
234234

235-
# Friction coefficient (1 / ps).
236-
protocol_dict["inverse friction"] = "{:.5f}".format(
235+
# Friction coefficient (1 / ps). Note that the unit is written
236+
# to the configuration file as "picosecond". This is because SOMD
237+
# applies the value to OpenMM without inverting it, so has things the
238+
# wrong way round, i.e. it uses the inverse friction as the friction.
239+
protocol_dict["inverse friction"] = "{:.5f} picosecond".format(
237240
1 / self._protocol.getThermostatTimeConstant().picoseconds().value()
238241
)
239242

test/Process/test_somd.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -172,10 +172,8 @@ def run_process(system, protocol):
172172
)
173173
res = False
174174

175-
return not res
176-
177175
# Make sure the process didn't error.
178-
assert not process.isError()
176+
assert not res
179177

180178
# Make sure that we get a molecular system back.
181179
assert process.getSystem() is not None

test/Sandpit/Exscientia/Process/test_somd.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -155,10 +155,8 @@ def run_process(system, protocol):
155155
)
156156
res = False
157157

158-
return not res
159-
160158
# Make sure the process didn't error.
161-
assert not process.isError()
159+
assert not res
162160

163161
# Make sure that we get a molecular system back.
164162
assert process.getSystem() is not None

0 commit comments

Comments
 (0)