├── .conda.yml ├── .conda_gpu.yml ├── .editorconfig ├── .gitignore ├── .pyup.yml ├── .travis.yml ├── AUTHORS.rst ├── CONTRIBUTING.rst ├── Dockerfile ├── HISTORY.rst ├── LICENSE ├── MANIFEST.in ├── Makefile ├── README.rst ├── conda ├── meta.yaml └── run_test.sh ├── docking_py ├── __init__.py ├── cli.py ├── docking.py └── tests │ ├── __init__.py │ ├── input │ ├── 1hsg.pdb │ ├── 4yob.pdb │ ├── lig.pdbqt │ └── rec.pdbqt │ └── test_docking_py.py ├── docs ├── Makefile ├── _static │ ├── dock.html │ ├── lig.html │ └── rec.html ├── authors.rst ├── conf.py ├── contributing.rst ├── docking_py.rst ├── history.rst ├── index.rst ├── installation.rst ├── make.bat ├── modules.rst ├── notebook │ └── Usage.ipynb └── readme.rst ├── pytest.ini ├── requirements.txt ├── requirements_dev.txt ├── setup.cfg ├── setup.py └── tox.ini /.conda.yml: -------------------------------------------------------------------------------- 1 | name: docking 2 | channels: 3 | - conda-forge 4 | - bioconda 5 | - hcc 6 | dependencies: 7 | - numpy 8 | - pdb_manip_py==1.3.10 9 | - os_command_py==1.1.0 10 | - python>=3.5 11 | - mgltools 12 | - smina 13 | - autodock-vina 14 | - qvina 15 | - autodock 16 | - autogrid==4.2.6 17 | - pytest 18 | - pip -------------------------------------------------------------------------------- /.conda_gpu.yml: -------------------------------------------------------------------------------- 1 | name: docking_gpu 2 | channels: 3 | - conda-forge 4 | - bioconda 5 | - hcc 6 | dependencies: 7 | - numpy 8 | - pdb_manip_py==1.3.10 9 | - os_command_py==1.1.0 10 | - python>=3.5 11 | - mgltools 12 | - smina 13 | - autodock-vina 14 | - qvina 15 | - autodock 16 | - autodock-gpu 17 | - pytest 18 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | indent_style = space 7 | indent_size = 4 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | charset = utf-8 11 | end_of_line = lf 12 | 13 | [*.bat] 14 | indent_style = tab 15 | end_of_line = crlf 16 | 17 | [LICENSE] 18 | insert_final_newline = false 19 | 20 | [Makefile] 21 | indent_style = tab 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 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 | # IDE settings 105 | .vscode/ -------------------------------------------------------------------------------- /.pyup.yml: -------------------------------------------------------------------------------- 1 | # autogenerated pyup.io config file 2 | # see https://pyup.io/docs/configuration/ for all available options 3 | 4 | schedule: '' 5 | update: false 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: generic 2 | 3 | # Doesn't matter, tox will test py35, py36, py37 and py38 4 | python: 5 | - "3.8" 6 | 7 | matrix: 8 | include: 9 | - os: linux 10 | # - os: osx # Removed because of credit issues 11 | 12 | install: 13 | - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; 14 | then 15 | sudo apt-get update; 16 | MINICONDA_OS=Linux; 17 | else 18 | MINICONDA_OS=MacOSX; 19 | fi 20 | - wget https://repo.anaconda.com/miniconda/Miniconda3-latest-$MINICONDA_OS-x86_64.sh -O miniconda.sh; 21 | - bash miniconda.sh -b -p $HOME/miniconda 22 | - source "$HOME/miniconda/etc/profile.d/conda.sh" 23 | - hash -r 24 | - conda config --set always_yes yes --set changeps1 no 25 | - conda update -q conda 26 | # Useful for debugging any issues with conda 27 | - conda info -a 28 | - conda env create -f .conda.yml 29 | - conda activate docking 30 | # Need to update pip, setuptools and wheel only for python3.5 31 | - pip install -U pip setuptools wheel 32 | # Install tox-conda to use tox in conda 33 | - pip install tox-conda 34 | - pip install codecov 35 | - pip install -r requirements.txt 36 | 37 | script: 38 | - tox 39 | 40 | after_success: 41 | - codecov 42 | -------------------------------------------------------------------------------- /AUTHORS.rst: -------------------------------------------------------------------------------- 1 | ======= 2 | Credits 3 | ======= 4 | 5 | Development Lead 6 | ---------------- 7 | 8 | * Samuel Murail, Université de Paris 9 | 10 | Contributors 11 | ------------ 12 | 13 | * Pierre Tuffery, INSERM 14 | * Damien Espana 15 | 16 | We are open to any contribution. 17 | -------------------------------------------------------------------------------- /CONTRIBUTING.rst: -------------------------------------------------------------------------------- 1 | .. highlight:: shell 2 | 3 | ============ 4 | Contributing 5 | ============ 6 | 7 | Contributions are welcome, and they are greatly appreciated! Every little bit 8 | helps, and credit will always be given. 9 | 10 | You can contribute in many ways: 11 | 12 | Types of Contributions 13 | ---------------------- 14 | 15 | Report Bugs 16 | ~~~~~~~~~~~ 17 | 18 | Report bugs at https://github.com/samuelmurail/docking_py/issues. 19 | 20 | If you are reporting a bug, please include: 21 | 22 | * Your operating system name and version. 23 | * Any details about your local setup that might be helpful in troubleshooting. 24 | * Detailed steps to reproduce the bug. 25 | 26 | Fix Bugs 27 | ~~~~~~~~ 28 | 29 | Look through the GitHub issues for bugs. Anything tagged with "bug" and "help 30 | wanted" is open to whoever wants to implement it. 31 | 32 | Implement Features 33 | ~~~~~~~~~~~~~~~~~~ 34 | 35 | Look through the GitHub issues for features. Anything tagged with "enhancement" 36 | and "help wanted" is open to whoever wants to implement it. 37 | 38 | Write Documentation 39 | ~~~~~~~~~~~~~~~~~~~ 40 | 41 | Docking Python could always use more documentation, whether as part of the 42 | official Docking Python docs, in docstrings, or even on the web in blog posts, 43 | articles, and such. 44 | 45 | Submit Feedback 46 | ~~~~~~~~~~~~~~~ 47 | 48 | The best way to send feedback is to file an issue at https://github.com/samuelmurail/docking_py/issues. 49 | 50 | If you are proposing a feature: 51 | 52 | * Explain in detail how it would work. 53 | * Keep the scope as narrow as possible, to make it easier to implement. 54 | * Remember that this is a volunteer-driven project, and that contributions 55 | are welcome :) 56 | 57 | Get Started! 58 | ------------ 59 | 60 | Ready to contribute? Here's how to set up `docking_py` for local development. 61 | 62 | 1. Fork the `docking_py` repo on GitHub. 63 | 2. Clone your fork locally:: 64 | 65 | $ git clone git@github.com:your_name_here/docking_py.git 66 | 67 | 3. Install your local copy into a virtualenv. Assuming you have virtualenvwrapper installed, this is how you set up your fork for local development:: 68 | 69 | $ mkvirtualenv docking_py 70 | $ cd docking_py/ 71 | $ python setup.py develop 72 | 73 | 4. Create a branch for local development:: 74 | 75 | $ git checkout -b name-of-your-bugfix-or-feature 76 | 77 | Now you can make your changes locally. 78 | 79 | 5. When you're done making changes, check that your changes pass flake8 and the 80 | tests, including testing other Python versions with tox:: 81 | 82 | $ flake8 docking_py tests 83 | $ python setup.py test or pytest 84 | $ tox 85 | 86 | To get flake8 and tox, just pip install them into your virtualenv. 87 | 88 | 6. Commit your changes and push your branch to GitHub:: 89 | 90 | $ git add . 91 | $ git commit -m "Your detailed description of your changes." 92 | $ git push origin name-of-your-bugfix-or-feature 93 | 94 | 7. Submit a pull request through the GitHub website. 95 | 96 | Pull Request Guidelines 97 | ----------------------- 98 | 99 | Before you submit a pull request, check that it meets these guidelines: 100 | 101 | 1. The pull request should include tests. 102 | 2. If the pull request adds functionality, the docs should be updated. Put 103 | your new functionality into a function with a docstring, and add the 104 | feature to the list in README.rst. 105 | 3. The pull request should work for Python 3.5, 3.6, 3.7 and 3.8, and for PyPy. Check 106 | https://travis-ci.com/samuelmurail/docking_py/pull_requests 107 | and make sure that the tests pass for all supported Python versions. 108 | 109 | Tips 110 | ---- 111 | 112 | To run a subset of tests:: 113 | 114 | $ pytest tests.test_docking_py 115 | 116 | 117 | Deploying 118 | --------- 119 | 120 | A reminder for the maintainers on how to deploy. 121 | Make sure all your changes are committed (including an entry in HISTORY.rst). 122 | Then run:: 123 | 124 | $ bump2version patch # possible: major / minor / patch 125 | $ git push 126 | $ git push --tags 127 | 128 | Travis will then deploy to PyPI if tests pass. 129 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM continuumio/miniconda3 2 | 3 | # Trick to ensure git clone is done if the deposit has been changed 4 | ADD https://api.github.com/repos/samuelmurail/gromacs_py/git/refs/heads/master version.json 5 | 6 | COPY .conda.yml /tmp/environment.yml 7 | RUN conda env create -f /tmp/environment.yml -n docking_py 8 | RUN echo "conda activate docking_py" >> ~/.bashrc 9 | COPY setup.py setup.py 10 | COPY README.rst README.rst 11 | COPY HISTORY.rst HISTORY.rst 12 | COPY docking_py docking_py 13 | RUN conda run -n docking_py python setup.py install 14 | 15 | ENV PATH /opt/conda/envs/docking_py/bin:$PATH 16 | ENV CONDA_DEFAULT_ENV docking_py 17 | -------------------------------------------------------------------------------- /HISTORY.rst: -------------------------------------------------------------------------------- 1 | ======= 2 | History 3 | ======= 4 | 5 | 0.3.0 (2021-15-11) 6 | ------------------ 7 | 8 | `Docking_py` module has been published in the reference `SeamDock` article 9 | 10 | - Murail S, de Vries SJ, Rey J, Moroy G and Tufféry P. *SeamDock: An Interactive and Collaborative Online Docking Resource to Assist Small Compound Molecular Docking.* **Front. Mol. Biosci. (2021)**. 8:716466. doi: 10.3389/fmolb.2021.716466. 11 | 12 | 0.1.0 (2020-04-15) 13 | ------------------ 14 | 15 | * First release on PyPI. 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include AUTHORS.rst 2 | include CONTRIBUTING.rst 3 | include HISTORY.rst 4 | include LICENSE 5 | include README.rst 6 | 7 | recursive-include docking_py/tests/ * 8 | recursive-exclude * __pycache__ 9 | recursive-exclude * *.py[co] 10 | 11 | recursive-include docs *.rst conf.py Makefile make.bat *.jpg *.png *.gif 12 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: clean clean-test clean-pyc clean-build docs help 2 | .DEFAULT_GOAL := help 3 | 4 | define BROWSER_PYSCRIPT 5 | import os, webbrowser, sys 6 | 7 | from urllib.request import pathname2url 8 | 9 | webbrowser.open("file://" + pathname2url(os.path.abspath(sys.argv[1]))) 10 | endef 11 | export BROWSER_PYSCRIPT 12 | 13 | define PRINT_HELP_PYSCRIPT 14 | import re, sys 15 | 16 | for line in sys.stdin: 17 | match = re.match(r'^([a-zA-Z_-]+):.*?## (.*)$$', line) 18 | if match: 19 | target, help = match.groups() 20 | print("%-20s %s" % (target, help)) 21 | endef 22 | export PRINT_HELP_PYSCRIPT 23 | 24 | BROWSER := python -c "$$BROWSER_PYSCRIPT" 25 | 26 | help: 27 | @python -c "$$PRINT_HELP_PYSCRIPT" < $(MAKEFILE_LIST) 28 | 29 | clean: clean-build clean-pyc clean-test ## remove all build, test, coverage and Python artifacts 30 | 31 | clean-build: ## remove build artifacts 32 | rm -fr build/ 33 | rm -fr dist/ 34 | rm -fr .eggs/ 35 | find . -name '*.egg-info' -exec rm -fr {} + 36 | find . -name '*.egg' -exec rm -f {} + 37 | 38 | clean-pyc: ## remove Python file artifacts 39 | find . -name '*.pyc' -exec rm -f {} + 40 | find . -name '*.pyo' -exec rm -f {} + 41 | find . -name '*~' -exec rm -f {} + 42 | find . -name '__pycache__' -exec rm -fr {} + 43 | 44 | clean-test: ## remove test and coverage artifacts 45 | rm -fr .tox/ 46 | rm -f .coverage 47 | rm -fr htmlcov/ 48 | rm -fr .pytest_cache 49 | 50 | lint: ## check style with flake8 51 | flake8 docking_py 52 | 53 | test: ## run tests quickly with the default Python 54 | pytest docking_py 55 | 56 | test-all: ## run tests on every Python version with tox 57 | tox 58 | 59 | coverage: ## check code coverage quickly with the default Python 60 | coverage run --source docking_py -m pytest 61 | coverage report -m 62 | coverage html 63 | $(BROWSER) htmlcov/index.html 64 | 65 | docs: ## generate Sphinx HTML documentation, including API docs 66 | rm -f docs/docking_py.rst 67 | rm -f docs/modules.rst 68 | sphinx-apidoc -o docs/ docking_py 69 | $(MAKE) -C docs clean 70 | $(MAKE) -C docs html 71 | $(BROWSER) docs/_build/html/index.html 72 | 73 | servedocs: docs ## compile the docs watching for changes 74 | watchmedo shell-command -p '*.rst' -c '$(MAKE) -C docs html' -R -D . 75 | 76 | release: dist ## package and upload a release 77 | twine upload dist/* 78 | 79 | dist: clean ## builds source and wheel package 80 | python setup.py sdist 81 | python setup.py bdist_wheel 82 | ls -l dist 83 | 84 | install: clean ## install the package to the active Python's site-packages 85 | python setup.py install 86 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | ============== 2 | Docking Python 3 | ============== 4 | 5 | 6 | .. image:: https://travis-ci.org/samuelmurail/docking_py.svg?branch=master 7 | :target: https://travis-ci.org/samuelmurail/docking_py 8 | 9 | .. image:: https://readthedocs.org/projects/docking-py/badge/?version=latest 10 | :target: https://docking-py.readthedocs.io/en/latest/?badge=latest 11 | :alt: Documentation Status 12 | 13 | .. image:: https://codecov.io/gh/samuelmurail/docking_py/branch/master/graph/badge.svg 14 | :target: https://codecov.io/gh/samuelmurail/docking_py 15 | 16 | .. image:: https://badge.fury.io/py/docking-py.svg 17 | :target: https://badge.fury.io/py/docking-py 18 | 19 | .. image:: https://static.pepy.tech/badge/docking-py 20 | :target: https://pepy.tech/projects/docking-py 21 | 22 | .. image:: https://anaconda.org/bioconda/docking_py/badges/version.svg 23 | :target: https://anaconda.org/bioconda/docking_py 24 | 25 | .. image:: https://zenodo.org/badge/DOI/10.5281/zenodo.4506970.svg 26 | :target: https://doi.org/10.5281/zenodo.4506970 27 | 28 | Docking_py is a python library allowing a simplified use of the Smina, vina, qvina2 and qvinaw docking software. Docking_py can be easily automatize and scripted. 29 | 30 | 31 | * Free software: GNU General Public License v2 (GPLv2) 32 | * Documentation: https://docking-py.readthedocs.io. 33 | 34 | 35 | Features 36 | -------- 37 | 38 | * Prepare receptors and ligands. 39 | * Launch docking using: 40 | * Autodock with or without **GPU** acceleration 41 | * Vina 42 | * Smina 43 | * Qvina2 44 | * Qvinaw 45 | 46 | Citing this work 47 | ---------------- 48 | 49 | If you use the code or data in this package, please cite: 50 | 51 | .. code-block:: 52 | 53 | @Article{SeamDock2021, 54 | title = {SeamDock: An Interactive and Collaborative Online Docking Resource to Assist Small Compound Molecular Docking}, 55 | shorttitle = {SeamDock}, 56 | author = {Murail, Samuel and de Vries, Sjoerd J. and Rey, Julien and Moroy, Gautier and Tuff{\'e}ry, Pierre}, 57 | year = {2021}, 58 | journal = {Frontiers in Molecular Biosciences}, 59 | volume = {8}, 60 | pages = {762}, 61 | issn = {2296-889X}, 62 | doi = {10.3389/fmolb.2021.716466}, 63 | } 64 | 65 | 66 | Credits 67 | ------- 68 | 69 | This package was created with Cookiecutter_ and the `audreyr/cookiecutter-pypackage`_ project template. 70 | 71 | .. _Cookiecutter: https://github.com/audreyr/cookiecutter 72 | .. _`audreyr/cookiecutter-pypackage`: https://github.com/audreyr/cookiecutter-pypackage 73 | -------------------------------------------------------------------------------- /conda/meta.yaml: -------------------------------------------------------------------------------- 1 | {% set name = "docking_py" %} 2 | {% set version = "0.3.0" %} 3 | 4 | package: 5 | name: "{{ name|lower }}" 6 | version: "{{ version }}" 7 | 8 | source: 9 | url: "https://pypi.io/packages/source/{{ name[0] }}/{{ name }}/{{ name }}-{{ version }}.tar.gz" 10 | sha256: 5477ed7d66d863645960d7138c51bfd3f05f1c0b3d2f0ca2df66072cd46145e2 11 | 12 | build: 13 | number: 0 14 | noarch: python 15 | script: "{{ PYTHON }} -m pip install . -vv" 16 | entry_points: 17 | - docking_py=docking_py.cli:main 18 | 19 | requirements: 20 | host: 21 | - pip 22 | - python >=3.5 23 | run: 24 | - python >=3.5 25 | - numpy 26 | - os_command_py 27 | - pdb2pqr_htmd_propka30 28 | - pdb_manip_py 29 | - mgltools=1.5.6 30 | - smina 31 | - autodock-vina 32 | - qvina 33 | 34 | test: 35 | imports: 36 | - docking_py.docking 37 | requires: 38 | - pytest 39 | 40 | about: 41 | home: "https://github.com/samuelmurail/docking_py" 42 | license: "GPL-2.0-only" 43 | license_file: LICENSE 44 | summary: "Docking_py is a python library allowing a simplified use of the Smina, vina, qvina2 and qvinaw docking software. Docking_py can be easily automatize and scripted." 45 | doc_url: "https://docking-py.readthedocs.io/en/latest/" 46 | dev_url: "https://docking-py.readthedocs.io/en/latest/contributing.html" 47 | 48 | extra: 49 | recipe-maintainers: 50 | - samuelmurail 51 | -------------------------------------------------------------------------------- /conda/run_test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | pytest --pyargs docking_py --doctest-modules -------------------------------------------------------------------------------- /docking_py/__init__.py: -------------------------------------------------------------------------------- 1 | """Top-level package for Docking Python.""" 2 | 3 | # Autorship information 4 | __author__ = "Samuel Murail, Damien Espana, Pierre Tuffery" 5 | __copyright__ = "Copyright 2020, RPBS" 6 | __credits__ = ["Damien Espana", "Pierre Tuffery", "Samuel Murail"] 7 | __license__ = "GNU General Public License v2.0" 8 | __version__ = "__version__ = '0.3.0'" 9 | __maintainer__ = "Samuel Murail" 10 | __email__ = "samuel.murail@u-paris.fr" 11 | __status__ = "Prototype" 12 | -------------------------------------------------------------------------------- /docking_py/cli.py: -------------------------------------------------------------------------------- 1 | """Console script for docking_py.""" 2 | import argparse 3 | import sys 4 | 5 | 6 | def main(): 7 | """Console script for docking_py.""" 8 | parser = argparse.ArgumentParser() 9 | parser.add_argument('_', nargs='*') 10 | args = parser.parse_args() 11 | 12 | print("Arguments: " + str(args._)) 13 | print("Replace this message by putting your code into " 14 | "docking_py.cli.main") 15 | return 0 16 | 17 | 18 | if __name__ == "__main__": 19 | sys.exit(main()) # pragma: no cover 20 | -------------------------------------------------------------------------------- /docking_py/docking.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | """ Include the Docking class 4 | """ 5 | 6 | 7 | # standard library 8 | import os 9 | import sys 10 | import logging 11 | from shutil import copy as shutil_copy 12 | 13 | # 3rd party packages 14 | import numpy as np 15 | from os_command_py import os_command 16 | from pdb_manip_py import pdb_manip 17 | 18 | # Logging 19 | logger = logging.getLogger(__name__) 20 | 21 | 22 | def set_log_level(level=logging.INFO): 23 | """ 24 | setup log verbose level 25 | """ 26 | # Delete all handlers 27 | logger.handlers = [] 28 | # Set the logger level to INFO 29 | logger.setLevel(level) 30 | # Add sys.sdout as handler 31 | logger.addHandler(logging.StreamHandler(sys.stderr)) 32 | 33 | 34 | def show_log(): 35 | """ 36 | To use only with Doctest !!! 37 | Redirect logger output to sys.stdout 38 | """ 39 | set_log_level(logging.INFO) 40 | # Show pdb_manip Logs: 41 | pdb_manip.show_log() 42 | 43 | 44 | # Get Path of excecutables 45 | # Check if Readthedoc is launched skip the program path searching 46 | on_rtd = os.environ.get('READTHEDOCS') == 'True' 47 | if on_rtd: 48 | logger.info('Smina cannot be found') 49 | SMINA_LIG = '' 50 | SMINA_REC = '' 51 | SMINA_GPF = '' 52 | SMINA_PYTHON = '' 53 | else: 54 | 55 | SMINA_BIN = os_command.which('smina') 56 | logger.info("Smina executable is {}".format(SMINA_BIN)) 57 | 58 | VINA_BIN = os_command.which('vina') 59 | logger.info("Vina executable is {}".format(VINA_BIN)) 60 | 61 | QVINA_BIN = os_command.which('qvina2') 62 | logger.info("QVina executable is {}".format(QVINA_BIN)) 63 | 64 | QVINAW_BIN = os_command.which('qvinaw') 65 | logger.info("QVinaw executable is {}".format(QVINAW_BIN)) 66 | 67 | # MGLTools scripts: 68 | 69 | PREPARE_LIG = os_command.which('prepare_ligand4.py') 70 | logger.info("MGLTools ligand script is {}".format(PREPARE_LIG)) 71 | PREPARE_REC = os_command.which('prepare_receptor4.py') 72 | logger.info("MGLTools receptor script is {}".format(PREPARE_REC)) 73 | 74 | # Find python 2 from conda env 75 | # Try to fix issues with tox on Travic CI 76 | # Issue with os.getenv() with tox command 77 | # CONDA_PREFIX = os.getenv('CONDA_PREFIX') 78 | CONDA_PREFIX = '/'.join(SMINA_BIN.split('/')[:-2]) 79 | # With tox CONDA_PREFIX is None 80 | if CONDA_PREFIX is None: 81 | # CONDA_PREFIX = '/'.join(SMINA_BIN.split('/')[:-2]) 82 | CONDA_PREFIX = '/'.join(PREPARE_REC.split('/')[:-2]) 83 | 84 | if os_command.check_file_exist(os.path.join( 85 | CONDA_PREFIX, 'bin/python2.5')): 86 | MGLTOOL_PYTHON = os.path.join(CONDA_PREFIX, 'bin/python2.5') 87 | elif os_command.check_file_exist(os.path.join( 88 | CONDA_PREFIX, 'bin/python2.7')): 89 | MGLTOOL_PYTHON = os.path.join(CONDA_PREFIX, 'bin/python2.7') 90 | else: 91 | raise NameError('Could not find MGLTOOL_PYTHON in {}'.format( 92 | CONDA_PREFIX)) 93 | 94 | logger.info("Python Smina is {}".format(MGLTOOL_PYTHON)) 95 | 96 | PREPARE_GPF = os.path.join( 97 | CONDA_PREFIX, 98 | 'MGLToolsPckgs/AutoDockTools/Utilities24/prepare_gpf4.py') 99 | logger.info("MGLTools grid script is {}".format(PREPARE_GPF)) 100 | 101 | PREPARE_DPF = os.path.join( 102 | CONDA_PREFIX, 103 | 'MGLToolsPckgs/AutoDockTools/Utilities24/prepare_dpf42.py') 104 | logger.info("MGLTools docking prepare script is {}".format(PREPARE_DPF)) 105 | 106 | # Autodock part 107 | AUTOGRID_BIN = os_command.which('autogrid4') 108 | logger.info("Autogrid4 executable is {}".format(AUTOGRID_BIN)) 109 | 110 | AUTODOCK_BIN = os_command.which('autodock4') 111 | logger.info("Autodock4 executable is {}".format(AUTODOCK_BIN)) 112 | 113 | 114 | # Test folder path 115 | LIB_DIR = os.path.dirname(os.path.abspath(__file__)) 116 | TEST_PATH = os.path.join(LIB_DIR, "./tests/input/") 117 | 118 | 119 | class Docking: 120 | """Docking encapsulation class. 121 | 122 | This class can be used to launch vina, smina, qvina and qvinaw. 123 | 124 | :param name: generic name of the system 125 | :type name: str 126 | 127 | :param lig_pdb: path of the ligand coordinate file (.pdb) 128 | :type lig_pdb: str, optional 129 | 130 | :param rec_pdb: path of the receptor coordinate file (.pdb) 131 | :type rec_pdb: str, optional 132 | 133 | :param lig_pdbqt: path of the ligand coordinate file (.pdbqt) 134 | :type lig_pdbqt: str, optional 135 | 136 | :param rec_pdbqt: path of the receptor coordinate file (.pdbqt) 137 | :type rec_pdbqt: str, optional 138 | 139 | :param dock_pdb: path of the docking ligand coordinate file (.pdb) 140 | :type dock_pdb: str, optional 141 | 142 | :param dock_log: path of the docking log file (.log) 143 | :type dock_log: str, optional 144 | 145 | """ 146 | 147 | def __init__(self, name, lig_pdb=None, rec_pdb=None, 148 | lig_pdbqt=None, rec_pdbqt=None, log_level=logging.INFO): 149 | self.name = name 150 | self.lig_pdb = lig_pdb 151 | self.rec_pdb = rec_pdb 152 | self.lig_pdbqt = lig_pdbqt 153 | self.rec_pdbqt = rec_pdbqt 154 | self.dock_pdb = None 155 | self.dock_log = None 156 | self.dock_xml = None 157 | set_log_level(log_level) 158 | 159 | # @property is used to get the realtive path of this variables: 160 | # Usefull to print command in a shorter way 161 | @property 162 | def lig_pdb(self): 163 | if self._lig_pdb is not None: 164 | return os.path.relpath(self._lig_pdb) 165 | return None 166 | 167 | @property 168 | def lig_pdbqt(self): 169 | if self._lig_pdbqt is not None: 170 | return os.path.relpath(self._lig_pdbqt) 171 | return None 172 | 173 | @property 174 | def rec_pdb(self): 175 | if self._rec_pdb is not None: 176 | return os.path.relpath(self._rec_pdb) 177 | return None 178 | 179 | @property 180 | def rec_pdbqt(self): 181 | if self._rec_pdbqt is not None: 182 | return os.path.relpath(self._rec_pdbqt) 183 | return None 184 | 185 | @property 186 | def dock_pdb(self): 187 | if self._dock_pdb is not None: 188 | return os.path.relpath(self._dock_pdb) 189 | return None 190 | 191 | @property 192 | def dock_log(self): 193 | if self._dock_log is not None: 194 | return os.path.relpath(self._dock_log) 195 | return None 196 | 197 | @property 198 | def dock_xml(self): 199 | if self._dock_xml is not None: 200 | return os.path.relpath(self._dock_xml) 201 | return None 202 | 203 | @property 204 | def ref_lig_pdb(self): 205 | if self._ref_lig_pdb is not None: 206 | return os.path.relpath(self._ref_lig_pdb) 207 | return None 208 | 209 | @property 210 | def gpf(self): 211 | if self._gpf is not None: 212 | return os.path.relpath(self._gpf) 213 | return None 214 | 215 | # @var.setter is used to assign the full path to this variables: 216 | # Usefull if the working path is changed 217 | @lig_pdb.setter 218 | def lig_pdb(self, lig_pdb): 219 | if lig_pdb is not None: 220 | self._lig_pdb = os_command.full_path_and_check(lig_pdb) 221 | else: 222 | self._lig_pdb = None 223 | 224 | @lig_pdbqt.setter 225 | def lig_pdbqt(self, lig_pdbqt): 226 | if lig_pdbqt is not None: 227 | self._lig_pdbqt = os_command.full_path_and_check(lig_pdbqt) 228 | else: 229 | self._lig_pdbqt = None 230 | 231 | @rec_pdb.setter 232 | def rec_pdb(self, rec_pdb): 233 | if rec_pdb is not None: 234 | self._rec_pdb = os_command.full_path_and_check(rec_pdb) 235 | else: 236 | self._rec_pdb = None 237 | 238 | @rec_pdbqt.setter 239 | def rec_pdbqt(self, rec_pdbqt): 240 | if rec_pdbqt is not None: 241 | self._rec_pdbqt = os_command.full_path_and_check(rec_pdbqt) 242 | else: 243 | self._rec_pdbqt = None 244 | 245 | @dock_pdb.setter 246 | def dock_pdb(self, dock_pdb): 247 | if dock_pdb is not None: 248 | self._dock_pdb = os_command.full_path_and_check(dock_pdb) 249 | else: 250 | self._dock_pdb = None 251 | 252 | @dock_xml.setter 253 | def dock_xml(self, dock_xml): 254 | if dock_xml is not None: 255 | self._dock_xml = os_command.full_path_and_check(dock_xml) 256 | else: 257 | self._dock_xml = None 258 | 259 | @dock_log.setter 260 | def dock_log(self, dock_log): 261 | if dock_log is not None: 262 | self._dock_log = os_command.full_path_and_check(dock_log) 263 | else: 264 | self._dock_log = None 265 | 266 | @ref_lig_pdb.setter 267 | def ref_lig_pdb(self, ref_lig_pdb): 268 | if ref_lig_pdb is not None: 269 | self._ref_lig_pdb = os_command.full_path_and_check(ref_lig_pdb) 270 | else: 271 | self._ref_lig_pdb = None 272 | 273 | @gpf.setter 274 | def gpf(self, gpf): 275 | if gpf is not None: 276 | self._gpf = os_command.full_path_and_check(gpf) 277 | else: 278 | self._gpf = None 279 | 280 | def display(self): 281 | """Display defined attribute of the Docking object. 282 | """ 283 | 284 | # Order dict is only necessary for python 3.5, where dict are not 285 | # ordered. 286 | # This is only require for doctest 287 | 288 | numbermap = {'name': 1, 289 | '_lig_pdb': 2, 290 | '_lig_pdbqt': 3, 291 | '_rec_pdb': 4, 292 | '_rec_pdbqt': 5, 293 | '_ref_lig_pdb': 6, 294 | '_dock_pdb': 7, 295 | '_dock_log': 8, 296 | '_gpf': 9, 297 | 'affinity': 10, 298 | '_dock_xml': 11} 299 | 300 | attr_list = [attr for attr in vars(self) if not attr.startswith('__')] 301 | for attr in sorted(attr_list, key=numbermap.__getitem__): 302 | if attr[0] == "_": 303 | to_show = attr[1:] 304 | else: 305 | to_show = attr 306 | if getattr(self, to_show) is not None: 307 | print("{:12} : {}".format(to_show, getattr(self, to_show))) 308 | 309 | def view_dock(self, ref_pdb=None): 310 | """ Return a `nglview` object to view the object coordinates 311 | in a jupyter notebook with the module ``nglview``. 312 | 313 | MDAnalysis module is required. 314 | 315 | """ 316 | 317 | try: 318 | import nglview as nv 319 | except ImportError: 320 | logger.warning( 321 | 'Could not load nglview \nInstall it using conda:\n' + 322 | 'conda install -c conda-forge nglview') 323 | return 324 | 325 | try: 326 | import MDAnalysis as mda 327 | except ImportError: 328 | logger.warning( 329 | 'Could not load MDAnalysis \nInstall it using conda:\n' + 330 | 'conda install -c conda-forge MDAnalysis') 331 | return 332 | 333 | u = mda.Universe(self._dock_pdb) 334 | 335 | # Need simpletraj library 336 | view = nv.show_mdanalysis(u) 337 | view.add_representation('licorice', 'all') 338 | 339 | # In theory could be simpler 340 | # with add_component(self._rec_pdb) 341 | # However, works weardly depending on the location where the command 342 | # is launched 343 | 344 | if self._rec_pdb is not None: 345 | coor_rec = pdb_manip.Coor(self._rec_pdb) 346 | elif self._rec_pdbqt is not None: 347 | coor_rec = pdb_manip.Coor(self._rec_pdbqt) 348 | rec_str = nv.TextStructure(coor_rec.get_structure_string()) 349 | 350 | view.add_component(rec_str, default=False) 351 | view.component_1.add_representation( 352 | 'cartoon', selection='protein', color='blue') 353 | 354 | if ref_pdb is not None: 355 | coor_ref = pdb_manip.Coor(ref_pdb) 356 | ref_str = nv.TextStructure(coor_ref.get_structure_string()) 357 | view.add_component(ref_str, default=False) 358 | view.component_2.add_representation( 359 | 'licorice', selection='ligand', color='red') 360 | 361 | view.center() 362 | 363 | return view 364 | 365 | def prepare_ligand(self, lig_pdbqt=None, rigid=False, 366 | center=False, random_rot=False, 367 | check_file_out=True): 368 | """ Ligand preparation to `pdbqt` format using the `prepare_ligand4.py` 369 | command. 370 | Can center the ligand, could be usefull with autodock (issues when 371 | x,y,z > 100 Å). 372 | 373 | :param lig_pdbqt: output name 374 | :type lig_pdbqt: str, optional, default=None 375 | 376 | :param rigid: Flag to define if ligand is rigid 377 | :type rigid: bool, optional, default=False 378 | 379 | :param center: Flag to define if ligand have to centered 380 | :type center: bool, optional, default=False 381 | 382 | :param check_file_out: flag to check or not if file has already 383 | been created. If the file is present then the command break. 384 | :type check_file_out: bool, optional, default=True 385 | 386 | **Object requirement(s):** 387 | 388 | * self.lig_pdb 389 | 390 | **Object field(s) changed:** 391 | 392 | * self.lig_pdbqt 393 | 394 | :Example: 395 | 396 | >>> TEST_OUT = str(getfixture('tmpdir')) 397 | >>> coor_1hsg = pdb_manip.Coor(os.path.join(TEST_PATH, '1hsg.pdb'))\ 398 | #doctest: +ELLIPSIS 399 | Succeed to read file ...tests/input/1hsg.pdb , 1686 atoms found 400 | >>> lig_coor = coor_1hsg.select_part_dict(\ 401 | selec_dict={'res_name': 'MK1'}) 402 | >>> lig_atom_num = lig_coor.num 403 | >>> print('Ligand has {} atoms'.format(lig_atom_num)) 404 | Ligand has 45 atoms 405 | >>> out_lig = os.path.join(TEST_OUT,'lig.pdb') 406 | >>> lig_coor.write_pdb(out_lig) #doctest: +ELLIPSIS 407 | Succeed to save file .../lig.pdb 408 | >>> test_dock = Docking('test', lig_pdb=out_lig) 409 | >>> test_dock.prepare_ligand() #doctest: +ELLIPSIS 410 | python2... .../prepare_ligand4.py -l lig.pdb -B none -A\ 411 | hydrogens -o lig.pdbqt 412 | >>> coor_lig = pdb_manip.Coor(test_dock.lig_pdbqt)\ 413 | #doctest: +ELLIPSIS 414 | File name doesn't finish with .pdb read it as .pdb anyway 415 | Succeed to read file .../lig.pdbqt , 50 atoms found 416 | >>> test_dock.display() #doctest: +ELLIPSIS 417 | name : test 418 | lig_pdb : .../lig.pdb 419 | lig_pdbqt : .../lig.pdbqt 420 | ref_lig_pdb : .../lig.pdb 421 | """ 422 | 423 | # If lig_pdbqt is not defined use the lig_pdb name + .pdbqt 424 | if lig_pdbqt is None: 425 | lig_pdbqt = self._lig_pdb + 'qt' 426 | basename_pdbqt = os.path.basename(lig_pdbqt) 427 | 428 | # Check if output files exist: 429 | if check_file_out and os_command.check_file_and_create_path(lig_pdbqt): 430 | logger.info("prepare_ligand() not launched {} already" 431 | " exist".format(lig_pdbqt)) 432 | self.ref_lig_pdb = self._lig_pdb 433 | if random_rot: 434 | self.lig_pdb = self._lig_pdb[:-4] + '_rot.pdb' 435 | if center: 436 | self.lig_pdb = self._lig_pdb[:-4] + '_center.pdb' 437 | self.lig_pdbqt = lig_pdbqt 438 | return 439 | 440 | start_dir = os.path.abspath(".") 441 | 442 | # Create and go in out_folder: 443 | # prepare_ligand accept file name, not full path 444 | out_folder = os_command.get_directory(self._lig_pdb) 445 | os_command.create_and_go_dir(out_folder) 446 | 447 | option = [] 448 | if rigid: 449 | option.append('-Z') 450 | 451 | # Define reference pdb for ligand 452 | self.ref_lig_pdb = self._lig_pdb 453 | 454 | # Add random rot: 455 | if random_rot: 456 | lig_coor = pdb_manip.Coor(self._lig_pdb) 457 | tau_x, tau_y, tau_z = np.random.random_sample((3,)) * 360 458 | lig_coor.rotation_angle(tau_x, tau_y, tau_z) 459 | lig_coor.write_pdb(self._lig_pdb[:-4] + '_rot.pdb') 460 | self.lig_pdb = self._lig_pdb[:-4] + '_rot.pdb' 461 | 462 | # center ligand coordinates 463 | if center: 464 | lig_coor = pdb_manip.Coor(self._lig_pdb) 465 | lig_com = lig_coor.center_of_mass() 466 | lig_coor.translate(-lig_com) 467 | lig_coor.write_pdb(self._lig_pdb[:-4] + '_center.pdb') 468 | self.lig_pdb = self._lig_pdb[:-4] + '_center.pdb' 469 | 470 | cmd_lig = os_command.Command([MGLTOOL_PYTHON, PREPARE_LIG, 471 | "-l", self._lig_pdb, 472 | "-B", 'none', 473 | "-A", 'hydrogens', 474 | "-o", basename_pdbqt] + option) 475 | cmd_lig.display() 476 | cmd_lig.run() 477 | 478 | if os.path.abspath(lig_pdbqt) != os.path.abspath(basename_pdbqt): 479 | print("Something Wrong with lig_pdbqt path") 480 | 481 | self.lig_pdbqt = os.path.abspath(basename_pdbqt) 482 | 483 | os.chdir(start_dir) 484 | 485 | return 486 | 487 | def prepare_receptor(self, rec_pdbqt=None, check_file_out=True): 488 | """ Receptor preparation to `pdbqt` format using the `prepare_receptor4.py` 489 | command. 490 | 491 | :param rec_pdbqt: output name 492 | :type rec_pdbqt: str, optional, default=None 493 | 494 | :param check_file_out: flag to check or not if file has already been 495 | created. If the file is present then the command break. 496 | :type check_file_out: bool, optional, default=True 497 | 498 | **Object requirement(s):** 499 | 500 | * self.rec_pdb 501 | 502 | **Object field(s) changed:** 503 | 504 | * self.rec_pdbqt 505 | 506 | :Example: 507 | 508 | >>> TEST_OUT = str(getfixture('tmpdir')) 509 | >>> coor_1hsg = pdb_manip.Coor(os.path.join(TEST_PATH, '1hsg.pdb'))\ 510 | #doctest: +ELLIPSIS 511 | Succeed to read file .../1hsg.pdb , 1686 atoms found 512 | >>> # Keep only amino acid 513 | >>> rec_coor = coor_1hsg.select_part_dict(\ 514 | selec_dict={'res_name': pdb_manip.PROTEIN_RES}) 515 | >>> out_rec = os.path.join(TEST_OUT,'rec.pdb') 516 | >>> rec_coor.write_pdb(out_rec) #doctest: +ELLIPSIS 517 | Succeed to save file .../rec.pdb 518 | >>> rec_atom_num = rec_coor.num 519 | >>> print('Receptor has {} atoms'.format(rec_atom_num)) 520 | Receptor has 1514 atoms 521 | >>> test_dock = Docking('test', rec_pdb=out_rec) 522 | >>> test_dock.prepare_receptor() #doctest: +ELLIPSIS 523 | python2... .../prepare_receptor4.py -r .../rec.pdb -A checkhydrogens\ 524 | -o .../rec.pdbqt 525 | >>> coor_rec = pdb_manip.Coor(test_dock.rec_pdbqt)\ 526 | #doctest: +ELLIPSIS 527 | File name doesn't finish with .pdb read it as .pdb anyway 528 | Succeed to read file .../rec.pdbqt , 1844 atoms found 529 | >>> test_dock.display() #doctest: +ELLIPSIS 530 | name : test 531 | rec_pdb : .../rec.pdb 532 | rec_pdbqt : .../rec.pdbqt 533 | """ 534 | 535 | # If lig_pdbqt is not defined use the lig_pdb name + .pdbqt 536 | if rec_pdbqt is None: 537 | rec_pdbqt = self._rec_pdb + 'qt' 538 | 539 | # Check if output files exist: 540 | if check_file_out and os_command.check_file_and_create_path(rec_pdbqt): 541 | logger.info("prepare_receptor() not launched {} " 542 | "already exist".format(rec_pdbqt)) 543 | 544 | self.rec_pdbqt = rec_pdbqt 545 | return 546 | 547 | cmd_rec = os_command.Command([MGLTOOL_PYTHON, PREPARE_REC, 548 | "-r", self._rec_pdb, 549 | "-A", 'checkhydrogens', 550 | "-o", rec_pdbqt]) 551 | cmd_rec.display() 552 | cmd_rec.run() 553 | 554 | self.rec_pdbqt = rec_pdbqt 555 | return 556 | 557 | def prepare_grid(self, out_folder, gpf_out_prefix=None, 558 | spacing=0.375, grid_npts=None, center=None, 559 | check_file_out=True): 560 | """ Grid preparation 561 | 562 | Launch the ``prepare_gpf4.py`` command from MGLToolsPackage. 563 | And ``autogrid4``. 564 | 565 | """ 566 | 567 | start_dir = os.path.abspath(".") 568 | 569 | # Create and go in out_folder: 570 | # This is necessary for the autogrid creation 571 | os_command.create_and_go_dir(out_folder) 572 | 573 | if gpf_out_prefix is None: 574 | gpf_out_prefix = self.name 575 | gpf_out = gpf_out_prefix + '.gpf' 576 | 577 | logger.debug("prepare_grid gpf_out is: ", gpf_out) 578 | 579 | # Check if output files exist: 580 | if check_file_out and os_command.check_file_and_create_path(gpf_out): 581 | logger.info("prepare_grid() not launched {} " 582 | "already exist".format(gpf_out)) 583 | self.gpf = gpf_out 584 | os.chdir(start_dir) 585 | return 586 | 587 | # Add parameters for prepare_gpf 588 | option_gpf = [] 589 | 590 | if spacing != 0.375: 591 | option_gpf += ['-p', 'spacing={:.2f}'.format(spacing)] 592 | 593 | # Add grid points 594 | if grid_npts is None: 595 | grid_npts = self.rec_grid(spacing=spacing) 596 | logger.info('Grid points: {}'.format(grid_npts)) 597 | 598 | # Check that not point are above 255 599 | # Issues have been revaled with autodock gpu with more points 600 | clean_npts = [] 601 | for point in grid_npts: 602 | if point > 255: 603 | logger.warning('WARNING ! Each dimension of the grid must be' 604 | ' below 256. You should rise spacing !') 605 | clean_npts.append(255) 606 | else: 607 | clean_npts.append(point) 608 | 609 | option_gpf += ['-p', 'npts={:d},{:d},{:d}'.format(*clean_npts)] 610 | 611 | # Add grid points 612 | if center is None: 613 | center = self.rec_com() 614 | logger.info('Center: {}'.format(center)) 615 | 616 | option_gpf += ['-p', 'gridcenter={:.2f},{:.2f},{:.2f}'.format( 617 | *center)] 618 | 619 | # The rec.pdbqt should be in the same directory as gpf_out: 620 | if os.path.abspath( 621 | os.path.dirname(self._rec_pdbqt)) != os.path.abspath("."): 622 | shutil_copy(self._rec_pdbqt, os.path.abspath(".")) 623 | # The lig.pdbqt should be in the same directory as gpf_out: 624 | if os.path.abspath( 625 | os.path.dirname(self._lig_pdbqt)) != os.path.abspath("."): 626 | shutil_copy(self._lig_pdbqt, os.path.abspath(".")) 627 | 628 | cmd_grid = os_command.Command([MGLTOOL_PYTHON, PREPARE_GPF, 629 | "-r", os.path.basename(self._rec_pdbqt), 630 | "-l", os.path.basename(self._lig_pdbqt), 631 | "-o", gpf_out] + option_gpf) 632 | cmd_grid.display() 633 | cmd_grid.run() 634 | 635 | # grid_log = gpf_out[:-4] + '.log' 636 | grid_log = gpf_out_prefix + '.gpf_log' 637 | 638 | cmd_autogrid = os_command.Command([AUTOGRID_BIN, 639 | "-p", gpf_out, 640 | "-l", grid_log]) 641 | cmd_autogrid.display() 642 | cmd_autogrid.run() 643 | 644 | self.gpf = gpf_out 645 | 646 | os.chdir(start_dir) 647 | 648 | return 649 | 650 | def run_autodock_cpu(self, out_folder, dock_out_prefix=None, 651 | dock_log=None, dock_pdb=None, dock_xml=None, 652 | dpf_out=None, nrun=10, param_list=[], 653 | check_file_out=True): 654 | """ 655 | 1. Launch the ``prepare_dpf4.py`` command from MGLToolsPackage. 656 | 2. Launch ``autodock4`` 657 | 658 | This requires a gpf and associated map files, and ligand pdbqt 659 | It creates pose pdb + xml + dlg + dpf and smina like _log.txt files 660 | 661 | """ 662 | 663 | start_dir = os.path.abspath(".") 664 | 665 | # if dpf_out is None: 666 | # dpf_out = self.name + '_dock_param.dpf' 667 | # if dock_log is None: 668 | # dock_log = self.name + '_dock_log.dlg' 669 | # if dock_pdb is None: 670 | # dock_pdb = self.name + '_dock.pdb' 671 | 672 | # define common naming frame 673 | if dock_out_prefix is None: 674 | dock_out_prefix = self.name 675 | 676 | # Define dock_pdb name 677 | if dock_pdb is None: 678 | dock_pdb = dock_out_prefix + '.pdb' 679 | # Define dock_log name 680 | if dock_log is None: 681 | dock_log = dock_out_prefix + '.dlg' 682 | # Define dock_xml name 683 | if dock_xml is None: 684 | dock_xml = dock_out_prefix + '.xml' 685 | # Define dpf name 686 | if dpf_out is None: 687 | dpf_out = dock_out_prefix + '.dpf' 688 | 689 | logger.debug("autodock_cpu log is: {}".format(dock_log)) 690 | logger.debug("autodock_cpu pdb is: {}".format(dock_pdb)) 691 | logger.debug("autodock_cpu xml is: {}".format(dock_xml)) 692 | logger.debug("autodock_cpu dpf is: {}".format(dpf_out)) 693 | 694 | # Create and go in out_folder: 695 | # Run the autodock in the same directory as the dock_log file 696 | os_command.create_and_go_dir(out_folder) 697 | 698 | # Check if output files exist: 699 | # check_file_out = True 700 | if (check_file_out 701 | and os_command.check_file_and_create_path(dock_log) 702 | and os_command.check_file_and_create_path(dpf_out)): 703 | logger.info( 704 | "autodock_cpu: detected previous run log: {}. Will skip " 705 | "autodock calculations but perform result analysis" 706 | ".".format(dock_log)) 707 | self.dock_log = dock_log 708 | # self.dock_xml = dock_xml 709 | self.extract_autodock_pdb_affinity(os.path.basename(dock_pdb)) 710 | os.chdir(start_dir) 711 | return 712 | 713 | # Prepare docking: 714 | option = [] 715 | option += ['-p', 'ga_run={:d}'.format(nrun)] 716 | 717 | for parameter in param_list: 718 | option += ['-p', parameter] 719 | 720 | cmd_prep = os_command.Command([MGLTOOL_PYTHON, PREPARE_DPF, 721 | "-r", self._rec_pdbqt, 722 | "-l", self._lig_pdbqt, 723 | "-o", dpf_out] + option) 724 | cmd_prep.display() 725 | cmd_prep.run() 726 | logger.info("autodock_cpu: preparatory step completed ...\n") 727 | 728 | # Run autodock 729 | cmd_dock = os_command.Command([AUTODOCK_BIN, 730 | "-p", dpf_out, 731 | "-log", dock_log]) 732 | cmd_dock.display() 733 | cmd_dock.run() 734 | logger.info("autodock_cpu: autodock_cpu completed ...\n") 735 | 736 | self.dock_log = dock_log 737 | # self.dock_xml = dock_xml 738 | 739 | # Exract pdb + affinities form the log file: 740 | logger.info( 741 | "autodock_cpu: will extract affinities for {} ...\n".format( 742 | dock_pdb)) 743 | self.extract_autodock_pdb_affinity(os.path.basename(dock_pdb)) 744 | logger.info("autodock_cpu: affinities extracted ...\n") 745 | 746 | os.chdir(start_dir) 747 | return 748 | 749 | def run_autodock_gpu(self, out_folder, dock_out_prefix=None, 750 | dock_log=None, dock_pdb=None, dock_xml=None, 751 | nrun=10, check_file_out=True): 752 | """ 753 | Autodock GPU arguments: 754 | 755 | mandatory: 756 | -ffile ./input/1stp/derived/1stp_protein.maps.fld 757 | -lfile ./input/1stp/derived/1stp_ligand.pdbqt 758 | 759 | opyional: 760 | -nrun # LGA runs 1 761 | -nev # Score evaluations (max.) per LGA run 2500000 762 | -ngen # Generations (max.) per LGA run 27000 763 | -lsmet Local-search method sw (Solis-Wets) 764 | -lsit # Local-search iterations (max.) 300 765 | -psize Population size 150 766 | -mrat Mutation rate 2 (%) 767 | -crat Crossover rate 80 (%) 768 | -lsrat Local-search rate 6 (%) 769 | -trat Tournament (selection) rate 60 (%) 770 | -resnam Name for docking output log "docking" 771 | -hsym Handle symmetry in RMSD calc. 1 772 | 773 | This requires a gpf and associated map files, and ligand pdbqt 774 | It creates pose pdb + xml + dlg and smina like _log.txt files 775 | 776 | .. warning:: 777 | 778 | Difference between GPU and CPU version of autodock logs. 779 | Torsional Free Energy is not computed with GPU version. 780 | 781 | """ 782 | 783 | # Autodock part 784 | AUTODOCK_GPU_BIN = os_command.which('autodock_gpu_256wi') 785 | logger.info("Autodock GPU executable is {}".format(AUTODOCK_GPU_BIN)) 786 | 787 | # raise IOError("No receptor file defined") 788 | 789 | start_dir = os.path.abspath(".") 790 | 791 | # # Define dock_log name 792 | # if dock_log is None: 793 | # dock_log = self.name + '_dock_log.dlg' 794 | # # Define dock_pdb name 795 | # if dock_pdb is None: 796 | # dock_pdb = self.name + '_dock.pdb' 797 | 798 | # define common naming frame 799 | if dock_out_prefix is None: 800 | dock_out_prefix = self.name 801 | 802 | # Define dock_pdb name 803 | if dock_pdb is None: 804 | dock_pdb = dock_out_prefix + '.pdb' 805 | # Define dock_log name 806 | if dock_log is None: 807 | dock_log = dock_out_prefix + '.dlg' 808 | # Define dock_xml name 809 | if dock_xml is None: 810 | dock_xml = dock_out_prefix + '.xml' 811 | 812 | logger.debug("autodock_gpu log is: {}".format(dock_log)) 813 | logger.debug("autodock_gpu pdb is: {}".format(dock_pdb)) 814 | logger.debug("autodock_gpu xml is: {}".format(dock_xml)) 815 | 816 | # Create and go in out_folder: 817 | # Run the autodock in the same directory as the dock_log file 818 | logger.debug("autodock_gpu out_folder is: {}".format(out_folder)) 819 | os_command.create_and_go_dir(out_folder) 820 | 821 | # Check if output files exist: 822 | if check_file_out and os_command.check_file_and_create_path(dock_log): 823 | logger.info("run_autodock_gpu() not launched {} " 824 | "already exist".format(dock_log)) 825 | self.dock_log = dock_log 826 | self.dock_xml = dock_xml 827 | self.extract_autodock_pdb_affinity2(os.path.basename(dock_pdb)) 828 | os.chdir(start_dir) 829 | return 830 | 831 | gridfld = self.get_gridfld() 832 | 833 | cmd_dock = os_command.Command([AUTODOCK_GPU_BIN, 834 | "-ffile", gridfld, 835 | "-lfile", self._lig_pdbqt, 836 | "-nrun", str(nrun), 837 | "-resnam", dock_out_prefix]) 838 | # "-resnam", dock_log[:-4]]) 839 | cmd_dock.display() 840 | cmd_dock.run() 841 | 842 | self.dock_log = dock_log 843 | self.dock_xml = dock_xml 844 | 845 | # Exract pdb + affinities form the log file: 846 | # (cpu version does not generate an xml file) 847 | self.extract_autodock_pdb_affinity2(os.path.basename(dock_pdb)) 848 | 849 | os.chdir(start_dir) 850 | 851 | return 852 | 853 | def run_autodock(self, out_folder, dock_out_prefix=None, 854 | dock_log=None, dock_pdb=None, 855 | nrun=10, check_file_out=True, GPU=True): 856 | """ 857 | Run autodock with cpu or gpu if available 858 | 859 | """ 860 | 861 | if GPU: 862 | use_GPU = True 863 | try: 864 | logger.info("run_autodock: considering GPU version ...") 865 | AUTODOCK_GPU_BIN = os_command.which('autodock_gpu_256wi') 866 | except (IOError, OSError): 867 | use_GPU = False 868 | else: 869 | use_GPU = False 870 | 871 | if use_GPU: 872 | logger.info("Autodock GPU executable is {}".format( 873 | AUTODOCK_GPU_BIN)) 874 | self.run_autodock_gpu(out_folder=out_folder, 875 | dock_out_prefix=dock_out_prefix, 876 | dock_log=dock_log, 877 | dock_pdb=dock_pdb, 878 | nrun=nrun, 879 | check_file_out=check_file_out) 880 | else: 881 | logger.info("run_autodock: reverting to CPU version ...\n") 882 | self.run_autodock_cpu(out_folder=out_folder, 883 | dock_out_prefix=dock_out_prefix, 884 | dock_log=dock_log, 885 | dock_pdb=dock_pdb, 886 | nrun=nrun, 887 | check_file_out=check_file_out) 888 | logger.info("run_autodock: autodock completed ...\n") 889 | 890 | def extract_autodock_pdb_affinity(self, out_pdb, reorder=True): 891 | """ 892 | Extract pdb models from the the autodock log files. 893 | 894 | CPU version 895 | """ 896 | logger.info("extract_autodock_pdb_affinity:" 897 | " out_pdb (w) is: {}".format(out_pdb)) 898 | logger.info("extract_autodock_pdb_affinity:" 899 | " dock_log is: {}".format(self._dock_log)) 900 | 901 | logger.info("extract_autodock_pdb_affinity: parsing {}\n".format( 902 | out_pdb)) 903 | 904 | self.log_to_pdb(out_pdb) 905 | 906 | affinity_list = [ 907 | self.affinity[i]['affinity'] for i in self.affinity] 908 | 909 | if reorder: 910 | logger.info( 911 | "extract_autodock_pdb_affinity: Will reorder " 912 | "{} ...\n".format(out_pdb)) 913 | # Reorder coor models as function of affinity: 914 | dock_coor = pdb_manip.Multi_Coor(out_pdb) 915 | order_coor = pdb_manip.Multi_Coor() 916 | order_coor.crystal_pack = dock_coor.crystal_pack 917 | 918 | order_mode_info_dict = {} 919 | 920 | # best_affinity = min(affinity_list) 921 | infos = [] 922 | model = 1 923 | affinity = None 924 | logger.info("Will reorder {:d} pdbs ({:d} affinities)\n".format( 925 | len(dock_coor.coor_list), len(self.affinity))) 926 | 927 | for i in range(len(dock_coor.coor_list)): 928 | 929 | index = affinity_list.index(min(affinity_list)) 930 | affinity = min(affinity_list) 931 | affinity_list[index] = 10e10 932 | order_coor.coor_list.append(dock_coor.coor_list[index]) 933 | 934 | # print(i, index, len(dock_coor.coor_list)) 935 | 936 | if index <= len(dock_coor.coor_list) - 1: 937 | order_mode_info_dict[i + 1] = self.affinity[index + 1] 938 | 939 | infos.append({"mode": model, 940 | "run": index + 1, 941 | "affinity": float(affinity), 942 | "rmsdlb": float(0.0), 943 | "rmsdub": float(0.0)}) 944 | model += 1 945 | 946 | # order_coor.write_pdb(out_pdb+"_reorder.pdb") 947 | order_coor.write_pdb(out_pdb, check_file_out=False) 948 | self.affinity = order_mode_info_dict 949 | logger.info("reordered affinities: {}".format(self.affinity)) 950 | 951 | logger.info( 952 | "extract_autodock_pdb_affinity: Will output affinities ...\n") 953 | self.write_out_affinities(out_pdb.replace(".pdb", "_log.txt"), infos) 954 | 955 | return 956 | 957 | def extract_autodock_pdb_affinity2(self, out_pdb, reorder=True): 958 | """ 959 | Extract pdb models from the the autodock log files. 960 | Makes use of the xml generated by the gpu version. 961 | 962 | GPU version 963 | """ 964 | 965 | logger.info("extract_autodock_pdb_affinity:" 966 | " out_pdb (w) is: {}".format(out_pdb)) 967 | logger.info("extract_autodock_pdb_affinity:" 968 | " dock_log is: {}".format(self._dock_log)) 969 | logger.info("extract_autodock_pdb_affinity:" 970 | " dock_xml is: {}".format(self._dock_xml)) 971 | 972 | self.log_to_pdb(out_pdb) 973 | 974 | if reorder: 975 | # Reorder coor models as function of affinity: 976 | dock_coor = pdb_manip.Multi_Coor(out_pdb) 977 | order_coor = pdb_manip.Multi_Coor() 978 | order_coor.crystal_pack = dock_coor.crystal_pack 979 | 980 | order_mode_info_dict = {} 981 | from xml.etree import ElementTree as ET 982 | tree = ET.parse(self._dock_xml) 983 | root = tree.getroot() 984 | 985 | # best_affinity = min(affinity_list) 986 | 987 | model = 1 988 | infos = [] 989 | for p in root.findall('.//run'): 990 | index = int(p.attrib['run']) - 1 991 | # print(model, index) 992 | order_coor.coor_list.append(dock_coor.coor_list[index]) 993 | order_mode_info_dict[model] = self.affinity[index + 1] 994 | infos.append({"mode": model, 995 | "run": p.attrib['run'], 996 | "affinity": float(p.attrib['binding_energy']), 997 | "rmsdlb": float(p.attrib['cluster_rmsd']), 998 | "rmsdub": float(p.attrib['reference_rmsd'])}) 999 | model += 1 1000 | 1001 | # shutil_copy(out_pdb, out_ori_pdb) 1002 | order_coor.write_pdb(out_pdb, check_file_out=False) 1003 | self.affinity = order_mode_info_dict # No use for merge 1004 | # print("reordered affinities:", str(infos)) 1005 | 1006 | self.write_out_affinities(out_pdb.replace(".pdb", "_log.txt"), infos) 1007 | 1008 | return 1009 | 1010 | def log_to_pdb(self, out_pdb): 1011 | """ 1012 | Read autodock log, extract ligand model coordinates and extract 1013 | affinities. 1014 | 1015 | :param out_pdb: output pdb file 1016 | :type out_pdb: str 1017 | 1018 | .. warning:: 1019 | 1020 | Difference between GPU and CPU version of autodock logs. 1021 | Torsional Free Energy is not computed with GPU version. 1022 | 1023 | """ 1024 | 1025 | filout = open(out_pdb, "w") 1026 | 1027 | mode_info_dict = {} 1028 | affinity_list = [] 1029 | infos = [] 1030 | model = 0 1031 | affinity = None 1032 | 1033 | with open(self._dock_log, "r") as pdbfile: 1034 | for line in pdbfile: 1035 | if line.startswith("DOCKED: "): 1036 | if (model != 0) and (affinity is not None): 1037 | infos.append({"mode": model, 1038 | "run": model, 1039 | "affinity": affinity, 1040 | "rmsdlb": float(0.0), 1041 | "rmsdub": float(0.0)}) 1042 | affinity = None 1043 | 1044 | # print(line[8:16].strip()) 1045 | if line[8:16].strip() in ['ATOM', 'HETATM', 1046 | 'MODEL', 'ENDMDL']: 1047 | filout.write(line[8:]) 1048 | if line[8:16].strip() == 'MODEL': 1049 | model = int(line[20:]) 1050 | affinity = None 1051 | if line.startswith("DOCKED: USER Estimated Free " + 1052 | "Energy of Binding ="): 1053 | affinity = float(line.split()[8]) 1054 | affinity_list.append(affinity) 1055 | mode_info_dict[model] = {'affinity': affinity} 1056 | 1057 | filout.write("TER\n") 1058 | filout.close() 1059 | 1060 | self.affinity = mode_info_dict 1061 | self.dock_pdb = out_pdb 1062 | 1063 | return 1064 | 1065 | def write_out_affinities(self, fn, affinities): 1066 | """ Save affinities in a file 1067 | """ 1068 | header = "mode | affinity | dist from best mode\n" +\ 1069 | " | (kcal/mol) | rmsd l.b.| rmsd u.b.\n" +\ 1070 | "-----+------------+----------+----------\n" 1071 | 1072 | filout = open(fn, "w") 1073 | filout.write(header) 1074 | for aff in affinities: 1075 | # f.write("%-5d %-.1f \n" % (aff[0], aff[1])) 1076 | filout.write("{:5d} {:6.2f} {}\n".format( 1077 | aff["mode"], aff["affinity"], aff["run"])) 1078 | filout.close() 1079 | 1080 | return 1081 | 1082 | def get_gridfld(self): 1083 | """ 1084 | Get ``gridfld`` from the ``.gpf`` file. 1085 | """ 1086 | 1087 | with open(self._gpf, "r") as file: 1088 | for line in file: 1089 | if line.startswith('gridfld'): 1090 | gridfld = line.split()[1] 1091 | 1092 | return gridfld 1093 | 1094 | def rec_com(self): 1095 | """ Get center of mass of the receptor pdb file. 1096 | """ 1097 | if self._rec_pdb is not None: 1098 | rec_com = pdb_manip.Coor(self.rec_pdb) 1099 | elif self._rec_pdbqt is not None: 1100 | rec_com = pdb_manip.Coor(self.rec_pdbqt) 1101 | else: 1102 | raise IOError("No receptor file defined") 1103 | 1104 | rec_com = rec_com.center_of_mass() 1105 | return rec_com 1106 | 1107 | def rec_grid(self, buffer_space=30, spacing=1.0): 1108 | """ Compute grid from the receptor pdb file. 1109 | """ 1110 | if self._rec_pdb is not None: 1111 | rec_com = pdb_manip.Coor(self._rec_pdb) 1112 | elif self._rec_pdbqt is not None: 1113 | rec_com = pdb_manip.Coor(self._rec_pdbqt) 1114 | else: 1115 | raise IOError("No receptor file defined") 1116 | 1117 | grid_npts = ((np.ceil(rec_com.get_box_dim()) + 1118 | buffer_space) / spacing).astype(int) 1119 | return grid_npts 1120 | 1121 | def run_autodock_docking(self, out_pdb, log=None, prepare_grid=True, 1122 | num_modes=100, center=None, spacing=0.375, 1123 | grid_size=None, grid_max_points=None, 1124 | check_file_out=True, GPU=True): 1125 | """ 1126 | Run docking using autodock. 1127 | 1128 | :param out_pdb: PDB output name 1129 | :type out_pdb: str 1130 | 1131 | :param log: Log ouput name 1132 | :type log: str, optional, default=None 1133 | 1134 | :param prepare_grid: perform grid setup 1135 | :type prepare_grid: bool, optional, default=True 1136 | 1137 | :param num_modes: maximum number of binding modes to generate 1138 | :type num_modes: int, optional, default=100 1139 | 1140 | :param center: coordinate of the center (x, y, z, Angstroms) 1141 | :type center: list, optional, default=None 1142 | 1143 | :param grid_size: size in the docking box (x, y, z, Angstroms) 1144 | :type grid_size: list, optional, default=None 1145 | 1146 | :param grid_max_points: max number of grid points per dimension 1147 | (256 for GPU) 1148 | :type grid_max_points: int, optional, default=None 1149 | 1150 | :param check_file_out: flag to check or not if file has already been 1151 | created. If the file is present then the command break. 1152 | :type check_file_out: bool, optional, default=True 1153 | 1154 | 1155 | **Object requirement(s):** 1156 | 1157 | * self.lig_pdbqt 1158 | * self.rec_pdbqt 1159 | 1160 | **Object field(s) changed:** 1161 | 1162 | * self.dock_pdb 1163 | * self.dock_log 1164 | 1165 | :Example: 1166 | 1167 | """ 1168 | 1169 | # Check if output files exist: 1170 | if check_file_out and os_command.check_file_and_create_path(out_pdb): 1171 | logger.info("run_autodock_docking() not launched {} already" 1172 | " exists".format(out_pdb)) 1173 | self.dock_pdb = out_pdb 1174 | self.dock_log = log 1175 | return 1176 | 1177 | logger.info("run_autodock_docking: preliminary grid analysis ...\n") 1178 | 1179 | # Prepare grid: 1180 | if grid_size is not None: 1181 | grid_npts = [int(i / spacing) + 1 for i in grid_size] 1182 | # MUST BE A CHECK TO INCREASE SPACING IF NEEDED ... 1183 | if grid_max_points is not None: 1184 | cur_spacing = spacing 1185 | for i, npts in enumerate(grid_npts): 1186 | if npts > grid_max_points: 1187 | lspacing = (grid_size + spacing) / \ 1188 | float(grid_max_points) 1189 | if lspacing > cur_spacing: 1190 | cur_spacing = lspacing 1191 | if cur_spacing > spacing: 1192 | spacing = cur_spacing 1193 | grid_npts = [int(i / spacing) + 1 for i in grid_size] 1194 | logger.info("Increasing grid spacing up to {:f} to " 1195 | "preserve grid_max_points as {:d}".format( 1196 | spacing, grid_max_points)) 1197 | else: 1198 | grid_npts = None 1199 | 1200 | out_folder = os_command.get_directory(out_pdb) 1201 | basename = os.path.basename(out_pdb).replace(".pdb", "") 1202 | 1203 | logger.info("run_autodock_docking log is: {}".format(log)) 1204 | logger.info("autodock_docking pdb is: {}".format(out_pdb)) 1205 | 1206 | if prepare_grid: 1207 | logger.info("Will prepare grid ...\n") 1208 | self.prepare_grid(out_folder, 1209 | gpf_out_prefix=basename, 1210 | spacing=spacing, grid_npts=grid_npts, 1211 | center=center, 1212 | check_file_out=check_file_out) 1213 | 1214 | logger.info("run_autodock_docking: Will run autodock...\n") 1215 | self.run_autodock(out_folder, nrun=num_modes, 1216 | dock_out_prefix=basename, 1217 | dock_pdb=out_pdb, 1218 | dock_log=None, 1219 | check_file_out=check_file_out, 1220 | GPU=GPU) 1221 | logger.info("run_autodock_docking: autodock run terminated...\n") 1222 | 1223 | return 1224 | 1225 | def run_docking(self, out_pdb, log=None, dock_bin='vina', 1226 | num_modes=100, energy_range=10, exhaustiveness=16, 1227 | cpu=None, seed=None, autobox=False, 1228 | center=None, grid_size=None, min_rmsd_filter=None, 1229 | scoring=None, check_file_out=True): 1230 | """ 1231 | Run docking using vina, qvina, qvinaw or smina. 1232 | 1233 | :param out_pdb: PDB output name 1234 | :type out_pdb: str 1235 | 1236 | :param log: Log ouput name 1237 | :type log: str, optional, default=None 1238 | 1239 | :param dock_bin: Docking software name ('vina', 'qvina', 'qvinaw', 1240 | 'smina') 1241 | :type dock_bin: str, optional, default='vina' 1242 | 1243 | :param num_modes: maximum number of binding modes to generate 1244 | :type num_modes: int, optional, default=100 1245 | 1246 | :param energy_range: maximum energy difference between the best binding 1247 | mode and the worst one displayed (kcal/mol) 1248 | :type energy_range: int, optional, default=10 1249 | 1250 | :param exhaustiveness: exhaustiveness of the global search (roughly 1251 | proportional to time): 1+ 1252 | :type exhaustiveness: int, optional, default=16 1253 | 1254 | :param cpu: the number of CPUs to use (the default is to try 1255 | to detect the number of CPUs or, failing that, use 1) 1256 | :type cpu: int, optional, default=None 1257 | 1258 | :param seed: explicit random seed 1259 | :type seed: int, optional, default=None 1260 | 1261 | :param autobox: Flag to use ligand to define the docking box 1262 | :type autobox: bool, optional, default=False 1263 | 1264 | :param center: coordinate of the center (x, y, z, Angstroms) 1265 | :type center: list, optional, default=None 1266 | 1267 | :param grid_size: size in the docking box (x, y, z, Angstroms) 1268 | :type grid_size: list, optional, default=None 1269 | 1270 | :param check_file_out: flag to check or not if file has already been 1271 | created. If the file is present then the command break. 1272 | :type check_file_out: bool, optional, default=True 1273 | 1274 | 1275 | **Object requirement(s):** 1276 | 1277 | * self.lig_pdbqt 1278 | * self.rec_pdbqt 1279 | 1280 | **Object field(s) changed:** 1281 | 1282 | * self.dock_pdb 1283 | * self.dock_log 1284 | 1285 | :Example: 1286 | 1287 | """ 1288 | 1289 | # If log is not defined use out_pdb minus the '.pdb' and 1290 | # plus '_log.txt' 1291 | if log is None: 1292 | log = out_pdb[:-4] + '_log.txt' 1293 | 1294 | if dock_bin == 'vina': 1295 | DOCK_BIN = VINA_BIN 1296 | elif dock_bin == 'qvina': 1297 | DOCK_BIN = QVINA_BIN 1298 | elif dock_bin == 'qvinaw': 1299 | DOCK_BIN = QVINAW_BIN 1300 | elif dock_bin == 'smina': 1301 | DOCK_BIN = SMINA_BIN 1302 | else: 1303 | logger.error('Choose an appropriate docking software among:\n' 1304 | '- vina\n- qvina\n- qvinaw\n- smina\n') 1305 | return 1306 | 1307 | # Check if output files exist: 1308 | if check_file_out and os_command.check_file_and_create_path(out_pdb): 1309 | logger.info("run_docking() not launched {} already" 1310 | " exists".format(out_pdb)) 1311 | self.dock_pdb = out_pdb 1312 | self.dock_log = log 1313 | self.extract_affinity() 1314 | return 1315 | 1316 | option = [] 1317 | if autobox: 1318 | if dock_bin != 'smina': 1319 | logger.error('autobox option is only available with smina') 1320 | raise ValueError 1321 | 1322 | option += ['--autobox_ligand', self._lig_pdbqt] 1323 | option += ['--autobox_add', str(10.0)] 1324 | 1325 | # Define grid size: 1326 | if grid_size is None: 1327 | grid_npts = self.rec_grid() 1328 | logger.info('Grid points: {}'.format(grid_size)) 1329 | else: 1330 | grid_npts = np.array(grid_size).astype(int) 1331 | 1332 | option += ["--size_x", '{:.2f}'.format(grid_npts[0]), 1333 | "--size_y", '{:.2f}'.format(grid_npts[1]), 1334 | "--size_z", '{:.2f}'.format(grid_npts[2])] 1335 | 1336 | # Define grid center: 1337 | if center is None: 1338 | center = self.rec_com() 1339 | 1340 | option += ["--center_x", '{:.2f}'.format(center[0]), 1341 | "--center_y", '{:.2f}'.format(center[1]), 1342 | "--center_z", '{:.2f}'.format(center[2])] 1343 | 1344 | # Define cpu number: 1345 | if cpu is not None: 1346 | option += ["--cpu", str(cpu)] 1347 | 1348 | # Define Seed: 1349 | if seed is not None: 1350 | option += ["--seed", str(seed)] 1351 | 1352 | if dock_bin == 'smina': 1353 | if min_rmsd_filter is not None: 1354 | option += ["--min_rmsd_filter", str(min_rmsd_filter)] 1355 | if scoring is not None: 1356 | option += ["--scoring", str(scoring)] 1357 | 1358 | cmd_dock = os_command.Command([DOCK_BIN, 1359 | "--ligand", self._lig_pdbqt, 1360 | "--receptor", self._rec_pdbqt, 1361 | "--log", log, 1362 | "--num_modes", str(num_modes), 1363 | "--exhaustiveness", str(exhaustiveness), 1364 | "--energy_range", str(energy_range), 1365 | "--out", out_pdb] + option) 1366 | cmd_dock.display() 1367 | cmd_dock.run() 1368 | 1369 | self.dock_pdb = out_pdb 1370 | self.dock_log = log 1371 | self.extract_affinity() 1372 | 1373 | return 1374 | 1375 | def compute_dock_rmsd(self, ref_lig_pdb, selec_dict={}): 1376 | """ 1377 | Compute RMSD from docking pdb to ``ref_lig_pdb``. By 1378 | default use all atoms for RMSD calculation. 1379 | To use only Calpha atoms define ``selec_dict={'name':['CA']}``. 1380 | 1381 | :param ref_lig_pdb: PDB reference file 1382 | :type ref_lig_pdb: str 1383 | 1384 | :param selec_dict: Selection for RMSD calculation 1385 | :type selec_dict: dict, optional, default={} 1386 | 1387 | 1388 | :return: RMSD list 1389 | :rtype: list 1390 | 1391 | """ 1392 | 1393 | cryst_coor = pdb_manip.Coor(ref_lig_pdb) 1394 | 1395 | dock_coor = pdb_manip.Multi_Coor(self._dock_pdb) 1396 | dock_coor.write_pdb(self._dock_pdb[:-4] + '_vmd.pdb') 1397 | self.dock_pdb = self._dock_pdb[:-4] + '_vmd.pdb' 1398 | 1399 | rmsd = dock_coor.compute_rmsd_to(cryst_coor, selec_dict=selec_dict) 1400 | 1401 | return rmsd 1402 | 1403 | def extract_affinity(self): 1404 | """ 1405 | Extract affinity from the docking ``.log`` file. 1406 | 1407 | :return: Affinity and RMSD informations as a dictionnary 1408 | :rtype: dict 1409 | 1410 | """ 1411 | 1412 | mode_read = False 1413 | 1414 | mode_info_dict = {} 1415 | 1416 | with open(self._dock_log, "r") as dock_log: 1417 | for line in dock_log: 1418 | if line.startswith('-----+------------+----------+----------'): 1419 | mode_read = True 1420 | continue 1421 | if mode_read and not line.startswith('Writing'): 1422 | line_split = line.split() 1423 | mode_info_dict[int(line_split[0])] = { 1424 | 'affinity': float(line_split[1]), 1425 | 'rmsd_low': float(line_split[2]), 1426 | 'rmsd_high': float(line_split[3])} 1427 | 1428 | self.affinity = mode_info_dict 1429 | return 1430 | 1431 | def extract_lig_rec_pdb(self, coor_in, folder_out, rec_select_dict, 1432 | lig_select_dict): 1433 | """ 1434 | * Extract receptor and ligand coordinates from a coor file 1435 | * remove alternative location 1436 | * Keep only amino acid residues 1437 | * Save both coordinates and add it in the object 1438 | 1439 | 1440 | :param pdb_id: PDB ID 1441 | :type pdb_id: str 1442 | 1443 | :param rec_chain: Chain(s) of the receptor 1444 | :type rec_chain: list of str 1445 | 1446 | :param lig_chain: Chain(s) of the ligand 1447 | :type lig_chain: list of str 1448 | 1449 | **Object field(s) changed:** 1450 | 1451 | * self.rec_pdb 1452 | * self.lig_pdb 1453 | 1454 | :Example: 1455 | 1456 | >>> TEST_OUT = str(getfixture('tmpdir')) 1457 | >>> dock_1hsg = Docking(name='1hsg') 1458 | >>> dock_1hsg.extract_lig_rec_pdb(os.path.join(TEST_PATH, '1hsg.pdb'),\ 1459 | TEST_OUT, {'res_name': pdb_manip.PROTEIN_RES}, {'res_name': 'MK1'})\ 1460 | #doctest: +ELLIPSIS 1461 | Succeed to read file ...1hsg.pdb , 1686 atoms found 1462 | Succeed to save file ...1hsg_rec.pdb 1463 | Succeed to save file ...1hsg_input_lig.pdb 1464 | >>> coor_lig = pdb_manip.Coor(dock_1hsg.lig_pdb) #doctest: +ELLIPSIS 1465 | Succeed to read file ...1hsg_input_lig.pdb , 45 atoms found 1466 | >>> coor_rec = pdb_manip.Coor(dock_1hsg.rec_pdb) #doctest: +ELLIPSIS 1467 | Succeed to read file ...1hsg_rec.pdb , 1514 atoms found 1468 | 1469 | """ 1470 | 1471 | # Read pdb: 1472 | comp_coor = pdb_manip.Coor(coor_in) 1473 | 1474 | # Remove alter_loc B, C, D 1475 | alter_loc_bcd = comp_coor.get_index_selection( 1476 | {'alter_loc': ['B', 'C', 'D']}) 1477 | comp_coor.del_atom_index(index_list=alter_loc_bcd) 1478 | comp_coor.change_pdb_field(change_dict={"alter_loc": ""}) 1479 | 1480 | # Extract receptor pdb 1481 | out_rec = os.path.join(folder_out, '{}_rec.pdb'.format(self.name)) 1482 | rec_coor = comp_coor.select_part_dict( 1483 | rec_select_dict) 1484 | rec_coor.write_pdb(out_rec) 1485 | self.rec_pdb = out_rec 1486 | 1487 | # Extract ligand pdb 1488 | out_lig = os.path.join(folder_out, 1489 | '{}_input_lig.pdb'.format(self.name)) 1490 | lig_coor = comp_coor.select_part_dict( 1491 | lig_select_dict) 1492 | lig_coor.write_pdb(out_lig) 1493 | self.lig_pdb = out_lig 1494 | 1495 | def extract_receptor(self, coor_in, folder_out, 1496 | rec_select_dict): 1497 | """ 1498 | * Extract receptor coordinates 1499 | * remove alternative location 1500 | * Keep only amino acid residues 1501 | * align structure on ref 1502 | * Save coordinates and add it in the object 1503 | 1504 | 1505 | :param pdb_id: PDB ID 1506 | :type pdb_id: str 1507 | 1508 | :param ref_pdb: Reference coordinates file 1509 | :type ref_pdb: str 1510 | 1511 | :param rec_chain: Chain(s) of the receptor 1512 | :type rec_chain: list of str 1513 | 1514 | :param rec_chain: Chain(s) of the reference file 1515 | :type rec_chain: list of str 1516 | 1517 | **Object field(s) changed:** 1518 | 1519 | * self.rec_pdb 1520 | 1521 | :Example: 1522 | 1523 | >>> TEST_OUT = str(getfixture('tmpdir')) 1524 | >>> dock_1hsg = Docking(name='1hsg') 1525 | >>> dock_1hsg.extract_receptor(os.path.join(TEST_PATH, '1hsg.pdb'),\ 1526 | TEST_OUT, {'res_name': pdb_manip.PROTEIN_RES})\ 1527 | #doctest: +ELLIPSIS 1528 | Succeed to read file ...1hsg.pdb , 1686 atoms found 1529 | Succeed to save file ...1hsg_rec.pdb 1530 | >>> coor_rec = pdb_manip.Coor(dock_1hsg.rec_pdb) #doctest: +ELLIPSIS 1531 | Succeed to read file ...1hsg_rec.pdb , 1514 atoms found 1532 | 1533 | """ 1534 | 1535 | # Read pdb: 1536 | comp_coor = pdb_manip.Coor(coor_in) 1537 | 1538 | # Remove alter_loc B, C, D 1539 | alter_loc_bcd = comp_coor.get_index_selection( 1540 | {'alter_loc': ['B', 'C', 'D']}) 1541 | comp_coor.del_atom_index(index_list=alter_loc_bcd) 1542 | comp_coor.change_pdb_field(change_dict={"alter_loc": ""}) 1543 | 1544 | # Extract receptor pdb 1545 | rec_coor = comp_coor.select_part_dict(rec_select_dict) 1546 | 1547 | out_rec = os.path.join(folder_out, '{}_rec.pdb'.format(self.name)) 1548 | rec_coor.write_pdb(out_rec) 1549 | self.rec_pdb = out_rec 1550 | 1551 | return 1552 | 1553 | def align_receptor(self, ref_pdb, chain_ref=['A'], chain_rec=['A']): 1554 | """ 1555 | Align self.rec_pdb to ref_pdb. 1556 | 1557 | :Example: 1558 | 1559 | >>> pdb_manip.show_log() 1560 | >>> TEST_OUT = str(getfixture('tmpdir')) 1561 | >>> dock_4yob = Docking(name='4yob') 1562 | >>> dock_4yob.extract_receptor(os.path.join(TEST_PATH, '4yob.pdb'),\ 1563 | TEST_OUT, {'res_name': pdb_manip.PROTEIN_RES})\ 1564 | #doctest: +ELLIPSIS 1565 | Succeed to read file ...4yob.pdb , 916 atoms found 1566 | Succeed to save file ...4yob_rec.pdb 1567 | >>> dock_4yob.align_receptor(os.path.join(TEST_PATH, '1hsg.pdb')) 1568 | Succeed to read file .../4yob_rec.pdb , 760 atoms found 1569 | Succeed to read file .../1hsg.pdb , 1686 atoms found 1570 | PQITLWKRPIVTIKIGGQLKEALLNTGADDTVFEEVNLPGRWKPKLIGGIGGFVKVRQYDQVPIEICGHKVIGTVLVGPT 1571 | ******|**|**************|*******|**||********|*******|*******| ******\ 1572 | *|********* 1573 | PQITLWQRPLVTIKIGGQLKEALLDTGADDTVLEEMSLPGRWKPKMIGGIGGFIKVRQYDQILIEICGHKAIGTVLVGPT 1574 | 1575 | PTNVIGRNLMTQIGCTLNF 1576 | *|*|*****|********* 1577 | PVNIIGRNLLTQIGCTLNF 1578 | 1579 | Succeed to save file ...4yob_rec.pdb 1580 | >>> coor_holo = pdb_manip.Coor(os.path.join(TEST_PATH, '1hsg.pdb'))\ 1581 | #doctest: +ELLIPSIS 1582 | Succeed to read file ...1hsg.pdb , 1686 atoms found 1583 | >>> coor_rec = pdb_manip.Coor(dock_4yob.rec_pdb) #doctest: +ELLIPSIS 1584 | Succeed to read file ...4yob_rec.pdb , 760 atoms found 1585 | >>> rmsd = coor_rec.compute_rmsd_to(coor_holo,\ 1586 | selec_dict={'name': ['CA'], 'chain':['A']}) 1587 | >>> print('RMSD after alignement is {:.2f} Å'.format(rmsd)) 1588 | RMSD after alignement is 1.50 Å 1589 | """ 1590 | 1591 | # Extract receptor pdb 1592 | rec_coor = pdb_manip.Coor(self._rec_pdb) 1593 | 1594 | # Read ref_pdb 1595 | ref_coor = pdb_manip.Coor(ref_pdb) 1596 | # Keep only amino acid 1597 | aa_ref_coor = ref_coor.select_part_dict( 1598 | selec_dict={'res_name': pdb_manip.PROTEIN_RES}) 1599 | # Remove alter_loc B, C, D 1600 | alter_loc_bcd = aa_ref_coor.get_index_selection( 1601 | {'alter_loc': ['B', 'C', 'D']}) 1602 | aa_ref_coor.del_atom_index(index_list=alter_loc_bcd) 1603 | 1604 | rec_coor.align_seq_coor_to(aa_ref_coor, chain_1=chain_rec, 1605 | chain_2=chain_ref) 1606 | rec_coor.write_pdb(self._rec_pdb, check_file_out=False) 1607 | 1608 | return 1609 | 1610 | def extract_ligand(self, coor_in, folder_out, lig_select_dict): 1611 | """ 1612 | * Extract ligand coordinates 1613 | * remove alternative location 1614 | * Save coordinates and add it in the object 1615 | 1616 | **Object field(s) changed:** 1617 | 1618 | * self.lig_pdb 1619 | 1620 | :Example: 1621 | 1622 | >>> TEST_OUT = str(getfixture('tmpdir')) 1623 | >>> dock_1hsg = Docking(name='1hsg') 1624 | >>> dock_1hsg.extract_ligand(os.path.join(TEST_PATH, '1hsg.pdb'),\ 1625 | TEST_OUT, {'res_name': 'MK1'})\ 1626 | #doctest: +ELLIPSIS 1627 | Succeed to read file ...1hsg.pdb , 1686 atoms found 1628 | Succeed to save file ...1hsg_lig.pdb 1629 | >>> coor_lig = pdb_manip.Coor(dock_1hsg.lig_pdb) #doctest: +ELLIPSIS 1630 | Succeed to read file ...1hsg_lig.pdb , 45 atoms found 1631 | 1632 | """ 1633 | 1634 | # Get pdb: 1635 | comp_coor = pdb_manip.Coor(coor_in) 1636 | 1637 | # Remove alter_loc B, C, D 1638 | alter_loc_bcd = comp_coor.get_index_selection( 1639 | {'alter_loc': ['B', 'C', 'D']}) 1640 | 1641 | comp_coor.del_atom_index(index_list=alter_loc_bcd) 1642 | comp_coor.change_pdb_field(change_dict={"alter_loc": ""}) 1643 | 1644 | # Extract ligand pdb 1645 | out_lig = os.path.join(folder_out, '{}_lig.pdb'.format(self.name)) 1646 | lig_coor = comp_coor.select_part_dict( 1647 | selec_dict=lig_select_dict) 1648 | 1649 | lig_coor.write_pdb(out_lig) 1650 | self.lig_pdb = out_lig 1651 | 1652 | def random_rot_ligand(self): 1653 | """ 1654 | * Do a random rotation on ligand 1655 | 1656 | **Object field(s) changed:** 1657 | 1658 | * self.lig_pdb 1659 | 1660 | :Example: 1661 | 1662 | >>> TEST_OUT = str(getfixture('tmpdir')) 1663 | >>> dock_1hsg = Docking(name='1hsg') 1664 | >>> dock_1hsg.extract_ligand(os.path.join(TEST_PATH, '1hsg.pdb'),\ 1665 | TEST_OUT, {'res_name': 'MK1'})\ 1666 | #doctest: +ELLIPSIS 1667 | Succeed to read file ...1hsg.pdb , 1686 atoms found 1668 | Succeed to save file ...1hsg_lig.pdb 1669 | >>> coor_lig = pdb_manip.Coor(dock_1hsg.lig_pdb) #doctest: +ELLIPSIS 1670 | Succeed to read file ...1hsg_lig.pdb , 45 atoms found 1671 | >>> com_before = coor_lig.center_of_mass() 1672 | >>> dock_1hsg.random_rot_ligand() 1673 | Succeed to read file ...1hsg_lig.pdb , 45 atoms found 1674 | Succeed to save file ...1hsg_lig.pdb 1675 | >>> coor_lig = pdb_manip.Coor(dock_1hsg.lig_pdb) #doctest: +ELLIPSIS 1676 | Succeed to read file ...1hsg_lig.pdb , 45 atoms found 1677 | >>> com_after = coor_lig.center_of_mass() 1678 | >>> print('Same center of mass after rotation :{}'.format(\ 1679 | com_before==com_after)) 1680 | Same center of mass after rotation :[False False False] 1681 | 1682 | ..warning: 1683 | The function overwrite lig_pdb coordinates. 1684 | """ 1685 | 1686 | lig_coor = pdb_manip.Coor(self._lig_pdb) 1687 | 1688 | tau_x, tau_y, tau_z = np.random.random_sample((3,)) * 360 1689 | lig_coor.rotation_angle(tau_x, tau_y, tau_z) 1690 | lig_coor.write_pdb(self._lig_pdb, check_file_out=False) 1691 | 1692 | return 1693 | 1694 | 1695 | if __name__ == "__main__": 1696 | 1697 | import doctest 1698 | 1699 | print("-Test docking_py module:") 1700 | 1701 | print("docking_py: \t", doctest.testmod()) 1702 | -------------------------------------------------------------------------------- /docking_py/tests/__init__.py: -------------------------------------------------------------------------------- 1 | """Unit test package for docking_py.""" 2 | -------------------------------------------------------------------------------- /docking_py/tests/input/lig.pdbqt: -------------------------------------------------------------------------------- 1 | REMARK 0 active torsions: 2 | REMARK status: ('A' for Active; 'I' for Inactive) 3 | REMARK I between atoms: N1_1 and C31_43 4 | REMARK I between atoms: C2_3 and C3_4 5 | REMARK I between atoms: C3_4 and N2_6 6 | REMARK I between atoms: N2_6 and C4_8 7 | REMARK I between atoms: N3_12 and C10_15 8 | REMARK I between atoms: C10_15 and C11_16 9 | REMARK I between atoms: C11_16 and O2_17 10 | REMARK I between atoms: C11_16 and C12_19 11 | REMARK I between atoms: C12_19 and C13_20 12 | REMARK I between atoms: C13_20 and C21_28 13 | REMARK I between atoms: C13_20 and C14_21 14 | REMARK I between atoms: C14_21 and C15_22 15 | REMARK I between atoms: C21_28 and N4_30 16 | REMARK I between atoms: N4_30 and C22_32 17 | REMARK I between atoms: C23_33 and O4_34 18 | REMARK I between atoms: C31_43 and C32_44 19 | ROOT 20 | HETATM 1 N1 MK1 B 902 9.280 23.763 3.004 1.00 28.25 0.096 N 21 | HETATM 2 C1 MK1 B 902 9.498 23.983 4.459 1.00 30.30 0.307 C 22 | HETATM 3 C2 MK1 B 902 10.591 24.905 4.962 1.00 27.27 0.200 C 23 | HETATM 4 C3 MK1 B 902 10.591 24.864 6.466 1.00 28.85 0.242 C 24 | HETATM 5 O1 MK1 B 902 10.937 23.849 7.057 1.00 29.59 -0.271 OA 25 | HETATM 6 N2 MK1 B 902 10.193 25.953 7.094 1.00 22.29 -0.351 N 26 | ATOM 7 H2 MK1 B 902 9.867 26.704 6.485 1.00 0.00 0.163 HD 27 | HETATM 8 C4 MK1 B 902 10.145 26.250 8.490 1.00 23.47 0.022 C 28 | HETATM 9 C5 MK1 B 902 9.379 27.577 8.641 1.00 27.66 0.037 C 29 | HETATM 10 C6 MK1 B 902 11.398 26.347 9.074 1.00 21.71 0.037 C 30 | HETATM 11 C7 MK1 B 902 9.364 25.283 9.268 1.00 22.75 0.037 C 31 | HETATM 12 N3 MK1 B 902 11.819 24.282 4.355 1.00 28.91 -0.395 N 32 | HETATM 13 C8 MK1 B 902 11.753 23.776 2.961 1.00 26.24 0.148 C 33 | HETATM 14 C9 MK1 B 902 10.440 23.182 2.493 1.00 27.47 0.292 C 34 | HETATM 15 C10 MK1 B 902 13.083 24.963 4.552 1.00 20.86 0.149 C 35 | HETATM 16 C11 MK1 B 902 14.203 24.064 5.078 1.00 21.68 0.136 C 36 | HETATM 17 O2 MK1 B 902 15.242 24.884 4.634 1.00 15.87 -0.394 OA 37 | ATOM 18 H2 MK1 B 902 15.096 25.071 3.714 1.00 0.00 0.210 HD 38 | HETATM 19 C12 MK1 B 902 14.440 23.761 6.569 1.00 21.49 0.047 C 39 | HETATM 20 C13 MK1 B 902 15.573 22.821 7.005 1.00 26.89 0.084 C 40 | HETATM 21 C14 MK1 B 902 15.644 22.664 8.534 1.00 28.67 0.052 C 41 | HETATM 22 C15 MK1 B 902 16.733 21.750 8.961 1.00 26.89 -0.057 A 42 | HETATM 23 C16 MK1 B 902 18.058 21.916 8.553 1.00 29.22 0.007 A 43 | HETATM 24 C17 MK1 B 902 19.037 21.016 8.947 1.00 29.22 0.001 A 44 | HETATM 25 C18 MK1 B 902 18.673 19.939 9.758 1.00 30.97 0.000 A 45 | HETATM 26 C19 MK1 B 902 17.347 19.773 10.176 1.00 29.25 0.001 A 46 | HETATM 27 C20 MK1 B 902 16.374 20.687 9.772 1.00 29.96 0.007 A 47 | HETATM 28 C21 MK1 B 902 15.447 21.440 6.373 1.00 29.35 0.222 C 48 | HETATM 29 O3 MK1 B 902 14.367 20.831 6.397 1.00 32.66 -0.273 OA 49 | HETATM 30 N4 MK1 B 902 16.583 20.913 5.924 1.00 31.19 -0.350 N 50 | ATOM 31 H4 MK1 B 902 17.397 21.515 5.801 1.00 0.00 0.163 HD 51 | HETATM 32 C22 MK1 B 902 16.692 19.500 5.604 1.00 29.22 0.147 C 52 | HETATM 33 C23 MK1 B 902 18.067 18.945 5.936 1.00 28.82 0.149 C 53 | HETATM 34 O4 MK1 B 902 19.061 19.938 5.729 1.00 28.32 -0.393 OA 54 | ATOM 35 H4 MK1 B 902 19.921 19.591 5.937 1.00 0.00 0.210 HD 55 | HETATM 36 C24 MK1 B 902 18.226 17.726 5.057 1.00 32.05 0.073 C 56 | HETATM 37 C25 MK1 B 902 17.476 17.904 3.760 1.00 31.29 -0.047 A 57 | HETATM 38 C26 MK1 B 902 17.500 17.363 2.496 1.00 32.00 0.008 A 58 | HETATM 39 C27 MK1 B 902 16.613 17.872 1.541 1.00 28.00 0.001 A 59 | HETATM 40 C28 MK1 B 902 15.722 18.906 1.865 1.00 29.01 0.001 A 60 | HETATM 41 C29 MK1 B 902 15.683 19.479 3.129 1.00 27.70 0.010 A 61 | HETATM 42 C30 MK1 B 902 16.504 19.061 4.128 1.00 31.86 -0.027 A 62 | HETATM 43 C31 MK1 B 902 8.033 23.100 2.604 1.00 36.25 0.312 C 63 | HETATM 44 C32 MK1 B 902 6.666 23.739 2.876 1.00 42.75 -0.015 A 64 | HETATM 45 C33 MK1 B 902 6.158 24.808 2.124 1.00 47.41 0.096 A 65 | HETATM 46 N5 MK1 B 902 4.911 25.430 2.300 1.00 51.38 -0.375 N 66 | ATOM 47 H5 MK1 B 902 4.567 26.208 1.737 1.00 0.00 0.164 HD 67 | HETATM 48 C34 MK1 B 902 4.207 24.839 3.348 1.00 50.60 0.087 A 68 | HETATM 49 C35 MK1 B 902 4.654 23.774 4.136 1.00 49.34 0.018 A 69 | HETATM 50 C36 MK1 B 902 5.905 23.211 3.897 1.00 44.71 0.011 A 70 | ENDROOT 71 | TORSDOF 14 72 | -------------------------------------------------------------------------------- /docking_py/tests/test_docking_py.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """Tests for `docking_py` package.""" 4 | 5 | import pytest 6 | 7 | import os 8 | import re 9 | 10 | from docking_py import docking 11 | from pdb_manip_py import pdb_manip 12 | 13 | 14 | # Test folder path 15 | LIB_DIR = os.path.dirname(os.path.abspath(__file__)) 16 | TEST_PATH = os.path.join(LIB_DIR, "./input/") 17 | 18 | 19 | @pytest.fixture 20 | def response(): 21 | """Sample pytest fixture. 22 | 23 | See more at: http://doc.pytest.org/en/latest/fixture.html 24 | """ 25 | # import requests 26 | # return requests.get('https://github.com/audreyr/cookiecutter-pypackage') 27 | 28 | 29 | def test_content(response): 30 | """Sample pytest test function with the pytest fixture as an argument.""" 31 | # from bs4 import BeautifulSoup 32 | # assert 'GitHub' in BeautifulSoup(response.content).title.string 33 | 34 | 35 | def test_prepare_ligand_recetor(tmp_path, capsys): 36 | 37 | # Convert to str to avoid problem with python 3.5 38 | TEST_OUT = str(tmp_path) 39 | 40 | # Redirect pdb_manip logs 41 | pdb_manip.show_log() 42 | 43 | # Read 1hsg.pdb, extract lig.pdb and rec.pdb 44 | coor_1hsg = pdb_manip.Coor(os.path.join(TEST_PATH, '1hsg.pdb')) 45 | 46 | captured = capsys.readouterr() 47 | assert bool( 48 | re.match("Succeed to read file .+input/1hsg.pdb , 1686 atoms found\n", 49 | captured.out)) 50 | 51 | # Extratc Protein: 52 | # Keep only amino acid 53 | rec_coor = coor_1hsg.select_part_dict( 54 | selec_dict={'res_name': pdb_manip.PROTEIN_RES}) 55 | out_rec = os.path.join(TEST_OUT, 'rec.pdb') 56 | rec_coor.write_pdb(out_rec) 57 | 58 | captured = capsys.readouterr() 59 | assert bool(re.match("Succeed to save file .+rec.pdb\n", 60 | captured.out)) 61 | 62 | # Extract ligand: 63 | lig_coor = coor_1hsg.select_part_dict( 64 | selec_dict={'res_name': 'MK1'}) 65 | out_lig = os.path.join(TEST_OUT, 'lig.pdb') 66 | lig_coor.write_pdb(out_lig) 67 | 68 | captured = capsys.readouterr() 69 | assert bool(re.match("Succeed to save file .+lig.pdb\n", 70 | captured.out)) 71 | 72 | # Extract ligand center of mass and maximum dimension: 73 | center_lig = lig_coor.center_of_mass() 74 | max_size = lig_coor.get_max_size() 75 | print("Center coordinates is {:.1f} {:.1f} {:.1f}, maximum dimension" 76 | " is {:.1f} Å".format(*center_lig, max_size)) 77 | 78 | captured = capsys.readouterr() 79 | assert bool(re.match('Do a rotation of 99.65°\nCenter coordinates is 13.1' 80 | ' 22.5 5.6, maximum dimension is 16.0 Å\n', 81 | captured.out)) 82 | 83 | # Create Docking object 84 | test_dock = docking.Docking('test', 85 | rec_pdb=out_rec, 86 | lig_pdb=out_lig) 87 | 88 | # Prepare receptor 89 | test_dock.prepare_receptor() 90 | 91 | captured = capsys.readouterr() 92 | assert bool(re.match( 93 | ("python2.+ .+/prepare_receptor4.py -r .+/rec.pdb" 94 | " -A checkhydrogens -o .+/rec.pdbqt\n"), 95 | captured.out)) 96 | 97 | # Check that receptor is fine 98 | coor_rec = pdb_manip.Coor(test_dock.rec_pdbqt) 99 | print('Protein atom number : {}'.format(coor_rec.select_part_dict( 100 | {'res_name': pdb_manip.PROTEIN_RES}).num)) 101 | 102 | captured = capsys.readouterr() 103 | assert bool(re.match( 104 | "File name doesn't finish with .pdb read it as .pdb anyway\n" 105 | "Succeed to read file .+rec.pdbqt , 1844 atoms found\n" 106 | "Protein atom number : 1844\n", 107 | captured.out)) 108 | 109 | # Prepare Ligand 110 | test_dock.prepare_ligand(rigid=True) 111 | 112 | captured = capsys.readouterr() 113 | assert bool(re.match("python.+ .+prepare_ligand4.py -l lig.pdb -B " 114 | "none -A hydrogens -o lig.pdbqt -Z\n", 115 | captured.out)) 116 | 117 | # Check that ligand pdbqt is fine 118 | coor_lig = pdb_manip.Coor(test_dock.lig_pdbqt) 119 | print('Protein atom number : {}'.format(coor_lig.select_part_dict( 120 | {'res_name': pdb_manip.PROTEIN_RES}).num)) 121 | 122 | captured = capsys.readouterr() 123 | assert bool(re.match( 124 | "File name doesn't finish with .pdb read it as .pdb anyway\n" 125 | "Succeed to read file .+lig.pdbqt , 50 atoms found\n" 126 | "Protein atom number : 0\n", 127 | captured.out)) 128 | 129 | 130 | def test_smina_rigid(tmp_path, capsys): 131 | 132 | # Convert to str to avoid problem with python 3.5 133 | TEST_OUT = str(tmp_path) 134 | 135 | # Redirect pdb_manip logs 136 | pdb_manip.show_log() 137 | 138 | # Extract center and max_sizer: 139 | lig_coor = pdb_manip.Coor(os.path.join(TEST_PATH, 'lig.pdbqt')) 140 | 141 | center_lig = lig_coor.center_of_mass() 142 | max_size = lig_coor.get_max_size() 143 | print("Center coordinates is {:.1f} {:.1f} {:.1f}, maximum dimension" 144 | " is {:.1f} Å".format(*center_lig, max_size)) 145 | 146 | captured = capsys.readouterr() 147 | assert bool(re.match("File name doesn't finish with .pdb read it as .pdb" 148 | " anyway\n" 149 | 'Succeed to read file .+/input/lig.pdbqt , 50 ' 150 | 'atoms found\nDo a rotation of 99.71°\nCenter ' 151 | 'coordinates is 13.1 22.5 5.5, maximum dimension is ' 152 | '18.0 Å\n', 153 | captured.out)) 154 | 155 | # Create Docking object 156 | test_dock = docking.Docking( 157 | name='test_smina', 158 | rec_pdbqt=os.path.join(TEST_PATH, 'rec.pdbqt'), 159 | lig_pdbqt=os.path.join(TEST_PATH, 'lig.pdbqt')) 160 | 161 | out_dock = os.path.join(TEST_OUT, '{}_dock.pdb'.format('test_smina')) 162 | 163 | test_dock.run_docking(out_dock, 164 | num_modes=10, 165 | energy_range=10, 166 | exhaustiveness=2, 167 | dock_bin='smina', 168 | center=center_lig, 169 | grid_size=[max_size + 5] * 3, 170 | seed=1) 171 | 172 | captured = capsys.readouterr() 173 | capture_line = captured.out.split('\n') 174 | assert bool(re.match( 175 | ("smina --ligand .+lig.pdbqt --receptor .+rec.pdbqt --log " 176 | ".+test_smina_dock_log.txt --num_modes 10 --exhaustiveness 2" 177 | " --energy_range 10 --out .+test_smina_dock.pdb " 178 | "--size_x 23.00 --size_y 23.00 --size_z 23.00" 179 | " --center_x 13.08 --center_y 22.52 --center_z 5.54" 180 | " --seed 1"), 181 | capture_line[0])) 182 | 183 | rmsd_list = test_dock.compute_dock_rmsd(test_dock.lig_pdbqt) 184 | assert len(rmsd_list) >= 1 185 | assert rmsd_list[0] < 15 186 | 187 | assert len(test_dock.affinity) >= 1 188 | assert test_dock.affinity[1]['affinity'] < -10 189 | 190 | # Read test_dock.dock_pdb 191 | coor_dock = pdb_manip.Multi_Coor(test_dock.dock_pdb) 192 | assert len(coor_dock.coor_list) >= 1 193 | assert len(coor_dock.coor_list[0].atom_dict) == 50 194 | 195 | 196 | def test_vina_rigid(tmp_path, capsys): 197 | 198 | # Convert to str to avoid problem with python 3.5 199 | TEST_OUT = str(tmp_path) 200 | 201 | # Redirect pdb_manip logs 202 | pdb_manip.show_log() 203 | 204 | # Extract center and max_sizer: 205 | lig_coor = pdb_manip.Coor(os.path.join(TEST_PATH, 'lig.pdbqt')) 206 | 207 | center_lig = lig_coor.center_of_mass() 208 | max_size = lig_coor.get_max_size() 209 | print("Center coordinates is {:.1f} {:.1f} {:.1f}, maximum dimension" 210 | " is {:.1f} Å".format(*center_lig, max_size)) 211 | 212 | captured = capsys.readouterr() 213 | assert bool(re.match("File name doesn't finish with .pdb read it as .pdb" 214 | " anyway\n" 215 | 'Succeed to read file .+/input/lig.pdbqt , 50 ' 216 | 'atoms found\nDo a rotation of 99.71°\nCenter ' 217 | 'coordinates is 13.1 22.5 5.5, maximum dimension is ' 218 | '18.0 Å\n', 219 | captured.out)) 220 | 221 | # Create Docking object 222 | test_dock = docking.Docking( 223 | name='test_vina', 224 | rec_pdbqt=os.path.join(TEST_PATH, 'rec.pdbqt'), 225 | lig_pdbqt=os.path.join(TEST_PATH, 'lig.pdbqt')) 226 | 227 | out_dock = os.path.join(TEST_OUT, '{}_dock.pdb'.format('test_vina')) 228 | 229 | test_dock.run_docking(out_dock, 230 | num_modes=10, 231 | energy_range=10, 232 | exhaustiveness=2, 233 | dock_bin='vina', 234 | center=center_lig, 235 | grid_size=[max_size + 5] * 3, 236 | seed=1) 237 | 238 | captured = capsys.readouterr() 239 | capture_line = captured.out.split('\n') 240 | assert bool(re.match( 241 | ("vina --ligand .+lig.pdbqt --receptor .+rec.pdbqt --log " 242 | ".+test_vina_dock_log.txt --num_modes 10 --exhaustiveness 2" 243 | " --energy_range 10 --out .+test_vina_dock.pdb " 244 | "--size_x 23.00 --size_y 23.00 --size_z 23.00" 245 | " --center_x 13.08 --center_y 22.52 --center_z 5.54" 246 | " --seed 1"), 247 | capture_line[0])) 248 | 249 | rmsd_list = test_dock.compute_dock_rmsd(test_dock.lig_pdbqt) 250 | assert len(rmsd_list) >= 1 251 | assert rmsd_list[0] < 15 252 | 253 | assert len(test_dock.affinity) >= 1 254 | assert test_dock.affinity[1]['affinity'] < -10 255 | 256 | captured = capsys.readouterr() 257 | 258 | test_dock.display() 259 | 260 | captured = capsys.readouterr() 261 | assert bool(re.match( 262 | ("name : test_vina\n" 263 | "lig_pdbqt : .+lig.pdbqt\n" 264 | "rec_pdbqt : .+rec.pdbqt\n" 265 | "dock_pdb : .+test_vina_dock_vmd.pdb\n" 266 | "dock_log : .+test_vina_dock_log.txt\n" 267 | "affinity : {1: .+'affinity': .+}}\n"), 268 | captured.out)) 269 | 270 | # Read test_dock.dock_pdb 271 | coor_dock = pdb_manip.Multi_Coor(test_dock.dock_pdb) 272 | assert len(coor_dock.coor_list) >= 1 273 | assert len(coor_dock.coor_list[0].atom_dict) == 50 274 | 275 | 276 | def test_autodock_rigid(tmp_path, capsys): 277 | 278 | # Convert to str to avoid problem with python 3.5 279 | TEST_OUT = str(tmp_path) 280 | 281 | # Redirect pdb_manip logs 282 | pdb_manip.show_log() 283 | 284 | # Extract center and max_sizer: 285 | lig_coor = pdb_manip.Coor(os.path.join(TEST_PATH, 'lig.pdbqt')) 286 | 287 | center_lig = lig_coor.center_of_mass() 288 | max_size = lig_coor.get_max_size() 289 | print("Center coordinates is {:.1f} {:.1f} {:.1f}, maximum dimension" 290 | " is {:.1f} Å".format(*center_lig, max_size)) 291 | 292 | captured = capsys.readouterr() 293 | assert bool(re.match("File name doesn't finish with .pdb read it as .pdb" 294 | " anyway\n" 295 | 'Succeed to read file .+/input/lig.pdbqt , 50 ' 296 | 'atoms found\nDo a rotation of 99.71°\nCenter ' 297 | 'coordinates is 13.1 22.5 5.5, maximum dimension is ' 298 | '18.0 Å\n', 299 | captured.out)) 300 | 301 | # Create Docking object 302 | test_dock = docking.Docking( 303 | name='test_autodock', 304 | rec_pdbqt=os.path.join(TEST_PATH, 'rec.pdbqt'), 305 | lig_pdbqt=os.path.join(TEST_PATH, 'lig.pdbqt')) 306 | 307 | # Prepare Grid 308 | spacing = 0.375 309 | test_dock.prepare_grid(out_folder=TEST_OUT, spacing=spacing, 310 | center=center_lig, 311 | grid_npts=[int(max_size / spacing)] * 3) 312 | 313 | captured = capsys.readouterr() 314 | assert bool(re.match( 315 | ("python2.+ .+prepare_gpf4.py -r rec.pdbqt -l lig.pdbqt -o " 316 | "test_autodock.gpf -p npts=48,48,48 -p " 317 | "gridcenter=13.08,22.52,5.54\nautogrid4 -p test_autodock.gpf -l " 318 | "test_autodock.gpf_log"), 319 | captured.out)) 320 | 321 | test_dock.run_autodock(out_folder=TEST_OUT, nrun=1) 322 | 323 | rmsd_list = test_dock.compute_dock_rmsd(test_dock.lig_pdbqt) 324 | assert len(rmsd_list) >= 1 325 | assert rmsd_list[0] < 15 326 | assert test_dock.affinity[1]['affinity'] < -10 327 | 328 | assert bool(test_dock.lig_pdbqt.endswith("lig.pdbqt")) 329 | assert bool(test_dock.rec_pdbqt.endswith("rec.pdbqt")) 330 | assert bool(test_dock.dock_pdb.endswith("test_autodock_vmd.pdb")) 331 | assert bool(test_dock.gpf.endswith("test_autodock.gpf")) 332 | assert bool(test_dock.dock_log.endswith("test_autodock.dlg")) 333 | 334 | # Read test_dock.dock_pdb 335 | coor_dock = pdb_manip.Multi_Coor(test_dock.dock_pdb) 336 | assert len(coor_dock.coor_list) >= 1 337 | assert len(coor_dock.coor_list[0].atom_dict) == 50 338 | 339 | 340 | def test_autodock_2_rigid(tmp_path, capsys): 341 | 342 | # Convert to str to avoid problem with python 3.5 343 | TEST_OUT = str(tmp_path) 344 | 345 | # Redirect pdb_manip logs 346 | pdb_manip.show_log() 347 | 348 | # Extract center and max_sizer: 349 | lig_coor = pdb_manip.Coor(os.path.join(TEST_PATH, 'lig.pdbqt')) 350 | 351 | center_lig = lig_coor.center_of_mass() 352 | max_size = lig_coor.get_max_size() 353 | print("Center coordinates is {:.1f} {:.1f} {:.1f}, maximum dimension" 354 | " is {:.1f} Å".format(*center_lig, max_size)) 355 | 356 | captured = capsys.readouterr() 357 | assert bool(re.match("File name doesn't finish with .pdb read it as .pdb" 358 | " anyway\n" 359 | 'Succeed to read file .+/input/lig.pdbqt , 50 ' 360 | 'atoms found\nDo a rotation of 99.71°\nCenter ' 361 | 'coordinates is 13.1 22.5 5.5, maximum dimension is ' 362 | '18.0 Å\n', 363 | captured.out)) 364 | 365 | # Create Docking object 366 | test_dock = docking.Docking( 367 | name='test_autodock_2', 368 | rec_pdbqt=os.path.join(TEST_PATH, 'rec.pdbqt'), 369 | lig_pdbqt=os.path.join(TEST_PATH, 'lig.pdbqt')) 370 | 371 | out_dock = os.path.join(TEST_OUT, '{}_dock.pdb'.format('test_autodock_2')) 372 | 373 | test_dock.run_autodock_docking(out_dock, 374 | num_modes=2, 375 | center=center_lig, 376 | grid_size=[max_size + 5] * 3) 377 | 378 | captured = capsys.readouterr() 379 | capture_line = captured.out.split('\n') 380 | assert bool(re.match( 381 | ("python2.+ .+prepare_gpf4.py -r rec.pdbqt -l lig.pdbqt -o " 382 | "test_autodock_2_dock.gpf -p npts=62,62,62 -p " 383 | "gridcenter=13.08,22.52,5.54"), 384 | capture_line[0])) 385 | 386 | assert bool(re.match( 387 | ("autogrid4 -p test_autodock_2_dock.gpf " 388 | "-l test_autodock_2_dock.gpf_log"), 389 | capture_line[1])) 390 | 391 | rmsd_list = test_dock.compute_dock_rmsd(test_dock.lig_pdbqt) 392 | assert len(rmsd_list) == 2 393 | assert rmsd_list[0] < 15 394 | 395 | assert len(test_dock.affinity) == 2 396 | assert test_dock.affinity[1]['affinity'] < -10 397 | 398 | assert bool(test_dock.lig_pdbqt.endswith("lig.pdbqt")) 399 | assert bool(test_dock.rec_pdbqt.endswith("rec.pdbqt")) 400 | assert bool(test_dock.dock_pdb.endswith("test_autodock_2_dock_vmd.pdb")) 401 | assert bool(test_dock.dock_log.endswith("test_autodock_2_dock.dlg")) 402 | assert bool(test_dock.gpf.endswith("test_autodock_2_dock.gpf")) 403 | 404 | # Read test_dock.dock_pdb 405 | coor_dock = pdb_manip.Multi_Coor(test_dock.dock_pdb) 406 | assert len(coor_dock.coor_list) == 2 407 | assert len(coor_dock.coor_list[0].atom_dict) == 50 408 | 409 | 410 | def test_autodock_cpu(tmp_path, capsys): 411 | 412 | # Convert to str to avoid problem with python 3.5 413 | TEST_OUT = str(tmp_path) 414 | 415 | # Redirect pdb_manip logs 416 | pdb_manip.show_log() 417 | 418 | # Extract center and max_sizer: 419 | lig_coor = pdb_manip.Coor(os.path.join(TEST_PATH, 'lig.pdbqt')) 420 | 421 | center_lig = lig_coor.center_of_mass() 422 | max_size = lig_coor.get_max_size() 423 | print("Center coordinates is {:.1f} {:.1f} {:.1f}, maximum dimension" 424 | " is {:.1f} Å".format(*center_lig, max_size)) 425 | 426 | captured = capsys.readouterr() 427 | assert bool(re.match("File name doesn't finish with .pdb read it as .pdb" 428 | " anyway\n" 429 | 'Succeed to read file .+/input/lig.pdbqt , 50 ' 430 | 'atoms found\nDo a rotation of 99.71°\nCenter ' 431 | 'coordinates is 13.1 22.5 5.5, maximum dimension is ' 432 | '18.0 Å\n', 433 | captured.out)) 434 | 435 | # Create Docking object 436 | test_dock = docking.Docking( 437 | name='test_autodock', 438 | rec_pdbqt=os.path.join(TEST_PATH, 'rec.pdbqt'), 439 | lig_pdbqt=os.path.join(TEST_PATH, 'lig.pdbqt')) 440 | 441 | # Prepare Grid 442 | spacing = 0.375 443 | test_dock.prepare_grid(out_folder=TEST_OUT, spacing=spacing, 444 | center=center_lig, 445 | grid_npts=[int(max_size / spacing)] * 3) 446 | 447 | captured = capsys.readouterr() 448 | assert bool(re.match( 449 | ("python2.+ .+prepare_gpf4.py -r rec.pdbqt -l lig.pdbqt -o " 450 | "test_autodock.gpf -p npts=48,48,48 -p " 451 | "gridcenter=13.08,22.52,5.54\nautogrid4 -p test_autodock.gpf -l " 452 | "test_autodock.gpf_log"), 453 | captured.out)) 454 | 455 | test_dock.run_autodock_cpu(out_folder=TEST_OUT, nrun=2) 456 | 457 | rmsd_list = test_dock.compute_dock_rmsd(test_dock.lig_pdbqt) 458 | 459 | assert len(rmsd_list) == 2 460 | assert rmsd_list[0] < 15 461 | 462 | assert len(test_dock.affinity) == 2 463 | assert test_dock.affinity[1]['affinity'] < -10 464 | 465 | assert bool(test_dock.lig_pdbqt.endswith("lig.pdbqt")) 466 | assert bool(test_dock.rec_pdbqt.endswith("rec.pdbqt")) 467 | assert bool(test_dock.dock_pdb.endswith("test_autodock_vmd.pdb")) 468 | assert bool(test_dock.dock_log.endswith("test_autodock.dlg")) 469 | assert bool(test_dock.gpf.endswith("test_autodock.gpf")) 470 | 471 | # Read test_dock.dock_pdb 472 | coor_dock = pdb_manip.Multi_Coor(test_dock.dock_pdb) 473 | assert len(coor_dock.coor_list) == 2 474 | assert len(coor_dock.coor_list[0].atom_dict) == 50 475 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = python -msphinx 7 | SPHINXPROJ = docking_py 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) 21 | -------------------------------------------------------------------------------- /docs/authors.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../AUTHORS.rst 2 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # docking_py documentation build configuration file, created by 4 | # sphinx-quickstart on Fri Jun 9 13:47:02 2017. 5 | # 6 | # This file is execfile()d with the current directory set to its 7 | # containing dir. 8 | # 9 | # Note that not all possible configuration values are present in this 10 | # autogenerated file. 11 | # 12 | # All configuration values have a default; values that are commented out 13 | # serve to show the default. 14 | 15 | # If extensions (or modules to document with autodoc) are in another 16 | # directory, add these directories to sys.path here. If the directory is 17 | # relative to the documentation root, use os.path.abspath to make it 18 | # absolute, like shown here. 19 | # 20 | import os 21 | import sys 22 | sys.path.insert(0, os.path.abspath('..')) 23 | 24 | # import docking_py 25 | 26 | # -- General configuration --------------------------------------------- 27 | 28 | # If your documentation needs a minimal Sphinx version, state it here. 29 | # 30 | # needs_sphinx = '1.0' 31 | 32 | # Add any Sphinx extension module names here, as strings. They can be 33 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. 34 | extensions = [ 35 | 'sphinx.ext.autodoc', 36 | 'sphinx.ext.todo', 37 | 'sphinx.ext.githubpages', 38 | 'sphinxarg.ext', 39 | 'sphinx.ext.mathjax', 40 | 'nbsphinx', 41 | ] 42 | 43 | # Add any paths that contain templates here, relative to this directory. 44 | templates_path = ['_templates'] 45 | 46 | # The suffix(es) of source filenames. 47 | # You can specify multiple suffix as a list of string: 48 | # 49 | # source_suffix = ['.rst', '.md'] 50 | source_suffix = ['.rst'] 51 | 52 | # The master toctree document. 53 | master_doc = 'index' 54 | 55 | # General information about the project. 56 | project = 'Docking Python' 57 | copyright = "2020, Samuel Murail" 58 | author = "Samuel Murail" 59 | 60 | 61 | # The version info for the project you're documenting, acts as replacement 62 | # for |version| and |release|, also used in various other places throughout 63 | # the built documents. 64 | 65 | # The short X.Y version 66 | version = "0.3.0" 67 | # The full version, including alpha/beta/rc tags 68 | release = "0.3.0-rc" 69 | 70 | # The language for content autogenerated by Sphinx. Refer to documentation 71 | # for a list of supported languages. 72 | # 73 | # This is also used if you do content translation via gettext catalogs. 74 | # Usually you set "language" from the command line for these cases. 75 | language = None 76 | 77 | # List of patterns, relative to source directory, that match files and 78 | # directories to ignore when looking for source files. 79 | # This patterns also effect to html_static_path and html_extra_path 80 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store', '_build', '**.ipynb_checkpoints'] 81 | 82 | # The name of the Pygments (syntax highlighting) style to use. 83 | pygments_style = 'sphinx' 84 | 85 | # If true, `todo` and `todoList` produce output, else they produce nothing. 86 | todo_include_todos = False 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 97 | # theme 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 | 108 | # -- Options for HTMLHelp output --------------------------------------- 109 | 110 | # Output file base name for HTML help builder. 111 | htmlhelp_basename = 'docking_pydoc' 112 | 113 | 114 | # -- Options for LaTeX output ------------------------------------------ 115 | 116 | latex_elements = { 117 | # The paper size ('letterpaper' or 'a4paper'). 118 | # 119 | # 'papersize': 'letterpaper', 120 | 121 | # The font size ('10pt', '11pt' or '12pt'). 122 | # 123 | # 'pointsize': '10pt', 124 | 125 | # Additional stuff for the LaTeX preamble. 126 | # 127 | # 'preamble': '', 128 | 129 | # Latex figure (float) alignment 130 | # 131 | # 'figure_align': 'htbp', 132 | } 133 | 134 | # Grouping the document tree into LaTeX files. List of tuples 135 | # (source start file, target name, title, author, documentclass 136 | # [howto, manual, or own class]). 137 | latex_documents = [ 138 | (master_doc, 'docking_py.tex', 139 | 'Docking Python Documentation', 140 | 'Samuel Murail', 'manual'), 141 | ] 142 | 143 | 144 | # -- Options for manual page output ------------------------------------ 145 | 146 | # One entry per manual page. List of tuples 147 | # (source start file, name, description, authors, manual section). 148 | man_pages = [ 149 | (master_doc, 'docking_py', 150 | 'Docking Python Documentation', 151 | [author], 1) 152 | ] 153 | 154 | 155 | # -- Options for Texinfo output ---------------------------------------- 156 | 157 | # Grouping the document tree into Texinfo files. List of tuples 158 | # (source start file, target name, title, author, 159 | # dir menu entry, description, category) 160 | texinfo_documents = [ 161 | (master_doc, 'docking_py', 162 | 'Docking Python Documentation', 163 | author, 164 | 'docking_py', 165 | 'One line description of project.', 166 | 'Miscellaneous'), 167 | ] 168 | 169 | 170 | 171 | -------------------------------------------------------------------------------- /docs/contributing.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../CONTRIBUTING.rst 2 | -------------------------------------------------------------------------------- /docs/docking_py.rst: -------------------------------------------------------------------------------- 1 | docking\_py package 2 | =================== 3 | 4 | Subpackages 5 | ----------- 6 | 7 | .. toctree:: 8 | :maxdepth: 4 9 | 10 | docking_py.tests 11 | 12 | Submodules 13 | ---------- 14 | 15 | docking\_py.cli module 16 | ---------------------- 17 | 18 | .. automodule:: docking_py.cli 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | docking\_py.docking module 24 | -------------------------- 25 | 26 | .. automodule:: docking_py.docking 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | 31 | Module contents 32 | --------------- 33 | 34 | .. automodule:: docking_py 35 | :members: 36 | :undoc-members: 37 | :show-inheritance: 38 | -------------------------------------------------------------------------------- /docs/history.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../HISTORY.rst 2 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | Welcome to Docking Python's documentation! 2 | ========================================== 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | :caption: Contents: 7 | 8 | readme 9 | installation 10 | notebook/Usage.ipynb 11 | modules 12 | contributing 13 | authors 14 | history 15 | 16 | Indices and tables 17 | ================== 18 | * :ref:`genindex` 19 | * :ref:`modindex` 20 | * :ref:`search` 21 | -------------------------------------------------------------------------------- /docs/installation.rst: -------------------------------------------------------------------------------- 1 | .. highlight:: shell 2 | 3 | ============ 4 | Installation 5 | ============ 6 | 7 | 1. Get sources from the `GithubRepo`_ 8 | -------------------------------------- 9 | 10 | The sources for Docking Python can be downloaded from the `GithubRepo`_. 11 | 12 | You can either clone the public repository: 13 | 14 | .. code-block:: console 15 | 16 | $ git clone git://github.com/samuelmurail/docking_py 17 | 18 | Or download the `tarball`_: 19 | 20 | .. code-block:: console 21 | 22 | $ curl -OJL https://github.com/samuelmurail/docking_py/tarball/master 23 | 24 | Once you have a copy of the source, switch to the ``docking_py`` directorie. 25 | 26 | .. code-block:: console 27 | 28 | cd docking_py 29 | 30 | 31 | .. _GithubRepo: https://github.com/samuelmurail/docking_py 32 | .. _tarball: https://github.com/samuelmurail/docking_py/tarball/master 33 | 34 | 35 | 2. Create Conda Environment 36 | --------------------------- 37 | 38 | 39 | You need to create a conda environment to be able to use: 40 | 41 | 42 | * vina 43 | * smina 44 | * qvina2 and qvinaw 45 | * MGLTools for ``prepare_ligand4.py`` and ``prepare_receptor4.py`` scripts. 46 | * Autodock with or without GPU *support* 47 | 48 | 49 | Use `conda en create` to create it using the ``.conda.yml`` file. You can overide the environmnent name using the option ``--name YOUR_NAME``. 50 | 51 | .. code-block:: console 52 | 53 | $ conda env create -f .conda.yml 54 | 55 | If you use a linux OS and have a GPU card, you could try the ``autodock-gpu`` version: 56 | 57 | .. code-block:: console 58 | 59 | $ conda env create -f .conda_gpu.yml 60 | 61 | 62 | This will create an environmnet called ``docking`` or ``docking_gpu`` (or the name you defined). You will then, need to activate the environmnent: 63 | 64 | .. code-block:: console 65 | 66 | $ conda activate docking 67 | 68 | 69 | 3. Install docking_py 70 | --------------------- 71 | 72 | Once you have a copy of the source and have create a conda encironment, 73 | you can install it with: 74 | 75 | .. code-block:: console 76 | 77 | $ python setup.py install 78 | 79 | 80 | 81 | 4. Test Installation 82 | -------------------- 83 | 84 | To test the installation, simply use ``pytest``: 85 | 86 | .. code-block:: console 87 | 88 | $ pytest 89 | ==================================== test session starts ==================================== 90 | platform linux -- Python 3.8.2, pytest-5.4.2, py-1.9.0, pluggy-0.13.1 91 | rootdir: /home/murail/Documents/Code/docking_py, inifile: pytest.ini 92 | plugins: cov-2.10.1 93 | collected 13 items 94 | 95 | docking_py/docking.py ....... [ 53%] 96 | docking_py/tests/test_docking_py.py ...... [100%] 97 | 98 | ============================== 13 passed, 1 warning in 21.18s =============================== 99 | 100 | -------------------------------------------------------------------------------- /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=python -msphinx 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=_build 12 | set SPHINXPROJ=docking_py 13 | 14 | if "%1" == "" goto help 15 | 16 | %SPHINXBUILD% >NUL 2>NUL 17 | if errorlevel 9009 ( 18 | echo. 19 | echo.The Sphinx module was not found. Make sure you have Sphinx installed, 20 | echo.then set the SPHINXBUILD environment variable to point to the full 21 | echo.path of the 'sphinx-build' executable. Alternatively you may add the 22 | echo.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/modules.rst: -------------------------------------------------------------------------------- 1 | docking_py 2 | ========== 3 | 4 | .. toctree:: 5 | :maxdepth: 4 6 | 7 | docking_py 8 | -------------------------------------------------------------------------------- /docs/notebook/Usage.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Usage\n", 8 | "\n", 9 | "To explain the usage of ``docking_py``, we will use a redocking procedure\n", 10 | "\n", 11 | "The same project should be launched from the ``docking`` conda environment:\n", 12 | "\n", 13 | "```\n", 14 | "$ conda activate docking\n", 15 | "```\n", 16 | "\n", 17 | "To use Docking Python in a project:" 18 | ] 19 | }, 20 | { 21 | "cell_type": "code", 22 | "execution_count": 1, 23 | "metadata": {}, 24 | "outputs": [], 25 | "source": [ 26 | "from pdb_manip_py import pdb_manip" 27 | ] 28 | }, 29 | { 30 | "cell_type": "markdown", 31 | "metadata": {}, 32 | "source": [ 33 | "## Extract Ligand coordinates with pdb_manip_py\n", 34 | "\n", 35 | "First you need to extract the ligand coordinates, we will use the ``1hsg.pdb``\n", 36 | "PDB file and extract the coordinates of L-735,524 an inhibitor of the HIV proteases (resname ``MK1``) using the ``pdb_manip_py`` library (Installed with ``docking_py``):" 37 | ] 38 | }, 39 | { 40 | "cell_type": "code", 41 | "execution_count": 2, 42 | "metadata": {}, 43 | "outputs": [], 44 | "source": [ 45 | "# Create a Coor object\n", 46 | "coor_1hsg = pdb_manip.Coor()\n", 47 | "coor_1hsg.get_PDB('1hsg', 'data/1hsg.pdb')" 48 | ] 49 | }, 50 | { 51 | "cell_type": "code", 52 | "execution_count": 3, 53 | "metadata": {}, 54 | "outputs": [], 55 | "source": [ 56 | "# Select res_name MK1\n", 57 | "lig_coor = coor_1hsg.select_part_dict(selec_dict={'res_name': ['MK1']})\n", 58 | "# Save the ligand coordinates\n", 59 | "lig_coor.write_pdb('data/lig.pdb')" 60 | ] 61 | }, 62 | { 63 | "cell_type": "code", 64 | "execution_count": 17, 65 | "metadata": {}, 66 | "outputs": [ 67 | { 68 | "data": { 69 | "application/vnd.jupyter.widget-view+json": { 70 | "model_id": "32139d78c4684bd39ba35d1a821b3a0f", 71 | "version_major": 2, 72 | "version_minor": 0 73 | }, 74 | "text/plain": [ 75 | "NGLWidget()" 76 | ] 77 | }, 78 | "metadata": {}, 79 | "output_type": "display_data" 80 | } 81 | ], 82 | "source": [ 83 | "view_lig = lig_coor.view\n", 84 | "view_lig" 85 | ] 86 | }, 87 | { 88 | "cell_type": "code", 89 | "execution_count": 19, 90 | "metadata": { 91 | "nbsphinx": "hidden" 92 | }, 93 | "outputs": [], 94 | "source": [ 95 | "# To hide this cell add the following info in the cell metadata:\n", 96 | "# \"nbsphinx\": \"hidden\"\n", 97 | "import nglview as nv\n", 98 | "nv.write_html('../_static/lig.html', [view_lig])\n", 99 | "from IPython.display import IFrame" 100 | ] 101 | }, 102 | { 103 | "cell_type": "code", 104 | "execution_count": 20, 105 | "metadata": {}, 106 | "outputs": [ 107 | { 108 | "data": { 109 | "text/html": [ 110 | "\n", 111 | " \n", 118 | " " 119 | ], 120 | "text/plain": [ 121 | "" 122 | ] 123 | }, 124 | "execution_count": 20, 125 | "metadata": {}, 126 | "output_type": "execute_result" 127 | } 128 | ], 129 | "source": [ 130 | "# Unecessary, only need to nglview online:\n", 131 | "IFrame(src='../_static/lig.html', width=800, height=300)" 132 | ] 133 | }, 134 | { 135 | "cell_type": "markdown", 136 | "metadata": {}, 137 | "source": [ 138 | "## Extract Receptor coordinates with pdb_manip_py\n", 139 | "\n", 140 | "Then you need to extract the receptor coordinates, we will use the \n", 141 | "``1hsg.pdb`` PDB file and extract the coordinates of the HIV II protease \n", 142 | "using the ``pdb_manip_py`` library:" 143 | ] 144 | }, 145 | { 146 | "cell_type": "code", 147 | "execution_count": 21, 148 | "metadata": {}, 149 | "outputs": [], 150 | "source": [ 151 | "# Keep only the amino acids\n", 152 | "rec_coor = coor_1hsg.select_part_dict(selec_dict={'res_name': pdb_manip.PROTEIN_RES})\n", 153 | "rec_coor.write_pdb('data/rec.pdb')" 154 | ] 155 | }, 156 | { 157 | "cell_type": "code", 158 | "execution_count": 22, 159 | "metadata": {}, 160 | "outputs": [ 161 | { 162 | "data": { 163 | "application/vnd.jupyter.widget-view+json": { 164 | "model_id": "78491598eeca47b394076c77f8a9b44d", 165 | "version_major": 2, 166 | "version_minor": 0 167 | }, 168 | "text/plain": [ 169 | "NGLWidget()" 170 | ] 171 | }, 172 | "metadata": {}, 173 | "output_type": "display_data" 174 | } 175 | ], 176 | "source": [ 177 | "view_rec = rec_coor.view\n", 178 | "view_rec" 179 | ] 180 | }, 181 | { 182 | "cell_type": "code", 183 | "execution_count": 23, 184 | "metadata": { 185 | "nbsphinx": "hidden" 186 | }, 187 | "outputs": [], 188 | "source": [ 189 | "# To hide this cell add the following info in the cell metadata:\n", 190 | "# \"nbsphinx\": \"hidden\"\n", 191 | "import nglview as nv\n", 192 | "nv.write_html('../_static/rec.html', [view_rec])\n", 193 | "from IPython.display import IFrame" 194 | ] 195 | }, 196 | { 197 | "cell_type": "code", 198 | "execution_count": 25, 199 | "metadata": {}, 200 | "outputs": [ 201 | { 202 | "data": { 203 | "text/html": [ 204 | "\n", 205 | " \n", 212 | " " 213 | ], 214 | "text/plain": [ 215 | "" 216 | ] 217 | }, 218 | "execution_count": 25, 219 | "metadata": {}, 220 | "output_type": "execute_result" 221 | } 222 | ], 223 | "source": [ 224 | "# Unecessary, only need to nglview online:\n", 225 | "IFrame(src='../_static/rec.html', width=800, height=300)" 226 | ] 227 | }, 228 | { 229 | "cell_type": "markdown", 230 | "metadata": {}, 231 | "source": [ 232 | "## Prepare Ligand and receptor structures\n", 233 | "\n", 234 | "You need to create a ``Docking`` object, and the use the\n", 235 | "functions ``prepare_ligand()`` and ``prepare_receptor()``:" 236 | ] 237 | }, 238 | { 239 | "cell_type": "code", 240 | "execution_count": 8, 241 | "metadata": {}, 242 | "outputs": [ 243 | { 244 | "name": "stdout", 245 | "output_type": "stream", 246 | "text": [ 247 | "python2.5 ../../../../../../miniconda3/envs/docking/bin/prepare_ligand4.py -l lig.pdb -B none -A hydrogens -o lig.pdbqt\n" 248 | ] 249 | } 250 | ], 251 | "source": [ 252 | "from docking_py import docking\n", 253 | "\n", 254 | "test_dock = docking.Docking('test', lig_pdb='data/lig.pdb', rec_pdb='data/rec.pdb')\n", 255 | "test_dock.prepare_ligand()" 256 | ] 257 | }, 258 | { 259 | "cell_type": "code", 260 | "execution_count": 9, 261 | "metadata": {}, 262 | "outputs": [ 263 | { 264 | "name": "stdout", 265 | "output_type": "stream", 266 | "text": [ 267 | "python2.5 ../../../../../miniconda3/envs/docking/bin/prepare_receptor4.py -r data/rec.pdb -A checkhydrogens -o data/rec.pdbqt\n" 268 | ] 269 | } 270 | ], 271 | "source": [ 272 | "test_dock.prepare_receptor()" 273 | ] 274 | }, 275 | { 276 | "cell_type": "markdown", 277 | "metadata": {}, 278 | "source": [ 279 | "## Launch docking calculation\n", 280 | "\n", 281 | "Launch the docking:" 282 | ] 283 | }, 284 | { 285 | "cell_type": "code", 286 | "execution_count": 10, 287 | "metadata": {}, 288 | "outputs": [ 289 | { 290 | "name": "stderr", 291 | "output_type": "stream", 292 | "text": [ 293 | "Grid points: None\n" 294 | ] 295 | }, 296 | { 297 | "name": "stdout", 298 | "output_type": "stream", 299 | "text": [ 300 | "smina --ligand data/lig.pdbqt --receptor data/rec.pdbqt --log test_dock_log.txt --num_modes 10 --exhaustiveness 16 --energy_range 10 --out test_dock.pdb --size_x 66.00 --size_y 81.00 --size_z 83.00 --center_x 16.07 --center_y 26.49 --center_z 3.77\n" 301 | ] 302 | } 303 | ], 304 | "source": [ 305 | "test_dock.run_docking(out_pdb='test_dock.pdb',\n", 306 | " num_modes=10,\n", 307 | " energy_range=10,\n", 308 | " exhaustiveness=16,\n", 309 | " dock_bin='smina')" 310 | ] 311 | }, 312 | { 313 | "cell_type": "markdown", 314 | "metadata": {}, 315 | "source": [ 316 | "## Analysis\n", 317 | "\n", 318 | "Extract affinity and RMSD to crystal structure:" 319 | ] 320 | }, 321 | { 322 | "cell_type": "code", 323 | "execution_count": 11, 324 | "metadata": { 325 | "scrolled": true 326 | }, 327 | "outputs": [ 328 | { 329 | "name": "stderr", 330 | "output_type": "stream", 331 | "text": [ 332 | "File name doesn't finish with .pdb read it as .pdb anyway\n" 333 | ] 334 | } 335 | ], 336 | "source": [ 337 | "rmsd_list = test_dock.compute_dock_rmsd(test_dock.lig_pdbqt)" 338 | ] 339 | }, 340 | { 341 | "cell_type": "code", 342 | "execution_count": 12, 343 | "metadata": {}, 344 | "outputs": [ 345 | { 346 | "data": { 347 | "text/plain": [ 348 | "[0.6172348337545442,\n", 349 | " 4.523207300135602,\n", 350 | " 11.579705736330263,\n", 351 | " 9.904196947759067,\n", 352 | " 10.692842899809198,\n", 353 | " 10.975378963844483,\n", 354 | " 12.19258827074875,\n", 355 | " 10.207969165313932,\n", 356 | " 9.394261151362569,\n", 357 | " 12.029979500398163]" 358 | ] 359 | }, 360 | "execution_count": 12, 361 | "metadata": {}, 362 | "output_type": "execute_result" 363 | } 364 | ], 365 | "source": [ 366 | "rmsd_list" 367 | ] 368 | }, 369 | { 370 | "cell_type": "code", 371 | "execution_count": 26, 372 | "metadata": { 373 | "scrolled": true 374 | }, 375 | "outputs": [ 376 | { 377 | "data": { 378 | "application/vnd.jupyter.widget-view+json": { 379 | "model_id": "9ad1c8ca78a140f4af5e097f5d5cdc92", 380 | "version_major": 2, 381 | "version_minor": 0 382 | }, 383 | "text/plain": [ 384 | "NGLWidget(max_frame=9)" 385 | ] 386 | }, 387 | "metadata": {}, 388 | "output_type": "display_data" 389 | } 390 | ], 391 | "source": [ 392 | "view_dock = test_dock.view_dock(ref_pdb=\"data/1hsg.pdb\")\n", 393 | "view_dock" 394 | ] 395 | }, 396 | { 397 | "cell_type": "code", 398 | "execution_count": 29, 399 | "metadata": { 400 | "nbsphinx": "hidden" 401 | }, 402 | "outputs": [], 403 | "source": [ 404 | "# To hide this cell add the following info in the cell metadata:\n", 405 | "# \"nbsphinx\": \"hidden\"\n", 406 | "import nglview as nv\n", 407 | "nv.write_html('../_static/dock.html', [view_dock], frame_range=(0, 10))\n", 408 | "from IPython.display import IFrame" 409 | ] 410 | }, 411 | { 412 | "cell_type": "code", 413 | "execution_count": 30, 414 | "metadata": {}, 415 | "outputs": [ 416 | { 417 | "data": { 418 | "text/html": [ 419 | "\n", 420 | " \n", 427 | " " 428 | ], 429 | "text/plain": [ 430 | "" 431 | ] 432 | }, 433 | "execution_count": 30, 434 | "metadata": {}, 435 | "output_type": "execute_result" 436 | } 437 | ], 438 | "source": [ 439 | "# Unecessary, only need to nglview online:\n", 440 | "IFrame(src='../_static/dock.html', width=800, height=300)" 441 | ] 442 | }, 443 | { 444 | "cell_type": "code", 445 | "execution_count": 15, 446 | "metadata": {}, 447 | "outputs": [ 448 | { 449 | "data": { 450 | "text/plain": [ 451 | "{1: {'affinity': -11.9, 'rmsd_low': 0.0, 'rmsd_high': 0.0},\n", 452 | " 2: {'affinity': -10.6, 'rmsd_low': 2.288, 'rmsd_high': 4.387},\n", 453 | " 3: {'affinity': -9.3, 'rmsd_low': 3.55, 'rmsd_high': 11.574},\n", 454 | " 4: {'affinity': -8.8, 'rmsd_low': 5.812, 'rmsd_high': 9.719},\n", 455 | " 5: {'affinity': -8.7, 'rmsd_low': 5.959, 'rmsd_high': 10.368},\n", 456 | " 6: {'affinity': -8.7, 'rmsd_low': 3.265, 'rmsd_high': 10.921},\n", 457 | " 7: {'affinity': -8.4, 'rmsd_low': 3.702, 'rmsd_high': 12.258},\n", 458 | " 8: {'affinity': -8.3, 'rmsd_low': 5.468, 'rmsd_high': 9.968},\n", 459 | " 9: {'affinity': -8.2, 'rmsd_low': 5.679, 'rmsd_high': 9.289},\n", 460 | " 10: {'affinity': -8.1, 'rmsd_low': 7.058, 'rmsd_high': 11.97}}" 461 | ] 462 | }, 463 | "execution_count": 15, 464 | "metadata": {}, 465 | "output_type": "execute_result" 466 | } 467 | ], 468 | "source": [ 469 | "test_dock.affinity" 470 | ] 471 | }, 472 | { 473 | "cell_type": "code", 474 | "execution_count": null, 475 | "metadata": {}, 476 | "outputs": [], 477 | "source": [] 478 | } 479 | ], 480 | "metadata": { 481 | "celltoolbar": "Edit Metadata", 482 | "kernelspec": { 483 | "display_name": "Python 3", 484 | "language": "python", 485 | "name": "python3" 486 | }, 487 | "language_info": { 488 | "codemirror_mode": { 489 | "name": "ipython", 490 | "version": 3 491 | }, 492 | "file_extension": ".py", 493 | "mimetype": "text/x-python", 494 | "name": "python", 495 | "nbconvert_exporter": "python", 496 | "pygments_lexer": "ipython3", 497 | "version": "3.8.2" 498 | } 499 | }, 500 | "nbformat": 4, 501 | "nbformat_minor": 4 502 | } 503 | -------------------------------------------------------------------------------- /docs/readme.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../README.rst 2 | -------------------------------------------------------------------------------- /pytest.ini: -------------------------------------------------------------------------------- 1 | [pytest] 2 | addopts = --doctest-modules 3 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | numpy 2 | os_command_py==1.1.0 3 | pdb_manip_py==1.3.10 4 | -------------------------------------------------------------------------------- /requirements_dev.txt: -------------------------------------------------------------------------------- 1 | pip 2 | bump2version 3 | wheel 4 | watchdog 5 | flake8 6 | tox 7 | coverage 8 | Sphinx 9 | twine 10 | 11 | pytest 12 | pytest-runner 13 | pytest-cov 14 | 15 | numpy 16 | os_command_py==1.1.0 17 | pdb_manip_py==1.3.10 18 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [bumpversion] 2 | current_version = 0.3.0 3 | commit = True 4 | tag = True 5 | 6 | [bumpversion:file:setup.py] 7 | search = version='{current_version}' 8 | replace = version='{new_version}' 9 | 10 | [bumpversion:file:docking_py/__init__.py] 11 | search = __version__ = '{current_version}' 12 | replace = __version__ = '{new_version}' 13 | 14 | [bumpversion:file:conda/meta.yaml] 15 | search = version = "{current_version}" 16 | replace = version = "{new_version}" 17 | 18 | [bumpversion:file:docs/conf.py] 19 | 20 | [flake8] 21 | exclude = docs 22 | 23 | [aliases] 24 | test = pytest 25 | 26 | [tool:pytest] 27 | collect_ignore = ['setup.py'] 28 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """The setup script.""" 4 | 5 | from setuptools import setup, find_packages 6 | 7 | with open('README.rst') as readme_file: 8 | readme = readme_file.read() 9 | 10 | with open('HISTORY.rst') as history_file: 11 | history = history_file.read() 12 | 13 | requirements = ['numpy', 14 | 'os_command_py==1.1.0', 15 | 'pdb_manip_py==1.3.10', 16 | 'pdb2pqr-htmd-propka30'] 17 | 18 | test_requirements = ['pytest>=3', ] 19 | 20 | setup( 21 | version='0.3.0', 22 | author="Samuel Murail", 23 | author_email='samuel.murail@u-paris.fr', 24 | python_requires='>=3.5', 25 | classifiers=[ 26 | 'Development Status :: 2 - Pre-Alpha', 27 | 'Intended Audience :: Developers', 28 | 'License :: OSI Approved :: GNU General Public License v2 (GPLv2)', 29 | 'Natural Language :: English', 30 | 'Operating System :: OS Independent', 31 | 'Programming Language :: Python :: 3', 32 | 'Programming Language :: Python :: 3.5', 33 | 'Programming Language :: Python :: 3.6', 34 | 'Programming Language :: Python :: 3.7', 35 | 'Programming Language :: Python :: 3.8', 36 | 'Topic :: Scientific/Engineering :: Bio-Informatics', 37 | ], 38 | description="Docking_py is a python library allowing a simplified use of "\ 39 | "the Smina, vina, qvina2 and qvinaw docking software. "\ 40 | "Docking_py can be easily automatize and scripted.", 41 | entry_points={ 42 | 'console_scripts': [ 43 | 'docking_py=docking_py.cli:main', 44 | ], 45 | }, 46 | install_requires=requirements, 47 | license="GNU General Public License v2 (GPLv2)", 48 | long_description=readme + '\n\n' + history, 49 | include_package_data=True, 50 | keywords='docking_py', 51 | name='docking_py', 52 | packages=find_packages(include=['docking_py', 'docking_py.*']), 53 | test_suite='tests', 54 | tests_require=test_requirements, 55 | url='https://github.com/samuelmurail/docking_py', 56 | zip_safe=False, 57 | ) 58 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = py36, py37, py38, flake8 3 | requires = tox-conda 4 | 5 | [travis] 6 | python = 7 | 3.8: py38 8 | 3.7: py37 9 | 3.6: py36 10 | 11 | [testenv:flake8] 12 | basepython = python 13 | deps = flake8 14 | commands = flake8 docking_py 15 | 16 | [testenv] 17 | passenv = TOXENV CI TRAVIS TRAVIS_* CODECOV_* 18 | 19 | setenv = 20 | PYTHONPATH = {toxinidir} 21 | deps = 22 | -r{toxinidir}/requirements_dev.txt 23 | codecov 24 | ; If you want to make tox run the tests with the same versions, create a 25 | ; requirements.txt with the pinned versions and uncomment the following line: 26 | ; -r{toxinidir}/requirements.txt 27 | commands = 28 | pip install -U pip 29 | pytest --basetemp={envtmpdir} --cov-report=xml --cov=docking_py 30 | codecov -e TOXENV 31 | 32 | --------------------------------------------------------------------------------