├── .codecov.yml ├── .gitattributes ├── .github ├── CONTRIBUTING.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ └── CI.yaml ├── .gitignore ├── .lgtm.yml ├── .readthedocs.yaml ├── LICENSE ├── MANIFEST.in ├── README.md ├── devtools ├── README.md ├── conda-envs │ └── test_env.yaml ├── legacy-miniconda-setup │ └── before_install.sh └── scripts │ └── create_conda_env.py ├── docs ├── Makefile ├── README.md ├── _static │ ├── README.md │ ├── entropy_barrier.mp4 │ └── muller_potential.mp4 ├── _templates │ └── README.md ├── api.rst ├── api_examples.rst ├── citations.rst ├── conf.py ├── faq.rst ├── index.rst ├── installation.rst ├── make.bat ├── media │ ├── tutorial_hostguest_analysis_results.png │ ├── tutorial_hostguest_directory.png │ ├── tutorial_hostguest_guest.png │ ├── tutorial_hostguest_host.png │ ├── tutorial_hostguest_koff_conv.png │ ├── tutorial_hostguest_model_input.png │ ├── tutorial_hostguest_pmf.png │ ├── tutorial_toy_entropy_barrier.png │ ├── tutorial_toy_model_input.png │ └── tutorial_toy_muller_potential.png ├── model_input_files.rst ├── program_options.rst ├── program_options_analyze.rst ├── program_options_converge.rst ├── program_options_prepare.rst ├── program_options_run.rst ├── requirements.txt ├── requirements.yaml ├── running_calculations.rst ├── tutorial.rst ├── tutorial1_hostguest.rst └── tutorial2_toy_systems.rst ├── pyproject.toml └── seekr2 ├── __init__.py ├── analyze.py ├── continuous_integration └── run_ci.py ├── converge.py ├── data ├── README.md ├── hostguest_files │ ├── hostguest.parm7 │ ├── hostguest.rst7 │ ├── hostguest.xml │ ├── hostguest_at0.5.pdb │ ├── hostguest_at1.5.pdb │ ├── hostguest_at10.5.pdb │ ├── hostguest_at11.5.pdb │ ├── hostguest_at12.5.pdb │ ├── hostguest_at2.5.pdb │ ├── hostguest_at3.5.pdb │ ├── hostguest_at4.5.pdb │ ├── hostguest_at5.5.pdb │ ├── hostguest_at6.5.pdb │ ├── hostguest_at7.5.pdb │ ├── hostguest_at8.5.pdb │ ├── hostguest_at9.5.pdb │ ├── hostguest_for_NAMD.parm7 │ ├── hostguest_for_xml.pdb │ ├── hostguest_ligand.pqr │ ├── hostguest_ligand_same_resid.pqr │ ├── hostguest_output.pdb │ ├── hostguest_receptor.pqr │ ├── hostguest_system.xml │ └── input_tiwary.xml ├── sample_input_elber_openmm.xml ├── sample_input_mmvt_namd.xml └── sample_input_mmvt_openmm.xml ├── modules ├── __init__.py ├── check.py ├── common_analyze.py ├── common_base.py ├── common_converge.py ├── common_cv.py ├── common_prepare.py ├── common_sim_browndye2.py ├── common_sim_namd.py ├── common_sim_openmm.py ├── due.py ├── elber_analyze.py ├── elber_cvs │ ├── __init__.py │ ├── elber_cv_base.py │ ├── elber_external_cv.py │ └── elber_spherical_cv.py ├── elber_sim_openmm.py ├── filetree.py ├── markov_chain_monte_carlo.py ├── mmvt_analyze.py ├── mmvt_base.py ├── mmvt_cvs │ ├── __init__.py │ ├── mmvt_closest_pair_cv.py │ ├── mmvt_count_contacts_cv.py │ ├── mmvt_cv_base.py │ ├── mmvt_external_cv.py │ ├── mmvt_planar_cv.py │ ├── mmvt_rmsd_cv.py │ ├── mmvt_spherical_cv.py │ ├── mmvt_tiwary_cv.py │ ├── mmvt_voronoi_cv.py │ └── mmvt_z_distance_cv.py ├── mmvt_sim_namd.py ├── mmvt_sim_openmm.py ├── runner_browndye2.py ├── runner_namd.py └── runner_openmm.py ├── prepare.py ├── run.py └── tests ├── __init__.py ├── conftest.py ├── create_model_input.py ├── create_toy_system.py ├── data ├── ala_ala_ala.pdb ├── ala_ala_ala.psf ├── charmm22.par ├── charmm22.rtf ├── hostguest_at0.5_swarm.pdb ├── hostguest_state_a1.xml ├── ligand_for_test.pqr ├── sample_bd_milestone_results.xml ├── sample_bd_results_file.xml ├── sample_bd_results_file2.xml ├── test_analyze_output_elber.txt ├── test_analyze_outputfile.txt ├── test_analyze_outputfile_checkpoint1.txt ├── test_analyze_outputfile_checkpoint2.txt ├── test_analyze_outputfile_namd.txt ├── test_analyze_outputfile_namd_checkpoint1.txt ├── test_analyze_outputfile_namd_checkpoint2.txt ├── test_analyze_outputfile_namd_restart1.txt ├── test_analyze_outputfile_namd_restart2.txt ├── test_analyze_outputfile_restart1.txt ├── test_analyze_outputfile_restart2.txt ├── test_analyze_statistics.txt ├── test_namd.xsc ├── traj_test.index.xml └── traj_test.xml ├── pytest.ini ├── test_analyze.py ├── test_check.py ├── test_common_analyze.py ├── test_common_base.py ├── test_common_converge.py ├── test_common_cv.py ├── test_common_prepare.py ├── test_common_sim_browndye2.py ├── test_common_sim_openmm.py ├── test_converge.py ├── test_elber_analyze.py ├── test_elber_cv_base.py ├── test_elber_external_cv.py ├── test_elber_sim_openmm.py ├── test_elber_spherical_cv.py ├── test_markov_chain_monte_carlo.py ├── test_mmvt_analyze.py ├── test_mmvt_closest_pair_cv.py ├── test_mmvt_count_contacts_cv.py ├── test_mmvt_cv.py ├── test_mmvt_cv_base.py ├── test_mmvt_external_cv.py ├── test_mmvt_planar_cv.py ├── test_mmvt_rmsd_cv.py ├── test_mmvt_sim_namd.py ├── test_mmvt_sim_openmm.py ├── test_mmvt_spherical_cv.py ├── test_mmvt_tiwary_cv.py ├── test_mmvt_voronoi_cv.py ├── test_prepare.py ├── test_run.py ├── test_runner_browndye2.py ├── test_runner_namd.py └── test_runner_openmm.py /.codecov.yml: -------------------------------------------------------------------------------- 1 | # Codecov configuration to make it a bit less noisy 2 | coverage: 3 | status: 4 | patch: false 5 | project: 6 | default: 7 | threshold: 50% 8 | comment: 9 | layout: "header" 10 | require_changes: false 11 | branches: null 12 | behavior: default 13 | flags: null 14 | paths: null -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | seekr2/_version.py export-subst 2 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to contribute 2 | 3 | We welcome contributions from external contributors, and this document 4 | describes how to merge code changes into this seekr2. 5 | 6 | ## Getting Started 7 | 8 | * Make sure you have a [GitHub account](https://github.com/signup/free). 9 | * [Fork](https://help.github.com/articles/fork-a-repo/) this repository on GitHub. 10 | * On your local machine, 11 | [clone](https://help.github.com/articles/cloning-a-repository/) your fork of 12 | the repository. 13 | 14 | ## Making Changes 15 | 16 | * Add some really awesome code to your local fork. It's usually a [good 17 | idea](http://blog.jasonmeridth.com/posts/do-not-issue-pull-requests-from-your-master-branch/) 18 | to make changes on a 19 | [branch](https://help.github.com/articles/creating-and-deleting-branches-within-your-repository/) 20 | with the branch name relating to the feature you are going to add. 21 | * When you are ready for others to examine and comment on your new feature, 22 | navigate to your fork of seekr2 on GitHub and open a [pull 23 | request](https://help.github.com/articles/using-pull-requests/) (PR). Note that 24 | after you launch a PR from one of your fork's branches, all 25 | subsequent commits to that branch will be added to the open pull request 26 | automatically. Each commit added to the PR will be validated for 27 | mergability, compilation and test suite compliance; the results of these tests 28 | will be visible on the PR page. 29 | * If you're providing a new feature, you must add test cases and documentation. 30 | * When the code is ready to go, make sure you run the test suite using pytest. 31 | * When you're ready to be considered for merging, check the "Ready to go" 32 | box on the PR page to let the seekr2 devs know that the changes are complete. 33 | The code will not be merged until this box is checked, the continuous 34 | integration returns checkmarks, 35 | and multiple core developers give "Approved" reviews. 36 | 37 | # Additional Resources 38 | 39 | * [General GitHub documentation](https://help.github.com/) 40 | * [PR best practices](http://codeinthehole.com/writing/pull-requests-and-other-good-practices-for-teams-using-github/) 41 | * [A guide to contributing to software packages](http://www.contribution-guide.org) 42 | * [Thinkful PR example](http://www.thinkful.com/learn/github-pull-request-tutorial/#Time-to-Submit-Your-First-PR) 43 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | Provide a brief description of the PR's purpose here. 3 | 4 | ## Todos 5 | Notable points that this PR has either accomplished or will accomplish. 6 | - [ ] TODO 1 7 | 8 | ## Questions 9 | - [ ] Question1 10 | 11 | ## Status 12 | - [ ] Ready to go -------------------------------------------------------------------------------- /.github/workflows/CI.yaml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | # GitHub has started calling new repo's first branch "main" https://github.com/github/renaming 5 | # Existing codes likely still have "master" as the primary branch 6 | # Both are tracked here to keep legacy and new codes working 7 | push: 8 | branches: 9 | - "master" 10 | - "main" 11 | pull_request: 12 | branches: 13 | - "master" 14 | - "main" 15 | # schedule: 16 | # # Nightly tests run on master by default: 17 | # # Scheduled workflows run on the latest commit on the default or base branch. 18 | # # (from https://help.github.com/en/actions/reference/events-that-trigger-workflows#scheduled-events-schedule) 19 | # - cron: "0 0 * * *" 20 | 21 | jobs: 22 | test: 23 | name: Test on ${{ matrix.os }}, Python ${{ matrix.python-version }} 24 | runs-on: ${{ matrix.os }} 25 | strategy: 26 | matrix: 27 | os: [ubuntu-latest] # [macOS-latest, ubuntu-latest, windows-latest] 28 | python-version: [3.8] #, 3.8, 3.9] 29 | 30 | steps: 31 | - uses: actions/checkout@v1 32 | 33 | - name: Additional info about the build 34 | shell: bash 35 | run: | 36 | uname -a 37 | df -h 38 | ulimit -a 39 | 40 | 41 | # More info on options: https://github.com/conda-incubator/setup-miniconda 42 | - uses: conda-incubator/setup-miniconda@v2 43 | with: 44 | python-version: ${{ matrix.python-version }} 45 | environment-file: devtools/conda-envs/test_env.yaml 46 | 47 | channels: conda-forge,defaults 48 | 49 | activate-environment: test 50 | auto-update-conda: false 51 | auto-activate-base: false 52 | show-channel-urls: true 53 | 54 | 55 | #- name: Build OpenMM 56 | # shell: bash -l {0} 57 | # run: | 58 | # git clone https://github.com/openmm/openmm.git 59 | # mkdir -p /home/runner/work/build/bin 60 | # cd openmm 61 | # mkdir build 62 | # cd build 63 | # cmake -DCMAKE_INSTALL_PREFIX=/home/runner/work/build/bin/openmm .. 64 | # make 65 | # make install 66 | # make PythonInstall 67 | # cd ../.. 68 | 69 | - name: Get NAMD 70 | shell: bash -l {0} 71 | env: 72 | NAMD_ACCESS_TOKEN3: ${{ secrets.NAMD_ACCESS_TOKEN3 }} 73 | run: | 74 | 75 | git clone https://github.com/UIUC-PPL/charm 76 | cd charm 77 | ./build charm++ multicore-linux-x86_64 --with-production 78 | export CHRMDIR=${PWD} 79 | cd .. 80 | wget http://www.ks.uiuc.edu/Research/namd/libraries/tcl8.5.9-linux-x86_64.tar.gz 81 | tar xzf tcl8.5.9-linux-x86_64.tar.gz 82 | mkdir tcl 83 | mv tcl8.5.9-linux-x86_64 tcl 84 | export TCLINC=${PWD}/tcl/tcl8.5.9-linux-x86_64/lib/ 85 | export TCLLIB=${PWD}/tcl/tcl8.5.9-linux-x86_64/include/ 86 | export LD_LIBRARY_PATH=${PWD}/tcl/tcl8.5.9-linux-x86_64/include/:$LD_LIBRARY_PATH 87 | export TCLDIR=${PWD}/tcl/tcl8.5.9-linux-x86_64 88 | 89 | # This was commented before 90 | #wget http://www.ks.uiuc.edu/Research/namd/libraries/fftw-linux-x86_64.tar.gz 91 | #tar xzf fftw-linux-x86_64.tar.gz 92 | #mkdir fftw 93 | #mv linux-x86_64 fftw 94 | #export FFTWDIR=${PWD}/fftw/linux-x86_64 95 | 96 | # DON'T FORGET TO MODIFY NAMD_ACCESS_TOKEN3 REFERENCE ABOVE 97 | 98 | git clone https://oauth2:${NAMD_ACCESS_TOKEN3}@gitlab.com/tcbgUIUC/namd.git 99 | cd namd 100 | git checkout master 101 | ./config Linux-x86_64-g++ --charm-base $CHRMDIR --tcl-prefix $TCLDIR --without-fftw #--fftw-prefix ${FFTWDIR} 102 | cd Linux-x86_64-g++ 103 | make 104 | pwd 105 | ls 106 | export PATH="$PWD:$PATH" 107 | echo "PATH: $PATH" 108 | cd ../.. 109 | 110 | 111 | - name: Install package 112 | 113 | # conda setup requires this special shell 114 | shell: bash -l {0} 115 | run: | 116 | python -m pip install . --no-deps 117 | conda list 118 | 119 | # Install seekr systems repository 120 | git clone https://github.com/seekrcentral/seekr2_systems.git 121 | 122 | # Install seekr openmm plugin 123 | git clone https://github.com/seekrcentral/seekr2_openmm_plugin.git 124 | cd seekr2_openmm_plugin/seekr2plugin 125 | mkdir build 126 | cd build 127 | export OPENMM_INSTALL_DIR=${CONDA_PREFIX} 128 | export OPENMM_LIB_PATH=$OPENMM_INSTALL_DIR/lib 129 | export OPENMM_PLUGIN_DIR=$OPENMM_LIB_PATH/plugins 130 | export LD_LIBRARY_PATH=$OPENMM_LIB_PATH:$OPENMM_PLUGIN_DIR:$LD_LIBRARY_PATH 131 | cmake -DCMAKE_INSTALL_PREFIX=${CONDA_PREFIX} -DSEEKR2_BUILD_OPENCL_LIB=OFF -DOPENMM_DIR=${CONDA_PREFIX} .. 132 | make 133 | make install 134 | make PythonInstall 135 | make test 136 | 137 | 138 | - name: Install BrownDye 139 | shell: bash -l {0} 140 | run: | 141 | sudo apt-get install libexpat1 apbs 142 | wget https://browndye.ucsd.edu/downloads/browndye2-ubuntu-20.04.tar.gz 143 | tar -xzf browndye2-ubuntu-20.04.tar.gz 144 | cd browndye2/bin 145 | export PATH="$PWD:$PATH" 146 | echo "PATH: $PATH" 147 | ls 148 | cd ../.. 149 | 150 | 151 | - name: Run tests 152 | 153 | # conda setup requires this special shell 154 | shell: bash -l {0} 155 | 156 | run: | 157 | export PATH="/home/runner/work/seekr2/seekr2/browndye2/bin:$PATH" 158 | export PATH="/home/runner/work/seekr2/seekr2/namd/Linux-x86_64-g++/:$PATH" 159 | python -m pip install . 160 | python -m openmm.testInstallation 161 | pytest -v --cov=seekr2 --cov-report=xml --color=yes -m "not needs_cuda" seekr2/tests/ seekr2_systems/tests/ 162 | # pytest -v --cov=seekr2 --cov-report=xml --color=yes -m "not needs_cuda" seekr2/tests/ 163 | # pytest -v --cov=seekr2_systems --cov-append --cov-report=xml --color=yes -m "not needs_cuda" seekr2_systems/tests/ 164 | 165 | - name: CodeCov 166 | uses: codecov/codecov-action@v1 167 | with: 168 | token: ${{ secrets.CODECOV_TOKEN }} 169 | file: ./coverage.xml 170 | directory: ./coverage/reports/ 171 | flags: unittests 172 | name: codecov-${{ matrix.os }}-py${{ matrix.python-version }} 173 | fail_ci_if_error: true 174 | path_to_write_report: ./coverage/codecov_report.txt 175 | verbose: true 176 | -------------------------------------------------------------------------------- /.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 | .pytest_cache 45 | nosetests.xml 46 | coverage.xml 47 | *.cover 48 | .hypothesis/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | 58 | # Flask stuff: 59 | instance/ 60 | .webassets-cache 61 | 62 | # Scrapy stuff: 63 | .scrapy 64 | 65 | # Sphinx documentation 66 | docs/_build/ 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 | # profraw files from LLVM? Unclear exactly what triggers this 105 | # There are reports this comes from LLVM profiling, but also Xcode 9. 106 | *profraw 107 | -------------------------------------------------------------------------------- /.lgtm.yml: -------------------------------------------------------------------------------- 1 | # Configure LGTM for this package 2 | 3 | extraction: 4 | python: # Configure Python 5 | python_setup: # Configure the setup 6 | version: 3 # Specify Version 3 7 | path_classifiers: 8 | library: 9 | - versioneer.py # Set Versioneer.py to an external "library" (3rd party code) 10 | - devtools/* 11 | generated: 12 | - seekr2/_version.py 13 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # .readthedocs.yml 2 | 3 | version: 2 4 | 5 | build: 6 | os: ubuntu-22.04 7 | tools: 8 | python: "3.12" 9 | 10 | sphinx: 11 | configuration: docs/conf.py 12 | 13 | python: 14 | install: 15 | - requirements: docs/requirements.txt 16 | - method: pip 17 | path: . 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | MIT License 3 | 4 | Copyright (c) 2021 Lane Votapka 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include LICENSE 2 | include MANIFEST.in 3 | include versioneer.py 4 | 5 | graft seekr2 6 | global-exclude *.py[cod] __pycache__ *.so 7 | include seekr2/_version.py 8 | -------------------------------------------------------------------------------- /devtools/README.md: -------------------------------------------------------------------------------- 1 | # Development, testing, and deployment tools 2 | 3 | This directory contains a collection of tools for running Continuous Integration (CI) tests, 4 | conda installation, and other development tools not directly related to the coding process. 5 | 6 | 7 | ## Manifest 8 | 9 | ### Continuous Integration 10 | 11 | You should test your code, but do not feel compelled to use these specific programs. You also may not need Unix and 12 | Windows testing if you only plan to deploy on specific platforms. These are just to help you get started. 13 | 14 | The items in this directory have been left for legacy purposes since the change to GitHub Actions, 15 | They will likely be removed in a future version. 16 | 17 | * `legacy-miniconda-setup`: A preserved copy of a helper directory which made Linux and OSX based testing through [Travis-CI](https://about.travis-ci.com/) simpler 18 | * `before_install.sh`: Pip/Miniconda pre-package installation script for Travis. No longer needed thanks to 19 | [GitHub Actions](https://docs.github.com/en/free-pro-team@latest/actions) and the [conda-incubator/setup-miniconda Action](https://github.com/conda-incubator/setup-miniconda) 20 | 21 | ### Conda Environment: 22 | 23 | This directory contains the files to setup the Conda environment for testing purposes 24 | 25 | * `conda-envs`: directory containing the YAML file(s) which fully describe Conda Environments, their dependencies, and those dependency provenance's 26 | * `test_env.yaml`: Simple test environment file with base dependencies. Channels are not specified here and therefore respect global Conda configuration 27 | 28 | ### Additional Scripts: 29 | 30 | This directory contains OS agnostic helper scripts which don't fall in any of the previous categories 31 | * `scripts` 32 | * `create_conda_env.py`: Helper program for spinning up new conda environments based on a starter file with Python Version and Env. Name command-line options 33 | 34 | 35 | ## How to contribute changes 36 | - Clone the repository if you have write access to the main repo, fork the repository if you are a collaborator. 37 | - Make a new branch with `git checkout -b {your branch name}` 38 | - Make changes and test your code 39 | - Ensure that the test environment dependencies (`conda-envs`) line up with the build and deploy dependencies (`conda-recipe/meta.yaml`) 40 | - Push the branch to the repo (either the main or your fork) with `git push -u origin {your branch name}` 41 | * Note that `origin` is the default name assigned to the remote, yours may be different 42 | - Make a PR on GitHub with your changes 43 | - We'll review the changes and get your code into the repo after lively discussion! 44 | 45 | 46 | ## Checklist for updates 47 | - [ ] Make sure there is an/are issue(s) opened for your specific update 48 | - [ ] Create the PR, referencing the issue 49 | - [ ] Debug the PR as needed until tests pass 50 | - [ ] Tag the final, debugged version 51 | * `git tag -a X.Y.Z [latest pushed commit] && git push --follow-tags` 52 | - [ ] Get the PR merged in 53 | 54 | ## Versioneer Auto-version 55 | [Versioneer](https://github.com/warner/python-versioneer) will automatically infer what version 56 | is installed by looking at the `git` tags and how many commits ahead this version is. The format follows 57 | [PEP 440](https://www.python.org/dev/peps/pep-0440/) and has the regular expression of: 58 | ```regexp 59 | \d+.\d+.\d+(?\+\d+-[a-z0-9]+) 60 | ``` 61 | If the version of this commit is the same as a `git` tag, the installed version is the same as the tag, 62 | e.g. `seekr2-0.1.2`, otherwise it will be appended with `+X` where `X` is the number of commits 63 | ahead from the last tag, and then `-YYYYYY` where the `Y`'s are replaced with the `git` commit hash. 64 | -------------------------------------------------------------------------------- /devtools/conda-envs/test_env.yaml: -------------------------------------------------------------------------------- 1 | name: test 2 | channels: 3 | - conda-forge 4 | 5 | dependencies: 6 | # Base depends 7 | - python 8 | - pip 9 | - numpy 10 | - scipy 11 | - matplotlib 12 | - openmm 13 | - swig 14 | 15 | # Testing 16 | - pytest 17 | - pytest-cov 18 | - codecov 19 | 20 | # Pip-only installs 21 | - pip: 22 | - codecov 23 | - parmed 24 | - mdtraj 25 | - bubblebuster 26 | 27 | -------------------------------------------------------------------------------- /devtools/legacy-miniconda-setup/before_install.sh: -------------------------------------------------------------------------------- 1 | # Temporarily change directory to $HOME to install software 2 | pushd . 3 | cd $HOME 4 | # Make sure some level of pip is installed 5 | python -m ensurepip 6 | 7 | # Install Miniconda 8 | if [ "$TRAVIS_OS_NAME" == "osx" ]; then 9 | # Make OSX md5 mimic md5sum from linux, alias does not work 10 | md5sum () { 11 | command md5 -r "$@" 12 | } 13 | MINICONDA=Miniconda3-latest-MacOSX-x86_64.sh 14 | else 15 | MINICONDA=Miniconda3-latest-Linux-x86_64.sh 16 | fi 17 | MINICONDA_HOME=$HOME/miniconda 18 | MINICONDA_MD5=$(wget -qO- https://repo.anaconda.com/miniconda/ | grep -A3 $MINICONDA | sed -n '4p' | sed -n 's/ *\(.*\)<\/td> */\1/p') 19 | wget -q https://repo.anaconda.com/miniconda/$MINICONDA 20 | if [[ $MINICONDA_MD5 != $(md5sum $MINICONDA | cut -d ' ' -f 1) ]]; then 21 | echo "Miniconda MD5 mismatch" 22 | exit 1 23 | fi 24 | bash $MINICONDA -b -p $MINICONDA_HOME 25 | 26 | # Configure miniconda 27 | export PIP_ARGS="-U" 28 | # New to conda >=4.4 29 | echo ". $MINICONDA_HOME/etc/profile.d/conda.sh" >> ~/.bashrc # Source the profile.d file 30 | echo "conda activate" >> ~/.bashrc # Activate conda 31 | source ~/.bashrc # source file to get new commands 32 | #export PATH=$MINICONDA_HOME/bin:$PATH # Old way, should not be needed anymore 33 | 34 | conda config --add channels conda-forge 35 | 36 | conda config --set always_yes yes 37 | conda install conda conda-build jinja2 anaconda-client 38 | conda update --quiet --all 39 | 40 | # Restore original directory 41 | popd 42 | -------------------------------------------------------------------------------- /devtools/scripts/create_conda_env.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import os 3 | import re 4 | import glob 5 | import shutil 6 | import subprocess as sp 7 | from tempfile import TemporaryDirectory 8 | from contextlib import contextmanager 9 | # YAML imports 10 | try: 11 | import yaml # PyYAML 12 | loader = yaml.load 13 | except ImportError: 14 | try: 15 | import ruamel_yaml as yaml # Ruamel YAML 16 | except ImportError: 17 | try: 18 | # Load Ruamel YAML from the base conda environment 19 | from importlib import util as import_util 20 | CONDA_BIN = os.path.dirname(os.environ['CONDA_EXE']) 21 | ruamel_yaml_path = glob.glob(os.path.join(CONDA_BIN, '..', 22 | 'lib', 'python*.*', 'site-packages', 23 | 'ruamel_yaml', '__init__.py'))[0] 24 | # Based on importlib example, but only needs to load_module since its the whole package, not just 25 | # a module 26 | spec = import_util.spec_from_file_location('ruamel_yaml', ruamel_yaml_path) 27 | yaml = spec.loader.load_module() 28 | except (KeyError, ImportError, IndexError): 29 | raise ImportError("No YAML parser could be found in this or the conda environment. " 30 | "Could not find PyYAML or Ruamel YAML in the current environment, " 31 | "AND could not find Ruamel YAML in the base conda environment through CONDA_EXE path. " 32 | "Environment not created!") 33 | loader = yaml.YAML(typ="safe").load # typ="safe" avoids odd typing on output 34 | 35 | 36 | @contextmanager 37 | def temp_cd(): 38 | """Temporary CD Helper""" 39 | cwd = os.getcwd() 40 | with TemporaryDirectory() as td: 41 | try: 42 | os.chdir(td) 43 | yield 44 | finally: 45 | os.chdir(cwd) 46 | 47 | 48 | # Args 49 | parser = argparse.ArgumentParser(description='Creates a conda environment from file for a given Python version.') 50 | parser.add_argument('-n', '--name', type=str, 51 | help='The name of the created Python environment') 52 | parser.add_argument('-p', '--python', type=str, 53 | help='The version of the created Python environment') 54 | parser.add_argument('conda_file', 55 | help='The file for the created Python environment') 56 | 57 | args = parser.parse_args() 58 | 59 | # Open the base file 60 | with open(args.conda_file, "r") as handle: 61 | yaml_script = loader(handle.read()) 62 | 63 | python_replacement_string = "python {}*".format(args.python) 64 | 65 | try: 66 | for dep_index, dep_value in enumerate(yaml_script['dependencies']): 67 | if re.match('python([ ><=*]+[0-9.*]*)?$', dep_value): # Match explicitly 'python' and its formats 68 | yaml_script['dependencies'].pop(dep_index) 69 | break # Making the assumption there is only one Python entry, also avoids need to enumerate in reverse 70 | except (KeyError, TypeError): 71 | # Case of no dependencies key, or dependencies: None 72 | yaml_script['dependencies'] = [] 73 | finally: 74 | # Ensure the python version is added in. Even if the code does not need it, we assume the env does 75 | yaml_script['dependencies'].insert(0, python_replacement_string) 76 | 77 | # Figure out conda path 78 | if "CONDA_EXE" in os.environ: 79 | conda_path = os.environ["CONDA_EXE"] 80 | else: 81 | conda_path = shutil.which("conda") 82 | if conda_path is None: 83 | raise RuntimeError("Could not find a conda binary in CONDA_EXE variable or in executable search path") 84 | 85 | print("CONDA ENV NAME {}".format(args.name)) 86 | print("PYTHON VERSION {}".format(args.python)) 87 | print("CONDA FILE NAME {}".format(args.conda_file)) 88 | print("CONDA PATH {}".format(conda_path)) 89 | 90 | # Write to a temp directory which will always be cleaned up 91 | with temp_cd(): 92 | temp_file_name = "temp_script.yaml" 93 | with open(temp_file_name, 'w') as f: 94 | f.write(yaml.dump(yaml_script)) 95 | sp.call("{} env create -n {} -f {}".format(conda_path, args.name, temp_file_name), shell=True) 96 | -------------------------------------------------------------------------------- /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 = seekr2 8 | SOURCEDIR = . 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 | # Compiling seekr2's Documentation 2 | 3 | The docs for this project are built with [Sphinx](http://www.sphinx-doc.org/en/master/). 4 | To compile the docs, first ensure that Sphinx and the ReadTheDocs theme are installed. 5 | 6 | 7 | ```bash 8 | conda install sphinx sphinx_rtd_theme 9 | ``` 10 | 11 | 12 | Once installed, you can use the `Makefile` in this directory to compile static HTML pages by 13 | ```bash 14 | make html 15 | ``` 16 | 17 | The compiled docs will be in the `_build` directory and can be viewed by opening `index.html` (which may itself 18 | be inside a directory called `html/` depending on what version of Sphinx is installed). 19 | 20 | 21 | A configuration file for [Read The Docs](https://readthedocs.org/) (readthedocs.yaml) is included in the top level of the repository. To use Read the Docs to host your documentation, go to https://readthedocs.org/ and connect this repository. You may need to change your default branch to `main` under Advanced Settings for the project. 22 | 23 | If you would like to use Read The Docs with `autodoc` (included automatically) and your package has dependencies, you will need to include those dependencies in your documentation yaml file (`docs/requirements.yaml`). 24 | 25 | -------------------------------------------------------------------------------- /docs/_static/README.md: -------------------------------------------------------------------------------- 1 | # Static Doc Directory 2 | 3 | Add any paths that contain custom static files (such as style sheets) here, 4 | relative to the `conf.py` file's directory. 5 | They are copied after the builtin static files, 6 | so a file named "default.css" will overwrite the builtin "default.css". 7 | 8 | The path to this folder is set in the Sphinx `conf.py` file in the line: 9 | ```python 10 | templates_path = ['_static'] 11 | ``` 12 | 13 | ## Examples of file to add to this directory 14 | * Custom Cascading Style Sheets 15 | * Custom JavaScript code 16 | * Static logo images 17 | -------------------------------------------------------------------------------- /docs/_static/entropy_barrier.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seekrcentral/seekr2/93bf27571b0bdbce8133227538261e4cddc7b137/docs/_static/entropy_barrier.mp4 -------------------------------------------------------------------------------- /docs/_static/muller_potential.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seekrcentral/seekr2/93bf27571b0bdbce8133227538261e4cddc7b137/docs/_static/muller_potential.mp4 -------------------------------------------------------------------------------- /docs/_templates/README.md: -------------------------------------------------------------------------------- 1 | # Templates Doc Directory 2 | 3 | Add any paths that contain templates here, relative to 4 | the `conf.py` file's directory. 5 | They are copied after the builtin template files, 6 | so a file named "page.html" will overwrite the builtin "page.html". 7 | 8 | The path to this folder is set in the Sphinx `conf.py` file in the line: 9 | ```python 10 | html_static_path = ['_templates'] 11 | ``` 12 | 13 | ## Examples of file to add to this directory 14 | * HTML extensions of stock pages like `page.html` or `layout.html` 15 | -------------------------------------------------------------------------------- /docs/api.rst: -------------------------------------------------------------------------------- 1 | API Documentation 2 | ================= 3 | 4 | Normally, one would run SEEKR2 directly on the Linux terminal. However, it is 5 | possible to perform an entire SEEKR2 calculation, along with all of its 6 | auxiliary functions, from a custom python program by using SEEKR2's Application 7 | Programming Interface (API). 8 | 9 | .. toctree:: 10 | :maxdepth: 1 11 | :caption: Contents: 12 | 13 | api_examples 14 | 15 | -------------------------------------------------------------------------------- /docs/api_examples.rst: -------------------------------------------------------------------------------- 1 | API Examples 2 | ============ 3 | 4 | An example of a script to run a SEEKR2 calculation can be found in Listing 1. 5 | This script defines a “model input” object, loads its parameters from an XML 6 | file, generates the full model, checks the model for potential problems, runs 7 | any and all of the MD and BD simulations, and analyzes the results.   8 | 9 | **Listing 1:** a sample Python script using the SEEKR2 API to perform a full 10 | SEEKR calculation. NOTE: this script should be run from the seekr2/seekr2/ 11 | directory to work as-is.:: 12 | 13 | import seekr2 14 | model_input_filename = “data/sample_input_mmvt_openmm.xml" 15 | model_input = seekr2.prepare.common_prepare.Model_input() 16 | model_input.deserialize(model_input_filename, user_input=True) 17 | model, xml_path = seekr2.prepare.prepare(model_input) 18 | model.anchor_rootdir = os.path.dirname(xml_path) 19 | seekr2.modules.check.check_pre_simulation_all(model) 20 | seekr2.run.run(model, "any") 21 | analysis = seekr2.analyze.analyze(model) 22 | analysis.print_results() 23 | 24 | The objects can be accessed/modified from the Python API at any step in the 25 | process. For instance, if one wishes to add or move milestones, one could add 26 | the lines shown in Listing 2 before the model is prepared. Or say that one 27 | wants to access the milestoning matrix directly, one could add the lines in 28 | listing 3 after analysis object is generated.   29 | 30 | **Listing 2:** a an additional snippet of sample Python code to use the SEEKR2 31 | API for first add an anchor to the calculation and generate the model. Then, 32 | to demonstrate that the radius can be changed after the model is generated, 33 | the anchor’s radius is changed and the model is regenerated.:: 34 | 35 | from openmm import unit 36 | new_input_anchor = seekr2.modules.common_cv.Spherical_cv_anchor() 37 | new_input_anchor.radius = 0.1 * unit.nanometer 38 | model_input.cv_inputs[0].input_anchors.insert(1, new_input_anchor) 39 | model, xml_path = seekr2.prepare.prepare(model_input, force_overwrite=True) 40 | model_input.cv_inputs[0].input_anchors[1].radius = 0.11 * unit.nanometers 41 | model, xml_path = seekr2.prepare.prepare(model_input, force_overwrite=True) 42 |    43 | **Listing 3:** The milestoning rate matrix “Q” or free energy profile are just 44 | two examples of many quantities that may be accessed directly from the Python 45 | analysis object.:: 46 | 47 | print(analysis.main_data_sample.Q) 48 | print(analysis.free_energy_profile) 49 | 50 | This script is just intended to give developers a glimpse of what is possible 51 | when using the API. Please consult the documentation within the code itself 52 | for details about the arguments to each of these functions. -------------------------------------------------------------------------------- /docs/citations.rst: -------------------------------------------------------------------------------- 1 | Citations 2 | ========= 3 | 4 | On this page, you will find a list of BibTex format citations for easy citing. 5 | 6 | Main SEEKR2 Paper 7 | ----------------- 8 | 9 | If you wish to cite SEEKR2, please cite the following paper:: 10 | 11 | @article{votapka2022seekr2, 12 | title={SEEKR2: Versatile multiscale milestoning utilizing the OpenMM molecular dynamics engine}, 13 | author={Votapka, Lane W and Stokely, Andrew M and Ojha, Anupam A and Amaro, Rommie E}, 14 | journal={Journal of chemical information and modeling}, 15 | volume={62}, 16 | number={13}, 17 | pages={3253--3262}, 18 | year={2022}, 19 | publisher={ACS Publications} 20 | } 21 | 22 | Dependencies 23 | ------------ 24 | 25 | One should also cite SEEKR2's dependencies:: 26 | 27 | @Article{Hunter:2007, 28 | Author = {Hunter, J. D.}, 29 | Title = {Matplotlib: A 2D graphics environment}, 30 | Journal = {Computing in Science \& Engineering}, 31 | Volume = {9}, 32 | Number = {3}, 33 | Pages = {90--95}, 34 | abstract = {Matplotlib is a 2D graphics package used for Python for 35 | application development, interactive scripting, and publication-quality 36 | image generation across user interfaces and operating systems.}, 37 | publisher = {IEEE COMPUTER SOC}, 38 | doi = {10.1109/MCSE.2007.55}, 39 | year = 2007 40 | } 41 | 42 | @article{van2011numpy, 43 | title={The NumPy array: a structure for efficient numerical computation}, 44 | author={Van Der Walt, Stefan and Colbert, S Chris and Varoquaux, Gael}, 45 | journal={Computing in Science \& Engineering}, 46 | volume={13}, 47 | number={2}, 48 | pages={22--30}, 49 | year={2011}, 50 | publisher={AIP Publishing}, 51 | doi={10.1109/MCSE.2011.37} 52 | } 53 | 54 | @Misc{JOP+01, 55 | author = {Eric Jones and Travis Oliphant and Pearu Peterson and others}, 56 | title = {{SciPy}: Open source scientific tools for {Python}}, 57 | year = {2001--}, 58 | url = "http://www.scipy.org/", 59 | note = {[Online; accessed 2015-07-13]} 60 | } 61 | 62 | @article{doi:10.1021/acs.jctc.9b01211, 63 | author = {Swinburne, Thomas D. and Wales, David J.}, 64 | title = {Defining, Calculating, and Converging Observables of a Kinetic Transition Network}, 65 | journal = {Journal of Chemical Theory and Computation}, 66 | volume = {16}, 67 | number = {4}, 68 | pages = {2661-2679}, 69 | year = {2020}, 70 | doi = {10.1021/acs.jctc.9b01211}, 71 | note ={PMID: 32155072}, 72 | } 73 | 74 | Other SEEKR Papers 75 | ------------------ 76 | 77 | One may also optionally cite one or more of the following papers:: 78 | 79 | @article{ojha2023qmrebind, 80 | title={QMrebind: incorporating quantum mechanical force field reparameterization at the ligand binding site for improved drug-target kinetics through milestoning simulations}, 81 | author={Ojha, Anupam Anand and Votapka, Lane William and Amaro, Rommie Elizabeth}, 82 | journal={Chemical Science}, 83 | volume={14}, 84 | number={45}, 85 | pages={13159--13175}, 86 | year={2023}, 87 | publisher={Royal Society of Chemistry} 88 | } 89 | 90 | @article{doi:10.1021/acs.jcim.2c01589, 91 | author = {Ojha, Anupam Anand and Srivastava, Ambuj and Votapka, Lane William and Amaro, Rommie E.}, 92 | title = {Selectivity and Ranking of Tight-Binding JAK-STAT Inhibitors Using Markovian Milestoning with Voronoi Tessellations}, 93 | journal = {Journal of Chemical Information and Modeling}, 94 | volume = {63}, 95 | number = {8}, 96 | pages = {2469-2482}, 97 | year = {2023}, 98 | doi = {10.1021/acs.jcim.2c01589}, 99 | note ={PMID: 37023323} 100 | } 101 | 102 | @article{votapka2017seekr, 103 | title={SEEKR: simulation enabled estimation of kinetic rates, a computational tool to estimate molecular kinetics and its application to trypsin--benzamidine binding}, 104 | author={Votapka, Lane W and Jagger, Benjamin R and Heyneman, Alexandra L and Amaro, Rommie E}, 105 | journal={The Journal of Physical Chemistry B}, 106 | volume={121}, 107 | number={15}, 108 | pages={3597--3606}, 109 | year={2017}, 110 | publisher={ACS Publications} 111 | } 112 | 113 | @article{jagger2020predicting, 114 | title={Predicting ligand binding kinetics using a Markovian milestoning with voronoi tessellations multiscale approach}, 115 | author={Jagger, Benjamin R and Ojha, Anupam A and Amaro, Rommie E}, 116 | journal={Journal of Chemical Theory and Computation}, 117 | volume={16}, 118 | number={8}, 119 | pages={5348--5357}, 120 | year={2020}, 121 | publisher={ACS Publications} 122 | } 123 | 124 | @article{doi:10.1021/acs.jpclett.8b02047, 125 | author = {Jagger, Benjamin R. and Lee, Christopher T. and Amaro, Rommie E.}, 126 | title = {Quantitative Ranking of Ligand Binding Kinetics with a Multiscale Milestoning Simulation Approach}, 127 | journal = {The Journal of Physical Chemistry Letters}, 128 | volume = {9}, 129 | number = {17}, 130 | pages = {4941-4948}, 131 | year = {2018}, 132 | doi = {10.1021/acs.jpclett.8b02047}, 133 | note ={PMID: 30070844}, 134 | } 135 | 136 | @article{10.1371/journal.pcbi.1004381, 137 | doi = {10.1371/journal.pcbi.1004381}, 138 | author = {Votapka, Lane W. AND Amaro, Rommie E.}, 139 | journal = {PLOS Computational Biology}, 140 | publisher = {Public Library of Science}, 141 | title = {Multiscale Estimation of Binding Kinetics Using Brownian Dynamics, Molecular Dynamics and Milestoning}, 142 | year = {2015}, 143 | month = {10}, 144 | volume = {11}, 145 | url = {https://doi.org/10.1371/journal.pcbi.1004381}, 146 | pages = {1-24}, 147 | abstract = {The kinetic rate constants of binding were estimated for four biochemically relevant molecular systems by a method that uses milestoning theory to combine Brownian dynamics simulations with more detailed molecular dynamics simulations. The rate constants found using this method agreed well with experimentally and theoretically obtained values. We predicted the association rate of a small charged molecule toward both a charged and an uncharged spherical receptor and verified the estimated value with Smoluchowski theory. We also calculated the kon rate constant for superoxide dismutase with its natural substrate, O2−, in a validation of a previous experiment using similar methods but with a number of important improvements. We also calculated the kon for a new system: the N-terminal domain of Troponin C with its natural substrate Ca2+. The kon calculated for the latter two systems closely resemble experimentally obtained values. This novel multiscale approach is computationally cheaper and more parallelizable when compared to other methods of similar accuracy. We anticipate that this methodology will be useful for predicting kinetic rate constants and for understanding the process of binding between a small molecule and a protein receptor.}, 148 | number = {10}, 149 | } 150 | 151 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Configuration file for the Sphinx documentation builder. 4 | # 5 | # This file does only contain a selection of the most common options. For a 6 | # full list see the documentation: 7 | # http://www.sphinx-doc.org/en/stable/config 8 | 9 | # -- Path setup -------------------------------------------------------------- 10 | 11 | # If extensions (or modules to document with autodoc) are in another directory, 12 | # add these directories to sys.path here. If the directory is relative to the 13 | # documentation root, use os.path.abspath to make it absolute, like shown here. 14 | 15 | # Incase the project was not installed 16 | import os 17 | import sys 18 | sys.path.insert(0, os.path.abspath('..')) 19 | 20 | import seekr2 21 | 22 | 23 | # -- Project information ----------------------------------------------------- 24 | 25 | project = 'seekr2' 26 | copyright = ("2021, Lane Votapka. Project structure based on the " 27 | "Computational Molecular Science Python Cookiecutter version 1.5") 28 | author = 'Lane Votapka' 29 | 30 | # The short X.Y version 31 | version = '2.1' 32 | # The full version, including alpha/beta/rc tags 33 | release = '2.1.4-beta' 34 | 35 | 36 | # -- General configuration --------------------------------------------------- 37 | 38 | # If your documentation needs a minimal Sphinx version, state it here. 39 | # 40 | # needs_sphinx = '1.0' 41 | 42 | # Add any Sphinx extension module names here, as strings. They can be 43 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 44 | # ones. 45 | extensions = [ 46 | 'sphinx.ext.autosummary', 47 | 'sphinx.ext.autodoc', 48 | 'sphinx.ext.mathjax', 49 | 'sphinx.ext.viewcode', 50 | 'sphinx.ext.napoleon', 51 | 'sphinx.ext.intersphinx', 52 | 'sphinx.ext.extlinks', 53 | 'sphinx_rtd_theme', 54 | ] 55 | 56 | autosummary_generate = True 57 | napoleon_google_docstring = False 58 | napoleon_use_param = False 59 | napoleon_use_ivar = True 60 | 61 | # Add any paths that contain templates here, relative to this directory. 62 | templates_path = ['_templates'] 63 | 64 | # The suffix(es) of source filenames. 65 | # You can specify multiple suffix as a list of string: 66 | # 67 | # source_suffix = ['.rst', '.md'] 68 | source_suffix = '.rst' 69 | 70 | # The master toctree document. 71 | master_doc = 'index' 72 | 73 | # The language for content autogenerated by Sphinx. Refer to documentation 74 | # for a list of supported languages. 75 | # 76 | # This is also used if you do content translation via gettext catalogs. 77 | # Usually you set "language" from the command line for these cases. 78 | language = "en" 79 | 80 | # List of patterns, relative to source directory, that match files and 81 | # directories to ignore when looking for source files. 82 | # This pattern also affects html_static_path and html_extra_path . 83 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] 84 | 85 | # The name of the Pygments (syntax highlighting) style to use. 86 | pygments_style = 'default' 87 | 88 | 89 | # -- Options for HTML output ------------------------------------------------- 90 | 91 | # The theme to use for HTML and HTML Help pages. See the documentation for 92 | # a list of builtin themes. 93 | # 94 | html_theme = 'sphinx_rtd_theme' 95 | 96 | # Theme options are theme-specific and customize the look and feel of a theme 97 | # further. For a list of options available for each theme, see the 98 | # documentation. 99 | # 100 | # html_theme_options = {} 101 | 102 | # Add any paths that contain custom static files (such as style sheets) here, 103 | # relative to this directory. They are copied after the builtin static files, 104 | # so a file named "default.css" will overwrite the builtin "default.css". 105 | html_static_path = ['_static'] 106 | 107 | # Custom sidebar templates, must be a dictionary that maps document names 108 | # to template names. 109 | # 110 | # The default sidebars (for documents that don't match any pattern) are 111 | # defined by theme itself. Builtin themes are using these templates by 112 | # default: ``['localtoc.html', 'relations.html', 'sourcelink.html', 113 | # 'searchbox.html']``. 114 | # 115 | # html_sidebars = {} 116 | 117 | 118 | # -- Options for HTMLHelp output --------------------------------------------- 119 | 120 | # Output file base name for HTML help builder. 121 | htmlhelp_basename = 'seekr2doc' 122 | 123 | 124 | # -- Options for LaTeX output ------------------------------------------------ 125 | 126 | latex_elements = { 127 | # The paper size ('letterpaper' or 'a4paper'). 128 | # 129 | # 'papersize': 'letterpaper', 130 | 131 | # The font size ('10pt', '11pt' or '12pt'). 132 | # 133 | # 'pointsize': '10pt', 134 | 135 | # Additional stuff for the LaTeX preamble. 136 | # 137 | # 'preamble': '', 138 | 139 | # Latex figure (float) alignment 140 | # 141 | # 'figure_align': 'htbp', 142 | } 143 | 144 | # Grouping the document tree into LaTeX files. List of tuples 145 | # (source start file, target name, title, 146 | # author, documentclass [howto, manual, or own class]). 147 | latex_documents = [ 148 | (master_doc, 'seekr2.tex', 'seekr2 Documentation', 149 | 'seekr2', 'manual'), 150 | ] 151 | 152 | 153 | # -- Options for manual page output ------------------------------------------ 154 | 155 | # One entry per manual page. List of tuples 156 | # (source start file, name, description, authors, manual section). 157 | man_pages = [ 158 | (master_doc, 'seekr2', 'seekr2 Documentation', 159 | [author], 1) 160 | ] 161 | 162 | 163 | # -- Options for Texinfo output ---------------------------------------------- 164 | 165 | # Grouping the document tree into Texinfo files. List of tuples 166 | # (source start file, target name, title, author, 167 | # dir menu entry, description, category) 168 | texinfo_documents = [ 169 | (master_doc, 'seekr2', 'seekr2 Documentation', 170 | author, 'seekr2', 'Simulation-Enabled Estimation of Kinetic Rates - Version 2', 171 | 'Miscellaneous'), 172 | ] 173 | 174 | 175 | # -- Extension configuration ------------------------------------------------- 176 | -------------------------------------------------------------------------------- /docs/faq.rst: -------------------------------------------------------------------------------- 1 | Frequently Asked Questions 2 | ========================== 3 | 4 | .. contents:: Contents 5 | :depth: 3 6 | 7 | What is SEEKR2? 8 | --------------- 9 | Simulation Enabled Estimation of Kinetic Rates is, simultaneously, a collection 10 | of scientific software programs, and also a technical approach to estimate the 11 | kinetics and thermodynamics of certain molecular processes, especially ligand- 12 | receptor binding, using Milestoning theory. SEEKR2 is the second iteration of 13 | the software, with better speed, capabilities, and usability than the earlier 14 | version. 15 | 16 | What can SEEKR2 do? 17 | ------------------- 18 | At present, the main utility of SEEKR2 is to estimate the kinetics of binding 19 | and unbinding (represented by the quantities k-on and k-off), in addition to 20 | the thermodynamics of binding (represented by the Gibbs free energy of 21 | binding). 22 | 23 | Testing and preliminary calculations indicate that SEEKR2 can 24 | consistently obtain binding/unbinding rate constants within an order of 25 | magnitude of the experimental quantity, and sometimes much better, even for 26 | systems with very long residence times. SEEKR2 can also usually obtain Gibbs 27 | free energies of binding within ~1 kcal/mol of experiment. In addition, the 28 | SEEKR method has been able to rank compounds by their residence time and 29 | affinity to a receptor with good accuracy. 30 | 31 | More details about SEEKR2's accuracy and performance can be obtained from the 32 | publications on the :doc:`Index page`. 33 | 34 | Development is ongoing, and more capabilities for SEEKR2 are being actively 35 | pursued. The kinetics and thermodynamics of intramolecular motion (such as 36 | hinge or pocket opening/closing), intersite transfer, peptide folding, and 37 | processes can be estimated using SEEKR2. Publications of these applications 38 | are forthcoming. 39 | 40 | What if I doubt SEEKR2's usefulness/validity? 41 | --------------------------------------------- 42 | 43 | 44 | 45 | How can I use SEEKR2 for my research? 46 | ------------------------------------- 47 | 48 | 49 | How does one get a benchmark of a SEEKR2 calculation? 50 | ----------------------------------------------------- 51 | If the SEEKR2 run.py program terminates successfully, the last thing it will 52 | print is a benchmark (in ns/day) for an MD anchor. Therefore, if you wish to 53 | obtain a benchmark, consider running a short SEEKR2 calculation by passing a 54 | relatively small number (like 10000) to the "-t" argument of run.py. 55 | 56 | 57 | How many CPUs are optimal for a SEEKR2 calculation? 58 | --------------------------------------------------- 59 | In NAMD mode, using multiple CPUs is likely to make the calculation go faster. 60 | However, in OpenMM mode, the CUDA platform is designed to use only one CPU, 61 | so using multiple CPUs in OpenMM mode is not likely to make the calculation go 62 | any faster. 63 | 64 | 65 | How are the convergence plots calculated in SEEKR2? 66 | --------------------------------------------------- 67 | 68 | 69 | 70 | How does SEEKR2 compute the convergence value for the individual anchors? 71 | ------------------------------------------------------------------------- 72 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | SEEKR2: Multiscale Milestoning Calculations of Kinetics and Thermodynamics 2 | ========================================================================== 3 | 4 | :Release: |release| 5 | :Date: |today| 6 | 7 | **SEEKR2** Simulation Enabled Estimation of Kinetic Rates version 2 8 | is a package to perform simulations at multiple scales for the calculation of 9 | kinetics and thermodynamics quantities. 10 | 11 | Most typically, one would use this package to obtain the kinetics and 12 | thermodynamics of binding and unbinding between a small molecule and 13 | biomolecular receptor. Also typically, this package performs molecular 14 | dynamics (MD) and Brownian dynamics (BD) simulations of the binding process 15 | within multiple regions of phase space, utilizing expensive, but highly 16 | accurate MD for regions where close molecular interaction would require high 17 | accuracy, but utilizing faster, but more approximate BD for regions of greater 18 | intermolecular distance. This way the advantages of each simulation regime is 19 | augmented and their disadvantages are reduced. The regimes are then combined 20 | using the theory of milestoning such that the kinetics and thermodynamics of the 21 | process under interest is obtained. 22 | 23 | Two versions of milestoning theory are available to use in SEEKR2: 24 | 25 | 1. **Markovian milestoning with Voronoi Tesselations (MMVT)**: Vanden-Eijnden, E.; Venturoli, M. Markovian Milestoning with Voronoi Tessellations. J. Chem. Phys. 2009, 130 (19), 194101. https://doi.org/10.1063/1.3129843 26 | 27 | 2. **The original formulation of milestoning theory (Elber milestoning)**: Faradjian, A. K.; Elber, R. Computing Time Scales from Reaction Coordinates by Milestoning. J. Chem. Phys. 2004, 120 (23), 10880–10889. https://doi.org/10.1063/1.1738640 28 | 29 | .. toctree:: 30 | :maxdepth: 1 31 | :caption: Contents: 32 | 33 | installation 34 | running_calculations 35 | tutorial 36 | model_input_files 37 | program_options 38 | api 39 | faq 40 | citations 41 | 42 | Cite SEEKR2 43 | =========== 44 | 45 | For BibTex files of any or all of the following citations, please visit: https://seekr2.readthedocs.io/en/latest/citations.html 46 | 47 | If you wish to cite SEEKR2, please cite the following paper: 48 | 49 | * Votapka, L. W.; Stokely, A. M.; Ojha, A. A.; Amaro, R. E. SEEKR2: Versatile Multiscale Milestoning Utilizing the OpenMM Molecular Dynamics Engine. J. Chem. Inf. Mod. 2022 62 (13), 3253-3262. DOI: 10.1021/acs.jcim.2c00501 50 | 51 | One should also cite SEEKR2's dependencies: 52 | 53 | * Van Der Walt, S., Colbert, S.C. & Varoquaux, G., 2011. The NumPy array: a structure for efficient numerical computation. Computing in Science & Engineering, 13(2), pp.22–30. 54 | 55 | * Jones, E. et al., 2001. SciPy: Open source scientific tools for Python. 56 | 57 | * Hunter, J.D., 2007. Matplotlib: A 2D graphics environment. Computing in Science & Engineering, 9(3), pp.90–95. 58 | 59 | * T.D. Swinburne and D.J. Wales, Defining, Calculating, and Converging Observables of a Kinetic Transition Network, J. Chemical Theory and Computation (2020), https://doi.org/10.1021/acs.jctc.9b01211 60 | 61 | One may also optionally cite one or more of the following papers: 62 | 63 | * Ojha, A. A., Votapka L. W., Amaro, R. E. QMrebind: incorporating quantum mechanical force field reparameterization at the ligand binding site for improved drug-target kinetics through milestoning simulations. Chemical Science 14 (45), 13159-13175 64 | 65 | * Ojha A. A., Srivastava A., Votapka L. W., and Amaro R. E. Selectivity and Ranking of Tight-Binding JAK-STAT Inhibitors Using Markovian Milestoning with Voronoi Tessellations. Journal of Chemical Information and Modeling 2023 63 (8), 2469-2482. DOI: 10.1021/acs.jcim.2c01589 66 | 67 | * Votapka, L. W.; Jagger, B. R.; Heyneman, A. L.; Amaro, R. E. SEEKR: Simulation Enabled Estimation of Kinetic Rates, A Computational Tool to Estimate Molecular Kinetics and Its Application to Trypsin–Benzamidine Binding. J. Phys. Chem. B 2017, 121 (15), 3597–3606. https://doi.org/10.1021/acs.jpcb.6b09388. 68 | 69 | * Jagger, B. R.; Ojha, A. A.; Amaro, R. E. Predicting Ligand Binding Kinetics Using a Markovian Milestoning with Voronoi Tessellations Multiscale Approach. J. Chem. Theory Comput. 2020. https://doi.org/10.1021/acs.jctc.0c00495. 70 | 71 | * Jagger, B. R.; Lee, C. T.; Amaro, R. E. Quantitative Ranking of Ligand Binding Kinetics with a Multiscale Milestoning Simulation Approach. J. Phys. Chem. Lett. 2018, 9 (17), 4941–4948. https://doi.org/10.1021/acs.jpclett.8b02047. 72 | 73 | * Votapka LW, Amaro RE (2015) Multiscale Estimation of Binding Kinetics Using Brownian Dynamics, Molecular Dynamics and Milestoning. PLOS Computational Biology 11(10): e1004381. https://doi.org/10.1371/journal.pcbi.1004381 74 | 75 | 76 | Getting Involved 77 | ================ 78 | 79 | Please report **bugs** or **enhancement requests** through the `Issue 80 | Tracker`_. 81 | 82 | .. _Issue Tracker: https://github.com/seekrcentral/seekr2/issues 83 | 84 | Indices and tables 85 | ================== 86 | 87 | * :ref:`genindex` 88 | * :ref:`modindex` 89 | * :ref:`search` 90 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=_build 12 | set SPHINXPROJ=seekr2 13 | 14 | if "%1" == "" goto help 15 | 16 | %SPHINXBUILD% >NUL 2>NUL 17 | if errorlevel 9009 ( 18 | echo. 19 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 20 | echo.installed, then set the SPHINXBUILD environment variable to point 21 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 22 | echo.may add the Sphinx directory to PATH. 23 | echo. 24 | echo.If you don't have Sphinx installed, grab it from 25 | echo.http://sphinx-doc.org/ 26 | exit /b 1 27 | ) 28 | 29 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 30 | goto end 31 | 32 | :help 33 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 34 | 35 | :end 36 | popd 37 | -------------------------------------------------------------------------------- /docs/media/tutorial_hostguest_analysis_results.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seekrcentral/seekr2/93bf27571b0bdbce8133227538261e4cddc7b137/docs/media/tutorial_hostguest_analysis_results.png -------------------------------------------------------------------------------- /docs/media/tutorial_hostguest_directory.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seekrcentral/seekr2/93bf27571b0bdbce8133227538261e4cddc7b137/docs/media/tutorial_hostguest_directory.png -------------------------------------------------------------------------------- /docs/media/tutorial_hostguest_guest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seekrcentral/seekr2/93bf27571b0bdbce8133227538261e4cddc7b137/docs/media/tutorial_hostguest_guest.png -------------------------------------------------------------------------------- /docs/media/tutorial_hostguest_host.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seekrcentral/seekr2/93bf27571b0bdbce8133227538261e4cddc7b137/docs/media/tutorial_hostguest_host.png -------------------------------------------------------------------------------- /docs/media/tutorial_hostguest_koff_conv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seekrcentral/seekr2/93bf27571b0bdbce8133227538261e4cddc7b137/docs/media/tutorial_hostguest_koff_conv.png -------------------------------------------------------------------------------- /docs/media/tutorial_hostguest_model_input.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seekrcentral/seekr2/93bf27571b0bdbce8133227538261e4cddc7b137/docs/media/tutorial_hostguest_model_input.png -------------------------------------------------------------------------------- /docs/media/tutorial_hostguest_pmf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seekrcentral/seekr2/93bf27571b0bdbce8133227538261e4cddc7b137/docs/media/tutorial_hostguest_pmf.png -------------------------------------------------------------------------------- /docs/media/tutorial_toy_entropy_barrier.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seekrcentral/seekr2/93bf27571b0bdbce8133227538261e4cddc7b137/docs/media/tutorial_toy_entropy_barrier.png -------------------------------------------------------------------------------- /docs/media/tutorial_toy_model_input.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seekrcentral/seekr2/93bf27571b0bdbce8133227538261e4cddc7b137/docs/media/tutorial_toy_model_input.png -------------------------------------------------------------------------------- /docs/media/tutorial_toy_muller_potential.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seekrcentral/seekr2/93bf27571b0bdbce8133227538261e4cddc7b137/docs/media/tutorial_toy_muller_potential.png -------------------------------------------------------------------------------- /docs/program_options.rst: -------------------------------------------------------------------------------- 1 | Program Options 2 | =============== 3 | 4 | The arguments and inputs of the various SEEKR2 programs are described here. 5 | 6 | .. toctree:: 7 | :maxdepth: 1 8 | :caption: Contents: 9 | 10 | program_options_prepare 11 | program_options_run 12 | program_options_analyze 13 | program_options_converge 14 | -------------------------------------------------------------------------------- /docs/program_options_analyze.rst: -------------------------------------------------------------------------------- 1 | Analyze.py Inputs and Arguments 2 | =============================== 3 | 4 | The analyze.py program takes the data generated from run.py, constructs a 5 | milestoning model, and computes the kinetics and thermodynamics results. 6 | 7 | usage:: 8 | 9 | python analyze.py [-h] [-f] [-n NUM_ERROR_SAMPLES] [-p] [-d IMAGE_DIRECTORY] 10 | [-s] MDOEL_FILE 11 | 12 | Required Arguments 13 | ------------------ 14 | 15 | **MODEL_FILE** 16 | Provide a path to a file named "model.xml" which can be found 17 | in the tag of the model input file provided to prepare.py. 18 | 19 | Optional Arguments 20 | ------------------ 21 | 22 | **-h, --help** 23 | show help message and exit. 24 | 25 | **-f, --force_warning** 26 | By default, missing statistics for any anchors will 27 | generate fatal errors. Analyze.py will attempt to catch these situations early 28 | and abort gracefully. This option will instead raise a warning and attempt 29 | the calculation anyway. 30 | 31 | **-n NUM_ERROR_SAMPLES, --num_error_samples NUM_ERROR_SAMPLES** 32 | Specify the number of error samples to generate for estimating 33 | error/uncertainty of computed values. Default: 1000. 34 | 35 | **-S STRIDE_ERROR_SAMPLES, --stride_error_samples STRIDE_ERROR_SAMPLES** 36 | Specify the number of strides betweensaved error samples. An argument of 37 | None automatically assigns the quantity at the number of milestones in the 38 | model squared. Default: None 39 | 40 | **-K SKIP_ERROR_SAMPLES, --skip_error_samples SKIP_ERROR_SAMPLES** 41 | Specify the number of error samples. An argument of None automatically 42 | assigns the quantity at ten times the number of milestones in the model 43 | squared. Default: None. 44 | 45 | **-d IMAGE_DIRECTORY, --image_directory IMAGE_DIRECTORY** 46 | Define the directory where all plots and images will be saved. By default, 47 | graphics will be saved to the 'images_and_plots/' directory in the model's 48 | anchor root directory. 49 | 50 | **-s, --skip_checks** 51 | By default, post-simulation checks will be run before 52 | the analysis is started, and if the checks fail, the analysis will not proceed. 53 | This argument bypasses those checks and allows the analysis to proceed anyways. 54 | 55 | **-t MINIMUM_TIME, --minimum_time MINIMUM_TIME** 56 | A user may wish to skip an amount of simulation time for each anchor before 57 | counting the transitions for milestoning analysis. Enter the time (in ps) to 58 | skip a portion of the production simulations when performing analysis. 59 | 60 | **-T MAXIMUM_TIME, --maximum_time MAXIMUM_TIME** 61 | A user may wish to stop the analysis of simulation time for each anchor at 62 | a particular time. Enter the time (in ps) at which to end the analysis at 63 | a given anchor if the simulation time exceeds it. 64 | -------------------------------------------------------------------------------- /docs/program_options_converge.rst: -------------------------------------------------------------------------------- 1 | Converge.py Inputs and Arguments 2 | ================================ 3 | 4 | The converge.py program takes the data generated from run.py and provides the 5 | user with information about simulation progress, including the lengths of 6 | simulations, the number of transitions (bounces) against milestones, and 7 | convergence information. 8 | 9 | In addition, the run.py program can be configured to use the output of 10 | converge.py's API to run simulations to convergence. 11 | 12 | usage:: 13 | 14 | python converge.py [-h] [-s K_ON_STATE] [-d IMAGE_DIRECTORY] [-c CUTOFF] 15 | [-m MINIMUM_ANCHOR_TRANSITIONS] [-p] MODEL_FILE 16 | 17 | 18 | Required Arguments 19 | ------------------ 20 | 21 | **MODEL_FILE** 22 | Provide a path to a file named "model.xml" which can be found 23 | in the tag of the model input file provided to prepare.py. 24 | 25 | Optional Arguments 26 | ------------------ 27 | 28 | -h, --help show help message and exit. 29 | 30 | -s K_ON_STATE, --k_on_state K_ON_STATE 31 | Define the bound state (anchor index) that will be used 32 | to compute k-on. If left blank, and k-on statistics 33 | exist, then the first end state in the model will be 34 | chosen by default. 35 | 36 | -d IMAGE_DIRECTORY, --image_directory IMAGE_DIRECTORY 37 | Define the directory where all plots and images will 38 | be saved. By default, graphics will be saved to the 39 | 'images_and_plots/' directory in the model's anchor root 40 | directory. 41 | 42 | -c CUTOFF, --cutoff CUTOFF 43 | The minimum convergence that must be achieved before 44 | concluding that the calculations have converged for a 45 | given anchor. 46 | 47 | -m MINIMUM_ANCHOR_TRANSITIONS, --minimum_anchor_transitions MINIMUM_ANCHOR_TRANSITIONS 48 | Enter a minimum number of transitions that must be 49 | observed per milestone in a given MD anchor as a 50 | criteria for the simulations to be considered converged. 51 | -------------------------------------------------------------------------------- /docs/program_options_prepare.rst: -------------------------------------------------------------------------------- 1 | Prepare.py Inputs and Arguments 2 | =============================== 3 | 4 | The prepare.py program takes a :doc:`Model Input File` as 5 | input and generates the files necessary to run a SEEKR2 calculation. 6 | 7 | usage:: 8 | 9 | python prepare.py [-h] [-f] [-s] MODEL_INPUT_FILE 10 | 11 | Required Arguments 12 | ------------------ 13 | 14 | **MODEL_INPUT_FILE** 15 | The name of a model input XML file for a SEEKR2 calculation. Samples model 16 | files can be found in the following locations:: 17 | 18 | seekr2/seekr2/data/sample_input_mmvt_openmm.xml 19 | seekr2/seekr2/data/sample_input_mmvt_namd.xml 20 | seekr2/seekr2/data/sample_input_elber_openmm.xml 21 | seekr2/seekr2/data/trypsin_benzamidine_files/input_tryp_ben_mmvt.xml 22 | seekr2/seekr2/data/trypsin_benzamidine_files/input_tryp_ben_elber.xml 23 | 24 | Also, an :doc:`entire page of documentation` is dedicated 25 | to explaining the inputs of the model input file. 26 | 27 | Optional Arguments 28 | ------------------ 29 | 30 | **-h, --help** 31 | show help message and exit 32 | 33 | **-f, --force_overwrite** 34 | Toggle whether to overwrite existing simulation 35 | output files within any anchor that might have existed in an old model that 36 | would be overwritten by generating this new model. If not toggled while 37 | attempting to overwrite an old model with a new model, this program will 38 | throw an exception instead of performing any such overwrite. 39 | 40 | **-s, --skip_checks** 41 | By default, pre-simulation checks will be run after 42 | the preparation is complete, and if the checks fail, prepare.py will terminate 43 | and the SEEKR2 model will not be saved. This argument bypasses those checks 44 | and allows the model to be generated regardless of check outcomes. 45 | -------------------------------------------------------------------------------- /docs/program_options_run.rst: -------------------------------------------------------------------------------- 1 | Run.py Inputs and Arguments 2 | =========================== 3 | 4 | The run.py program controls the MD or BD simulations in a SEEKR2 calculation, 5 | ensuring that they are run with the correct dynamics settings and milestone 6 | boundary definitions, while also generating restart checkpoints. Upon failure, 7 | run.py can restart a simulation automatically from a saved checkpoint. 8 | 9 | As its primary input, the run.py program takes an INSTRUCTION and the path to 10 | a file named "model.xml" (generated by prepare.py). Other options control 11 | various aspects of the simulations. 12 | 13 | usage:: 14 | 15 | python run.py [-h] [-c CUDA_DEVICE_INDEX] [-t MIN_TOTAL_SIMULATION_LENGTH] 16 | [-T MAX_TOTAL_SIMULATION_LENGTH] [-C CONVERGENCE_CUTOFF] 17 | [-m MINIMUM_ANCHOR_TRANSITIONS] [-d DIRECTORY] [-f] [-s] [-S] 18 | [-n NAMD_COMMAND] [-a NAMD_ARGUMENTS] 19 | [-b MINIMUM_B_SURFACE_TRAJECTORIES] 20 | [-y MIN_B_SURFACE_ENCOUNTERS] [-L NUM_REV_LAUNCHES] [-u] 21 | INSTRUCTION MODEL_FILE 22 | 23 | 24 | Required Arguments 25 | ------------------ 26 | 27 | **INSTRUCTION** 28 | This argument defines which type of dynamics for which anchor 29 | (region of the calculation) should be run. The possible arguments for 30 | INSTRUCTION are listed below: 31 | 32 | **any** - Instruct run.py to run any anchor, whether MD or BD, that still needs 33 | more sampling. The run.py program will attempt to do this in a "smart" manner, 34 | by focusing attention on anchors and regions that are undersampled, based 35 | on transition counts and/or convergence criteria. 36 | 37 | **any_md** - Instruct run.py to run any MD anchor (excluding BD) that still 38 | needs more sampling. This feature can be useful if MD simulations must be 39 | run on a supercomputer or cluster (or a GPU node), while BD must be run on 40 | a different machine (or a CPU node). As with the **any** instruction, run.py 41 | will attempt to be smart about this, and focus on running undersampled 42 | anchors. 43 | 44 | **any_bd** - Instruct run.py to run any unfinished BD simulations (at this 45 | time, this is only the b-surface). As mentioned with the **any_md** 46 | instruction above, this argument can be useful if one wishes to run BD on a 47 | separate machine than MD. 48 | 49 | **(integer value)** - By entering an integer value (Examples: "0", "1", "2", 50 | etc.), the MD anchor with that index will be run to completion or 51 | interruption. 52 | 53 | **b_surface** - Run the b-surface BD simulations. 54 | 55 | **MODEL_FILE** 56 | Provide a path to a file named "model.xml" which can be found 57 | in the tag of the model input file provided to prepare.py. 58 | 59 | Optional Arguments 60 | ------------------ 61 | **-h, --help** 62 | Show help message and exit. 63 | 64 | **-c CUDA_DEVICE_INDEX, --cuda_device_index CUDA_DEVICE_INDEX** 65 | Modify which 66 | cuda_device_index to run the MD simulation on. For example, the number 0 would 67 | instruct the MD engine to run using the GPU with the assigned index of 0. To 68 | run on multiple GPU indices, simply enter comma separated indices. 69 | Example: '0,1'. If a value is not supplied, the value in the MODEL_FILE will 70 | be used by default. 71 | 72 | **-t MIN_TOTAL_SIMULATION_LENGTH, --minimum_total_simulation_length MIN_TOTAL_SIMULATION_LENGTH** 73 | Enter a minimum MD simulation length 74 | (in time steps) to run the simulation if a different number of steps are 75 | desired than what is in the "" (MMVT) or 76 | "" (Elber) tags in the MODEL_FILE. Be aware: A 77 | longer simulation may still occur if other specified criteria are not met, 78 | such as the --convergence_cutoff, for example. 79 | 80 | **-T MAX_TOTAL_SIMULATION_LENGTH, --maximum_total_simulation_length MAX_TOTAL_SIMULATION_LENGTH** 81 | Enter the maximum number of MD simulation 82 | timesteps. Simulations will not exceed this length, even if other criteria, 83 | such as --convergence_cutoff are not met. 84 | 85 | **-C CONVERGENCE_CUTOFF, --convergence_cutoff CONVERGENCE_CUTOFF** 86 | Enter a target convergence for each anchor. See the documentation of 87 | converge.py for more detail about how convergence is calculated. 88 | 89 | **-m MINIMUM_ANCHOR_TRANSITIONS, --minimum_anchor_transitions MINIMUM_ANCHOR_TRANSITIONS** 90 | Enter a minimum number of transitions that 91 | must be observed per milestone in a given anchor as a criteria for the 92 | simulations. 93 | 94 | **-d DIRECTORY, --directory DIRECTORY** 95 | Provide the location of the 96 | directory which contains the anchors. If this argument is omitted, then the 97 | directory within the anchor_rootdir setting of the MODEL_FILE will be used. 98 | 99 | **-f, --force_overwrite** 100 | Toggle whether to overwrite existing files within 101 | an anchor. If this option is enabled then the anchor's production directory 102 | will be emptied of all output, trajectory, and backup files for the new 103 | simulation. 104 | 105 | **-s, --save_state_for_all_boundaries** 106 | Toggle whether to save at least one 107 | state file for each boundary until every boundary has been bounced against. 108 | Warning: can generate very large numbers of files. 109 | 110 | **-S, --save_state_file** 111 | Toggle whether to save a state file every time a 112 | bounce occurs. Warning: can generate very large numbers of files. 113 | 114 | **-n NAMD_COMMAND, --namd_command NAMD_COMMAND** 115 | Define a different NAMD 116 | command. This allows users to define a path to NAMD or to use a 117 | 'charmrun namd2' command. By default, 'namd2' is used. Only valid for NAMD 118 | runs. 119 | 120 | **-a NAMD_ARGUMENTS, --namd_arguments NAMD_ARGUMENTS** 121 | Additional arguments 122 | for NAMD can be entered here. Note: this will require quotation marks around 123 | the arguments. Example: -a '+p8 +devices 0,2'. Only valid for NAMD runs. 124 | 125 | **-b MINIMUM_B_SURFACE_TRAJECTORIES, --minimum_b_surface_trajectories MINIMUM_B_SURFACE_TRAJECTORIES** 126 | Enter a minimum number of BD trajectories 127 | to run for the b-surface if a different number of trajectories are desired 128 | than what is indicated in the tag in the 129 | MODEL_FILE. A longer simulation may be run if other specified criteria are 130 | not met, such as the --min_b_surface_encounters, for example. 131 | 132 | **-y MIN_B_SURFACE_ENCOUNTERS, --min_b_surface_encounters MIN_B_SURFACE_ENCOUNTERS** 133 | Enter a minimum number of encounters that must 134 | be observed for the b-surface as a criteria to finish running simulations. 135 | 136 | **-L NUM_REV_LAUNCHES, --num_rev_launches NUM_REV_LAUNCHES** 137 | In Elber milestoning, this parameter defines how many reversals to launch 138 | for each equilibrium configuration generated by the umbrella stage. For each 139 | launch, the positions will be identical, but the velocities will be 140 | resampled from a Maxwell-Boltzmann distribution. 141 | 142 | **-u, --umbrella_restart_mode** 143 | In Elber milestoning, this option allows 144 | one to use the umbrella simulations that already exist in the anchor, and 145 | just re-run the reversals and forwards simulations. 146 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | sphinx-rtd-theme 2 | -------------------------------------------------------------------------------- /docs/requirements.yaml: -------------------------------------------------------------------------------- 1 | name: docs 2 | channels: 3 | - defaults 4 | dependencies: 5 | # Base depends 6 | - python=3.12 7 | - pip 8 | - cython 9 | 10 | # Pip-only installs 11 | - pip: 12 | - sphinx-autoapi 13 | - sphinx-rtd-theme 14 | 15 | -------------------------------------------------------------------------------- /docs/running_calculations.rst: -------------------------------------------------------------------------------- 1 | Running Calculations in SEEKR2 2 | ============================== 3 | 4 | This page provides a cursory overview of a typical SEEKR2 calculation. 5 | 6 | SEEKR2 calculations have three distinct stages: 7 | 8 | 1. Prepare 9 | 2. Run 10 | 3. Analyze 11 | 12 | These are the main components, although there can also be more optional 13 | components to a SEEKR calculation. 14 | 15 | Appropriately, in SEEKR2, the programs that accomplish each of these stages 16 | are named: 17 | 18 | 1. prepare.py 19 | 2. run.py 20 | 3. analyze.py 21 | 22 | Prepare 23 | ------- 24 | 25 | In order to run the prepare stage, SEEKR2 typically needs a "model input" XML 26 | file. Some examples of input files can be found in the following locations:: 27 | 28 | seekr2/seekr2/data/sample_input_mmvt_openmm.xml 29 | seekr2/seekr2/data/sample_input_mmvt_namd.xml 30 | seekr2/seekr2/data/sample_input_elber_openmm.xml 31 | 32 | Inside these files are entries like temperature, type of calculations, system 33 | parameters, and starting atomic positions. This file also defines the 34 | milestone locations and shapes. More information about the structure of 35 | model input files can be found in the 36 | :doc:`Model Input Files` documentation. 37 | 38 | In addition, a number of input parameter, topology, and structure files must 39 | be provided which provide the simulation engines with forcefield information, 40 | starting atomic positions for each of the anchors (for MD), and waterbox 41 | dimensions. Examples of such files can also be found in the seekr2/seekr2/data/ 42 | directory:: 43 | 44 | seekr2/seekr2/data/hostguest_files 45 | 46 | The prepare.py script typically takes one argument - the model input XML file. 47 | For example:: 48 | 49 | python prepare.py data/sample_input_mmvt_openmm.xml 50 | 51 | The script will construct a directory and file tree located at the path 52 | specified by the tag in the model input XML file. 53 | 54 | More arguments to prepare.py can be found by running prepare.py with the "-h" 55 | argument, or by consulting the :doc:`Program Options` 56 | documentation. 57 | 58 | Additionally, more systems and sample input files can be found in the 59 | seekr2_systems repository: https://github.com/seekrcentral/seekr2_systems.git. 60 | 61 | Run 62 | --- 63 | 64 | The prepare stage will generate a filetree of all necessary files and 65 | directories at the location specified by the tag of the 66 | model input file. Within this directory is a file named *model.xml*. The 67 | path to this file will be the argument of most programs used in SEEKR2 68 | in the run stage and beyond. 69 | 70 | *NOTE: the model.xml file is not intended to be modified directly without 71 | re-running prepare.py on the model input file.* 72 | 73 | The run stage is started with the run.py script:: 74 | 75 | python run.py any /path/to/root_directory/model.xml 76 | 77 | The word "any" is the INSTRUCTION argument to run.py, and instructs run.py to 78 | run any unfinished MD or BD simulations. One may use "any_md" or "any_bd" as 79 | inputs to INSTRUCTION if one wishes to simulation only unfinished MD or 80 | unfinished BD simulations, respectively. There are many more inputs to 81 | INSTRUCTION and arguments to run.py, and they are all listed in 82 | :doc:`Program Options`. 83 | 84 | Following the run.py command, simulations will run until completion or 85 | interruption. SEEKR saves checkpoints for MD and BD simulations, so if an 86 | interruption occurs, one may re-enter the run.py command and the calculation 87 | will pick up where it left off. 88 | 89 | One may check on the progress and convergence of the calculation with the 90 | converge.py program:: 91 | 92 | python converge.py /path/to/root_directory/model.xml 93 | 94 | The program converge.py will also generate convergence plots and images, 95 | which may be found in the "plots_and_images" subfolder of . 96 | 97 | More arguments to both run.py and converge.py can be found by running 98 | either program with the "-h" argument, or by consulting the 99 | :doc:`Program Options` documentation. 100 | 101 | Analyze 102 | ------- 103 | 104 | The final stage of a typical SEEKR2 calculation involves analyzing the results 105 | of the simulations to construct the kinetics and thermodynamics of the 106 | process in question. 107 | 108 | The analyze stage is launches with the analyze.py script:: 109 | 110 | python analyze.py /path/to/root_directory/model.xml 111 | 112 | The analyze.py script constructs the milestoning model, populates it with the 113 | probabilities and times from the simulations, and computes other quantities, 114 | like the error margins. 115 | 116 | Upon completion, interesting quantities will be printed to the screen, and 117 | more images will be saved in the "plots_and_images" subfolder of 118 | , including a free energy profile (potential of mean force) of 119 | each milestone. -------------------------------------------------------------------------------- /docs/tutorial.rst: -------------------------------------------------------------------------------- 1 | Tutorials for SEEKR2 2 | ==================== 3 | 4 | Follow these tutorials to learn how to use SEEKR2. 5 | 6 | It is assumed that you have completed the installation and tests outlined in the 7 | :doc:`Installation` documentation. 8 | 9 | **Looking for tutorials on how to prepare systems for a SEEKR2 calculation?** 10 | see the Seekrtools tutorials: 11 | https://seekrtools.readthedocs.io/en/latest/tutorial.html 12 | 13 | .. toctree:: 14 | :maxdepth: 1 15 | :caption: Contents: 16 | 17 | tutorial1_hostguest 18 | tutorial2_toy_systems 19 | -------------------------------------------------------------------------------- /docs/tutorial1_hostguest.rst: -------------------------------------------------------------------------------- 1 | Tutorial 1: Host-guest calculation 2 | ================================== 3 | 4 | In this tutorial, we will be performing a sample SEEKR2 calculation to determine 5 | the kinetics of binding between beta-cyclodextrin (the "host") and the small 6 | molecule 1-butanol (the "guest"). 7 | 8 | .. figure:: media/tutorial_hostguest_host.png 9 | :align: center 10 | 11 | The beta-cyclodextrin "host" molecule 12 | 13 | 14 | .. figure:: media/tutorial_hostguest_guest.png 15 | :align: center 16 | 17 | The 1-butanol "guest" molecule 18 | 19 | Navigate to the location where the seekr2/ Git repository was cloned, and enter 20 | the repository's program directory and view the available programs:: 21 | 22 | cd seekr2/seekr2 23 | ls 24 | 25 | You should see a number of python programs, as well as a few directories. The 26 | first program we will be using is the "prepare.py" script. 27 | 28 | The prepare.py script requires a "model input" file, which is in XML format. 29 | Using Gedit, Vim, or another editor, open up the file 30 | "data/sample_input_mmvt_openmm.xml", which is a sample model input file. 31 | 32 | .. figure:: media/tutorial_hostguest_model_input.png 33 | :align: center 34 | 35 | Model input file of the host-guest system. 36 | 37 | There is a lot of information in here, the details of which are described in 38 | the :doc:`Model Input Files` documentation. For this 39 | tutorial, we will be using this file as-is, for now. 40 | 41 | There are other provided files we need for this SEEKR2 calculation, they are 42 | described here: 43 | 44 | * **data/hostguest_files/hostguest.parm7** - The AMBER parameter/topology file 45 | which contains parameters for the host and guest molecules, as well as the 46 | water molecules comprising the waterbox. 47 | 48 | * **data/hostguest_files/hostguest_at###.pdb** - Each of these files describe 49 | the starting atomic coordinates and box vectors for each of the anchors in the 50 | MD stage. These PDB files were made using an SMD simulation, where the "guest" 51 | was pulled slowly away from the bound state, and the structures were saved 52 | as the guest molecule reached each of the anchor locations. 53 | 54 | * **hostguest_receptor.pqr** - The host molecule (beta-cyclodextrin) for 55 | Browndye input in PQR format. 56 | 57 | * **hostguest_ligand.pqr** - The guest molecule (1-butanol) for 58 | Browndye input in PQR format. 59 | 60 | If you want to use SEEKR2 on a system of your own choosing, you will need to 61 | generate similar input files for it. 62 | 63 | 64 | Next, run prepare.py on the model input file:: 65 | 66 | python prepare.py data/sample_input_mmvt_openmm.xml 67 | 68 | For a few minutes, the script will construct a directory and file tree located 69 | at "~/test_mmvt_openmm/". The program may throw a few warnings, but these can 70 | usually be safely ignored, as long as there are no errors or check failures. 71 | 72 | When the command is complete, enter the new directory and see what is there:: 73 | 74 | cd ~/test_mmvt_openmm/ 75 | ls 76 | 77 | You'll see a number of directories starting with "anchor", as well as a 78 | "b_surface" directory. Let's talk about each of these 79 | files/directories. (Consider viewing the contents of the files and directories 80 | as we talk about them). 81 | 82 | .. figure:: media/tutorial_hostguest_directory.png 83 | :align: center 84 | 85 | The files and directories of a SEEKR2 calculation. 86 | 87 | * **model.xml** - This is arguably the most important file. It contains most of 88 | the high-level information used by later SEEKR2 stages. 89 | 90 | * **anchor_0/, anchor_1/, etc...** - These directories contain the MD 91 | simulation information in two directories: 92 | 93 | * **building/** - This directory contains the parameter/topology and starting 94 | structure files for the MD simulations. 95 | 96 | * **prod/** - This directory will contain the "production" data generated by the 97 | MD simulation, including trajectory data, restart checkpoint files, and, 98 | most importantly, the "bounce" information needed for the MMVT analysis to 99 | extract transition probabilities and times. 100 | 101 | * **b_surface** - This directory contains the input files for BD simulations 102 | starting from the b-surface and either escaping or ending at the BD milestone. 103 | 104 | The preparation stage is complete. Next, we complete the run stage. 105 | 106 | Navigate to the location where the seekr2/ Git repository was cloned, and enter 107 | the repository's program directory and view the available programs again:: 108 | 109 | cd seekr2/seekr2 110 | ls 111 | 112 | This time, we will use the run.py program, and we will use the new model.xml 113 | file as the INPUT FILE argument:: 114 | 115 | python run.py any ~/test_mmvt_openmm/model.xml 116 | 117 | The keyword "any" is an INSTRUCTION argument which indicates that SEEKR2 118 | should run any unfinished MD or BD calculations. 119 | 120 | Note that SEEKR2 periodically creates checkpoints, so if your calculation 121 | is ever interrupted, the run.py program can just pick right up where it left 122 | off as long as the INSTRUCTION covers the calculation that was interrupted. 123 | This can be very useful if running SEEKR2 on a supercomputer with a queue for 124 | jobs that run only a limited time. 125 | 126 | Since this is the first time you're running this calculation, there are no 127 | simulations yet complete, so SEEKR2 will run all the needed MD and BD 128 | simulations. This is likely to take an hour or two if you have a relatively 129 | fast GPU running OpenMM. (Warning: Without a GPU, this calculation will probably 130 | take a prohibitively long time). 131 | 132 | Once complete, we are finished with the run stage. We can check the progress of 133 | our simulations with the converge.py program:: 134 | 135 | python converge.py ~/test_mmvt_openmm/model.xml 136 | 137 | The output will show how many transitions were observed for the various MD and 138 | BD simulations. One can also see additional convergence information. 139 | 140 | Next, let us perform the analysis stage. Return to the SEEKR2 program 141 | directory:: 142 | 143 | cd seekr2/seekr2 144 | ls 145 | 146 | To analyze our results, we use the analyze.py program:: 147 | 148 | python analyze.py ~/test_mmvt_openmm/model.xml 149 | 150 | After a few minutes, the script should display kinetic and thermodynamic 151 | results (your results will be different due to the stochastic nature of 152 | simulations): 153 | 154 | .. figure:: media/tutorial_hostguest_analysis_results.png 155 | :align: center 156 | 157 | The script analyze.py outputs the kinetics and thermodynamics of binding. 158 | 159 | in addition, we may look at some generated images and plots:: 160 | 161 | cd ~/test_mmvt_openmm 162 | cd images_and_plots 163 | 164 | Now use EOG or another visualization program to view the k-off convergence 165 | image:: 166 | 167 | eog k_off_convergence.png 168 | 169 | .. figure:: media/tutorial_hostguest_koff_conv.png 170 | :align: center 171 | 172 | Convergence plots can give hints about whether more sampling is needed. 173 | 174 | Next, take a look at the free energy profile (potential of mean force):: 175 | 176 | eog free_energy_profile.png 177 | 178 | .. figure:: media/tutorial_hostguest_pmf.png 179 | :align: center 180 | 181 | The free energy profile (or potential of mean force). 182 | 183 | *NOTE: all of these results were generated using far too little sampling for a 184 | true SEEKR2 calculation, and simulations were cut very short here for 185 | demonstration purposes, so that a SEEKR2 calculation could be completed within 186 | the span of a couple of hours on a desktop computer with a GPU. The results 187 | generated in this tutorial should not be taken seriously.* 188 | 189 | Congratulations! If you've made it to this point successfully, you've completed 190 | a SEEKR2 calculation. -------------------------------------------------------------------------------- /docs/tutorial2_toy_systems.rst: -------------------------------------------------------------------------------- 1 | Tutorial 2: Toy Systems 2 | ======================= 3 | 4 | In this tutorial, we will be performing a SEEKR2 calculation on a "Toy System", 5 | that is - a system with one or few particle(s) that move on a relatively simple 6 | potential energy surface. 7 | 8 | Toy systems can be very useful to benchmark the accuracy of a new method, 9 | to improve conceptual understanding of the interaction between a method and 10 | a real molecular system, or as a teaching tool about a method. 11 | 12 | In this tutorial, we will be using the Entropy Barrier and Muller Potential 13 | toy systems. 14 | 15 | .. figure:: media/tutorial_toy_entropy_barrier.png 16 | :align: center 17 | 18 | The Entropy Barrier toy system 19 | 20 | 21 | .. figure:: media/tutorial_toy_muller_potential.png 22 | :align: center 23 | 24 | The Muller Potential toy system 25 | 26 | Entropy Barrier Toy System 27 | -------------------------- 28 | 29 | First, to prepare and run the toy systems, it will be helpful to have a 30 | sample input XML. 31 | 32 | Move to your home directory or other convenient location and clone the 33 | seekr2_systems repository.:: 34 | 35 | cd 36 | git clone https://github.com/seekrcentral/seekr2_systems.git 37 | 38 | A number of useful input files can be found in this repository, but we are 39 | going to use the input files in the seekr2_systems/systems/toy_systems/ 40 | directory. Let's start by looking at the Entropy Barrier system input.:: 41 | 42 | cd seekr2_systems/systems/toy_systems 43 | 44 | Using Gedit, Vim, or another editor, open up the file 45 | "input_entropy_barrier.xml". 46 | 47 | .. figure:: media/tutorial_toy_model_input.png 48 | :align: center 49 | 50 | Model input file of the Entropy Barrier toy system. 51 | 52 | As with the host/guest system, this input file contains all the information 53 | to prepare a SEEKR calculation. Detailed information for all inputs can be 54 | found in :doc:`Model Input Files` and some should be 55 | familiar from :doc:`Tutorial 1`, but I'm going to 56 | highlight a few key changes unique to toy systems. 57 | 58 | First, toy systems require their own kind of collective variable (CV). 59 | Notice that the CV is of a "Toy_cv_input" type, and its anchors are of the 60 | "Toy_cv_anchor" type. Notice that, for a toy system, none of the input 61 | require any files except the Model Input File, which is an advantage to running 62 | toy systems, as opposed to real molecular systems which need starting 63 | coordinate files as well as parameter and topology files. 64 | 65 | 66 | The value "[[0]]" is a Python list of a list, both dimensions of length 1, 67 | and this entry indicates that this CV only keeps track of a single group, 68 | formed of a single atom, and that's atom index 0. Toy systems can have any 69 | number of atoms, and Toy CVs can keep track of any of those atoms as needed. 70 | 71 | 72 | One may change the string representation of the CV's variable by changing 73 | this string. The string "value" should suffice in most any circumstance, 74 | although some CVs use the string "radius" to represent their variables. 75 | 76 | 77 | This expression is used to determine anchor location, as well as to 78 | construct the mathematical milestone expression. In essence, milestones 79 | are constructed along the surfaces where this expression is constant 80 | (isosurfaces). In this case, the milestones are constructed where the 81 | y-coordinate of the first (and only) atom is constant. (OpenMM expressions 82 | start indexing at 1, not 0). 83 | 84 | Within the input_anchor objects: 85 | 86 | 87 | Instead of providing a PDB file as starting positions, for a toy system, 88 | we provide starting coordinates for each of the particles. This input is 89 | a triple-nested list. The outermost layer are "frames" of a toy simulation, 90 | in order to use or test the "swarm" capabilities of MMVT. 91 | The next layer are the particles in a frame of the swarm. Since this toy 92 | system has only one particle, there is only one item in this list. The 93 | final layer are the x,y,z coordinates of the particle. Notice that in the 94 | first input anchor, there are two frames, making a swarm of size two. 95 | In contrast the second anchor has only a single frame. These are in units 96 | of nanometers. 97 | 98 | At the very end of the Model Input file, one can find the 99 | tag. Inside are a number of other settings for the toy system. 100 | 101 | 102 | Define the function of particle positions that describe the potential 103 | energy surface. 104 | 105 | 106 | The total number of particles in this toy system. 107 | 108 | 109 | A list of masses by particle (in units of AMU). 110 | 111 | Create the correct output directory and we are ready to run prepare.py on 112 | the model input file, run, and analyze.:: 113 | 114 | mkdir ~/toy_seekr_systems 115 | cd seekr2/seekr2 116 | python prepare.py input_entropy_barrier.xml.xml 117 | python run.py any ~/toy_seekr_systems/entropy_barrier/model.xml 118 | python converge.py ~/toy_seekr_systems/entropy_barrier/model.xml > converge.txt 119 | python analyze.py ~/toy_seekr_systems/entropy_barrier/model.xml > analyze.txt 120 | 121 | All of these commands should work the same for the toy system as they did 122 | for the molecular host/guest system. View converge.txt and analyze.txt in 123 | Gedit, Vim, or another text file viewer/editor. 124 | 125 | One final step involves visualizing the trajectories in the toy system. 126 | The seekr2_systems repository contains some scripts for visualizing the 127 | results of the toy systems.:: 128 | 129 | cd ~/seekr2_systems/systems/toy_systems 130 | python entropy_barrier_plot.py 131 | 132 | A video should appear that shows the trajectories moving around the Voronoi 133 | cells of the Entropy Barrier system. At the bottom of the 134 | entropy_barrier_plot.py script, there are some commented lines that will 135 | generate a movie that can be played. 136 | 137 | .. raw:: html 138 | 139 | 140 | 141 | Entropy Barrier MMVT trajectories 142 | 143 | Muller Potential Toy System 144 | --------------------------- 145 | 146 | Let us perform the same calculation using the Muller potential. 147 | 148 | The model input file for the Muller potential can be found in 149 | seekr2_systems/systems/toy_systems. Using Vim, Gedit, or another text 150 | editor, open the file "input_muller_potential.xml". There are a few 151 | key differences between the Muller potential and the Entropy Barrier system. 152 | 153 | In the tag: 154 | 155 | 156 | Now, the tag has been given a new function: 157 | "1.0*y1 - 0.66*x1". This will cause the milestones to be "slanted" in the 158 | coordinate system, unlike the horizontal lines milestones of the Entropy 159 | Barrier system. 160 | 161 | 162 | One may optionally provide the expression that will be used by OpenMM to 163 | construct the milestone surfaces, though this is optional. 164 | 165 | In the tag: 166 | 167 | 168 | A new expression is needed to use the Muller potential energy landscape. 169 | 170 | We will perform the same steps as before.:: 171 | 172 | cd seekr2/seekr2 173 | python prepare.py input_muller_potential.xml.xml 174 | python run.py any ~/toy_seekr_systems/muller_potential/model.xml 175 | python converge.py ~/toy_seekr_systems/muller_potential/model.xml > converge.txt 176 | python analyze.py ~/toy_seekr_systems/muller_potential/model.xml > analyze.txt 177 | 178 | Feel free to examine analyze.txt or converge.txt. One may also make a video 179 | of the MMVT simulations in the Muller potential by using the 180 | muller_potential_plot.py program.:: 181 | 182 | cd ~/seekr2_systems/systems/toy_systems 183 | python muller_potential_plot.py 184 | 185 | .. raw:: html 186 | 187 | 188 | 189 | Muller Potential MMVT trajectories -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["setuptools>=61.0", "versioningit~=2.0"] 3 | build-backend = "setuptools.build_meta" 4 | 5 | # Self-descriptive entries which should always be present 6 | [project] 7 | name = "seekr2" 8 | description = "Simulation-Enabled Estimation of Kinetic Rates - Version 2." 9 | dynamic = ["version"] 10 | readme = "README.md" 11 | authors = [ 12 | { name = "Lane Votapka", email = "lvotapka@protonmail.com" } 13 | ] 14 | license = { text = "MIT" } 15 | # See https://pypi.org/classifiers/ 16 | classifiers = [ 17 | "License :: OSI Approved :: MIT License", 18 | "Programming Language :: Python :: 3", 19 | ] 20 | requires-python = ">=3.8" 21 | # Declare any run-time dependencies that should be installed with the package. 22 | dependencies = [ 23 | "numpy", 24 | "scipy", 25 | "pyparsing", 26 | "matplotlib", 27 | "nptyping", 28 | "parmed", 29 | "mdtraj", 30 | "pytest", 31 | "abserdes", 32 | "PyGT", 33 | ] 34 | 35 | # Update the urls once the hosting is set up. 36 | [project.urls] 37 | "Source" = "https://github.com/seekrcentral/seekr2" 38 | "Documentation" = "https://seekr2.readthedocs.io" 39 | 40 | [tool.setuptools] 41 | # This subkey is a beta stage development and keys may change in the future, see https://setuptools.pypa.io/en/latest/userguide/pyproject_config.html for more details 42 | # 43 | # As of version 0.971, mypy does not support type checking of installed zipped 44 | # packages (because it does not actually import the Python packages). 45 | # We declare the package not-zip-safe so that our type hints are also available 46 | # when checking client code that uses our (installed) package. 47 | # Ref: 48 | # https://mypy.readthedocs.io/en/stable/installed_packages.html?highlight=zip#using-installed-packages-with-mypy-pep-561 49 | zip-safe = false 50 | # Let setuptools discover the package in the current directory, 51 | # but be explicit about non-Python files. 52 | # See also: 53 | # https://setuptools.pypa.io/en/latest/userguide/pyproject_config.html#setuptools-specific-configuration 54 | # Note that behavior is currently evolving with respect to how to interpret the 55 | # "data" and "tests" subdirectories. As of setuptools 63, both are automatically 56 | # included if namespaces is true (default), even if the package is named explicitly 57 | # (instead of using 'find'). With 'find', the 'tests' subpackage is discovered 58 | # recursively because of its __init__.py file, but the data subdirectory is excluded 59 | # with include-package-data = false and namespaces = false. 60 | include-package-data = true 61 | [tool.setuptools.packages.find] 62 | namespaces = true 63 | where = ["."] 64 | 65 | # Ref https://setuptools.pypa.io/en/latest/userguide/datafiles.html#package-data 66 | [tool.setuptools.package-data] 67 | qmrebind = [ 68 | "py.typed", 69 | # Commenting these so that other packages can easily import seekr2 test data. 70 | # "*.dat", 71 | # "*.txt", 72 | # "*.pdb", 73 | # "*.pqr", 74 | # "*.parm7", 75 | # "*.prmtop", 76 | # "*.rst7", 77 | # "*.xml", 78 | ] 79 | 80 | [tool.versioningit] 81 | default-version = "2.1.0" 82 | 83 | [tool.versioningit.format] 84 | distance = "{base_version}+{distance}.{vcs}{rev}" 85 | dirty = "{base_version}+{distance}.{vcs}{rev}.dirty" 86 | distance-dirty = "{base_version}+{distance}.{vcs}{rev}.dirty" 87 | 88 | [tool.versioningit.vcs] 89 | # The method key: 90 | method = "git" # <- The method name 91 | # Parameters to pass to the method: 92 | match = ["*"] 93 | default-tag = "2.1.0" 94 | 95 | [tool.versioningit.write] 96 | file = "seekr2/_version.py" 97 | 98 | 99 | -------------------------------------------------------------------------------- /seekr2/__init__.py: -------------------------------------------------------------------------------- 1 | __version__ = "{version}" 2 | 3 | __all__ = [ 4 | "analyze", 5 | "converge", 6 | "prepare", 7 | "run", 8 | ] -------------------------------------------------------------------------------- /seekr2/continuous_integration/run_ci.py: -------------------------------------------------------------------------------- 1 | """ 2 | Run entire SEEKR2 calculations to test for problems in the 3 | pipeline. 4 | """ 5 | import os 6 | import sys 7 | import time 8 | import tempfile 9 | 10 | import seekr2 11 | import seekr2.tests.create_model_input as create_model_input 12 | import seekr2.prepare as prepare 13 | import seekr2.modules.check as check 14 | import seekr2.run as run 15 | import seekr2.converge as converge 16 | import seekr2.modules.common_converge as common_converge 17 | import seekr2.analyze as analyze 18 | from seekr2.modules.common_prepare import Browndye_settings_input, \ 19 | MMVT_input_settings, Elber_input_settings 20 | from seekr2.modules.common_base import Ion, Amber_params, Forcefield_params, \ 21 | Box_vectors 22 | from seekr2.modules.common_cv import Spherical_cv_anchor, Spherical_cv_input 23 | 24 | def run_short_ci(model_input, cuda_device_index, long_check=True): 25 | start_dir = os.getcwd() 26 | model, xml_path = prepare.prepare(model_input, force_overwrite=False) 27 | 28 | model_dir = os.path.dirname(xml_path) 29 | model.anchor_rootdir = os.path.abspath(model_dir) 30 | check.check_pre_simulation_all(model) 31 | run.run(model, "any", min_b_surface_simulation_length=1000, 32 | num_rev_launches=10, cuda_device_index=cuda_device_index, 33 | save_state_file=True) 34 | data_sample_list, times_dict = converge.converge(model, k_on_state=0) 35 | rmsd_convergence_results = common_converge.calc_RMSD_conv_amount( 36 | model, data_sample_list) 37 | transition_minima, transition_details, transition_times \ 38 | = common_converge.calc_transition_steps( 39 | model, data_sample_list[-1]) 40 | converge.print_convergence_results( 41 | model, rmsd_convergence_results, cutoff=0.1, 42 | transition_results=transition_details, 43 | transition_time_results=transition_times, 44 | minimum_anchor_transitions=10, 45 | bd_transition_counts=data_sample_list[-1].bd_transition_counts) 46 | check.check_post_simulation_all(model, long_check=long_check) 47 | analysis = analyze.analyze(model) 48 | analysis.print_results() 49 | os.chdir(start_dir) 50 | return 51 | 52 | def run_generic_hostguest_ci(cuda_device_index): 53 | FF = "system" 54 | #FF = "amber" 55 | TIMESTEP = 0.002 56 | #TIMESTEP = 0.004 57 | with tempfile.TemporaryDirectory() as temp_dir: 58 | host_guest_model_input \ 59 | = create_model_input.create_host_guest_mmvt_model_input( 60 | temp_dir, ff=FF) 61 | host_guest_model_input.integrator_type = "langevin" 62 | host_guest_model_input.timestep = TIMESTEP 63 | host_guest_model_input.hydrogenMass = 3.0 64 | host_guest_model_input.calculation_settings.md_output_interval = 2000 65 | host_guest_model_input.calculation_settings.md_steps_per_anchor = 20000 66 | run_short_ci(host_guest_model_input, cuda_device_index) 67 | 68 | return 69 | 70 | def run_generic_namd_hostguest_ci(cuda_device_index): 71 | with tempfile.TemporaryDirectory() as temp_dir: 72 | host_guest_model_input \ 73 | = create_model_input.create_host_guest_mmvt_model_input(temp_dir) 74 | host_guest_model_input.md_program = "namd" 75 | for input_anchor in host_guest_model_input.cv_inputs[0].input_anchors: 76 | input_anchor.starting_amber_params.prmtop_filename \ 77 | = "../data/hostguest_files/hostguest_for_NAMD.parm7" 78 | run_short_ci(host_guest_model_input, cuda_device_index, 79 | long_check=False) 80 | 81 | return 82 | 83 | def run_elber_hostguest_ci(cuda_device_index): 84 | with tempfile.TemporaryDirectory() as temp_dir: 85 | host_guest_model_input \ 86 | = create_model_input.create_host_guest_elber_model_input(temp_dir) 87 | run_short_ci(host_guest_model_input, cuda_device_index, 88 | long_check=False) 89 | host_guest_model_input.calculation_type = "elber" 90 | 91 | return 92 | 93 | def run_multisite_sod_ci(cuda_device_index): 94 | with tempfile.TemporaryDirectory() as temp_dir: 95 | sod_model_input \ 96 | = create_model_input.create_sod_mmvt_model_input(temp_dir) 97 | run_short_ci(sod_model_input, cuda_device_index, long_check=False) 98 | 99 | return 100 | 101 | def run_doc_api_examples_ci(cuda_device_index): 102 | os.chdir("..") 103 | with tempfile.TemporaryDirectory() as temp_dir: 104 | model_input_filename = "data/sample_input_mmvt_openmm.xml" 105 | model_input = seekr2.prepare.common_prepare.Model_input() 106 | model_input.deserialize(model_input_filename, user_input=True) 107 | # this line not part of API documentation 108 | model_input.root_directory = os.path.join(temp_dir, "test_api_examples") 109 | model, xml_path = seekr2.prepare.prepare(model_input) 110 | model.anchor_rootdir = os.path.dirname(xml_path) 111 | seekr2.modules.check.check_pre_simulation_all(model) 112 | seekr2.run.run(model, "any") 113 | analysis = seekr2.analyze.analyze(model) 114 | analysis.print_results() 115 | 116 | # listing 2 117 | from openmm import unit 118 | new_input_anchor = seekr2.modules.common_cv.Spherical_cv_anchor() 119 | new_input_anchor.radius = 0.1 120 | model_input.cv_inputs[0].input_anchors.insert(1, new_input_anchor) 121 | model, xml_path = seekr2.prepare.prepare( 122 | model_input, force_overwrite=True) 123 | model_input.cv_inputs[0].input_anchors[1].radius \ 124 | = 0.11 125 | model, xml_path = seekr2.prepare.prepare( 126 | model_input, force_overwrite=True) 127 | 128 | # listing 3 129 | print(analysis.main_data_sample.Q) 130 | print(analysis.free_energy_profile) 131 | 132 | if __name__ == "__main__": 133 | if len(sys.argv) <= 1: 134 | argument = "short" 135 | else: 136 | argument = sys.argv[1] 137 | 138 | if len(sys.argv) == 3: 139 | cuda_device_index = sys.argv[2] 140 | else: 141 | cuda_device_index = None 142 | 143 | starttime = time.time() 144 | if argument == "short": 145 | run_generic_hostguest_ci(cuda_device_index) 146 | elif argument == "namd": 147 | run_generic_namd_hostguest_ci(cuda_device_index) 148 | elif argument == "elber": 149 | run_elber_hostguest_ci(cuda_device_index) 150 | elif argument == "multisite": 151 | run_multisite_sod_ci(cuda_device_index) 152 | elif argument == "long": 153 | run_generic_hostguest_ci(cuda_device_index) 154 | run_generic_namd_hostguest_ci(cuda_device_index) 155 | run_elber_hostguest_ci(cuda_device_index) 156 | run_multisite_sod_ci(cuda_device_index) 157 | elif argument == "api_examples": 158 | run_doc_api_examples_ci(cuda_device_index) 159 | 160 | print("Time elapsed: {:.3f}".format(time.time() - starttime)) 161 | print("Continuous Integration Tests Passed Successfully.") -------------------------------------------------------------------------------- /seekr2/data/README.md: -------------------------------------------------------------------------------- 1 | # Sample Package Data 2 | 3 | This directory contains sample additional data you may want to include with your package. 4 | This is a place where non-code related additional information (such as data files, molecular structures, etc.) can 5 | go that you want to ship alongside your code. 6 | 7 | Please note that it is not recommended to place large files in your git directory. If your project requires files larger 8 | than a few megabytes in size it is recommended to host these files elsewhere. This is especially true for binary files 9 | as the `git` structure is unable to correctly take updates to these files and will store a complete copy of every version 10 | in your `git` history which can quickly add up. As a note most `git` hosting services like GitHub have a 1 GB per repository 11 | cap. 12 | 13 | ## Including package data 14 | 15 | Modify your package's `setup.py` file and the `setup()` command. Include the 16 | [`package_data`](http://setuptools.readthedocs.io/en/latest/setuptools.html#basic-use) keyword and point it at the 17 | correct files. 18 | 19 | ## Manifest 20 | 21 | * `look_and_say.dat`: first entries of the "Look and Say" integer series, sequence [A005150](https://oeis.org/A005150) 22 | -------------------------------------------------------------------------------- /seekr2/data/hostguest_files/hostguest_ligand.pqr: -------------------------------------------------------------------------------- 1 | REMARK 1 File generated by pdb2.py by Lane Votapka 2 | ATOM 1 C43 APN 1 0.066 -0.637 1.175 0.3270 1.700 3 | ATOM 2 H71 APN 2 -0.551 0.272 0.871 0.0250 1.300 4 | ATOM 3 H79 APN 3 -0.180 -1.482 0.450 -0.0390 1.300 5 | ATOM 4 O36 APN 4 1.481 -0.393 1.095 -0.6920 1.500 6 | ATOM 5 H80 APN 5 1.741 -0.633 0.125 0.4070 0.800 7 | ATOM 6 C44 APN 6 -0.265 -1.122 2.579 -0.1440 1.700 8 | ATOM 7 H77 APN 7 -0.772 -2.138 2.478 0.0000 1.300 9 | ATOM 8 H78 APN 8 0.678 -1.273 3.200 0.0270 1.300 10 | ATOM 9 C45 APN 9 -1.251 -0.188 3.283 0.2930 1.700 11 | ATOM 10 H72 APN 10 -1.713 0.484 2.486 -0.0510 1.300 12 | ATOM 11 H73 APN 11 -2.101 -0.768 3.774 -0.0530 1.300 13 | ATOM 12 C46 APN 12 -0.539 0.713 4.284 -0.2350 1.700 14 | ATOM 13 H75 APN 13 0.311 1.294 3.793 0.0480 1.300 15 | ATOM 14 H74 APN 14 -0.077 0.041 5.081 0.0430 1.300 16 | ATOM 15 H76 APN 15 -1.273 1.409 4.809 0.0430 1.300 17 | -------------------------------------------------------------------------------- /seekr2/data/hostguest_files/hostguest_ligand_same_resid.pqr: -------------------------------------------------------------------------------- 1 | REMARK 1 File generated by pdb2.py by Lane Votapka 2 | ATOM 1 C43 APN 1 0.066 -0.637 1.175 0.3270 1.700 3 | ATOM 2 H71 APN 1 -0.551 0.272 0.871 0.0250 1.300 4 | ATOM 3 H79 APN 1 -0.180 -1.482 0.450 -0.0390 1.300 5 | ATOM 4 O36 APN 1 1.481 -0.393 1.095 -0.6920 1.500 6 | ATOM 5 H80 APN 1 1.741 -0.633 0.125 0.4070 0.800 7 | ATOM 6 C44 APN 1 -0.265 -1.122 2.579 -0.1440 1.700 8 | ATOM 7 H77 APN 1 -0.772 -2.138 2.478 0.0000 1.300 9 | ATOM 8 H78 APN 1 0.678 -1.273 3.200 0.0270 1.300 10 | ATOM 9 C45 APN 1 -1.251 -0.188 3.283 0.2930 1.700 11 | ATOM 10 H72 APN 1 -1.713 0.484 2.486 -0.0510 1.300 12 | ATOM 11 H73 APN 1 -2.101 -0.768 3.774 -0.0530 1.300 13 | ATOM 12 C46 APN 1 -0.539 0.713 4.284 -0.2350 1.700 14 | ATOM 13 H75 APN 1 0.311 1.294 3.793 0.0480 1.300 15 | ATOM 14 H74 APN 1 -0.077 0.041 5.081 0.0430 1.300 16 | ATOM 15 H76 APN 1 -1.273 1.409 4.809 0.0430 1.300 17 | -------------------------------------------------------------------------------- /seekr2/data/hostguest_files/hostguest_output.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seekrcentral/seekr2/93bf27571b0bdbce8133227538261e4cddc7b137/seekr2/data/hostguest_files/hostguest_output.pdb -------------------------------------------------------------------------------- /seekr2/modules/__init__.py: -------------------------------------------------------------------------------- 1 | __all__ = [ 2 | "check", 3 | "common_analyze", 4 | "common_base", 5 | "common_converge", 6 | "common_cv", 7 | "common_prepare", 8 | "common_sim_browndye2", 9 | "common_sim_namd", 10 | "common_sim_openmm", 11 | "elber_analyze", 12 | "elber_sim_openmm", 13 | "filetree", 14 | "markov_chain_monte_carlo", 15 | "mmvt_analyze", 16 | "mmvt_base", 17 | "mmvt_sim_namd", 18 | "mmvt_sim_openmm", 19 | "runner_browndye2", 20 | "runner_namd", 21 | "runner_openmm" 22 | ] -------------------------------------------------------------------------------- /seekr2/modules/due.py: -------------------------------------------------------------------------------- 1 | # emacs: at the end of the file 2 | # ex: set sts=4 ts=4 sw=4 et: 3 | # ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### # 4 | from __future__ import annotations 5 | 6 | from typing import Any 7 | 8 | """ 9 | 10 | Stub file for a guaranteed safe import of duecredit constructs: if duecredit 11 | is not available. 12 | 13 | To use it, place it into your project codebase to be imported, e.g. copy as 14 | 15 | cp stub.py /path/tomodule/module/due.py 16 | 17 | Note that it might be better to avoid naming it duecredit.py to avoid shadowing 18 | installed duecredit. 19 | 20 | Then use in your code as 21 | 22 | from .due import due, Doi, BibTeX, Text 23 | 24 | See https://github.com/duecredit/duecredit/blob/master/README.md for examples. 25 | 26 | Origin: Originally a part of the duecredit 27 | Copyright: 2015-2021 DueCredit developers 28 | License: BSD-2 29 | """ 30 | 31 | __version__ = "0.0.9" 32 | 33 | 34 | class InactiveDueCreditCollector: 35 | """Just a stub at the Collector which would not do anything""" 36 | 37 | def _donothing(self, *_args: Any, **_kwargs: Any) -> None: 38 | """Perform no good and no bad""" 39 | pass 40 | 41 | def dcite(self, *_args: Any, **_kwargs: Any): 42 | """If I could cite I would""" 43 | 44 | def nondecorating_decorator(func): 45 | return func 46 | 47 | return nondecorating_decorator 48 | 49 | active = False 50 | activate = add = cite = dump = load = _donothing 51 | 52 | def __repr__(self) -> str: 53 | return self.__class__.__name__ + "()" 54 | 55 | 56 | def _donothing_func(*args: Any, **kwargs: Any) -> None: 57 | """Perform no good and no bad""" 58 | pass 59 | 60 | 61 | try: 62 | from duecredit import BibTeX, Doi, Text, Url, due # lgtm [py/unused-import] 63 | 64 | if "due" in locals() and not hasattr(due, "cite"): 65 | raise RuntimeError("Imported due lacks .cite. DueCredit is now disabled") 66 | except Exception as e: 67 | if not isinstance(e, ImportError): 68 | import logging 69 | 70 | logging.getLogger("duecredit").error( 71 | "Failed to import duecredit due to %s" % str(e) 72 | ) 73 | # Initiate due stub 74 | due = InactiveDueCreditCollector() # type: ignore 75 | BibTeX = Doi = Url = Text = _donothing_func # type: ignore 76 | 77 | # Emacs mode definitions 78 | # Local Variables: 79 | # mode: python 80 | # py-indent-offset: 4 81 | # tab-width: 4 82 | # indent-tabs-mode: nil 83 | # End: 84 | -------------------------------------------------------------------------------- /seekr2/modules/elber_cvs/__init__.py: -------------------------------------------------------------------------------- 1 | __all__ = [ 2 | "elber_cv_base", 3 | "elber_external_cv", 4 | "elber_spherical_cv", 5 | ] -------------------------------------------------------------------------------- /seekr2/modules/markov_chain_monte_carlo.py: -------------------------------------------------------------------------------- 1 | """ 2 | markov_chain_monte_carlo.py 3 | 4 | Algorithms used to sample distributions of rate matrices for Elber and MMVT 5 | milestoning calculations. 6 | 7 | Citation: Noe, F. "Probability Distributions of molecular observables 8 | computed from Markov models." J. Chem. Phys. 2008, 128, No. 244103. 9 | Distribution is: p(Q|N) = p(Q)p(N|Q)/p(N) = 10 | p(Q) PI(q_ij**N_ij * exp(-q_ij * Ri)) 11 | """ 12 | import random 13 | from copy import deepcopy 14 | 15 | import numpy as np 16 | from scipy.stats import expon 17 | 18 | def irreversible_stochastic_matrix_algorithm_sample( 19 | Q, N, R, nonzero_indices=None): 20 | """ 21 | Sample an additional matrix Q from the distribution using a Monte-Carlo 22 | method. Use a modified version of Algorithm 1 from Noe 2008. 23 | """ 24 | MAX_ITER = 1e7 25 | if (not Q.any()) or (not N.any()) or (not R.any()): 26 | return Q 27 | # step 0 - Generate uniform random variables: i,j members of {1,...,m} 28 | m = Q.shape[0] 29 | if nonzero_indices == None: 30 | i = random.choice(range(m)) 31 | j = random.choice(range(m)) 32 | counter = 0 33 | while (Q[i,j] == 0.0) or (Q[i,i] == 0.0) or (N[i,j] <= 1) \ 34 | or (R[i,0] == 0) or (i==j): 35 | i = random.choice(range(m)) 36 | j = random.choice(range(m)) 37 | counter += 1 38 | if counter > MAX_ITER: 39 | raise Exception("Maximum iterations exceeded.") 40 | else: 41 | i, j = random.choice(nonzero_indices) 42 | assert i!=j, "Cannot choose same indices i and j" 43 | 44 | # step 1 - Initialize the matrix (already done) 45 | Qnew = deepcopy(Q) 46 | # step 2.1 - delta, r between 0 and 1 47 | # delta must be sampled such that when it's subtracted from q_ij, the 48 | # result doesn't go below zero 49 | delta = Q[i,j] * (1.0 - expon.rvs()) 50 | random_uniform = random.random() 51 | # step 2.2 - copy Q to a new matrix - already done 52 | 53 | # step 2.3 - Nonreversible element shift 54 | # prior probability: P(Q) 55 | log_prior_probability_old = np.abs(-Qnew[i,j]) 56 | log_prior_probability_new = np.abs(-Qnew[i,j] + delta) 57 | if (log_prior_probability_old == 0.0) or (log_prior_probability_new == 0.0): 58 | p_acc = 0.0 59 | else: 60 | log_p_Q_old = N[i,j] * np.log(np.abs(Qnew[i,j])) - Qnew[i,j] * R[i,0] 61 | log_p_Q_new = N[i,j] * np.log(np.abs(Qnew[i,j] - delta)) \ 62 | - (Qnew[i,j] - delta) * R[i,0] 63 | p_acc = log_p_Q_new - log_p_Q_old + log_prior_probability_new \ 64 | - log_prior_probability_old 65 | 66 | if np.log(random_uniform) <= p_acc: 67 | #log(r) can be directly compared to 68 | # log-likelihood acceptance, p_acc 69 | Qnew[i,i] = Qnew[i,i] + delta 70 | Qnew[i,j] = Qnew[i,j] - delta 71 | 72 | return Qnew -------------------------------------------------------------------------------- /seekr2/modules/mmvt_base.py: -------------------------------------------------------------------------------- 1 | """ 2 | Exists only for backwards-compatibility. 3 | """ 4 | 5 | from seekr2.modules.mmvt_cvs.mmvt_cv_base import MMVT_settings 6 | from seekr2.modules.mmvt_cvs.mmvt_cv_base import MMVT_anchor 7 | from seekr2.modules.mmvt_cvs.mmvt_cv_base import MMVT_toy_anchor 8 | from seekr2.modules.mmvt_cvs.mmvt_spherical_cv import MMVT_spherical_CV 9 | from seekr2.modules.mmvt_cvs.mmvt_tiwary_cv import MMVT_tiwary_CV 10 | from seekr2.modules.mmvt_cvs.mmvt_planar_cv import MMVT_planar_CV 11 | from seekr2.modules.mmvt_cvs.mmvt_rmsd_cv import MMVT_RMSD_CV 12 | from seekr2.modules.mmvt_cvs.mmvt_closest_pair_cv import MMVT_closest_pair_CV 13 | from seekr2.modules.mmvt_cvs.mmvt_count_contacts_cv import MMVT_count_contacts_CV 14 | from seekr2.modules.mmvt_cvs.mmvt_external_cv import MMVT_external_CV 15 | from seekr2.modules.mmvt_cvs.mmvt_voronoi_cv import MMVT_Voronoi_CV -------------------------------------------------------------------------------- /seekr2/modules/mmvt_cvs/__init__.py: -------------------------------------------------------------------------------- 1 | __all__ = [ 2 | "mmvt_closest_pair_cv", 3 | "mmvt_count_contacts_cv", 4 | "mmvt_cv_base", 5 | "mmvt_external_cv", 6 | "mmvt_planar_cv", 7 | "mmvt_rmsd_cv", 8 | "mmvt_spherical_cv", 9 | "mmvt_tiwary_cv", 10 | "mmvt_voronoi_cv", 11 | ] -------------------------------------------------------------------------------- /seekr2/prepare.py: -------------------------------------------------------------------------------- 1 | """ 2 | prepare.py 3 | 4 | Accept a model input file and other arguments and settings for creating a 5 | SEEKR2 calculation. Generated files including the model.xml file as well as 6 | the entire filetree. 7 | """ 8 | 9 | import os 10 | import argparse 11 | 12 | import seekr2.modules.common_base as base 13 | import seekr2.modules.common_prepare as common_prepare 14 | import seekr2.modules.filetree as filetree 15 | import seekr2.modules.check as check 16 | # Don't remove the following library imports - needed by deserializer 17 | from seekr2.modules.common_prepare import Browndye_settings_input, \ 18 | MMVT_input_settings, Elber_input_settings, Toy_settings_input 19 | from seekr2.modules.common_base import Ion, Amber_params, Forcefield_params, \ 20 | Charmm_params, Box_vectors 21 | from seekr2.modules.common_cv import Spherical_cv_anchor, Spherical_cv_input, \ 22 | Tiwary_cv_anchor, Tiwary_cv_input, Tiwary_cv_distance_order_parameter, \ 23 | Tiwary_cv_angle_order_parameter, Tiwary_cv_torsion_order_parameter, \ 24 | RMSD_cv_input, RMSD_cv_anchor, Toy_cv_input, Toy_cv_anchor, \ 25 | Z_distance_cv_anchor, Z_distance_cv_input, Grid_combo, \ 26 | State_point, Voronoi_cv_input, Voronoi_cv_anchor, Voronoi_cv_toy_anchor, \ 27 | Closest_pair_cv_input, Closest_pair_cv_anchor, Count_contacts_cv_input, \ 28 | Count_contacts_cv_anchor 29 | 30 | def prepare(model_input, force_overwrite=False): 31 | """ 32 | Using the Model_input from the user, prepare the Model 33 | object and the filetree. Then prepare all building files 34 | for each anchor and serialize the Model to XML. 35 | """ 36 | curdir = os.getcwd() 37 | model = common_prepare.model_factory(model_input) 38 | root_directory = os.path.abspath( 39 | os.path.expanduser(model_input.root_directory)) 40 | model_input.root_directory = root_directory 41 | filetree.generate_filetree_root(model, root_directory) 42 | 43 | xml_path = os.path.join(root_directory, "model.xml") 44 | common_prepare.prepare_model_cvs_and_anchors(model, model_input, 45 | force_overwrite) 46 | filetree.generate_filetree_bd(model, root_directory) 47 | filetree.copy_bd_files(model, model_input, root_directory) 48 | common_prepare.generate_bd_files(model, root_directory) 49 | #model.serialize(xml_path) 50 | base.save_model(model, xml_path) 51 | os.chdir(curdir) 52 | return model, xml_path 53 | 54 | if __name__ == "__main__": 55 | argparser = argparse.ArgumentParser(description=__doc__) 56 | argparser.add_argument( 57 | "model_input_file", metavar="MODEL_INPUT_FILE", type=str, 58 | help="The name of input XML file for a SEEKR2 calculation.") 59 | 60 | argparser.add_argument( 61 | "-f", "--force_overwrite", dest="force_overwrite", default=False, 62 | help="Toggle whether to overwrite existing simulation output files "\ 63 | "within any anchor that might have existed in an old model that would "\ 64 | "be overwritten by generating this new model. If not toggled, this "\ 65 | "program will throw an exception instead of performing any such "\ 66 | "overwrite.", action="store_true") 67 | argparser.add_argument( 68 | "-s", "--skip_checks", dest="skip_checks", default=False, 69 | help="By default, pre-simulation checks will be run after the "\ 70 | "preparation is complete, and if the checks fail, the SEEKR2 "\ 71 | "model will not be saved. This argument bypasses those "\ 72 | "checks and allows the model to be generated anyways.", 73 | action="store_true") 74 | args = argparser.parse_args() # parse the args into a dictionary 75 | args = vars(args) 76 | model_input_filename = args["model_input_file"] 77 | force_overwrite = args["force_overwrite"] 78 | skip_checks = args["skip_checks"] 79 | model_input = common_prepare.Model_input() 80 | model_input.deserialize(model_input_filename, user_input=True) 81 | model, xml_path = prepare(model_input, force_overwrite) 82 | if model.anchor_rootdir == ".": 83 | model_dir = os.path.dirname(xml_path) 84 | model.anchor_rootdir = os.path.abspath(model_dir) 85 | if not skip_checks: 86 | check.check_pre_simulation_all(model) -------------------------------------------------------------------------------- /seekr2/tests/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Empty init file in case you choose a package besides PyTest such as Nose which may look for such a file 3 | """ 4 | -------------------------------------------------------------------------------- /seekr2/tests/create_toy_system.py: -------------------------------------------------------------------------------- 1 | """ 2 | create_toy_system.py 3 | 4 | For creating systems of dummy particles that can be used to test 5 | boundary and restraining forces, etc. 6 | 7 | """ 8 | 9 | import numpy as np 10 | 11 | try: 12 | import openmm.unit as unit 13 | except ImportError: 14 | import simtk.unit as unit 15 | 16 | try: 17 | import openmm 18 | except ImportError: 19 | import simtk.openmm as openmm 20 | 21 | try: 22 | import openmm.app as openmm_app 23 | except ImportError: 24 | import simtk.openmm.app as openmm_app 25 | 26 | import seekr2.modules.mmvt_cvs.mmvt_closest_pair_cv as mmvt_closest_pair_cv 27 | 28 | def make_toy_system_and_topology(num_particles): 29 | """ 30 | Make openmm system and topology files for use with a toy system 31 | with n_particles. 32 | """ 33 | system = openmm.System() 34 | topology = openmm_app.Topology() 35 | for i in range(num_particles): 36 | mass = 10.0 * openmm.unit.amu 37 | system.addParticle(mass) 38 | atom_name = "X{}".format(i) 39 | if not atom_name in openmm_app.element.Element._elements_by_symbol: 40 | element = openmm_app.element.Element(0, atom_name, atom_name, mass) 41 | else: 42 | element = openmm_app.element.Element._elements_by_symbol[atom_name] 43 | chain = topology.addChain() 44 | residue = topology.addResidue("UNK", chain) 45 | topology.addAtom(atom_name, element, residue) 46 | 47 | return system, topology 48 | 49 | def make_toy_simulation_and_context(system, topology, positions): 50 | integrator = openmm.LangevinIntegrator( 51 | 300.0*unit.kelvin, 1.0/unit.picoseconds, 0.002*unit.picoseconds) 52 | ref_platform = openmm.Platform.getPlatformByName('Reference') 53 | ref_properties = {} 54 | simulation = openmm_app.Simulation( 55 | topology, system, integrator, ref_platform, ref_properties) 56 | simulation.context.setPositions(positions) 57 | simulation.context.setVelocitiesToTemperature(300.0*unit.kelvin) 58 | return simulation 59 | 60 | def assign_nonbonded_cv_info(cv, system, box_vectors, cutoff=None): 61 | """ 62 | Update the cv with the correct nonbonded information. 63 | """ 64 | cv.num_system_particles = system.getNumParticles() 65 | #forces = { force.__class__.__name__ : force for force in system.getForces() } 66 | #reference_force = forces['NonbondedForce'] 67 | cv.exclusion_pairs = [] 68 | #for index in range(reference_force.getNumExceptions()): 69 | # [iatom, jatom, chargeprod, sigma, epsilon] \ 70 | # = reference_force.getExceptionParameters(index) 71 | # cv.exclusion_pairs.append((iatom, jatom)) 72 | 73 | if cutoff is None: 74 | cv.cutoff_distance = 0.4 * box_vectors.get_min_length() 75 | else: 76 | cv.cutoff_distance = cutoff 77 | print("cv.cutoff_distance:", cv.cutoff_distance) 78 | 79 | return -------------------------------------------------------------------------------- /seekr2/tests/data/ala_ala_ala.pdb: -------------------------------------------------------------------------------- 1 | REMARK * 2 | REMARK DATE: 8/ 5/ 9 14:44:19 CREATED BY USER: mjw 3 | CRYST1 61.208 61.208 85.000 90.00 90.00 90.00 1 4 | ATOM 1 N ALA 1 0.024 -0.103 -0.101 1.00 0.00 AAL 5 | ATOM 2 HT1 ALA 1 0.027 -1.132 -0.239 1.00 0.00 AAL 6 | ATOM 3 HT2 ALA 1 -0.805 0.163 0.471 1.00 0.00 AAL 7 | ATOM 4 HT3 ALA 1 -0.059 0.384 -1.019 1.00 0.00 AAL 8 | ATOM 5 CA ALA 1 1.247 0.375 0.636 1.00 0.00 AAL 9 | ATOM 6 HA ALA 1 0.814 0.861 1.495 1.00 0.00 AAL 10 | ATOM 7 CB ALA 1 2.057 -0.772 1.289 1.00 0.00 AAL 11 | ATOM 8 HB1 ALA 1 3.136 -0.752 1.032 1.00 0.00 AAL 12 | ATOM 9 HB2 ALA 1 1.990 -0.641 2.395 1.00 0.00 AAL 13 | ATOM 10 HB3 ALA 1 1.656 -1.782 1.063 1.00 0.00 AAL 14 | ATOM 11 C ALA 1 1.956 1.579 0.036 1.00 0.00 AAL 15 | ATOM 12 O ALA 1 1.219 2.525 -0.201 1.00 0.00 AAL 16 | ATOM 13 N ALA 2 3.289 1.631 -0.202 1.00 0.00 AAL 17 | ATOM 14 HN ALA 2 3.939 0.868 -0.174 1.00 0.00 AAL 18 | ATOM 15 CA ALA 2 3.990 2.909 -0.215 1.00 0.00 AAL 19 | ATOM 16 HA ALA 2 3.742 3.440 0.695 1.00 0.00 AAL 20 | ATOM 17 CB ALA 2 3.662 3.802 -1.434 1.00 0.00 AAL 21 | ATOM 18 HB1 ALA 2 4.192 4.778 -1.358 1.00 0.00 AAL 22 | ATOM 19 HB2 ALA 2 3.956 3.311 -2.382 1.00 0.00 AAL 23 | ATOM 20 HB3 ALA 2 2.577 4.027 -1.467 1.00 0.00 AAL 24 | ATOM 21 C ALA 2 5.487 2.654 -0.128 1.00 0.00 AAL 25 | ATOM 22 O ALA 2 5.889 1.489 -0.137 1.00 0.00 AAL 26 | ATOM 23 N ALA 3 6.275 3.733 -0.037 1.00 0.00 AAL 27 | ATOM 24 HN ALA 3 5.963 4.691 -0.028 1.00 0.00 AAL 28 | ATOM 25 CA ALA 3 7.707 3.802 0.068 1.00 0.00 AAL 29 | ATOM 26 HA ALA 3 8.160 3.418 -0.833 1.00 0.00 AAL 30 | ATOM 27 CB ALA 3 8.233 3.093 1.333 1.00 0.00 AAL 31 | ATOM 28 HB1 ALA 3 9.342 3.149 1.356 1.00 0.00 AAL 32 | ATOM 29 HB2 ALA 3 7.835 3.593 2.240 1.00 0.00 AAL 33 | ATOM 30 HB3 ALA 3 7.923 2.030 1.332 1.00 0.00 AAL 34 | ATOM 31 C ALA 3 8.018 5.323 0.136 1.00 0.00 AAL 35 | ATOM 32 OT1 ALA 3 7.032 6.119 0.127 1.00 0.00 AAL 36 | ATOM 33 OT2 ALA 3 9.219 5.692 0.188 1.00 0.00 AAL 37 | TER 34 ALA 3 38 | END 39 | -------------------------------------------------------------------------------- /seekr2/tests/data/ligand_for_test.pqr: -------------------------------------------------------------------------------- 1 | REMARK 1 File generated by pdb2.py by Lane Votapka 2 | ATOM 1 C43 APN 1 0.066 -0.637 1.175 0.3270 1.700 3 | ATOM 2 H71 APN 2 -0.551 0.272 0.871 0.0250 1.300 4 | ATOM 3 H79 APN 3 -0.180 -1.482 0.450 -0.0390 1.300 5 | ATOM 4 O36 APN 4 1.481 -0.393 1.095 -0.6920 1.500 6 | ATOM 5 H80 APN 5 1.741 -0.633 0.125 0.4070 0.800 7 | ATOM 6 C44 APN 6 -0.265 -1.122 2.579 -0.1440 1.700 8 | ATOM 7 H77 APN 7 -0.772 -2.138 2.478 0.0000 1.300 9 | ATOM 8 H78 APN 8 0.678 -1.273 3.200 0.0270 1.300 10 | ATOM 9 C45 APN 9 -1.251 -0.188 3.283 0.2930 1.700 11 | ATOM 10 H72 APN 10 -1.713 0.484 2.486 -0.0510 1.300 12 | ATOM 11 H73 APN 11 -2.101 -0.768 3.774 -0.0530 1.300 13 | ATOM 12 C46 APN 12 -0.539 0.713 4.284 -0.2350 1.700 14 | ATOM 13 H75 APN 13 0.311 1.294 3.793 0.0480 1.300 15 | ATOM 14 H74 APN 14 -0.077 0.041 5.081 0.0430 1.300 16 | ATOM 15 H76 APN 15 -1.273 1.409 4.809 0.0430 1.300 17 | -------------------------------------------------------------------------------- /seekr2/tests/data/sample_bd_milestone_results.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 1.0005 4 | 1.79769e+308 5 | 78 6 | 0.000142 7 | 0.243 8 | 1 9 | 10 | 1 11 | 12 | 0.2 13 | 0.05 14 | 0 15 | 0 16 | 17 | 18 | 17.3332 19 | 11.2152 20 | 2 21 | 22 | 23 | 100000 24 | 0 25 | 54070 26 | 27 | b_13 28 | 65239 29 | 30 | 31 | 13_12 32 | 45930 33 | 34 | 35 | 181617390 36 | 37 | -------------------------------------------------------------------------------- /seekr2/tests/data/sample_bd_results_file.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 1 4 | 8.75563 5 | 78 6 | 0.000142 7 | 0.243 8 | 1 9 | 10 | 1 11 | 12 | 0.2 13 | 0.05 14 | 0 15 | 0 16 | 17 | 18 | 71.957 19 | 43.1749 20 | 1 21 | 22 | 23 | 100000 24 | 0 25 | 95447 26 | 27 | b_10 28 | 4553 29 | 30 | 31 | 805045002 32 | 33 | -------------------------------------------------------------------------------- /seekr2/tests/data/sample_bd_results_file2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 1.0005 4 | 1.79769e+308 5 | 78 6 | 0.000142 7 | 0.243 8 | 1 9 | 10 | 1 11 | 12 | 0.2 13 | 0.05 14 | 0 15 | 0 16 | 17 | 18 | 17.3332 19 | 11.2152 20 | 2 21 | 22 | 23 | 100000 24 | 0 25 | 54070 26 | 27 | b_12 28 | 65239 29 | 30 | 31 | 12_11 32 | 45930 33 | 34 | 35 | 181617390 36 | 37 | -------------------------------------------------------------------------------- /seekr2/tests/data/test_analyze_output_elber.txt: -------------------------------------------------------------------------------- 1 | #"Crossed boundary ID","crossing counter","total time (ps)" 2 | # An asterisk(*) indicates that source milestone was never crossed - asterisked statistics are invalid and should be excluded. 3 | 3,2,0.11 4 | 3*,3,0.482 5 | 3,5,0.296 6 | 3,6,0.12 7 | 1,7,0.164 8 | 1,10,0.124 9 | 1*,11,0.358 10 | 3,14,0.084 11 | 1,15,0.178 12 | 3,18,0.248 -------------------------------------------------------------------------------- /seekr2/tests/data/test_analyze_outputfile_checkpoint1.txt: -------------------------------------------------------------------------------- 1 | #"Bounced boundary ID","bounce index","total time (ps)" 2 | CHECKPOINT,41.000 3 | 1,0,41.222000000004414 4 | 2,1,41.728000000005032 5 | CHECKPOINT,42.000 6 | CHECKPOINT,43.000 7 | 1,2,43.222000000006858 8 | 1,3,43.964000000007765 9 | CHECKPOINT,44.000 10 | 1,4,44.600000000008542 11 | 1,5,44.954000000008975 12 | CHECKPOINT,45.000 13 | 1,6,45.256000000009344 14 | CHECKPOINT,46.000 15 | 1,6,46.256000000009344 16 | -------------------------------------------------------------------------------- /seekr2/tests/data/test_analyze_outputfile_checkpoint2.txt: -------------------------------------------------------------------------------- 1 | #"Bounced boundary ID","bounce index","total time (ps)" 2 | CHECKPOINT,46.000 3 | 1,6,46.356000000009344 4 | 1,7,46.534000000009684 5 | 1,8,46.930000000010168 6 | CHECKPOINT,47.000 7 | 1,9,47.306000000010627 8 | -------------------------------------------------------------------------------- /seekr2/tests/data/test_analyze_outputfile_namd.txt: -------------------------------------------------------------------------------- 1 | #"Bounced boundary ID","bounce index","total time (ps)" 2 | SEEKR: Cell Collision: current: 1, new: 0, stepnum: 110 3 | SEEKR: Milestone Transition: anchor: 1, source: none, destination: 0, stepnum: 110, incubation steps: 110 4 | SEEKR: Cell Collision: current: 1, new: 2, stepnum: 115 5 | SEEKR: Milestone Transition: anchor: 1, source: 0, destination: 1, stepnum: 115, incubation steps: 5 6 | SEEKR: Cell Collision: current: 1, new: 0, stepnum: 120 7 | SEEKR: Milestone Transition: anchor: 1, source: 1, destination: 0, stepnum: 120, incubation steps: 5 8 | SEEKR: Cell Collision: current: 1, new: 0, stepnum: 125 9 | SEEKR: Cell Collision: current: 1, new: 0, stepnum: 130 10 | SEEKR: Cell Collision: current: 1, new: 0, stepnum: 135 11 | SEEKR: Cell Collision: current: 1, new: 0, stepnum: 140 12 | SEEKR: Cell Collision: current: 1, new: 0, stepnum: 145 13 | SEEKR: Cell Collision: current: 1, new: 0, stepnum: 150 14 | SEEKR: Cell Collision: current: 1, new: 0, stepnum: 155 -------------------------------------------------------------------------------- /seekr2/tests/data/test_analyze_outputfile_namd_checkpoint1.txt: -------------------------------------------------------------------------------- 1 | SEEKR: Cell Collision: current: 1, new: 0, stepnum: 110 2 | SEEKR: Milestone Transition: anchor: 1, source: none, destination: 0, stepnum: 110, incubation steps: 110 3 | SEEKR: Cell Collision: current: 1, new: 2, stepnum: 115 4 | SEEKR: Milestone Transition: anchor: 1, source: 0, destination: 1, stepnum: 115, incubation steps: 5 5 | SEEKR: Cell Collision: current: 1, new: 0, stepnum: 120 6 | SEEKR: Milestone Transition: anchor: 1, source: 1, destination: 0, stepnum: 120, incubation steps: 5 7 | CHECKPOINTING AT STEP 120 8 | SEEKR: Cell Collision: current: 1, new: 0, stepnum: 125 9 | SEEKR: Cell Collision: current: 1, new: 0, stepnum: 130 10 | SEEKR: Cell Collision: current: 1, new: 0, stepnum: 135 11 | CHECKPOINTING AT STEP 140 12 | SEEKR: Cell Collision: current: 1, new: 0, stepnum: 140 13 | SEEKR: Cell Collision: current: 1, new: 0, stepnum: 145 14 | -------------------------------------------------------------------------------- /seekr2/tests/data/test_analyze_outputfile_namd_checkpoint2.txt: -------------------------------------------------------------------------------- 1 | SEEKR: Cell Collision: current: 1, new: 0, stepnum: 142 2 | SEEKR: Cell Collision: current: 1, new: 0, stepnum: 147 3 | SEEKR: Cell Collision: current: 1, new: 0, stepnum: 150 4 | SEEKR: Cell Collision: current: 1, new: 0, stepnum: 155 5 | -------------------------------------------------------------------------------- /seekr2/tests/data/test_analyze_outputfile_namd_restart1.txt: -------------------------------------------------------------------------------- 1 | SEEKR: Cell Collision: current: 1, new: 0, stepnum: 110 2 | SEEKR: Milestone Transition: anchor: 1, source: none, destination: 0, stepnum: 110, incubation steps: 110 3 | SEEKR: Cell Collision: current: 1, new: 2, stepnum: 115 4 | SEEKR: Milestone Transition: anchor: 1, source: 0, destination: 1, stepnum: 115, incubation steps: 5 5 | SEEKR: Cell Collision: current: 1, new: 0, stepnum: 120 6 | SEEKR: Milestone Transition: anchor: 1, source: 1, destination: 0, stepnum: 120, incubation steps: 5 7 | SEEKR: Cell Collision: current: 1, new: 0, stepnum: 125 8 | SEEKR: Cell Collision: current: 1, new: 0, stepnum: 130 9 | SEEKR: Cell Collision: current: 1, new: 0, stepnum: 135 10 | SEEKR: Cell Collision: current: 1, new: 0, stepnum: 140 11 | SEEKR: Cell Collision: current: 1, new: 0, stepnum: 145 12 | -------------------------------------------------------------------------------- /seekr2/tests/data/test_analyze_outputfile_namd_restart2.txt: -------------------------------------------------------------------------------- 1 | SEEKR: Cell Collision: current: 1, new: 0, stepnum: 140 2 | SEEKR: Cell Collision: current: 1, new: 0, stepnum: 145 3 | SEEKR: Cell Collision: current: 1, new: 0, stepnum: 150 4 | SEEKR: Cell Collision: current: 1, new: 0, stepnum: 155 5 | -------------------------------------------------------------------------------- /seekr2/tests/data/test_analyze_outputfile_restart1.txt: -------------------------------------------------------------------------------- 1 | #"Bounced boundary ID","bounce index","total time (ps)" 2 | 1,0,41.222000000004414 3 | 2,1,41.728000000005032 4 | 1,2,43.222000000006858 5 | 1,3,43.964000000007765 6 | 1,4,44.600000000008542 7 | 1,5,44.954000000008975 8 | 1,6,45.256000000009344 -------------------------------------------------------------------------------- /seekr2/tests/data/test_analyze_outputfile_restart2.txt: -------------------------------------------------------------------------------- 1 | #"Bounced boundary ID","bounce index","total time (ps)" 2 | 1,5,44.954000000008975 3 | 1,6,45.256000000009344 4 | 1,7,45.534000000009684 5 | 1,8,45.930000000010168 6 | 1,9,46.306000000010627 -------------------------------------------------------------------------------- /seekr2/tests/data/test_analyze_statistics.txt: -------------------------------------------------------------------------------- 1 | N_alpha_1: 2423 2 | N_alpha_2: 98 3 | N_1_1_alpha: 0 4 | N_1_2_alpha: 52 5 | N_2_1_alpha: 52 6 | N_2_2_alpha: 0 7 | R_1_alpha: 1658.6959999999933 8 | R_2_alpha: 198.91199999999188 9 | T_alpha: 1954.7599999666209 10 | -------------------------------------------------------------------------------- /seekr2/tests/data/test_namd.xsc: -------------------------------------------------------------------------------- 1 | # NAMD extended system configuration output file 2 | #$LABELS step a_x a_y a_z b_x b_y b_z c_x c_y c_z o_x o_y o_z 3 | 1000 61.359 0 0 -20.451768 57.850256 0 -20.451768 -28.922514 50.1013 0 0 0 4 | -------------------------------------------------------------------------------- /seekr2/tests/pytest.ini: -------------------------------------------------------------------------------- 1 | # pytest.ini 2 | [pytest] 3 | markers = 4 | needs_cuda: marks tests as needing CUDA to run. -------------------------------------------------------------------------------- /seekr2/tests/test_check.py: -------------------------------------------------------------------------------- 1 | """ 2 | test_check.py 3 | """ 4 | 5 | from seekr2.modules import check 6 | 7 | def test_toy_check_systems_within_Voronoi_cells_elber(toy_elber_model): 8 | check.check_systems_within_Voronoi_cells(toy_elber_model) -------------------------------------------------------------------------------- /seekr2/tests/test_common_base.py: -------------------------------------------------------------------------------- 1 | """ 2 | test_common_base.py 3 | """ 4 | import os 5 | import pytest 6 | import random 7 | 8 | import numpy as np 9 | from parmed import unit 10 | 11 | import seekr2.modules.common_base as base 12 | 13 | TEST_DIRECTORY = os.path.dirname(__file__) 14 | 15 | def test_strBool(): 16 | assert base.strBool('True') == True 17 | assert base.strBool('true') == True 18 | assert base.strBool('TRUE') == True 19 | assert base.strBool('False') == False 20 | assert base.strBool('false') == False 21 | assert base.strBool('FALSE') == False 22 | with pytest.raises(Exception): 23 | base.strBool('balderdash') 24 | return 25 | 26 | def test_order_files_numerically(): 27 | string_list = ["/path/to/anchor0/output0_0", "/path/to/anchor0/output0_1", 28 | "/path/to/anchor0/output0_2", "/path/to/anchor0/output1_0", 29 | "/path/to/anchor0/output1_1", "/path/to/anchor0/output1_2", 30 | "/path/to/anchor1/output0_0", "/path/to/anchor1/output0_1", 31 | "/path/to/anchor1/output2_0", "/path/to/anchor1/output10_0"] 32 | desired_list = string_list[:] 33 | random.shuffle(string_list) 34 | ordered_list = base.order_files_numerically(string_list) 35 | 36 | for item1, item2 in zip(ordered_list, desired_list): 37 | assert item1==item2 38 | 39 | scrambled_list = ["me2.345.pdb", "me1.234.pdb", "me-3.456.pdb"] 40 | correct_list = ["me-3.456.pdb", "me1.234.pdb", "me2.345.pdb"] 41 | ordered_list = base.order_files_numerically(scrambled_list, func=float) 42 | for item1, item2 in zip(ordered_list, correct_list): 43 | assert item1==item2 44 | 45 | string_list = ["mmvt.restart1.out", "mmvt.restart2.out"] 46 | desired_list = string_list[:] 47 | random.shuffle(string_list) 48 | ordered_list = base.order_files_numerically(string_list) 49 | 50 | for item1, item2 in zip(ordered_list, desired_list): 51 | assert item1==item2 52 | 53 | string_list = ["/path/to/anchor_0.1/output0_0", 54 | "/path/to/anchor_0.2/output0_1"] 55 | 56 | desired_list = string_list[:] 57 | random.shuffle(string_list) 58 | ordered_list = base.order_files_numerically(string_list) 59 | 60 | return 61 | 62 | def test_box_vectors(): 63 | box_vector_q = unit.Quantity( 64 | [[64.9127105, 0.0, 0.0], 65 | [-21.6375684, 61.2002909, 0.0], 66 | [-21.6375684, -30.6001417, 53.0010088]], 67 | unit=unit.angstrom) 68 | box_vector = base.Box_vectors() 69 | box_vector.from_quantity(box_vector_q) 70 | assert np.isclose(box_vector.ax, 6.49127105) 71 | assert np.isclose(box_vector.ay, 0.0) 72 | assert np.isclose(box_vector.az, 0.0) 73 | assert np.isclose(box_vector.bx, -2.16375684) 74 | assert np.isclose(box_vector.by, 6.12002909) 75 | assert np.isclose(box_vector.bz, 0.0) 76 | assert np.isclose(box_vector.cx, -2.16375684) 77 | assert np.isclose(box_vector.cy, -3.06001417) 78 | assert np.isclose(box_vector.cz, 5.30010088) 79 | box_vector_q2 = box_vector.to_quantity() 80 | assert np.isclose(box_vector_q2.value_in_unit(unit.nanometers)[0][0], 81 | 6.49127105) 82 | assert np.isclose(box_vector_q2.value_in_unit(unit.nanometers)[0][1], 0.0) 83 | assert np.isclose(box_vector_q2.value_in_unit(unit.nanometers)[0][2], 0.0) 84 | assert np.isclose(box_vector_q2.value_in_unit(unit.nanometers)[1][0], 85 | -2.16375684) 86 | assert np.isclose(box_vector_q2.value_in_unit(unit.nanometers)[1][1], 87 | 6.12002909) 88 | assert np.isclose(box_vector_q2.value_in_unit(unit.nanometers)[1][2], 0.0) 89 | assert np.isclose(box_vector_q2.value_in_unit(unit.nanometers)[2][0], 90 | -2.16375684) 91 | assert np.isclose(box_vector_q2.value_in_unit(unit.nanometers)[2][1], 92 | -3.06001417) 93 | assert np.isclose(box_vector_q2.value_in_unit(unit.nanometers)[2][2], 94 | 5.30010088) 95 | box_6_vector = [61.239410, 61.239410, 61.239410, 109.471, 109.471, 109.471] 96 | box_vector2 = base.Box_vectors() 97 | box_vector2.from_6_vector(box_6_vector) 98 | assert np.isclose(box_vector2.ax, 6.1239410, atol=0.001) 99 | assert np.isclose(box_vector2.ay, 0.0) 100 | assert np.isclose(box_vector2.az, 0.0) 101 | assert np.isclose(box_vector2.bx, -2.041313667, atol=0.001) 102 | assert np.isclose(box_vector2.by, 5.773707003, atol=0.001) 103 | assert np.isclose(box_vector2.bz, 0.0) 104 | assert np.isclose(box_vector2.cx, -2.041313667, atol=0.001) 105 | assert np.isclose(box_vector2.cy, -2.886853152, atol=0.001) 106 | assert np.isclose(box_vector2.cz, 5.00017714, atol=0.001) 107 | expected_box_6_vector = [6.1239410, 6.1239410, 6.1239410, 109.47122, 108 | 109.47122, 109.47122] 109 | resulting_box_6_vector = box_vector2.to_6_vector() 110 | assert np.isclose(np.array(expected_box_6_vector), 111 | np.array(resulting_box_6_vector)).all() 112 | return 113 | 114 | def test_Barostat_settings(): 115 | """ 116 | Initialize the Barostat_settings_openmm and Barostat_settings_namd 117 | object to get more coverage. 118 | """ 119 | dummy1 = base.Barostat_settings_openmm() 120 | dummy2 = base.Barostat_settings_namd() 121 | return 122 | 123 | def test_Cuda_platform_settings(): 124 | """ 125 | Initialize the Cuda_platforms_settings() object. 126 | """ 127 | cuda_platform_settings = base.Cuda_platform_settings() 128 | properties = cuda_platform_settings.make_properties_dict() 129 | assert properties["CudaDeviceIndex"] == "0" 130 | assert properties["CudaPrecision"] == "mixed" 131 | return 132 | 133 | def test_model_get_type(host_guest_mmvt_model, host_guest_elber_model): 134 | """ 135 | Assure that the model.get_type() function is working properly 136 | """ 137 | assert host_guest_mmvt_model.get_type() == "mmvt" 138 | assert host_guest_elber_model.get_type() == "elber" 139 | host_guest_mmvt_model.calculation_type = "wrong" 140 | with pytest.raises(Exception) as e_info: 141 | host_guest_mmvt_model.get_type() 142 | return 143 | 144 | def test_model_get_timestep(host_guest_mmvt_model): 145 | """ 146 | Assure that the model.get_type() function is working properly 147 | """ 148 | assert host_guest_mmvt_model.get_timestep() == 0.002 149 | return 150 | 151 | def test_model_get_bulk_index(host_guest_mmvt_model, toy_multi_model): 152 | assert host_guest_mmvt_model.get_bulk_index() == 13 153 | assert toy_multi_model.get_bulk_index() == None 154 | return 155 | 156 | def test_get_box_vectors_from_pdb(): 157 | expected_box_vectors = unit.Quantity( 158 | [[40.142, 0.0, 0.0], 159 | [0.0, 40.329, 0.0], 160 | [0.0, 0.0, 32.472]], 161 | unit=unit.angstrom) 162 | test_pdb_filename = os.path.join( 163 | TEST_DIRECTORY, 164 | "../data/hostguest_files/hostguest_at0.5.pdb") 165 | result = base.get_box_vectors_from_pdb(test_pdb_filename) 166 | assert np.isclose(expected_box_vectors.value_in_unit(unit.angstroms), 167 | result.value_in_unit(unit.angstroms)).all() 168 | 169 | def test_parse_xml_list(): 170 | input_list1 = [3,4,5,6] 171 | assert base.parse_xml_list(input_list1) == input_list1 172 | input_range1 = "range(5)" 173 | assert base.parse_xml_list(input_range1) == [0,1,2,3,4] 174 | input_range1 = "range(2,7)" 175 | assert base.parse_xml_list(input_range1) == [2,3,4,5,6] 176 | input_range1 = "range(3,9,2)" 177 | assert base.parse_xml_list(input_range1) == [3,5,7] 178 | with pytest.raises(Exception): 179 | base.parse_xml_list(2) 180 | with pytest.raises(Exception): 181 | base.parse_xml_list("balderdash") 182 | return 183 | -------------------------------------------------------------------------------- /seekr2/tests/test_common_cv.py: -------------------------------------------------------------------------------- 1 | """ 2 | test_common_cv.py 3 | 4 | Testing modules/common_cv.py 5 | """ 6 | 7 | import seekr2.modules.common_cv as common_cv 8 | 9 | def test_assign_state_points_toy(toy_mmvt_model_input, toy_mmvt_model): 10 | stateA = common_cv.State_point() 11 | stateA.name = "stateA" 12 | stateA.location = [[0.0, -0.7, 0.0]] 13 | stateB = common_cv.State_point() 14 | stateB.name = "stateB" 15 | stateB.location = [[0.0, 0.7, 0.0]] 16 | toy_mmvt_model_input.cv_inputs[0].state_points = [stateA, stateB] 17 | common_cv.assign_state_points(toy_mmvt_model_input, toy_mmvt_model) 18 | assert toy_mmvt_model.anchors[0].name == "stateA" 19 | assert toy_mmvt_model.anchors[7].name == "stateB" 20 | return 21 | 22 | def test_assign_state_points_hostguest(host_guest_mmvt_model_input, 23 | host_guest_mmvt_model): 24 | bound_state = common_cv.State_point() 25 | bound_state.name = "bound" 26 | bound_state.location = 0.06 27 | bulk_state = common_cv.State_point() 28 | bulk_state.name = "bulk" 29 | bulk_state.location = 1.36 30 | host_guest_mmvt_model_input.cv_inputs[0].state_points \ 31 | = [bound_state, bulk_state] 32 | common_cv.assign_state_points(host_guest_mmvt_model_input, 33 | host_guest_mmvt_model) 34 | assert host_guest_mmvt_model.anchors[0].name == "bound" 35 | assert host_guest_mmvt_model.anchors[13].name == "bulk" 36 | return 37 | 38 | -------------------------------------------------------------------------------- /seekr2/tests/test_common_sim_browndye2.py: -------------------------------------------------------------------------------- 1 | """ 2 | test_sim_browndye2.py 3 | """ 4 | 5 | import pytest 6 | import os 7 | import re 8 | from shutil import copyfile 9 | 10 | import parmed 11 | import numpy as np 12 | 13 | import seekr2.modules.common_sim_browndye2 as sim_browndye2 14 | 15 | TEST_DIRECTORY = os.path.dirname(__file__) 16 | 17 | def verify_xml_text(filename, tag, text): 18 | with open(filename, 'r') as f: 19 | for line in f.readlines(): 20 | result = re.search("<%s>%s" % (tag, text, tag), line) 21 | if result: 22 | return 23 | 24 | raise Exception("tag not found in file: %s" % tag) 25 | return 26 | 27 | def make_test_browndye_input(tmp_path): 28 | test_filename = os.path.join(tmp_path, "test_input.xml") 29 | root = sim_browndye2.Root() 30 | root.n_threads = 3 31 | root.seed = 4567 32 | root.output = "test_output.xml" 33 | root.n_trajectories = 65535 34 | root.n_trajectories_per_output = 5 35 | root.max_n_steps = 123456 36 | root.trajectory_file = "test_traj" 37 | root.n_steps_per_output = 123 38 | root.system.start_at_site = "true" 39 | root.system.reaction_file = "my_rxns.xml" 40 | root.system.hydrodynamic_interactions = "false" 41 | root.system.solvent.dielectric = 77.4 42 | root.system.solvent.relative_viscosity = 0.4 43 | root.system.solvent.debye_length = 9.8 44 | root.system.solvent.kT = 1.456 45 | root.system.solvent.desolvation_parameter = 0.8 46 | ion1 = sim_browndye2.Ion() 47 | ion1.radius = 1.34 48 | ion1.charge = -2.0 49 | ion1.conc = 0.2 50 | ion2 = sim_browndye2.Ion() 51 | ion2.radius = 0.85 52 | ion2.charge = 1.0 53 | ion2.conc = 0.4 54 | root.system.solvent.ions = [ion1, ion2] 55 | root.system.time_step_tolerances = sim_browndye2.Time_step_tolerances() 56 | root.system.time_step_tolerances.minimum_core_dt = 0.1 57 | root.system.time_step_tolerances.minimum_core_reaction_dt = 0.01 58 | group1 = sim_browndye2.Group() 59 | group1.name = "receptor" 60 | core1 = sim_browndye2.Core() 61 | core1.name = "receptor" 62 | core1.atoms = "receptor.xml" 63 | core1.all_in_surface = "true" 64 | core1.is_protein = "true" 65 | core1.dielectric = 5.0 66 | core1.grid_spacing = 0.75 67 | grid1 = "receptor.dx" 68 | core1.electric_field.grid_list.append(grid1) 69 | group1.core_list.append(core1) 70 | 71 | group2 = sim_browndye2.Group() 72 | group2.name = "ligand" 73 | core2 = sim_browndye2.Core() 74 | core2.name = "ligand" 75 | core2.atoms = "ligand.xml" 76 | core1.all_in_surface = "true" 77 | core1.is_protein = "true" 78 | core1.dielectric = 5.0 79 | core2.grid_spacing = 0.5 80 | grid2 = "ligand.dx" 81 | core2.electric_field.grid_list.append(grid2) 82 | group2.core_list.append(core2) 83 | 84 | root.system.group_list.append(group1) 85 | root.system.group_list.append(group2) 86 | 87 | root.write(test_filename) 88 | return test_filename, root 89 | 90 | def make_test_browndye_rxn(tmp_path): 91 | test_filename = os.path.join(tmp_path, "test_rxn.xml") 92 | rxnroot = sim_browndye2.Reaction_root() 93 | rxnroot.first_state = "something1" 94 | rxn = sim_browndye2.Reaction() 95 | rxn.name = "test_rxn1" 96 | rxn.state_before = "something1" 97 | rxn.state_after = "something2" 98 | rxn.molecule0_group = "molec1" 99 | rxn.molecule0_core = "molec1" 100 | rxn.molecule1_group = "molec2" 101 | rxn.molecule1_core = "molec2" 102 | rxn.n_needed = 4 103 | pair = sim_browndye2.Pair() 104 | pair.atom1_index = 5432 105 | pair.atom2_index = 789 106 | pair.distance = 8.45 107 | rxn.pair_list.append(pair) 108 | rxnroot.reaction_list.append(rxn) 109 | rxnroot.write(test_filename) 110 | return test_filename 111 | 112 | def test_add_ghost_atom_to_pqr_from_atoms_center_of_mass(tmp_path): 113 | input_pqr_filename = \ 114 | os.path.join(os.path.dirname(__file__), 115 | "../data/hostguest_files/hostguest_ligand.pqr") 116 | atom_index_list = list(range(15)) 117 | output_pqr_filename = os.path.join(tmp_path, "test.pqr") 118 | ghost_index = sim_browndye2.add_ghost_atom_to_pqr_from_atoms_center_of_mass( 119 | input_pqr_filename, atom_index_list, output_pqr_filename) 120 | pqr_struct = parmed.load_file(output_pqr_filename, skip_bonds=True) 121 | ghost_atom = pqr_struct.atoms[ghost_index-1] 122 | assert(ghost_atom.name == "GHO") 123 | expected_ghost_location = np.array([[0.0, 0.0, 0.0]]) 124 | ghost_location = pqr_struct.coordinates[ghost_index-1] 125 | difference = np.linalg.norm(expected_ghost_location - ghost_location) 126 | assert(difference == 0.0) 127 | return 128 | 129 | def test_make_pqrxml(tmp_path): 130 | pqr_test_filename = os.path.join(TEST_DIRECTORY, "data/ligand_for_test.pqr") 131 | new_pqr_filename = os.path.join(tmp_path, "ligand_for_test.pqr") 132 | copyfile(pqr_test_filename, new_pqr_filename) 133 | xml_filename = sim_browndye2.make_pqrxml(new_pqr_filename) 134 | assert os.path.exists(xml_filename) 135 | 136 | def test_make_and_run_apbs(tmp_path): 137 | os.chdir(tmp_path) 138 | ligand_pqr_filename = \ 139 | os.path.join(os.path.dirname(__file__), 140 | "../data/hostguest_files/hostguest_ligand.pqr") 141 | receptor_pqr_filename = \ 142 | os.path.join(os.path.dirname(__file__), 143 | "../data/hostguest_files/hostguest_receptor.pqr") 144 | new_pqr_ligand = os.path.join(tmp_path, "ligand.pqr") 145 | new_pqr_receptor = os.path.join(tmp_path, "receptor.pqr") 146 | copyfile(ligand_pqr_filename, new_pqr_ligand) 147 | copyfile(receptor_pqr_filename, new_pqr_receptor) 148 | xml_ligand = sim_browndye2.make_pqrxml(new_pqr_ligand) 149 | xml_receptor = sim_browndye2.make_pqrxml(new_pqr_receptor) 150 | input_apbs_xml, root = make_test_browndye_input(tmp_path) 151 | debye_length = sim_browndye2.make_and_run_apbs(root, input_apbs_xml) 152 | assert float(debye_length) > 0.0 153 | 154 | def test_browndye_input_serializer_apbs_mode(tmp_path): 155 | test_filename, root = make_test_browndye_input(tmp_path) 156 | assert os.path.exists(test_filename) 157 | 158 | verify_xml_text(test_filename, "n_trajectories", "65535") 159 | verify_xml_text(test_filename, "n_threads", "3") 160 | verify_xml_text(test_filename, "seed", "4567") 161 | verify_xml_text(test_filename, "output", "test_output.xml") 162 | verify_xml_text(test_filename, "n_trajectories_per_output", "5") 163 | verify_xml_text(test_filename, "max_n_steps", "123456") 164 | verify_xml_text(test_filename, "trajectory_file", "test_traj") 165 | verify_xml_text(test_filename, "n_steps_per_output", "123") 166 | verify_xml_text(test_filename, "start_at_site", "true") 167 | verify_xml_text(test_filename, "reaction_file", "my_rxns.xml") 168 | verify_xml_text(test_filename, "hydrodynamic_interactions", "false") 169 | verify_xml_text(test_filename, "dielectric", "77.4") 170 | verify_xml_text(test_filename, "relative_viscosity", "0.4") 171 | verify_xml_text(test_filename, "kT", "1.456") 172 | verify_xml_text(test_filename, "desolvation_parameter", "0.8") 173 | verify_xml_text(test_filename, "radius", "1.34") 174 | verify_xml_text(test_filename, "charge", "-2.0") 175 | verify_xml_text(test_filename, "conc", "0.2") 176 | verify_xml_text(test_filename, "radius", "0.85") 177 | verify_xml_text(test_filename, "charge", "1.0") 178 | verify_xml_text(test_filename, "conc", "0.4") 179 | verify_xml_text(test_filename, "minimum_core_dt", "0.1") 180 | verify_xml_text(test_filename, "minimum_core_reaction_dt", "0.01") 181 | verify_xml_text(test_filename, "name", "receptor") 182 | verify_xml_text(test_filename, "atoms", "receptor.xml") 183 | verify_xml_text(test_filename, "all_in_surface", "true") 184 | verify_xml_text(test_filename, "is_protein", "true") 185 | verify_xml_text(test_filename, "dielectric", "5.0") 186 | verify_xml_text(test_filename, "grid_spacing", "0.75") 187 | verify_xml_text(test_filename, "name", "ligand") 188 | verify_xml_text(test_filename, "atoms", "ligand.xml") 189 | verify_xml_text(test_filename, "all_in_surface", "true") 190 | verify_xml_text(test_filename, "is_protein", "true") 191 | verify_xml_text(test_filename, "dielectric", "5.0") 192 | verify_xml_text(test_filename, "grid_spacing", "0.5") 193 | 194 | pytest.raises(Exception, verify_xml_text, test_filename, "gobblygook", "18") 195 | 196 | return 197 | 198 | def test_browndye_input_serializer_apbs_mode_rxn(tmp_path): 199 | test_filename = make_test_browndye_rxn(tmp_path) 200 | assert os.path.exists(test_filename) 201 | 202 | verify_xml_text(test_filename, "first_state", "something1") 203 | verify_xml_text(test_filename, "name", "test_rxn1") 204 | verify_xml_text(test_filename, "state_before", "something1") 205 | verify_xml_text(test_filename, "state_after", "something2") 206 | verify_xml_text(test_filename, "molecule0", "molec1 molec1") 207 | verify_xml_text(test_filename, "molecule1", "molec2 molec2") 208 | verify_xml_text(test_filename, "n_needed", "4") 209 | verify_xml_text(test_filename, "atoms", "5432 789") 210 | verify_xml_text(test_filename, "distance", "8.45") 211 | pytest.raises(Exception, verify_xml_text, test_filename, "gobblygook", "18") 212 | -------------------------------------------------------------------------------- /seekr2/tests/test_common_sim_openmm.py: -------------------------------------------------------------------------------- 1 | """ 2 | test_common_sim_openmm.py 3 | """ 4 | 5 | import os 6 | 7 | import pytest 8 | import numpy as np 9 | import mdtraj 10 | try: 11 | import openmm.unit as unit 12 | except ImportError: 13 | import simtk.openmm.unit as unit 14 | from seekr2.modules import common_sim_openmm 15 | 16 | def test_write_toy_pdb_file(toy_mmvt_model): 17 | anchor = toy_mmvt_model.anchors[1] 18 | out_file_name = os.path.join( 19 | toy_mmvt_model.anchor_rootdir, anchor.directory, 20 | anchor.building_directory, "toy.pdb") 21 | system, topology = common_sim_openmm.make_toy_system_object(toy_mmvt_model) 22 | positions = np.array([[3.0, 4.0, 5.0]]) * unit.nanometers 23 | common_sim_openmm.write_toy_pdb_file(topology, positions, out_file_name) 24 | assert os.path.exists(out_file_name) 25 | traj = mdtraj.load(out_file_name) 26 | assert traj.xyz[0,0,0] == 3.0 27 | assert traj.xyz[0,0,1] == 4.0 28 | assert traj.xyz[0,0,2] == 5.0 29 | return 30 | 31 | def test_make_toy_system_object(toy_mmvt_model): 32 | system, topology = common_sim_openmm.make_toy_system_object(toy_mmvt_model) 33 | force = system.getForce(0) 34 | assert force.getNumGroups() == 1 35 | assert force.getGlobalParameterName(0) == "k" 36 | return 37 | 38 | def test_create_openmm_system(toy_mmvt_model, host_guest_mmvt_model): 39 | my_sim_openmm = common_sim_openmm.Common_sim_openmm() 40 | anchor = toy_mmvt_model.anchors[0] 41 | system, topology, positions, box_vectors, num_frames \ 42 | = common_sim_openmm.create_openmm_system( 43 | my_sim_openmm, toy_mmvt_model, anchor, frame=0, load_state_file=None) 44 | assert num_frames == 2 45 | assert np.isclose(positions, np.array([[0.0, -0.7, 0.0]])\ 46 | *unit.nanometers).all() 47 | system2, topology2, positions2, box_vectors2, num_frames2 \ 48 | = common_sim_openmm.create_openmm_system( 49 | my_sim_openmm, toy_mmvt_model, anchor, frame=1, load_state_file=None) 50 | assert np.isclose(positions2, np.array([[0.3, -0.7, 0.0]])\ 51 | *unit.nanometers).all() 52 | 53 | anchor2 = host_guest_mmvt_model.anchors[0] 54 | system3, topology3, positions3, box_vectors3, num_frames3 \ 55 | = common_sim_openmm.create_openmm_system( 56 | my_sim_openmm, host_guest_mmvt_model, anchor2) 57 | 58 | 59 | def test_add_barostat(host_guest_mmvt_model_npt): 60 | my_sim_openmm = common_sim_openmm.Common_sim_openmm() 61 | anchor = host_guest_mmvt_model_npt.anchors[0] 62 | system, topology, positions, box_vectors, num_frames \ 63 | = common_sim_openmm.create_openmm_system( 64 | my_sim_openmm, host_guest_mmvt_model_npt, anchor, frame=0) 65 | forces = system.getForces() 66 | old_force_len = len(forces) 67 | common_sim_openmm.add_barostat(system, host_guest_mmvt_model_npt) 68 | forces2 = system.getForces() 69 | assert len(forces2) == old_force_len + 1 70 | barostat = forces2[-1] 71 | pressure = barostat.getDefaultPressure() 72 | assert pressure == 1.0 * unit.bar 73 | temperature = barostat.getDefaultTemperature() 74 | assert temperature == 298.15 * unit.kelvin 75 | 76 | def test_add_platform_ref(toy_mmvt_model): 77 | my_sim_openmm = common_sim_openmm.Common_sim_openmm() 78 | anchor = toy_mmvt_model.anchors[0] 79 | system, topology, positions, box_vectors, num_frames \ 80 | = common_sim_openmm.create_openmm_system( 81 | my_sim_openmm, toy_mmvt_model, anchor, frame=0) 82 | common_sim_openmm.add_platform(my_sim_openmm, toy_mmvt_model) 83 | assert my_sim_openmm.platform.getName() == "Reference" 84 | assert my_sim_openmm.properties == {} 85 | 86 | @pytest.mark.needs_cuda 87 | def test_add_platform_cuda(host_guest_mmvt_model): 88 | host_guest_mmvt_model.openmm_settings.cuda_platform_settings\ 89 | .cuda_device_index = "2" 90 | my_sim_openmm = common_sim_openmm.Common_sim_openmm() 91 | anchor = host_guest_mmvt_model.anchors[0] 92 | system, topology, positions, box_vectors, num_frames \ 93 | = common_sim_openmm.create_openmm_system( 94 | my_sim_openmm, host_guest_mmvt_model, anchor, frame=0) 95 | common_sim_openmm.add_platform(my_sim_openmm, host_guest_mmvt_model) 96 | assert my_sim_openmm.platform.getName() == "CUDA" 97 | assert my_sim_openmm.properties["CudaPrecision"] == "mixed" 98 | assert my_sim_openmm.properties["CudaDeviceIndex"] == "2" -------------------------------------------------------------------------------- /seekr2/tests/test_elber_analyze.py: -------------------------------------------------------------------------------- 1 | """ 2 | test_elber_analyze.py 3 | 4 | Testing elber_analyze.py 5 | """ 6 | 7 | import os 8 | 9 | import numpy as np 10 | import pytest 11 | from shutil import copyfile 12 | 13 | import seekr2.modules.common_base as base 14 | import seekr2.modules.elber_cvs.elber_cv_base as elber_cv_base 15 | import seekr2.modules.common_analyze as common_analyze 16 | import seekr2.modules.elber_analyze as elber_analyze 17 | from seekr2.tests.conftest import compare_dicts 18 | import seekr2.modules.markov_chain_monte_carlo as markov_chain_monte_carlo 19 | 20 | TEST_DIRECTORY = os.path.dirname(os.path.realpath(__file__)) 21 | 22 | test_output_filename = os.path.join(TEST_DIRECTORY, 23 | "data/test_analyze_output_elber.txt") 24 | 25 | def test_openmm_read_output_file_list(): 26 | N_i_j, R_i_total, lines = elber_analyze.openmm_read_output_file_list( 27 | [test_output_filename]) 28 | 29 | N_i_j_exp = {1: 3, 3: 5} 30 | R_i_exp = 1.324 31 | for key in N_i_j: 32 | assert key in N_i_j_exp 33 | assert np.isclose(N_i_j[key], N_i_j_exp[key]) 34 | 35 | assert np.isclose(R_i_total, R_i_exp) 36 | 37 | N_i_j, R_i_list, lines = elber_analyze.openmm_read_output_file_list( 38 | [test_output_filename], min_time=1) 39 | assert len(lines) == 10 40 | N_i_j, R_i_list, lines = elber_analyze.openmm_read_output_file_list( 41 | [test_output_filename], max_time=9) 42 | assert len(lines) == 10 43 | return 44 | 45 | def test_Elber_anchor_statistics_read_output_file_list(toy_elber_model): 46 | """ 47 | Test the read_output_file_list method of the MMVT_anchor_statistics 48 | object. 49 | """ 50 | stats = elber_analyze.Elber_anchor_statistics(1) 51 | engine = "openmm" 52 | output_file_list = [test_output_filename] 53 | min_time = None 54 | max_time = None 55 | stats.read_output_file_list(engine, output_file_list, min_time, 56 | max_time, None, None) 57 | 58 | N_i_j_exp = {1: 3, 3: 5} 59 | R_i_exp = 1.324 60 | for key in stats.N_i_j: 61 | assert key in N_i_j_exp 62 | assert np.isclose(stats.N_i_j[key], N_i_j_exp[key]) 63 | 64 | assert np.isclose(stats.R_i_total, R_i_exp) 65 | stats.print_stats() 66 | return 67 | 68 | def make_simple_model(): 69 | n_anchors = 3 70 | n_milestones = 3 71 | 72 | # generate data to feed directly into MMVT_data_sample() 73 | model = base.Model() 74 | model.calculation_type = "elber" 75 | model.num_milestones = n_milestones 76 | model.num_anchors = n_anchors 77 | anchor0 = elber_cv_base.Elber_toy_anchor() 78 | anchor0.index = 0 79 | anchor0.endstate = True 80 | milestone_0_0 = base.Milestone() 81 | milestone_0_0.index = 0 82 | milestone_0_0.neighbor_anchor_index = 0 83 | milestone_0_0.alias_index = 2 84 | milestone_0_1 = base.Milestone() 85 | milestone_0_1.index = 1 86 | milestone_0_1.neighbor_anchor_index = 1 87 | milestone_0_1.alias_index = 3 88 | anchor0.milestones = [milestone_0_0, milestone_0_1] 89 | 90 | anchor1 = elber_cv_base.Elber_toy_anchor() 91 | anchor1.index = 1 92 | milestone_1_0 = base.Milestone() 93 | milestone_1_0.index = 0 94 | milestone_1_0.neighbor_anchor_index = 0 95 | milestone_1_0.alias_index = 1 96 | milestone_1_1 = base.Milestone() 97 | milestone_1_1.index = 1 98 | milestone_1_1.neighbor_anchor_index = 1 99 | milestone_1_1.alias_index = 2 100 | milestone_1_2 = base.Milestone() 101 | milestone_1_2.index = 2 102 | milestone_1_2.neighbor_anchor_index = 2 103 | milestone_1_2.alias_index = 3 104 | anchor1.milestones = [milestone_1_0, milestone_1_1, milestone_1_2] 105 | 106 | anchor2 = elber_cv_base.Elber_toy_anchor() 107 | anchor2.index = 2 108 | milestone_2_0 = base.Milestone() 109 | milestone_2_0.index = 1 110 | milestone_2_0.neighbor_anchor_index = 1 111 | milestone_2_0.alias_index = 1 112 | milestone_2_1 = base.Milestone() 113 | milestone_2_1.index = 2 114 | milestone_2_1.neighbor_anchor_index = 2 115 | milestone_2_1.alias_index = 2 116 | 117 | anchor2.milestones = [milestone_2_0, milestone_2_1] 118 | anchor2.bulkstate = True 119 | model.anchors = [anchor0, anchor1, anchor2] 120 | return model 121 | 122 | def test_Elber_data_sample_fill_out_data_quantities(): 123 | model = make_simple_model() 124 | N_i_j_list = [{(0,1): 4}, {(1,0): 4, (1,2): 2}, {(2,1): 2}] 125 | R_i_list = [2.4, 2.4] 126 | N_i_j_exp = {(0,1): 4, (1,0): 4, (1,2): 2} 127 | data_sample = elber_analyze.Elber_data_sample(model, N_i_j_list, R_i_list) 128 | data_sample.fill_out_data_quantities() 129 | compare_dicts(N_i_j_exp, data_sample.N_ij) 130 | assert len(R_i_list) == len(data_sample.R_i) 131 | for item1, item2 in zip(R_i_list, data_sample.R_i): 132 | assert item1 == data_sample.R_i[item2] 133 | return 134 | 135 | def test_monte_carlo_milestoning_error(): 136 | model = make_simple_model() 137 | N_i_j_list = [{(0,1): 4}, {(1,0): 4, (1,2): 2}, {(2,1): 2, (2,3): 2}] 138 | R_i_list = [2.4, 2.4, 1.2] 139 | N_i_j_exp = {(0,1): 4, (1,0): 4, (1,2): 2, (2,1): 2} 140 | data_sample = elber_analyze.Elber_data_sample(model, N_i_j_list, R_i_list) 141 | data_sample.fill_out_data_quantities() 142 | data_sample.compute_rate_matrix() 143 | data_sample.calculate_thermodynamics() 144 | data_sample.calculate_kinetics() 145 | 146 | # Elber matrix sampler 147 | num = 1000 148 | stride = 10 149 | skip = 10 150 | n_milestones = 3 151 | n_anchors = 3 152 | data_sample_list, p_i_error, free_energy_profile_err, MFPTs_error, \ 153 | k_off_error, k_ons_error = elber_analyze.monte_carlo_milestoning_error( 154 | data_sample, num=num, stride=stride, skip=skip, verbose=True) 155 | 156 | result_q1_distribution = [] 157 | result_q2_distribution = [] 158 | for data_sample in data_sample_list: 159 | result_q1_distribution.append(data_sample.Q[0,1]) 160 | result_q2_distribution.append(data_sample.Q[1,0]) 161 | 162 | N_i_j = {(0,1): 4, (1,0): 4, (1,2): 2, (2,1): 2} 163 | R_i = {0: 2.4, 1: 2.4, 2: 1.2} 164 | elber_N = np.array([[0, 4, 0], 165 | [4, 0, 2], 166 | [0, 2, 0]]) 167 | elber_R = np.array([[2.4], 168 | [2.4], 169 | [1.2]]) 170 | 171 | elber_Q = np.zeros((n_milestones, n_milestones)) 172 | for i in range(n_milestones): 173 | for j in range(n_milestones): 174 | key = (i,j) 175 | if key in N_i_j: 176 | elber_Q[i,j] = N_i_j[key] / R_i[i] 177 | 178 | for i in range(n_milestones): 179 | elber_Q[i,i] = -np.sum(elber_Q[i,:]) 180 | 181 | # Elber matrix sampler 182 | elber_q1_distribution = [] 183 | elber_q2_distribution = [] 184 | for counter in range(num * (stride) + skip): 185 | #if verbose: print("MCMC stepnum: ", counter) 186 | elber_Qnew = markov_chain_monte_carlo\ 187 | .irreversible_stochastic_matrix_algorithm_sample( 188 | elber_Q, elber_N, elber_R) 189 | if counter > skip and counter % stride == 0: 190 | elber_q1_distribution.append(elber_Q[0,1]) 191 | elber_q2_distribution.append(elber_Q[1,0]) 192 | 193 | elber_Q = elber_Qnew 194 | 195 | assert np.isclose(np.mean(elber_q1_distribution), 196 | np.mean(result_q1_distribution), rtol=0.5, atol=0.01) 197 | assert np.isclose(np.std(elber_q1_distribution), 198 | np.std(result_q1_distribution), rtol=0.5, atol=0.01) 199 | assert np.isclose(np.mean(elber_q2_distribution), 200 | np.mean(result_q2_distribution), rtol=0.5, atol=0.01) 201 | assert np.isclose(np.std(elber_q2_distribution), 202 | np.std(result_q2_distribution), rtol=0.5, atol=0.01) 203 | return -------------------------------------------------------------------------------- /seekr2/tests/test_elber_cv_base.py: -------------------------------------------------------------------------------- 1 | """ 2 | test_elber_cv_base.py 3 | 4 | Testing elber base objects 5 | """ 6 | 7 | def test_create_elber_model_input(host_guest_elber_model_input_persistent): 8 | """ 9 | Just create the model input to see if it can be done without errors 10 | """ 11 | assert host_guest_elber_model_input_persistent.calculation_type == "elber" 12 | return 13 | 14 | def test_create_elber_model(host_guest_elber_model): 15 | """ 16 | Create the model based on the model input to ensure that it works 17 | without errors. 18 | """ 19 | assert host_guest_elber_model.calculation_type == "elber" 20 | return -------------------------------------------------------------------------------- /seekr2/tests/test_elber_external_cv.py: -------------------------------------------------------------------------------- 1 | """ 2 | test_elber_external_cv.py 3 | """ 4 | 5 | try: 6 | import openmm.unit as unit 7 | except ImportError: 8 | import simtk.unit as unit 9 | 10 | import seekr2.modules.common_sim_openmm as common_sim_openmm 11 | import seekr2.modules.elber_cvs.elber_external_cv as elber_external_cv 12 | import seekr2.tests.create_toy_system as create_toy_system 13 | 14 | def test_elber_external_boundary(tmp_path): 15 | # Set initial variables 16 | milestone_variables = {"k":-1.0, "value":0.5} 17 | my_variables = [-1.0, 0.5] 18 | positions1 = [[0.7, 0.0, 0.0], [0.7, 0.4, 0.0]] 19 | 20 | # Initialize the toy system with boundary force 21 | toy_system, toy_topology = create_toy_system.make_toy_system_and_topology(2) 22 | my_cv = elber_external_cv.Elber_external_CV(index=0, groups=[[0],[1]]) 23 | my_cv.openmm_fwd_rev_expression = "step(k*(x1 - value))" 24 | boundary_force1 = my_cv.make_fwd_rev_force_object() 25 | boundary_force1.setForceGroup(1) 26 | my_cv.add_fwd_rev_parameters(boundary_force1) 27 | my_cv.add_groups_and_variables( 28 | force=boundary_force1, group_list=[0,1], variables=my_variables) 29 | toy_system.addForce(boundary_force1) 30 | toy_simulation = create_toy_system.make_toy_simulation_and_context( 31 | toy_system, toy_topology, positions1) 32 | 33 | # Check that the particle is within the boundary 34 | toy_state = toy_simulation.context.getState(getEnergy=True, groups={1}) 35 | boundary_val1 = toy_state.getPotentialEnergy() 36 | assert boundary_val1.value_in_unit(unit.kilojoules/unit.mole) == 0.0 37 | 38 | # Move the particle outside the boundary 39 | positions2 = [[0.4, 0.0, 0.0], [0.4, 0.4, 0.0]] 40 | toy_simulation.context.setPositions(positions2) 41 | 42 | # Check that the particle is outside the boundary 43 | toy_state = toy_simulation.context.getState(getEnergy=True, groups={1}) 44 | boundary_val2 = toy_state.getPotentialEnergy() 45 | assert boundary_val2.value_in_unit(unit.kilojoules/unit.mole) == 1.0 46 | -------------------------------------------------------------------------------- /seekr2/tests/test_elber_sim_openmm.py: -------------------------------------------------------------------------------- 1 | """ 2 | test_elber_sim_openmm.py 3 | """ 4 | 5 | import pytest 6 | import os 7 | 8 | try: 9 | import openmm.unit as unit 10 | except ImportError: 11 | import simtk.openmm.unit as unit 12 | 13 | from seekr2.modules import elber_sim_openmm 14 | 15 | def test_add_integrators(toy_elber_model): 16 | my_sim_openmm = elber_sim_openmm.Elber_sim_openmm() 17 | state_prefix = "test_state_prefix" 18 | elber_sim_openmm.add_integrators(my_sim_openmm, toy_elber_model, 19 | state_prefix=state_prefix) 20 | assert my_sim_openmm.umbrella_integrator.getStepSize() \ 21 | == toy_elber_model.get_timestep() * unit.picoseconds 22 | assert my_sim_openmm.umbrella_integrator.getTemperature() \ 23 | == toy_elber_model.temperature * unit.kelvin 24 | assert my_sim_openmm.umbrella_integrator.getFriction() \ 25 | == toy_elber_model.openmm_settings.langevin_integrator\ 26 | .friction_coefficient / unit.picoseconds 27 | assert my_sim_openmm.umbrella_integrator.getRandomNumberSeed() \ 28 | == toy_elber_model.openmm_settings.langevin_integrator.random_seed 29 | 30 | assert my_sim_openmm.rev_integrator.getOutputFileName() \ 31 | == my_sim_openmm.rev_output_filename 32 | 33 | assert my_sim_openmm.fwd_integrator.getOutputFileName() \ 34 | == my_sim_openmm.fwd_output_filename 35 | assert my_sim_openmm.fwd_integrator.getSaveStateFileName() \ 36 | == state_prefix 37 | return 38 | 39 | def test_add_forces(tmp_path, toy_elber_model): 40 | anchor = toy_elber_model.anchors[1] 41 | output_file = os.path.join(tmp_path, "output.txt") 42 | my_sim_openmm = elber_sim_openmm.create_sim_openmm( 43 | toy_elber_model, anchor, output_file) 44 | umbrella_forces = my_sim_openmm.umbrella_system.getForces() 45 | old_force_len_umbrella = len(umbrella_forces) 46 | rev_forces = my_sim_openmm.rev_system.getForces() 47 | old_force_len_rev = len(rev_forces) 48 | fwd_forces = my_sim_openmm.fwd_system.getForces() 49 | old_force_len_fwd = len(fwd_forces) 50 | assert my_sim_openmm.rev_integrator.getNumSrcMilestoneGroups() \ 51 | == 1 52 | assert my_sim_openmm.rev_integrator.getNumDestMilestoneGroups() \ 53 | == len(anchor.milestones)-1 54 | assert my_sim_openmm.fwd_integrator.getNumSrcMilestoneGroups() \ 55 | == 1 56 | assert my_sim_openmm.fwd_integrator.getNumDestMilestoneGroups() \ 57 | == len(anchor.milestones)-1 58 | elber_sim_openmm.add_forces(my_sim_openmm, toy_elber_model, anchor) 59 | 60 | umbrella_forces2 = my_sim_openmm.umbrella_system.getForces() 61 | assert len(umbrella_forces2) == old_force_len_umbrella + 1 62 | rev_forces2 = my_sim_openmm.rev_system.getForces() 63 | assert len(rev_forces2) == old_force_len_rev + len(anchor.milestones) 64 | fwd_forces2 = my_sim_openmm.fwd_system.getForces() 65 | assert len(fwd_forces2) == old_force_len_fwd + len(anchor.milestones) 66 | return 67 | 68 | def test_add_simulation(tmp_path, toy_elber_model): 69 | anchor = toy_elber_model.anchors[0] 70 | output_file = os.path.join(tmp_path, "output.txt") 71 | my_sim_openmm = elber_sim_openmm.create_sim_openmm( 72 | toy_elber_model, anchor, output_file) 73 | assert my_sim_openmm.umbrella_simulation is not None 74 | assert my_sim_openmm.rev_simulation is not None 75 | assert my_sim_openmm.fwd_simulation is not None 76 | 77 | def test_elber_sim_openmm_toy(tmp_path, toy_elber_model): 78 | myanchor = toy_elber_model.anchors[1] 79 | toy_elber_model.openmm_settings.cuda_platform_settings = None 80 | toy_elber_model.openmm_settings.reference_platform = True 81 | output_file = os.path.join(tmp_path, "output.txt") 82 | my_sim_openmm = elber_sim_openmm.create_sim_openmm( 83 | toy_elber_model, myanchor, output_file) 84 | return 85 | 86 | def test_elber_sim_openmm_amber(tmp_path, host_guest_elber_model): 87 | myanchor = host_guest_elber_model.anchors[1] 88 | host_guest_elber_model.openmm_settings.cuda_platform_settings = None 89 | host_guest_elber_model.openmm_settings.reference_platform = True 90 | output_file = os.path.join(tmp_path, "output.txt") 91 | my_sim_openmm = elber_sim_openmm.create_sim_openmm( 92 | host_guest_elber_model, myanchor, output_file) 93 | return 94 | 95 | @pytest.mark.skip 96 | def test_elber_sim_openmm_forcefield(tmp_path, host_guest_elber_model): 97 | # TODO: un-skip this test if forcefield inputs ever become widely-used 98 | myanchor = host_guest_elber_model.anchors[1] 99 | host_guest_elber_model.openmm_settings.cuda_platform_settings = None 100 | host_guest_elber_model.openmm_settings.reference_platform = True 101 | output_file = os.path.join(tmp_path, "output.txt") 102 | my_sim_openmm = elber_sim_openmm.create_sim_openmm( 103 | host_guest_elber_model, myanchor, output_file) 104 | return 105 | 106 | def test_make_elber_umbrella_force(toy_elber_model): 107 | myanchor = toy_elber_model.anchors[1] 108 | mymilestone = myanchor.milestones[1] 109 | cv_index = mymilestone.cv_index 110 | mycv = toy_elber_model.collective_variables[cv_index] 111 | myforce = elber_sim_openmm.make_elber_umbrella_force( 112 | toy_elber_model, myanchor) 113 | assert myforce.getPerBondParameterName(0) == "k" 114 | assert myforce.getPerBondParameterName(1) == "value" 115 | return 116 | 117 | def test_make_elber_boundary_definitions(toy_elber_model): 118 | myanchor = toy_elber_model.anchors[1] 119 | mymilestone = myanchor.milestones[1] 120 | cv_index = mymilestone.cv_index 121 | mycv = toy_elber_model.collective_variables[cv_index] 122 | myforce = elber_sim_openmm.make_elber_boundary_definitions( 123 | mycv, mymilestone) 124 | assert myforce.getPerBondParameterName(0) == "k" 125 | assert myforce.getPerBondParameterName(1) == "value" 126 | return 127 | -------------------------------------------------------------------------------- /seekr2/tests/test_elber_spherical_cv.py: -------------------------------------------------------------------------------- 1 | """ 2 | test_elber_spherical_cv.py 3 | """ 4 | 5 | try: 6 | import openmm.unit as unit 7 | except ImportError: 8 | import simtk.unit as unit 9 | 10 | import seekr2.modules.common_sim_openmm as common_sim_openmm 11 | import seekr2.modules.elber_cvs.elber_spherical_cv as elber_spherical_cv 12 | import seekr2.tests.create_toy_system as create_toy_system 13 | 14 | def test_elber_spherical_boundary(tmp_path): 15 | # Set initial variables 16 | milestone_variables = {"k":-1.0, "radius":0.3} 17 | my_variables = [-1.0, 0.3] 18 | positions1 = [[0.0, 0.0, 0.0], [0.3, 0.4, 0.0]] 19 | 20 | # Initialize the toy system with boundary force 21 | toy_system, toy_topology = create_toy_system.make_toy_system_and_topology(2) 22 | my_cv = elber_spherical_cv.Elber_spherical_CV(index=0, groups=[[0],[1]]) 23 | 24 | boundary_force1 = my_cv.make_fwd_rev_force_object() 25 | boundary_force1.setForceGroup(1) 26 | my_cv.add_fwd_rev_parameters(boundary_force1) 27 | my_cv.add_groups_and_variables( 28 | force=boundary_force1, group_list=[0,1], variables=my_variables) 29 | toy_system.addForce(boundary_force1) 30 | toy_simulation = create_toy_system.make_toy_simulation_and_context( 31 | toy_system, toy_topology, positions1) 32 | 33 | # Check that the particle is within the boundary 34 | toy_state = toy_simulation.context.getState(getEnergy=True, groups={1}) 35 | boundary_val1 = toy_state.getPotentialEnergy() 36 | assert boundary_val1.value_in_unit(unit.kilojoules/unit.mole) == 0.0 37 | 38 | # Move the particle outside the boundary 39 | positions2 = [[0.0, 0.0, 0.0], [0.1, 0.1, 0.0]] 40 | toy_simulation.context.setPositions(positions2) 41 | 42 | # Check that the particle is outside the boundary 43 | toy_state = toy_simulation.context.getState(getEnergy=True, groups={1}) 44 | boundary_val2 = toy_state.getPotentialEnergy() 45 | assert boundary_val2.value_in_unit(unit.kilojoules/unit.mole) == 1.0 46 | -------------------------------------------------------------------------------- /seekr2/tests/test_mmvt_closest_pair_cv.py: -------------------------------------------------------------------------------- 1 | """ 2 | test_mmvt_closest_pair_cv.py 3 | """ 4 | 5 | import os 6 | import shutil 7 | 8 | import numpy as np 9 | 10 | try: 11 | import openmm.unit as unit 12 | except ImportError: 13 | import simtk.unit as unit 14 | 15 | try: 16 | import openmm 17 | except ImportError: 18 | import simtk.openmm as openmm 19 | 20 | try: 21 | import openmm.app as openmm_app 22 | except ImportError: 23 | import simtk.openmm.app as openmm_app 24 | 25 | import mdtraj 26 | 27 | import seekr2.modules.common_base as base 28 | import seekr2.modules.common_sim_openmm as common_sim_openmm 29 | import seekr2.modules.mmvt_cvs.mmvt_closest_pair_cv as mmvt_closest_pair_cv 30 | import seekr2.tests.create_toy_system as create_toy_system 31 | 32 | 33 | def test_mmvt_closest_pair_boundary(tmp_path): 34 | # Set initial variables 35 | milestone_variables = {"k":-1.0, "value":0.1, "exponent":50.0} 36 | my_variables = [1.0, -1.0, 0.1, 50.0] 37 | positions1 = [[0.0, 0.0, 0.0], [0.1, 0.0, 0.1], 38 | [0.3, 0.0, 0.1], [0.4, 0.0, 0.0]] 39 | 40 | # Initialize the toy system with boundary force 41 | toy_system, toy_topology = create_toy_system.make_toy_system_and_topology(4) 42 | my_cv = mmvt_closest_pair_cv.MMVT_closest_pair_CV( 43 | index=0, groups=[[0,1],[2,3]]) 44 | 45 | box_vectors = base.Box_vectors() 46 | 47 | box_vectors.from_quantity(np.array( 48 | [[5.0, 0.0, 0.0], [0.0, 5.0, 0.0], [0.0, 0.0, 5.0]]) \ 49 | * unit.nanometers) 50 | 51 | toy_system.setDefaultPeriodicBoxVectors(*box_vectors.to_quantity()) 52 | toy_topology.setPeriodicBoxVectors(box_vectors.to_quantity()) 53 | 54 | create_toy_system.assign_nonbonded_cv_info(my_cv, toy_system, box_vectors) 55 | 56 | boundary_force1 = my_cv.make_boundary_force(alias_id=1) 57 | boundary_force1.setForceGroup(1) 58 | my_cv.add_parameters(boundary_force1) 59 | my_cv.add_groups_and_variables( 60 | force=boundary_force1, variables=my_variables, alias_id=1) 61 | toy_system.addForce(boundary_force1) 62 | toy_simulation = create_toy_system.make_toy_simulation_and_context( 63 | toy_system, toy_topology, positions1) 64 | 65 | # Check that the particle is within the boundary 66 | toy_state = toy_simulation.context.getState(getEnergy=True, groups={1}) 67 | boundary_val1 = toy_state.getPotentialEnergy() 68 | assert boundary_val1.value_in_unit(unit.kilojoules/unit.mole) == 0.0 69 | 70 | # Ensure that check_mdtraj_within_boundary works for this cv 71 | pdb_filename1 = os.path.join(tmp_path, "closest_mmvt_toy1.pdb") 72 | common_sim_openmm.write_toy_pdb_file(toy_topology, positions1, pdb_filename1) 73 | pdbtraj1 = mdtraj.load(pdb_filename1) 74 | assert my_cv.check_mdtraj_within_boundary( 75 | pdbtraj1, milestone_variables, verbose=False, TOL=0.0) 76 | 77 | # Ensure that check_openmm_context_within_boundary works for this cv 78 | assert my_cv.check_openmm_context_within_boundary( 79 | toy_simulation.context, milestone_variables) 80 | 81 | # Move the particle outside the boundary 82 | positions2 = [[0.0, 0.0, 0.0], [0.1, 0.0, 0.1], 83 | [0.15, 0.0, 0.1], [0.25, 0.0, 0.0]] 84 | toy_simulation.context.setPositions(positions2) 85 | 86 | # Check that the particle is outside the boundary 87 | toy_state = toy_simulation.context.getState(getEnergy=True, groups={1}) 88 | boundary_val2 = toy_state.getPotentialEnergy() 89 | assert boundary_val2.value_in_unit(unit.kilojoules/unit.mole) == 1.0 90 | 91 | # Move the boundary to inside the interparticle distance 92 | milestone_variables = {"k":-1.0, "value":0.01, "exponent":50.0} 93 | new_variables = [1.0, -1.0, 0.01, 50.0] 94 | 95 | my_cv.update_groups_and_variables( 96 | force=boundary_force1, variables=new_variables, alias_id=1, 97 | context=toy_simulation.context) 98 | toy_simulation.context.reinitialize(preserveState=True) 99 | 100 | # Check that the particle is within the new boundary 101 | toy_state = toy_simulation.context.getState(getEnergy=True, groups={1}) 102 | boundary_val3 = toy_state.getPotentialEnergy() 103 | assert boundary_val3.value_in_unit(unit.kilojoules/unit.mole) == 0.0 104 | 105 | # Ensure that check_mdtraj_within_boundary still works 106 | pdb_filename2 = os.path.join(tmp_path, "closest_mmvt_toy2.pdb") 107 | common_sim_openmm.write_toy_pdb_file(toy_topology, positions2, pdb_filename2) 108 | pdbtraj2 = mdtraj.load(pdb_filename2) 109 | assert my_cv.check_mdtraj_within_boundary( 110 | pdbtraj2, milestone_variables, verbose=False, TOL=0.0) 111 | 112 | # Ensure that check_openmm_context_within_boundary still works 113 | assert my_cv.check_openmm_context_within_boundary( 114 | toy_simulation.context, milestone_variables) 115 | 116 | return 117 | 118 | def test_mmvt_count_contacts_voronoi_boundary(): 119 | # Set initial variables 120 | me_val = 0.2 121 | neighbor_val = 0.4 122 | positions1 = [[0.0, 0.0, 0.0], [0.1, 0.0, 0.1], 123 | [0.3, 0.0, 0.1], [0.4, 0.0, 0.0]] 124 | toy_system, toy_topology = create_toy_system.make_toy_system_and_topology(4) 125 | # Initialize the toy system with boundary force 126 | box_vectors = base.Box_vectors() 127 | box_vectors.from_quantity(np.array( 128 | [[5.0, 0.0, 0.0], [0.0, 5.0, 0.0], [0.0, 0.0, 5.0]]) \ 129 | * unit.nanometers) 130 | toy_system.setDefaultPeriodicBoxVectors(*box_vectors.to_quantity()) 131 | toy_topology.setPeriodicBoxVectors(box_vectors.to_quantity()) 132 | my_cv = mmvt_closest_pair_cv.MMVT_closest_pair_CV( 133 | index=0, groups=[[0,1],[2,3]]) 134 | 135 | create_toy_system.assign_nonbonded_cv_info(my_cv, toy_system, box_vectors) 136 | 137 | me_force, neighbor_force = my_cv.make_voronoi_cv_boundary_forces( 138 | me_val, neighbor_val, 1) 139 | me_force.setForceGroup(1) 140 | neighbor_force.setForceGroup(2) 141 | toy_system.addForce(me_force) 142 | toy_system.addForce(neighbor_force) 143 | toy_simulation = create_toy_system.make_toy_simulation_and_context( 144 | toy_system, toy_topology, positions1) 145 | 146 | # Test if the Voronoi boundary returns the correct number 147 | toy_state_me = toy_simulation.context.getState(getEnergy=True, groups={1}) 148 | toy_state_neighbor = toy_simulation.context.getState(getEnergy=True, groups={2}) 149 | boundary_val_me = toy_state_me.getPotentialEnergy() 150 | boundary_val_neighbor = toy_state_neighbor.getPotentialEnergy() 151 | assert np.isclose(boundary_val_me.value_in_unit(unit.kilojoules/unit.mole), 0.0) 152 | assert not np.isclose(boundary_val_neighbor.value_in_unit(unit.kilojoules/unit.mole), 0.0) 153 | 154 | # Move the particle outside the boundary and test Voronoi again 155 | positions2 = [[0.0, 0.0, 0.0], [0.1, 0.0, 0.1], 156 | [0.5, 0.0, 0.1], [0.6, 0.0, 0.0]] 157 | toy_simulation.context.setPositions(positions2) 158 | toy_state_me = toy_simulation.context.getState(getEnergy=True, groups={1}) 159 | toy_state_neighbor = toy_simulation.context.getState(getEnergy=True, groups={2}) 160 | boundary_val_me = toy_state_me.getPotentialEnergy() 161 | boundary_val_neighbor = toy_state_neighbor.getPotentialEnergy() 162 | assert not np.isclose(boundary_val_me.value_in_unit(unit.kilojoules/unit.mole), 0.0) 163 | assert np.isclose(boundary_val_neighbor.value_in_unit(unit.kilojoules/unit.mole), 0.0) 164 | 165 | # Move the boundary inside the particle and test 166 | new_me_val = 0.4 167 | new_neighbor_val = 0.6 168 | my_cv.update_voronoi_cv_boundary_forces( 169 | me_force, new_me_val, neighbor_force, new_neighbor_val, 1, 170 | toy_simulation.context) 171 | toy_simulation.context.reinitialize(preserveState=True) 172 | toy_state_me = toy_simulation.context.getState(getEnergy=True, groups={1}) 173 | toy_state_neighbor = toy_simulation.context.getState(getEnergy=True, groups={2}) 174 | boundary_val_me = toy_state_me.getPotentialEnergy() 175 | boundary_val_neighbor = toy_state_neighbor.getPotentialEnergy() 176 | assert np.isclose(boundary_val_me.value_in_unit(unit.kilojoules/unit.mole), 0.0) 177 | assert not np.isclose(boundary_val_neighbor.value_in_unit(unit.kilojoules/unit.mole), 0.0) 178 | 179 | return 180 | -------------------------------------------------------------------------------- /seekr2/tests/test_mmvt_count_contacts_cv.py: -------------------------------------------------------------------------------- 1 | """ 2 | test_mmvt_count_contacts_cv.py 3 | """ 4 | 5 | import os 6 | import shutil 7 | 8 | import numpy as np 9 | 10 | try: 11 | import openmm.unit as unit 12 | except ImportError: 13 | import simtk.unit as unit 14 | 15 | try: 16 | import openmm 17 | except ImportError: 18 | import simtk.openmm as openmm 19 | 20 | try: 21 | import openmm.app as openmm_app 22 | except ImportError: 23 | import simtk.openmm.app as openmm_app 24 | 25 | import mdtraj 26 | 27 | import seekr2.modules.common_base as base 28 | import seekr2.modules.common_sim_openmm as common_sim_openmm 29 | import seekr2.modules.mmvt_cvs.mmvt_count_contacts_cv as mmvt_count_contacts_cv 30 | import seekr2.tests.create_toy_system as create_toy_system 31 | 32 | 33 | def test_mmvt_count_contacts_boundary(tmp_path): 34 | # Set initial variables 35 | cutoff = 0.2 36 | milestone_variables = {"k":-1.0, "value":1} 37 | my_variables = [1.0, -1.0, 1] 38 | positions1 = [[0.0, 0.0, 0.0], [0.1, 0.0, 0.0], 39 | [0.0, 0.0, 0.1], [0.4, 0.0, 0.0]] 40 | 41 | # Initialize the toy system with boundary force 42 | toy_system, toy_topology = create_toy_system.make_toy_system_and_topology(4) 43 | my_cv = mmvt_count_contacts_cv.MMVT_count_contacts_CV( 44 | index=0, groups=[[0],[1,2,3]]) 45 | 46 | box_vectors = base.Box_vectors() 47 | 48 | box_vectors.from_quantity(np.array( 49 | [[5.0, 0.0, 0.0], [0.0, 5.0, 0.0], [0.0, 0.0, 5.0]]) \ 50 | * unit.nanometers) 51 | 52 | toy_system.setDefaultPeriodicBoxVectors(*box_vectors.to_quantity()) 53 | toy_topology.setPeriodicBoxVectors(box_vectors.to_quantity()) 54 | 55 | create_toy_system.assign_nonbonded_cv_info(my_cv, toy_system, box_vectors, 56 | cutoff=cutoff) 57 | 58 | boundary_force1 = my_cv.make_boundary_force(alias_id=1) 59 | boundary_force1.setForceGroup(1) 60 | my_cv.add_parameters(boundary_force1) 61 | my_cv.add_groups_and_variables( 62 | force=boundary_force1, variables=my_variables, alias_id=1) 63 | toy_system.addForce(boundary_force1) 64 | toy_simulation = create_toy_system.make_toy_simulation_and_context( 65 | toy_system, toy_topology, positions1) 66 | 67 | # Check that the particle is within the boundary 68 | toy_state = toy_simulation.context.getState(getEnergy=True, groups={1}) 69 | boundary_val1 = toy_state.getPotentialEnergy() 70 | assert boundary_val1.value_in_unit(unit.kilojoules/unit.mole) == 0.0 71 | 72 | # Ensure that check_mdtraj_within_boundary works for this cv 73 | pdb_filename1 = os.path.join(tmp_path, "count_mmvt_toy1.pdb") 74 | common_sim_openmm.write_toy_pdb_file(toy_topology, positions1, pdb_filename1) 75 | pdbtraj1 = mdtraj.load(pdb_filename1) 76 | assert my_cv.check_mdtraj_within_boundary( 77 | pdbtraj1, milestone_variables, verbose=False, TOL=0.0) 78 | 79 | # Ensure that check_openmm_context_within_boundary works for this cv 80 | assert my_cv.check_openmm_context_within_boundary( 81 | toy_simulation.context, milestone_variables) 82 | 83 | # Move the particle outside the boundary 84 | positions2 = [[0.0, 0.0, 0.0], [0.8, 0.0, 0.0], 85 | [0.0, 0.0, 0.8], [0.9, 0.0, 0.0]] 86 | toy_simulation.context.setPositions(positions2) 87 | 88 | # Check that the particle is outside the boundary 89 | toy_state = toy_simulation.context.getState(getEnergy=True, groups={1}) 90 | boundary_val2 = toy_state.getPotentialEnergy() 91 | assert boundary_val2.value_in_unit(unit.kilojoules/unit.mole) == 1.0 92 | 93 | # Move the boundary to inside the interparticle distance 94 | milestone_variables = {"k":1.0, "value":1} 95 | new_variables = [1.0, 1.0, 1] 96 | 97 | my_cv.update_groups_and_variables( 98 | force=boundary_force1, variables=new_variables, alias_id=1, 99 | context=toy_simulation.context) 100 | toy_simulation.context.reinitialize(preserveState=True) 101 | 102 | # Check that the particle is within the new boundary 103 | toy_state = toy_simulation.context.getState(getEnergy=True, groups={1}) 104 | boundary_val3 = toy_state.getPotentialEnergy() 105 | assert boundary_val3.value_in_unit(unit.kilojoules/unit.mole) == 0.0 106 | 107 | # Ensure that check_mdtraj_within_boundary still works 108 | pdb_filename2 = os.path.join(tmp_path, "count_mmvt_toy2.pdb") 109 | common_sim_openmm.write_toy_pdb_file(toy_topology, positions2, pdb_filename2) 110 | pdbtraj2 = mdtraj.load(pdb_filename2) 111 | assert my_cv.check_mdtraj_within_boundary( 112 | pdbtraj2, milestone_variables, verbose=False, TOL=0.0) 113 | 114 | # Ensure that check_openmm_context_within_boundary still works 115 | assert my_cv.check_openmm_context_within_boundary( 116 | toy_simulation.context, milestone_variables) 117 | 118 | return 119 | 120 | def test_mmvt_count_contacts_voronoi_boundary(): 121 | # Set initial variables 122 | me_val = 2 123 | neighbor_val = 3 124 | cutoff = 0.2 125 | positions1 = [[0.0, 0.0, 0.0], [0.1, 0.0, 0.0], 126 | [0.0, 0.0, 0.1], [0.4, 0.0, 0.0]] 127 | toy_system, toy_topology = create_toy_system.make_toy_system_and_topology(4) 128 | # Initialize the toy system with boundary force 129 | box_vectors = base.Box_vectors() 130 | box_vectors.from_quantity(np.array( 131 | [[5.0, 0.0, 0.0], [0.0, 5.0, 0.0], [0.0, 0.0, 5.0]]) \ 132 | * unit.nanometers) 133 | toy_system.setDefaultPeriodicBoxVectors(*box_vectors.to_quantity()) 134 | toy_topology.setPeriodicBoxVectors(box_vectors.to_quantity()) 135 | my_cv = mmvt_count_contacts_cv.MMVT_count_contacts_CV( 136 | index=0, groups=[[0],[1,2,3]]) 137 | 138 | create_toy_system.assign_nonbonded_cv_info(my_cv, toy_system, box_vectors, 139 | cutoff=cutoff) 140 | 141 | me_force, neighbor_force = my_cv.make_voronoi_cv_boundary_forces( 142 | me_val, neighbor_val, 1) 143 | me_force.setForceGroup(1) 144 | neighbor_force.setForceGroup(2) 145 | toy_system.addForce(me_force) 146 | toy_system.addForce(neighbor_force) 147 | toy_simulation = create_toy_system.make_toy_simulation_and_context( 148 | toy_system, toy_topology, positions1) 149 | 150 | # Test if the Voronoi boundary returns the correct number 151 | toy_state_me = toy_simulation.context.getState(getEnergy=True, groups={1}) 152 | toy_state_neighbor = toy_simulation.context.getState(getEnergy=True, groups={2}) 153 | boundary_val_me = toy_state_me.getPotentialEnergy() 154 | boundary_val_neighbor = toy_state_neighbor.getPotentialEnergy() 155 | assert np.isclose(boundary_val_me.value_in_unit(unit.kilojoules/unit.mole), 0.0) 156 | assert not np.isclose(boundary_val_neighbor.value_in_unit(unit.kilojoules/unit.mole), 0.0) 157 | 158 | # Move the particle outside the boundary and test Voronoi again 159 | positions2 = [[0.0, 0.0, 0.0], [0.1, 0.0, 0.0], 160 | [0.0, 0.0, 0.1], [0.0, 0.1, 0.0]] 161 | toy_simulation.context.setPositions(positions2) 162 | toy_state_me = toy_simulation.context.getState(getEnergy=True, groups={1}) 163 | toy_state_neighbor = toy_simulation.context.getState(getEnergy=True, groups={2}) 164 | boundary_val_me = toy_state_me.getPotentialEnergy() 165 | boundary_val_neighbor = toy_state_neighbor.getPotentialEnergy() 166 | assert not np.isclose(boundary_val_me.value_in_unit(unit.kilojoules/unit.mole), 0.0) 167 | assert np.isclose(boundary_val_neighbor.value_in_unit(unit.kilojoules/unit.mole), 0.0) 168 | 169 | # Move the boundary inside the particle and test 170 | new_me_val = 3 171 | new_neighbor_val = 4 172 | my_cv.update_voronoi_cv_boundary_forces( 173 | me_force, new_me_val, neighbor_force, new_neighbor_val, 1, 174 | toy_simulation.context) 175 | toy_simulation.context.reinitialize(preserveState=True) 176 | toy_state_me = toy_simulation.context.getState(getEnergy=True, groups={1}) 177 | toy_state_neighbor = toy_simulation.context.getState(getEnergy=True, groups={2}) 178 | boundary_val_me = toy_state_me.getPotentialEnergy() 179 | boundary_val_neighbor = toy_state_neighbor.getPotentialEnergy() 180 | assert np.isclose(boundary_val_me.value_in_unit(unit.kilojoules/unit.mole), 0.0) 181 | assert not np.isclose(boundary_val_neighbor.value_in_unit(unit.kilojoules/unit.mole), 0.0) 182 | 183 | return 184 | -------------------------------------------------------------------------------- /seekr2/tests/test_mmvt_cv.py: -------------------------------------------------------------------------------- 1 | """ 2 | Test the mmvt_cv.py module 3 | """ 4 | 5 | import numpy as np 6 | 7 | import seekr2.modules.common_cv as common_cv 8 | import seekr2.modules.check as check 9 | 10 | # TODO: move tests to appropriate file and remove this test file 11 | 12 | def test_tiwary_input_and_model(tiwary_mmvt_model_input, tiwary_mmvt_model): 13 | """ 14 | 15 | """ 16 | assert len(tiwary_mmvt_model_input.cv_inputs[0].order_parameters) == 3 17 | check.check_pre_simulation_all(tiwary_mmvt_model) 18 | return 19 | 20 | def test_distance_order_parameter_get_value(): 21 | """ 22 | 23 | """ 24 | op = common_cv.Tiwary_cv_distance_order_parameter() 25 | com1 = np.array([1.0, 1.0, 1.0]) 26 | com2 = np.array([4.0, 5.0, 1.0]) 27 | expected_dist = 5.0 28 | dist = op.get_value([com1, com2]) 29 | assert np.isclose(dist, expected_dist) 30 | return 31 | 32 | def test_angle_order_parameter_get_value(): 33 | """ 34 | 35 | """ 36 | op = common_cv.Tiwary_cv_angle_order_parameter() 37 | com1 = np.array([1.0, 0.0, 0.0]) 38 | com2 = np.array([0.0, 0.0, 0.0]) 39 | com3 = np.array([0.0, 0.0, 1.0]) 40 | expected_angle = 0.5 * np.pi 41 | angle = op.get_value([com1, com2, com3]) 42 | assert np.isclose(angle, expected_angle) 43 | return 44 | 45 | def test_torsion_order_parameter_get_value(): 46 | """ 47 | 48 | """ 49 | op = common_cv.Tiwary_cv_torsion_order_parameter() 50 | com1 = np.array([0.0, 0.0, 1.0]) 51 | com2 = np.array([0.0, 0.0, 0.0]) 52 | com3 = np.array([1.0, 0.0, 0.0]) 53 | com4 = np.array([1.0, 1.0, 0.0]) 54 | expected_phi = -0.5 * np.pi 55 | phi = op.get_value([com1, com2, com3, com4]) 56 | assert np.isclose(phi, expected_phi) 57 | return 58 | 59 | def test_toy_input_and_model(toy_mmvt_model_input, toy_mmvt_model): 60 | """ 61 | 62 | """ 63 | check.check_pre_simulation_all(toy_mmvt_model) 64 | return -------------------------------------------------------------------------------- /seekr2/tests/test_mmvt_cv_base.py: -------------------------------------------------------------------------------- 1 | """ 2 | test_mmvt_cv_base.py 3 | """ 4 | 5 | import os 6 | import shutil 7 | 8 | import numpy as np 9 | 10 | from seekr2.modules import mmvt_sim_openmm 11 | 12 | # TODO: move tests to appropriate test files and remove this test file 13 | 14 | def test_MMVT_anchor_id_from_alias(host_guest_mmvt_model): 15 | """ 16 | Test the anchor's ability to return information about itself and its 17 | milestones - id_from_alias. 18 | """ 19 | anchor0 = host_guest_mmvt_model.anchors[0] 20 | anchor1 = host_guest_mmvt_model.anchors[1] 21 | # test id_from_alias 22 | assert anchor0.id_from_alias(1) == 0 23 | assert anchor1.id_from_alias(1) == 0 24 | assert anchor1.id_from_alias(2) == 1 25 | return 26 | 27 | def test_MMVT_anchor_alias_from_id(host_guest_mmvt_model): 28 | """ 29 | Test the anchor's ability to return information about itself and its 30 | milestones - alias_from_id. 31 | """ 32 | anchor0 = host_guest_mmvt_model.anchors[0] 33 | anchor1 = host_guest_mmvt_model.anchors[1] 34 | # test id_from_alias 35 | assert anchor0.alias_from_id(0) == 1 36 | assert anchor1.alias_from_id(0) == 1 37 | assert anchor1.alias_from_id(1) == 2 38 | return 39 | 40 | def test_MMVT_anchor_alias_from_neighbor_id(host_guest_mmvt_model): 41 | """ 42 | Test the anchor's ability to return information about itself and its 43 | milestones - alias_from_neighbor_id. 44 | """ 45 | anchor0 = host_guest_mmvt_model.anchors[0] 46 | anchor1 = host_guest_mmvt_model.anchors[1] 47 | # test id_from_alias 48 | assert anchor0.alias_from_neighbor_id(1) == 1 49 | assert anchor1.alias_from_neighbor_id(0) == 1 50 | assert anchor1.alias_from_neighbor_id(2) == 2 51 | return 52 | 53 | def test_MMVT_anchor_get_ids(host_guest_mmvt_model): 54 | """ 55 | Test the anchor's ability to return information about itself and its 56 | milestones - id_from_alias. 57 | """ 58 | anchor0 = host_guest_mmvt_model.anchors[0] 59 | anchor1 = host_guest_mmvt_model.anchors[1] 60 | # test id_from_alias 61 | assert anchor0.get_ids() == [0] 62 | assert anchor1.get_ids() == [0, 1] 63 | return 64 | 65 | def test_check_openmm_context_within_boundary(host_guest_mmvt_model, tmp_path): 66 | """ 67 | Test whether the check can find systems that exist outside the proper 68 | Voronoi cells. 69 | """ 70 | # Test check success: system starting within Voronoi cells 71 | anchor = host_guest_mmvt_model.anchors[0] 72 | output_file = os.path.join(tmp_path, "output.txt") 73 | host_guest_mmvt_model.openmm_settings.cuda_platform_settings = None 74 | host_guest_mmvt_model.openmm_settings.reference_platform = True 75 | my_sim_openmm = mmvt_sim_openmm.create_sim_openmm( 76 | host_guest_mmvt_model, anchor, output_file) 77 | context = my_sim_openmm.simulation.context 78 | 79 | final_result = True 80 | for milestone in anchor.milestones: 81 | cv = host_guest_mmvt_model.collective_variables[milestone.cv_index] 82 | result = cv.check_openmm_context_within_boundary( 83 | context, milestone.variables, verbose=True) 84 | final_result = final_result and result 85 | 86 | assert final_result 87 | 88 | # Test check failure(s): system outside Voronoi cells 89 | anchor_pdb1 \ 90 | = host_guest_mmvt_model.anchors[0].amber_params.pdb_coordinates_filename 91 | anchor_pdb2 \ 92 | = host_guest_mmvt_model.anchors[1].amber_params.pdb_coordinates_filename 93 | anchor_pdb_src_path1 = os.path.join( 94 | host_guest_mmvt_model.anchor_rootdir, 95 | host_guest_mmvt_model.anchors[0].directory, 96 | host_guest_mmvt_model.anchors[0].building_directory, 97 | anchor_pdb1) 98 | anchor_pdb_src_path2 = os.path.join( 99 | host_guest_mmvt_model.anchor_rootdir, 100 | host_guest_mmvt_model.anchors[1].directory, 101 | host_guest_mmvt_model.anchors[1].building_directory, 102 | anchor_pdb2) 103 | anchor_pdb_dest_path1 = os.path.join( 104 | host_guest_mmvt_model.anchor_rootdir, 105 | host_guest_mmvt_model.anchors[0].directory, 106 | host_guest_mmvt_model.anchors[0].building_directory, 107 | anchor_pdb2) 108 | anchor_pdb_dest_path2 = os.path.join( 109 | host_guest_mmvt_model.anchor_rootdir, 110 | host_guest_mmvt_model.anchors[1].directory, 111 | host_guest_mmvt_model.anchors[1].building_directory, 112 | anchor_pdb1) 113 | shutil.copyfile(anchor_pdb_src_path1, anchor_pdb_dest_path2) 114 | shutil.copyfile(anchor_pdb_src_path2, anchor_pdb_dest_path1) 115 | host_guest_mmvt_model.anchors[0].amber_params.pdb_coordinates_filename \ 116 | = anchor_pdb2 117 | host_guest_mmvt_model.anchors[1].amber_params.pdb_coordinates_filename \ 118 | = anchor_pdb1 119 | 120 | my_sim_openmm = mmvt_sim_openmm.create_sim_openmm( 121 | host_guest_mmvt_model, anchor, output_file) 122 | context = my_sim_openmm.simulation.context 123 | 124 | final_result = True 125 | for milestone in anchor.milestones: 126 | cv = host_guest_mmvt_model.collective_variables[milestone.cv_index] 127 | result = cv.check_openmm_context_within_boundary( 128 | context, milestone.variables, verbose=True) 129 | final_result = final_result and result 130 | 131 | assert not final_result 132 | 133 | return 134 | 135 | def test_check_toy_openmm_context_within_boundary(toy_mmvt_model, tmp_path): 136 | """ 137 | Test whether the check can find systems that exist outside the proper 138 | Voronoi cells. 139 | """ 140 | # Test check success: system starting within Voronoi cells 141 | anchor = toy_mmvt_model.anchors[0] 142 | output_file = os.path.join(tmp_path, "output.txt") 143 | toy_mmvt_model.openmm_settings.cuda_platform_settings = None 144 | toy_mmvt_model.openmm_settings.reference_platform = True 145 | my_sim_openmm = mmvt_sim_openmm.create_sim_openmm( 146 | toy_mmvt_model, anchor, output_file) 147 | context = my_sim_openmm.simulation.context 148 | 149 | final_result = True 150 | for milestone in anchor.milestones: 151 | cv = toy_mmvt_model.collective_variables[milestone.cv_index] 152 | result = cv.check_openmm_context_within_boundary( 153 | context, milestone.variables, verbose=True) 154 | final_result = final_result and result 155 | 156 | assert final_result 157 | 158 | # Test check failure(s): system outside Voronoi cells 159 | toy_mmvt_model.anchors[0].starting_positions = np.array( 160 | [[[0.0, -0.7, 0.0]], [[0.2, -0.5, 0.0]]]) 161 | toy_mmvt_model.anchors[1].starting_positions = np.array( 162 | [[[0.0, -0.3, 0.0]]]) 163 | 164 | anchor = toy_mmvt_model.anchors[0] 165 | my_sim_openmm = mmvt_sim_openmm.create_sim_openmm( 166 | toy_mmvt_model, anchor, output_file, frame=1) 167 | context = my_sim_openmm.simulation.context 168 | 169 | final_result = True 170 | for milestone in anchor.milestones: 171 | cv = toy_mmvt_model.collective_variables[milestone.cv_index] 172 | result = cv.check_openmm_context_within_boundary( 173 | context, milestone.variables, verbose=True) 174 | final_result = final_result and result 175 | 176 | assert not final_result 177 | 178 | anchor = toy_mmvt_model.anchors[1] 179 | my_sim_openmm = mmvt_sim_openmm.create_sim_openmm( 180 | toy_mmvt_model, anchor, output_file) 181 | context = my_sim_openmm.simulation.context 182 | 183 | final_result = True 184 | for milestone in anchor.milestones: 185 | cv = toy_mmvt_model.collective_variables[milestone.cv_index] 186 | result = cv.check_openmm_context_within_boundary( 187 | context, milestone.variables, verbose=True) 188 | final_result = final_result and result 189 | 190 | assert not final_result 191 | 192 | return -------------------------------------------------------------------------------- /seekr2/tests/test_mmvt_sim_namd.py: -------------------------------------------------------------------------------- 1 | """ 2 | test_mmvt_sim_namd.py 3 | """ 4 | 5 | import os 6 | 7 | from seekr2.modules import mmvt_sim_namd 8 | 9 | def test_mmvt_sim_namd_amber(tmp_path, host_guest_mmvt_model_namd): 10 | myanchor = host_guest_mmvt_model_namd.anchors[1] 11 | output_file = os.path.join(tmp_path, "output.txt") 12 | my_sim_openmm = mmvt_sim_namd.create_sim_namd(host_guest_mmvt_model_namd, 13 | myanchor, output_file) 14 | assert my_sim_openmm.colvars_config is not None 15 | assert my_sim_openmm.seekr_namd_settings is not None 16 | return 17 | -------------------------------------------------------------------------------- /seekr2/tests/test_mmvt_sim_openmm.py: -------------------------------------------------------------------------------- 1 | """ 2 | test_mmvt_sim_openmm.py 3 | """ 4 | 5 | import pytest 6 | import os 7 | 8 | try: 9 | import openmm.unit as unit 10 | except ImportError: 11 | import simtk.openmm.unit as unit 12 | from seekr2.modules import mmvt_sim_openmm 13 | 14 | TEST_DIRECTORY = os.path.dirname(__file__) 15 | 16 | def test_add_integrator(toy_mmvt_model): 17 | my_sim_openmm = mmvt_sim_openmm.MMVT_sim_openmm() 18 | state_prefix = "test_state_prefix" 19 | mmvt_sim_openmm.add_integrator(my_sim_openmm, toy_mmvt_model, 20 | state_prefix=state_prefix) 21 | assert my_sim_openmm.integrator.getStepSize() \ 22 | == toy_mmvt_model.get_timestep() 23 | assert my_sim_openmm.integrator.getTemperature() \ 24 | == toy_mmvt_model.temperature 25 | assert my_sim_openmm.integrator.getFriction() \ 26 | == toy_mmvt_model.openmm_settings.langevin_integrator\ 27 | .friction_coefficient 28 | assert my_sim_openmm.integrator.getRandomNumberSeed() \ 29 | == toy_mmvt_model.openmm_settings.langevin_integrator.random_seed 30 | assert my_sim_openmm.integrator.getOutputFileName() \ 31 | == my_sim_openmm.output_filename 32 | assert my_sim_openmm.integrator.getSaveStateFileName() \ 33 | == state_prefix 34 | return 35 | 36 | def test_add_forces(tmp_path, toy_mmvt_model): 37 | anchor = toy_mmvt_model.anchors[0] 38 | output_file = os.path.join(tmp_path, "output.txt") 39 | my_sim_openmm = mmvt_sim_openmm.create_sim_openmm( 40 | toy_mmvt_model, anchor, output_file) 41 | forces = my_sim_openmm.system.getForces() 42 | old_force_len = len(forces) 43 | assert my_sim_openmm.integrator.getNumMilestoneGroups() \ 44 | == len(anchor.milestones) 45 | mmvt_sim_openmm.add_forces(my_sim_openmm, toy_mmvt_model, anchor, None) 46 | forces2 = my_sim_openmm.system.getForces() 47 | assert len(forces2) == old_force_len + len(anchor.milestones) 48 | return 49 | 50 | def test_add_simulation(tmp_path, toy_mmvt_model): 51 | anchor = toy_mmvt_model.anchors[0] 52 | output_file = os.path.join(tmp_path, "output.txt") 53 | my_sim_openmm = mmvt_sim_openmm.create_sim_openmm( 54 | toy_mmvt_model, anchor, output_file) 55 | assert my_sim_openmm.simulation is not None 56 | 57 | @pytest.mark.needs_cuda 58 | def test_mmvt_sim_openmm_amber(tmp_path, host_guest_mmvt_model): 59 | myanchor = host_guest_mmvt_model.anchors[1] 60 | output_file = os.path.join(tmp_path, "output.txt") 61 | my_sim_openmm = mmvt_sim_openmm.create_sim_openmm( 62 | host_guest_mmvt_model, myanchor, output_file) 63 | assert my_sim_openmm.system is not None 64 | assert my_sim_openmm.integrator is not None 65 | assert my_sim_openmm.simulation is not None 66 | return 67 | 68 | # No forcefield inputs currently working correctly 69 | @pytest.mark.skip() 70 | def test_mmvt_sim_openmm_forcefield(tmp_path, host_guest_mmvt_model_forcefield): 71 | 72 | myanchor = host_guest_mmvt_model_forcefield.anchors[1] 73 | output_file = os.path.join(tmp_path, "output.txt") 74 | my_sim_openmm = mmvt_sim_openmm.create_sim_openmm( 75 | host_guest_mmvt_model_forcefield, myanchor, output_file) 76 | assert my_sim_openmm.system is not None 77 | assert my_sim_openmm.integrator is not None 78 | assert my_sim_openmm.simulation is not None 79 | return 80 | 81 | @pytest.mark.needs_cuda 82 | def test_mmvt_sim_openmm_system(tmp_path, host_guest_mmvt_model_system): 83 | 84 | myanchor = host_guest_mmvt_model_system.anchors[1] 85 | output_file = os.path.join(tmp_path, "output.txt") 86 | my_sim_openmm = mmvt_sim_openmm.create_sim_openmm( 87 | host_guest_mmvt_model_system, myanchor, output_file) 88 | assert my_sim_openmm.system is not None 89 | assert my_sim_openmm.integrator is not None 90 | assert my_sim_openmm.simulation is not None 91 | return 92 | 93 | def test_make_mmvt_boundary_definitions(toy_mmvt_model): 94 | myanchor = toy_mmvt_model.anchors[1] 95 | mymilestone = myanchor.milestones[0] 96 | cv_index = mymilestone.cv_index 97 | mycv = toy_mmvt_model.collective_variables[cv_index] 98 | myforce = mmvt_sim_openmm.make_mmvt_boundary_definitions( 99 | mycv, mymilestone) 100 | assert myforce.getPerBondParameterName(0) == "bitcode" 101 | assert myforce.getPerBondParameterName(1) == "k" 102 | assert myforce.getPerBondParameterName(2) == "value" 103 | return 104 | 105 | def test_get_starting_structure_num_frames(tmp_path, toy_mmvt_model): 106 | myanchor = toy_mmvt_model.anchors[0] 107 | output_file = os.path.join(tmp_path, "output.txt") 108 | num_frames = mmvt_sim_openmm.get_starting_structure_num_frames( 109 | toy_mmvt_model, myanchor, output_file, load_state_file=None) 110 | assert num_frames == 2 111 | num_frames2 = mmvt_sim_openmm.get_starting_structure_num_frames( 112 | toy_mmvt_model, myanchor, output_file, load_state_file="dummy") 113 | assert num_frames2 == 1 114 | 115 | @pytest.mark.needs_cuda 116 | def test_check_if_state_in_anchor(host_guest_mmvt_model): 117 | state_file = os.path.join(TEST_DIRECTORY, "data/hostguest_state_a1.xml") 118 | myanchor1 = host_guest_mmvt_model.anchors[1] 119 | result1 = mmvt_sim_openmm.check_if_state_in_anchor( 120 | host_guest_mmvt_model, myanchor1, state_file) 121 | assert result1 122 | myanchor2 = host_guest_mmvt_model.anchors[0] 123 | result2 = mmvt_sim_openmm.check_if_state_in_anchor( 124 | host_guest_mmvt_model, myanchor2, state_file) 125 | assert not result2 126 | myanchor3 = host_guest_mmvt_model.anchors[2] 127 | result3 = mmvt_sim_openmm.check_if_state_in_anchor( 128 | host_guest_mmvt_model, myanchor3, state_file) 129 | assert not result3 -------------------------------------------------------------------------------- /seekr2/tests/test_mmvt_voronoi_cv.py: -------------------------------------------------------------------------------- 1 | """ 2 | test_mmvt_voronoi.py 3 | """ 4 | 5 | import os 6 | import shutil 7 | 8 | import numpy as np 9 | 10 | try: 11 | import openmm.unit as unit 12 | except ImportError: 13 | import simtk.unit as unit 14 | 15 | try: 16 | import openmm 17 | except ImportError: 18 | import simtk.openmm as openmm 19 | 20 | try: 21 | import openmm.app as openmm_app 22 | except ImportError: 23 | import simtk.openmm.app as openmm_app 24 | 25 | import mdtraj 26 | 27 | import seekr2.modules.common_sim_openmm as common_sim_openmm 28 | import seekr2.modules.mmvt_cvs.mmvt_spherical_cv as mmvt_spherical_cv 29 | import seekr2.modules.mmvt_cvs.mmvt_voronoi_cv as mmvt_voronoi_cv 30 | import seekr2.tests.create_toy_system as create_toy_system 31 | 32 | def test_mmvt_voronoi_boundary(tmp_path): 33 | # Set initial variables 34 | milestone_variables = {"k":1.0, "me_0":0.4, "neighbor_0":0.7} 35 | my_variables = [1.0, 1.0, 0.4, 0.7] 36 | positions1 = [[0.0, 0.0, 0.0], [0.3, 0.4, 0.0]] 37 | 38 | # Initialize the toy system with boundary force 39 | toy_system, toy_topology = create_toy_system.make_toy_system_and_topology(2) 40 | my_cv = mmvt_voronoi_cv.MMVT_Voronoi_CV(index=0) 41 | child_cv = mmvt_spherical_cv.MMVT_spherical_CV(index=0, groups=[[0],[1]]) 42 | my_cv.child_cvs.append(child_cv) 43 | boundary_force1 = my_cv.make_boundary_force(alias_id=1) 44 | boundary_force1.setForceGroup(1) 45 | my_cv.add_parameters(boundary_force1) 46 | my_cv.add_groups_and_variables( 47 | force=boundary_force1, variables=my_variables, alias_id=1) 48 | toy_system.addForce(boundary_force1) 49 | toy_simulation = create_toy_system.make_toy_simulation_and_context( 50 | toy_system, toy_topology, positions1) 51 | 52 | # Check that the particle is within the boundary 53 | toy_state = toy_simulation.context.getState(getEnergy=True, groups={1}) 54 | boundary_val1 = toy_state.getPotentialEnergy() 55 | assert boundary_val1.value_in_unit(unit.kilojoules/unit.mole) == 0.0 56 | 57 | # Ensure that check_mdtraj_within_boundary works for this cv 58 | pdb_filename1 = os.path.join(tmp_path, "voronoi_mmvt_toy1.pdb") 59 | common_sim_openmm.write_toy_pdb_file(toy_topology, positions1, pdb_filename1) 60 | pdbtraj1 = mdtraj.load(pdb_filename1) 61 | assert my_cv.check_mdtraj_within_boundary( 62 | pdbtraj1, milestone_variables, verbose=False, TOL=0.0) 63 | 64 | # Ensure that check_openmm_context_within_boundary works for this cv 65 | assert my_cv.check_openmm_context_within_boundary( 66 | toy_simulation.context, milestone_variables) 67 | 68 | # Move the particle outside the boundary 69 | positions2 = [[0.0, 0.0, 0.0], [0.0, 0.6, 0.0]] 70 | toy_simulation.context.setPositions(positions2) 71 | 72 | # Check that the particle is outside the boundary 73 | toy_state = toy_simulation.context.getState(getEnergy=True, groups={1}) 74 | boundary_val2 = toy_state.getPotentialEnergy() 75 | assert boundary_val2.value_in_unit(unit.kilojoules/unit.mole) == 1.0 76 | 77 | return 78 | -------------------------------------------------------------------------------- /seekr2/tests/test_prepare.py: -------------------------------------------------------------------------------- 1 | """ 2 | test_prepare.py 3 | """ 4 | 5 | def test_prepare(toy_mmvt_model): 6 | pass 7 | 8 | def test_prepare_multidim(toy_multi_model): 9 | pass 10 | 11 | def test_prepare_planar(planar_mmvt_model): 12 | pass 13 | 14 | def test_prepare_rmsd(rmsd_mmvt_model): 15 | pass 16 | 17 | def test_prepare_closest_pair(closest_pair_mmvt_model): 18 | pass 19 | 20 | def test_prepare_count_contacts(count_contacts_mmvt_model): 21 | pass 22 | 23 | def test_prepare_voronoi(toy_voronoi_model): 24 | pass 25 | 26 | def test_prepare_ala_ala_ala_charmm(ala_ala_ala_mmvt_model_charmm): 27 | pass -------------------------------------------------------------------------------- /seekr2/tests/test_runner_namd.py: -------------------------------------------------------------------------------- 1 | """ 2 | test_runner_namd.py 3 | 4 | test runner_namd.py script(s) 5 | """ 6 | 7 | import os 8 | import glob 9 | import pathlib 10 | 11 | import seekr2.modules.common_base as base 12 | import seekr2.modules.mmvt_cvs.mmvt_cv_base as mmvt_cv_base 13 | import seekr2.modules.mmvt_sim_namd as mmvt_sim_namd 14 | import seekr2.modules.runner_namd as runner_namd 15 | import seekr2.run as run 16 | 17 | TEST_DIRECTORY = os.path.dirname(__file__) 18 | TEST_DATA_DIRECTORY = os.path.join(TEST_DIRECTORY, "data") 19 | 20 | def test_search_for_state_to_load(host_guest_mmvt_model): 21 | anchor0 = host_guest_mmvt_model.anchors[1] 22 | state_dir = os.path.join( 23 | host_guest_mmvt_model.anchor_rootdir, anchor0.directory, 24 | anchor0.production_directory, "states") 25 | if not os.path.exists(state_dir): 26 | os.mkdir(state_dir) 27 | state0 = os.path.join(state_dir, "namdmmvt_2_2") 28 | pathlib.Path(state0).touch() 29 | anchor1 = host_guest_mmvt_model.anchors[2] 30 | state1 = runner_namd.search_for_state_to_load(host_guest_mmvt_model, anchor1) 31 | assert state1 == os.path.join(state_dir, "namdmmvt_2_2") 32 | anchor2 = host_guest_mmvt_model.anchors[3] 33 | state2 = runner_namd.search_for_state_to_load(host_guest_mmvt_model, anchor2) 34 | assert state2 is None 35 | return 36 | 37 | def test_read_xsc_step_number(): 38 | xsc_filename = os.path.join(TEST_DATA_DIRECTORY, "test_namd.xsc") 39 | assert runner_namd.read_xsc_step_number(xsc_filename) == 1000 40 | 41 | def test_cleanse_anchor_outputs(host_guest_mmvt_model_namd): 42 | num_steps = 10 43 | dcd_interval = 1 44 | host_guest_mmvt_model_namd.calculation_settings.num_production_steps \ 45 | = num_steps 46 | host_guest_mmvt_model_namd.calculation_settings\ 47 | .restart_checkpoint_interval = 1 48 | host_guest_mmvt_model_namd.calculation_settings\ 49 | .trajectory_reporter_interval = dcd_interval 50 | anchor1 = host_guest_mmvt_model_namd.anchors[0] 51 | prod_directory = os.path.join( 52 | host_guest_mmvt_model_namd.anchor_rootdir, anchor1.directory, 53 | anchor1.production_directory) 54 | run.run(host_guest_mmvt_model_namd, "0", force_overwrite=True, save_state_file=True) 55 | runner_namd.cleanse_anchor_outputs( 56 | host_guest_mmvt_model_namd, anchor1) 57 | #print("os.listdir(prod_directory):", os.listdir(prod_directory)) 58 | assert len(os.listdir(prod_directory)) == 0 59 | 60 | def test_Runner_namd_default(host_guest_mmvt_model): 61 | host_guest_mmvt_model.calculation_settings.num_production_steps = 10 62 | host_guest_mmvt_model.namd_settings = base.Namd_settings() 63 | myanchor = host_guest_mmvt_model.anchors[1] 64 | namd_command = "namd2" 65 | namd_arguments = "" 66 | runner = runner_namd.Runner_namd( 67 | host_guest_mmvt_model, myanchor, namd_command, namd_arguments) 68 | default_output_file, output_basename, state_file_prefix, restart_index = \ 69 | runner.prepare(force_overwrite=True) 70 | mmvt_output_filename = os.path.join( 71 | host_guest_mmvt_model.anchor_rootdir, myanchor.directory, "prod", 72 | "%s%d" % (mmvt_cv_base.NAMDMMVT_BASENAME, 1)) 73 | my_sim_namd = mmvt_sim_namd.create_sim_namd( 74 | host_guest_mmvt_model, myanchor, mmvt_output_filename) 75 | my_sim_namd.namd_root.periodic_boundary_conditions.PMEGridSpacing = None 76 | runner.run(my_sim_namd, mmvt_output_filename+".out") 77 | myglob = mmvt_output_filename+".out*" 78 | outfiles = glob.glob(myglob) 79 | outfile = outfiles[0] 80 | assert os.path.exists(outfile) 81 | return 82 | 83 | def test_Runner_namd_load_state(host_guest_mmvt_model): 84 | host_guest_mmvt_model.calculation_settings.num_production_steps = 10 85 | host_guest_mmvt_model.namd_settings = base.Namd_settings() 86 | myanchor = host_guest_mmvt_model.anchors[1] 87 | namd_command = "namd2" 88 | namd_arguments = "" 89 | runner = runner_namd.Runner_namd( 90 | host_guest_mmvt_model, myanchor, namd_command, namd_arguments) 91 | default_output_file, output_basename, state_file_prefix, restart_index = \ 92 | runner.prepare(force_overwrite=True) 93 | mmvt_output_filename = os.path.join( 94 | host_guest_mmvt_model.anchor_rootdir, myanchor.directory, "prod", 95 | "%s%d" % (mmvt_cv_base.NAMDMMVT_BASENAME, 1)) 96 | loading_state_filename = os.path.join(host_guest_mmvt_model.anchor_rootdir, 97 | "start.state") 98 | my_sim_namd = mmvt_sim_namd.create_sim_namd( 99 | host_guest_mmvt_model, myanchor, mmvt_output_filename) 100 | my_sim_namd.namd_root.periodic_boundary_conditions.PMEGridSpacing = None 101 | runner.run(my_sim_namd, mmvt_output_filename+".out") 102 | myglob = mmvt_output_filename+".out*" 103 | outfiles = glob.glob(myglob) 104 | outfile = outfiles[0] 105 | assert os.path.exists(outfile) 106 | return 107 | 108 | def test_Runner_namd_save_states(host_guest_mmvt_model): 109 | host_guest_mmvt_model.calculation_settings.num_production_steps = 10 110 | host_guest_mmvt_model.namd_settings = base.Namd_settings() 111 | myanchor = host_guest_mmvt_model.anchors[1] 112 | namd_command = "namd2" 113 | namd_arguments = "" 114 | runner = runner_namd.Runner_namd( 115 | host_guest_mmvt_model, myanchor, namd_command, namd_arguments) 116 | default_output_file, output_basename, state_file_prefix, restart_index = \ 117 | runner.prepare(force_overwrite=True, save_state_file=True) 118 | mmvt_output_filename = os.path.join( 119 | host_guest_mmvt_model.anchor_rootdir, myanchor.directory, "prod", 120 | "%s%d" % (mmvt_cv_base.NAMDMMVT_BASENAME, 1)) 121 | my_sim_namd = mmvt_sim_namd.create_sim_namd( 122 | host_guest_mmvt_model, myanchor, mmvt_output_filename) 123 | my_sim_namd.namd_root.periodic_boundary_conditions.PMEGridSpacing = None 124 | runner.run(my_sim_namd, mmvt_output_filename+".out") 125 | myglob = mmvt_output_filename+".out*" 126 | outfiles = glob.glob(myglob) 127 | outfile = outfiles[0] 128 | assert os.path.exists(outfile) 129 | return 130 | 131 | def test_Runner_namd_save_states_until_all_bounds(host_guest_mmvt_model): 132 | host_guest_mmvt_model.calculation_settings.num_production_steps = 10 133 | host_guest_mmvt_model.namd_settings = base.Namd_settings() 134 | myanchor = host_guest_mmvt_model.anchors[1] 135 | namd_command = "namd2" 136 | namd_arguments = "" 137 | runner = runner_namd.Runner_namd( 138 | host_guest_mmvt_model, myanchor, namd_command, namd_arguments) 139 | default_output_file, output_basename, state_file_prefix, restart_index = \ 140 | runner.prepare(force_overwrite=True, save_state_boundaries=True) 141 | mmvt_output_filename = os.path.join( 142 | host_guest_mmvt_model.anchor_rootdir, myanchor.directory, "prod", 143 | "%s%d" % (mmvt_cv_base.NAMDMMVT_BASENAME, 1)) 144 | my_sim_namd = mmvt_sim_namd.create_sim_namd( 145 | host_guest_mmvt_model, myanchor, mmvt_output_filename) 146 | my_sim_namd.namd_root.periodic_boundary_conditions.PMEGridSpacing = None 147 | runner.run(my_sim_namd, mmvt_output_filename+".out") 148 | myglob = mmvt_output_filename+".out*" 149 | outfiles = glob.glob(myglob) 150 | outfile = outfiles[0] 151 | assert os.path.exists(outfile) 152 | return --------------------------------------------------------------------------------