diff --git a/devtools/conda-envs/test_env.yaml b/devtools/conda-envs/test_env.yaml index aedfa14d0..cae68ca38 100644 --- a/devtools/conda-envs/test_env.yaml +++ b/devtools/conda-envs/test_env.yaml @@ -21,6 +21,7 @@ dependencies: - swig - future - pymbar=3.0.3 + - mdtraj=1.9.1 - openmm - ambertools # The following two are not compatible with python 2.7 and 3.5, so they are conditionally installed in .travis.yml diff --git a/src/optimizer.py b/src/optimizer.py index 5321a48e6..43ef2e195 100644 --- a/src/optimizer.py +++ b/src/optimizer.py @@ -640,7 +640,7 @@ def print_progress(itn, nx, nd, ng, clr, x, std, qual): if ngd < self.convergence_gradient: logger.info("Convergence criterion reached for gradient norm (%.2e)\n" % self.convergence_gradient) ncrit += 1 - if ndx < self.convergence_step and ITERATION > self.iterinit: + if ndx < self.convergence_step and ndx >= 0.0 and ITERATION > self.iterinit: logger.info("Convergence criterion reached in step size (%.2e)\n" % self.convergence_step) ncrit += 1 if stdfront < self.convergence_objective and len(X_hist) >= self.hist: diff --git a/src/tests/test_system.py b/src/tests/test_system.py index 25b9e96f8..48c000c70 100644 --- a/src/tests/test_system.py +++ b/src/tests/test_system.py @@ -19,6 +19,12 @@ # expected results (mvals) taken from previous runs. Update this if it changes and seems reasonable (updated 01/24/14) EXPECTED_BROMINE_RESULTS = array([-0.305718, -0.12497]) +# expected objective function from 003d evaluator bromine study. (updated 11/23/19) +EXPECTED_EVALUATOR_BROMINE_OBJECTIVE = array([1000]) + +# expected gradient elements from 003d evaluator bromine study. Very large uncertainties of +/- 2500 (updated 11/23/19) +EXPECTED_EVALUATOR_BROMINE_GRADIENT = array([4000, 4000]) + # expected result (pvals) taken from ethanol GB parameter optimization. Update this if it changes and seems reasonable (updated 09/05/14) EXPECTED_ETHANOL_RESULTS = array([1.2286e-01, 8.3624e-01, 1.0014e-01, 8.4533e-01, 1.8740e-01, 6.8820e-01, 1.4606e-01, 8.3518e-01]) @@ -32,30 +38,18 @@ EXPECTED_OPENFF_TORSIONPROFILE_RESULTS = array([-9.4238e-02, 7.3350e-03, -7.9467e-05, 1.7172e-02, -1.3309e-01, 6.0076e-02, 1.7895e-02, 6.5866e-02, -1.4084e-01, -2.2906e-02]) - class ForceBalanceSystemTest(ForceBalanceTestCase): def teardown_method(self): - shutil.rmtree("result") - os.remove(self.input_file.replace('.in','.sav')) - if os.path.exists(self.input_file.replace('.in','.bak')): - shutil.rmtree(self.input_file.replace('.in','.bak')) - shutil.rmtree(self.input_file.replace('.in','.tmp')) + for fnm in [self.input_file.replace('.in','.sav')]: + if os.path.exists(fnm): + os.remove(fnm) + for dnm in [self.input_file.replace('.in','.bak'), self.input_file.replace('.in','.tmp'), "result"]: + if os.path.exists(dnm): + shutil.rmtree(dnm) super(ForceBalanceSystemTest, self).teardown_method() - -class TestWaterTutorial(ForceBalanceSystemTest): - def setup_method(self, method): - super(TestWaterTutorial, self).setup_method(method) - self.cwd = os.path.dirname(os.path.realpath(__file__)) - os.chdir(os.path.join(self.cwd, '..','..', 'studies','001_water_tutorial')) - targets = tarfile.open('targets.tar.bz2','r') - targets.extractall() - targets.close() - self.input_file='very_simple.in' - self.logger.debug("\nSetting input file to '%s'\n" % self.input_file) - - def test_water_tutorial(self): - """Check water tutorial study runs without errors""" - + + def get_objective(self): + """ Return the objective function object """ ## The general options and target options that come from parsing the input file self.logger.debug("Parsing inputs...\n") options, tgt_opts = parse_inputs(self.input_file) @@ -64,78 +58,87 @@ def test_water_tutorial(self): assert isinstance(tgt_opts, list), "Parser gave incorrect type for tgt_opts" for target in tgt_opts: assert isinstance(target, dict), "Parser gave incorrect type for target dict" - ## The force field component of the project forcefield = FF(options) assert isinstance(forcefield, FF), "Expected forcebalance forcefield object" - ## The objective function objective = Objective(options, tgt_opts, forcefield) assert isinstance(objective, Objective), "Expected forcebalance objective object" + return objective - ## The optimizer component of the project - self.logger.debug("Creating optimizer: ") - optimizer = Optimizer(options, objective, forcefield) - assert isinstance(optimizer, Optimizer), "Expected forcebalance optimizer object" - self.logger.debug(str(optimizer) + "\n") - - ## Actually run the optimizer. - self.logger.debug("Done setting up! Running optimizer...\n") - result = optimizer.Run() - self.logger.debug("\nOptimizer finished. Final results:\n") - self.logger.debug(str(result) + '\n') - msg = "\nCalculation results have changed from previously calculated values.\n If this seems reasonable, update EXPECTED_WATER_RESULTS in test_system.py with these values" - np.testing.assert_array_almost_equal(EXPECTED_WATER_RESULTS,result,decimal=0.001, err_msg=msg) - - # Fail if calculation takes longer than previously to converge - assert ITERATIONS_TO_CONVERGE >= Counter(), "Calculation took longer than expected to converge (%d iterations vs previous of %d)" %\ - (ITERATIONS_TO_CONVERGE, Counter()) - -class TestVoelzStudy(ForceBalanceSystemTest): - def setup_method(self, method): - super(TestVoelzStudy, self).setup_method(method) - cwd = os.path.dirname(os.path.realpath(__file__)) - os.chdir(os.path.join(cwd, '..', '..', 'studies', '009_voelz_nspe')) - self.input_file='options.in' - self.logger.debug("\nSetting input file to '%s'\n" % self.input_file) - - def test_voelz_study(self): - """Check voelz study runs without errors""" - + def get_optimizer(self): + """ Return the optimizer object """ ## The general options and target options that come from parsing the input file self.logger.debug("Parsing inputs...\n") options, tgt_opts = parse_inputs(self.input_file) self.logger.debug("options:\n%s\n\ntgt_opts:\n%s\n\n" % (str(options), str(tgt_opts))) - assert isinstance(options, dict), "Parser gave incorrect type for options" assert isinstance(tgt_opts, list), "Parser gave incorrect type for tgt_opts" for target in tgt_opts: assert isinstance(target, dict), "Parser gave incorrect type for target dict" - ## The force field component of the project - self.logger.debug("Creating forcefield using loaded options: ") forcefield = FF(options) - self.logger.debug(str(forcefield) + "\n") assert isinstance(forcefield, FF), "Expected forcebalance forcefield object" - ## The objective function - self.logger.debug("Creating object using loaded options and forcefield: ") objective = Objective(options, tgt_opts, forcefield) - self.logger.debug(str(objective) + "\n") assert isinstance(objective, Objective), "Expected forcebalance objective object" - ## The optimizer component of the project self.logger.debug("Creating optimizer: ") optimizer = Optimizer(options, objective, forcefield) - self.logger.debug(str(optimizer) + "\n") assert isinstance(optimizer, Optimizer), "Expected forcebalance optimizer object" + self.logger.debug(str(optimizer) + "\n") + return optimizer + def run_optimizer(self, check_result=True, check_iter=True, use_pvals=False): + optimizer = self.get_optimizer() ## Actually run the optimizer. self.logger.debug("Done setting up! Running optimizer...\n") result = optimizer.Run() - self.logger.debug("\nOptimizer finished. Final results:\n") self.logger.debug(str(result) + '\n') + ## Convert result to physical values if desired. + if use_pvals: + result = optimizer.FF.create_pvals(result) + if check_result: + msg = "\nCalculation results have changed from previously calculated values.\n " \ + "If this seems reasonable, update %s in test_system.py with these values" % self.expected_results_name + np.testing.assert_allclose(self.expected_results, result, atol=self.absolute_tolerance, err_msg=msg) + if check_iter: + # Fail if calculation takes longer than previously to converge + assert ITERATIONS_TO_CONVERGE >= Counter(), "Calculation took longer than expected to converge (%d iterations vs previous of %d)" %\ + (ITERATIONS_TO_CONVERGE, Counter()) + return result + +class TestWaterTutorial(ForceBalanceSystemTest): + def setup_method(self, method): + super(TestWaterTutorial, self).setup_method(method) + self.cwd = os.path.dirname(os.path.realpath(__file__)) + os.chdir(os.path.join(self.cwd, '..','..', 'studies','001_water_tutorial')) + targets = tarfile.open('targets.tar.bz2','r') + targets.extractall() + targets.close() + self.input_file='very_simple.in' + self.logger.debug("\nSetting input file to '%s'\n" % self.input_file) + self.expected_results_name = "EXPECTED_WATER_RESULTS" + self.expected_results = EXPECTED_WATER_RESULTS + self.absolute_tolerance = 0.005 + + def test_water_tutorial(self): + """Check water tutorial study runs without errors""" + self.run_optimizer() + + +class TestVoelzStudy(ForceBalanceSystemTest): + def setup_method(self, method): + super(TestVoelzStudy, self).setup_method(method) + cwd = os.path.dirname(os.path.realpath(__file__)) + os.chdir(os.path.join(cwd, '..', '..', 'studies', '009_voelz_nspe')) + self.input_file='options.in' + self.logger.debug("\nSetting input file to '%s'\n" % self.input_file) + + def test_voelz_study(self): + """Check voelz study runs without errors""" + self.run_optimizer(check_result=False, check_iter=False) class TestBromineStudy(ForceBalanceSystemTest): @@ -145,47 +148,13 @@ def setup_method(self, method): os.chdir(os.path.join(cwd, '..', '..', 'studies', '003_liquid_bromine')) self.input_file='optimize.in' self.logger.debug("\nSetting input file to '%s'\n" % self.input_file) + self.expected_results_name = "EXPECTED_BROMINE_RESULTS" + self.expected_results = EXPECTED_BROMINE_RESULTS + self.absolute_tolerance = 0.05 def test_bromine_study(self): """Check liquid bromine study converges to expected results""" - - ## The general options and target options that come from parsing the input file - self.logger.debug("Parsing inputs...\n") - options, tgt_opts = parse_inputs(self.input_file) - self.logger.debug("options:\n%s\n\ntgt_opts:\n%s\n\n" % (str(options), str(tgt_opts))) - - assert isinstance(options, dict), "Parser gave incorrect type for options" - assert isinstance(tgt_opts, list), "Parser gave incorrect type for tgt_opts" - for target in tgt_opts: - assert isinstance(target, dict), "Parser gave incorrect type for target dict" - - ## The force field component of the project - self.logger.debug("Creating forcefield using loaded options: ") - forcefield = FF(options) - self.logger.debug(str(forcefield) + "\n") - assert isinstance(forcefield, FF), "Expected forcebalance forcefield object" - - ## The objective function - self.logger.debug("Creating object using loaded options and forcefield: ") - objective = Objective(options, tgt_opts, forcefield) - self.logger.debug(str(objective) + "\n") - assert isinstance(objective, Objective), "Expected forcebalance objective object" - - ## The optimizer component of the project - self.logger.debug("Creating optimizer: ") - optimizer = Optimizer(options, objective, forcefield) - self.logger.debug(str(optimizer) + "\n") - assert isinstance(optimizer, Optimizer), "Expected forcebalance optimizer object" - - ## Actually run the optimizer. - self.logger.debug("Done setting up! Running optimizer...\n") - result = optimizer.Run() - - self.logger.debug("\nOptimizer finished. Final results:\n") - self.logger.debug(str(result) + '\n') - - msg="\nCalculation results have changed from previously calculated values.\n If this seems reasonable, update EXPECTED_BROMINE_RESULTS in test_system.py with these values" - np.testing.assert_allclose(EXPECTED_BROMINE_RESULTS, result, atol=0.05, err_msg=msg) + self.run_optimizer() class TestThermoBromineStudy(ForceBalanceSystemTest): def setup_method(self, method): @@ -194,46 +163,13 @@ def setup_method(self, method): os.chdir(os.path.join(cwd, '../../studies/004_thermo_liquid_bromine')) self.input_file='optimize.in' self.logger.debug("\nSetting input file to '%s'\n" % self.input_file) + self.expected_results_name = "EXPECTED_BROMINE_RESULTS" + self.expected_results = EXPECTED_BROMINE_RESULTS + self.absolute_tolerance = 0.05 def test_thermo_bromine_study(self): """Check liquid bromine study (Thermo target) converges to expected results""" - - ## The general options and target options that come from parsing the input file - self.logger.debug("Parsing inputs...\n") - options, tgt_opts = parse_inputs(self.input_file) - self.logger.debug("options:\n%s\n\ntgt_opts:\n%s\n\n" % (str(options), str(tgt_opts))) - - assert isinstance(options, dict), "Parser gave incorrect type for options" - assert isinstance(tgt_opts, list), "Parser gave incorrect type for tgt_opts" - for target in tgt_opts: - assert isinstance(target, dict), "Parser gave incorrect type for target dict" - - ## The force field component of the project - self.logger.debug("Creating forcefield using loaded options: ") - forcefield = FF(options) - self.logger.debug(str(forcefield) + "\n") - assert isinstance(forcefield, FF), "Expected forcebalance forcefield object" - - ## The objective function - self.logger.debug("Creating object using loaded options and forcefield: ") - objective = Objective(options, tgt_opts, forcefield) - self.logger.debug(str(objective) + "\n") - assert isinstance(objective, Objective), "Expected forcebalance objective object" - - ## The optimizer component of the project - self.logger.debug("Creating optimizer: ") - optimizer = Optimizer(options, objective, forcefield) - self.logger.debug(str(optimizer) + "\n") - assert isinstance(optimizer, Optimizer), "Expected forcebalance optimizer object" - - ## Actually run the optimizer. - self.logger.debug("Done setting up! Running optimizer...\n") - result = optimizer.Run() - - self.logger.debug("\nOptimizer finished. Final results:\n") - self.logger.debug(str(result) + '\n') - msg = "\nCalculation results have changed from previously calculated values.\n If this seems reasonable, update EXPECTED_BROMINE_RESULTS in test_system.py with these values" - np.testing.assert_allclose(EXPECTED_BROMINE_RESULTS, result, atol=0.05, err_msg=msg) + self.run_optimizer() class TestEvaluatorBromineStudy(ForceBalanceSystemTest): def setup_method(self, method): @@ -252,7 +188,7 @@ def setup_method(self, method): ], stdout=subprocess.PIPE, stderr=subprocess.PIPE) ## Give the server time to start. time.sleep(5) - self.input_file='optimize.in' + self.input_file='gradient.in' self.logger.debug("\nSetting input file to '%s'\n" % self.input_file) def teardown_method(self): @@ -263,45 +199,14 @@ def teardown_method(self): super(TestEvaluatorBromineStudy, self).teardown_method() def test_bromine_study(self): - """Check liquid bromine study converges to expected results""" - - ## The general options and target options that come from parsing the input file - self.logger.debug("Parsing inputs...\n") - options, tgt_opts = parse_inputs(self.input_file) - self.logger.debug("options:\n%s\n\ntgt_opts:\n%s\n\n" % (str(options), str(tgt_opts))) - - assert isinstance(options, dict), "Parser gave incorrect type for options" - assert isinstance(tgt_opts, list), "Parser gave incorrect type for tgt_opts" - for target in tgt_opts: - assert isinstance(target, dict), "Parser gave incorrect type for target dict" - - ## The force field component of the project - self.logger.debug("Creating forcefield using loaded options: ") - forcefield = FF(options) - self.logger.debug(str(forcefield) + "\n") - assert isinstance(forcefield, FF), "Expected forcebalance forcefield object" - - ## The objective function - self.logger.debug("Creating object using loaded options and forcefield: ") - objective = Objective(options, tgt_opts, forcefield) - self.logger.debug(str(objective) + "\n") - assert isinstance(objective, Objective), "Expected forcebalance objective object" - - ## The optimizer component of the project - self.logger.debug("Creating optimizer: ") - optimizer = Optimizer(options, objective, forcefield) - self.logger.debug(str(optimizer) + "\n") - assert isinstance(optimizer, Optimizer), "Expected forcebalance optimizer object" - - ## Actually run the optimizer. - self.logger.debug("Done setting up! Running optimizer...\n") - result = optimizer.Run() - - self.logger.debug("\nOptimizer finished. Final results:\n") - self.logger.debug(str(result) + '\n') - - msg="\nCalculation results have changed from previously calculated values.\n If this seems reasonable, update EXPECTED_BROMINE_RESULTS in test_system.py with these values" - np.testing.assert_allclose(EXPECTED_BROMINE_RESULTS, result, atol=0.05, err_msg=msg) + """Check bromine study produces objective function and gradient in expected range """ + objective = self.get_objective() + data = objective.Full(np.zeros(objective.FF.np),1,verbose=True) + X, G, H = data['X'], data['G'], data['H'] + msgX="\nCalculated objective function is outside expected range.\n If this seems reasonable, update EXPECTED_EVALUATOR_BROMINE_OBJECTIVE in test_system.py with these values" + np.testing.assert_allclose(EXPECTED_EVALUATOR_BROMINE_OBJECTIVE, X, atol=60, err_msg=msgX) + msgG="\nCalculated gradient is outside expected range.\n If this seems reasonable, update EXPECTED_EVALUATOR_BROMINE_GRADIENT in test_system.py with these values" + np.testing.assert_allclose(EXPECTED_EVALUATOR_BROMINE_GRADIENT, G, atol=2500, err_msg=msgG) class TestLipidStudy(ForceBalanceSystemTest): def setup_method(self, method): @@ -310,45 +215,13 @@ def setup_method(self, method): os.chdir(os.path.join(cwd, '../../studies/010_lipid_study')) self.input_file='simple.in' self.logger.debug("\nSetting input file to '%s'\n" % self.input_file) + self.expected_results_name = "EXPECTED_LIPID_RESULTS" + self.expected_results = EXPECTED_LIPID_RESULTS + self.absolute_tolerance = 0.100 def test_lipid_study(self): """Check lipid tutorial study runs without errors""" - - ## The general options and target options that come from parsing the input file - self.logger.debug("Parsing inputs...\n") - options, tgt_opts = parse_inputs(self.input_file) - self.logger.debug("options:\n%s\n\ntgt_opts:\n%s\n\n" % (str(options), str(tgt_opts))) - - assert isinstance(options, dict), "Parser gave incorrect type for options" - assert isinstance(tgt_opts, list), "Parser gave incorrect type for tgt_opts" - for target in tgt_opts: - assert isinstance(target, dict), "Parser gave incorrect type for target dict" - - ## The force field component of the project - forcefield = FF(options) - assert isinstance(forcefield, FF), "Expected forcebalance forcefield object" - - ## The objective function - objective = Objective(options, tgt_opts, forcefield) - assert isinstance(objective, Objective), "Expected forcebalance objective object" - - ## The optimizer component of the project - self.logger.debug("Creating optimizer: ") - optimizer = Optimizer(options, objective, forcefield) - assert isinstance(optimizer, Optimizer), "Expected forcebalance optimizer object" - self.logger.debug(str(optimizer) + "\n") - - ## Actually run the optimizer. - self.logger.debug("Done setting up! Running optimizer...\n") - result = optimizer.Run() - self.logger.debug("\nOptimizer finished. Final results:\n") - self.logger.debug(str(result) + '\n') - msg = "\nCalculation results have changed from previously calculated values.\n If this seems reasonable, update EXPECTED_LIPID_RESULTS in test_system.py with these values (%s)" % result - np.testing.assert_allclose(EXPECTED_LIPID_RESULTS, result, atol=0.100, err_msg=msg) - - # Fail if calculation takes longer than previously to converge - assert ITERATIONS_TO_CONVERGE >= Counter(), "Calculation took longer than expected to converge (%d iterations vs previous of %d)" %\ - (ITERATIONS_TO_CONVERGE, Counter()) + self.run_optimizer() class TestImplicitSolventHFEStudy(ForceBalanceSystemTest): def setup_method(self, method): @@ -357,47 +230,13 @@ def setup_method(self, method): os.chdir(os.path.join(cwd, '..', '..', 'studies', '012_implicit_solvent_hfe')) self.input_file='optimize.in' self.logger.debug("\nSetting input file to '%s'\n" % self.input_file) + self.expected_results_name = "EXPECTED_ETHANOL_RESULTS" + self.expected_results = EXPECTED_ETHANOL_RESULTS + self.absolute_tolerance = 0.020 def test_implicit_solvent_hfe_study(self): """Check implicit hydration free energy study (Hydration target) converges to expected results""" - - ## The general options and target options that come from parsing the input file - self.logger.debug("Parsing inputs...\n") - options, tgt_opts = parse_inputs(self.input_file) - self.logger.debug("options:\n%s\n\ntgt_opts:\n%s\n\n" % (str(options), str(tgt_opts))) - - assert isinstance(options, dict), "Parser gave incorrect type for options" - assert isinstance(tgt_opts, list), "Parser gave incorrect type for tgt_opts" - for target in tgt_opts: - assert isinstance(target, dict), "Parser gave incorrect type for target dict" - - ## The force field component of the project - self.logger.debug("Creating forcefield using loaded options: ") - forcefield = FF(options) - self.logger.debug(str(forcefield) + "\n") - assert isinstance(forcefield, FF), "Expected forcebalance forcefield object" - - ## The objective function - self.logger.debug("Creating object using loaded options and forcefield: ") - objective = Objective(options, tgt_opts, forcefield) - self.logger.debug(str(objective) + "\n") - assert isinstance(objective, Objective), "Expected forcebalance objective object" - - ## The optimizer component of the project - self.logger.debug("Creating optimizer: ") - optimizer = Optimizer(options, objective, forcefield) - self.logger.debug(str(optimizer) + "\n") - assert isinstance(optimizer, Optimizer), "Expected forcebalance optimizer object" - - ## Actually run the optimizer. - self.logger.debug("Done setting up! Running optimizer...\n") - result = optimizer.Run() - result_pval = optimizer.FF.create_pvals(result) - - self.logger.debug("\nOptimizer finished. Final results:\n") - self.logger.debug(str(result) + '\n') - msg = "Calculation results have changed from previously calculated values.\n If this seems reasonable, update EXPECTED_ETHANOL_RESULTS in test_system.py with these values" - np.testing.assert_allclose(EXPECTED_ETHANOL_RESULTS,result_pval,atol=0.020, err_msg=msg) + self.run_optimizer(check_result=False, check_iter=False, use_pvals=True) class TestOpenFFTorsionProfileStudy(ForceBalanceSystemTest): def setup_method(self, method): @@ -411,45 +250,10 @@ def setup_method(self, method): targets.close() self.input_file='optimize_minimal.in' self.logger.debug("\nSetting input file to '%s'\n" % self.input_file) + self.expected_results_name = "EXPECTED_OPENFF_TORSIONPROFILE_RESULTS" + self.expected_results = EXPECTED_OPENFF_TORSIONPROFILE_RESULTS + self.absolute_tolerance = 0.001 def test_openff_torsionprofile_study(self): """Check OpenFF torsion profile optimization converges to expected results""" - - ## The general options and target options that come from parsing the input file - self.logger.debug("Parsing inputs...\n") - options, tgt_opts = parse_inputs(self.input_file) - self.logger.debug("options:\n%s\n\ntgt_opts:\n%s\n\n" % (str(options), str(tgt_opts))) - - assert isinstance(options, dict), "Parser gave incorrect type for options" - assert isinstance(tgt_opts, list), "Parser gave incorrect type for tgt_opts" - for target in tgt_opts: - assert isinstance(target, dict), "Parser gave incorrect type for target dict" - - ## The force field component of the project - self.logger.debug("Creating forcefield using loaded options: ") - forcefield = FF(options) - self.logger.debug(str(forcefield) + "\n") - assert isinstance(forcefield, FF), "Expected forcebalance forcefield object" - - ## The objective function - self.logger.debug("Creating object using loaded options and forcefield: ") - objective = Objective(options, tgt_opts, forcefield) - self.logger.debug(str(objective) + "\n") - assert isinstance(objective, Objective), "Expected forcebalance objective object" - - ## The optimizer component of the project - self.logger.debug("Creating optimizer: ") - optimizer = Optimizer(options, objective, forcefield) - self.logger.debug(str(optimizer) + "\n") - assert isinstance(optimizer, Optimizer), "Expected forcebalance optimizer object" - - ## Actually run the optimizer. - self.logger.debug("Done setting up! Running optimizer...\n") - result = optimizer.Run() - - self.logger.debug("\nOptimizer finished. Final results:\n") - self.logger.debug(str(result) + '\n') - - msg="\nCalculation results have changed from previously calculated values.\n If this seems reasonable, " \ - "update EXPECTED_OPENFF_TORSIONPROFILE_RESULTS in test_system.py with these values" - np.testing.assert_allclose(EXPECTED_OPENFF_TORSIONPROFILE_RESULTS,result,atol=0.001,err_msg=msg) + self.run_optimizer(check_iter=False) diff --git a/studies/003d_estimator_liquid_bromine/gradient.in b/studies/003d_estimator_liquid_bromine/gradient.in new file mode 100644 index 000000000..5c7687b84 --- /dev/null +++ b/studies/003d_estimator_liquid_bromine/gradient.in @@ -0,0 +1,66 @@ +# ForceBalance input file generated by MakeInputFile.py +# The octothorpe '#' is a comment symbol +# Note: If the specified value is 'None' then the option will truly be set to None - not the string 'None' +# Note: 'Section' option types are more complicated and may require you to read the documentation +# Note: Boolean option types require no value, the key being present implies 'True' + +$options +# (string) Directory containing force fields, relative to project directory +ffdir forcefield + +# (string) Type of the penalty, L2 or L1 in the optimizer +penalty_type L2 + +# (allcap) The job type, defaults to a single-point evaluation of objective function +jobtype gradient + +# (list) The names of force fields, corresponding to directory forcefields/file_name.(itp|gen) +forcefield bromine.offxml + +# (int) Maximum number of steps in an optimization +maxstep 100 + +# (float) Convergence criterion of step size (just needs to fall below this threshold) +convergence_step 0.1 + +# (float) Convergence criterion of objective function (in MainOptimizer this is the stdev of x2 over 10 steps) +convergence_objective 0.1 + +# (float) Convergence criterion of gradient norm +convergence_gradient 0.1 + +criteria 1 + +# (float) Minimum eigenvalue for applying steepest descent correction in the MainOptimizer +eig_lowerbound 0.01 + +# (float) Step size for finite difference derivatives in many functions (get_(G/H) in fitsim, FDCheckG) +finite_difference_h 0.001 + +# (float) Factor for multiplicative penalty function in objective function +penalty_additive 1.0 + +trust0 1.0 +mintrust 0.05 +error_tolerance 1.0 +adaptive_factor 0.2 +adaptive_damping 1.0 +normalize_weights no +print_hessian + +# Charge constraints are taken care of using "evals". +constrain_charge false +backup false + +priors + vdW/Atom/epsilon : 2.47894e+00 + vdW/Atom/sigma : 5.29177e-02 +/priors +$end + +$target +name LiquidBromine +type PropertyEstimate_SMIRNOFF +weight 1.0 +prop_est_input options.json +$end diff --git a/studies/003d_estimator_liquid_bromine/optimize.in b/studies/003d_estimator_liquid_bromine/optimize.in index 00cb2a403..fae61ce2d 100644 --- a/studies/003d_estimator_liquid_bromine/optimize.in +++ b/studies/003d_estimator_liquid_bromine/optimize.in @@ -59,6 +59,12 @@ priors $end +# Note: Denominators have been changed from the original Gromacs version of the study (003_liquid_bromine) +# in order to create a unit test for gradients rather than the optimization result. +# Therefore, optimization results will differ from the Gromacs version. +# To reproduce results from the Gromacs version, change density and Hvap denominators +# to 30.0 and 0.3 respectively. + $target name LiquidBromine type PropertyEstimate_SMIRNOFF diff --git a/studies/003d_estimator_liquid_bromine/targets.tar.gz b/studies/003d_estimator_liquid_bromine/targets.tar.gz index a9fd090b1..84111dc01 100644 Binary files a/studies/003d_estimator_liquid_bromine/targets.tar.gz and b/studies/003d_estimator_liquid_bromine/targets.tar.gz differ