Skip to content

Commit de6629c

Browse files
authored
Merge pull request #390 from fjclark/devel
Update Exscientia Sandpit SOMD config settings
2 parents b12baa4 + 8a323fc commit de6629c

File tree

2 files changed

+36
-28
lines changed

2 files changed

+36
-28
lines changed

python/BioSimSpace/Sandpit/Exscientia/Protocol/_config.py

+28-27
Original file line numberDiff line numberDiff line change
@@ -743,51 +743,52 @@ def generateSomdConfig(
743743
# Get the report and restart intervals.
744744
report_interval = self._report_interval
745745
restart_interval = self._restart_interval
746-
runtime = self.protocol.getRunTime()
747746

748-
# Get the timestep.
749-
timestep = self.protocol._timestep
750-
751-
# Work out the number of cycles.
752-
ncycles = (runtime / timestep) / report_interval
753-
754-
# If the number of cycles isn't integer valued, adjust the report
755-
# interval so that we match specified the run time.
756-
if ncycles - _math.floor(ncycles) != 0:
757-
ncycles = _math.floor(ncycles)
758-
if ncycles == 0:
759-
ncycles = 1
760-
report_interval = _math.ceil((runtime / timestep) / ncycles)
747+
# Work out the number of cycles. We want one per nanosecond of simulation.
748+
if self.protocol.getRunTime().nanoseconds().value() < 2:
749+
ncycles = 1
750+
moves_per_cycle = self._steps
751+
else:
752+
ncycles = _math.ceil(self.protocol.getRunTime().nanoseconds().value())
753+
moves_per_cycle = _math.ceil(self._steps / ncycles)
761754

762-
# For free energy simulations, the report interval must be a multiple
763-
# of the energy frequency which is 250 steps.
764-
if isinstance(self.protocol, _Protocol._FreeEnergyMixin):
765-
if report_interval % 250 != 0:
766-
report_interval = 250 * _math.ceil(report_interval / 250)
755+
# The number of moves needs to be multiple of the report interval.
756+
if moves_per_cycle % report_interval != 0:
757+
moves_per_cycle = (
758+
_math.ceil(moves_per_cycle / report_interval) * report_interval
759+
)
767760

768761
# Work out the number of cycles per frame.
769-
cycles_per_frame = restart_interval / report_interval
762+
cycles_per_frame = restart_interval / moves_per_cycle
770763

771764
# Work out whether we need to adjust the buffer frequency.
772765
buffer_freq = 0
773766
if cycles_per_frame < 1:
774-
buffer_freq = cycles_per_frame * restart_interval
767+
buffer_freq = restart_interval
775768
cycles_per_frame = 1
776-
self._buffer_freq = buffer_freq
777769
else:
778770
cycles_per_frame = _math.floor(cycles_per_frame)
779771

772+
# Make sure that we aren't buffering more than 1000 frames per cycle.
773+
if buffer_freq > 0 and moves_per_cycle / buffer_freq > 1000:
774+
_warnings.warn(
775+
"Trajectory buffering will exceed limit. Reducing buffer frequency."
776+
)
777+
buffer_freq = moves_per_cycle / 1000
778+
780779
# For free energy simulations, the buffer frequency must be an integer
781780
# multiple of the frequency at which free energies are written, which
782-
# is 250 steps. Round down to the closest multiple.
781+
# is report interval. Round down to the closest multiple.
783782
if isinstance(self.protocol, _Protocol._FreeEnergyMixin):
784783
if buffer_freq > 0:
785-
buffer_freq = 250 * _math.floor(buffer_freq / 250)
784+
buffer_freq = report_interval * _math.floor(
785+
buffer_freq / report_interval
786+
)
786787

787788
# The number of SOMD cycles.
788-
protocol_dict["ncycles"] = int(ncycles)
789+
protocol_dict["ncycles"] = ncycles
789790
# The number of moves per cycle.
790-
protocol_dict["nmoves"] = report_interval
791+
protocol_dict["nmoves"] = moves_per_cycle
791792
# Cycles per trajectory write.
792793
protocol_dict["ncycles_per_snap"] = cycles_per_frame
793794
# Buffering frequency.
@@ -862,7 +863,7 @@ def generateSomdConfig(
862863
"hbonds-notperturbed" # Handle hydrogen perturbations.
863864
)
864865
protocol_dict["energy frequency"] = (
865-
250 # Write gradients every 250 steps.
866+
report_interval # Write gradients at report interval.
866867
)
867868

868869
protocol = [str(x) for x in self.protocol.getLambdaValues()]

tests/Sandpit/Exscientia/Protocol/test_config.py

+8-1
Original file line numberDiff line numberDiff line change
@@ -480,14 +480,21 @@ def system_and_boresch_restraint():
480480
def test_turn_on_restraint_boresch(self, system_and_boresch_restraint):
481481
"""Test for turning on multiple distance restraints"""
482482
system, restraint = system_and_boresch_restraint
483-
protocol = FreeEnergy(perturbation_type="restraint")
483+
protocol = FreeEnergy(perturbation_type="restraint",
484+
runtime=1*BSS.Units.Time.nanosecond,
485+
timestep=2*BSS.Units.Time.femtosecond)
484486
freenrg = BSS.FreeEnergy.AlchemicalFreeEnergy(
485487
system, protocol, engine="SOMD", restraint=restraint
486488
)
487489

488490
# Test .cfg file
489491
with open(f"{freenrg._work_dir}/lambda_0.0000/somd.cfg", "r") as f:
490492
cfg_text = f.read()
493+
assert "nmoves = 500000" in cfg_text
494+
assert "ncycles_per_snap = 1" in cfg_text
495+
assert "buffered coordinates frequency = 1000" in cfg_text
496+
assert "timestep = 2.00 femtosecond" in cfg_text
497+
assert "energy frequency = 200" in cfg_text
491498
assert "use boresch restraints = True" in cfg_text
492499
assert 'boresch restraints dictionary = {"anchor_points":{"r1":1,'
493500
' "r2":2, "r3":3, "l1":4, "l2":5, "l3":6}, "equilibrium_values"'

0 commit comments

Comments
 (0)