├── .codecov.yml ├── .gitattributes ├── .github └── workflows │ └── CI.yml ├── .gitignore ├── .readthedocs.yaml ├── LICENSE ├── MANIFEST.in ├── Makefile ├── README.rst ├── devtools ├── conda-envs │ ├── base.yaml │ ├── dev.yaml │ └── docs.yaml ├── scripts │ ├── conda_env.py │ └── dev_conda_env.py └── travis-ci │ └── before_install.sh ├── docs ├── Makefile ├── readme.md └── source │ ├── algorithms.rst │ ├── api.rst │ ├── conf.py │ ├── convergence.rst │ ├── coords.rst │ ├── index.rst │ ├── molecule.rst │ ├── optimizations.rst │ └── options.rst ├── media ├── optking.jpeg └── s8.png ├── optking ├── IRCdata.py ├── IRCfollowing.py ├── __init__.py ├── _version.py ├── addIntcos.py ├── bend.py ├── cart.py ├── caseInsensitiveDict.py ├── compute_wrappers.py ├── convcheck.py ├── dimerfrag.py ├── displace.py ├── exceptions.py ├── frag.py ├── hessian.py ├── history.py ├── intcosMisc.py ├── linearAlgebra.py ├── linesearch.py ├── lj_functions.py ├── loggingconfig.py ├── misc.py ├── molsys.py ├── oofp.py ├── opt_helper.py ├── optimize.py ├── optparams.py ├── optwrapper.py ├── orient.py ├── printTools.py ├── simple.py ├── stepAlgorithms.py ├── stre.py ├── testB.py ├── tests │ ├── __init__.py │ ├── ch3chch2cl.in │ ├── conftest.py │ ├── dimer_benzene_jupyter_demo.ipynb │ ├── json_betapinene.json │ ├── json_h2o.json │ ├── json_hooh_frozen.json │ ├── json_lif_cp.json │ ├── json_lif_nocp.json │ ├── psi4_helper.py │ ├── psi4inputs │ │ ├── __init__.py │ │ ├── psiAPIversions │ │ │ ├── __init__.py │ │ │ ├── dimer-h2o-c6h6.py │ │ │ ├── dimer-h2o.py │ │ │ ├── dimer-ne2.py │ │ │ └── froz-dimer-h2o.py │ │ └── psithon_versions │ │ │ ├── b3lyp-g-phenylacetylene.in │ │ │ ├── ccsd-g-ch2.in │ │ │ ├── ccsd-g-h2o.in │ │ │ ├── dcft-g-o2.in │ │ │ ├── hf-e-h2o.in │ │ │ ├── hf-g-SF4-breaksLinear.in │ │ │ ├── hf-g-alleneLinear.in │ │ │ ├── hf-g-alleneNonlinear.in │ │ │ ├── hf-g-h2o-freq.in │ │ │ ├── hf-g-h2o-frozenCart.in │ │ │ ├── hf-g-h2o-large.in │ │ │ ├── hf-g-h2o-test-maxiter.in │ │ │ ├── hf-g-h2o-tight.in │ │ │ ├── hf-g-h2o.in │ │ │ ├── hf-g-hooh-fixed-3.in │ │ │ ├── hf-g-hooh-frozen-3.in │ │ │ ├── hf-g-hooh-frozenCart-2.in │ │ │ ├── hf-g-hooh-frozenCartInCarts-3.in │ │ │ ├── hf-g-ketene-bent.in │ │ │ ├── mp2-g-h2o.in │ │ │ ├── scsomp2-g-h2o.in │ │ │ ├── scsomp3-g-h2o.in │ │ │ ├── sosomp2-g-h2o.in │ │ │ ├── sosomp3-g-h2o.in │ │ │ ├── todo-psi4tests.txt │ │ │ ├── ts-hf-g-hooh-2.in │ │ │ ├── uccsd-g-ch2.in │ │ │ ├── uccsdpt-g-ch2.in │ │ │ └── uhf-g-ch2-dummy.in │ ├── test_2_hessians.py │ ├── test_atom.py │ ├── test_atom_stepwise.py │ ├── test_auxiliary_bonds.py │ ├── test_ccsd_g_opt.py │ ├── test_conjugate.py │ ├── test_dcft_g_opt.py │ ├── test_deriv_transforms.py │ ├── test_dimers_Bmat.py │ ├── test_dimers_benzene_pes.py │ ├── test_dimers_h2o.py │ ├── test_dimers_mt_tyr_Rscan.py │ ├── test_dimers_mt_tyr_frozen_orientation.py │ ├── test_dimers_ne2.py │ ├── test_dimers_orient.py │ ├── test_frozen_cart_and_backstep.py │ ├── test_frozen_internals.py │ ├── test_g_convergence.py │ ├── test_hbond.py │ ├── test_hf_g_keywords.py │ ├── test_hf_g_opt.py │ ├── test_hooh_ext_force.py │ ├── test_irc_hooh.py │ ├── test_jsoninput.py │ ├── test_linesearch.py │ ├── test_lj.py │ ├── test_methimazole.py │ ├── test_mp2_g_opt.py │ ├── test_nearlinear_dft_opt.py │ ├── test_oofp.py │ ├── test_openshell.py │ ├── test_opt2_allene.py │ ├── test_opt5-ch2.py │ ├── test_opthelper.py │ ├── test_optimization_input.py │ ├── test_ranged_internals.py │ ├── test_scsmp2_opt.py │ ├── test_sf4_quasilinear.py │ ├── test_step_types.py │ ├── test_trimers_h2o.py │ ├── test_ts_opt.py │ └── utils │ │ ├── __init__.py │ │ └── utils.py ├── tors.py └── v3d.py ├── setup.cfg ├── setup.py └── versioneer.py /.codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | status: 3 | patch: false 4 | project: 5 | default: 6 | threshold: 50% 7 | ignore: 8 | - "tests/.*" 9 | - "setup.py" 10 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | optking/_version.py export-subst 2 | -------------------------------------------------------------------------------- /.github/workflows/CI.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | 8 | # prevent actions from running on both the push to the PR and PR 9 | # only run actions on PRs originating from a fork 10 | if: 11 | github.event_name == 'push' || github.event.pull_request.head.repo.full_name != 12 | github.repository 13 | 14 | runs-on: ubuntu-latest 15 | strategy: 16 | fail-fast: false 17 | matrix: 18 | cfg: 19 | - conda-env: base 20 | python-version: 3.8 21 | - conda-env: base 22 | python-version: 3.9 23 | - conda-env: base 24 | python-version: "3.10" 25 | - conda-env: base 26 | python-version: "3.12" 27 | env: 28 | PYVER: ${{ matrix.cfg.python-version }} 29 | CONDA_ENV: ${{ matrix.cfg.conda-env }} 30 | 31 | steps: 32 | - uses: actions/checkout@v2 33 | 34 | - name: Create Environment 35 | uses: conda-incubator/setup-miniconda@v2 36 | with: 37 | installer-url: https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh 38 | activate-environment: test 39 | environment-file: devtools/conda-envs/${{ matrix.cfg.conda-env }}.yaml 40 | python-version: ${{ matrix.cfg.python-version }} 41 | auto-activate-base: false 42 | 43 | - name: Setup Information 44 | shell: bash -l {0} 45 | run: | 46 | uname -a 47 | df -h 48 | ulimit -a 49 | echo $CONDA 50 | echo $(which conda) 51 | conda --version 52 | 53 | - name: Install 54 | shell: bash -l {0} 55 | run: | 56 | python -m pip install . --no-deps 57 | - name: Environment Information 58 | shell: bash -l {0} 59 | run: | 60 | conda list --show-channel-urls 61 | - name: PyTest 62 | shell: bash -l {0} 63 | run: | 64 | pytest -rws -v -m "not long" --cov=optking --color=yes --cov-report=xml optking/ 65 | - name: CodeCov 66 | uses: codecov/codecov-action@v4 67 | with: 68 | token: ${{ secrets.CODECOV_TOKEN }} 69 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | 49 | # Translations 50 | *.mo 51 | *.pot 52 | 53 | # Django stuff: 54 | *.log 55 | local_settings.py 56 | 57 | # Flask stuff: 58 | instance/ 59 | .webassets-cache 60 | 61 | # Scrapy stuff: 62 | .scrapy 63 | 64 | # Sphinx documentation 65 | docs/_build/ 66 | docs/source/api/ 67 | 68 | # PyBuilder 69 | target/ 70 | 71 | # Jupyter Notebook 72 | .ipynb_checkpoints 73 | 74 | # pyenv 75 | .python-version 76 | 77 | # celery beat schedule file 78 | celerybeat-schedule 79 | 80 | # SageMath parsed files 81 | *.sage.py 82 | 83 | # dotenv 84 | .env 85 | 86 | # virtualenv 87 | .venv 88 | venv/ 89 | ENV/ 90 | 91 | # Spyder project settings 92 | .spyderproject 93 | .spyproject 94 | 95 | # Rope project settings 96 | .ropeproject 97 | 98 | # mkdocs documentation 99 | /site 100 | 101 | # mypy 102 | .mypy_cache/ 103 | 104 | # Files resulting from compilation 105 | *.o 106 | *.a 107 | *.so 108 | *.d 109 | .idea 110 | 111 | # Compilation directories that people use 112 | obj* 113 | *objdir 114 | config 115 | build* 116 | debug 117 | debug_latest 118 | *.sh 119 | TEST 120 | */test.py 121 | */test.dat 122 | 123 | # Files resulting from running PSI4 124 | ijk.dat 125 | output.dat 126 | input.py.dat 127 | *.out 128 | *.32 129 | *.clean 130 | *timer.dat 131 | *.molden 132 | *.cube 133 | dfh.* 134 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | build: 4 | os: ubuntu-22.04 5 | tools: 6 | python: "mambaforge-latest" 7 | 8 | conda: 9 | environment: devtools/conda-envs/docs.yaml 10 | 11 | sphinx: 12 | configuration: docs/source/conf.py 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2017-2022, Rollin A. King 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | recursive-include optking *.py *.json 2 | 3 | include setup.py 4 | include README.md 5 | include LICENSE 6 | include MANIFEST.in 7 | 8 | include versioneer.py 9 | include optking/_version.py 10 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | isort = isort optking 2 | black = black -l 120 optking 3 | 4 | .PHONY: format 5 | format: 6 | $(isort) 7 | $(black) 8 | 9 | .PHONY: lint 10 | lint: 11 | $(isort) --check-only 12 | $(black) --check 13 | -------------------------------------------------------------------------------- /devtools/conda-envs/base.yaml: -------------------------------------------------------------------------------- 1 | name: test 2 | channels: 3 | - conda-forge 4 | - nodefaults 5 | dependencies: 6 | # Base 7 | - numpy 8 | - python 9 | - qcelemental 10 | - msgpack-python 11 | 12 | # Testing 13 | - pytest 14 | - pytest-cov 15 | - psi4 1.9.1 16 | - dftd3-python 17 | - codecov 18 | -------------------------------------------------------------------------------- /devtools/conda-envs/dev.yaml: -------------------------------------------------------------------------------- 1 | name: test 2 | channels: 3 | - conda-forge 4 | - nodefaults 5 | dependencies: 6 | # Base 7 | - numpy 8 | - python 9 | - qcelemental 10 | - qcengine 11 | - msgpack-python 12 | 13 | # Testing 14 | - pytest 15 | - pytest-cov 16 | - psi4 1.9.1 17 | - dftd3-python 18 | - codecov 19 | 20 | # Dev 21 | - sphinx 22 | - sphinx-automodapi 23 | - sphinx_material 24 | - graphviz 25 | - black 26 | - isort 27 | -------------------------------------------------------------------------------- /devtools/conda-envs/docs.yaml: -------------------------------------------------------------------------------- 1 | name: test 2 | channels: 3 | - conda-forge 4 | 5 | dependencies: 6 | - numpy 7 | - python 8 | - qcelemental 9 | - msgpack-python 10 | - sphinx=7.3.7 11 | - sphinx-automodapi=0.16 12 | - sphinx_rtd_theme=2.0.0 13 | - graphviz=9.0.0 14 | -------------------------------------------------------------------------------- /devtools/scripts/conda_env.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import os 3 | import shutil 4 | import subprocess as sp 5 | 6 | # Args 7 | parser = argparse.ArgumentParser( 8 | description="Creates a conda environment from file for a given Python version." 9 | ) 10 | parser.add_argument( 11 | "-n", "--name", type=str, nargs=1, help="The name of the created Python environment" 12 | ) 13 | parser.add_argument( 14 | "-p", 15 | "--python", 16 | type=str, 17 | nargs=1, 18 | help="The version of the created Python environment", 19 | ) 20 | parser.add_argument( 21 | "conda_file", nargs="*", help="The file for the created Python environment" 22 | ) 23 | 24 | args = parser.parse_args() 25 | 26 | with open(args.conda_file[0], "r") as handle: 27 | script = handle.read() 28 | 29 | tmp_file = "tmp_env.yaml" 30 | script = script.replace("- python", "- python {}*".format(args.python[0])) 31 | 32 | with open(tmp_file, "w") as handle: 33 | handle.write(script) 34 | 35 | conda_path = shutil.which("conda") 36 | 37 | print("CONDA ENV NAME {}".format(args.name[0])) 38 | print("PYTHON VERSION {}".format(args.python[0])) 39 | print("CONDA FILE NAME {}".format(args.conda_file[0])) 40 | print("CONDA path {}".format(conda_path)) 41 | 42 | sp.call( 43 | "{} env create -n {} -f {}".format(conda_path, args.name[0], tmp_file), shell=True 44 | ) 45 | os.unlink(tmp_file) 46 | -------------------------------------------------------------------------------- /devtools/scripts/dev_conda_env.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import os 3 | import shutil 4 | import subprocess as sp 5 | 6 | # Args 7 | parser = argparse.ArgumentParser( 8 | description="Creates a conda environment from file for a given Python version." 9 | ) 10 | 11 | parser.add_argument( 12 | "-n", "--name", type=str, nargs=1, help="The name of the created Python environment" 13 | ) 14 | 15 | args = parser.parse_args() 16 | 17 | with open('../conda-envs/dev.yaml', "r") as handle: 18 | script = handle.read() 19 | 20 | tmp_file = "tmp_env.yaml" 21 | 22 | with open(tmp_file, "w") as handle: 23 | handle.write(script) 24 | 25 | conda_path = shutil.which("conda") 26 | 27 | sp.call( 28 | "{} env create -n {} -f {}".format(conda_path, args.name[0], tmp_file), shell=True 29 | ) 30 | os.unlink(tmp_file) 31 | 32 | -------------------------------------------------------------------------------- /devtools/travis-ci/before_install.sh: -------------------------------------------------------------------------------- 1 | # Temporarily change directory to $HOME to install software 2 | pushd . 3 | cd "$HOME" 4 | 5 | # Install Miniconda 6 | if [ "$TRAVIS_OS_NAME" == "osx" ]; then 7 | # Make OSX md5 mimic md5sum from linux, alias does not work 8 | md5sum () { 9 | command md5 -r "$@" 10 | } 11 | MINICONDA=Miniconda3-latest-MacOSX-x86_64.sh 12 | else 13 | MINICONDA=Miniconda3-latest-Linux-x86_64.sh 14 | fi 15 | MINICONDA_HOME=$HOME/miniconda 16 | 17 | echo "-- Installing latest Miniconda" 18 | if [ -d "$MINICONDA_HOME/bin" ]; then 19 | echo "-- Miniconda latest version FOUND in cache" 20 | 21 | # Config settings are not saved in the cache 22 | export PIP_ARGS="-U" 23 | export PATH=$MINICONDA_HOME/bin:$PATH 24 | 25 | conda config --set always_yes yes --set changeps1 no 26 | else 27 | MINICONDA_MD5=$(wget -qO- https://repo.anaconda.com/miniconda/ | grep -A3 $MINICONDA | sed -n '4p' | sed -n 's/ *\(.*\)<\/td> */\1/p') 28 | echo "-- Miniconda latest version NOT FOUND in cache" 29 | wget -q https://repo.continuum.io/miniconda/$MINICONDA 30 | if [[ $MINICONDA_MD5 != $(md5sum $MINICONDA | cut -d ' ' -f 1) ]]; then 31 | echo "Miniconda MD5 mismatch" 32 | exit 1 33 | fi 34 | # Travis creates the cached directories for us. 35 | # This is problematic when wanting to install Anaconda for the first time... 36 | rm -rf "$MINICONDA_HOME" 37 | bash $MINICONDA -b -p "$MINICONDA_HOME" 38 | 39 | # Configure miniconda 40 | export PIP_ARGS="-U" 41 | export PATH=$MINICONDA_HOME/bin:$PATH 42 | 43 | conda config --set always_yes yes --set changeps1 no 44 | conda update -q conda 45 | 46 | rm -f $MINICONDA 47 | fi 48 | echo "-- Done with latest Miniconda" 49 | 50 | # Restore original directory 51 | popd 52 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | SPHINXPROJ = pyoptking 8 | SOURCEDIR = source 9 | BUILDDIR = build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -------------------------------------------------------------------------------- /docs/readme.md: -------------------------------------------------------------------------------- 1 | Optking's documentation is built by `sphinx` and hosted on `readthedocs.org` 2 | To build the documentation install the following dependencies 3 | 4 | ``` 5 | conda install sphinx graphviz sphinx-automodapi sphinx_rtd_theme -c conda-forge 6 | ``` 7 | 8 | To build locally 9 | 10 | ``` 11 | cd docs && make html 12 | ``` 13 | 14 | For instructions on how to add documentation or a primer on `reStructuredText`, read the [Sphinx documentation](https://www.sphinx-doc.org/en/master/index.html) 15 | -------------------------------------------------------------------------------- /docs/source/algorithms.rst: -------------------------------------------------------------------------------- 1 | Optimization Algorithms 2 | ======================= 3 | 4 | Optking performs Newton-Raphson (NR) and Qausi-NR optimizations for small to medium-sized molecules. 5 | 6 | Algorithms include 7 | * Steepest descent 8 | * NR 9 | * Rational function optimization (RFO) 10 | * Restricted Step RFO 11 | * Partioned RFO 12 | * Intrinsic Reaction Coordinate (IRC) optimizations 13 | 14 | The type of optimization is controlled by the `step_type` and `opt_type` keywords. `step_type` chooses optimization algorithm (SD, NR, etc.) 15 | `opt_type` selects the kind of optimization (min, TS, or IRC) and unless overriden chooses the appropriate (or default) `step_type`. 16 | 17 | API Documentation 18 | ----------------- 19 | 20 | For more information on the OptHelper classes see `optimizations`_. To simply run an optimization 21 | the OptHelper classes or the interfaces through QCEngine and Psi4 are recommended, especially the later. 22 | 23 | For more information on interacting directly with the algorithms see the API documentation below. In short, 24 | the OptimizationAlgorithm class provides a basic "interface" for running optimizations through the `take_step()` 25 | method. The OptimizationManager class extends this interface to encompass the addition of linesearching 26 | to any of the basic algorithms and IRCFollowing. 27 | 28 | .. automodapi:: optking.stepAlgorithms 29 | .. automodapi:: optking.linesearch 30 | .. automodapi:: optking.IRCfollowing 31 | -------------------------------------------------------------------------------- /docs/source/api.rst: -------------------------------------------------------------------------------- 1 | 2 | High Level functions and Classes 3 | -------------------------------- 4 | 5 | The following documentation pertains to the classes and functions that would 6 | most likely be useful for running optimizations directly through optkings python API and 7 | functions that would be helpful for driver level operations. 8 | 9 | .. automodapi:: optking.opt_helper 10 | .. automodapi:: optking.optimize 11 | 12 | -------------------------------------------------------------------------------- /docs/source/convergence.rst: -------------------------------------------------------------------------------- 1 | ########### 2 | Convergence 3 | ########### 4 | 5 | .. |delta| unicode:: U+0394 6 | 7 | Optking utilizes a number of optimization presets which mirror and/or mimic the optmization behavior from a number 8 | of popular Quantum Chemistry packages. These may be selected with the *G_CONVERGENCE* keyword. Descriptions of each 9 | preset may be found below. See Notes [#fe] and [#ff] for clarification on what combinations of 10 | criteria are required or allowed. 11 | 12 | For greater control one or more ctriteria can be selectively activated through use of the *_G_CONVERGENCE* keywords. 13 | In order to modify a preset both *FLEXIBLE_G_CONVERGENCE* and one or more *_G_CONVERGENCE* keywords must be 14 | selected in addition to the preset. Specifying *_G_CONVERGENCE* without *FLEXIBLE_G_CONVERGENCE* will cause 15 | the preset to be discarded and optking will ONLY consider the *_G_CONVERGENCE* keyword for convergence. 16 | 17 | As an example the first set of options only changes the `rms_force` threshold. The second changes from `QCHEM` to `GAU_TIGHT` while 18 | loosening the `rms_force` threshold 19 | 20 | :: 21 | 22 | {"g_convergence": "gau_tight", "rms_force_g_convergence": 3e-5} 23 | {"g_convergence": "gau_tight", "flexible_g_convergence": True, "rms_force_g_convergence": 3e-5} 24 | 25 | .. _`table:optkingconv`: 26 | 27 | .. table:: Summary of convergence criteria for *g_convergence* defaults in optking (Same as in Psi4) 28 | 29 | +-----------------------------+----------------------------+----------------------------+----------------------------+----------------------------+----------------------------+ 30 | | *g_convergence* | |delta| E | Max Force | RMS Force | Max Disp | RMS Disp | 31 | +=============================+============================+============================+============================+============================+============================+ 32 | | NWCHEM_LOOSE [#fd]_ | | :math:`4.5 \times 10^{-3}` | :math:`3.0 \times 10^{-3}` | :math:`5.4 \times 10^{-3}` | :math:`3.6 \times 10^{-3}` | 33 | +-----------------------------+----------------------------+----------------------------+----------------------------+----------------------------+----------------------------+ 34 | | GAU_LOOSE [#ff]_ | | :math:`2.5 \times 10^{-3}` | :math:`1.7 \times 10^{-3}` | :math:`1.0 \times 10^{-2}` | :math:`6.7 \times 10^{-3}` | 35 | +-----------------------------+----------------------------+----------------------------+----------------------------+----------------------------+----------------------------+ 36 | | TURBOMOLE [#fd]_ | :math:`1.0 \times 10^{-6}` | :math:`1.0 \times 10^{-3}` | :math:`5.0 \times 10^{-4}` | :math:`1.0 \times 10^{-3}` | :math:`5.0 \times 10^{-4}` | 37 | +-----------------------------+----------------------------+----------------------------+----------------------------+----------------------------+----------------------------+ 38 | | GAU [#fc]_ [#ff]_ | | :math:`4.5 \times 10^{-4}` | :math:`3.0 \times 10^{-4}` | :math:`1.8 \times 10^{-3}` | :math:`1.2 \times 10^{-3}` | 39 | +-----------------------------+----------------------------+----------------------------+----------------------------+----------------------------+----------------------------+ 40 | | CFOUR [#fd]_ | | | :math:`1.0 \times 10^{-4}` | | | 41 | +-----------------------------+----------------------------+----------------------------+----------------------------+----------------------------+----------------------------+ 42 | | QCHEM [#fa]_ [#fe]_ | :math:`1.0 \times 10^{-6}` | :math:`3.0 \times 10^{-4}` | | :math:`1.2 \times 10^{-3}` | | 43 | +-----------------------------+----------------------------+----------------------------+----------------------------+----------------------------+----------------------------+ 44 | | MOLPRO [#fb]_ [#fe]_ | :math:`1.0 \times 10^{-6}` | :math:`3.0 \times 10^{-4}` | | :math:`3.0 \times 10^{-4}` | | 45 | +-----------------------------+----------------------------+----------------------------+----------------------------+----------------------------+----------------------------+ 46 | | GAU_TIGHT [#fc]_ [#ff]_ | | :math:`1.5 \times 10^{-5}` | :math:`1.0 \times 10^{-5}` | :math:`6.0 \times 10^{-5}` | :math:`4.0 \times 10^{-5}` | 47 | +-----------------------------+----------------------------+----------------------------+----------------------------+----------------------------+----------------------------+ 48 | | GAU_VERYTIGHT [#ff]_ | | :math:`2.0 \times 10^{-6}` | :math:`1.0 \times 10^{-6}` | :math:`6.0 \times 10^{-6}` | :math:`4.0 \times 10^{-6}` | 49 | +-----------------------------+----------------------------+----------------------------+----------------------------+----------------------------+----------------------------+ 50 | 51 | .. rubric:: Footnotes 52 | 53 | .. [#fa] Default 54 | .. [#fb] Baker convergence criteria are the same. 55 | .. [#fc] Counterpart NWCHEM convergence criteria are the same. 56 | .. [#fd] Convergence achieved when all active criteria are fulfilled. 57 | .. [#fe] Convergence achieved when **Max Force** and one of **Max Energy** or **Max Disp** are fulfilled. 58 | .. [#ff] Normal convergence achieved when all four criteria (**Max Force**, **RMS Force**, 59 | **Max Disp**, and **RMS Disp**) are fulfilled. To help with flat 60 | potential surfaces, alternate convergence achieved when 100\ :math:`\times`\ *rms force* is less 61 | than **RMS Force** criterion. 62 | 63 | IRC Convergence 64 | --------------- 65 | 66 | The IRC algorithm uses slightly different convergence criteria since the step sizes are of a fixed distance. 67 | The optimization ends when the forces are opposite the forces of the previous step at a certain threshold < -0.7. 68 | Alternatively an increase in energy along the MEP with any negative overlap of the forces is sufficient. 69 | 70 | Individual points on the IRC are optimized in a constrained optimization (on a hypersphere of fixed radius) according 71 | to the convergence criteria of the table above. 72 | -------------------------------------------------------------------------------- /docs/source/coords.rst: -------------------------------------------------------------------------------- 1 | General Recommendations 2 | ======================= 3 | 4 | Redundant internal coordinates are the default coordinate set for optking. All possible simple stretches, bends, 5 | and dihedral angles are constructed. Automatic supplementation of cartesian coordinates is in development. 6 | If difficulty is encountered with linear coordinates, switching to `opt_coordinates = 'cartesian'` may be 7 | necessary. In some cases a full set of internal and cartesian coordinates has been found to work well this 8 | corresonds to `opt_coordinates = 'both'` 9 | 10 | It should be noted that optking does NOT accept zmatrix coordinates through any of it's supported interfaces. 11 | Communication of the initial geometry between optking and qcengine or psi4 is purely in cartesian coordinates. 12 | Simple internal coordinates can be created through the class constructors if desired; however, 13 | ghost atoms are not supported. 14 | 15 | Adding Constraints to the Optimization 16 | ====================================== 17 | 18 | Three types of constraints are supported. The built in coordinates (stre, bend, cart, etc) can be frozen with a 19 | `frozen_` keyword. The coordinate will be held constant with the initial provided value throughout the 20 | optimization. 21 | 22 | For users of the old c++ optking, the `fixed_` options have been replaced with more general 23 | `ranged_` counterparts. This keyword adds forces to the optimization to keep the coordinate within a desired 24 | min and max value (these can be set arbitrarily close to each other to recover the `fixed_` behavior). 25 | 26 | Where applicable input should be specified in Angstroms and Degrees (even if the geomtry is provided in atomic units through QCEngine). 27 | 28 | Frozen Coordinates 29 | ~~~~~~~~~~~~~~~~~~ 30 | 31 | Input for the `frozen_` keywords is expected as a list of the indices to constrain. 32 | Parentheses can be added by the user for clarity and are avoided. 33 | The string parsing is more robust and forgiving than in the c++ version and multiline strings and strange spacing 34 | is allowed. 35 | 36 | For hydrogen peroxide the following coordinates could be frozen: 37 | 38 | .. code-block:: python 39 | 40 | hooh = psi4.geometry( 41 | """ 42 | H 43 | O 1 0.90 44 | O 2 1.40 1 100.0 45 | H 3 0.90 2 100.0 1 115.0 46 | """ 47 | ) 48 | 49 | params = { 50 | "frozen_distance": "1 2 3 4" 51 | } 52 | 53 | freezing bond angles:: 54 | 55 | "frozen_bend": "1 2 3 2 3 4" 56 | 57 | freezing torsions:: 58 | 59 | "frozen_dihedral": "1 2 3 4" 60 | 61 | The following strings are all acceptable to freeze the cartesian coordinates of the hydrogens: 62 | 63 | .. code-block:: python 64 | 65 | """ 1 Xyz 4 xYz """ 66 | """ 2 xyz 3 xyz """ 67 | """ 68 | 1 x 69 | 1 y 70 | 1 Z 71 | 4 x 72 | 4 Y 73 | 4 z """ 74 | 75 | Ranged Coordinates 76 | ~~~~~~~~~~~~~~~~~~ 77 | 78 | The `ranged_` follows the basic format. `1 2 ... min max`. Multiple coordinates can be assigned 79 | ranges by specifying them sequentially in the string. Using the above example for `HOOH`: 80 | 81 | .. code-block:: python 82 | 83 | params = { 84 | "ranged_distance": "2 3 1.38 1.42" 85 | } 86 | 87 | or using parentheses for clarity: 88 | 89 | .. code-block:: python 90 | 91 | params = { 92 | "ranged_bend": "(1 2 3 99.0 110.0) (2 3 4 99.0 110.0)" 93 | } 94 | 95 | 96 | Adding Forces 97 | ~~~~~~~~~~~~~ 98 | 99 | Custom forces may be added to specific coordinates by adding a potential function to the coordinate as a function of x. 100 | 101 | For instance a simple linear potential function can be added to push the OH bond lengths towards 0.95 angstroms:: 102 | 103 | "ext_force_distance": "1 2 '-8.0*(x-0.950)' 3 4 '-8.0*(x-0.950)'" 104 | 105 | Currently supported functions are `"sin", "cos", "log", "ln", "log10", "exp", "pow", "abs"` 106 | 107 | 108 | Multifragment Optimizations 109 | =========================== 110 | 111 | For multifragment systems, dimer coordinates are recommended. These may be configured automatically 112 | (simply set `"frag_mode"="MULTI"`) or manually through the `interfrag_coords` keyword. 113 | The `interfrag_coords` keyword expects a dictionary and has a number of fields to allow full 114 | specification of these coordinates 115 | 116 | The DimerFrag creates internal coordinates between pairs of molecules. i.e. water trimer would 117 | consist internal coordinates for A, B, and C as well as dimer coordinates for AB, AC, and BC 118 | 119 | The important keys are 120 | * `"Natoms per frag"` is a list of ints 121 | * `X Frag` specifies the index of the Xth fragment in the molecular system. 122 | * `A Ref Atoms` list of the atoms to use as the three reference points. In the below example we choose the oxygen atom, 123 | third hydrogen atom, and the center of the two hydrogens. 124 | Lists of multiple indices denote the mid-point between the specified atoms. 125 | 126 | .. code-block:: python 127 | 128 | h2oA = psi4.geometry( 129 | """ 130 | O 131 | H 1 1.0 132 | H 1 1.0 2 104.5 133 | """ 134 | ) 135 | Axyz = h2oA.geometry().np 136 | 137 | h2oB = psi4.geometry( 138 | """ 139 | O 140 | H 1 1.0 141 | H 1 1.0 2 104.5 142 | """ 143 | ) 144 | 145 | water_dimer = { 146 | "Natoms per frag": [3, 3], 147 | "A Frag": 1, # Index of fragment in Molsys. 1 Based indexing 148 | "A Ref Atoms": [[1], [2, 3], [3]], 149 | "A Label": "Water-A", # optional 150 | "B Frag": 2, 151 | "B Ref Atoms": [[4], [5, 6], [6]], 152 | "B Label": "Water-B", # optional 153 | } 154 | 155 | 156 | .. automodapi:: optking.stre 157 | .. automodapi:: optking.bend 158 | .. automodapi:: optking.tors 159 | -------------------------------------------------------------------------------- /docs/source/index.rst: -------------------------------------------------------------------------------- 1 | .. pyoptking documentation master file, created by 2 | sphinx-quickstart on Wed Jul 25 16:46:02 2018. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to pyoptking's documentation! 7 | ===================================== 8 | 9 | .. image:: ../../media/optking.jpeg 10 | .. image:: ../../media/s8.png 11 | 12 | .. toctree:: 13 | :maxdepth: 2 14 | :caption: Contents: 15 | 16 | optimizations 17 | convergence 18 | algorithms 19 | molecule 20 | coords 21 | options 22 | 23 | 24 | Indices and tables 25 | ================== 26 | 27 | * :ref:`genindex` 28 | * :ref:`modindex` 29 | * :ref:`search` 30 | -------------------------------------------------------------------------------- /docs/source/molecule.rst: -------------------------------------------------------------------------------- 1 | The Molecular System 2 | ==================== 3 | 4 | Opkting's molecular system, at its core, is a list of intramolecular fragments `frag.Frag` and 5 | intermolecular fragments `dimerfrag.DimerFrag`. The fragments in turn are lists of masses, atomic numbers and coordinates (cartesian or internal) 6 | along with a numpy array for the cartesian geometry. 7 | NIST values for masses, and atomic numbers can be easily retrieved through `qcelemental` e.g. `qcelemental.periodictable.to_Z('O')` 8 | 9 | A fragment for water: 10 | 11 | .. code-block:: python-console 12 | 13 | >>> import optking 14 | >>> zs = [1, 8, 1] 15 | >>> masses = [1.007825032230, 15.994914619570, 1.007825032230] 16 | >>> geometry = [[-0.028413670411, 0.928922556351, 0.000000000000], 17 | [-0.053670056908, -0.039737675589, 0.000000000000], 18 | [ 0.880196420813, -0.298256807934, 0.000000000000]] 19 | >>> fragment = optking.Frag(zs, geometry, masses) 20 | 21 | The optimization coordinates can be added manually. 22 | 23 | .. code-block:: python-console 24 | 25 | >>> intcos = [optking.Stre(1, 2), optking.Stre(2, 3), optking.Bend(1, 2, 3)] 26 | >>> fragment.intcos = intcos # intcos can also be added at instantiation 27 | 28 | More typically, the coordinate system is automatically generated once the full molecular system is built and then edited if nessecary. 29 | 30 | .. code-block:: python-console 31 | 32 | >>> molsys = optking.Molsys([fragment]) 33 | >>> optking.make_internal_coords(molsys) 34 | 35 | To control the automatic generation of coordinates the following keywords can be modified. For more information see the keyword 36 | documentation. 37 | 38 | # TODO keyword documentation needs work (mostly copying pasting?) 39 | 40 | .. automodapi:: optking.molsys 41 | .. automodapi:: optking.frag 42 | .. automodapi:: optking.dimerfrag 43 | -------------------------------------------------------------------------------- /docs/source/options.rst: -------------------------------------------------------------------------------- 1 | Keywords and Options 2 | ==================== 3 | 4 | .. automodapi:: optking.optparams 5 | -------------------------------------------------------------------------------- /media/optking.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/psi-rking/optking/2838f7d3fe3286e0aa5e3a16a1242d4dab16978b/media/optking.jpeg -------------------------------------------------------------------------------- /media/s8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/psi-rking/optking/2838f7d3fe3286e0aa5e3a16a1242d4dab16978b/media/s8.png -------------------------------------------------------------------------------- /optking/__init__.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import os 3 | import sys 4 | from logging.config import dictConfig 5 | from . import lj_functions, loggingconfig 6 | 7 | if "psi4" in sys.argv[0] or "psi4" in sys._getframe(1).f_globals.get("__name__") or "psi4" in sys.modules: 8 | 9 | opt_log = logging.getLogger("psi4.optking") 10 | log_name = "psi4." 11 | opt_log.propagate = True 12 | else: 13 | logger = logging.getLogger() 14 | dictConfig(loggingconfig.logging_configuration) 15 | logger = logging.getLogger(__name__) 16 | log_name = "" 17 | 18 | from . import optparams as op 19 | from ._version import get_versions 20 | from .opt_helper import EngineHelper, CustomHelper 21 | from .optimize import make_internal_coords, optimize 22 | from .optwrapper import optimize_psi4, optimize_qcengine 23 | from .stre import Stre 24 | from .bend import Bend 25 | from .tors import Tors 26 | from .frag import Frag 27 | from .molsys import Molsys 28 | from .history import History 29 | 30 | op.Params = op.OptParams({}) 31 | 32 | __version__ = get_versions()["version"] 33 | del get_versions 34 | _optking_provenance_stamp = { 35 | "creator": "optking", 36 | "routine": None, 37 | "version": __version__, 38 | } 39 | -------------------------------------------------------------------------------- /optking/cart.py: -------------------------------------------------------------------------------- 1 | import qcelemental as qcel 2 | 3 | from .exceptions import AlgError, OptError 4 | from .misc import string_math_fx 5 | from .simple import Simple 6 | 7 | 8 | class Cart(Simple): 9 | """Cartesian displacement coordinate on one atom 10 | 11 | Parameters 12 | ---------- 13 | a : int 14 | atom number (zero indexing) 15 | constraint : string 16 | set coordinate as 'free', 'frozen', etc. 17 | """ 18 | 19 | def __init__( 20 | self, 21 | a, 22 | xyz_in, 23 | constraint="free", 24 | range_min=None, 25 | range_max=None, 26 | ext_force=None, 27 | ): 28 | 29 | self.xyz = xyz_in # uses setter below 30 | atoms = (a,) 31 | Simple.__init__(self, atoms, constraint, range_min, range_max, ext_force) 32 | 33 | def __str__(self): 34 | if self.frozen: 35 | s = "*" 36 | elif self.ranged: 37 | s = "[" 38 | else: 39 | s = " " 40 | 41 | if self.has_ext_force: 42 | s += ">" 43 | 44 | if self._xyz == 0: 45 | s += "X" 46 | elif self._xyz == 1: 47 | s += "Y" 48 | elif self._xyz == 2: 49 | s += "Z" 50 | 51 | s += "(%d)" % (self.A + 1) 52 | if self.ranged: 53 | s += "[{:.3f},{:.3f}]".format(self.range_min * self.q_show_factor, self.range_max * self.q_show_factor) 54 | return s 55 | 56 | def __eq__(self, other): 57 | if self.atoms != other.atoms: 58 | return False 59 | elif not isinstance(other, Cart): 60 | return False 61 | elif self.xyz != other.xyz: 62 | return False 63 | else: 64 | return True 65 | 66 | @property 67 | def xyz(self): 68 | return self._xyz 69 | 70 | @xyz.setter 71 | def xyz(self, setval): 72 | if setval in [0, "x", "X"]: 73 | self._xyz = 0 74 | elif setval in [1, "y", "Y"]: 75 | self._xyz = 1 76 | elif setval in [2, "z", "Z"]: 77 | self._xyz = 2 78 | else: 79 | raise OptError("Cartesian coordinate must be set to 0-2 or X-Z") 80 | 81 | def q(self, geom): 82 | return geom[self.A, self._xyz] 83 | 84 | @property 85 | def q_show_factor(self): 86 | return qcel.constants.bohr2angstroms 87 | 88 | def q_show(self, geom): 89 | return self.q_show_factor * self.q(geom) 90 | 91 | @property 92 | def f_show_factor(self): 93 | return qcel.constants.hartree2aJ / qcel.constants.bohr2angstroms 94 | 95 | def to_dict(self): 96 | d = {} 97 | d["type"] = Cart.__name__ # 'Cart' 98 | d["atoms"] = self.atoms # id to a tuple 99 | d["xyz"] = self.xyz 100 | d["constraint"] = self.constraint 101 | d["range_min"] = self.range_min 102 | d["range_max"] = self.range_max 103 | if self.has_ext_force: 104 | d["ext_force_str"] = self.ext_force.formula_string 105 | else: 106 | d["ext_force_str"] = None 107 | return d 108 | 109 | @classmethod 110 | def from_dict(cls, d): 111 | a = d["atoms"][0] 112 | constraint = d.get("constraint", "free") 113 | range_min = d.get("range_min", None) 114 | range_max = d.get("range_max", None) 115 | xyz = d.get("xyz", None) 116 | fstr = d.get("ext_force_str", None) 117 | if fstr is None: 118 | ext_force = None 119 | else: 120 | ext_force = string_math_fx(fstr) 121 | return cls(a, xyz, constraint, range_min, range_max, ext_force) 122 | 123 | # Compute and return in-place array of first derivative (row of B matrix) 124 | def DqDx(self, geom, dqdx, mini=False): 125 | dqdx[3 * self.A + self._xyz] = 1.0 126 | return 127 | 128 | # Do nothing, derivative B matrix is zero. 129 | def Dq2Dx2(self, geom, dq2dx2): 130 | pass 131 | 132 | def diagonal_hessian_guess(self, geom, Z, connectivity, guess_type="Simple"): 133 | """Generates diagonal empirical Hessians in a.u. such as 134 | Schlegel, Theor. Chim. Acta, 66, 333 (1984) and 135 | Fischer and Almlof, J. Phys. Chem., 96, 9770 (1992). 136 | """ 137 | return 0.1 138 | -------------------------------------------------------------------------------- /optking/caseInsensitiveDict.py: -------------------------------------------------------------------------------- 1 | import copy 2 | from collections.abc import Mapping 3 | 4 | 5 | class CaseInsensitiveDict(Mapping): 6 | def __init__(self, d): 7 | self._d = d 8 | self._s = dict((k.lower(), k) for k in d) 9 | 10 | def __contains__(self, k): 11 | return k.lower() in self._s 12 | 13 | def __len__(self): 14 | return len(self._s) 15 | 16 | def __iter__(self): 17 | return iter(self._s) 18 | 19 | def __getitem__(self, k): 20 | return self._d[self._s[k.lower()]] 21 | 22 | def __setitem__(self, k, val): 23 | self._s[k.lower()] = k 24 | self._d[k] = val 25 | return 26 | 27 | def actual_key_case(self, k): 28 | return self._s.get(k.lower()) 29 | 30 | def copy(self): 31 | return copy.copy(self) 32 | -------------------------------------------------------------------------------- /optking/exceptions.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | from . import log_name 4 | 5 | optimize_log = logging.getLogger(f"{log_name}{__name__}") 6 | 7 | # We don't catch this one internallyclass OptFail(Exception): 8 | class OptError(Exception): 9 | def __init__(self, mesg="None given", err_type="Not specified"): 10 | # optimize_log.critical("Error message: %s", mesg) 11 | # optimize_log.critical("OptError: Optimization has failed.") 12 | self.mesg = mesg 13 | self.err_type = err_type 14 | # Exception.__init__(self, mesg) 15 | 16 | 17 | class AlgError(Exception): 18 | # maybe generalize later def __init__(self, *args, **kwargs): 19 | def __init__(self, mesg="None given", new_linear_bends=[], new_linear_torsion=[], oofp_failures=[]): 20 | optimize_log.error(f"AlgError: Exception created. Mesg: {mesg}") 21 | if new_linear_bends: 22 | optimize_log.error("AlgError: Linear bends detected.\n%s", '\n'.join(map(str, new_linear_bends))) 23 | if new_linear_torsion: 24 | optimize_log.error("AlgError: Linear Torsions Detected\n%s", '\n'.join(map(str, new_linear_torsion))) 25 | if oofp_failures: 26 | optimize_log.error("AlgError: Linear Oofps Detected\n%s", '\n'.join(map(str, oofp_failures))) 27 | self.linear_bends = new_linear_bends 28 | self.linear_torsions = new_linear_torsion 29 | self.oofp_failures = oofp_failures 30 | self.mesg = mesg 31 | -------------------------------------------------------------------------------- /optking/hessian.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import json 3 | 4 | import numpy as np 5 | import qcelemental as qcel 6 | 7 | from .bend import Bend 8 | from .printTools import print_mat_string 9 | from .stre import Stre 10 | from .tors import Tors 11 | from . import log_name 12 | 13 | logger = logging.getLogger(f"{log_name}{__name__}") 14 | 15 | 16 | def show(H: np.ndarray, oMolsys): 17 | """Print the Hessian in common spectroscopic units of [aJ/Ang^2], [aJ/deg^2] or [aJ/(Ang deg)]""" 18 | 19 | factors = np.zeros(oMolsys.num_intcos) 20 | cnt = -1 21 | for F in oMolsys._fragments: 22 | for I in F.intcos: 23 | cnt += 1 24 | factors[cnt] = I.q_show_factor 25 | for DI in oMolsys._dimer_intcos: 26 | for I in DI._pseudofrag._intcos: 27 | cnt += 1 28 | factors[cnt] = I.q_show_factor 29 | 30 | factors_inv = np.divide(1.0, factors) 31 | scaled_H = np.einsum("i,ij,j->ij", factors_inv, H, factors_inv) 32 | scaled_H *= qcel.constants.hartree2aJ 33 | logger.info("Hessian in [aJ/Ang^2], [aJ/deg^2], etc.\n" + print_mat_string(scaled_H)) 34 | 35 | 36 | # def guess(intcos, geom, Z, connectivity=None, guessType="SIMPLE"): 37 | def guess(oMolsys, connectivity=None, guessType="SIMPLE"): 38 | """Generates diagonal empirical Hessian in a.u. 39 | 40 | Parameters 41 | ---------- 42 | intcos : list of Stre, Bend, Tors 43 | geom : ndarray 44 | cartesian geometry 45 | connectivity : ndarray, optional 46 | connectivity matrix 47 | guessType: str, optional 48 | the default is SIMPLE. other options: FISCHER, LINDH_SIMPLE, SCHLEGEL 49 | 50 | Notes 51 | ----- 52 | such as 53 | Schlegel, Theor. Chim. Acta, 66, 333 (1984) and 54 | Fischer and Almlof, J. Phys. Chem., 96, 9770 (1992). 55 | """ 56 | 57 | diag = [] 58 | for F in oMolsys._fragments: 59 | if F.num_intcos: 60 | geom = F.geom 61 | Z = F.Z 62 | connectivity = F.connectivity_from_distances() 63 | for intco in F._intcos: 64 | diag.append(intco.diagonal_hessian_guess(geom, Z, connectivity, guessType)) 65 | 66 | # Since the reference points might not even be at atomic positions, let's not worry 67 | # about implementing various options for the diagonal Hessian guess. 68 | for DI in oMolsys._dimer_intcos: 69 | vals = DI.q() 70 | for i, intco in enumerate(DI._pseudo_frag._intcos): 71 | if isinstance(intco, Stre): 72 | h = 0.007 73 | if intco.inverse: 74 | h *= pow(1.0 / vals[i], 4) 75 | # i should be 0=stretch 76 | elif isinstance(intco, Bend): 77 | h = 0.003 78 | elif isinstance(intco, Tors): 79 | h = 0.001 80 | else: 81 | h = 0.111 82 | diag.append(h) 83 | 84 | H = np.diagflat(np.asarray(diag)) 85 | return H 86 | 87 | 88 | def from_file(filename): 89 | """Read user provided hessian from disk""" 90 | 91 | with open(filename) as f: 92 | if ".json" == filename[:-5]: 93 | result = json.load(f) 94 | hess = result["return_result"] 95 | ncart = 3 * len(result["molecule"]["symbols"]) 96 | else: 97 | # 2D split. Cast everything to floats and convert back to 2D list from map. 98 | lines = f.readlines() 99 | hess = [list(map(float, line.split())) for line in lines[1:]] 100 | ncart = int(lines[0].split()[1]) # assumes FCMFINAL / CFOUR format 101 | try: 102 | H = np.array(hess, dtype=float) 103 | H = H.reshape(ncart, ncart) 104 | except (IndexError, ValueError, TypeError) as error: 105 | logger.error("Hessian should be 3Nx3N cartesian force constant matrix or provided by MolSSI Schema") 106 | logger.error(error) 107 | raise ValueError("Could not load hessian from disk") from error 108 | else: 109 | return H 110 | -------------------------------------------------------------------------------- /optking/intcosMisc.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from math import sqrt 3 | 4 | import numpy as np 5 | 6 | from . import bend 7 | from . import tors 8 | from . import log_name 9 | 10 | # Some of these functions act on an arbitrary list of simple internals, 11 | # geometry etc. that may or may not be in a molecular system. 12 | 13 | logger = logging.getLogger(f"{log_name}{__name__}") 14 | 15 | 16 | def q_values(intcos, geom): 17 | # available for simple intco lists 18 | vals = [intco.q(geom) for intco in intcos] 19 | return np.asarray(vals) 20 | 21 | 22 | def Bmat(intcos, geom, masses=None): 23 | # Allocate memory for full system. 24 | # Returns mass-weighted Bmatrix if masses are supplied. 25 | # available for simple intco lists 26 | Nint = len(intcos) 27 | B = np.zeros((Nint, 3 * len(geom))) 28 | 29 | for i, intco in enumerate(intcos): 30 | intco.DqDx(geom, B[i]) 31 | 32 | if type(masses) is np.ndarray: 33 | sqrtm = np.array([np.repeat(np.sqrt(masses), 3)] * Nint, float) 34 | B[:] = np.divide(B, sqrtm) 35 | 36 | return B 37 | 38 | 39 | def tors_contains_bend(b, t): 40 | return b.atoms in [ 41 | t.atoms[0:3], 42 | t.atoms[3::-1], 43 | t.atoms[1:4], 44 | t.atoms[4:0:-1], 45 | ] 46 | 47 | 48 | def remove_old_now_linear_bend(atoms, intcos): 49 | """For given bend [A,B,C], remove any regular bends as well as any torsions 50 | which contain it 51 | """ 52 | b = bend.Bend(atoms[0], atoms[1], atoms[2]) 53 | logger.info("Removing Old Linear Bend") 54 | logger.info(str(b) + "\n") 55 | intcos[:] = [coord for coord in intcos if coord != b] 56 | intcos[:] = [coord for coord in intcos if not (isinstance(coord, tors.Tors) and tors_contains_bend(b, coord))] 57 | -------------------------------------------------------------------------------- /optking/linearAlgebra.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from math import sqrt 3 | 4 | import numpy as np 5 | from numpy.linalg import LinAlgError 6 | 7 | from .exceptions import OptError 8 | from . import log_name 9 | 10 | logger = logging.getLogger(f"{log_name}{__name__}") 11 | # Linear algebra routines. # 12 | 13 | 14 | def norm(V): 15 | return np.linalg.norm(V) 16 | 17 | 18 | def abs_max(V): 19 | return max(abs(elem) for elem in V) 20 | 21 | 22 | def abs_min(V): 23 | return min(abs(elem) for elem in V) 24 | 25 | 26 | def rms(V): 27 | return np.sqrt(np.mean(V**2)) 28 | 29 | 30 | def sign_of_double(d): 31 | if d > 0: 32 | return 1 33 | elif d < 0: 34 | return -1 35 | else: 36 | return 0 37 | 38 | 39 | # Returns eigenvectors as rows? 40 | def symm_mat_eig(mat): 41 | try: 42 | evals, evects = np.linalg.eigh(mat) 43 | if abs(min(evects[:, 0])) > abs(max(evects[:, 0])): 44 | evects[:, 0] *= -1.0 45 | except: 46 | raise OptError("symm_mat_eig: could not compute eigenvectors") 47 | # could be ALG_FAIL ? 48 | evects = evects.T 49 | return evals, evects 50 | 51 | 52 | def lowest_eigenvector_symm_mat(mat): 53 | """Returns eigenvector with lowest eigenvalues; makes the largest 54 | magnitude element positive. 55 | 56 | Parameters 57 | ---------- 58 | mat: np.ndarray 59 | 60 | Returns 61 | ------- 62 | np.ndarray 63 | eigenvector for lowest eigenvalue 64 | 65 | """ 66 | 67 | try: 68 | evals, evects = np.linalg.eigh(mat) 69 | if abs(min(evects[:, 0])) > abs(max(evects[:, 0])): 70 | evects[:, 0] *= -1.0 71 | except: 72 | raise OptError("symm_mat_eig: could not compute eigenvectors") 73 | return evects[:, 0] 74 | 75 | 76 | def asymm_mat_eig(mat): 77 | """Compute the eigenvalues and right eigenvectors of a square array. 78 | Wraps numpy.linalg.eig to sort eigenvalues, put eigenvectors in rows, and suppress complex. 79 | 80 | Parameters 81 | ---------- 82 | mat : ndarray 83 | (n, n) Square matrix to diagonalize. 84 | 85 | Returns 86 | ------- 87 | ndarray, ndarray 88 | (n, ), (n, n) sorted eigenvalues and normalized corresponding eigenvectors in rows. 89 | 90 | Raises 91 | ------ 92 | OptError 93 | When eigenvalue computation does not converge. 94 | 95 | """ 96 | try: 97 | evals, evects = np.linalg.eig(mat) 98 | except np.LinAlgError as e: 99 | raise OptError("asymm_mat_eig: could not compute eigenvectors") from e 100 | 101 | idx = np.argsort(evals) 102 | evals = evals[idx] 103 | evects = evects[:, idx] 104 | 105 | return evals.real, evects.real.T 106 | 107 | 108 | def symm_mat_inv(A, redundant=False, small_val_limit=1.0e-10): 109 | """ 110 | Return the inverse of a real, symmetric matrix. 111 | 112 | Parameters 113 | ---------- 114 | A : np.ndarray 115 | redundant : bool 116 | allow generalized inverse 117 | smallValLimit : float 118 | specifies how small of singular values to invert 119 | 120 | Returns 121 | ------- 122 | np.ndarray 123 | 124 | """ 125 | 126 | dim = A.shape[0] 127 | if dim == 0: 128 | return np.zeros((0, 0)) 129 | 130 | try: 131 | if redundant: 132 | 133 | if logger.isEnabledFor(logging.DEBUG): 134 | try: 135 | evals, evects = np.linalg.eigh(A) 136 | except LinAlgError: 137 | raise OptError("symm_mat_inv: could not compute eigenvectors") 138 | 139 | absEvals = np.abs(evals) 140 | threshold = small_val_limit * np.max(absEvals) 141 | logger.debug("Singular | values | > %8.3e will be inverted." % threshold) 142 | val = np.min(absEvals[absEvals > threshold]) 143 | logger.debug("Smallest inverted value is %8.3e." % val) 144 | 145 | return np.linalg.pinv(A, rcond=small_val_limit) 146 | 147 | else: 148 | return np.linalg.inv(A) 149 | 150 | except LinAlgError: 151 | raise OptError("symmMatrixInv: could not compute eigenvectors") 152 | # could be LinAlgError? 153 | 154 | 155 | def symm_mat_root(A, Inverse=None): 156 | """ 157 | Compute A^(1/2) for a positive-definite matrix 158 | 159 | Parameters 160 | ---------- 161 | A : np.ndarray 162 | Inverse : bool 163 | calculate A^(-1/2) 164 | 165 | Returns 166 | ------- 167 | np.ndarray 168 | 169 | """ 170 | try: 171 | evals, evects = np.linalg.eigh(A) 172 | # Eigenvectors of A are in columns of evects 173 | # Evals in ascending order 174 | except LinAlgError: 175 | raise OptError("symm_mat_root: could not compute eigenvectors") 176 | 177 | evals[np.abs(evals) < 10 * np.finfo(float).resolution] = 0.0 178 | evects[np.abs(evects) < 10 * np.finfo(float).resolution] = 0.0 179 | 180 | rootMatrix = np.zeros((len(evals), len(evals))) 181 | if Inverse: 182 | for i in range(0, len(evals)): 183 | evals[i] = 1 / evals[i] 184 | 185 | for i in range(0, len(evals)): 186 | rootMatrix[i][i] = sqrt(evals[i]) 187 | 188 | A = np.dot(evects, np.dot(rootMatrix, evects.T)) 189 | 190 | return A 191 | -------------------------------------------------------------------------------- /optking/lj_functions.py: -------------------------------------------------------------------------------- 1 | """ 2 | A simple set of functions to compute LJ energies and gradients. 3 | """ 4 | 5 | from itertools import combinations 6 | 7 | import numpy as np 8 | 9 | 10 | def calc_energy_and_gradient(positions, sigma, epsilon, do_gradient=True): 11 | r""" 12 | Computes the energy and gradient of a expression in the form 13 | V_{ij} = 4 \epsilon [ (sigma / r) ^ 12 - (sigma / r)^6] 14 | """ 15 | 16 | natom = positions.shape[0] 17 | # Holds the energy and the energy gradient 18 | E = 0.0 19 | 20 | gradient = np.zeros((natom, 3)) 21 | 22 | sigma6 = sigma**6 23 | sigma12 = sigma6**2 24 | 25 | # Double loop over all particles 26 | for i, j in combinations(range(natom), 2): 27 | v_ij = positions[j] - positions[i] 28 | r = np.linalg.norm(v_ij) 29 | v_ij[:] = v_ij / r 30 | r6 = np.power(r, 6) 31 | r12 = np.power(r6, 2) 32 | E += sigma12 / r12 - sigma6 / r6 33 | 34 | if do_gradient: 35 | dVdr = -12 * sigma12 / (r12 * r) + 6 * sigma6 / (r6 * r) 36 | for xyz in range(3): 37 | gradient[i, xyz] -= dVdr * v_ij[xyz] 38 | gradient[j, xyz] += dVdr * v_ij[xyz] 39 | 40 | E *= 4.0 * epsilon 41 | 42 | if do_gradient: 43 | gradient = 4.0 * epsilon * gradient.reshape(3 * natom) 44 | return E, gradient 45 | else: 46 | return E 47 | -------------------------------------------------------------------------------- /optking/loggingconfig.py: -------------------------------------------------------------------------------- 1 | import os 2 | import logging 3 | 4 | logging_configuration = { 5 | "version": 1, 6 | "disable_existing_loggers": False, 7 | "formatters": { 8 | "time_severity_message": { 9 | "format": "[{asctime}] - [{levelname}]: {message}", 10 | "style": "{", 11 | }, 12 | "severity_name_message": { 13 | "format": "[{levelname}] [{name}]: {message}", 14 | "style": "{", 15 | }, 16 | "severity_message": {"format": "[{levelname}]: {message}", "style": "{"}, 17 | "message_format": {"format": "{message}", "style": "{"}, 18 | }, 19 | "handlers": { 20 | "terminal_debug": { 21 | "class": "logging.StreamHandler", 22 | "formatter": "severity_message", 23 | "level": "DEBUG", 24 | }, 25 | "terminal_info": { 26 | "class": "logging.StreamHandler", 27 | "formatter": "severity_message", 28 | "level": "INFO", 29 | }, 30 | "file_log_debug": { 31 | "class": "logging.FileHandler", 32 | "mode": "w", 33 | "formatter": "severity_message", 34 | "level": "DEBUG", 35 | "filename": os.path.join(os.getcwd(), "opt_log.out"), 36 | }, 37 | "file_log_info": { 38 | "class": "logging.FileHandler", 39 | "mode": "w", 40 | "formatter": "severity_message", 41 | "level": "INFO", 42 | "filename": os.path.join(os.getcwd(), "opt_log.out"), 43 | }, 44 | "file_king_info": { 45 | "class": "logging.FileHandler", 46 | "formatter": "message_format", 47 | "mode": "w", 48 | "level": "INFO", 49 | "filename": os.path.join(os.getcwd(), "opt_log.out"), 50 | }, 51 | }, 52 | "loggers": {"optking": {"level": "INFO", "handlers": ["file_log_info"]}}, 53 | #"loggers": {"optking": {"level": "DEBUG", "handlers": ["file_log_debug"]}}, 54 | # "root": { 55 | # # "level": "INFO", 56 | # # "handlers": ["file_log_info"], 57 | # "level": "WARNING", 58 | # "handlers": [logging.handlers.] 59 | # }, 60 | } 61 | -------------------------------------------------------------------------------- /optking/orient.py: -------------------------------------------------------------------------------- 1 | from math import acos, cos, sin, sqrt 2 | 3 | import numpy as np 4 | 5 | from optking import v3d 6 | 7 | from .exceptions import AlgError 8 | 9 | """ Tools for analytic rotation and orientation """ 10 | 11 | 12 | def rotate_vector(rot_axis, phi, v): 13 | """rotate_vecs(): Rotate a set of vectors around an arbitrary axis 14 | 15 | Parameters 16 | ---------- 17 | rot_axis : numpy array float[3] 18 | axis to rotate around - gets normalized here 19 | phi : float 20 | magnitude of rotation in radians 21 | v : numpy array of floats 22 | n points to rotate ; overwritten on exit 23 | vectors are rows. 24 | 25 | Returns 26 | ------- 27 | None, but v is overwritten with new vectors 28 | """ 29 | # normalize rotation axis 30 | norm = sqrt(rot_axis[0] ** 2 + rot_axis[1] ** 2 + rot_axis[2] ** 2) 31 | rot_axis /= norm 32 | 33 | wx = rot_axis[0] 34 | wy = rot_axis[1] 35 | wz = rot_axis[2] 36 | cos_phi = cos(phi) 37 | sin_phi = sin(phi) 38 | cp = 1.0 - cos_phi 39 | 40 | R = np.ndarray((3, 3), float) 41 | R[0, 0] = cos_phi + wx * wx * cp 42 | R[0, 1] = -wz * sin_phi + wx * wy * cp 43 | R[0, 2] = wy * sin_phi + wx * wz * cp 44 | R[1, 0] = wz * sin_phi + wx * wy * cp 45 | R[1, 1] = cos_phi + wy * wy * cp 46 | R[1, 2] = -wx * sin_phi + wy * wz * cp 47 | R[2, 0] = -wy * sin_phi + wx * wz * cp 48 | R[2, 1] = wx * sin_phi + wy * wz * cp 49 | R[2, 2] = cos_phi + wz * wz * cp 50 | 51 | v_new = np.dot(R, v.T) # vectors came in as rows! 52 | v[:] = v_new.T 53 | return 54 | 55 | 56 | def zmat_point(A, B, C, R_CD, theta_BCD, phi_ABCD): 57 | """zmat_point(): Given the xyz coordinates for three points and 58 | R, theta, and phi, as traditionally understood in a Z-matrix, 59 | returns the location of a 4th point. 60 | 61 | Parameters 62 | ---------- 63 | A : numpy array float[3] 64 | Cartesian coordinates of atom A 65 | B : numpy array float[3] 66 | Cartesian coordinates of atom B 67 | C : numpy array float[3] 68 | Cartesian coordinates of atom C 69 | R_CD : float 70 | Distance between atoms C and d 71 | theta_BCD : 72 | Angle between atoms B, C and d 73 | phi_ABCD : 74 | Dihedral Angle between atoms A, B, C and d 75 | 76 | Returns 77 | ---------- 78 | d : numpy array float[3] 79 | Cartesian coordinates of atom d 80 | """ 81 | 82 | eAB = v3d.eAB(A, B) # vector A->B 83 | eBC = v3d.eAB(B, C) # vector B->C 84 | cosABC = -v3d.dot(eAB, eBC) 85 | 86 | sinABC = sqrt(1 - (cosABC * cosABC)) 87 | if (sinABC - 1.0e-14) < 0.0: 88 | raise AlgError("Z-matrix (reference) points cannot be colinear.") 89 | 90 | eY = v3d.cross(eAB, eBC) / sinABC 91 | eX = v3d.cross(eY, eBC) 92 | D = C + R_CD * (-eBC * cos(theta_BCD) + eX * sin(theta_BCD) * cos(phi_ABCD) + eY * sin(theta_BCD) * sin(phi_ABCD)) 93 | return D 94 | 95 | 96 | # axis = np.array( [0,0,1],float ) 97 | # v = np.array( [2,0,0],float ) 98 | # angle = acos(-1) 99 | # print('v:', v) 100 | # print('axis:',axis) 101 | # print('angle: %15.10f' % angle) 102 | # rotate_vector(axis, angle, v) 103 | # print('v:', v) 104 | -------------------------------------------------------------------------------- /optking/printTools.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | 3 | import logging 4 | from itertools import chain 5 | 6 | import numpy as np 7 | import qcelemental as qcel 8 | 9 | # from sys import stdout 10 | 11 | 12 | def print_mat_string(M, Ncol=7, title=None): 13 | """Formats a Matrix for Logging or Printing 14 | 15 | Parameters 16 | ---------- 17 | M : ndarray, list 18 | 19 | title : string, optional 20 | title to include 21 | 22 | Returns 23 | ------- 24 | string 25 | numpy array as string 26 | 27 | """ 28 | # if title != "\n": 29 | # title = title + "\n" 30 | # return np.array2string(M, max_line_width=100, precision=6, prefix=title, suffix="\n") 31 | s = "\t" 32 | if title != None: 33 | s += title + "\n\t" 34 | for row in range(M.shape[0]): 35 | tab = 0 36 | for col in range(M.shape[1]): 37 | tab += 1 38 | s += " %10.6f" % M[row, col] 39 | if tab == Ncol and col != (M.shape[1] - 1): 40 | s += "\n\t" 41 | tab = 0 42 | s += "\n\t" 43 | s = s[:-1] 44 | return s 45 | 46 | 47 | def print_array_string(M, Ncol=7, title=None, form=":10.6f"): 48 | """Formats Arrays for Logging or Printing 49 | 50 | Parameters 51 | ---------- 52 | M : ndarray, list 53 | 54 | title="\n" : string 55 | optional title to include 56 | 57 | Returns 58 | ------- 59 | string 60 | numpy array as string 61 | """ 62 | # M = np.asarray(M) 63 | # if title != "\n": 64 | # title = title + "\n" 65 | # return np.array2string(M, max_line_width=100, precision=6, prefix=title, suffix="\n") 66 | s = "\t" 67 | if title != None: 68 | s += title + "\n\t\t" 69 | tab = 0 70 | formstring = "{" + form + "}" 71 | for i, entry in enumerate(M): 72 | tab += 1 73 | s += formstring.format(entry) 74 | if tab == Ncol and i != (len(M) - 1): 75 | s += "\n\t\t" 76 | tab = 0 77 | s += "\n" 78 | return s 79 | 80 | 81 | def print_geom_grad(geom, grad): 82 | 83 | Natom = geom.shape[0] 84 | geometry = [f"{'Geometry (au)':>22}"] 85 | geometry += ["{:15.10f}{:15.10f}{:15.10f}".format(geom[i, 0], geom[i, 1], geom[i, 2]) for i in range(Natom)] 86 | 87 | gradient = [f"{' ':39}Gradient (au)\n"] 88 | gradient += [ 89 | "\t\t{:15.10f}{:15.10f}{:15.10f}\n".format(grad[3 * i + 0], grad[3 * i + 1], grad[3 * i + 2]) 90 | for i in range(Natom) 91 | ] 92 | 93 | return "".join(list(chain(*zip(geometry, gradient)))) 94 | 95 | 96 | def print_geom_string(symbols, geom, unit=None): 97 | if unit == "Angstrom" or unit == "Angstroms": 98 | geom_str = "\n\tCartesian Geometry (in Angstroms)\n" 99 | for i in range(geom.shape[0]): 100 | geom_str += "\t%5s%20.10f%20.10f%20.10f\n" % ( 101 | symbols[i], 102 | qcel.constants.bohr2angstroms * geom[i, 0], 103 | qcel.constants.bohr2angstroms * geom[i, 1], 104 | qcel.constants.bohr2angstroms * geom[i, 2], 105 | ) 106 | else: 107 | geom_str = "\n\tCartesian Geometry\n" 108 | for i in range(geom.shape[0]): 109 | geom_str += "\t%5s%20.10f%20.10f%20.10f\n" % ( 110 | symbols[i], 111 | geom[i, 0], 112 | geom[i, 1], 113 | geom[i, 2], 114 | ) 115 | return geom_str 116 | 117 | 118 | def welcome(): 119 | welcome_string = """ 120 | \t\t\t-----------------------------------------\n 121 | \t\t\t OPTKING 3.0: for geometry optimizations \n 122 | \t\t\t By R.A. King, Bethel University \n 123 | \t\t\t with contributions from \n 124 | \t\t\t A.V. Copan, J. Cayton, A. Heide \n 125 | \t\t\t-----------------------------------------\n 126 | """ 127 | return welcome_string 128 | -------------------------------------------------------------------------------- /optking/simple.py: -------------------------------------------------------------------------------- 1 | from abc import ABC, abstractmethod 2 | 3 | from .exceptions import AlgError, OptError 4 | 5 | supported_constraint_types = ("free", "frozen", "ranged") 6 | 7 | 8 | class Simple(ABC): 9 | def __init__(self, atoms, constraint, range_min, range_max, ext_force): 10 | # these lines use the property's and setters below 11 | self.atoms = atoms # atom indices for internal definition 12 | if constraint.lower() not in supported_constraint_types: 13 | raise OptError("status for simple intco unknown") 14 | self.constraint = constraint.lower() 15 | self._range_min = range_min 16 | self._range_max = range_max 17 | self._ext_force = ext_force 18 | 19 | @property 20 | def atoms(self): 21 | return self._atoms 22 | 23 | @atoms.setter 24 | def atoms(self, values): 25 | try: 26 | for v in values: 27 | if int(v) < 0: 28 | raise OptError("Atom identifier cannot be negative.") 29 | except TypeError: 30 | raise OptError("Atoms must be iterable list of whole numbers.") 31 | self._atoms = values 32 | 33 | @property 34 | def frozen(self): 35 | return self.constraint == "frozen" 36 | 37 | @property 38 | def ranged(self): 39 | return self.constraint == "ranged" 40 | 41 | def freeze(self): 42 | if self.constraint == "free": 43 | self.constraint = "frozen" 44 | # for now if 'ranged', don't change 45 | return 46 | 47 | def unfreeze(self): 48 | if self.constraint == "frozen": 49 | self.constraint = "free" 50 | # for now if 'ranged', don't change 51 | 52 | def set_range(self, range_min, range_max): 53 | self.constraint = "ranged" 54 | self._range_min = range_min 55 | self._range_max = range_max 56 | 57 | @property 58 | def range_min(self): 59 | return self._range_min 60 | 61 | @property 62 | def range_max(self): 63 | return self._range_max 64 | 65 | @property 66 | def has_ext_force(self): 67 | return bool(self._ext_force is not None) 68 | 69 | @property 70 | def ext_force(self): 71 | return self._ext_force 72 | 73 | # could add checking here later 74 | @ext_force.setter 75 | def ext_force(self, eqn): 76 | self._ext_force = eqn 77 | 78 | def ext_force_val(self, geom): 79 | val = self.q_show(geom) # angstroms or degrees 80 | return self._ext_force.evaluate(val) 81 | 82 | @property 83 | def A(self): 84 | try: 85 | return self.atoms[0] 86 | except: 87 | raise OptError("A() called but atoms[0] does not exist") 88 | 89 | @property 90 | def B(self): 91 | try: 92 | return self.atoms[1] 93 | except: 94 | raise OptError("B() called but atoms[1] does not exist") 95 | 96 | @property 97 | def C(self): 98 | try: 99 | return self.atoms[2] 100 | except: 101 | raise OptError("C() called but atoms[2] does not exist") 102 | 103 | @property 104 | def D(self): 105 | try: 106 | return self.atoms[3] 107 | except: 108 | raise OptError("d() called but atoms[3] does not exist") 109 | 110 | # ** constructor + 9 abstract methods are currently required 111 | # for full functionality ** 112 | @abstractmethod # Given geometry, return value in Bohr or radians 113 | def q(self, geom): 114 | pass 115 | 116 | @abstractmethod # Given geometry, return Value in Angstroms or degrees. 117 | def q_show(self, geom): 118 | pass 119 | 120 | @abstractmethod # Return the scalar needed to convert value in au to Ang or Deg 121 | def q_show_factor(self): 122 | pass 123 | 124 | @abstractmethod # Return the scalar needed to convert force in au to aJ/(Ang or Deg) 125 | def f_show_factor(self): 126 | pass 127 | 128 | @abstractmethod # print type/classname plus contents to export 129 | def to_dict(self): 130 | pass 131 | 132 | @abstractmethod # construct from dictionary 133 | def from_dict(self, d): 134 | pass 135 | 136 | # Modify provided DqDx array with first derivative of value wrt cartesians 137 | # i.e., provide rows of B matrix. 138 | # Num. of rows is len(self._atoms), or Num. of atoms in coordinate definition 139 | # By default, col dimension of dqdx is assumed to be 3*(Num. of atoms in fragment, 140 | # or the number of atoms consistent with the values of self._atoms). 141 | # If mini==True, then col dimension of dqdx is only 3*len(self._atoms). For a stretch 142 | # then, e.g, DqDx is 2x6. 143 | @abstractmethod 144 | def DqDx(self, geom, dqdx, mini=False): 145 | raise AlgError("no DqDx for this coordinate") 146 | 147 | # Modify provided Dq2Dx2 array with second derivative of value wrt cartesians 148 | # i.e., provide derivative B matrix for coordinate. 149 | # dimension of dq2dx2 is 3*len(self._atoms)x3*len(self._atoms), or 150 | # cartesian by cartesian - of minimum size. 151 | @abstractmethod # Derivative of value wrt cartesians, i.e., B-matrix elements. 152 | def Dq2Dx2(self, geom, dq2dx2): 153 | raise AlgError("no Dq2Dx2 for this coordinate") 154 | 155 | @abstractmethod # Diagonal hessian guess 156 | def diagonal_hessian_guess(geom, Z, connectivity, guess_type): 157 | raise AlgError("no hessian guess for this coordinate") 158 | -------------------------------------------------------------------------------- /optking/tests/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Init file for tests, blank to avoid automatic imports. 3 | """ 4 | -------------------------------------------------------------------------------- /optking/tests/ch3chch2cl.in: -------------------------------------------------------------------------------- 1 | # Problem case from CDS 2 | 3 | memory 1024 mb 4 | 5 | molecule mol { 6 | 1 1 7 | C 0.00000000 0.00000000 0.00000000 8 | Cl 0.19771002 -0.99671665 -1.43703398 9 | C 1.06037767 1.11678073 0.00000000 10 | C 2.55772698 0.75685710 0.00000000 11 | H 3.15117939 1.67114056 0.00000000 12 | H 2.79090687 0.17233980 0.88998127 13 | H 2.79090687 0.17233980 -0.88998127 14 | H 0.75109254 2.16198057 0.00000000 15 | H -0.99541786 0.44412079 0.00000000 16 | H 0.12244541 -0.61728474 0.88998127 17 | } 18 | 19 | set scf_type df 20 | set basis 6-31+G(d) 21 | set reference rhf 22 | mol.update_geometry() 23 | mol.symmetrize(1e-3) 24 | 25 | e, wfn = optimize('scf', return_wfn=True) 26 | oeprop(wfn, "MULLIKEN_CHARGES") 27 | mol.print_out() 28 | print_variables() 29 | 30 | -------------------------------------------------------------------------------- /optking/tests/conftest.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | 4 | def pytest_configure(config): 5 | # Register marks to avoid warnings in installed testing 6 | # sync with setup.cfg 7 | config.addinivalue_line("markers", "long") 8 | config.addinivalue_line("markers", "dimers") 9 | config.addinivalue_line("markers", "multimers") 10 | 11 | 12 | @pytest.fixture(scope="function", autouse=True) 13 | def set_up(): 14 | import optking 15 | 16 | optking.optparams.Params = optking.optparams.OptParams({}) 17 | 18 | 19 | def pytest_addoption(parser): 20 | parser.addoption( 21 | "--check_iter", 22 | action="store", 23 | default=0, 24 | help="1 -- raise error if # of steps taken doesn't match expected. 0 (default) -- ignore mismatch but warn user in log", 25 | ) 26 | 27 | 28 | @pytest.fixture 29 | def check_iter(request): 30 | return request.config.getoption("--check_iter") 31 | -------------------------------------------------------------------------------- /optking/tests/dimer_benzene_jupyter_demo.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import psi4\n", 10 | "import optking\n", 11 | "import qcelemental as qcel\n", 12 | "au2kcal = qcel.constants.hartree2kcalmol\n", 13 | "import numpy as np\n", 14 | "\n", 15 | "dimerMol = psi4.geometry(\"\"\"\n", 16 | " C -1.2025450 -0.6942916 0.0\n", 17 | " C -1.2025450 0.6942916 0.0\n", 18 | " C 0.0000000 -1.3886100 0.0\n", 19 | " C -0.0000000 1.3886100 0.0\n", 20 | " C 1.2025450 -0.6942916 0.0\n", 21 | " C 1.2025450 0.6942916 0.0\n", 22 | " H -2.1397760 -1.2353675 0.0\n", 23 | " H -2.1397760 1.2353675 0.0\n", 24 | " H 0.0000000 -2.4708011 0.0\n", 25 | " H -0.0000000 2.4708011 0.0\n", 26 | " H 2.1397760 -1.2353675 0.0\n", 27 | " H 2.1397760 1.2353675 0.0\n", 28 | " --\n", 29 | " C -1.2025450 -0.6942916 10.0\n", 30 | " C -1.2025450 0.6942916 10.0\n", 31 | " C 0.0000000 -1.3886100 10.0\n", 32 | " C -0.0000000 1.3886100 10.0\n", 33 | " C 1.2025450 -0.6942916 10.0\n", 34 | " C 1.2025450 0.6942916 10.0\n", 35 | " H -2.1397760 -1.2353675 10.0\n", 36 | " H -2.1397760 1.2353675 10.0\n", 37 | " H 0.0000000 -2.4708011 10.0\n", 38 | " H -0.0000000 2.4708011 10.0\n", 39 | " H 2.1397760 -1.2353675 10.0\n", 40 | " H 2.1397760 1.2353675 10.0\n", 41 | "\"\"\")" 42 | ] 43 | }, 44 | { 45 | "cell_type": "code", 46 | "execution_count": null, 47 | "metadata": {}, 48 | "outputs": [], 49 | "source": [ 50 | "Axyz = dimerMol.geometry().np[0:12,]\n", 51 | "Bxyz = dimerMol.geometry().np[12:,]\n", 52 | "\n", 53 | "# Define some reference atoms\n", 54 | "ArefAtoms = [ [0,1,2,3,4,5], # COM (between Carbon's)\n", 55 | " [2], # carbon on x-axis\n", 56 | " [1]] # another carbon\n", 57 | "BrefAtoms = [ [0,1,2,3,4,5], # COM (between Carbon's)\n", 58 | " [2], # carbon on x-axis\n", 59 | " [1]] # another carbon\n", 60 | "\n", 61 | "dimerCoord = optking.dimerfrag.DimerFrag(0, ArefAtoms, 1, BrefAtoms)\n", 62 | "\n", 63 | "# Here are the dimer coordinates defined, with their values in the\n", 64 | "# default of au or radians.:\n", 65 | "# name = value # description\n", 66 | "R = 6.0 # Distance A1 to B1 (in this case, between COM's)\n", 67 | "theta_A = np.pi/2 # Angle, A2-A1-B1\n", 68 | "theta_B = np.pi/2 # Angle, A1-B1-B2\n", 69 | "tau = 0.0 # Dihedral angle, A2-A1-B1-B2\n", 70 | "phi_A = np.pi/2 # Dihedral angle, A3-A2-A1-B1\n", 71 | "phi_B = -np.pi/2 # Dihedral angle, A1-B1-B2-B3\n", 72 | "# To see starting values:\n", 73 | "# dimerCoord.update_reference_geometry(Axyz, Bxyz)\n", 74 | "#q = dimerCoord.q_array()\n", 75 | "#print(q)\n", 76 | "\n", 77 | "# Choose a theory.\n", 78 | "psi4.core.clean_options()\n", 79 | "psi4_options = { 'basis':'sto-3g', 'd_convergence':'9' }\n", 80 | "psi4.set_options(psi4_options)\n", 81 | "\n", 82 | "# Vary tau, spinning one benzene ring above another parallel one at a distance of 6\n", 83 | "# Angstroms. Use degrees for fun.\n", 84 | "R = 3.0 \n", 85 | "theta_A = 90.0\n", 86 | "theta_B = 90.0\n", 87 | "phi_A = 90.0\n", 88 | "phi_B = -90.0\n", 89 | "\n", 90 | "E_tau = []\n", 91 | "geoms = []\n", 92 | "for tau in range(0,180,30):\n", 93 | " q_target = np.array([R, theta_A, theta_B, tau, phi_A, phi_B])\n", 94 | " Bxyz[:] = dimerCoord.orient_fragment(Axyz, Bxyz, q_target, unit_angle='deg', unit_length='Angstrom')\n", 95 | " xyz = psi4.core.Matrix.from_array( np.concatenate( (Axyz,Bxyz) ) )\n", 96 | " dimerMol.set_geometry( xyz )\n", 97 | " #dimerMol.update_geometry()\n", 98 | " E_tau.append( [tau, xyz.to_array(), psi4.energy('scf')] )\n", 99 | " \n", 100 | "E_tau = np.array(E_tau)\n", 101 | "Emin = min(E_tau[:,2])\n", 102 | "E_tau[:,2] = au2kcal*(E_tau[:,2] - Emin)\n", 103 | "\n", 104 | "import matplotlib.pyplot as plt\n", 105 | "x = E_tau[:,0]\n", 106 | "y = E_tau[:,2]\n", 107 | "fig = plt.figure()\n", 108 | "ax = fig.add_axes( [0.10,0.10,0.80,0.80] )\n", 109 | "ax.set_title('Benzene dimer')\n", 110 | "ax.set_xlabel('tau angle')\n", 111 | "ax.set_ylabel('Energy')\n", 112 | "ax.plot(x,y, 'g+-')\n", 113 | "plt.xlim(0,180)\n", 114 | "plt.show()\n", 115 | "\n", 116 | "# Lets see geometry at tau=60.0\n", 117 | "row = np.where(E_tau[:,0]==60.0)[0]\n", 118 | "dimerMol.set_geometry( psi4.core.Matrix.from_array(E_tau[row[0],1]) )\n", 119 | "qcelMol = qcel.models.Molecule(**dimerMol.to_schema(dtype=2))\n", 120 | "qcelMol.show()" 121 | ] 122 | }, 123 | { 124 | "cell_type": "code", 125 | "execution_count": null, 126 | "metadata": {}, 127 | "outputs": [], 128 | "source": [] 129 | } 130 | ], 131 | "metadata": { 132 | "kernelspec": { 133 | "display_name": "Python 3", 134 | "language": "python", 135 | "name": "python3" 136 | }, 137 | "language_info": { 138 | "codemirror_mode": { 139 | "name": "ipython", 140 | "version": 3 141 | }, 142 | "file_extension": ".py", 143 | "mimetype": "text/x-python", 144 | "name": "python", 145 | "nbconvert_exporter": "python", 146 | "pygments_lexer": "ipython3", 147 | "version": "3.7.5" 148 | } 149 | }, 150 | "nbformat": 4, 151 | "nbformat_minor": 4 152 | } 153 | -------------------------------------------------------------------------------- /optking/tests/json_betapinene.json: -------------------------------------------------------------------------------- 1 | { 2 | "schema_name": "qcschema_optimization_input", 3 | "schema_version": 1, 4 | "keywords": { 5 | "program": "psi4" 6 | }, 7 | "initial_molecule": { 8 | "geometry": [ 9 | 1.570733, 10 | -1.623467, 11 | -4.880418, 12 | 1.466284, 13 | -1.616729, 14 | -2.827198, 15 | 1.421269, 16 | 1.255828, 17 | 1.082211, 18 | -2.33399, 19 | -1.577555, 20 | 0.265482, 21 | -1.51017, 22 | 1.162298, 23 | 0.637200, 24 | -1.05096, 25 | -2.899489, 26 | -1.986679, 27 | 1.636940, 28 | 1.135992, 29 | -1.865913, 30 | -2.36670, 31 | -2.872735, 32 | -3.569843, 33 | 3.080220, 34 | -2.687655, 35 | -2.143045, 36 | -2.71718, 37 | 2.165516, 38 | 1.966455, 39 | -0.72171, 40 | -4.878211, 41 | -1.539549, 42 | 3.208824, 43 | 2.139504, 44 | -2.736660, 45 | -1.02444, 46 | 2.355555, 47 | -2.000223, 48 | -0.97038, 49 | 4.403126, 50 | -1.943530, 51 | -2.24904, 52 | 1.760297, 53 | -3.535001, 54 | -4.00031, 55 | -2.707375, 56 | 1.706060, 57 | -4.53858, 58 | -4.656572, 59 | 1.421038, 60 | -4.92484, 61 | -1.743122, 62 | 3.250121, 63 | 2.296896, 64 | 3.838233, 65 | 2.138840, 66 | 4.343961, 67 | 3.973550, 68 | 2.062462, 69 | 1.718395, 70 | 4.033472, 71 | 4.098434, 72 | 1.515345, 73 | 5.410438, 74 | 1.083602, 75 | 2.654332, 76 | -0.848272, 77 | 2.686102, 78 | 4.696013, 79 | -0.785032, 80 | 2.483374, 81 | 2.014302, 82 | -2.718905, 83 | 2.157681, 84 | 2.204852, 85 | -0.565852, 86 | 4.668446 87 | ], 88 | "symbols": [ 89 | "H", 90 | "C", 91 | "C", 92 | "C", 93 | "C", 94 | "C", 95 | "C", 96 | "H", 97 | "H", 98 | "H", 99 | "H", 100 | "H", 101 | "C", 102 | "H", 103 | "H", 104 | "C", 105 | "H", 106 | "H", 107 | "C", 108 | "H", 109 | "H", 110 | "H", 111 | "C", 112 | "H", 113 | "H", 114 | "H" 115 | ] 116 | }, 117 | "input_specification": { 118 | "schema_name": "qcschema_input", 119 | "schema_version": 1, 120 | "driver": "gradient", 121 | "model": { 122 | "method": "HF", 123 | "basis": "sto-3g" 124 | }, 125 | "keywords": {} 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /optking/tests/json_h2o.json: -------------------------------------------------------------------------------- 1 | { 2 | "schema_name": "qcschema_optimization_input", 3 | "schema_version": 1, 4 | "keywords": { 5 | "program": "psi4" 6 | }, 7 | "initial_molecule": { 8 | "geometry": [ 9 | 0.0, 10 | 0.0, 11 | 0.28100228, 12 | 0.0, 13 | 1.42674323, 14 | -0.8431958, 15 | 0.0, 16 | -1.42674323, 17 | -0.8431958 18 | ], 19 | "symbols": [ 20 | "O", 21 | "H", 22 | "H" 23 | ], 24 | "masses": [ 25 | 15.994915, 26 | 1.007825, 27 | 1.007825 28 | ] 29 | }, 30 | "input_specification": { 31 | "schema_name": "qcschema_input", 32 | "schema_version": 1, 33 | "driver": "gradient", 34 | "model": { 35 | "method": "hf", 36 | "basis": "sto-3g" 37 | }, 38 | "keywords": { 39 | "diis": false, 40 | "e_convergence": 10, 41 | "d_convergence": 10, 42 | "scf_type": "pk" 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /optking/tests/json_hooh_frozen.json: -------------------------------------------------------------------------------- 1 | { 2 | "schema_name": "qcschema_optimization_input", 3 | "schema_version": 1, 4 | "keywords": { 5 | "program": "psi4", 6 | "frozen_bend": "1 2 3 2 3 4", 7 | "g_convergence": "gau_verytight" 8 | }, 9 | "initial_molecule": { 10 | "geometry": [ 11 | 1.635264, 12 | 1.392752, 13 | 0.846589, 14 | 0.194579, 15 | 1.308419, 16 | -0.053343, 17 | -0.194579, 18 | -1.308419, 19 | -0.053343, 20 | -1.635264, 21 | -1.392752, 22 | 0.846589 23 | ], 24 | "symbols": [ 25 | "H", 26 | "O", 27 | "O", 28 | "H" 29 | ] 30 | }, 31 | "input_specification": { 32 | "schema_name": "qcschema_input", 33 | "schema_version": 1, 34 | "driver": "gradient", 35 | "model": { 36 | "method": "HF", 37 | "basis": "cc-pvdz" 38 | }, 39 | "keywords": { 40 | "diis": false, 41 | "scf_type": "pk" 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /optking/tests/json_lif_cp.json: -------------------------------------------------------------------------------- 1 | {"initial_molecule": {"fragment_charges": [1, -1], "fragments": [[0], [1]], "geometry": [0.0, 0.0, 0.0, 0.0, 0.0, 3.0], "symbols": ["Li", "F"]}, 2 | "input_specification": {"driver": "energy", 3 | "schema_name": "qcschema_manybodyspecification", 4 | "keywords": {"bsse_type": "cp", "supersystem_ie_only": true}, 5 | "protocols": {"component_results": "all"}, 6 | "specification": {"driver": "energy", 7 | "extras": {"psiapi": true}, 8 | "keywords": {}, 9 | "model": {"basis": "6-31g", "method": "hf"}, 10 | "program": "psi4", 11 | "protocols": {"stdout": false}}}, 12 | "keywords": {"g_convergence": "interfrag_tight", "program": "psi4"}, 13 | "protocols": {"trajectory": "final"}, 14 | "provenance": {"creator": "optking", "routine": "optimize_qcengine", "version": "0.2.1+14.gdc8fd03.dirty"}, 15 | "schema_name": "qcschema_generalizedoptimizationinput", 16 | "schema_version": 1} 17 | 18 | -------------------------------------------------------------------------------- /optking/tests/json_lif_nocp.json: -------------------------------------------------------------------------------- 1 | {"initial_molecule": {"fragment_charges": [1, -1], "fragments": [[0], [1]], "geometry": [0.0, 0.0, 0.0, 0.0, 0.0, 3.0], "symbols": ["Li", "F"]}, 2 | "input_specification": {"driver": "energy", 3 | "keywords": {"bsse_type": "nocp", "supersystem_ie_only": true}, 4 | "protocols": {"component_results": "all"}, 5 | "schema_name": "qcschema_manybodyspecification", 6 | "specification": {"driver": "energy", 7 | "extras": {"psiapi": true}, 8 | "keywords": {}, 9 | "model": {"basis": "6-31g", "method": "hf"}, 10 | "program": "psi4", 11 | "protocols": {"stdout": false}}}, 12 | "keywords": {"g_convergence": "gau_verytight", "program": "psi4"}, 13 | "protocols": {"trajectory": "final"}, 14 | "provenance": {"creator": "optking", "routine": "optimize_qcengine", "version": "0.2.1+14.gdc8fd03.dirty"}, 15 | "schema_name": "qcschema_generalizedoptimizationinput", 16 | "schema_version": 1} 17 | 18 | -------------------------------------------------------------------------------- /optking/tests/psi4_helper.py: -------------------------------------------------------------------------------- 1 | """ 2 | A simple OptKing wrapper for the Psi4 quantum chemistry program 3 | """ 4 | 5 | import numpy 6 | import pytest 7 | from qcelemental.util import which_import 8 | 9 | # Try to pull in Psi4 10 | try: 11 | import psi4 12 | 13 | found_psi4 = True 14 | except ImportError: 15 | found_psi4 = False 16 | 17 | # Wrap Psi4 in ifden 18 | using_psi4 = pytest.mark.skipif(found_psi4, reason="Psi4 not found, skipping.") 19 | using_qcmanybody = pytest.mark.skipif( 20 | which_import("qcmanybody", return_bool=True) is False, 21 | reason="cound not find qcmanybody. please install the package to enable tests", 22 | ) 23 | -------------------------------------------------------------------------------- /optking/tests/psi4inputs/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /optking/tests/psi4inputs/psiAPIversions/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /optking/tests/psi4inputs/psiAPIversions/dimer-h2o-c6h6.py: -------------------------------------------------------------------------------- 1 | import psi4 2 | import optking 3 | 4 | refenergy = -303.25404554 5 | 6 | dimer = psi4.geometry( 7 | """ 8 | 0 1 9 | O -0.5026452583 -0.9681078610 -0.4772692868 10 | H -2.3292990446 -1.1611084524 -0.4772692868 11 | H -0.8887241813 0.8340933116 -0.4772692868 12 | -- 13 | 0 1 14 | C 0.8853463281 -5.2235996493 0.5504918473 15 | C 1.8139169342 -2.1992967152 3.8040686146 16 | C 2.8624456357 -4.1143863257 0.5409035710 17 | C -0.6240195463 -4.8153482424 2.1904642137 18 | C -0.1646305764 -3.3031992532 3.8141619690 19 | C 3.3271056135 -2.6064153737 2.1669340785 20 | H 0.5244823836 -6.4459192939 -0.7478283184 21 | H 4.0823309159 -4.4449979205 -0.7680411190 22 | H -2.2074914566 -5.7109913627 2.2110247636 23 | H -1.3768100495 -2.9846751653 5.1327625515 24 | H 4.9209603634 -1.7288723155 2.1638694922 25 | H 2.1923374156 -0.9964630692 5.1155773223 26 | nocom 27 | units au 28 | """ 29 | ) 30 | 31 | psi4_options = { 32 | "basis": "sto-3g", 33 | "frag_mode": "MULTI", 34 | "frag_ref_atoms": [ 35 | [[1], [2], [3]], # reference atoms are O, H, H for h2o,frag1 36 | [[1, 2, 3, 4, 5, 6], [2], [6]], # reference atoms are center of ring, C, C frag2 37 | ], 38 | } 39 | psi4.set_options(psi4_options) 40 | 41 | json_output = optking.optimize_psi4("mp2") 42 | 43 | print("Number of iterations: %5d" % len(json_output["energies"])) 44 | print("Start energy: %15.10f" % json_output["energies"][0]) 45 | print("Final energy: %15.10f" % json_output["energies"][-1]) 46 | 47 | assert psi4.compare_values(refenergy, json_output["energies"][-1], 6, "Reference energy") 48 | -------------------------------------------------------------------------------- /optking/tests/psi4inputs/psiAPIversions/dimer-h2o.py: -------------------------------------------------------------------------------- 1 | #! water dimer 2 | import psi4 3 | import optking 4 | 5 | refenergy = -149.9414053335 6 | 7 | dimer = psi4.geometry( 8 | """ 9 | 0 1 10 | H 0.53297836 -1.10088263 -2.17523351 11 | O 0.67046349 -1.17150926 -0.32413149 12 | H -0.87285505 -0.32827188 0.18313336 13 | -- 14 | 0 1 15 | H -0.75224517 -2.04662631 -6.55895403 16 | O -0.20225739 -0.70744543 -5.42642983 17 | H 0.62391765 0.47566674 -6.56493124 18 | nocom 19 | units au 20 | """ 21 | ) 22 | 23 | psi4_options = { 24 | "basis": "sto-3g", 25 | "geom_maxiter": 30, 26 | "frag_mode": "MULTI", 27 | "frag_ref_atoms": [ 28 | [[2], [1], [3]], # atoms for reference pts. on frag1 29 | [[2], [1], [3]], # atoms for reference pts. on frag 2 30 | ], 31 | } 32 | 33 | psi4.set_options(psi4_options) 34 | json_output = optking.optimize_psi4("hf") 35 | 36 | print("Number of iterations: %5d" % len(json_output["energies"])) 37 | print("Start energy: %15.10f" % json_output["energies"][0]) 38 | print("Final energy: %15.10f" % json_output["energies"][-1]) 39 | 40 | assert psi4.compare_values(refenergy, json_output["energies"][-1], 6, "Reference energy") 41 | -------------------------------------------------------------------------------- /optking/tests/psi4inputs/psiAPIversions/dimer-ne2.py: -------------------------------------------------------------------------------- 1 | #! neon dimer; test interfragment coordinates for minimal system 2 | import psi4 3 | import optking 4 | 5 | refenergy = -253.209145 6 | 7 | dimer = psi4.geometry( 8 | """ 9 | 0 1 10 | Ne 0.0 0.0 0.0 11 | -- 12 | 0 1 13 | Ne 1.5 0.0 0.0 14 | nocom 15 | units au 16 | """ 17 | ) 18 | 19 | psi4_options = { 20 | "basis": "sto-3g", 21 | "geom_maxiter": 30, 22 | "frag_mode": "MULTI", 23 | "frag_ref_atoms": [[[1]], [[1]]], # atoms for reference pts. on frag1 # atoms for reference pts. on frag 2 24 | "g_convergence": "gau_tight", 25 | } 26 | psi4.set_options(psi4_options) 27 | 28 | json_output = optking.optimize_psi4("hf") 29 | 30 | print("\nNumber of iterations: %5d" % len(json_output["energies"])) 31 | print("Start energy: %15.10f" % json_output["energies"][0]) 32 | print("Final energy: %15.10f" % json_output["energies"][-1]) 33 | 34 | assert psi4.compare_values(refenergy, json_output["energies"][-1], 6, "Reference energy") 35 | -------------------------------------------------------------------------------- /optking/tests/psi4inputs/psiAPIversions/froz-dimer-h2o.py: -------------------------------------------------------------------------------- 1 | #! water dimer 2 | import psi4 3 | import optking 4 | 5 | refenergy = -149.9414053335 6 | 7 | dimer = psi4.geometry( 8 | """ 9 | 0 1 10 | H 0.53297836 -1.10088263 -2.17523351 11 | O 0.67046349 -1.17150926 -0.32413149 12 | H -0.87285505 -0.32827188 0.18313336 13 | -- 14 | 0 1 15 | H -0.75224517 -2.04662631 -6.55895403 16 | O -0.20225739 -0.70744543 -5.42642983 17 | H 0.62391765 0.47566674 -6.56493124 18 | nocom 19 | units au 20 | """ 21 | ) 22 | 23 | psi4_options = { 24 | "basis": "sto-3g", 25 | "geom_maxiter": 40, 26 | "frag_mode": "MULTI", 27 | "frag_ref_atoms": [ 28 | [[2], [1], [3]], # atoms for reference pts. on frag1 29 | [[2], [1], [3]], # atoms for reference pts. on frag 2 30 | ], 31 | "freeze_intrafrag": True, 32 | "intrafrag_step_limit": 0.2, 33 | "intrafrag_step_limit_max": 0.3, 34 | } 35 | 36 | psi4.set_options(psi4_options) 37 | json_output = optking.optimize_psi4("hf") 38 | 39 | print("Number of iterations: %5d" % len(json_output["energies"])) 40 | print("Start energy: %15.10f" % json_output["energies"][0]) 41 | print("Final energy: %15.10f" % json_output["energies"][-1]) 42 | 43 | assert psi4.compare_values(refenergy, json_output["energies"][-1], 6, "Reference energy") 44 | -------------------------------------------------------------------------------- /optking/tests/psi4inputs/psithon_versions/b3lyp-g-phenylacetylene.in: -------------------------------------------------------------------------------- 1 | #! B3LYP cc-pVDZ geometry optimzation of phenylacetylene, starting from 2 | #! not quite linear structure 3 | import optking 4 | b3lyp_E = 308.413691796 # from tight run 5 | 6 | molecule { 7 | 0 1 8 | C 0.50424 2.62143 -1.86897 9 | C -0.79405 2.10443 -1.80601 10 | C -1.78491 2.59819 -2.66154 11 | C -1.47738 3.60745 -3.57782 12 | C -0.17996 4.12418 -3.64086 13 | C 0.81143 3.63137 -2.78697 14 | H 1.27012 2.23852 -1.20693 15 | H -2.24344 3.98980 -4.23978 16 | H 0.05756 4.90505 -4.35040 17 | H -1.03189 1.32372 -1.09717 18 | H -2.78881 2.19838 -2.61341 19 | C 2.14399 4.16411 -2.85667 20 | C 3.26501 4.60083 -2.90366 21 | H 4.24594 4.99166 -2.95361 22 | } 23 | 24 | set { 25 | guess sad 26 | basis cc-pVDZ 27 | } 28 | 29 | result = optking.optimize_psi4('B3LYP') 30 | thisenergy = result['energies'][-1] 31 | compare_values(b3lyp_E, thisenergy, 6, "B3LYP energy") 32 | -------------------------------------------------------------------------------- /optking/tests/psi4inputs/psithon_versions/ccsd-g-ch2.in: -------------------------------------------------------------------------------- 1 | #! ROHF-CCSD/cc-pVDZ $^{3}B@@1$ CH2 geometry optimization via analytic gradients 2 | import optking 3 | 4 | molecule ch2 { 5 | 0 3 6 | C 7 | H 1 1.1 8 | H 1 1.1 2 109.0 9 | } 10 | 11 | set { 12 | reference rohf 13 | basis cc-pvdz 14 | max_disp_g_convergence 1e-6 15 | max_force_g_convergence 1.0e-6 16 | max_energy_g_convergence 7 17 | e_convergence 10 18 | r_convergence 10 19 | } 20 | 21 | result = optking.optimize_psi4('CCSD') 22 | 23 | this_scf = result['trajectory'][-1]['properties']['scf_total_energy'] 24 | this_ccsd = result['trajectory'][-1]['properties']['ccsd_correlation_energy'] 25 | this_total = result['trajectory'][-1]['properties']['return_energy'] 26 | 27 | REF_scf = -38.921394733562281 28 | REF_cor = -0.120484098351036 29 | REF_tot = -39.041878831913316 30 | 31 | compare_values(REF_scf, this_scf, 6, "SCF energy") 32 | compare_values(REF_cor, this_ccsd, 6, "CCSD contribution") 33 | compare_values(REF_tot, this_total, 6, "Total energy") 34 | -------------------------------------------------------------------------------- /optking/tests/psi4inputs/psithon_versions/ccsd-g-h2o.in: -------------------------------------------------------------------------------- 1 | #! RHF-CCSD 6-31G** all-electron optimization of the H2O molecule 2 | import optking 3 | 4 | molecule h2o { 5 | O 6 | H 1 0.97 7 | H 1 0.97 2 103.0 8 | } 9 | 10 | set { 11 | basis 6-31G** 12 | } 13 | 14 | result = optking.optimize_psi4('ccsd') 15 | 16 | this_scf = result['trajectory'][-1]['properties']['scf_total_energy'] 17 | this_ccsd = result['trajectory'][-1]['properties']['ccsd_correlation_energy'] 18 | this_total = result['trajectory'][-1]['properties']['return_energy'] 19 | 20 | REF_scf = -76.0229427274435 #TEST 21 | REF_ccsd = -0.20823570806196 #TEST 22 | REF_total = -76.2311784355056 #TEST 23 | 24 | compare_values(REF_scf, this_scf, 5, "SCF energy") #TEST 25 | compare_values(REF_ccsd, this_ccsd, 5, "CCSD contribution") #TEST 26 | compare_values(REF_total, this_total, 5, "Total energy") #TEST 27 | -------------------------------------------------------------------------------- /optking/tests/psi4inputs/psithon_versions/dcft-g-o2.in: -------------------------------------------------------------------------------- 1 | #! DC-06 calculation for the O2 molecule (triplet ground state). This performs 2 | #! geometry optimization using two-step and simultaneous solution of the 3 | #! response equations for the analytic gradient. 4 | import optking 5 | 6 | REF_uhf = -149.65205193206810 7 | REF_mp2 = -150.01099865665492 8 | REF_dctscf = -149.24779428002528 9 | REF_dct = -150.02279378629558 10 | 150.022793786307 11 | 12 | molecule O2 { 13 | 0 3 14 | O 15 | O 1 R 16 | R = 1.230 17 | } 18 | 19 | set { 20 | r_convergence 10 21 | algorithm twostep 22 | response_algorithm twostep 23 | basis dzp 24 | max_disp_g_convergence 1e-6 25 | rms_force_g_convergence 1e-6 26 | max_energy_g_convergence 1e-6 27 | reference uhf 28 | } 29 | 30 | set dct_functional dc-06 31 | result = optking.optimize_psi4('dct') 32 | 33 | this_uhf = result['trajectory'][-1]['properties']['scf_total_energy'] 34 | this_mp2 = result['trajectory'][-1]['properties']['mp2_total_energy'] 35 | this_dct = result['energies'][-1] 36 | 37 | compare_values(REF_uhf, this_uhf, 6, "UHF Energy"); 38 | compare_values(REF_mp2, this_mp2, 6, "MP2 Energy"); 39 | compare_values(REF_dct, this_dct, 6, "DC-06 Energy (two-step response)"); 40 | #compare_values(REF_dctscf, variable("DCT SCF ENERGY"), 6, "DC-06 SCF Energy (two-step response)"); 41 | 42 | set response_algorithm simultaneous 43 | O2.R = 1.232 44 | 45 | result = optking.optimize_psi4('dct') 46 | 47 | this_uhf = result['trajectory'][-1]['properties']['scf_total_energy'] 48 | this_mp2 = result['trajectory'][-1]['properties']['mp2_total_energy'] 49 | this_dct = result['energies'][-1] 50 | 51 | compare_values(REF_uhf, this_uhf, 6, "UHF Energy"); 52 | compare_values(REF_mp2, this_mp2, 6, "MP2 Energy"); 53 | compare_values(REF_dct, this_dct, 6, "DC-06 Energy (simultaneous response)"); 54 | #compare_values(REF_dctscf, variable("DCT SCF ENERGY"), 6, "DC-06 SCF Energy (simultaneous response)"); 55 | 56 | -------------------------------------------------------------------------------- /optking/tests/psi4inputs/psithon_versions/hf-e-h2o.in: -------------------------------------------------------------------------------- 1 | #! SCF STO-3G geometry optimzation, with Z-matrix input, by finite-differences 2 | import optking 3 | 4 | REF_energy = -74.965901192 5 | 6 | molecule h2o { 7 | O 8 | H 1 1.0 9 | H 1 1.0 2 104.5 10 | } 11 | 12 | set { 13 | diis false 14 | basis sto-3g 15 | e_convergence 10 16 | d_convergence 10 17 | points 3 18 | scf_type pk 19 | } 20 | 21 | # This test requires a change to ~/psi4/psi4/driver/schema_wrapper.py 22 | # to detect "dertype" as a keyword and allow it to be an integer. 23 | result = optking.optimize_psi4('scf', dertype=0) 24 | this_energy = result['energies'][-1] 25 | print( result['trajectory'][-1]['stdout'] ) 26 | 27 | compare_values(REF_energy, this_energy, 6, "Reference energy") 28 | 29 | -------------------------------------------------------------------------------- /optking/tests/psi4inputs/psithon_versions/hf-g-SF4-breaksLinear.in: -------------------------------------------------------------------------------- 1 | #! 6-31G(d) optimization of SF4 starting from linear bond angle 2 | #! that is not linear in the optimized structure but is in a 3 | #! symmetry plane of the molecule. 4 | # Difficult case. It runs fine for ~7 steps but won't converge 5 | # until we get a symmetrization of our steps to keep C2v. 6 | import optking 7 | SCF_E = -795.1433964231258 8 | 9 | molecule { 10 | 0 1 11 | S 0.00000000 0.00000000 0.00000000 12 | F 0.03923814 -1.73955752 0.00000000 13 | F -1.73955752 -0.03923814 0.00000000 14 | F 1.73955752 0.03923814 0.00000000 15 | F -0.01961907 0.86977876 -1.50688420 16 | } 17 | 18 | set { 19 | scf_type pk 20 | basis 6-31G(d) 21 | reference rhf 22 | geom_maxiter 15 23 | } 24 | 25 | set optking intrafrag_step_limit_max 0.3 26 | 27 | result = optking.optimize_psi4('SCF') 28 | thisenergy = result['energies'][-1] 29 | print( result['trajectory'][-1]['stdout'] ) 30 | 31 | compare_values(SCF_E, thisenergy, 5, "6-31G(D) SCF optimization of SF4") 32 | 33 | -------------------------------------------------------------------------------- /optking/tests/psi4inputs/psithon_versions/hf-g-alleneLinear.in: -------------------------------------------------------------------------------- 1 | #! SCF DZ allene geometry optimization, with Cartesian input, first in c2v symmetry, 2 | #! then in Cs symmetry from a starting point with a non-linear central bond angle. 3 | import optking 4 | 5 | REF_energy = -115.8302823663 6 | 7 | # starting point is D2d/c2v 8 | molecule allene { 9 | H 0.0 -0.92 -1.8 10 | H 0.0 0.92 -1.8 11 | C 0.0 0.00 -1.3 12 | C 0.0 0.00 0.0 13 | C 0.0 0.00 1.3 14 | H 0.92 0.00 1.8 15 | H -0.92 0.00 1.8 16 | } 17 | 18 | set { 19 | basis DZ 20 | e_convergence 10 21 | d_convergence 10 22 | scf_type pk 23 | } 24 | 25 | result = optking.optimize_psi4('scf') 26 | thisenergy = result['energies'][-1] 27 | compare_values(REF_energy, thisenergy, 6, "Reference energy") 28 | 29 | -------------------------------------------------------------------------------- /optking/tests/psi4inputs/psithon_versions/hf-g-alleneNonlinear.in: -------------------------------------------------------------------------------- 1 | #! SCF DZ allene geometry optimization in Cs symmetry from a non-linear starting point. 2 | import optking 3 | 4 | REF_energy = -115.8302823663 5 | 6 | # central C-C-C bond angle starts around 170 degrees to test the dynamic addition 7 | # of new linear bending coordinates, and the redefinition of dihedrals. 8 | molecule allene { 9 | H 0.0 -0.92 -1.8 10 | H 0.0 0.92 -1.8 11 | C 0.0 0.00 -1.3 12 | C 0.0 0.10 0.0 13 | C 0.0 0.00 1.3 14 | H 0.92 0.00 1.8 15 | H -0.92 0.00 1.8 16 | } 17 | 18 | set { 19 | basis DZ 20 | e_convergence 10 21 | d_convergence 10 22 | scf_type pk 23 | } 24 | 25 | result = optking.optimize_psi4('scf') 26 | thisenergy = result['energies'][-1] 27 | 28 | compare_values(REF_energy, thisenergy, 6, "Reference energy") 29 | 30 | -------------------------------------------------------------------------------- /optking/tests/psi4inputs/psithon_versions/hf-g-h2o-freq.in: -------------------------------------------------------------------------------- 1 | #! Optimization followed by frequencies H2O HF/cc-pVDZ 2 | import optking 3 | 4 | molecule h2o { 5 | O 6 | H 1 0.96 7 | H 1 0.96 2 104.5 8 | } 9 | 10 | set basis cc-pVDZ 11 | result = optking.optimize_psi4('scf') 12 | 13 | nextStepSchema = result['final_molecule'] 14 | nextStepMolecule = Molecule.from_schema( nextStepSchema ) 15 | set_active_molecule( nextStepMolecule ) 16 | 17 | scf_e, scf_wfn = frequencies('scf', return_wfn=True, dertype=1) 18 | fd_freqs = scf_wfn.frequencies() 19 | 20 | ref_freqs = psi4.Vector(3) 21 | ref_freqs.set(0, 0, 1776.15) 22 | ref_freqs.set(0, 1, 4113.69) 23 | ref_freqs.set(0, 2, 4212.12) 24 | 25 | #ref_freqs.set(0, 0, 1775.65) These were not correct for closer/tight to minimum. 26 | #ref_freqs.set(0, 1, 4113.38) The values above came from C++ optimizer with tight convergence. 27 | #ref_freqs.set(0, 2, 4212.18) 28 | 29 | compare_vectors(ref_freqs, fd_freqs, 1, "Reference vs computed frequencies to 0.1 cm^-1") 30 | 31 | -------------------------------------------------------------------------------- /optking/tests/psi4inputs/psithon_versions/hf-g-h2o-frozenCart.in: -------------------------------------------------------------------------------- 1 | #! SCF/cc-pVDZ optimization example with frozen cartesian 2 | import optking 3 | 4 | molecule h2o { 5 | 0 1 6 | O 1.000000 1.000000 1.000000 7 | H 2.000000 1.000000 1.000000 8 | H 1.000000 2.000000 1.000000 9 | units angstrom 10 | no_com 11 | no_reorient 12 | } 13 | 14 | set { 15 | reference rhf 16 | basis cc-pVDZ 17 | e_convergence 11 18 | guess sad 19 | scf_type df 20 | } 21 | 22 | freeze_list = ''' 23 | 1 xyz''' 24 | 25 | set optking { 26 | frozen_cartesian $freeze_list 27 | } 28 | 29 | result = optking.optimize_psi4('scf') 30 | opt_energy = result['energies'][-1] 31 | 32 | compare_values(opt_energy, -76.0270327834836, 6, "SCF Optimized energy") 33 | 34 | compare_values( h2o.x(0), 1.88972613289, 6, "X Frozen coordinate") 35 | compare_values( h2o.y(0), 1.88972613289, 6, "Y Frozen coordinate") 36 | compare_values( h2o.z(0), 1.88972613289, 6, "Z Frozen coordinate") 37 | 38 | -------------------------------------------------------------------------------- /optking/tests/psi4inputs/psithon_versions/hf-g-h2o-large.in: -------------------------------------------------------------------------------- 1 | #! SCF cc-pVTZ geometry optimzation, with Z-matrix input 2 | import optking 3 | 4 | REF_energy = -76.057769702 5 | 6 | molecule h2o { 7 | O 8 | H 1 1.0 9 | H 1 1.0 2 104.5 10 | } 11 | 12 | set { 13 | basis cc-pvtz 14 | e_convergence 10 15 | d_convergence 10 16 | scf_type pk 17 | } 18 | 19 | result = optking.optimize_psi4('scf') 20 | thisenergy = result['energies'][-1] 21 | 22 | compare_values(REF_energy, thisenergy, 6, "Reference energy") 23 | -------------------------------------------------------------------------------- /optking/tests/psi4inputs/psithon_versions/hf-g-h2o-test-maxiter.in: -------------------------------------------------------------------------------- 1 | #! Geometry optimization that fails to converge within geom_maxiter steps. The next-step geometry 2 | #! is placed in final_molecule, and its energy is tested. 3 | import optking 4 | 5 | molecule h2o { 6 | O 7 | H 1 1.0 8 | H 1 1.0 2 104.5 9 | } 10 | 11 | set { 12 | basis cc-pvdz 13 | e_convergence 10 14 | d_convergence 10 15 | scf_type pk 16 | g_convergence gau_verytight 17 | geom_maxiter 2 18 | } 19 | 20 | result = optking.optimize_psi4('scf') 21 | compare_integers(0, int(result['success']), 'optking() hit maxiter gracefully') 22 | 23 | nextStepSchema = result['final_molecule'] 24 | nextStepMolecule = Molecule.from_schema( nextStepSchema ) 25 | set_active_molecule( nextStepMolecule ) 26 | nextStepEnergy = energy('scf') 27 | 28 | compare_values(-76.0270534, nextStepEnergy, 6, 'Energy of next-step/final molecule') 29 | 30 | # 1 -76.021418445931 -76.021418445931 0.05227592 0.04279207 0.10706998 0.08921782 ~ 31 | # 2 -76.026924207554 -0.005505761623 0.00639940 0.00521067 0.03551610 0.02119399 ~ 32 | # 3 -76.027052076499 -0.000127868945 0.00069761 0.00065158 0.00274272 0.00186582 ~ 33 | # 4 -76.027053484650 -0.000001408151 0.00013145 0.00010801 0.00022518 0.00018425 ~ 34 | # 5 -76.027053512590 -0.000000027940 0.00000849 0.00000726 0.00002709 0.00002046 ~ 35 | # 6 -76.027053512764 -0.000000000174 0.00000069 0.00000057 0.00000161 0.00000138 ~ 36 | -------------------------------------------------------------------------------- /optking/tests/psi4inputs/psithon_versions/hf-g-h2o-tight.in: -------------------------------------------------------------------------------- 1 | #! SCF cc-pVDZ geometry optimzation, with Z-matrix input 2 | import optking 3 | 4 | # nucenergy = 9.3007 5 | REF_energy = -76.027053513 6 | 7 | molecule h2o { 8 | O 9 | H 1 1.0 10 | H 1 1.0 2 104.5 11 | } 12 | 13 | set { 14 | diis false 15 | basis cc-pvdz 16 | e_convergence 10 17 | d_convergence 10 18 | g_convergence gau_tight 19 | scf_type pk 20 | } 21 | 22 | result = optking.optimize_psi4('scf') 23 | 24 | #compare_values(nucenergy, h2o.nuclear_repulsion_energy(), 4, "Nuclear repulsion energy") 25 | compare_values(REF_energy, result['energies'][-1], 9, "Reference energy") 26 | -------------------------------------------------------------------------------- /optking/tests/psi4inputs/psithon_versions/hf-g-h2o.in: -------------------------------------------------------------------------------- 1 | #! SCF STO-3G geometry optimzation, with Z-matrix input 2 | import optking 3 | 4 | #REF_nucenergy = 8.9064890670 5 | REF_energy = -74.965901192 6 | 7 | molecule h2o { 8 | O 9 | H 1 1.0 10 | H 1 1.0 2 104.5 11 | } 12 | 13 | set { 14 | diis false 15 | basis sto-3g 16 | e_convergence 10 17 | d_convergence 10 18 | scf_type pk 19 | } 20 | 21 | result = optking.optimize_psi4('scf') 22 | compare_values(REF_energy, result['energies'][-1], 6, "Reference energy") 23 | 24 | #computedNucenergy = result['trajectory'][-1]['properties']['nuclear_repulsion_energy'] 25 | #compare_values(nucenergy, computedNucenergy, 3, "Nuclear repulsion energy") 26 | 27 | -------------------------------------------------------------------------------- /optking/tests/psi4inputs/psithon_versions/hf-g-hooh-fixed-3.in: -------------------------------------------------------------------------------- 1 | #! Various constrained energy minimizations of HOOH with cc-pvdz RHF. 2 | #! For "fixed" coordinates, the final value is provided by the user. 3 | import optking 4 | 5 | # Minimized energy with OH bonds at 0.950 Angstroms. #TEST 6 | OH_950_stre = -150.78666731 #TEST 7 | # Minimized energy with OOH angles at 105.0 degrees. #TEST 8 | OOH_105_bend = -150.78617685 #TEST 9 | # Minimized energy with HOOH torsion at 120.0 degrees. #TEST 10 | HOOH_120_dihedral = -150.78664695 #TEST 11 | 12 | set { 13 | diis false 14 | basis cc-pvdz 15 | g_convergence gau_tight 16 | } 17 | 18 | # Constrained minimization with O-H bonds fixed to reach equilibrium at 0.950 Angstroms. 19 | molecule { 20 | H 21 | O 1 0.90 22 | O 2 1.40 1 100.0 23 | H 3 0.90 2 100.0 1 115.0 24 | } 25 | 26 | set optking { 27 | fixed_distance = (" 28 | 1 2 0.950 29 | 3 4 0.950 30 | ") 31 | } 32 | result = optking.optimize_psi4('scf') 33 | thisenergy = result['energies'][-1] 34 | compare_values(OH_950_stre , thisenergy, 6, "Int. Coord. RHF opt of HOOH with O-H fixed to 0.95, energy") #TEST 35 | 36 | # Constrained minimization with O-O-H angles fixed to reach eq. at 105.0 degrees. 37 | molecule { 38 | H 39 | O 1 0.90 40 | O 2 1.40 1 100.0 41 | H 3 0.90 2 100.0 1 115.0 42 | } 43 | 44 | set optking { 45 | fixed_distance = (" ") 46 | fixed_bend = (" 47 | 1 2 3 105.0 48 | 2 3 4 105.0 49 | ") 50 | } 51 | result = optking.optimize_psi4('scf') 52 | thisenergy = result['energies'][-1] 53 | compare_values(OOH_105_bend , thisenergy, 6, "Int. Coord. RHF opt of HOOH with O-O-H fixed to 105, energy") #TEST 54 | 55 | # Constrained minimization with H-O-O-H dihedral fixed to 120.0 degrees. 56 | molecule { 57 | H 58 | O 1 0.90 59 | O 2 1.40 1 100.0 60 | H 3 0.90 2 100.0 1 115.0 61 | } 62 | 63 | set optking { 64 | fixed_bend = (" ") 65 | fixed_dihedral = (" 66 | 1 2 3 4 120.0 67 | ") 68 | } 69 | result = optking.optimize_psi4('scf') 70 | thisenergy = result['energies'][-1] 71 | compare_values(HOOH_120_dihedral , thisenergy, 6, "Int. Coord. RHF opt of HOOH with H-O-O-H fixed to 120, energy") #TEST 72 | 73 | -------------------------------------------------------------------------------- /optking/tests/psi4inputs/psithon_versions/hf-g-hooh-frozen-3.in: -------------------------------------------------------------------------------- 1 | #! Various constrained energy minimizations of HOOH with cc-pvdz RHF 2 | #! Internal-coordinate constraints in internal-coordinate optimizations. 3 | import optking 4 | 5 | OH_frozen_stre_rhf = -150.78104113 6 | OOH_frozen_bend_rhf = -150.78628057 7 | HOOH_frozen_dihedral_rhf = -150.78667424 8 | 9 | set { 10 | diis false 11 | basis cc-pvdz 12 | } 13 | 14 | # Constrained minimization with O-H bonds frozen. 15 | molecule { 16 | H 17 | O 1 0.90 18 | O 2 1.40 1 100.0 19 | H 3 0.90 2 100.0 1 115.0 20 | } 21 | 22 | set optking { 23 | frozen_distance = (" 24 | 1 2 25 | 3 4 26 | ") 27 | } 28 | result = optking.optimize_psi4('scf') 29 | thisenergy = result['energies'][-1] 30 | compare_values(OH_frozen_stre_rhf , thisenergy, 7, "Int. Coord. RHF opt of HOOH with O-H frozen, energy") 31 | 32 | # Constrained minimization with O-O-H angles frozen. 33 | molecule { 34 | H 35 | O 1 0.90 36 | O 2 1.40 1 100.0 37 | H 3 0.90 2 100.0 1 115.0 38 | } 39 | 40 | set optking { 41 | frozen_distance = "" # here, it's been previous used, so must be blanked 42 | frozen_bend = (" 43 | 1 2 3 44 | 2 3 4 45 | ") 46 | } 47 | result = optking.optimize_psi4('scf') 48 | thisenergy = result['energies'][-1] 49 | compare_values(OOH_frozen_bend_rhf , thisenergy, 7, "Int. Coord. RHF opt of HOOH with O-O-H frozen, energy") 50 | 51 | # Constrained minimization with H-O-O-H dihedral frozen. 52 | molecule { 53 | H 54 | O 1 0.90 55 | O 2 1.40 1 100.0 56 | H 3 0.90 2 100.0 1 115.0 57 | } 58 | 59 | set optking { 60 | frozen_distance = "" # here, it's been previous used, so must be blanked 61 | frozen_bend = "" 62 | frozen_dihedral = (" 63 | 1 2 3 4 64 | ") 65 | } 66 | result = optking.optimize_psi4('scf') 67 | thisenergy = result['energies'][-1] 68 | compare_values(HOOH_frozen_dihedral_rhf , thisenergy, 7, "Int. Coord. RHF opt of HOOH with H-O-O-H frozen, energy") 69 | 70 | -------------------------------------------------------------------------------- /optking/tests/psi4inputs/psithon_versions/hf-g-hooh-frozenCart-2.in: -------------------------------------------------------------------------------- 1 | #! Various constrained energy minimizations of HOOH with cc-pvdz RHF. 2 | #! Cartesian-coordinate constrained optimizations of HOOH in internals. 3 | import optking 4 | HOOH_E_fixed_H_xyz = -150.7866490998188 5 | HOOH_E_fixed_O_xyz = -150.7866389583059 6 | 7 | set { basis cc-pvdz } 8 | 9 | # Freeze H xyz in HOOH. 10 | molecule { 11 | H 0.90 0.80 0.5 12 | O 0.00 0.70 0.0 13 | O 0.00 -0.70 0.0 14 | H -0.90 -0.80 0.5 15 | no_com 16 | no_reorient 17 | } 18 | 19 | freeze_list = """ 20 | 1 xyz 21 | 4 xyz 22 | """ 23 | 24 | set optking frozen_cartesian $freeze_list 25 | result = optking.optimize_psi4('scf') 26 | thisenergy = result['energies'][-1] 27 | compare_values(HOOH_E_fixed_H_xyz, thisenergy, 6, "Int. Coord. RHF opt of HOOH with H's xyz frozen, energy") 28 | 29 | # Freeze O xyz in HOOH. 30 | molecule { 31 | H 0.90 0.80 0.5 32 | O 0.00 0.70 0.0 33 | O 0.00 -0.70 0.0 34 | H -0.90 -0.80 0.5 35 | no_com 36 | no_reorient 37 | } 38 | 39 | freeze_list = """ 40 | 2 xyz 41 | 3 xyz 42 | """ 43 | set optking frozen_cartesian $freeze_list 44 | result = optking.optimize_psi4('scf') 45 | thisenergy = result['energies'][-1] 46 | compare_values(HOOH_E_fixed_O_xyz, thisenergy, 6, "Int. Coord. RHF opt of HOOH with O's xyz frozen, energy") 47 | -------------------------------------------------------------------------------- /optking/tests/psi4inputs/psithon_versions/hf-g-hooh-frozenCartInCarts-3.in: -------------------------------------------------------------------------------- 1 | #! Various constrained energy minimizations of HOOH with cc-pvdz RHF. 2 | #! Cartesian-coordinate constrained optimizations of HOOH in Cartesians. 3 | import optking 4 | 5 | HOOH_E_fixed_H_xyz = -150.7866490998188 6 | HOOH_E_fixed_O_xyz = -150.7866389583059 7 | HOOH_E = -150.786674252464 8 | 9 | set { 10 | basis cc-pvdz 11 | opt_coordinates cartesian 12 | } 13 | 14 | # Freeze H xyz in HOOH. 15 | molecule { 16 | H 0.90 0.80 0.5 17 | O 0.00 0.70 0.0 18 | O 0.00 -0.70 0.0 19 | H -0.90 -0.80 0.5 20 | no_com 21 | no_reorient 22 | } 23 | 24 | freeze_list = """ 25 | 1 xyz 26 | 4 xyz 27 | """ 28 | 29 | set optking frozen_cartesian $freeze_list 30 | result = optking.optimize_psi4('scf') 31 | thisenergy = result['energies'][-1] 32 | compare_values(HOOH_E_fixed_H_xyz, thisenergy, 6, "Cart. Coord. RHF opt of HOOH with H's xyz frozen, energy") 33 | 34 | # Freeze O xyz in HOOH. 35 | molecule { 36 | H 0.90 0.80 0.5 37 | O 0.00 0.70 0.0 38 | O 0.00 -0.70 0.0 39 | H -0.90 -0.80 0.5 40 | no_com 41 | no_reorient 42 | } 43 | 44 | freeze_list = """ 45 | 2 xyz 46 | 3 xyz 47 | """ 48 | 49 | set optking frozen_cartesian $freeze_list 50 | result = optking.optimize_psi4('scf') 51 | thisenergy = result['energies'][-1] 52 | compare_values(HOOH_E_fixed_O_xyz, thisenergy, 6, "Cart. Coord. RHF opt of HOOH with O's xyz frozen, energy") 53 | 54 | # Full optimization 55 | molecule { 56 | H 0.90 0.80 0.5 57 | O 0.00 0.70 0.0 58 | O 0.00 -0.70 0.0 59 | H -0.90 -0.80 0.5 60 | no_com 61 | no_reorient 62 | } 63 | 64 | set g_convergence gau_tight 65 | 66 | freeze_list = "" 67 | set optking frozen_cartesian $freeze_list 68 | result = optking.optimize_psi4('scf') 69 | thisenergy = result['energies'][-1] 70 | compare_values(HOOH_E, thisenergy, 6, "Cart. Coord. RHF opt of HOOH, energy") 71 | 72 | -------------------------------------------------------------------------------- /optking/tests/psi4inputs/psithon_versions/hf-g-ketene-bent.in: -------------------------------------------------------------------------------- 1 | #! SCF cc-pVDZ geometry optimzation of ketene, starting from bent structure 2 | import optking 3 | scf_E = -151.740757212 4 | 5 | molecule h2c2o { 6 | 0 1 7 | H 8 | C 1 1.1 9 | C 2 1.3 1 130.0 10 | H 2 1.1 3 110.0 1 180.0 11 | O 3 1.1 4 120.0 1 180.0 12 | } 13 | 14 | set basis cc-pVDZ 15 | set g_convergence gau_tight 16 | 17 | result = optking.optimize_psi4('scf') 18 | thisenergy = result['energies'][-1] 19 | 20 | compare_values(scf_E, thisenergy, 8, "Reference energy") 21 | -------------------------------------------------------------------------------- /optking/tests/psi4inputs/psithon_versions/mp2-g-h2o.in: -------------------------------------------------------------------------------- 1 | #! All-electron MP2 6-31G** geometry optimization of water 2 | import optking 3 | 4 | REF_nucenergy = 9.1622581908184 5 | REF_mp2 = -76.2224486598878 6 | 7 | molecule h2o { 8 | O 9 | H 1 1.0 10 | H 1 1.0 2 106.0 11 | } 12 | 13 | set { 14 | basis 6-31G** 15 | reference rhf 16 | d_convergence 9 17 | e_convergence 9 18 | mp2_type conv 19 | } 20 | 21 | result = optking.optimize_psi4('mp2') 22 | this_mp2 = result['energies'][-1] 23 | this_nucenergy = result['trajectory'][-1]['properties']['nuclear_repulsion_energy'] 24 | 25 | compare_values(REF_nucenergy, this_nucenergy, 3, "Nuclear repulsion energy") 26 | compare_values(REF_mp2, this_mp2, 6, "CONV MP2 energy") 27 | 28 | -------------------------------------------------------------------------------- /optking/tests/psi4inputs/psithon_versions/scsomp2-g-h2o.in: -------------------------------------------------------------------------------- 1 | #! SCS-OMP2 cc-pVDZ geometry optimization for the H2O molecule. 2 | import optking 3 | 4 | REF_nuc = 9.11180990045111 5 | REF_scf = -76.02608509946806 6 | REF_scsomp2 = -76.22804532525168 7 | 8 | molecule h2o { 9 | 0 1 10 | o 11 | h 1 0.958 12 | h 1 0.958 2 104.4776 13 | } 14 | 15 | set { 16 | basis cc-pvdz 17 | } 18 | 19 | result = optking.optimize_psi4('scs-omp2') 20 | 21 | this_nucenergy = result['trajectory'][-1]['properties']['nuclear_repulsion_energy'] 22 | this_scf = result['trajectory'][-1]['properties']['scf_total_energy'] 23 | this_energy = result['energies'][-1] 24 | 25 | compare_values(REF_nuc, this_nucenergy, 5, "Nuclear Repulsion Energy (a.u.)"); 26 | compare_values(REF_scf, this_scf, 6, "SCF Energy (a.u.)"); 27 | compare_values(REF_scsomp2, this_energy, 6, "SCS-OMP2 Total Energy (a.u.)"); 28 | 29 | -------------------------------------------------------------------------------- /optking/tests/psi4inputs/psithon_versions/scsomp3-g-h2o.in: -------------------------------------------------------------------------------- 1 | #! SCS-OMP3 cc-pVDZ geometry optimization for the H2O molecule. 2 | import optking 3 | 4 | REF_nuc = 9.11871568396669 5 | REF_scf = -76.02615852683365 6 | REF_scsomp3 = -76.22962586987757 7 | 8 | molecule h2o { 9 | 0 1 10 | o 11 | h 1 0.958 12 | h 1 0.958 2 104.4776 13 | } 14 | 15 | set { 16 | basis cc-pvdz 17 | } 18 | 19 | result = optking.optimize_psi4('scs-omp3') 20 | this_nuc = result['trajectory'][-1]['properties']['nuclear_repulsion_energy'] 21 | this_scf = result['trajectory'][-1]['properties']['scf_total_energy'] 22 | this_energy = result['energies'][-1] 23 | 24 | compare_values(REF_nuc, this_nuc, 5, "Nuclear Repulsion Energy (a.u.)"); 25 | compare_values(REF_scf, this_scf, 6, "SCF Energy (a.u.)"); 26 | compare_values(REF_scsomp3, this_energy, 6, "SCS-OMP3 Total Energy (a.u.)"); 27 | 28 | -------------------------------------------------------------------------------- /optking/tests/psi4inputs/psithon_versions/sosomp2-g-h2o.in: -------------------------------------------------------------------------------- 1 | #! SOS-OMP2 cc-pVDZ geometry optimization for the H2O molecule. 2 | import optking 3 | 4 | REF_nuc = 9.12295422215394 5 | REF_scf = -76.02621188217395 6 | REF_sosomp2 = -76.21065070996092 7 | 8 | molecule h2o { 9 | 0 1 10 | o 11 | h 1 0.958 12 | h 1 0.958 2 104.4776 13 | } 14 | 15 | set { 16 | basis cc-pvdz 17 | } 18 | 19 | result = optking.optimize_psi4('sos-omp2') 20 | this_nuc = result['trajectory'][-1]['properties']['nuclear_repulsion_energy'] 21 | this_scf = result['trajectory'][-1]['properties']['scf_total_energy'] 22 | this_energy = result['energies'][-1] 23 | 24 | 25 | compare_values(REF_nuc, this_nuc, 4, "Nuclear Repulsion Energy (a.u.)"); 26 | compare_values(REF_scf, this_scf, 6, "SCF Energy (a.u.)"); 27 | compare_values(REF_sosomp2, this_energy, 6, "SOS-OMP2 Total Energy (a.u.)"); 28 | 29 | -------------------------------------------------------------------------------- /optking/tests/psi4inputs/psithon_versions/sosomp3-g-h2o.in: -------------------------------------------------------------------------------- 1 | #! SOS-OMP3 cc-pVDZ geometry optimization for the H2O molecule. 2 | import optking 3 | 4 | REF_nuc = 9.11294430202143 5 | REF_scf = -76.02611710513384 6 | REF_sosomp3 = -76.22772062866821 7 | 8 | molecule h2o { 9 | 0 1 10 | o 11 | h 1 0.958 12 | h 1 0.958 2 104.4776 13 | } 14 | 15 | set { 16 | basis cc-pvdz 17 | } 18 | 19 | result = optking.optimize_psi4('sos-omp3') 20 | this_nuc = result['trajectory'][-1]['properties']['nuclear_repulsion_energy'] 21 | this_scf = result['trajectory'][-1]['properties']['scf_total_energy'] 22 | this_energy = result['energies'][-1] 23 | 24 | compare_values(REF_nuc, this_nuc, 5, "Nuclear Repulsion Energy (a.u.)"); 25 | compare_values(REF_scf, this_scf, 6, "SCF Energy (a.u.)"); 26 | compare_values(REF_sosomp3, this_energy, 6, "SOS-OMP3 Total Energy (a.u.)"); 27 | 28 | -------------------------------------------------------------------------------- /optking/tests/psi4inputs/psithon_versions/todo-psi4tests.txt: -------------------------------------------------------------------------------- 1 | # Jan. 2019, Converting existing Psi4 test cases to here to see 2 | # how much functionality we can reproduce, and to test the 3 | # optimizer. 4 | 5 | * Input filename here * Previous directory name in psi4/tests 6 | _______________________________________________________________ 7 | TODO: 8 | OK for 7-8 steps, but fails when step breaks c2v symmetry. 9 | May require fixing bond axes between steps. 10 | hf-g-SF4-breaksLinear opt14 11 | 12 | # TODO : other possible tests to examine. 13 | hf-h-h2o-fullHessEvery opt-full-hess-every 14 | ccsd-g-h2o-freqs cc3 15 | hf-g-h2o-freq tu4-h2o-freq 16 | irc-hf-g-hooh opt-irc-1 17 | irc-hf-g-hcn-2 opt-irc-2 18 | irc-hf-g-hooh-tight opt-irc-3 19 | mp2-g-ch4Dimer-fragsC1 opt-multi-dimer-c1 20 | mp2-g-ch4Dimer-fragsC2h opt-multi-dimer-c2h 21 | mp2-g-ch4Dimer-fragsFrozen opt-multi-frozen-dimer-c2h 22 | hf-g-h2o-freqIsotope1 freq-isotope1 23 | hf-g-h2o-freqIsotope2 freq-isotope2 24 | hf-g-several-gibbs gibbs 25 | hf-g-h2oTrimer-freq nbody-freq 26 | 27 | # TODO: get finite differences of energies working 28 | # Got one working using psi4_optimize( dertype=0) 29 | # converted into a keyword argument, and then processed 30 | # by a modified driver/schema_wrapper.py 31 | hf-e-alleneLinear opt2-fd 32 | ccsd-e-h2o cc2 33 | cisd-e-h2o cisd-opt-fd 34 | 35 | # Too computationally large of a test to keep? 36 | ts-mp2-gh-C5H8N2 opt10 37 | 38 | # Worry about later or forget? 39 | cbs-xtpl-func 40 | cbs-xtpl-opt 41 | cbs-xtpl-wrapper 42 | hf-g-benzene-pubchem 43 | pywrap-all 44 | pywrap-db2 45 | pywrap-opt-sowreap 46 | opt-lindep-change 47 | tu3-h2o-opt 48 | -------------------------------------------------------------------------------- /optking/tests/psi4inputs/psithon_versions/ts-hf-g-hooh-2.in: -------------------------------------------------------------------------------- 1 | #! Transition-state optimizations of HOOH to both torsional transition states. 2 | import optking 3 | TORS_ENERGY = -150.7853070 4 | ZERO_TORS_ENERGY = -150.7739141 5 | 6 | # Optimization to 180 degree torsion from 120 7 | molecule hooh { 8 | 0 1 9 | H 10 | O 1 0.95 11 | O 2 1.40 1 105.0 12 | H 3 0.95 2 105.0 1 120.0 13 | noreorient 14 | } 15 | set { 16 | basis cc-pvdz 17 | opt_type ts 18 | docc = [ 5 , 4 ] 19 | intrafrag_step_limit 0.1 20 | # loose convergence criteria due to scf convergence problems as c2h structure is approached 21 | MAX_FORCE_G_CONVERGENCE 5.0e-4 22 | } 23 | 24 | result = optking.optimize_psi4('scf') 25 | thisenergy = result['energies'][-1] 26 | compare_values(TORS_ENERGY, thisenergy, 6, "cc-pVDZ RHF transition-state opt. of HOOH (dihedral=180), energy") 27 | 28 | # Optimization to 0 degree torsion from 100 29 | molecule hooh { 30 | H 31 | O 1 0.95 32 | O 2 1.40 1 105.0 33 | H 3 0.95 2 105.0 1 100.0 34 | } 35 | 36 | result = optking.optimize_psi4('scf') 37 | thisenergy = result['energies'][-1] 38 | compare_values(ZERO_TORS_ENERGY, thisenergy, 6, "cc-pVDZ RHF transition-state opt. of HOOH (dihedral=0), energy") 39 | 40 | -------------------------------------------------------------------------------- /optking/tests/psi4inputs/psithon_versions/uccsd-g-ch2.in: -------------------------------------------------------------------------------- 1 | #! UHF-CCSD/cc-pVDZ $^{3}B@@1$ CH2 geometry optimization via analytic gradients 2 | import optking 3 | 4 | REF_scf = -38.92658702693478 5 | REF_ccsd = -0.11533612150975 6 | REF_total = -39.04192314844453 7 | 8 | molecule ch2 { 9 | 0 3 10 | C 11 | H 1 1.1 12 | H 1 1.1 2 109.0 13 | } 14 | 15 | set { 16 | reference uhf 17 | basis cc-pvdz 18 | max_disp_g_convergence 1e-6 19 | max_force_g_convergence 1.0e-6 20 | max_energy_g_convergence 7 21 | e_convergence 10 22 | d_convergence 10 23 | } 24 | 25 | result = optking.optimize_psi4('CCSD') 26 | 27 | this_scf = result['trajectory'][-1]['properties']['scf_total_energy'] 28 | this_ccsd = result['trajectory'][-1]['properties']['ccsd_correlation_energy'] 29 | this_total = result['trajectory'][-1]['properties']['return_energy'] 30 | 31 | compare_values(REF_scf, this_scf, 6, "SCF energy") 32 | compare_values(REF_ccsd, this_ccsd, 6, "CCSD contribution") 33 | compare_values(REF_total, this_total, 6, "Total energy") 34 | -------------------------------------------------------------------------------- /optking/tests/psi4inputs/psithon_versions/uccsdpt-g-ch2.in: -------------------------------------------------------------------------------- 1 | #! UHF-CCSD(T)/cc-pVDZ $^{3}B@@1$ CH2 geometry optimization via analytic gradients 2 | import optking 3 | 4 | molecule ch2 { 5 | 0 3 6 | C 7 | H 1 1.1 8 | H 1 1.1 2 109.0 9 | } 10 | 11 | set { 12 | reference uhf 13 | basis cc-pvdz 14 | max_disp_g_convergence 1e-6 15 | max_force_g_convergence 1.0e-6 16 | max_energy_g_convergence 7 17 | e_convergence 10 18 | r_convergence 10 19 | } 20 | 21 | result = optking.optimize_psi4('CCSD(T)') 22 | 23 | REF_scf = -38.92655208442658 24 | REF_ccsd_t = -0.11716018769631 25 | REF_total = -39.04371227103925 26 | 27 | this_scf = result['trajectory'][-1]['properties']['scf_total_energy'] 28 | this_ccsd_t = result['trajectory'][-1]['properties']['ccsd_prt_pr_correlation_energy'] 29 | this_total = result['trajectory'][-1]['properties']['ccsd_prt_pr_total_energy'] 30 | this_return = result['trajectory'][-1]['properties']['return_energy'] 31 | 32 | compare_values(REF_scf, this_scf, 6, "SCF energy") 33 | compare_values(REF_ccsd_t, this_ccsd_t, 6, "CCSD(T) contribution") 34 | compare_values(REF_total, this_total, 6, "Total CCSD(T) energy") 35 | compare_values(REF_total, this_return, 6, "Total CCSD(T) return energy") 36 | 37 | -------------------------------------------------------------------------------- /optking/tests/psi4inputs/psithon_versions/uhf-g-ch2-dummy.in: -------------------------------------------------------------------------------- 1 | #! 6-31G** UHF CH2 3B1 optimization. Uses a Z-Matrix with dummy atoms, just for demo and testing purposes. 2 | import optking 3 | 4 | REF_energy = -38.925486977153 5 | 6 | molecule ch2 { 7 | 0 3 8 | c 9 | x 1 1.0 10 | h 1 b1 2 a1 11 | h 1 b1 2 a1 3 180.0 12 | 13 | b1 = 1.0 14 | a1 = 60.0 15 | } 16 | 17 | set { 18 | reference uhf 19 | basis 6-31G(d,p) 20 | docc [2, 0, 0, 1] 21 | socc [1, 0, 1, 0] 22 | scf_type pk 23 | } 24 | 25 | result = optking.optimize_psi4('scf') 26 | thisenergy = result['energies'][-1] 27 | 28 | compare_values(REF_energy, thisenergy, 6, "Reference energy") 29 | -------------------------------------------------------------------------------- /optking/tests/test_2_hessians.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import pytest 3 | import psi4 4 | import optking 5 | from .utils import utils 6 | 7 | final_energy = -150.786766850 8 | hess_every = [(-1, final_energy, 10), (0, final_energy, 10), (1, final_energy, 4), (3, final_energy, 5)] 9 | hess_guess = [ 10 | ("fischer", final_energy, 9), 11 | ("lindH_simple", final_energy, 11), 12 | ("simple", final_energy, 12), 13 | ("lindh", final_energy, 16), 14 | ] 15 | hess_update = [("MS", final_energy, 10), ("powell", final_energy, 11), ("bofill", final_energy, 10)] 16 | 17 | logger = optking.logger 18 | 19 | 20 | @pytest.mark.parametrize("every, expected, num_steps", hess_every, ids=["None", "First Step", "Every", "Every 3"]) 21 | def test_hess_every(check_iter, every, expected, num_steps): 22 | 23 | hooh = psi4.geometry( 24 | """ 25 | H 26 | O 1 0.95 27 | O 2 1.39 1 102.0 28 | H 3 0.95 2 102.0 1 130.0 29 | """ 30 | ) 31 | 32 | psi4.core.clean_options() 33 | psi4_options = { 34 | "basis": "cc-pvdz", 35 | "scf_type": "pk", 36 | "g_convergence": "gau_verytight", 37 | "full_hess_every": every, 38 | "print": 4, 39 | } 40 | 41 | psi4.set_options(psi4_options) 42 | json_output = optking.optimize_psi4("hf") # Uses default program (psi4) 43 | E = json_output["energies"][-1] 44 | 45 | assert psi4.compare_values(expected, E, 8, "Final energy, every step Hessian") # TEST 46 | 47 | utils.compare_iterations(json_output, num_steps, check_iter) 48 | 49 | 50 | @pytest.mark.parametrize("guess, expected, num_steps", hess_guess) 51 | def test_hess_guess(check_iter, guess, expected, num_steps): 52 | 53 | hooh = psi4.geometry( 54 | """ 55 | H 56 | O 1 0.95 57 | O 2 1.39 1 102.0 58 | H 3 0.95 2 102.0 1 130.0 59 | """ 60 | ) 61 | 62 | psi4.core.clean_options() 63 | psi4_options = {"basis": "cc-pvdz", "scf_type": "pk", "g_convergence": "gau_verytight", "intrafrag_hess": guess} 64 | 65 | psi4.set_options(psi4_options) 66 | json_output = optking.optimize_psi4("hf") # Uses default program (psi4) 67 | E = json_output["energies"][-1] 68 | print(f"Number of steps taken {len(json_output['trajectory'])}") 69 | assert psi4.compare_values(expected, E, 8, "Final energy, every step Hessian") # TEST 70 | 71 | utils.compare_iterations(json_output, num_steps, check_iter) 72 | 73 | 74 | @pytest.mark.parametrize("update, expected, num_steps", hess_update) 75 | def test_hess_update(check_iter, update, expected, num_steps): 76 | 77 | hooh = psi4.geometry( 78 | """ 79 | H 80 | O 1 0.95 81 | O 2 1.39 1 102.0 82 | H 3 0.95 2 102.0 1 130.0 83 | """ 84 | ) 85 | 86 | psi4.core.clean_options() 87 | psi4_options = {"basis": "cc-pvdz", "scf_type": "pk", "g_convergence": "gau_verytight", "hess_update": update} 88 | 89 | psi4.set_options(psi4_options) 90 | json_output = optking.optimize_psi4("hf") # Uses default program (psi4) 91 | E = json_output["energies"][-1] 92 | 93 | assert psi4.compare_values(expected, E, 8, "Final energy, every step Hessian") # TEST 94 | 95 | utils.compare_iterations(json_output, num_steps, check_iter) 96 | 97 | def test_hess_read(check_iter): 98 | import os 99 | hooh = psi4.geometry( 100 | """ 101 | H 102 | O 1 0.95 103 | O 2 1.39 1 102.0 104 | H 3 0.95 2 102.0 1 130.0 105 | """ 106 | ) 107 | 108 | psi4_options = { 109 | "basis": "cc-pvdz", 110 | "scf_type": "pk", 111 | "g_convergence": "gau_verytight", 112 | "hessian_write": True, 113 | } 114 | 115 | psi4.set_options(psi4_options) 116 | json_output = psi4.frequencies("hf") # Uses default program (psi4) 117 | 118 | psi4.core.clean_options() 119 | psi4_options = { 120 | "basis": "cc-pvdz", 121 | "scf_type": "pk", 122 | "g_convergence": "gau_verytight", 123 | "cart_hess_read": True, 124 | } 125 | 126 | psi4.set_options(psi4_options) 127 | json_output = optking.optimize_psi4("hf", **{"cart_hess_read": True, "hessian_file": f"stdout.default.{os.getpid()}.hess"}) 128 | E = json_output["energies"][-1] 129 | assert psi4.compare_values(final_energy, E, 8, "Final energy, every step Hessian") # TEST 130 | utils.compare_iterations(json_output, 10, check_iter) 131 | 132 | -------------------------------------------------------------------------------- /optking/tests/test_atom.py: -------------------------------------------------------------------------------- 1 | #! Test handling of atom. No optimization, computes energy. 2 | import psi4 3 | import optking 4 | 5 | RefEnergy = -127.8037761406364581 6 | 7 | def test_atom(): 8 | mol = psi4.geometry( """ Ne 0.0 0.0 0.0 """ ) 9 | psi4.core.clean_options() 10 | psi4.set_options({ "basis": "3-21G" }) 11 | 12 | qc_output = optking.optimize_psi4("hf") 13 | 14 | E = qc_output['energies'][-1] 15 | success = qc_output['success'] 16 | Etraj = qc_output["trajectory"][-1]['extras']['qcvars']['CURRENT ENERGY'] 17 | 18 | assert not qc_output['success'] 19 | assert qc_output["error"]["error_message"] == "There is only 1 atom. Nothing to optimize. Computing energy." 20 | assert psi4.compare_values(E, RefEnergy, 6, "Atom energy (energies)") 21 | assert psi4.compare_values(Etraj, RefEnergy, 6, "Atom energy (trajectory)") 22 | 23 | -------------------------------------------------------------------------------- /optking/tests/test_atom_stepwise.py: -------------------------------------------------------------------------------- 1 | #! Test handling of atom for non optimize_psi4 case. No optimization, computes energy. 2 | import psi4 3 | import optking 4 | import numpy as np 5 | 6 | from optking.optparams import OptParams 7 | from optking.molsys import Molsys 8 | from optking.optimize import OptimizationManager 9 | from optking.optwrapper import make_computer 10 | from optking.history import History 11 | from optking.exceptions import OptError 12 | 13 | RefEnergy = -127.8037761406364581 14 | 15 | def test_atom_stepwise(): 16 | neon = psi4.geometry(""" Ne """) 17 | 18 | psi4.core.clean_options() 19 | 20 | params = OptParams({}) 21 | history = History(params) 22 | opt_mol, qcschema_mol = Molsys.from_psi4(neon) 23 | 24 | opt_input = { 25 | #"keywords": {}, for optimizer, optional 26 | "initial_molecule": qcschema_mol, 27 | "input_specification": { 28 | "model": {"basis": "3-21G", "method": 'hf'}, 29 | "driver": "gradient", 30 | "keywords": {}, 31 | }, 32 | } 33 | computer = make_computer(opt_input, "psi4") 34 | 35 | opt_manager = OptimizationManager(opt_mol, history, params, computer) 36 | 37 | try: 38 | opt_manager.start_step(np.array(0)) 39 | assert False 40 | except OptError as error: 41 | qc_output = opt_manager.opt_error_handler(error) 42 | E = qc_output['energies'][-1] 43 | Etraj = qc_output["trajectory"][-1]['extras']['qcvars']['CURRENT ENERGY'] 44 | 45 | assert not qc_output['success'] 46 | assert qc_output["error"]["error_message"] == "There is only 1 atom. Nothing to optimize. Computing energy." 47 | assert psi4.compare_values(RefEnergy, E, 6, "Atom energy (energies)") 48 | assert psi4.compare_values(RefEnergy, E, 6, "Atom energy (trajectory)") 49 | 50 | -------------------------------------------------------------------------------- /optking/tests/test_auxiliary_bonds.py: -------------------------------------------------------------------------------- 1 | #! Test of adding auxiliary bonds. These are stre coordinates between 2 | #! two non-H atoms that are < 2.5(sum of covalent radii) but NOT already 3 | #! connected by 3 stretches as in A-x-y-B. 4 | 5 | # Here are number of iterations to convergence as of Jan 2022 for 3 molecules 6 | # in Baker database: 7 | # menthone ACHTAR10 histidine 8 | # 2 bonds added 1 bond added 1 bond added 9 | # RHF/6-31+G* 11 -> 10 RHF/6-31+G* 13 -> 11 RHF/6-31+G* 15 -> 16 10 | # B3LYP/6-31+G* 10 -> 9 B3LYP/6-31+G* 12 -> 11 B3LYP/6-31+G* 14 -> 14 11 | # TODO: explore FISCHER Hessian guess alongside auxiliary bonds performance 12 | 13 | import psi4 14 | import optking 15 | import pytest 16 | from .utils import utils 17 | 18 | menthone = psi4.geometry(""" 19 | 0 1 20 | O 0.00000000 0.00000000 4.83502957 21 | C -5.06597212 -1.27592091 0.49885049 22 | C -3.60348796 -1.49111229 -2.01995066 23 | C -1.13779972 0.12182250 -2.02402508 24 | C 0.69335828 -0.53324847 0.24699141 25 | C -0.81879368 -0.76420189 2.79442766 26 | C -3.41755812 -2.06413311 2.77868746 27 | C 0.08327139 -0.18247958 -4.66184769 28 | C 3.16977849 1.11788425 0.33780916 29 | C 5.23967937 0.00000000 2.05851212 30 | C 2.74820737 3.91648659 1.03692914 31 | H -5.73534045 0.69223903 0.75660810 32 | H -6.80139535 -2.44289264 0.43045930 33 | H -3.15419510 -3.50140339 -2.39715388 34 | H -4.86109777 -0.90264082 -3.58603040 35 | H -1.71463208 2.12647811 -1.82542348 36 | H 1.33530286 -2.48925976 -0.10949068 37 | H -4.41049264 -1.64891601 4.56938165 38 | H -3.10227312 -4.12767303 2.77142958 39 | H -1.27515064 0.19340176 -6.20625544 40 | H 0.83979297 -2.10810531 -4.96157719 41 | H 1.65711962 1.15531285 -4.96195049 42 | H 4.01314574 1.10167735 -1.57473542 43 | H 4.69908810 0.02990650 4.07747056 44 | H 7.03475689 1.05859686 1.90111311 45 | H 5.66887645 -1.98486988 1.56898286 46 | H 4.52277834 5.01677786 0.95132487 47 | H 1.98900684 4.13531008 2.97264568 48 | H 1.40402606 4.85096335 -0.25821233 49 | units bohr 50 | """) 51 | 52 | ACHTAR10 = psi4.geometry(""" 53 | 0 1 54 | O 0.00000000 0.00000000 3.93735249 55 | O 1.79875939 0.00000000 -0.09531034 56 | N -4.40589519 1.32037243 -3.31810156 57 | C -2.43021636 -0.18962157 -2.05696026 58 | C -0.22185404 1.49597798 -1.20775357 59 | C 1.69726730 -0.59259412 2.46067577 60 | C 3.97685548 -2.11479138 3.27934906 61 | H -3.68043380 2.27933244 -4.84082518 62 | H -5.10144333 2.68085421 -2.12147722 63 | H -3.24985392 -1.18842676 -0.41051393 64 | H -1.74547418 -1.68142667 -3.35347133 65 | H 0.55351430 2.51912058 -2.85842920 66 | H -0.88071695 2.99188292 0.10524925 67 | H 5.73529679 -1.04410557 2.94759034 68 | H 4.08562680 -3.90736002 2.21955987 69 | H 3.86856770 -2.56921447 5.31306580 70 | units bohr 71 | """) 72 | 73 | HF_expected_noaux = {'menthone': 11, 'ACHTAR10': 13} 74 | HF_expected_aux = {'menthone': 10, 'ACHTAR10': 11} 75 | HF_E = {'menthone': -464.0439981504222, 'ACHTAR10': -360.90442278650494} 76 | 77 | B3LYP_expected_noaux = {'menthone': 10, 'ACHTAR10': 12} 78 | B3LYP_expected_aux = {'menthone': 9, 'ACHTAR10': 11} 79 | B3LYP_E = {'menthone': -467.157103348465, 'ACHTAR10': -363.065807664032} 80 | 81 | @pytest.mark.long 82 | def test_auxiliary_bonds(check_iter): 83 | for molname in ['menthone', 'ACHTAR10']: 84 | psi4.core.set_active_molecule(eval(molname)) 85 | 86 | psi4.core.clean_options() 87 | psi4.set_options({ "basis": "6-31+G*", }) 88 | 89 | result = optking.optimize_psi4("HF") 90 | utils.compare_iterations(result, HF_expected_noaux[molname], check_iter) 91 | E = result["energies"][-1] 92 | assert psi4.compare_values(HF_E[molname], E, 5, "HF energy") 93 | 94 | psi4.core.set_active_molecule(eval(molname)) 95 | psi4.core.clean_options() 96 | 97 | psi4.set_options({ "basis": "6-31+G*", }) 98 | optking_options = {"add_auxiliary_bonds": True} 99 | 100 | result = optking.optimize_psi4("HF", **optking_options) 101 | utils.compare_iterations(result, HF_expected_aux[molname], check_iter) 102 | E = result["energies"][-1] 103 | assert psi4.compare_values(HF_E[molname], E, 5, "HF energy") 104 | 105 | -------------------------------------------------------------------------------- /optking/tests/test_ccsd_g_opt.py: -------------------------------------------------------------------------------- 1 | import psi4 2 | import optking 3 | import pytest 4 | from .utils import utils 5 | 6 | #! RHF-CCSD 6-31G** all-electron opt of H2O, default convergence 7 | def test_ccsd_h2o(check_iter): 8 | 9 | h2o = psi4.geometry( 10 | """ 11 | O 12 | H 1 0.97 13 | H 1 0.97 2 103.0 14 | """ 15 | ) 16 | 17 | psi4.core.clean_options() 18 | psi4_options = {"basis": "6-31G**", "scf_type": "pk"} 19 | psi4.set_options(psi4_options) 20 | 21 | result = optking.optimize_psi4("ccsd") 22 | print(result["trajectory"][-1].keys()) 23 | 24 | this_scf = result["trajectory"][-1]["properties"]["scf_total_energy"] # TEST 25 | this_ccsd = result["trajectory"][-1]["properties"]["ccsd_correlation_energy"] # TEST 26 | this_total = result["trajectory"][-1]["properties"]["return_energy"] # TEST 27 | REF_scf = -76.0229406477 # TEST 28 | REF_ccsd = -0.2082378354 # TEST 29 | REF_total = -76.2311784830 # TEST 30 | assert psi4.compare_values(REF_scf, this_scf, 4, "SCF energy") # TEST 31 | assert psi4.compare_values(REF_ccsd, this_ccsd, 4, "CCSD contribution") # TEST 32 | assert psi4.compare_values(REF_total, this_total, 4, "Total energy") # TEST 33 | 34 | utils.compare_iterations(result, 3, check_iter) 35 | 36 | 37 | #! ROHF-CCSD/cc-pVDZ $^{3}B@@1$ CH2 geometry opt, analytic gradients, tight 38 | def test_ccsd_ch2(check_iter): 39 | 40 | ch2 = psi4.geometry( 41 | """ 42 | 0 3 43 | C 44 | H 1 1.1 45 | H 1 1.1 2 109.0 46 | """ 47 | ) 48 | 49 | psi4.core.clean_options() 50 | psi4_options = { 51 | "reference": "rohf", 52 | "basis": "cc-pvdz", 53 | "max_disp_g_convergence": 1e-6, 54 | "max_force_g_convergence": 1.0e-6, 55 | "max_energy_g_convergence": 7, 56 | "e_convergence": 10, 57 | "r_convergence": 10, 58 | "scf_type": "pk", 59 | } 60 | psi4.set_options(psi4_options) 61 | 62 | result = optking.optimize_psi4("CCSD") 63 | 64 | this_scf = result["trajectory"][-1]["properties"]["scf_total_energy"] # TEST 65 | this_ccsd = result["trajectory"][-1]["properties"]["ccsd_correlation_energy"] # TEST 66 | this_total = result["trajectory"][-1]["properties"]["return_energy"] # TEST 67 | REF_scf = -38.9213947335 # TEST 68 | REF_cor = -0.1204840983 # TEST 69 | REF_tot = -39.0418788319 # TEST 70 | assert psi4.compare_values(REF_scf, this_scf, 6, "ROHF energy") # TEST 71 | assert psi4.compare_values(REF_cor, this_ccsd, 6, "ROHF CCSD contribution") # TEST 72 | assert psi4.compare_values(REF_tot, this_total, 6, "ROHF CCSD Total energy") # TEST 73 | 74 | utils.compare_iterations(result, 9, check_iter) 75 | 76 | 77 | #! UHF-CCSD/cc-pVDZ $^{3}B@@1$ CH2 geometry opt via analytic gradients, tight 78 | def test_uccsd_ch2(check_iter): 79 | 80 | ch2 = psi4.geometry( 81 | """ 82 | 0 3 83 | C 84 | H 1 1.1 85 | H 1 1.1 2 109.0 86 | """ 87 | ) 88 | 89 | psi4.core.clean_options() 90 | psi4_options = { 91 | "reference": "uhf", 92 | "basis": "cc-pvdz", 93 | "max_disp_g_convergence": 1e-6, 94 | "max_force_g_convergence": 1.0e-6, 95 | "max_energy_g_convergence": 7, 96 | "e_convergence": 10, 97 | "r_convergence": 10, 98 | "scf_type": "pk", 99 | } 100 | psi4.set_options(psi4_options) 101 | 102 | result = optking.optimize_psi4("CCSD") 103 | 104 | this_scf = result["trajectory"][-1]["properties"]["scf_total_energy"] # TEST 105 | this_ccsd = result["trajectory"][-1]["properties"]["ccsd_correlation_energy"] # TEST 106 | this_total = result["trajectory"][-1]["properties"]["return_energy"] # TEST 107 | REF_scf = -38.9265869596 # TEST 108 | REF_ccsd = -0.1153361899 # TEST 109 | REF_total = -39.0419231495 # TEST 110 | assert psi4.compare_values(REF_scf, this_scf, 6, "UHF energy") # TEST 111 | assert psi4.compare_values(REF_ccsd, this_ccsd, 6, "UHF CCSD contribution") # TEST 112 | assert psi4.compare_values(REF_total, this_total, 6, "UCCSD Total energy") # TEST 113 | 114 | utils.compare_iterations(result, 9, check_iter) 115 | 116 | 117 | #! UHF-CCSD(T)/cc-pVDZ $^{3}B@@1$ CH2 geometry optimization via analytic gradients 118 | @pytest.mark.long 119 | def test_uccsdpt_ch2(check_iter): 120 | 121 | ch2 = psi4.geometry( 122 | """ 123 | 0 3 124 | C 125 | H 1 1.1 126 | H 1 1.1 2 109.0 127 | """ 128 | ) 129 | 130 | psi4.core.clean_options() 131 | psi4_options = { 132 | "reference": "uhf", 133 | "basis": "cc-pvdz", 134 | "max_disp_g_convergence": 1e-6, 135 | "max_force_g_convergence": 1.0e-6, 136 | "max_energy_g_convergence": 7, 137 | "e_convergence": 10, 138 | "r_convergence": 10, 139 | "scf_type": "pk", 140 | } 141 | psi4.set_options(psi4_options) 142 | 143 | result = optking.optimize_psi4("CCSD(T)") 144 | 145 | this_ccsd_t = result["trajectory"][-1]["properties"]["ccsd_prt_pr_correlation_energy"] # TEST 146 | this_total = result["trajectory"][-1]["properties"]["ccsd_prt_pr_total_energy"] # TEST 147 | REF_scf = -38.9265520844 # TEST. Value is not currently included in trajectory output 148 | REF_ccsd_t = -0.1171601876 # TEST 149 | REF_total = -39.0437122710 # TEST 150 | assert psi4.compare_values(REF_ccsd_t, this_ccsd_t, 6, "CCSD(T) contribution") # TEST 151 | assert psi4.compare_values(REF_total, this_total, 6, "Total CCSD(T) energy") # TEST 152 | 153 | utils.compare_iterations(result, 9, check_iter) 154 | 155 | -------------------------------------------------------------------------------- /optking/tests/test_conjugate.py: -------------------------------------------------------------------------------- 1 | #! Test conjugate gradient algorithms by optimizing propylamine 2 | #! For comparison steepest descent converges in 16 iterations. 3 | import pytest 4 | 5 | import psi4 6 | import optking 7 | from .utils import utils 8 | 9 | check_iter = True 10 | 11 | refE = -173.3000252 12 | cg_step_types = [("FLETCHER",14),("DESCENT", 24), ("POLAK", 44)] 13 | 14 | @pytest.mark.long 15 | @pytest.mark.parametrize("option, num_steps", cg_step_types, ids=["FLETCHER","DESCENT","POLAK"]) 16 | def test_conjugate_gradient_type(option, num_steps, check_iter): 17 | propylamine = psi4.geometry( 18 | """ 19 | N 1.8767 -0.1522 -0.0054 20 | C -0.5459 -0.5165 0.0053 21 | C 0.5800 0.5145 0.0053 22 | C -1.9108 0.1542 -0.0052 23 | H -0.4629 -1.1669 -0.8740 24 | H -0.4700 -1.1586 0.8912 25 | H 0.5127 1.1539 0.8920 26 | H 0.5047 1.1629 -0.8741 27 | H -2.0434 0.7874 0.8779 28 | H -2.0351 0.7769 -0.8969 29 | H -2.7039 -0.6001 -0.0045 30 | H 1.9441 -0.7570 -0.8233 31 | H 1.9519 -0.7676 0.8039 32 | """ 33 | ) 34 | 35 | psi4.core.clean_options() 36 | psi4_options = {"basis": "cc-pVDZ", "d_convergence": 10, "geom_maxiter": 70} 37 | psi4.set_options(psi4_options) 38 | 39 | optking_options = { 40 | "step_type" : "CONJUGATE", 41 | "conjugate_gradient_type" : option 42 | } 43 | 44 | json_output = optking.optimize_psi4("hf", **optking_options) 45 | thisenergy = json_output["energies"][-1] 46 | 47 | assert psi4.compare_values(refE, thisenergy, 5) 48 | utils.compare_iterations(json_output, num_steps, check_iter) 49 | 50 | -------------------------------------------------------------------------------- /optking/tests/test_dcft_g_opt.py: -------------------------------------------------------------------------------- 1 | import psi4 2 | import optking 3 | from .utils import utils 4 | 5 | #! DC-06 calculation for the O2 molecule (triplet ground state). This performs 6 | #! geometry optimization using two-step and simultaneous solution of the 7 | #! response equations for the analytic gradient. 8 | def test_dcft_O2(check_iter): 9 | o2 = psi4.geometry( 10 | """ 11 | 0 3 12 | O 13 | O 1 R 14 | R = 1.230 15 | """ 16 | ) 17 | 18 | psi4.core.clean_options() 19 | psi4_options = { 20 | "r_convergence": 10, 21 | "algorithm": "twostep", 22 | "response_algorithm": "twostep", 23 | "basis": "dzp", 24 | "max_disp_g_convergence": 1e-6, 25 | "rms_force_g_convergence": 1e-6, 26 | "max_energy_g_convergence": 1e-7, 27 | "reference": "uhf", 28 | "dct_functional": "dc-06", 29 | } 30 | psi4.set_options(psi4_options) 31 | 32 | result = optking.optimize_psi4("dct") 33 | 34 | this_uhf = result["trajectory"][-1]["properties"]["scf_total_energy"] # TEST 35 | this_mp2 = result["trajectory"][-1]["properties"]["mp2_total_energy"] # TEST 36 | this_dct = result["energies"][-1] # TEST 37 | REF_uhf = -149.6520519320 # TEST 38 | REF_mp2 = -150.0109986566 # TEST 39 | REF_dct = -150.0227937862 # TEST 40 | assert psi4.compare_values(REF_uhf, this_uhf, 6, "UHF Energy") # TEST 41 | assert psi4.compare_values(REF_mp2, this_mp2, 6, "MP2 Energy") # TEST 42 | assert psi4.compare_values(REF_dct, this_dct, 6, "DC-06 Energy (two-step response)") # TEST 43 | 44 | utils.compare_iterations(result, 4, check_iter) 45 | # Psi4 should test this; so optking shouldn't need to. 46 | # Now try alternative response 47 | # psi4.set_options( {'response_algorithm': 'simultaneous'} ) 48 | # o2.R = 1.232 49 | # 50 | # result = optking.optimize_psi4('dct') 51 | # 52 | # this_uhf = result['trajectory'][-1]['properties']['scf_total_energy'] 53 | # this_mp2 = result['trajectory'][-1]['properties']['mp2_total_energy'] 54 | # this_dct = result['energies'][-1] 55 | # assert psi4.compare_values(REF_uhf, this_uhf, 6, "UHF Energy"); 56 | # assert psi4.compare_values(REF_mp2, this_mp2, 6, "MP2 Energy"); 57 | # assert psi4.compare_values(REF_dct, this_dct, 6, "DC-06 Energy (simultaneous response)"); 58 | -------------------------------------------------------------------------------- /optking/tests/test_dimers_Bmat.py: -------------------------------------------------------------------------------- 1 | import psi4 2 | import optking 3 | import numpy as np 4 | import pytest 5 | 6 | # Test interfragment coordinate B matrix numerically. 7 | @pytest.mark.dimers 8 | def test_dimers_bmat(): 9 | h2oA = psi4.geometry( 10 | """ 11 | O 12 | H 1 1.0 13 | H 1 1.0 2 104.5 14 | """ 15 | ) 16 | Axyz = h2oA.geometry().np 17 | h2oB = psi4.geometry( 18 | """ 19 | O 20 | H 1 1.0 21 | H 1 1.0 2 104.5 22 | """ 23 | ) 24 | Bxyz = Axyz.copy() + 5.0 # Move B not right on top of A. 25 | 26 | dimer = { 27 | "Natoms per frag": [3, 3], 28 | "A Frag": 1, 29 | "A Ref Atoms": [[1], [2, 3], [3]], 30 | "B Frag": 2, 31 | "B Ref Atoms": [[4], [5, 6], [6]], 32 | } 33 | Itest = optking.dimerfrag.DimerFrag.fromUserDict(dimer) 34 | 35 | # Here is lower level method 36 | # Aref = [[0],[1,2],[2]] 37 | # Bref = [[0],[1,2],[2]] 38 | # Itest = optking.dimerfrag.DimerFrag(0,Aref,1,Bref) 39 | 40 | Itest.update_reference_geometry(Axyz, Bxyz) 41 | print(Itest) 42 | 43 | max_error = Itest.test_B(Axyz, Bxyz) 44 | 45 | print("Max. difference between analytic and numerical B matrix: {:8.3e}".format(max_error)) 46 | assert max_error < 1.0e-9 47 | -------------------------------------------------------------------------------- /optking/tests/test_dimers_h2o.py: -------------------------------------------------------------------------------- 1 | import psi4 2 | import optking 3 | import numpy as np 4 | import pytest 5 | from .utils import utils 6 | 7 | # Demonstrate and test positioning two water molecules by specifying 8 | # their interfragment reference points and coordinates. 9 | @pytest.mark.dimers 10 | def test_dimerfrag_orient_h2o_dimers(): 11 | h2oA = psi4.geometry( 12 | """ 13 | O 14 | H 1 1.0 15 | H 1 1.0 2 104.5 16 | """ 17 | ) 18 | Axyz = h2oA.geometry().np 19 | 20 | h2oB = psi4.geometry( 21 | """ 22 | O 23 | H 1 1.0 24 | H 1 1.0 2 104.5 25 | """ 26 | ) 27 | Bxyz = Axyz.copy() + 5.0 # Move B not right on top of A. 28 | 29 | # Choose some reference atoms for each fragment. 30 | # These would be # the O atom, the point between the two H atoms, 31 | # and one of the hydrogen atoms for each fragment. 32 | 33 | dimer = { 34 | "Natoms per frag": [3, 3], 35 | "A Frag": 1, 36 | "A Ref Atoms": [[1], [2, 3], [3]], 37 | "A Label": "Water-A", # optional 38 | "B Frag": 2, 39 | "B Ref Atoms": [[4], [5, 6], [6]], 40 | "B Label": "Water-B", # optional 41 | } 42 | 43 | # The default weights are equal between involved atoms but 44 | # may be specified. Fragment labels are optional. 45 | Itest = optking.dimerfrag.DimerFrag.fromUserDict(dimer) 46 | Itest.update_reference_geometry(Axyz, Bxyz) 47 | # print(Itest) 48 | 49 | # Create arbitrary target for displacement with illustrative names. 50 | R_A1B1 = 3.4 51 | theta_A2A1B1 = 2.5 52 | theta_A1B1B2 = 2.7 53 | tau_A2A1B1B2 = -1.5 54 | phi_A3A2A1B1 = 0.3 55 | phi_A1B1B2B3 = 0.6 56 | 57 | q_target = np.array([R_A1B1, theta_A2A1B1, theta_A1B1B2, tau_A2A1B1B2, phi_A3A2A1B1, phi_A1B1B2B3]) 58 | Bxyz_new = Itest.orient_fragment(Axyz, Bxyz, q_target) 59 | 60 | # Test how we did 61 | Itest.update_reference_geometry(Axyz, Bxyz_new) 62 | rms_error = np.sqrt(np.mean((q_target - Itest.q_array()) ** 2)) 63 | print("RMS deviation from target interfragment coordinates: {:8.3e}".format(rms_error)) 64 | assert rms_error < 1.0e-10 65 | 66 | 67 | MP2minEnergy = -152.5352095 68 | 69 | 70 | @pytest.mark.dimers 71 | @pytest.mark.parametrize("option, iter", [("gau_tight", 13), ("interfrag_tight", 11)]) 72 | def test_dimers_h2o_auto(check_iter, option, iter): # auto reference pt. creation 73 | h2oD = psi4.geometry( 74 | """ 75 | 0 1 76 | H 0.280638 -1.591779 -0.021801 77 | O 0.351675 -1.701049 0.952490 78 | H -0.464013 -1.272980 1.251761 79 | -- 80 | 0 1 81 | H -0.397819 -1.918411 -2.373012 82 | O -0.105182 -1.256691 -1.722965 83 | H 0.334700 -0.589454 -2.277374 84 | nocom 85 | noreorient 86 | """ 87 | ) 88 | 89 | psi4.core.clean_options() 90 | psi4_options = { 91 | "basis": "aug-cc-pvdz", 92 | "geom_maxiter": 40, 93 | "frag_mode": "MULTI", 94 | "g_convergence": f"{option}", 95 | } 96 | psi4.set_options(psi4_options) 97 | 98 | newOptParams = {"interfrag_collinear_tol": 0.2} # increase to prevent too colinear reference points 99 | json_output = optking.optimize_psi4("mp2", **newOptParams) 100 | 101 | E = json_output["energies"][-1] 102 | assert psi4.compare_values(MP2minEnergy, E, 6, "MP2 Energy opt from afar, auto") 103 | 104 | utils.compare_iterations(json_output, iter, check_iter) 105 | -------------------------------------------------------------------------------- /optking/tests/test_dimers_mt_tyr_frozen_orientation.py: -------------------------------------------------------------------------------- 1 | # Constrained optimization of tyrosine side group with methylthiophene. 2 | # The relative orientation of the two monomers is fixed. The monomers 3 | # themselves and the distance between them are optimized. 4 | import psi4 5 | import optking 6 | 7 | # import numpy as np 8 | import pytest 9 | # import qcelemental as qcel 10 | # import qcengine as qcng 11 | from qcengine.testing import has_program 12 | 13 | @pytest.mark.long 14 | @pytest.mark.dimers 15 | @pytest.mark.skipif( 16 | (has_program("dftd3") or has_program("s-dftd3")) is False, 17 | reason="Neither DFTD3 nor s-DFTD3 is findable" 18 | ) 19 | def test_dimers_mt_tyr_frozen_orientation(): 20 | # Starting at R ~ 5 Angstroms 21 | init_xyz = """ 22 | C -1.258686 0.546935 0.436840 23 | H -0.683650 1.200389 1.102833 24 | C -0.699036 -0.349093 -0.396608 25 | C -2.693370 0.550414 0.355311 26 | H -3.336987 1.206824 0.952052 27 | C -3.159324 -0.343127 -0.536418 28 | H -4.199699 -0.558111 -0.805894 29 | S -1.883829 -1.212288 -1.301525 30 | C 0.786082 -0.656530 -0.606057 31 | H 1.387673 -0.016033 0.048976 32 | H 1.054892 -0.465272 -1.651226 33 | H 0.978834 -1.708370 -0.365860 34 | -- 35 | C -6.955593 -0.119764 -1.395442 36 | C -6.977905 -0.135060 1.376787 37 | C -7.111625 1.067403 -0.697024 38 | C -6.810717 -1.314577 -0.707746 39 | C -6.821873 -1.322226 0.678369 40 | C -7.122781 1.059754 0.689090 41 | H -7.226173 2.012097 -1.240759 42 | H -6.687348 -2.253224 -1.259958 43 | H -6.707325 -2.266920 1.222105 44 | H -7.246150 1.998400 1.241304 45 | O -6.944245 -0.111984 -2.805375 46 | H -7.058224 0.807436 -3.049180 47 | C -6.990227 -0.143507 2.907714 48 | H -8.018305 -0.274985 3.264065 49 | H -6.592753 0.807024 3.281508 50 | H -6.368443 -0.968607 3.273516 51 | nocom 52 | unit angstrom 53 | """ 54 | # Note that nocom is needed so psi4 does not move the fragment COM's. 55 | 56 | # Define the reference atoms for each fragment, as a linear combination 57 | # of the positions of one or more atoms of the fragment. 58 | # If no weights are given, then the atoms are equally weighted. 59 | MTdimer = { 60 | "Natoms per frag": [12, 16], 61 | "A Frag": 1, 62 | "A Ref Atoms": [[1, 3, 4, 6, 8], [8], [11]], 63 | "A Label": "methylthiophene", 64 | "B Frag": 2, 65 | "B Ref Atoms": [[13, 14, 15, 16, 17, 18], [13], [15]], 66 | "B Label": "tyrosine", 67 | "Frozen": ["theta_A", "theta_B", "tau", "phi_A", "phi_B"], 68 | } 69 | # Here are the dimer coordinates that are used with their definitions. 70 | # R : Distance A1 to B1 71 | # theta_A : Angle, A2-A1-B1 72 | # theta_B : Angle, A1-B1-B2 73 | # tau : Dihedral angle, A2-A1-B1-B2 74 | # phi_A : Dihedral angle, A3-A2-A1-B1 75 | # phi_B : Dihedral angle, A1-B1-B2-B3 76 | 77 | # mTmol = qcel.models.Molecule.from_data(init_xyz) 78 | # Build the psi4 molecule. 79 | MTmol = psi4.geometry(init_xyz) 80 | 81 | # To see the values of the interfragment coordinates, do this: 82 | # MTdimerCoord = optking.dimerfrag.DimerFrag.fromUserDict(MTdimer) 83 | # Axyz = MTmol.geometry().np[0:12,] 84 | # Bxyz = MTmol.geometry().np[12:,] 85 | # MTdimerCoord.update_reference_geometry(Axyz, Bxyz) 86 | # print( MTdimerCoord ) 87 | # quit() 88 | 89 | # input_data = {"input_specification": { 90 | # "model": { 91 | # "method": "B3LYP-d3mbj", 92 | # "basis": "6-31G(d)"}, 93 | # "keywords": {"d_convergence": 9} 94 | # }, 95 | # "keywords": { 96 | # "frag_mode": "multi", 97 | # "interfrag_coords": str(MTdimer)}, 98 | # "initial_molecule": mTmol 99 | # } 100 | 101 | # opt_input = qcel.models.OptimizationInput(**input_data) 102 | # result = qcng.compute_procedure(opt_input, "optking") 103 | 104 | # For the moment, 'interfrag_coords' is a non-standard keyword and so 105 | # must be passed like this. 106 | # Optimize fragments and R but not interfragment angular coordinates. 107 | # psi4.set_options({"d_convergence": 9, "basis": "6-31G(d)", "interfrag_coords": str(MTdimer)}) 108 | # result = optking.optimize_psi4("b3lyp-d3mbj") 109 | psi4.set_options({"d_convergence": 9, "basis": "6-31G(d)"}) 110 | result = optking.optimize_psi4("b3lyp-d3mbj", **{"interfrag_coords": str(MTdimer)}) 111 | 112 | E = result["energies"][-1] 113 | 114 | REF_631Gd_Energy = -939.169521 115 | # REF_321G_Energy = -934.237170 116 | assert psi4.compare_values(REF_631Gd_Energy, E, 4, "B3LYP-D3MBJ energy") # TEST 117 | -------------------------------------------------------------------------------- /optking/tests/test_dimers_ne2.py: -------------------------------------------------------------------------------- 1 | import psi4 2 | import optking 3 | import numpy as np 4 | import pytest 5 | from .utils import utils 6 | 7 | # Optimized neon dimer 8 | MP2minEnergy = -257.4109749 9 | 10 | #! (Ne)_2 with interfrag coordinates, specifying ref atoms, from long-range 11 | @pytest.mark.dimers 12 | def test_dimers_ne2_long(check_iter): 13 | # Test from long distance start. 14 | ne2 = psi4.geometry( 15 | """ 16 | 0 1 17 | Ne 0.0 0.0 0.0 18 | -- 19 | 0 1 20 | Ne 4.0 0.0 0.0 21 | nocom 22 | """ 23 | ) 24 | 25 | psi4_options = { 26 | "basis": "aug-cc-pvdz", 27 | "geom_maxiter": 30, 28 | "frag_mode": "MULTI", 29 | "frag_ref_atoms": [[[1]], [[2]]], # reference point atoms, numbering now total 30 | "g_convergence": "gau_verytight", 31 | } 32 | psi4.set_options(psi4_options) 33 | json_output = optking.optimize_psi4("mp2") 34 | E = json_output["energies"][-1] 35 | assert psi4.compare_values(MP2minEnergy, E, 6, "MP2 Energy opt from afar") 36 | utils.compare_iterations(json_output, 14, check_iter) 37 | 38 | 39 | #! (Ne)_2 with interfrag coordinates, specifying ref atoms, from short-range 40 | @pytest.mark.dimers 41 | def test_dimers_ne2_short(check_iter): 42 | # Test from short distance start. 43 | ne2 = psi4.geometry( 44 | """ 45 | 0 1 46 | Ne 0.0 0.0 0.0 47 | -- 48 | 0 1 49 | Ne 2.5 0.0 0.0 50 | nocom 51 | """ 52 | ) 53 | 54 | psi4_options = { 55 | "basis": "aug-cc-pvdz", 56 | "geom_maxiter": 30, 57 | "frag_mode": "MULTI", 58 | "frag_ref_atoms": [[[1]], [[2]]], # reference point atoms, numbering now total 59 | "g_convergence": "gau_verytight", 60 | } 61 | psi4.core.clean_options() 62 | psi4.set_options(psi4_options) 63 | json_output = optking.optimize_psi4("mp2") 64 | E = json_output["energies"][-1] 65 | assert psi4.compare_values(MP2minEnergy, E, 6, "MP2 Energy opt from close") 66 | utils.compare_iterations(json_output, 15, check_iter) 67 | 68 | 69 | #! (Ne)_2 with interfrag coordinates, auto-generated ref atoms 70 | @pytest.mark.dimers 71 | def test_dimers_ne2_auto(check_iter): # auto reference pt. creation 72 | ne2 = psi4.geometry( 73 | """ 74 | 0 1 75 | Ne 0.0 0.0 0.0 76 | -- 77 | 0 1 78 | Ne 3.0 0.0 0.0 79 | nocom 80 | """ 81 | ) 82 | 83 | psi4.core.clean_options() 84 | psi4_options = {"basis": "aug-cc-pvdz", "geom_maxiter": 30, "frag_mode": "MULTI", "g_convergence": "gau_verytight"} 85 | psi4.set_options(psi4_options) 86 | json_output = optking.optimize_psi4("mp2") 87 | E = json_output["energies"][-1] 88 | assert psi4.compare_values(MP2minEnergy, E, 6, "MP2 Energy opt from afar, auto") 89 | utils.compare_iterations(json_output, 13, check_iter) 90 | 91 | 92 | #! (Ne)_2 with interfrag coordinates, using 1/R distance 93 | @pytest.mark.dimers 94 | def test_dimers_ne2_inverseR(check_iter): 95 | ne2 = psi4.geometry( 96 | """ 97 | 0 1 98 | Ne 0.0 0.0 0.0 99 | -- 100 | 0 1 101 | Ne 3.0 0.0 0.0 102 | nocom 103 | """ 104 | ) 105 | 106 | psi4.core.clean_options() 107 | psi4_options = { 108 | "basis": "aug-cc-pvdz", 109 | "geom_maxiter": 20, 110 | "frag_mode": "MULTI", 111 | "g_convergence": "gau_verytight", 112 | "frag_ref_atoms": [[[1]], [[2]]], # atoms for reference points 113 | "interfrag_dist_inv": True, 114 | "test_B": True, 115 | } 116 | psi4.set_options(psi4_options) 117 | json_output = optking.optimize_psi4("mp2") 118 | E = json_output["energies"][-1] 119 | assert psi4.compare_values(MP2minEnergy, E, 6, "MP2 Energy opt from afar, auto") 120 | utils.compare_iterations(json_output, 10, check_iter) 121 | 122 | 123 | #! (Ne)_2 with interfrag coordinates, using full user dict input 124 | @pytest.mark.dimers 125 | def test_dimers_ne2_dict(): 126 | ne2 = psi4.geometry( 127 | """ 128 | 0 1 129 | Ne 0.0 0.0 0.0 130 | Ne 4.0 0.0 0.0 131 | nocom 132 | """ 133 | ) 134 | psi4.core.clean_options() 135 | psi4_options = {"basis": "aug-cc-pvdz", "geom_maxiter": 30, "frag_mode": "MULTI", "g_convergence": "gau_verytight"} 136 | 137 | dimer = { 138 | "Natoms per frag": [1, 1], 139 | "A Frag": 1, 140 | "A Ref Atoms": [[1]], 141 | "A Label": "Ne atom 1", 142 | "B Frag": 2, 143 | "B Ref Atoms": [[2]], 144 | "B Label": "Ne atom 2", 145 | } 146 | 147 | psi4.set_options(psi4_options) 148 | json_output = optking.optimize_psi4("mp2", interfrag_coords=str(dimer)) 149 | E = json_output["energies"][-1] 150 | assert psi4.compare_values(MP2minEnergy, E, 6, "MP2 Energy opt from afar, auto") 151 | -------------------------------------------------------------------------------- /optking/tests/test_dimers_orient.py: -------------------------------------------------------------------------------- 1 | import optking 2 | import pytest 3 | 4 | # Tests the dimer orientation code. 5 | # 1) Create random geometries for fragments with NA and NB atoms, respectively. 6 | # 2) Randomly choose 1-3 atoms on each fragment with which to define the 7 | # reference points on each fragment. Assign them random weights. 8 | # The linear combination prescribes each reference point. 9 | # 3) Choose an arbitrary displacement of the interfragment coordinates, rotate 10 | # the geometry of second fragment to match precisely the new values. 11 | # 4) If number of atoms in a fragment is <3, then tests code for all the 12 | # annoying situations in which some of the 6 interfragment coordinates drop out. 13 | 14 | 15 | @pytest.mark.dimers 16 | @pytest.mark.parametrize("NA,NB,seed", [(i, j, s) for i in range(1, 5) for j in range(1, 5) for s in range(1, 5)]) 17 | def test_dimerfrag_orient(NA, NB, seed): 18 | rms_error = optking.dimerfrag.test_orient(NA, NB, randomSeed=seed) 19 | print("Error: {:10.5e}".format(rms_error)) 20 | assert rms_error < 1.0e-10 21 | -------------------------------------------------------------------------------- /optking/tests/test_frozen_cart_and_backstep.py: -------------------------------------------------------------------------------- 1 | import psi4 2 | import optking 3 | import pytest 4 | from .utils import utils 5 | import numpy as np 6 | from qcelemental import constants 7 | bohr2angstroms = constants.bohr2angstroms 8 | 9 | #! Various constrained energy minimizations of HOOH with cc-pvdz RHF. 10 | #! Cartesian-coordinate constrained optimizations of HOOH in Cartesians. 11 | #! 1. Cartesian optimization. 12 | #! 2. Cartesian optimization with frozen H's. 13 | #! 3. Cartesian optimization with frozen O's. 14 | HOOH_E = -150.7866742 # TEST 15 | HOOH_E_frozen_H_xyz = -150.7866491 # TEST 16 | HOOH_E_frozen_O_xyz = -150.7866390 # TEST 17 | 18 | f0 = """""" 19 | # Freeze H xyz in HOOH. 20 | f1 = """ 1 Xyz 4 xYz """ 21 | # Freeze O xyz in HOOH. 22 | f2 = """ 2 xyz 3 xyz """ 23 | # Freeze H xyz with individual input entries in HOOH. 24 | f3 = """ 25 | 1 x 26 | 1 y 27 | 1 Z 28 | 4 x 29 | 4 Y 30 | 4 z """ 31 | 32 | opt0 = {"frozen_cartesian": f0} 33 | opt1 = {"frozen_cartesian": f1} 34 | opt2 = {"frozen_cartesian": f2} 35 | opt3 = {"frozen_cartesian": f3} 36 | opt4 = {"frozen_cartesian": f1, "opt_coordinates": "redundant"} 37 | 38 | optking__freeze_params = [ 39 | (opt0, HOOH_E, 15), 40 | (opt1, HOOH_E_frozen_H_xyz, 13), 41 | (opt2, HOOH_E_frozen_O_xyz, 13), 42 | (opt3, HOOH_E_frozen_H_xyz, 13), 43 | (opt4, HOOH_E_frozen_H_xyz, 13), 44 | ] 45 | 46 | 47 | @pytest.mark.parametrize( 48 | "options, expected, num_steps", 49 | # freeze_params, 50 | optking__freeze_params, 51 | ids=["Only backstep", "freeze H", "freeze O", "freeze individual x,y,z", "freeze then change coord"], 52 | ) 53 | def test_hooh_freeze_xyz_Hs(check_iter, options, expected, num_steps): 54 | 55 | hooh = psi4.geometry( 56 | """ 57 | H 0.90 0.80 0.5 58 | O 0.00 0.70 0.0 59 | O 0.00 -0.70 0.0 60 | H -0.90 -0.80 0.5 61 | """ 62 | ) 63 | 64 | psi4.core.clean_options() 65 | psi4_options = { 66 | "basis": "cc-pvdz", 67 | "optking__opt_coordinates": "cartesian", 68 | "optking__g_convergence": "gau_tight", 69 | "optking__geom_maxiter": 20, 70 | "optking__consecutive_backsteps": 1, 71 | } 72 | psi4.set_options(psi4_options) 73 | psi4.set_options(options) 74 | 75 | json_output = optking.optimize_psi4("hf") 76 | 77 | thisenergy = json_output["energies"][-1] # TEST 78 | assert psi4.compare_values(expected, thisenergy, 6) # TEST 79 | 80 | utils.compare_iterations(json_output, num_steps, check_iter) 81 | 82 | 83 | #! test if we can keep oxygen atom from moving off of the point (1,1,1) 84 | def test_frozen_cart_h2o(check_iter): 85 | 86 | h2o = psi4.geometry( 87 | """ 88 | O 1.000000 1.000000 1.000000 89 | H 2.000000 1.000000 1.000000 90 | H 1.000000 2.000000 1.000000 91 | units angstrom 92 | no_com 93 | no_reorient 94 | """ 95 | ) 96 | 97 | psi4.core.clean_options() 98 | psi4_options = {"basis": "cc-pvdz", "reference": "rhf", "scf_type": "df", "max_energy_g_convergence": 7} 99 | psi4.set_options(psi4_options) 100 | psi4.set_options({"optking__frozen_cartesian": """1 xyz"""}) 101 | 102 | json_output = optking.optimize_psi4("hf") 103 | 104 | optGeom = bohr2angstroms*np.asarray(json_output['final_molecule']['geometry']).reshape(-1,3) 105 | 106 | thisenergy = json_output["energies"][-1] 107 | assert psi4.compare_values(-76.0270327834836, thisenergy, 6, "RHF Energy") 108 | assert psi4.compare_values(optGeom[0,0], 1.0, 6, "X Frozen coordinate") 109 | assert psi4.compare_values(optGeom[0,1], 1.0, 6, "Y Frozen coordinate") 110 | assert psi4.compare_values(optGeom[0,2], 1.0, 6, "Z Frozen coordinate") 111 | 112 | utils.compare_iterations(json_output, 6, check_iter) 113 | 114 | 115 | #! test h2o dimer with frozen oxygen atoms 116 | def test_frozen_cart_h2o_dimer(check_iter): 117 | h2oDimer = psi4.geometry( 118 | """ 119 | O -0.3289725 -1.4662712 0.0000000 120 | H -1.3007725 -1.5158712 0.0000000 121 | H 0.0634274 0.4333287 0.0000000 122 | O 0.3010274 1.3644287 0.0000000 123 | H 0.8404274 1.3494287 0.7893000 124 | H 0.8404274 1.3494287 -0.7893000 125 | units = angstrom 126 | no_com 127 | no_reorient 128 | """ 129 | ) 130 | inputGeom= np.asarray(h2oDimer.geometry()) 131 | 132 | psi4.core.clean_options() 133 | psi4_options = { 134 | "basis": "cc-pVDZ", 135 | "optking__g_convergence": "gau_tight", 136 | "optking__frozen_cartesian": """ 1 xyz 4 xyz """, 137 | "optking__geom_maxiter": 40, 138 | } 139 | psi4.set_options(psi4_options) 140 | 141 | json_output = optking.optimize_psi4("mp2") 142 | 143 | optGeom = np.asarray(json_output['final_molecule']['geometry']).reshape(-1,3) 144 | 145 | thisenergy = json_output["energies"][-1] # TEST 146 | assert psi4.compare_values(-152.47381494, thisenergy, 8, "MP2 Energy") 147 | 148 | assert psi4.compare_values(inputGeom[0,0], optGeom[0,0], 6, "O1 X Frozen coordinate") 149 | assert psi4.compare_values(inputGeom[0,1], optGeom[0,1], 6, "O1 Y Frozen coordinate") 150 | assert psi4.compare_values(inputGeom[0,2], optGeom[0,2], 6, "O1 Z Frozen coordinate") 151 | assert psi4.compare_values(inputGeom[3,0], optGeom[3,0], 6, "O2 X Frozen coordinate") 152 | assert psi4.compare_values(inputGeom[3,1], optGeom[3,1], 6, "O2 Y Frozen coordinate") 153 | assert psi4.compare_values(inputGeom[3,2], optGeom[3,2], 6, "O2 Z Frozen coordinate") 154 | assert np.abs(inputGeom[1,0] - optGeom[1,0]) > 0.01 # Check a not-frozen coordinate. 155 | 156 | utils.compare_iterations(json_output, 25, True) 157 | 158 | -------------------------------------------------------------------------------- /optking/tests/test_frozen_internals.py: -------------------------------------------------------------------------------- 1 | #! Various constrained energy minimizations of HOOH with cc-pvdz RHF 2 | #! Internal-coordinate constraints in internal-coordinate optimizations. 3 | import pytest 4 | 5 | import psi4 6 | import optking 7 | from .utils import utils 8 | 9 | 10 | OH_frozen_stre_rhf = -150.781130356 # TEST 11 | OOH_frozen_bend_rhf = -150.786372411 # TEST 12 | HOOH_frozen_dihedral_rhf = -150.786766848 # TEST 13 | 14 | f1 = {"frozen_distance": "1 2 3 4"} 15 | f2 = {"frozen_bend": "1 2 3 2 3 4"} 16 | f3 = {"frozen_dihedral": "1 2 3 4"} 17 | 18 | optking__frozen_coords = [ 19 | (f1, OH_frozen_stre_rhf, 9), 20 | (f2, OOH_frozen_bend_rhf, 6), 21 | (f3, HOOH_frozen_dihedral_rhf, 6) 22 | ] 23 | 24 | @pytest.mark.parametrize( 25 | "option, expected, num_steps", 26 | optking__frozen_coords, 27 | ids=["frozen stretch", "frozen bend", "frozen dihedral"] 28 | ) 29 | def test_frozen_coords(option, expected, num_steps, check_iter): 30 | # Constrained minimization with frozen bond, bend, and torsion 31 | hooh = psi4.geometry( 32 | """ 33 | H 34 | O 1 0.90 35 | O 2 1.40 1 100.0 36 | H 3 0.90 2 100.0 1 115.0 37 | """ 38 | ) 39 | 40 | psi4.core.clean_options() 41 | 42 | psi4_options = { 43 | "diis": "false", 44 | "basis": "cc-PVDZ", 45 | "scf_type": "pk", 46 | "print": 4, 47 | "g_convergence": "gau_tight" 48 | } 49 | psi4.set_options(psi4_options) 50 | psi4.set_options(option) 51 | 52 | json_output = optking.optimize_psi4("hf") 53 | thisenergy = json_output["energies"][-1] 54 | 55 | assert psi4.compare_values(expected, thisenergy, 6) # TEST 56 | utils.compare_iterations(json_output, num_steps, check_iter) 57 | 58 | 59 | def test_butane_frozen(check_iter): 60 | _ = psi4.geometry("pubchem:butane") 61 | 62 | psi4.core.clean_options() 63 | psi4_options = { 64 | "basis": "6-31G", 65 | "g_convergence": "gau_tight", 66 | } 67 | psi4.set_options(psi4_options) 68 | 69 | tmp = {"freeze_all_dihedrals": True,} 70 | result = optking.optimize_psi4("scf", **tmp) 71 | E1 = result["energies"][-1] # TEST 72 | 73 | psi4.core.clean_options() 74 | psi4_options = { 75 | "basis": "6-31G", 76 | "g_convergence": "gau_tight", 77 | "frozen_dihedral": """ 78 | 1 2 4 12 79 | 1 2 4 13 80 | 1 2 4 14 81 | 2 1 3 9 82 | 2 1 3 10 83 | 2 1 3 11 84 | 3 1 2 4 85 | 3 1 2 7 86 | 3 1 2 8 87 | 4 2 1 5 88 | 4 2 1 6 89 | 5 1 2 7 90 | 5 1 2 8 91 | 5 1 3 9 92 | 5 1 3 10 93 | 5 1 3 11 94 | 6 1 2 7 95 | 6 1 2 8 96 | 6 1 3 9 97 | 6 1 3 10 98 | 6 1 3 11 99 | 7 2 4 12 100 | 7 2 4 13 101 | 7 2 4 14 102 | 8 2 4 12 103 | 8 2 4 13 104 | 8 2 4 14 105 | """ 106 | } 107 | psi4.set_options(psi4_options) 108 | result = optking.optimize_psi4("scf") 109 | E2 = result["energies"][-1] 110 | 111 | assert psi4.compare_values(E1, E2, 8, "RHF energy") # TEST 112 | utils.compare_iterations(result, 5, check_iter) 113 | 114 | def test_butane_skip_frozen(check_iter): 115 | _ = psi4.geometry("pubchem:butane") 116 | 117 | psi4.core.clean_options() 118 | psi4_options = { 119 | "basis": "6-31G", 120 | "g_convergence": "gau_tight", 121 | } 122 | tmp = { 123 | "freeze_all_dihedrals": True, 124 | "unfreeze_dihedrals": """ 125 | 8 2 4 12 126 | 8 2 4 13 127 | 8 2 4 14 128 | 3 1 2 8 129 | 5 1 2 8 130 | 6 1 2 8"""} 131 | 132 | psi4.set_options(psi4_options) 133 | 134 | result = optking.optimize_psi4("scf", **tmp) 135 | E1 = result["energies"][-1] # TEST 136 | 137 | psi4.core.clean_options() 138 | psi4_options = { 139 | "basis": "6-31G", 140 | "g_convergence": "gau_tight", 141 | "frozen_dihedral": """ 142 | 1 2 4 12 143 | 1 2 4 13 144 | 1 2 4 14 145 | 2 1 3 9 146 | 2 1 3 10 147 | 2 1 3 11 148 | 3 1 2 4 149 | 3 1 2 7 150 | 4 2 1 5 151 | 4 2 1 6 152 | 5 1 2 7 153 | 5 1 3 9 154 | 5 1 3 10 155 | 5 1 3 11 156 | 6 1 2 7 157 | 6 1 3 9 158 | 6 1 3 10 159 | 6 1 3 11 160 | 7 2 4 12 161 | 7 2 4 13 162 | 7 2 4 14 163 | """ 164 | } 165 | psi4.set_options(psi4_options) 166 | result = optking.optimize_psi4("scf") 167 | E2 = result["energies"][-1] 168 | 169 | assert psi4.compare_values(E1, E2, 8, "RHF energy") # TEST 170 | utils.compare_iterations(result, 5, check_iter) 171 | -------------------------------------------------------------------------------- /optking/tests/test_hbond.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import numpy as np 3 | 4 | import optking.stre 5 | import optking.bend 6 | import optking.tors 7 | import optking.intcosMisc 8 | import optking.addIntcos 9 | import optking.displace 10 | import optking.optparams as op 11 | import optking.caseInsensitiveDict 12 | 13 | 14 | # stretch displacement 15 | # bend displacement 16 | # whether h bond should be detected 17 | @pytest.mark.skip 18 | @pytest.mark.parametrize( 19 | "options, expected", [((0, 0), True), ((-0.375, 0), False), ((0, -np.pi / 8), False), ((0.8, 0), False)] 20 | ) 21 | def test_hydrogen_bonds(options, expected): 22 | 23 | # Manually construct water dimer in single frag mode 24 | # Tests fail when run with entire suite due to op.Params missing 25 | op.Params = op.OptParams(optking.caseInsensitiveDict.CaseInsensitiveDict({})) 26 | 27 | # Geometry in Bohr 28 | geom = np.array( 29 | [ 30 | [-1.2824641813, -2.3421356740, 0.0913301558], 31 | [-0.0314167971, -3.6520400907, 0.0340038272], 32 | [-1.9858966815, -2.4709212198, 1.7566192883], 33 | [1.3419482749, 2.4585411267, -0.1017720514], 34 | [0.4210461244, 0.8871180358, -0.1345980555], 35 | [0.6522116213, 3.3884042683, -1.4903045984], 36 | ] 37 | ) 38 | 39 | Z = [8, 1, 1, 8, 1, 1] 40 | masses = [15.999, 1.008, 1.008, 15.999, 1.008, 1.008] 41 | 42 | s1 = optking.stre.Stre(0, 1) 43 | s2 = optking.stre.Stre(0, 2) 44 | s3 = optking.stre.Stre(0, 4) 45 | s4 = optking.stre.Stre(3, 4) 46 | s5 = optking.stre.Stre(3, 5) 47 | 48 | b1 = optking.bend.Bend(1, 0, 2) 49 | b2 = optking.bend.Bend(1, 0, 4) 50 | b3 = optking.bend.Bend(2, 0, 4) 51 | b4 = optking.bend.Bend(0, 4, 3) 52 | b5 = optking.bend.Bend(4, 3, 5) 53 | 54 | t1 = optking.bend.Bend(1, 0, 4, 3) 55 | t2 = optking.bend.Bend(2, 0, 4, 3) 56 | t3 = optking.bend.Bend(0, 4, 3, 5) 57 | 58 | intcos = [s1, s2, s3, s4, s5, b1, b2, b3, b4, b5, t1, t2, t3] 59 | 60 | o_frag = optking.frag.Frag(Z, geom, masses, intcos) 61 | 62 | dq = np.zeros(13) 63 | dq[2] = options[0] 64 | dq[8] = options[1] 65 | 66 | # Displace in Bohr and degrees. Do four smaller displacements 67 | optking.displace.displace_frag(o_frag, dq) 68 | o_frag.add_h_bonds() 69 | 70 | assert (optking.stre.HBond(0, 4) in o_frag.intcos) == expected 71 | 72 | 73 | # test_hydrogen_bonds( (-0.5,0), True) 74 | -------------------------------------------------------------------------------- /optking/tests/test_hf_g_keywords.py: -------------------------------------------------------------------------------- 1 | import psi4 2 | import optking 3 | from .utils import utils 4 | 5 | # HF SCF CC-PVDZ geometry optimization of HOOH with Z-matrix input 6 | def test_B_dB_matrices(check_iter): 7 | 8 | hooh = psi4.geometry( 9 | """ 10 | H 11 | O 1 0.9 12 | O 2 1.4 1 100.0 13 | H 3 0.9 2 100.0 1 114.0 14 | """ 15 | ) 16 | 17 | psi4.core.clean_options() 18 | psi4_options = { 19 | "basis": "cc-pvdz", 20 | "g_convergence": "gau_tight", 21 | "scf_type": "pk", 22 | "TEST_B": True, 23 | "TEST_DERIVATIVE_B": True, 24 | "G_CONVERGENCE": "gau_tight", 25 | } 26 | psi4.set_options(psi4_options) 27 | 28 | json_output = optking.optimize_psi4("hf") # Uses default program (psi4) 29 | 30 | E = json_output["energies"][-1] # TEST 31 | nucenergy = json_output["trajectory"][-1]["properties"]["nuclear_repulsion_energy"] # TEST 32 | refnucenergy = 38.06177 # TEST 33 | refenergy = -150.786766850 # TEST 34 | assert "test_b" in json_output["keywords"] # TEST 35 | assert "test_derivative_b" in json_output["keywords"] # TEST 36 | assert "g_convergence" in json_output["keywords"] # TEST 37 | assert psi4.compare_values(refnucenergy, nucenergy, 3, "Nuclear repulsion energy") # TEST 38 | assert psi4.compare_values(refenergy, E, 8, "Reference energy") # TEST 39 | utils.compare_iterations(json_output, 7, check_iter) 40 | 41 | 42 | def test_maxiter(check_iter): 43 | 44 | h2o = psi4.geometry( 45 | """ 46 | O 47 | H 1 1.0 48 | H 1 1.0 2 104.5 49 | """ 50 | ) 51 | 52 | psi4.core.clean_options() 53 | psi4options = { 54 | # Throw a bunch of options at psi4 55 | "diis": 0, 56 | "basis": "STO-3G", 57 | "e_convergence": 1e-10, 58 | "d_convergence": 1e-10, 59 | "scf_type": "PK", 60 | "geom_maxiter": 2, 61 | } 62 | psi4.set_options(psi4options) 63 | 64 | json_output = optking.optimize_psi4("hf") 65 | 66 | assert "geom_maxiter" in json_output["keywords"] # TEST 67 | assert "Maximum number of steps exceeded" in json_output["error"]["error_message"] # TEST 68 | assert "OptError" in json_output["error"]["error_type"] # TEST 69 | 70 | 71 | # Test the energy of geometry output, when maxiter is reached. 72 | def test_maxiter_geom(): 73 | 74 | h2o = psi4.geometry( 75 | """ 76 | O 77 | H 1 1.0 78 | H 1 1.0 2 104.5 79 | """ 80 | ) 81 | 82 | psi4.core.clean_options() 83 | psi4options = {"basis": "cc-pvdz", "e_convergence": 10, "d_convergence": 10, "scf_type": "pk", "geom_maxiter": 2} 84 | psi4.set_options(psi4options) 85 | 86 | result = optking.optimize_psi4("hf") 87 | print(result) 88 | 89 | nextStepSchema = result["final_molecule"] # TEST 90 | nextStepMolecule = psi4.core.Molecule.from_schema(nextStepSchema) # TEST 91 | psi4.core.set_active_molecule(nextStepMolecule) # TEST 92 | psi4.set_options(psi4options) 93 | nextStepEnergy = psi4.driver.energy("scf/cc-pvdz") # TEST 94 | REF_energy = -76.0270381300 # TEST 95 | REF_energy = -76.0270521 # TEST changed. Energy different now that update occurs 96 | assert psi4.compare_values(REF_energy, nextStepEnergy, 5, "Energy of next-step molecule") 97 | # TEST 98 | -------------------------------------------------------------------------------- /optking/tests/test_hf_g_opt.py: -------------------------------------------------------------------------------- 1 | #! SCF STO-3G geometry optimzation, with Z-matrix input 2 | import json 3 | import psi4 4 | import optking 5 | from .utils import utils 6 | 7 | 8 | def test_hf_g_h2o(check_iter): 9 | h2o = psi4.geometry( 10 | """ 11 | O 12 | H 1 1.0 13 | H 1 1.0 2 104.5 14 | """ 15 | ) 16 | 17 | psi4.core.clean_options() 18 | psi4_options = { 19 | "diis": False, 20 | "basis": "sto-3g", 21 | "e_convergence": 10, 22 | "d_convergence": 10, 23 | "scf_type": "pk", 24 | } 25 | psi4.set_options(psi4_options) 26 | 27 | json_output = optking.optimize_psi4("hf") 28 | 29 | E = json_output["energies"][-1] # TEST 30 | nucenergy = json_output["trajectory"][-1]["properties"]["nuclear_repulsion_energy"] # TEST 31 | refnucenergy = 8.9064983474 # TEST 32 | refenergy = -74.9659011923 # TEST 33 | assert psi4.compare_values(refnucenergy, nucenergy, 3, "Nuclear repulsion energy") # TEST 34 | assert psi4.compare_values(refenergy, E, 6, "Reference energy") # TEST 35 | utils.compare_iterations(json_output, 4, check_iter) 36 | 37 | 38 | #! SCF cc-pVDZ geometry optimzation, Z-matrix input, tight convergence 39 | def test_hf_g_h2o_tight(check_iter): 40 | h2o = psi4.geometry( 41 | """ 42 | O 43 | H 1 1.0 44 | H 1 1.0 2 104.5 45 | """ 46 | ) 47 | 48 | psi4.core.clean_options() 49 | psi4_options = { 50 | "diis": False, 51 | "basis": "cc-pvdz", 52 | "e_convergence": 10, 53 | "d_convergence": 10, 54 | "g_convergence": "gau_tight", 55 | "scf_type": "pk", 56 | } 57 | psi4.set_options(psi4_options) 58 | 59 | json_output = optking.optimize_psi4("hf") 60 | 61 | E = json_output["energies"][-1] # TEST 62 | REF_energy = -76.02705351276 # TEST 63 | assert psi4.compare_values(REF_energy, E, 8, "RHF energy") # TEST 64 | utils.compare_iterations(json_output, 6, check_iter) 65 | 66 | 67 | def test_hf_g_h2o_large(check_iter): 68 | h2o = psi4.geometry( 69 | """ 70 | O 71 | H 1 1.0 72 | H 1 1.0 2 104.5 73 | """ 74 | ) 75 | 76 | psi4.core.clean_options() 77 | psi4_options = { 78 | "basis": "cc-pvtz", 79 | "e_convergence": 10, 80 | "d_convergence": 10, 81 | "g_convergence": "gau_tight", 82 | "scf_type": "pk", 83 | } 84 | psi4.set_options(psi4_options) 85 | 86 | json_output = optking.optimize_psi4("hf") 87 | 88 | E = json_output["energies"][-1] # TEST 89 | REF_energy = -76.05776970191 # TEST 90 | assert psi4.compare_values(REF_energy, E, 8, "RHF energy") # TEST 91 | utils.compare_iterations(json_output, 6, check_iter) 92 | 93 | 94 | #! SCF cc-pVDZ geometry optimzation of ketene, starting from bent structure 95 | def test_hf_g_ketene(check_iter): 96 | 97 | ketene = psi4.geometry( 98 | """ 99 | 0 1 100 | H 101 | C 1 1.1 102 | C 2 1.3 1 130.0 103 | H 2 1.1 3 110.0 1 180.0 104 | O 3 1.1 4 120.0 1 180.0 105 | """ 106 | ) 107 | 108 | psi4.core.clean_options() 109 | psi4_options = {"basis": "cc-pvdz", "g_convergence": "gau_tight", "scf_type": "pk"} 110 | psi4.set_options(psi4_options) 111 | 112 | result = optking.optimize_psi4("scf") 113 | optking.logger.info(json.dumps(result, indent=2)) 114 | E = result["energies"][-1] # TEST 115 | REF_energy = -151.7410313803 # TEST 116 | assert psi4.compare_values(REF_energy, E, 8, "RHF energy") # TEST 117 | utils.compare_iterations(result, 8, check_iter) 118 | -------------------------------------------------------------------------------- /optking/tests/test_hooh_ext_force.py: -------------------------------------------------------------------------------- 1 | #! Various constrained energy minimizations of HOOH with cc-pvdz RHF. 2 | #! For "fixed" coordinates, the final value is provided by the user. 3 | import pytest 4 | import psi4 5 | import optking 6 | from .utils import utils 7 | 8 | # Minimized energy with OH bonds pushed toward 0.950 Angstroms. 9 | OH_950_stre = -150.786669 10 | # Minimized energy with OOH angles pushed toward 105.0 degrees. 11 | OOH_105_bend = -150.786177 12 | # Minimized energy with HOOH torsion pushed toward 120.0 degrees. 13 | HOOH_120_dihedral = -150.786647 14 | # Minimize energy with the x and y coordinates of atom 1 pushed 15 | # to 1.0 and 1.0. Just for fun. 16 | HOOH_minimum = -150.7866742 17 | 18 | f1 = ({"ext_force_distance": "1 2 '-8.0*(x-0.950)' 3 4 '-8.0*(x-0.950)'"}, OH_950_stre, 9) 19 | f2 = ({"ext_force_bend": "1 2 3 '-8.0*(x-105.0)' 2 3 4 '-8.0*(x-105.0)'"}, OOH_105_bend, 17) 20 | f3 = ({"ext_force_dihedral": "1 2 3 4 '-8.0*(x-120.0)'"}, HOOH_120_dihedral, 15) 21 | f4 = ({"ext_force_cartesian": "1 x '-2.0*(x-1.0)' 1 y '-2.0*(x-1.0)'"}, HOOH_minimum, 10) 22 | # Same as f1, but 'soften'/dampen force at long range. 23 | f5 = ( 24 | { 25 | "ext_force_distance": "1 2 '-8.0 * (x-0.950) * exp(-20*abs(x-0.950) )' 3 4 '-8.0*(x-0.950) * exp(-20*abs(x-0.950))'" 26 | }, 27 | OH_950_stre, 28 | 13 29 | ) 30 | 31 | 32 | @pytest.mark.parametrize("option, expected, num_steps", [f1, f2, f3, f4, f5]) 33 | def test_hooh_fixed_OH_stre(option, expected, num_steps, check_iter): 34 | hooh = psi4.geometry( 35 | """ 36 | H 37 | O 1 0.90 38 | O 2 1.40 1 100.0 39 | H 3 0.90 2 100.0 1 115.0 40 | """ 41 | ) 42 | 43 | psi4.core.clean_options() 44 | psi4_options = {"diis": "false", "basis": "cc-pvdz", "g_convergence": "gau_tight"} 45 | psi4.set_options(psi4_options) 46 | 47 | json_output = optking.optimize_psi4("hf", **option) 48 | 49 | E = json_output["energies"][-1] 50 | assert psi4.compare_values(expected, E, 6, list(option.keys())[0]) 51 | utils.compare_iterations(json_output, num_steps, check_iter) 52 | -------------------------------------------------------------------------------- /optking/tests/test_irc_hooh.py: -------------------------------------------------------------------------------- 1 | # IRC for HOOH from cis confirmation. 2 | import psi4 3 | import optking 4 | import json 5 | from .utils import utils 6 | 7 | psi4.set_memory("2 GB") 8 | 9 | 10 | def test_hooh_irc(check_iter): 11 | energy_5th_IRC_pt = -150.812913276783 # TEST 12 | h2o2 = psi4.geometry( 13 | """ 14 | H 0.0000000000 0.9803530335 -0.8498671785 15 | O 0.0000000000 0.6988545188 0.0536419016 16 | O 0.0000000000 -0.6988545188 0.0536419016 17 | H 0.0000000000 -0.9803530335 -0.8498671785 18 | """ 19 | ) 20 | # Necessary since IRC will break C2h. 21 | h2o2.reset_point_group("c2") 22 | 23 | psi4.core.clean_options() 24 | 25 | psi4_options = { 26 | "basis": "dzp", 27 | "scf_type": "pk", 28 | "g_convergence": "gau_verytight", 29 | "opt_type": "irc", 30 | "geom_maxiter": 60, 31 | "full_hess_every": 0, 32 | } 33 | 34 | psi4.set_options(psi4_options) 35 | json_output = optking.optimize_psi4("hf") 36 | print(json.dumps(json_output, indent=2)) 37 | IRC = json_output["extras"]["irc_rxn_path"] 38 | 39 | print("%15s%15s%20s%15s" % ("Step Number", "Arc Distance", "Energy", "HOOH dihedral")) 40 | for step in IRC: 41 | print("%15d%15.5f%20.10f%15.5f" % (step["step_number"], step["arc_dist"], step["energy"], step["q"][5])) 42 | 43 | assert psi4.compare_values(energy_5th_IRC_pt, IRC[5]["energy"], 6, "Energy of 5th IRC point.") # TEST 44 | utils.compare_iterations(json_output, 45, check_iter) 45 | -------------------------------------------------------------------------------- /optking/tests/test_jsoninput.py: -------------------------------------------------------------------------------- 1 | import os 2 | import json 3 | 4 | import pytest 5 | import optking 6 | import psi4 7 | 8 | from qcelemental.models import OptimizationInput 9 | from qcelemental.testing import compare_values 10 | from .utils import utils 11 | from .psi4_helper import using_qcmanybody 12 | 13 | # Varying number of repulsion energy decimals to check. 14 | @pytest.mark.parametrize( 15 | "inp,expected,num_steps", 16 | [ 17 | pytest.param("json_h2o.json", (8.9064890670, -74.965901192, 3), 5), 18 | pytest.param("json_betapinene.json", (568.2219045869, -383.38105559, 1), 4), 19 | pytest.param("json_hooh_frozen.json", (37.969354880, -150.786372411, 2), 6), 20 | pytest.param("json_lif_cp.json", (8.95167, -106.8867587, 2, 3.016), 4, marks=using_qcmanybody), 21 | pytest.param("json_lif_nocp.json", (9.09281, -106.9208785, 2, 2.969), 5, marks=using_qcmanybody), 22 | ], 23 | ) 24 | def test_input_through_json(inp, expected, num_steps, check_iter): 25 | with open(os.path.join(os.path.dirname(__file__), inp)) as input_data: 26 | input_copy = json.load(input_data) 27 | if "lif" in inp: 28 | from qcmanybody.models.generalized_optimization import GeneralizedOptimizationInput 29 | opt_schema = GeneralizedOptimizationInput(**input_copy) 30 | else: 31 | opt_schema = OptimizationInput(**input_copy) 32 | 33 | # Note it's important to have `input_specification.schema_name = "qcschema_manybodyspecification"` 34 | # in your json for a MBE optimization. Or you can explicitly construct a 35 | # GeneralizedOptimizationInput like above. 36 | 37 | # optking.run_json_file(os.path.join(os.path.dirname(__file__), inp)) 38 | json_dict = optking.optimize_qcengine(input_copy) 39 | 40 | if "lif" in inp: 41 | assert inp, json_dict["trajectory"][-1]["schema_name"] == "qcschema_manybodyresult" 42 | else: 43 | assert inp, json_dict["trajectory"][-1]["schema_name"] == "qcschema_output" 44 | 45 | # For testing purposes. If this works, we have properly returned the output, and added the result 46 | # to the original file. In order to preserve the form of the test suite, we now resore the input 47 | # to its original state 48 | # with open(os.path.join(os.path.dirname(__file__), inp)) as input_data: 49 | # json_dict = json.load(input_data) 50 | 51 | # LAB: for the MBE optimizations, psi4.compare_values strangely segfaults python, so using compare_values from qcel 52 | assert compare_values( 53 | expected[0], 54 | json_dict["trajectory"][-1]["properties"]["nuclear_repulsion_energy"], 55 | atol=1.0 * 10**-expected[2], 56 | label="Nuclear repulsion energy", 57 | ) 58 | assert compare_values( 59 | expected[1], json_dict["trajectory"][-1]["properties"]["return_energy"], atol=1.e-6, label="Reference energy" 60 | ) 61 | utils.compare_iterations(json_dict, num_steps, check_iter) 62 | 63 | if len(expected) > 3: 64 | assert compare_values(expected[3], json_dict["final_molecule"]["geometry"][5] - json_dict["final_molecule"]["geometry"][2], atol=1.e-3, label="bond length") 65 | 66 | # with open(os.path.join(os.path.dirname(__file__), inp), 'r+') as input_data: 67 | # input_data.seek(0) 68 | # input_data.truncate() 69 | # json.dump(input_copy, input_data, indent=2) 70 | -------------------------------------------------------------------------------- /optking/tests/test_linesearch.py: -------------------------------------------------------------------------------- 1 | #! Linesearch tests 2 | # memory 8gb 3 | 4 | refnucenergy = 41.670589 # Eh 5 | refenergy = -1053.880393 # Eh 6 | 7 | import optking 8 | import psi4 9 | from .utils import utils 10 | 11 | 12 | def test_linesearch(check_iter): 13 | Ar2 = psi4.geometry( 14 | """ 15 | Ar 16 | Ar 1 5.0 17 | """ 18 | ) 19 | 20 | psi4.core.clean_options() 21 | psi4_options = { 22 | "basis": "cc-pvdz", 23 | "d_convergence": 10, 24 | "geom_maxiter": 60, 25 | "g_convergence": "gau_tight", 26 | "step_type": "SD", 27 | } 28 | 29 | psi4.set_options(psi4_options) 30 | 31 | # "linesearch" is not currrently recognized by psi4 read_options. 32 | json_output = optking.optimize_psi4("mp2", **{"linesearch": True}) 33 | print(json_output) 34 | E = json_output["energies"][-1] 35 | nucenergy = json_output["trajectory"][-1]["properties"]["nuclear_repulsion_energy"] 36 | assert psi4.compare_values(nucenergy, nucenergy, 3, "Nuclear repulsion energy") # TEST 37 | assert psi4.compare_values(refenergy, E, 1, "Reference energy") # TEST 38 | utils.compare_iterations(json_output, 25, check_iter) 39 | -------------------------------------------------------------------------------- /optking/tests/test_lj.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tests the LJ functions 3 | """ 4 | import optking 5 | import pytest 6 | import numpy as np 7 | 8 | # Before 9-4-2020, these were in error because function expected 9 | # sigma first, then epsilon. 10 | @pytest.mark.parametrize( 11 | "R,ref", 12 | [ 13 | (2.0, 1893.6914062), 14 | (3.0, 0.0000000), # V = 0 at r = sigma 15 | (3.0 * np.power(2, 1 / 6), -4.0), # Vmin=-epsilon at r = 2^(1/6)*sigma 16 | (4.0, -2.3408346), 17 | (6.0, -0.2460937500), 18 | ], 19 | ) 20 | def test_lj_energy(R, ref): 21 | positions = np.array([[0, 0, -R / 2.0], [0, 0, R / 2.0]]) 22 | energy = optking.lj_functions.calc_energy_and_gradient(positions, 3.0, 4.0, do_gradient=False) 23 | 24 | if not pytest.approx(ref) == energy: 25 | raise ValueError( 26 | "test_lj_energy for R=%.2f did not match reference (comp = %12.10f, ref = %12.10f)." % (R, energy, ref) 27 | ) 28 | -------------------------------------------------------------------------------- /optking/tests/test_methimazole.py: -------------------------------------------------------------------------------- 1 | import psi4 2 | import optking 3 | import pytest 4 | from .utils import utils 5 | 6 | REF_E = -662.48908779 7 | 8 | 9 | @pytest.mark.long 10 | def test_methimazole(check_iter): 11 | psi4.geometry( 12 | """ 13 | 0 1 14 | S -1.887836596846 -0.729301509543 0.000151677997 15 | N 0.379763403154 0.904898490457 -0.000348322003 16 | N 0.782863403154 -1.302501509543 -0.000048322003 17 | C -0.271536596846 -0.357101509543 -0.000448322003 18 | C 1.743863403154 0.684098490457 0.000051677997 19 | C -0.201136596846 2.231498490457 0.000151677997 20 | C 1.979363403154 -0.633601509543 0.000151677997 21 | H 2.450363403154 1.498298490457 0.000251677997 22 | H 0.132963403154 2.764798490457 0.894951677997 23 | H -1.292036596846 2.183998490457 -0.001348322003 24 | H 0.135363403154 2.766598490457 -0.892748322003 25 | H 0.687263403154 -2.310401509543 0.000151677997 26 | H 2.917763403154 -1.162001509543 0.000551677997 27 | """ 28 | ) 29 | psi4_options = {"basis": "pcseg-0"} 30 | psi4.set_options(psi4_options) 31 | result = optking.optimize_psi4("wb97x-d") 32 | E = result["energies"][-1] 33 | assert psi4.compare_values(E, REF_E, 5, "WB97X-D Min Energy") 34 | utils.compare_iterations(result, 6, check_iter) 35 | -------------------------------------------------------------------------------- /optking/tests/test_mp2_g_opt.py: -------------------------------------------------------------------------------- 1 | import psi4 2 | import optking 3 | from .utils import utils 4 | 5 | 6 | def test_mp2_h2o(check_iter): 7 | 8 | h2o = psi4.geometry( 9 | """ 10 | O 11 | H 1 1.0 12 | H 1 1.0 2 106.0 13 | """ 14 | ) 15 | 16 | psi4.core.clean_options() 17 | psi4_options = { 18 | "basis": "6-31G**", 19 | "reference": "rhf", 20 | "d_convergence": 9, 21 | "e_convergence": 9, 22 | "mp2_type": "conv", 23 | "max_energy_g_convergence": 7, 24 | } 25 | psi4.set_options(psi4_options) 26 | 27 | result = optking.optimize_psi4("mp2") 28 | 29 | this_nucenergy = result["trajectory"][-1]["properties"]["nuclear_repulsion_energy"] # TEST 30 | this_mp2 = result["energies"][-1] # TEST 31 | REF_nucenergy = 9.1622581908184 # TEST 32 | REF_mp2 = -76.2224486598878 # TEST 33 | assert psi4.compare_values(REF_nucenergy, this_nucenergy, 3, "Nuclear repulsion energy") # TEST 34 | assert psi4.compare_values(REF_mp2, this_mp2, 6, "CONV MP2 energy") # TEST 35 | utils.compare_iterations(result, 5, check_iter) 36 | -------------------------------------------------------------------------------- /optking/tests/test_nearlinear_dft_opt.py: -------------------------------------------------------------------------------- 1 | import psi4 2 | import optking 3 | from .utils import utils 4 | 5 | #! B3LYP cc-pVDZ geometry optimzation of phenylacetylene, starting from 6 | #! not quite linear structure 7 | def test_b3lyp_phenylacetylene(check_iter): 8 | 9 | phenylacetylene = psi4.geometry( 10 | """ 11 | 0 1 12 | C 0.50424 2.62143 -1.86897 13 | C -0.79405 2.10443 -1.80601 14 | C -1.78491 2.59819 -2.66154 15 | C -1.47738 3.60745 -3.57782 16 | C -0.17996 4.12418 -3.64086 17 | C 0.81143 3.63137 -2.78697 18 | H 1.27012 2.23852 -1.20693 19 | H -2.24344 3.98980 -4.23978 20 | H 0.05756 4.90505 -4.35040 21 | H -1.03189 1.32372 -1.09717 22 | H -2.78881 2.19838 -2.61341 23 | C 2.14399 4.16411 -2.85667 24 | C 3.26501 4.60083 -2.90366 25 | H 4.24594 4.99166 -2.95361 26 | """ 27 | ) 28 | 29 | psi4.core.clean_options() 30 | psi4_options = { 31 | "guess": "sad", 32 | "basis": "cc-pVDZ", 33 | } 34 | psi4.set_options(psi4_options) 35 | 36 | result = optking.optimize_psi4("B3LYP") 37 | 38 | REF_b3lyp_E = -308.413691796 # TEST 39 | E = result["energies"][-1] # TEST 40 | assert psi4.compare_values(REF_b3lyp_E, E, 5, "B3LYP energy") # TEST 41 | utils.compare_iterations(result, 5, check_iter) 42 | -------------------------------------------------------------------------------- /optking/tests/test_oofp.py: -------------------------------------------------------------------------------- 1 | #! Test out-of-plane angles. Added when only one central atom. 2 | # Usually not needed, but problem in a situation like this, very nearly 3 | # planar formaldehyde. Three bends become redundant as one approaches planarity. 4 | # So eigenvalues of (B*B^t) contain a very small eval. If you include this in 5 | # your matrix inversion it blows up, and if you don't, then you can't tightly 6 | # converge. Adding out-of-planes solves problem. 7 | 8 | b3lyp_opt_energy = -114.41550257 9 | # Range limit both H-C-O(-H) out-of-plane angles to >30 degrees 10 | b3lyp_ranged_oop_30_energy = -114.4032481 11 | # Add harmonic force to push out-of-plane angles to +30 and -30 degrees, 12 | # because extra force is additional, final values are not exactly 30/-30 13 | # and final is a bit lower. 14 | b3lyp_ext_force_oop_30_energy = -114.4032891 15 | 16 | import psi4 17 | import optking 18 | from .utils import utils 19 | 20 | 21 | def test_oofp_formaldehyde(check_iter): 22 | form = psi4.geometry( 23 | """ 24 | O 0.6 -0.00007 0.0 25 | C -0.6 -0.00007 0.0 26 | H -1.2 0.24 -0.9 27 | H -1.2 -0.24 0.9 28 | symmetry c1 29 | """ 30 | ) 31 | psi4.core.clean_options() 32 | psi4_options = { 33 | "basis": "def2-SVP", 34 | "g_convergence": "gau_tight", 35 | "test_B": True, 36 | } 37 | psi4.set_options(psi4_options) 38 | 39 | result = optking.optimize_psi4("b3lyp") 40 | E = result["energies"][-1] # TEST 41 | 42 | assert psi4.compare_values(b3lyp_opt_energy, E, 8, "B3LYP energy") 43 | utils.compare_iterations(result, 6, check_iter) 44 | 45 | 46 | def test_ranged_oofp(check_iter): 47 | form = psi4.geometry( 48 | """ 49 | O 0.08 0.60 -0.0 50 | C -0.04 -0.60 -0.0 51 | H -0.4 -1.14 -0.92 52 | H -0.4 -1.14 0.92 53 | """ 54 | ) 55 | psi4.core.clean_options() 56 | psi4_options = {"basis": "def2-SVP", "ensure_bt_convergence": True} 57 | psi4.set_options(psi4_options) 58 | 59 | xtra = {"ranged_oofp": "(3 2 1 4 -40.0 -30.0) (4 2 1 3 30.0 40.0)"} 60 | result = optking.optimize_psi4("b3lyp", **xtra) 61 | E = result["energies"][-1] 62 | 63 | assert psi4.compare_values(b3lyp_ranged_oop_30_energy, E, 5, "B3LYP energy") 64 | utils.compare_iterations(result, 3, check_iter) 65 | 66 | 67 | def test_ext_force_oofp(check_iter): 68 | form = psi4.geometry( 69 | """ 70 | O 0.08 0.60 -0.0 71 | C -0.04 -0.60 -0.0 72 | H -0.4 -1.14 -0.92 73 | H -0.4 -1.14 0.92 74 | """ 75 | ) 76 | psi4.core.clean_options() 77 | psi4_options = {"basis": "def2-SVP", "ensure_bt_convergence": True} 78 | psi4.set_options(psi4_options) 79 | 80 | xtra = {"ext_force_oofp": "3 2 1 4 '-0.5*(x+30)' 4 2 1 3 '-0.5*(x-30.0)'"} 81 | result = optking.optimize_psi4("b3lyp", **xtra) 82 | E = result["energies"][-1] 83 | 84 | assert psi4.compare_values(b3lyp_ext_force_oop_30_energy, E, 5, "B3LYP energy") 85 | utils.compare_iterations(result, 8, check_iter) 86 | -------------------------------------------------------------------------------- /optking/tests/test_openshell.py: -------------------------------------------------------------------------------- 1 | import psi4 2 | import optking 3 | 4 | from .utils import utils 5 | 6 | 7 | def test_charged_anion(check_iter): 8 | no2 = psi4.geometry( 9 | """ 10 | -1 1 11 | N -0.0001995858 -0.8633595176 0.0000000000 12 | O -0.7026831726 0.4173795866 0.0000000000 13 | O 0.7028810651 0.4175165407 0.0000000000 14 | """ 15 | ) 16 | 17 | psi4.core.clean_options() 18 | psi4_options = { 19 | "basis": "cc-pvdz", 20 | } 21 | psi4.set_options(psi4_options) 22 | 23 | json_output = optking.optimize_psi4("hf") 24 | 25 | E = json_output["energies"][-1] 26 | refenergy = -203.894394347422 27 | assert psi4.compare_values(refenergy, E, 6, "RHF singlet NO2- energy") 28 | utils.compare_iterations(json_output, 3, check_iter) 29 | 30 | 31 | def test_neutral_triplet(check_iter): 32 | o2 = psi4.geometry( 33 | """ 34 | 0 3 35 | O 36 | O 1 1.2 37 | """ 38 | ) 39 | 40 | psi4.core.clean_options() 41 | psi4_options = { 42 | "basis": "cc-pvdz", 43 | "reference": "uhf", 44 | } 45 | psi4.set_options(psi4_options) 46 | 47 | result = optking.optimize_psi4("hf") 48 | 49 | E = result["energies"][-1] 50 | REF_uhf = -149.6318688 51 | assert psi4.compare_values(REF_uhf, E, 6, "UHF triplet O2 Energy") # TEST 52 | utils.compare_iterations(result, 3, check_iter) 53 | -------------------------------------------------------------------------------- /optking/tests/test_opt2_allene.py: -------------------------------------------------------------------------------- 1 | #! SCF DZ allene geometry optimization, with Cartesian input, first in c2v symmetry, 2 | #! then in Cs symmetry from a starting point with a non-linear central bond angle. 3 | 4 | import psi4 5 | import optking 6 | from .utils import utils 7 | 8 | # import importlib 9 | 10 | 11 | def test_opt2_allene(check_iter): 12 | refnucenergy = 59.2532646680161 # TEST 13 | refenergy = -115.8302823663 # TEST 14 | 15 | # starting point is D2d/c2v 16 | allene = psi4.geometry( 17 | """ 18 | H 0.0 -0.92 -1.8 19 | H 0.0 0.92 -1.8 20 | C 0.0 0.00 -1.3 21 | C 0.0 0.00 0.0 22 | C 0.0 0.00 1.3 23 | H 0.92 0.00 1.8 24 | H -0.92 0.00 1.8 25 | """ 26 | ) 27 | 28 | psi4.core.clean_options() 29 | 30 | psi4_options = { 31 | "basis": "DZ", 32 | "e_convergence": 10, 33 | "d_convergence": 10, 34 | "scf_type": "pk", 35 | } 36 | psi4.set_options(psi4_options) 37 | 38 | json_output = optking.optimize_psi4("hf") 39 | E = json_output["energies"][-1] 40 | nucenergy = json_output["trajectory"][-1]["properties"]["nuclear_repulsion_energy"] 41 | assert psi4.compare_values(refnucenergy, nucenergy, 2, "Nuclear repulsion energy") # TEST 42 | assert psi4.compare_values(refenergy, E, 6, "Reference energy") # TEST 43 | 44 | # central C-C-C bond angle starts around 170 degrees to test the dynamic addition 45 | # of new linear bending coordinates, and the redefinition of dihedrals. 46 | allene = psi4.geometry( 47 | """ 48 | H 0.0 -0.92 -1.8 49 | H 0.0 0.92 -1.8 50 | C 0.0 0.00 -1.3 51 | C 0.0 0.10 0.0 52 | C 0.0 0.00 1.3 53 | H 0.92 0.00 1.8 54 | H -0.92 0.00 1.8 55 | """ 56 | ) 57 | 58 | psi4.set_options(psi4_options) 59 | json_output = optking.optimize_psi4("hf") 60 | E = json_output["energies"][-1] 61 | nucenergy = json_output["trajectory"][-1]["properties"]["nuclear_repulsion_energy"] 62 | assert psi4.compare_values(refnucenergy, nucenergy, 2, "Nuclear repulsion energy") # TEST 63 | assert psi4.compare_values(refenergy, E, 6, "Reference energy") # TEST 64 | utils.compare_iterations(json_output, 7, check_iter) 65 | -------------------------------------------------------------------------------- /optking/tests/test_opt5-ch2.py: -------------------------------------------------------------------------------- 1 | #! 6-31G** UHF CH2 3B1 optimization. Uses a Z-Matrix with dummy atoms, just for demo and testing purposes. 2 | 3 | import psi4 4 | import optking 5 | 6 | from .utils import utils 7 | 8 | nucrefenergy = 6.197322440574482 # TEST 9 | refenergy = -38.925486977153 # TEST 10 | 11 | 12 | def test_ch2_with_dummy_atoms(check_iter): 13 | ch2 = psi4.geometry( 14 | """ 15 | 0 3 16 | c 17 | x 1 1.0 18 | h 1 b1 2 a1 19 | h 1 b1 2 a1 3 180.0 20 | 21 | b1 = 1.0 22 | a1 = 60.0 23 | """ 24 | ) 25 | 26 | psi4.core.clean_options() 27 | 28 | psi4_options = { 29 | "reference": "uhf", 30 | "basis": "6-31G(d,p)", 31 | "docc": [2, 0, 0, 1], 32 | "socc": [1, 0, 1, 0], 33 | "scf_type": "pk", 34 | } 35 | 36 | psi4.set_options(psi4_options) 37 | 38 | json_output = optking.optimize_psi4("hf") 39 | thisenergy = json_output["energies"][-1] 40 | nucenergy = json_output["trajectory"][-1]["properties"]["nuclear_repulsion_energy"] 41 | 42 | assert psi4.compare_values(nucrefenergy, nucenergy, 3, "Nuclear repulsion energy") # TEST 43 | assert psi4.compare_values(refenergy, thisenergy, 6, "Reference energy") # TEST 44 | 45 | utils.compare_iterations(json_output, 4, check_iter) 46 | -------------------------------------------------------------------------------- /optking/tests/test_optimization_input.py: -------------------------------------------------------------------------------- 1 | import pprint 2 | import json 3 | from qcelemental.models.procedures import OptimizationInput 4 | from qcelemental.util.serialization import json_dumps 5 | 6 | from optking.optwrapper import optimize_qcengine, optimize_psi4, initialize_options, make_computer 7 | from optking.molsys import Molsys 8 | from optking.optimize import prepare_opt_output 9 | 10 | from optking.compute_wrappers import QCEngineComputer 11 | 12 | 13 | pp = pprint.PrettyPrinter(indent=2) 14 | 15 | 16 | def test_optimization_input(): 17 | 18 | opt_input_dict = { 19 | "schema_name": "qcschema_optimization_input", 20 | "schema_version": 1, 21 | "keywords": {"program": "psi4"}, 22 | "initial_molecule": { 23 | "geometry": [0.90, 0.80, 0.5, 0.00, 0.70, 0.0, 0.00, -0.70, 0.0, -0.90, -0.80, 0.5], 24 | "symbols": ["H", "O", "O", "H"], 25 | }, 26 | "input_specification": { 27 | "schema_name": "qcschema_input", 28 | "schema_version": 1, 29 | "driver": "gradient", 30 | "model": {"method": "HF", "basis": "sto-3g"}, 31 | "keywords": {"soscf": True}, 32 | }, 33 | } 34 | 35 | # Create Pydantic Model Fills all fields (including non-required) 36 | opt_in = OptimizationInput(**opt_input_dict) 37 | 38 | # Convert back to plain python dictionary 39 | full_model = json.loads(json_dumps(opt_in)) 40 | 41 | oMolsys = Molsys.from_schema(full_model["initial_molecule"]) # Create Optking's molecular system 42 | initialize_options(full_model["keywords"]) 43 | computer = make_computer(full_model, "qc") 44 | # Takes the o_json object and creates QCSchema formatted python dict. Has numpy elements 45 | opt_output = prepare_opt_output(oMolsys, computer) 46 | 47 | assert "success" in opt_output 48 | 49 | psi_computer = make_computer(full_model, "psi4") 50 | opt_output = prepare_opt_output(oMolsys, computer) 51 | -------------------------------------------------------------------------------- /optking/tests/test_ranged_internals.py: -------------------------------------------------------------------------------- 1 | #! Test of 'ranged' coordinates. Intcos that cannot move 2 | # out of a prescribed range. 3 | import pytest 4 | import psi4 5 | import optking 6 | from .utils import utils 7 | 8 | conv_RHF_OO_at_135 = -150.7853238 # minimum is 1.39 9 | init_OO_distance = [("1.28", 9), ("1.30", 7), ("1.325", 8), ("1.35", 9), ("1.38", 8)] 10 | 11 | @pytest.mark.parametrize("option, num_steps", init_OO_distance) 12 | def test_ranged_stretch(option, num_steps, check_iter): 13 | geom_input_string = ( 14 | """ 15 | H 16 | O 1 0.90 17 | O 2 """ 18 | + option 19 | + """ 1 100.0 20 | H 3 0.90 2 100.0 1 115.0 """ 21 | ) 22 | hooh = psi4.geometry(geom_input_string) 23 | 24 | psi4.core.clean_options() 25 | psi4options = {"basis": "cc-PVDZ", "print": 4, "g_convergence": "gau_tight", "geom_maxiter": 20} 26 | psi4.set_options(psi4options) 27 | 28 | xtra = {"ranged_distance": "2 3 1.30 1.35"} 29 | json_output = optking.optimize_psi4("hf", **xtra) 30 | 31 | thisenergy = json_output["energies"][-1] 32 | assert psi4.compare_values(conv_RHF_OO_at_135, thisenergy, 6) 33 | utils.compare_iterations(json_output, num_steps, check_iter) 34 | 35 | conv_RHF_HOO_at_105 = -150.7861769 # minimum is 102 degrees 36 | init_HOO_bend = [("100", 8), ("105", 6), ("108", 7), ("110", 8), ("115", 9)] 37 | 38 | @pytest.mark.parametrize("option, num_steps", init_HOO_bend) 39 | def test_ranged_bend(option, num_steps, check_iter): 40 | geom_input_string = ( 41 | """ 42 | H 43 | O 1 0.90 44 | O 2 1.35 1 """ 45 | + option 46 | + """ 47 | H 3 0.90 2 """ 48 | + option 49 | + """ 1 115.0 """ 50 | ) 51 | hooh = psi4.geometry(geom_input_string) 52 | 53 | psi4.core.clean_options() 54 | psi4options = {"basis": "cc-PVDZ", "g_convergence": "gau_tight", "geom_maxiter": 20} 55 | psi4.set_options(psi4options) 56 | 57 | xtra = {"ranged_bend": "(1 2 3 105.0 110.0) (2 3 4 105.0 110.0)"} 58 | json_output = optking.optimize_psi4("hf", **xtra) 59 | 60 | thisenergy = json_output["energies"][-1] 61 | assert psi4.compare_values(conv_RHF_HOO_at_105, thisenergy, 6) 62 | utils.compare_iterations(json_output, num_steps, check_iter) 63 | 64 | conv_RHF_HOOH_at_110 = -150.7866419 # minimum is 115 degrees 65 | init_HOOH_tors = ["95", "100", "105", "110", "115"] 66 | 67 | @pytest.mark.parametrize("option", init_HOOH_tors) 68 | def test_ranged_tors(option): 69 | geom_input_string = ( 70 | """ 71 | H 72 | O 1 0.90 73 | O 2 1.35 1 100.0 74 | H 3 0.90 2 100.0 1 """ 75 | + option 76 | ) 77 | hooh = psi4.geometry(geom_input_string) 78 | 79 | psi4.core.clean_options() 80 | psi4options = {"basis": "cc-PVDZ", "g_convergence": "gau_tight", "geom_maxiter": 20} 81 | psi4.set_options(psi4options) 82 | 83 | xtra = {"ranged_dihedral": "(1 2 3 4 100.0 110.0)"} 84 | json_output = optking.optimize_psi4("hf", **xtra) 85 | 86 | thisenergy = json_output["energies"][-1] 87 | assert psi4.compare_values(conv_RHF_HOOH_at_110, thisenergy, 6) 88 | 89 | 90 | conv_RHF_HOOH = -150.7866742 # this is the global minimum (GM) 91 | cart_limits = [ 92 | "1 x 0.77 0.80", # Make H x be within 0.77 - 0.80; converge to GM 93 | "2 y 0.50 0.60", # Make O y be within 0.50 - 0.60; converge to GM 94 | "(1 x 0.77 0.80) (2 y 0.50 0.60)", 95 | ] # parentheses optional 96 | 97 | 98 | @pytest.mark.parametrize("option", cart_limits) 99 | def test_ranged_cart(option): 100 | hooh = psi4.geometry( 101 | """ 102 | H 0.7551824472 0.7401035426 0.5633005896 103 | O 0.0870189589 0.6693673665 -0.0354930582 104 | O -0.0870189589 -0.6693673665 -0.0354930582 105 | H -0.7551824472 -0.7401035426 0.5633005896""" 106 | ) 107 | 108 | psi4.core.clean_options() 109 | psi4options = {"basis": "cc-PVDZ", "g_convergence": "gau_tight", "geom_maxiter": 20} 110 | psi4.set_options(psi4options) 111 | 112 | xtra = {"ranged_cartesian": option} 113 | json_output = optking.optimize_psi4("hf", **xtra) 114 | 115 | thisenergy = json_output["energies"][-1] 116 | assert psi4.compare_values(conv_RHF_HOOH, thisenergy, 6) 117 | -------------------------------------------------------------------------------- /optking/tests/test_scsmp2_opt.py: -------------------------------------------------------------------------------- 1 | import psi4 2 | import optking 3 | import json 4 | from .utils import utils 5 | 6 | #! SCS-OMP2 cc-pVDZ geometry optimization for the H2O molecule. 7 | def test_scsmp2_opt(check_iter): 8 | 9 | h2o = psi4.geometry( 10 | """ 11 | 0 1 12 | o 13 | h 1 0.958 14 | h 1 0.958 2 104.4776 15 | """ 16 | ) 17 | 18 | psi4.core.clean_options() 19 | psi4_options = {"basis": "cc-pvdz", "max_energy_g_convergence": 7} 20 | psi4.set_options(psi4_options) 21 | 22 | result = optking.optimize_psi4("scs-omp2") 23 | 24 | this_nuc = result["trajectory"][-1]["properties"]["nuclear_repulsion_energy"] # TEST 25 | this_scf = result["trajectory"][-1]["extras"]["qcvars"]["SCF TOTAL ENERGY"] # TEST 26 | this_energy = result["energies"][-1] # TEST 27 | REF_nuc = 9.1123208123 28 | REF_scf = -76.0260868661 29 | REF_scsomp2 = -76.2280452486 30 | assert psi4.compare_values(REF_nuc, this_nuc, 3, "Nuclear Repulsion Energy (a.u.)") 31 | # TEST 32 | assert psi4.compare_values(REF_scf, this_scf, 6, "SCF Energy (a.u.)") 33 | # TEST 34 | assert psi4.compare_values(REF_scsomp2, this_energy, 6, "SCS-OMP2 Total Energy (a.u.)") 35 | # TEST 36 | 37 | utils.compare_iterations(result, 4, check_iter) 38 | 39 | 40 | #! SCS-OMP3 cc-pVDZ geometry optimization for the H2O molecule. 41 | def test_scsmp3_opt(check_iter): 42 | 43 | h2o = psi4.geometry( 44 | """ 45 | 0 1 46 | o 47 | h 1 0.958 48 | h 1 0.958 2 104.4776 49 | """ 50 | ) 51 | 52 | psi4.core.clean_options() 53 | psi4_options = {"basis": "cc-pvdz", "max_energy_g_convergence": 7} 54 | psi4.set_options(psi4_options) 55 | 56 | result = optking.optimize_psi4("scs-omp3") 57 | print(json.dumps(result, indent=2)) 58 | 59 | this_nuc = result["trajectory"][-1]["properties"]["nuclear_repulsion_energy"] # TEST 60 | this_scf = result["trajectory"][-1]["extras"]["qcvars"]["SCF TOTAL ENERGY"] # TEST 61 | this_energy = result["energies"][-1] # TEST 62 | REF_nuc = 9.1193753755 # TEST 63 | REF_scf = -76.0261614278 # TEST 64 | REF_scsomp3 = -76.2296260036 # TEST 65 | assert psi4.compare_values(REF_nuc, this_nuc, 3, "Nuclear Repulsion Energy (a.u.)") 66 | # TEST 67 | assert psi4.compare_values(REF_scf, this_scf, 6, "SCF Energy (a.u.)") 68 | # TEST 69 | assert psi4.compare_values(REF_scsomp3, this_energy, 6, "SCS-OMP3 Total Energy (a.u.)") 70 | # TEST 71 | 72 | utils.compare_iterations(result, 4, check_iter) 73 | 74 | 75 | #! SOS-OMP2 cc-pVDZ geometry optimization for the H2O molecule. 76 | def test_sosmp2_opt(check_iter): 77 | 78 | h2o = psi4.geometry( 79 | """ 80 | 0 1 81 | o 82 | h 1 0.958 83 | h 1 0.958 2 104.4776 84 | """ 85 | ) 86 | 87 | psi4.core.clean_options() 88 | psi4_options = {"basis": "cc-pvdz", "max_energy_g_convergence": 7} 89 | psi4.set_options(psi4_options) 90 | 91 | result = optking.optimize_psi4("sos-omp2") 92 | print(json.dumps(result, indent=2)) 93 | 94 | this_nuc = result["trajectory"][-1]["properties"]["nuclear_repulsion_energy"] # TEST 95 | this_scf = result["trajectory"][-1]["extras"]["qcvars"]["SCF TOTAL ENERGY"] # TEST 96 | this_energy = result["energies"][-1] # TEST 97 | REF_nuc = 9.1236764248 # TEST 98 | REF_scf = -76.0262152850 # TEST 99 | REF_sosomp2 = -76.2106507336 # TEST 100 | assert psi4.compare_values(REF_nuc, this_nuc, 3, "Nuclear Repulsion Energy (a.u.)") 101 | # TEST 102 | assert psi4.compare_values(REF_scf, this_scf, 6, "SCF Energy (a.u.)") 103 | # TEST 104 | assert psi4.compare_values(REF_sosomp2, this_energy, 6, "SOS-OMP2 Total Energy (a.u.)") 105 | # TEST 106 | 107 | utils.compare_iterations(result, 4, check_iter) 108 | 109 | 110 | #! SOS-OMP3 cc-pVDZ geometry optimization for the H2O molecule. 111 | def test_sosmp3_opt(check_iter): 112 | 113 | h2o = psi4.geometry( 114 | """ 115 | 0 1 116 | o 117 | h 1 0.958 118 | h 1 0.958 2 104.4776 119 | """ 120 | ) 121 | 122 | psi4.core.clean_options() 123 | psi4_options = {"basis": "cc-pvdz", "max_energy_g_convergence": 7} 124 | psi4.set_options(psi4_options) 125 | 126 | result = optking.optimize_psi4("sos-omp3") 127 | print(json.dumps(result, indent=2)) 128 | 129 | this_nuc = result["trajectory"][-1]["properties"]["nuclear_repulsion_energy"] # TEST 130 | this_scf = result["trajectory"][-1]["extras"]["qcvars"]["SCF TOTAL ENERGY"] # TEST 131 | this_energy = result["energies"][-1] # TEST 132 | REF_nuc = 9.1134855397 # TEST 133 | REF_scf = -76.0261191302 # TEST 134 | REF_sosomp3 = -76.2277207554 # TEST 135 | assert psi4.compare_values(REF_nuc, this_nuc, 3, "Nuclear Repulsion Energy (a.u.)") 136 | # TEST 137 | assert psi4.compare_values(REF_scf, this_scf, 6, "SCF Energy (a.u.)") 138 | # TEST 139 | assert psi4.compare_values(REF_sosomp3, this_energy, 6, "SOS-OMP3 Total Energy (a.u.)") 140 | # TEST 141 | 142 | utils.compare_iterations(result, 4, check_iter) 143 | -------------------------------------------------------------------------------- /optking/tests/test_sf4_quasilinear.py: -------------------------------------------------------------------------------- 1 | # SF4 problem case 2 | # Has linear bend, breaks symmetry 3 | # Converges fine if Cartesian 4 | # needs debugging 5 | 6 | import psi4 7 | import optking 8 | import pytest 9 | 10 | from .utils import utils 11 | 12 | 13 | def test_sf4_quasilinear_cart(check_iter): 14 | sf4 = psi4.geometry( 15 | """ 16 | S 0.00000000 -0.00000000 -0.30618267 17 | F -1.50688420 -0.00000000 0.56381732 18 | F 0.00000000 -1.74000000 -0.30618267 19 | F -0.00000000 1.74000000 -0.30618267 20 | F 1.50688420 0.00000000 0.56381732 21 | """ 22 | ) 23 | 24 | psi4.core.clean_options() 25 | psi4_options = { 26 | "basis": "6-31G(d)", 27 | "scf_type": "pk", 28 | "opt_coordinates": "cartesian", 29 | } 30 | psi4.set_options(psi4_options) 31 | 32 | json_output = optking.optimize_psi4("hf") 33 | 34 | E = json_output["energies"][-1] 35 | REF_energy = -795.1433965 36 | assert psi4.compare_values(REF_energy, E, 6, "Reference energy") 37 | 38 | utils.compare_iterations(json_output, 9, check_iter) 39 | 40 | 41 | # This needs debugged. RAK (Jan. 2020) thinks that when/if we get 42 | # full symmetrization of our step (C2v) point group here, then the 43 | # problem that appears in step 7-8 will go away. 44 | # A secondary problem is that it is possible that our definition of 45 | # linear bends forces symmetry breaking, but for now this has been 46 | # tweaked for at least this case by choosing different bend axes 47 | # inside optking. (see the arbitrary ref. axes in Helgaker/Bakken). 48 | @pytest.mark.skip 49 | def test_sf4_quasilinear(): 50 | sf4 = psi4.geometry( 51 | """ 52 | S 0.00000000 -0.00000000 -0.30618267 53 | F -1.50688420 -0.00000000 0.56381732 54 | F 0.00000000 -1.74000000 -0.30618267 55 | F -0.00000000 1.74000000 -0.30618267 56 | F 1.50688420 0.00000000 0.56381732 57 | """ 58 | ) 59 | 60 | psi4.core.clean_options() 61 | psi4_options = { 62 | "basis": "6-31G(d)", 63 | "scf_type": "pk", 64 | "g_convergence": "gau_tight", 65 | } 66 | psi4.set_options(psi4_options) 67 | 68 | json_output = optking.optimize_psi4("hf") 69 | 70 | E = json_output["energies"][-1] 71 | REF_energy = -795.1433965 72 | assert psi4.compare_values(REF_energy, E, 5, "Reference energy") 73 | -------------------------------------------------------------------------------- /optking/tests/test_step_types.py: -------------------------------------------------------------------------------- 1 | import psi4 2 | import optking 3 | import pytest 4 | 5 | from .utils import utils 6 | 7 | finalEnergy = -76.05776970 # TEST 8 | 9 | #! SCF CC-PVTZ geometry optimzation, with Z-matrix input 10 | @pytest.mark.parametrize( 11 | "option, expected, num_steps", [("RFO", finalEnergy, 5), ("NR", finalEnergy, 5), ("SD", finalEnergy, 10)] 12 | ) 13 | def test_h2o_rfo(option, expected, num_steps, check_iter): 14 | 15 | h2o = psi4.geometry( 16 | """ 17 | O 18 | H 1 1.0 19 | H 1 1.0 2 104.5 20 | """ 21 | ) 22 | 23 | psi4.core.clean_options() 24 | psi4_options = { 25 | "basis": "cc-pvtz", 26 | "e_convergence": "10", 27 | "d_convergence": "10", 28 | "scf_type": "pk", 29 | "max_energy_g_convergence": 7, 30 | "step_type": option, 31 | } 32 | psi4.set_options(psi4_options) 33 | 34 | json_output = optking.optimize_psi4("hf") 35 | 36 | E = json_output["energies"][-1] # TEST 37 | assert psi4.compare_values(finalEnergy, E, 6, f"{option} Step Final Energy") # TEST 38 | utils.compare_iterations(json_output, num_steps, check_iter) 39 | -------------------------------------------------------------------------------- /optking/tests/test_ts_opt.py: -------------------------------------------------------------------------------- 1 | import psi4 2 | import optking 3 | import pytest 4 | 5 | from .utils import utils 6 | 7 | #! Optimization to 180 degree torsion from 120 8 | @pytest.mark.parametrize("option, expected_steps", [("P_RFO", 14), ("RS_I_RFO", 10)]) 9 | def test_hooh_TS(check_iter, option, expected_steps): 10 | 11 | hooh = psi4.geometry( 12 | """ 13 | 0 1 14 | H 15 | O 1 0.95 16 | O 2 1.40 1 105.0 17 | H 3 0.95 2 105.0 1 120.0 18 | """ 19 | ) 20 | 21 | psi4.core.clean_options() 22 | psi4options = { 23 | "basis": "cc-pvdz", 24 | "geom_maxiter": 30, 25 | "opt_type": "TS", 26 | "scf_type": "pk", 27 | "docc": [5, 4], 28 | "intrafrag_step_limit": 0.1, 29 | "max_energy_g_convergence": 7, 30 | } 31 | psi4.set_options(psi4options) 32 | 33 | json_output = optking.optimize_psi4("hf", {"step_type": option}) 34 | 35 | E = json_output["energies"][-1] # TEST 36 | # print( '{:15.10f}'.format(E) ) 37 | C2H_TS_ENERGY = -150.7854114803 # TEST 38 | assert psi4.compare_values(C2H_TS_ENERGY, E, 6, "RHF Energy after optimization to C2H TS") # TEST 39 | utils.compare_iterations(json_output, expected_steps, check_iter) 40 | 41 | 42 | #! Optimization to 0 degree torsion from 100 43 | @pytest.mark.parametrize("option, expected_steps", [("P_RFO", 21), ("RS_I_RFO", 10)]) 44 | def test_hooh_TS_zero(check_iter, option, expected_steps): 45 | 46 | hooh = psi4.geometry( 47 | """ 48 | 0 1 49 | H 50 | O 1 0.95 51 | O 2 1.40 1 105.0 52 | H 3 0.95 2 105.0 1 100.0 53 | """ 54 | ) 55 | 56 | psi4.core.clean_options() 57 | psi4options = { 58 | "basis": "cc-pvdz", 59 | "geom_maxiter": 40, 60 | "opt_type": "TS", 61 | "scf_type": "pk", 62 | "docc": [5, 4], 63 | "intrafrag_step_limit": 0.1, 64 | "max_energy_g_convergence": 7, 65 | } 66 | psi4.set_options(psi4options) 67 | 68 | json_output = optking.optimize_psi4("hf", {"step_type": option}) 69 | 70 | E = json_output["energies"][-1] # TEST 71 | C2V_TS_ENERGY = -150.774009217562 # TEST 72 | assert psi4.compare_values(C2V_TS_ENERGY, E, 6, "RHF Energy after optimization to C2H TS") # TEST 73 | utils.compare_iterations(json_output, expected_steps, check_iter) 74 | 75 | 76 | def test_hooh_min(check_iter): 77 | hooh = psi4.geometry( 78 | """ 79 | H 80 | O 1 0.95 81 | O 2 1.40 1 105.0 82 | H 3 0.95 2 105.0 1 100.0 83 | """ 84 | ) 85 | 86 | psi4.core.clean_options() 87 | psi4options = { 88 | "basis": "cc-pvdz", 89 | "geom_maxiter": 20, 90 | "opt_type": "min", 91 | "scf_type": "pk", 92 | "docc": [5, 4], 93 | "max_energy_g_convergence": 7, 94 | } 95 | psi4.set_options(psi4options) 96 | 97 | json_output = optking.optimize_psi4("hf") 98 | 99 | E = json_output["energies"][-1] # TEST 100 | # print( '{:15.10f}'.format(E) ) 101 | MIN_ENERGY = -150.7867668 # TEST 102 | assert psi4.compare_values(MIN_ENERGY, E, 6, "RHF Energy") # TEST 103 | utils.compare_iterations(json_output, 7, check_iter) 104 | -------------------------------------------------------------------------------- /optking/tests/utils/__init__.py: -------------------------------------------------------------------------------- 1 | from . import utils 2 | -------------------------------------------------------------------------------- /optking/tests/utils/utils.py: -------------------------------------------------------------------------------- 1 | import optking 2 | 3 | 4 | def compare_iterations(json_output, expected_steps, assert_iter): 5 | 6 | logger = optking.logger 7 | steps_taken = len(json_output["trajectory"]) 8 | if steps_taken != expected_steps: 9 | logger.warning(f"TEST - Number of steps taken {steps_taken}, Previous required steps {expected_steps}") 10 | else: 11 | logger.info(f"TEST - Number of steps taken matches expected {steps_taken}") 12 | 13 | if int(assert_iter): 14 | assert steps_taken == expected_steps 15 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | # Helper file to handle all configs 2 | 3 | [coverage:run] 4 | # .coveragerc to control coverage.py and pytest-cov 5 | # Omit the test directory from test coverage 6 | omit = 7 | */tests/* 8 | optking/_version.py 9 | 10 | 11 | [tool:isort] 12 | line_length=120 13 | include_trailing_comma=True 14 | force_grid_wrap=0 15 | use_parentheses=True 16 | multi_line_output=3 17 | 18 | [yapf] 19 | # YAPF, in .style.yapf files this shows up as "[style]" header 20 | BASED_ON_sTYLE = PEP8 21 | COLUMN_LIMIT = 119 22 | INDENT_WIDTH = 4 23 | USE_TABS = False 24 | 25 | [flake8] 26 | # Flake8, PyFlakes, etc 27 | max-line-length = 119 28 | 29 | [versioneer] 30 | # Automatic version numbering scheme 31 | VCS = git 32 | style = pep440 33 | versionfile_source = optking/_version.py 34 | versionfile_build = optking/_version.py 35 | tag_prefix = '' 36 | 37 | [tool:pytest] 38 | markers = 39 | dimers 40 | long 41 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import setuptools 2 | import versioneer 3 | 4 | short_description = "OptKing is a python geometry optimization module originally written for PSI by R. A. King." 5 | 6 | try: 7 | with open("README.md", "r") as handle: 8 | long_description = handle.read() 9 | except: 10 | long_description = short_description 11 | 12 | if __name__ == "__main__": 13 | setuptools.setup( 14 | name="OptKing", 15 | description="A geometry optimizer for quantum chemistry.", 16 | author="Rollin King", 17 | author_email="rking@bethel.edu", 18 | url="https://github.com/psi-rking/optking", 19 | license="BSD-3C", 20 | version=versioneer.get_version(), 21 | cmdclass=versioneer.get_cmdclass(), 22 | packages=setuptools.find_packages(), 23 | include_package_data=True, 24 | install_requires=[ 25 | "numpy>=1.20", 26 | "qcelemental>=0.20.0", 27 | "qcengine>=0.20.0", 28 | "msgpack>=1.0", 29 | ], 30 | extras_require={ 31 | "docs": [ 32 | "sphinx", # autodoc was broken in 1.3.1 33 | "sphinxcontrib-napoleon", 34 | "sphinx-automodapi" 35 | "sphinx_rtd_theme", 36 | "numpydoc", 37 | ], 38 | "tests": ["pytest", "pytest-cov", "pytest-pep8",], 39 | }, 40 | tests_require=["pytest", "pytest-cov", "pytest-pep8",], 41 | classifiers=[ 42 | "Development Status :: 4 - Beta", 43 | "Intended Audience :: Science/Research", 44 | "Programming Language :: Python :: 3", 45 | ], 46 | zip_safe=False, 47 | long_description=long_description, 48 | long_description_content_type="text/markdown", 49 | ) 50 | --------------------------------------------------------------------------------