Skip to content

Commit

Permalink
Merge pull request #39 from BSC-CNS-EAPM/multiple_control_files
Browse files Browse the repository at this point in the history
Multiple control files
  • Loading branch information
AlbertCS authored Nov 28, 2022
2 parents ab18eb2 + 9c02a18 commit 1b8980e
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 18 deletions.
6 changes: 5 additions & 1 deletion AdaptivePELE/runAllTests.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from AdaptivePELE.tests import testSpawning as tSpawning
from AdaptivePELE.tests import testAtomset as tAtomset
from AdaptivePELE.tests import testClustering as tClustering
from AdaptivePELE.tests import testSimulationRunner as tSimulation
from AdaptivePELE.tests import testAdaptiveSampling as tAdaptive
from AdaptivePELE.tests import testThresholdcalculator as tThreshold
from AdaptivePELE.tests import testDensityCalculator as tDensity
Expand All @@ -19,6 +20,7 @@ def parse_args():
desc = ("Run testing suite. Possible options are:\na -- Run all tests\n"
"at -- Run atomset tests\ns -- Run spawning tests\nth -- Run threshold "
"calculator tests\nd -- Run density tests\nc -- Run clustering tests\n"
"sr -- Run simulation runner tests \n"
"Ad -- Run adaptive integration tests\nMD -- Run adaptive MD tests\nMD_CUDA"
" -- Run adaptive MD tests with CUDA\nR -- Run reporter tests\n")
parser = argparse.ArgumentParser(description=desc, formatter_class=argparse.RawTextHelpFormatter)
Expand All @@ -32,7 +34,7 @@ def parse_args():
def main(run, exclude):
testSuite = unittest.TestSuite()
if run is None:
run = ["at", "s", "th", "d", "c", "Ad", "MD", "MD_CUDA", "R"]
run = ["at", "s", "th", "d", "c", "Ad", "MD", "MD_CUDA", "R", "sr"]
to_run = set(run)-set(exclude)

if "at" in to_run or "a" in to_run:
Expand All @@ -50,6 +52,8 @@ def main(run, exclude):
if "c" in to_run or "a" in to_run:
print("Will run clustering tests")
testSuite.addTest(unittest.makeSuite(tClustering.clusteringTest))
if "sr" in to_run or "a" in to_run:
testSuite.addTest(unittest.makeSuite(tSimulation.TestSimulationRunner))
if "Ad" in to_run or "a" in to_run:
print("Will run integration tests")
testSuite.addTest(unittest.makeSuite(tAdaptive.TestadaptiveSampling))
Expand Down
50 changes: 35 additions & 15 deletions AdaptivePELE/simulation/simulationrunner.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ class SimulationParameters:
def __init__(self):
self.processors = 0
self.executable = ""
self.templetizedControlFile = ""
self.templetizedControlFile = []
self.dataFolder = ""
self.documentsFolder = ""
self.iterations = 0
Expand Down Expand Up @@ -198,25 +198,33 @@ def checkExitCondition(self, clustering, outputFolder):
else:
return self.parameters.exitCondition.checkExitCondition(clustering)

def makeWorkingControlFile(self, workingControlFilename, dictionary, inputTemplate=None):
def getControlFileForEpoch(self, epoch):
"""
Get the control file for the epoch specified corresponding. For
most cases this will return the ony control file available, but in
some use-cases this will be used to select between the different
control files provided
:param epoch: Number of the epoch for which to provide the control
file
:type epoch: int
"""
numberControlFiles = len(self.parameters.templetizedControlFile)
return self.parameters.templetizedControlFile[epoch % numberControlFiles]

def makeWorkingControlFile(self, workingControlFilename, dictionary, inputTemplate):
"""
Substitute the values in the templetized control file
:param workingControlFilename: Name of the template control file
:type workingControlFilename: str
:param dictionary: Dictonary containing the parameters to substitute
in the control file
:type dictionary: dict
:param inputFileTemplate: Template control file
:type inputFileTemplate: str
:type dictionary: dict
"""
if inputTemplate is None:
with open(self.parameters.templetizedControlFile, "r") as inputFile:
inputFileContent = inputFile.read()
else:
inputFileContent = inputTemplate

inputFileTemplate = string.Template(inputFileContent)
inputFileTemplate = string.Template(inputTemplate)
outputFileContent = inputFileTemplate.substitute(dictionary)
with open(workingControlFilename, "w") as outputFile:
outputFileContent = outputFileContent.replace("'", '"')
Expand Down Expand Up @@ -297,7 +305,10 @@ def prepareControlFile(self, epoch, outputPathConstants, peleControlFileDictiona
if self.parameters.boxCenter is not None:
peleControlFileDictionary["BOX_RADIUS"] = self.parameters.boxRadius
peleControlFileDictionary["BOX_CENTER"] = self.parameters.boxCenter
self.makeWorkingControlFile(outputPathConstants.tmpControlFilename % epoch, peleControlFileDictionary)
with open(self.getControlFileForEpoch(epoch), "r") as inputFile:
templateControlFileContent = inputFile.read()
self.makeWorkingControlFile(outputPathConstants.tmpControlFilename % epoch, peleControlFileDictionary, templateControlFileContent)


def unifyReportNames(self, spawningReportName):
"""
Expand Down Expand Up @@ -639,7 +650,10 @@ def equilibrate(self, initialStructures, outputPathConstants, reportFilename, ou
self.parameters.equilibrationLength = self.calculateEquilibrationLength()
trajName = "".join(self.parameters.trajectoryName.split("_%d"))
equilibrationPeleDict = {"PELE_STEPS": self.parameters.equilibrationLength, "SEED": self.parameters.seed}
peleControlFileDict, templateNames = utilities.getPELEControlFileDict(self.parameters.templetizedControlFile)
# in cases with more than one control file, we arbitrarely use the
# first one for the equilibration, this might be revisited in the
# future depending on the use case
peleControlFileDict, templateNames = utilities.getPELEControlFileDict(self.parameters.templetizedControlFile[0])
peleControlFileDict = self.getEquilibrationControlFile(peleControlFileDict)
similarityColumn = self.getMetricColumns(peleControlFileDict)

Expand Down Expand Up @@ -1227,7 +1241,7 @@ def runSimulation(self, epoch, outputPathConstants, initialStructuresAsString, t
checkpoints = glob.glob(os.path.join(outputDir, "checkpoint*.chk"))
checkpoints = sorted(checkpoints, key=utilities.getTrajNum)
# always read the prmtop files from disk to serve as communication
# between diffrent processses
# between different processses
prmtops = glob.glob(os.path.join(outputPathConstants.topologies, "*prmtop"))
# sort the prmtops according to the original topology order
self.prmtopFiles = sorted(prmtops, key=utilities.getPrmtopNum)
Expand Down Expand Up @@ -1481,11 +1495,17 @@ def build(self, simulationRunnerBlock):
if params.dataFolder is None or params.documentsFolder is None or params.executable is None:
raise utilities.ImproperParameterValueException("PELE parameters not defined! Please ensure that you have defined the path to the PELE executable, the Data and Documents paths")
params.templetizedControlFile = paramsBlock[blockNames.SimulationParams.templetizedControlFile]
if isinstance(params.templetizedControlFile, basestring):
params.templetizedControlFile = [params.templetizedControlFile]
params.iterations = paramsBlock[blockNames.SimulationParams.iterations]
params.peleSteps = paramsBlock[blockNames.SimulationParams.peleSteps]
params.seed = paramsBlock[blockNames.SimulationParams.seed]
params.trajectoryName = paramsBlock.get(blockNames.SimulationParams.trajectoryName)
peleDict, _ = utilities.getPELEControlFileDict(params.templetizedControlFile)
# in cases with more than one control file, we arbitrarely use the
# first one for the equilibration, this might be revisited in the
# future depending on the use case
templetizedControlFileExmaple = params.templetizedControlFile[0]
peleDict, _ = utilities.getPELEControlFileDict(templetizedControlFileExmaple)
params.reportName, trajectoryName = utilities.getReportAndTrajectoryWildcard(peleDict)
if params.trajectoryName is None:
params.trajectoryName = trajectoryName
Expand Down Expand Up @@ -1523,7 +1543,7 @@ def build(self, simulationRunnerBlock):
exitConditionBlock = paramsBlock.get(blockNames.SimulationParams.exitCondition, None)
if exitConditionBlock:
exitConditionBuilder = ExitConditionBuilder()
params.exitCondition = exitConditionBuilder.build(exitConditionBlock, params.templetizedControlFile, params.processors)
params.exitCondition = exitConditionBuilder.build(exitConditionBlock, templetizedControlFileExmaple, params.processors)

return PeleSimulation(params)
elif simulationType == blockNames.SimulationType.md:
Expand Down
37 changes: 37 additions & 0 deletions AdaptivePELE/tests/testSimulationRunner.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
from __future__ import absolute_import, division, print_function, unicode_literals
import unittest

from AdaptivePELE.simulation import simulationrunner

class TestSimulationRunner(unittest.TestCase):
def testMultipleControlFileSelection(self):
params = simulationrunner.SimulationParameters()
params.templetizedControlFile = ["file1.txt", "file2.txt", "file3.txt"]
runner = simulationrunner.PeleSimulation(params)
files_out = [runner.getControlFileForEpoch(i) for i in range(10)]
golden = ["file1.txt", "file2.txt", "file3.txt"]*3+["file1.txt"]
self.assertEqual(files_out, golden)

def testOneControlFileSelection(self):
params = simulationrunner.SimulationParameters()
params.templetizedControlFile = ["file1.txt"]
runner = simulationrunner.PeleSimulation(params)
files_out = [runner.getControlFileForEpoch(i) for i in range(10)]
golden = ["file1.txt"]*10
self.assertEqual(files_out, golden)

def testMultipleControlFileSelectionEven(self):
params = simulationrunner.SimulationParameters()
params.templetizedControlFile = ["file1.txt", "file2.txt"]
runner = simulationrunner.PeleSimulation(params)
files_out = [runner.getControlFileForEpoch(i) for i in range(10)]
golden = ["file1.txt", "file2.txt"]*5
self.assertEqual(files_out, golden)

def testMultipleControlFileSelectionLessThan(self):
params = simulationrunner.SimulationParameters()
params.templetizedControlFile = [f"file{i}.txt" for i in range(10)]
runner = simulationrunner.PeleSimulation(params)
files_out = [runner.getControlFileForEpoch(i) for i in range(5)]
golden = [f"file{i}.txt" for i in range(5)]
self.assertEqual(files_out, golden)
4 changes: 2 additions & 2 deletions AdaptivePELE/validator/validatorBlockNames.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ class SimulationParams:
types = {
"pele": {
"processors": "numbers.Real",
"controlFile": "basestring",
"controlFile": "basestring|list",
"seed": "numbers.Real",
"peleSteps": "numbers.Real",
"iterations": "numbers.Real"
Expand Down Expand Up @@ -159,7 +159,7 @@ class SimulationParams:
"origin": "basestring",
"time": "numbers.Real",
"processors": "numbers.Real",
"controlFile": "basestring",
"controlFile": "basestring|list",
"seed": "numbers.Real",
"peleSteps": "numbers.Real",
"iterations": "numbers.Real",
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)

- Add script to run RMSD clustering from scratch
- Add filters for plotAdaptive script
- Add support for multiple control files

## Bug fixes:

Expand Down

0 comments on commit 1b8980e

Please sign in to comment.