Upload folder using huggingface_hub
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- .gitattributes +31 -34
- .gitignore +186 -0
- LICENSE +21 -0
- README.md +447 -0
- conf/params_example/example.yml +146 -0
- config.json +17 -0
- environment.yaml +434 -0
- model/comp_surface/prepare_target/__init_.py +0 -0
- model/comp_surface/prepare_target/computeAPBS.py +116 -0
- model/comp_surface/prepare_target/computeCharges.py +219 -0
- model/comp_surface/prepare_target/computeHydrophobicity.py +39 -0
- model/comp_surface/prepare_target/computeMSMS.py +53 -0
- model/comp_surface/prepare_target/computeTargetMesh.py +254 -0
- model/comp_surface/prepare_target/computeTargetMesh_test_samples.py +262 -0
- model/comp_surface/prepare_target/compute_normal.py +78 -0
- model/comp_surface/prepare_target/default_config/README.md +3 -0
- model/comp_surface/prepare_target/default_config/__init__.py +0 -0
- model/comp_surface/prepare_target/default_config/chemistry.py +152 -0
- model/comp_surface/prepare_target/default_config/global_vars.py +32 -0
- model/comp_surface/prepare_target/default_config/masif_opts.py +83 -0
- model/comp_surface/prepare_target/fix_pdb.py +22 -0
- model/comp_surface/prepare_target/fixmesh.py +71 -0
- model/comp_surface/prepare_target/input_output/README.md +2 -0
- model/comp_surface/prepare_target/input_output/__init__.py +0 -0
- model/comp_surface/prepare_target/input_output/extractHelix.py +32 -0
- model/comp_surface/prepare_target/input_output/extractPDB.py +69 -0
- model/comp_surface/prepare_target/input_output/protonate.py +32 -0
- model/comp_surface/prepare_target/input_output/read_msms.py +60 -0
- model/comp_surface/prepare_target/input_output/read_ply.py +53 -0
- model/comp_surface/prepare_target/input_output/save_ply.py +58 -0
- model/comp_surface/prepare_target/mol2graph.py +153 -0
- model/comp_surface/prepare_target/save_ply.py +68 -0
- model/comp_surface/prepare_target/triangulation/README.md +12 -0
- model/comp_surface/prepare_target/triangulation/__init__.py +0 -0
- model/comp_surface/prepare_target/triangulation/computeAPBS.py +68 -0
- model/comp_surface/prepare_target/triangulation/computeCharges.py +215 -0
- model/comp_surface/prepare_target/triangulation/computeHydrophobicity.py +33 -0
- model/comp_surface/prepare_target/triangulation/computeMSMS.py +46 -0
- model/comp_surface/prepare_target/triangulation/compute_normal.py +72 -0
- model/comp_surface/prepare_target/triangulation/fixmesh.py +53 -0
- model/comp_surface/prepare_target/triangulation/xyzrn.py +51 -0
- model/comp_surface/protein_process/openbabel_reduce_openbabel.py +68 -0
- model/comp_surface/tools/transfer/APBS-3.4.1.Linux/bin/GeometricFlow +3 -0
- model/comp_surface/tools/transfer/APBS-3.4.1.Linux/bin/GeometricFlowWrap +0 -0
- model/comp_surface/tools/transfer/APBS-3.4.1.Linux/bin/NanoShaper +3 -0
- model/comp_surface/tools/transfer/APBS-3.4.1.Linux/bin/apbs +3 -0
- model/comp_surface/tools/transfer/APBS-3.4.1.Linux/bin/msms +3 -0
- model/comp_surface/tools/transfer/APBS-3.4.1.Linux/bin/tabipb +3 -0
- model/comp_surface/tools/transfer/APBS-3.4.1.Linux/include/apbs.h +100 -0
- model/comp_surface/tools/transfer/APBS-3.4.1.Linux/include/apbscfg.h +132 -0
.gitattributes
CHANGED
|
@@ -1,35 +1,32 @@
|
|
| 1 |
-
*.
|
| 2 |
-
*.
|
| 3 |
-
|
| 4 |
-
*
|
| 5 |
-
*
|
| 6 |
-
*
|
| 7 |
-
*
|
| 8 |
-
*.h5 filter=lfs diff=lfs merge=lfs -text
|
| 9 |
-
*.joblib filter=lfs diff=lfs merge=lfs -text
|
| 10 |
-
*.lfs.* filter=lfs diff=lfs merge=lfs -text
|
| 11 |
-
*.mlmodel filter=lfs diff=lfs merge=lfs -text
|
| 12 |
-
*.model filter=lfs diff=lfs merge=lfs -text
|
| 13 |
-
*.msgpack filter=lfs diff=lfs merge=lfs -text
|
| 14 |
-
*.npy filter=lfs diff=lfs merge=lfs -text
|
| 15 |
-
*.npz filter=lfs diff=lfs merge=lfs -text
|
| 16 |
-
*.onnx filter=lfs diff=lfs merge=lfs -text
|
| 17 |
-
*.ot filter=lfs diff=lfs merge=lfs -text
|
| 18 |
-
*.parquet filter=lfs diff=lfs merge=lfs -text
|
| 19 |
-
*.pb filter=lfs diff=lfs merge=lfs -text
|
| 20 |
-
*.pickle filter=lfs diff=lfs merge=lfs -text
|
| 21 |
-
*.pkl filter=lfs diff=lfs merge=lfs -text
|
| 22 |
*.pt filter=lfs diff=lfs merge=lfs -text
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
*.ipynb linguist-vendored=false
|
| 2 |
+
*.ipynb linguist-detectable=false
|
| 3 |
+
/jupyter_notebooks linguist-vendored=false
|
| 4 |
+
jupyter_notebooks/** linguist-vendored
|
| 5 |
+
jupyter_notebooks/** linguist-vendored=false
|
| 6 |
+
jupyter_notebooks/* linguist-vendored
|
| 7 |
+
jupyter_notebooks/* linguist-vendored=false
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8 |
*.pt filter=lfs diff=lfs merge=lfs -text
|
| 9 |
+
model/comp_surface/tools/transfer/APBS-3.4.1.Linux/bin/GeometricFlow filter=lfs diff=lfs merge=lfs -text
|
| 10 |
+
model/comp_surface/tools/transfer/APBS-3.4.1.Linux/bin/NanoShaper filter=lfs diff=lfs merge=lfs -text
|
| 11 |
+
model/comp_surface/tools/transfer/APBS-3.4.1.Linux/bin/apbs filter=lfs diff=lfs merge=lfs -text
|
| 12 |
+
model/comp_surface/tools/transfer/APBS-3.4.1.Linux/bin/msms filter=lfs diff=lfs merge=lfs -text
|
| 13 |
+
model/comp_surface/tools/transfer/APBS-3.4.1.Linux/bin/tabipb filter=lfs diff=lfs merge=lfs -text
|
| 14 |
+
model/comp_surface/tools/transfer/APBS-3.4.1.Linux/lib/libGeometricFlowLib.a filter=lfs diff=lfs merge=lfs -text
|
| 15 |
+
model/comp_surface/tools/transfer/APBS-3.4.1.Linux/lib/libTABIPBlib.a filter=lfs diff=lfs merge=lfs -text
|
| 16 |
+
model/comp_surface/tools/transfer/APBS-3.4.1.Linux/lib/libapbs_fem.a filter=lfs diff=lfs merge=lfs -text
|
| 17 |
+
model/comp_surface/tools/transfer/APBS-3.4.1.Linux/lib/libapbs_generic.a filter=lfs diff=lfs merge=lfs -text
|
| 18 |
+
model/comp_surface/tools/transfer/APBS-3.4.1.Linux/lib/libapbs_geoflow_apbs.a filter=lfs diff=lfs merge=lfs -text
|
| 19 |
+
model/comp_surface/tools/transfer/APBS-3.4.1.Linux/lib/libapbs_mg.a filter=lfs diff=lfs merge=lfs -text
|
| 20 |
+
model/comp_surface/tools/transfer/APBS-3.4.1.Linux/lib/libapbs_pmgc.a filter=lfs diff=lfs merge=lfs -text
|
| 21 |
+
model/comp_surface/tools/transfer/APBS-3.4.1.Linux/lib/libapbs_routines.a filter=lfs diff=lfs merge=lfs -text
|
| 22 |
+
model/comp_surface/tools/transfer/APBS-3.4.1.Linux/lib/libcgcode.a filter=lfs diff=lfs merge=lfs -text
|
| 23 |
+
model/comp_surface/tools/transfer/APBS-3.4.1.Linux/lib/libgamer.a filter=lfs diff=lfs merge=lfs -text
|
| 24 |
+
model/comp_surface/tools/transfer/APBS-3.4.1.Linux/lib/libgmock.a filter=lfs diff=lfs merge=lfs -text
|
| 25 |
+
model/comp_surface/tools/transfer/APBS-3.4.1.Linux/lib/libgmock_main.a filter=lfs diff=lfs merge=lfs -text
|
| 26 |
+
model/comp_surface/tools/transfer/APBS-3.4.1.Linux/lib/libgtest.a filter=lfs diff=lfs merge=lfs -text
|
| 27 |
+
model/comp_surface/tools/transfer/APBS-3.4.1.Linux/lib/libgtest_main.a filter=lfs diff=lfs merge=lfs -text
|
| 28 |
+
model/comp_surface/tools/transfer/APBS-3.4.1.Linux/lib/libiapbs.a filter=lfs diff=lfs merge=lfs -text
|
| 29 |
+
model/comp_surface/tools/transfer/APBS-3.4.1.Linux/lib/libmaloc.a filter=lfs diff=lfs merge=lfs -text
|
| 30 |
+
model/comp_surface/tools/transfer/APBS-3.4.1.Linux/lib/libmc.a filter=lfs diff=lfs merge=lfs -text
|
| 31 |
+
model/comp_surface/tools/transfer/APBS-3.4.1.Linux/lib/libsuperlu.a filter=lfs diff=lfs merge=lfs -text
|
| 32 |
+
model/comp_surface/tools/transfer/APBS-3.4.1.Linux/lib/libvf2c.a filter=lfs diff=lfs merge=lfs -text
|
.gitignore
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
homework
|
| 2 |
+
inference_out_dir_not_specified
|
| 3 |
+
.plotly_cache
|
| 4 |
+
.DS_store
|
| 5 |
+
renew.sh
|
| 6 |
+
tmux_renew.sh
|
| 7 |
+
images
|
| 8 |
+
# Byte-compiled / optimized / DLL files
|
| 9 |
+
__pycache__/
|
| 10 |
+
*.py[cod]
|
| 11 |
+
*$py.class
|
| 12 |
+
# tools
|
| 13 |
+
comp_surface/tools/transfer
|
| 14 |
+
comp_surface/tools/transfer/*
|
| 15 |
+
./comp_surface/tools/transfer
|
| 16 |
+
./comp_surface/tools/transfer/*
|
| 17 |
+
# log file
|
| 18 |
+
./*/*.log
|
| 19 |
+
./*/*.LOG
|
| 20 |
+
./*/*.txt
|
| 21 |
+
**/*.txt
|
| 22 |
+
esm
|
| 23 |
+
esm/*
|
| 24 |
+
# C extensions
|
| 25 |
+
*.so
|
| 26 |
+
.so3_*
|
| 27 |
+
best_models/
|
| 28 |
+
# Distribution / packaging
|
| 29 |
+
.Python
|
| 30 |
+
build/
|
| 31 |
+
develop-eggs/
|
| 32 |
+
dist/
|
| 33 |
+
downloads/
|
| 34 |
+
eggs/
|
| 35 |
+
.eggs/
|
| 36 |
+
lib/
|
| 37 |
+
lib64/
|
| 38 |
+
parts/
|
| 39 |
+
sdist/
|
| 40 |
+
var/
|
| 41 |
+
wheels/
|
| 42 |
+
*.egg-info/
|
| 43 |
+
.installed.cfg
|
| 44 |
+
*.egg
|
| 45 |
+
MANIFEST
|
| 46 |
+
|
| 47 |
+
# PyInstaller
|
| 48 |
+
# Usually these files are written by a python script from a template
|
| 49 |
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
| 50 |
+
*.manifest
|
| 51 |
+
*.spec
|
| 52 |
+
|
| 53 |
+
# Installer logs
|
| 54 |
+
pip-log.txt
|
| 55 |
+
pip-delete-this-directory.txt
|
| 56 |
+
|
| 57 |
+
# Unit test / coverage reports
|
| 58 |
+
htmlcov/
|
| 59 |
+
.tox/
|
| 60 |
+
.coverage
|
| 61 |
+
.coverage.*
|
| 62 |
+
.cache
|
| 63 |
+
nosetests.xml
|
| 64 |
+
coverage.xml
|
| 65 |
+
*.cover
|
| 66 |
+
.hypothesis/
|
| 67 |
+
.pytest_cache/
|
| 68 |
+
|
| 69 |
+
# Translations
|
| 70 |
+
*.mo
|
| 71 |
+
*.pot
|
| 72 |
+
|
| 73 |
+
# Django stuff:
|
| 74 |
+
*.log
|
| 75 |
+
local_settings.py
|
| 76 |
+
db.sqlite3
|
| 77 |
+
|
| 78 |
+
# Flask stuff:
|
| 79 |
+
instance/
|
| 80 |
+
.webassets-cache
|
| 81 |
+
|
| 82 |
+
# Scrapy stuff:
|
| 83 |
+
.scrapy
|
| 84 |
+
|
| 85 |
+
# Sphinx documentation
|
| 86 |
+
docs/_build/
|
| 87 |
+
|
| 88 |
+
# PyBuilder
|
| 89 |
+
target/
|
| 90 |
+
|
| 91 |
+
# Jupyter Notebook
|
| 92 |
+
.ipynb_checkpoints
|
| 93 |
+
|
| 94 |
+
# pyenv
|
| 95 |
+
.python-version
|
| 96 |
+
|
| 97 |
+
# celery beat schedule file
|
| 98 |
+
celerybeat-schedule
|
| 99 |
+
|
| 100 |
+
# SageMath parsed files
|
| 101 |
+
*.sage.py
|
| 102 |
+
|
| 103 |
+
# Environments
|
| 104 |
+
.env
|
| 105 |
+
.venv
|
| 106 |
+
env/
|
| 107 |
+
venv/
|
| 108 |
+
ENV/
|
| 109 |
+
env.bak/
|
| 110 |
+
venv.bak/
|
| 111 |
+
|
| 112 |
+
# Spyder project settings
|
| 113 |
+
.spyderproject
|
| 114 |
+
.spyproject
|
| 115 |
+
|
| 116 |
+
# Rope project settings
|
| 117 |
+
.ropeproject
|
| 118 |
+
|
| 119 |
+
# mkdocs documentation
|
| 120 |
+
/site
|
| 121 |
+
|
| 122 |
+
# mypy
|
| 123 |
+
.mypy_cache/
|
| 124 |
+
local_config_inference2.yml
|
| 125 |
+
.vscode/
|
| 126 |
+
|
| 127 |
+
|
| 128 |
+
*.zip
|
| 129 |
+
|
| 130 |
+
.idea/
|
| 131 |
+
|
| 132 |
+
|
| 133 |
+
#################### Project specific
|
| 134 |
+
.p.npy
|
| 135 |
+
.score.npy
|
| 136 |
+
# this ignores everything in data except for the file
|
| 137 |
+
# !/data
|
| 138 |
+
# /data/*
|
| 139 |
+
# !/data/splits
|
| 140 |
+
# !/data/protein_ligand_example_csv.csv
|
| 141 |
+
# !/data/testset_csv.csv
|
| 142 |
+
# !/data/INDEX_general_PL_data.2020
|
| 143 |
+
test_run
|
| 144 |
+
|
| 145 |
+
cache
|
| 146 |
+
wandb
|
| 147 |
+
logs
|
| 148 |
+
|
| 149 |
+
# temporary files
|
| 150 |
+
.openbabel_cache
|
| 151 |
+
temp/
|
| 152 |
+
bsub*
|
| 153 |
+
stderr*
|
| 154 |
+
stdout*
|
| 155 |
+
!/workdir
|
| 156 |
+
/workdir/*
|
| 157 |
+
!/workdir/paper_confidence_model
|
| 158 |
+
!/workdir/paper_score_model
|
| 159 |
+
runs2
|
| 160 |
+
results
|
| 161 |
+
# this excludes everything in the runs directory except for that specific run
|
| 162 |
+
!/runs
|
| 163 |
+
/runs/*
|
| 164 |
+
!/runs/rigid_redocking
|
| 165 |
+
!/runs/flexible_self_docking
|
| 166 |
+
local_config.yml
|
| 167 |
+
local_config_inference.yml
|
| 168 |
+
local_config_confidence.yml
|
| 169 |
+
temp1.py
|
| 170 |
+
temp5.py
|
| 171 |
+
temp3.py
|
| 172 |
+
temp4.py
|
| 173 |
+
temp5.py
|
| 174 |
+
temp6.py
|
| 175 |
+
temp7.py
|
| 176 |
+
esm
|
| 177 |
+
fixed_pdbs
|
| 178 |
+
fixed_pdbs/*
|
| 179 |
+
# nohup files
|
| 180 |
+
./*/*.out
|
| 181 |
+
bash_scripts/*/*/*.out
|
| 182 |
+
|
| 183 |
+
*result*
|
| 184 |
+
|
| 185 |
+
|
| 186 |
+
|
LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
MIT License
|
| 2 |
+
|
| 3 |
+
Copyright (c) 2023 infinite recursion
|
| 4 |
+
|
| 5 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
| 6 |
+
of this software and associated documentation files (the "Software"), to deal
|
| 7 |
+
in the Software without restriction, including without limitation the rights
|
| 8 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
| 9 |
+
copies of the Software, and to permit persons to whom the Software is
|
| 10 |
+
furnished to do so, subject to the following conditions:
|
| 11 |
+
|
| 12 |
+
The above copyright notice and this permission notice shall be included in all
|
| 13 |
+
copies or substantial portions of the Software.
|
| 14 |
+
|
| 15 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 16 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 17 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
| 18 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
| 19 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
| 20 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
| 21 |
+
SOFTWARE.
|
README.md
ADDED
|
@@ -0,0 +1,447 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
license: mit
|
| 3 |
+
language:
|
| 4 |
+
- en
|
| 5 |
+
tags:
|
| 6 |
+
- OneScience
|
| 7 |
+
- SCNet
|
| 8 |
+
- DCU
|
| 9 |
+
- protein-ligand-docking
|
| 10 |
+
- virtual-screening
|
| 11 |
+
- diffusion-model
|
| 12 |
+
frameworks:
|
| 13 |
+
- PyTorch
|
| 14 |
+
---
|
| 15 |
+
|
| 16 |
+
<p align="center">
|
| 17 |
+
<strong><span style="font-size: 30px;">SurfDock</span></strong>
|
| 18 |
+
</p>
|
| 19 |
+
|
| 20 |
+
# Model Introduction
|
| 21 |
+
|
| 22 |
+
SurfDock is a surface-informed diffusion generative model for protein–ligand complex prediction and structure-based virtual screening. The model incorporates protein surface geometry and chemical information into the diffusion-based docking process to generate and screen protein–small-molecule binding conformations.
|
| 23 |
+
|
| 24 |
+
Paper:
|
| 25 |
+
|
| 26 |
+
> **SurfDock is a surface-informed diffusion generative model for reliable and accurate protein–ligand complex prediction**
|
| 27 |
+
> Duanhua Cao, Mingan Chen, Rui Zhang, et al.
|
| 28 |
+
> *Nature Methods*, 2024
|
| 29 |
+
> DOI: https://doi.org/10.1038/s41592-024-02516-y
|
| 30 |
+
|
| 31 |
+
# Model Description
|
| 32 |
+
|
| 33 |
+
SurfDock is a surface-informed diffusion generative model for protein–ligand complex prediction and structure-based virtual screening. The model first preprocesses the target protein structure and computes geometric and physicochemical information on the protein surface. In parallel, it uses ESM to extract protein sequence representations, providing both structural and sequence information for subsequent ligand conformation generation.
|
| 34 |
+
|
| 35 |
+
During inference, SurfDock uses a diffusion generative model to sample candidate ligand conformations within the protein binding site, and then evaluates and ranks the generated poses using a pose confidence model. For virtual screening tasks, a screening score model can be further applied to rescore candidate protein–ligand conformations, producing results that are better suited for downstream ranking and screening.
|
| 36 |
+
|
| 37 |
+
By integrating protein surface information, protein language model representations, and diffusion-based conformation generation, SurfDock can be used for protein–ligand docking, candidate binding pose generation, pose scoring, and structure-based virtual screening.
|
| 38 |
+
|
| 39 |
+
# Use Cases
|
| 40 |
+
|
| 41 |
+
| Use Case | Description |
|
| 42 |
+
| --- | --- |
|
| 43 |
+
| Protein–ligand docking | Predict the binding conformation of a ligand within a protein binding site |
|
| 44 |
+
| Structure-based virtual screening | Perform batch docking and scoring for small-molecule libraries |
|
| 45 |
+
| Ligand conformation generation | Sample candidate binding poses using a diffusion model |
|
| 46 |
+
| Protein surface modeling | Use protein surface geometry and physicochemical information to assist docking |
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
# Usage Instructions
|
| 50 |
+
|
| 51 |
+
## 1. OneCode Usage
|
| 52 |
+
|
| 53 |
+
You can use the OneCode online environment for intelligent one-click AI4S programming:
|
| 54 |
+
|
| 55 |
+
[Try intelligent one-click AI4S programming](https://web-2069360198568017922-iaaj.ksai.scnet.cn:58043/home)
|
| 56 |
+
|
| 57 |
+
## 2. Manual Installation and Usage
|
| 58 |
+
|
| 59 |
+
### Hardware Requirements
|
| 60 |
+
|
| 61 |
+
- SurfDock involves computationally intensive diffusion sampling, ESM representation extraction, and graph neural network computation. GPU/DCU acceleration is recommended.
|
| 62 |
+
|
| 63 |
+
### Environment Setup
|
| 64 |
+
|
| 65 |
+
#### DCU Environment
|
| 66 |
+
|
| 67 |
+
```bash
|
| 68 |
+
# Activate DTK and CONDA first
|
| 69 |
+
conda create -n onescience311 python=3.11 -y
|
| 70 |
+
conda activate onescience311
|
| 71 |
+
|
| 72 |
+
pip install onescience[bio] \
|
| 73 |
+
-i http://mirrors.onescience.ai:3141/pypi/simple/ \
|
| 74 |
+
--trusted-host mirrors.onescience.ai
|
| 75 |
+
```
|
| 76 |
+
|
| 77 |
+
### Environment Notes
|
| 78 |
+
|
| 79 |
+
- During actual execution, if dependencies are missing or version incompatibilities occur, refer to the dependency versions declared in `environment.yaml` in the repository root and install or adjust the corresponding dependencies as needed.
|
| 80 |
+
- SurfDock's protein surface processing pipeline depends on PyMesh. If the current Python version is not fully compatible with the upstream PyMesh package, compatibility adjustments should be made according to the actual call relationships.
|
| 81 |
+
|
| 82 |
+
|
| 83 |
+
### Weights and Data Preparation
|
| 84 |
+
|
| 85 |
+
#### SurfDock Model Weights
|
| 86 |
+
|
| 87 |
+
The current repository already includes the main model weights required for inference:
|
| 88 |
+
|
| 89 |
+
```text
|
| 90 |
+
weight/
|
| 91 |
+
├── docking/
|
| 92 |
+
│ ├── best_ema_inference_epoch_model.pt
|
| 93 |
+
│ └── model_parameters.yml
|
| 94 |
+
├── posepredict/
|
| 95 |
+
│ ├── best_model.pt
|
| 96 |
+
│ └── model_parameters.yml
|
| 97 |
+
└── screen/
|
| 98 |
+
├── best_model.pt
|
| 99 |
+
└── model_parameters.yml
|
| 100 |
+
```
|
| 101 |
+
|
| 102 |
+
Therefore, after downloading the complete repository, you generally do not need to download the main SurfDock model weights separately.
|
| 103 |
+
|
| 104 |
+
Check:
|
| 105 |
+
|
| 106 |
+
```bash
|
| 107 |
+
ls -lh weight/docking/
|
| 108 |
+
ls -lh weight/posepredict/
|
| 109 |
+
ls -lh weight/screen/
|
| 110 |
+
```
|
| 111 |
+
|
| 112 |
+
#### ESM Model
|
| 113 |
+
|
| 114 |
+
SurfDock uses ESM to extract protein sequence representations.
|
| 115 |
+
|
| 116 |
+
Official installation method:
|
| 117 |
+
|
| 118 |
+
```bash
|
| 119 |
+
git clone https://github.com/facebookresearch/esm model/esm
|
| 120 |
+
cd model/esm
|
| 121 |
+
pip install -e .
|
| 122 |
+
cd ../..
|
| 123 |
+
```
|
| 124 |
+
|
| 125 |
+
The official inference script uses:
|
| 126 |
+
|
| 127 |
+
```text
|
| 128 |
+
esm2_t33_650M_UR50D
|
| 129 |
+
```
|
| 130 |
+
|
| 131 |
+
and runs:
|
| 132 |
+
|
| 133 |
+
```bash
|
| 134 |
+
python model/esm/scripts/extract.py \
|
| 135 |
+
"esm2_t33_650M_UR50D" \
|
| 136 |
+
input.fasta \
|
| 137 |
+
output_dir \
|
| 138 |
+
--repr_layers 33 \
|
| 139 |
+
--include "per_tok" \
|
| 140 |
+
--truncation_seq_length 4096
|
| 141 |
+
```
|
| 142 |
+
|
| 143 |
+
to extract protein residue-level embeddings.
|
| 144 |
+
|
| 145 |
+
- If the current environment cannot access the internet, it is recommended to cache the corresponding ESM weights in advance. `esm2_t33_650M_UR50D` requires the following two files:
|
| 146 |
+
|
| 147 |
+
```text
|
| 148 |
+
https://dl.fbaipublicfiles.com/fair-esm/models/esm2_t33_650M_UR50D.pt
|
| 149 |
+
https://dl.fbaipublicfiles.com/fair-esm/regression/esm2_t33_650M_UR50D-contact-regression.pt
|
| 150 |
+
```
|
| 151 |
+
|
| 152 |
+
After downloading, it is recommended to place them in the current user's Torch Hub checkpoints cache directory:
|
| 153 |
+
|
| 154 |
+
```text
|
| 155 |
+
~/.cache/torch/hub/checkpoints/
|
| 156 |
+
```
|
| 157 |
+
|
| 158 |
+
The final file paths should be:
|
| 159 |
+
|
| 160 |
+
```text
|
| 161 |
+
~/.cache/torch/hub/checkpoints/esm2_t33_650M_UR50D.pt
|
| 162 |
+
~/.cache/torch/hub/checkpoints/esm2_t33_650M_UR50D-contact-regression.pt
|
| 163 |
+
```
|
| 164 |
+
|
| 165 |
+
#### PDBBind Data
|
| 166 |
+
|
| 167 |
+
If you need to retrain SurfDock, you must obtain PDBBind separately. According to the official instructions, the preprocessed data previously provided by EquiBind is no longer publicly distributed due to PDBBind licensing restrictions, so users need to obtain and process the data themselves through the official PDBBind channels.
|
| 168 |
+
|
| 169 |
+
After processing, place the data in:
|
| 170 |
+
|
| 171 |
+
```text
|
| 172 |
+
model/data/PDBBind_processed/
|
| 173 |
+
```
|
| 174 |
+
`model/data/splits/` contains data split information and is not equivalent to the complete PDBBind dataset.
|
| 175 |
+
|
| 176 |
+
## 3. Quick Start
|
| 177 |
+
|
| 178 |
+
### Download the Model Package
|
| 179 |
+
|
| 180 |
+
```bash
|
| 181 |
+
hf download \
|
| 182 |
+
OneScience-Group/SurfDock \
|
| 183 |
+
--local-dir ./SurfDock
|
| 184 |
+
|
| 185 |
+
cd SurfDock
|
| 186 |
+
```
|
| 187 |
+
- SurfDock uses ESM to extract protein sequence representations, so the ESM model must be downloaded separately. See the Weights and Data Preparation section for details.
|
| 188 |
+
|
| 189 |
+
# Example Data
|
| 190 |
+
|
| 191 |
+
The current repository already provides docking and screening examples:
|
| 192 |
+
|
| 193 |
+
```text
|
| 194 |
+
model/data/eval_sample_dirs/
|
| 195 |
+
model/data/Screen_sample_dirs/
|
| 196 |
+
```
|
| 197 |
+
|
| 198 |
+
When using your own data, organize the protein and ligand inputs according to the example directory structure, and modify the following paths in the corresponding bash scripts:
|
| 199 |
+
|
| 200 |
+
```text
|
| 201 |
+
data_dir
|
| 202 |
+
surface_out_dir
|
| 203 |
+
out_csv_file
|
| 204 |
+
Screen_lib_path
|
| 205 |
+
docking_out_dir
|
| 206 |
+
```
|
| 207 |
+
|
| 208 |
+
as needed.
|
| 209 |
+
|
| 210 |
+
# Inference Examples
|
| 211 |
+
|
| 212 |
+
The following commands are assumed to be executed from the SurfDock repository root directory.
|
| 213 |
+
|
| 214 |
+
## Protein–Ligand Docking Example
|
| 215 |
+
|
| 216 |
+
Run:
|
| 217 |
+
|
| 218 |
+
```bash
|
| 219 |
+
cd scripts/bash_scripts/test_scripts
|
| 220 |
+
bash eval_samples.sh
|
| 221 |
+
```
|
| 222 |
+
|
| 223 |
+
The script mainly performs the following steps automatically:
|
| 224 |
+
|
| 225 |
+
```text
|
| 226 |
+
1. Preprocess the protein structure
|
| 227 |
+
2. Compute the protein surface
|
| 228 |
+
3. Build the inference input CSV
|
| 229 |
+
4. Extract ESM embeddings
|
| 230 |
+
5. Run SurfDock diffusion sampling
|
| 231 |
+
6. Save docking results
|
| 232 |
+
```
|
| 233 |
+
|
| 234 |
+
Before running, it is recommended to check:
|
| 235 |
+
|
| 236 |
+
```bash
|
| 237 |
+
vim scripts/bash_scripts/test_scripts/eval_samples.sh
|
| 238 |
+
```
|
| 239 |
+
|
| 240 |
+
Pay particular attention to:
|
| 241 |
+
|
| 242 |
+
```text
|
| 243 |
+
gpu_string
|
| 244 |
+
data_dir
|
| 245 |
+
surface_out_dir
|
| 246 |
+
out_csv_file
|
| 247 |
+
esmbedding_dir
|
| 248 |
+
docking_out_dir
|
| 249 |
+
```
|
| 250 |
+
|
| 251 |
+
Users also need to adjust the `CUDA_VISIBLE_DEVICES` and `accelerate launch` settings in the script according to the actual adaptation method.
|
| 252 |
+
|
| 253 |
+
## Virtual Screening Example
|
| 254 |
+
|
| 255 |
+
Run:
|
| 256 |
+
|
| 257 |
+
```bash
|
| 258 |
+
cd scripts/bash_scripts/test_scripts
|
| 259 |
+
bash screen_pipeline.sh
|
| 260 |
+
```
|
| 261 |
+
|
| 262 |
+
Before running, check:
|
| 263 |
+
|
| 264 |
+
```bash
|
| 265 |
+
vim scripts/bash_scripts/test_scripts/screen_pipeline.sh
|
| 266 |
+
```
|
| 267 |
+
|
| 268 |
+
Modify the following as needed:
|
| 269 |
+
|
| 270 |
+
```text
|
| 271 |
+
gpu_string
|
| 272 |
+
data_dir
|
| 273 |
+
surface_out_dir
|
| 274 |
+
out_csv_file
|
| 275 |
+
esmbedding_dir
|
| 276 |
+
Screen_lib_path
|
| 277 |
+
docking_out_dir
|
| 278 |
+
```
|
| 279 |
+
|
| 280 |
+
Here, `Screen_lib_path` specifies the small-molecule library to be screened, for example the official sample:
|
| 281 |
+
|
| 282 |
+
```text
|
| 283 |
+
model/data/Screen_sample_dirs/test_samples/1a0q/1a0q_ligand_for_Screen.sdf
|
| 284 |
+
```
|
| 285 |
+
|
| 286 |
+
The screening workflow is mainly:
|
| 287 |
+
|
| 288 |
+
```text
|
| 289 |
+
Protein preprocessing
|
| 290 |
+
↓
|
| 291 |
+
Protein surface computation
|
| 292 |
+
↓
|
| 293 |
+
ESM embedding
|
| 294 |
+
↓
|
| 295 |
+
SurfDock generates candidate conformations
|
| 296 |
+
↓
|
| 297 |
+
Screen model rescoring
|
| 298 |
+
↓
|
| 299 |
+
Output screening results
|
| 300 |
+
```
|
| 301 |
+
|
| 302 |
+
## Skip Completed Protein Preprocessing
|
| 303 |
+
|
| 304 |
+
This parameter can be modified in the following two scripts:
|
| 305 |
+
|
| 306 |
+
```text
|
| 307 |
+
scripts/bash_scripts/test_scripts/eval_samples.sh
|
| 308 |
+
scripts/bash_scripts/test_scripts/screen_pipeline.sh
|
| 309 |
+
```
|
| 310 |
+
|
| 311 |
+
The scripts use:
|
| 312 |
+
|
| 313 |
+
```bash
|
| 314 |
+
target_have_processed=true
|
| 315 |
+
```
|
| 316 |
+
|
| 317 |
+
to control whether target preprocessing is skipped. When set to `true`, the scripts skip target protein preprocessing steps such as OpenBabel/reduce and proceed directly to subsequent surface computation, CSV construction, ESM embedding, and inference.
|
| 318 |
+
|
| 319 |
+
To reprocess the target protein:
|
| 320 |
+
|
| 321 |
+
```bash
|
| 322 |
+
target_have_processed=false
|
| 323 |
+
```
|
| 324 |
+
|
| 325 |
+
When set to `false`, the scripts rerun the target protein preprocessing steps.
|
| 326 |
+
|
| 327 |
+
## Generate ESM Embeddings Separately
|
| 328 |
+
|
| 329 |
+
First, build the FASTA file:
|
| 330 |
+
|
| 331 |
+
```bash
|
| 332 |
+
python model/datasets/esm_embedding_preparation.py \
|
| 333 |
+
--out_file ./protein.fasta \
|
| 334 |
+
--protein_ligand_csv ./input.csv
|
| 335 |
+
```
|
| 336 |
+
|
| 337 |
+
Extract ESM representations:
|
| 338 |
+
|
| 339 |
+
```bash
|
| 340 |
+
python model/esm/scripts/extract.py \
|
| 341 |
+
"esm2_t33_650M_UR50D" \
|
| 342 |
+
./protein.fasta \
|
| 343 |
+
./esm_embedding_output \
|
| 344 |
+
--repr_layers 33 \
|
| 345 |
+
--include "per_tok" \
|
| 346 |
+
--truncation_seq_length 4096
|
| 347 |
+
```
|
| 348 |
+
|
| 349 |
+
Extract pocket embeddings:
|
| 350 |
+
|
| 351 |
+
```bash
|
| 352 |
+
python model/datasets/get_pocket_embedding.py \
|
| 353 |
+
--protein_pocket_csv ./input.csv \
|
| 354 |
+
--embeddings_dir ./esm_embedding_output \
|
| 355 |
+
--pocket_emb_save_dir ./esm_embedding_pocket_output
|
| 356 |
+
```
|
| 357 |
+
|
| 358 |
+
Merge them into the `.pt` file required for SurfDock inference:
|
| 359 |
+
|
| 360 |
+
```bash
|
| 361 |
+
python model/datasets/esm_pocket_embeddings_to_pt.py \
|
| 362 |
+
--esm_embeddings_path ./esm_embedding_pocket_output \
|
| 363 |
+
--output_path ./esm2_pocket_embeddings.pt
|
| 364 |
+
```
|
| 365 |
+
|
| 366 |
+
# Training Instructions
|
| 367 |
+
|
| 368 |
+
## Retraining SurfDock
|
| 369 |
+
|
| 370 |
+
Retraining requires preparing the PDBBind data first and completing protein surface and ESM embedding preprocessing.
|
| 371 |
+
|
| 372 |
+
The training-related scripts are located in:
|
| 373 |
+
|
| 374 |
+
```text
|
| 375 |
+
scripts/bash_scripts/train_SurfDock_docking_module/
|
| 376 |
+
```
|
| 377 |
+
|
| 378 |
+
First, prepare the ESM embedding files required for training by following the "Generate ESM Embeddings Separately" section. The training script in the current repository is located at:
|
| 379 |
+
|
| 380 |
+
```text
|
| 381 |
+
scripts/bash_scripts/train_SurfDock_docking_module/train_SurfDock.sh
|
| 382 |
+
```
|
| 383 |
+
|
| 384 |
+
After completing the ESM embeddings, check the data, model, and output paths in `train_SurfDock.sh`, then run:
|
| 385 |
+
|
| 386 |
+
```bash
|
| 387 |
+
cd scripts/bash_scripts/train_SurfDock_docking_module
|
| 388 |
+
bash train_SurfDock.sh
|
| 389 |
+
```
|
| 390 |
+
|
| 391 |
+
## Retraining SurfScore
|
| 392 |
+
|
| 393 |
+
The SurfScore training script is located at:
|
| 394 |
+
|
| 395 |
+
```text
|
| 396 |
+
scripts/bash_scripts/train_SurfScore/train_SurfScore.sh
|
| 397 |
+
```
|
| 398 |
+
|
| 399 |
+
Before running, check the PDBBind data, cache, ESM embedding, output directory, and GPU parameters in the script, then run:
|
| 400 |
+
|
| 401 |
+
```bash
|
| 402 |
+
cd scripts/bash_scripts/train_SurfScore
|
| 403 |
+
bash train_SurfScore.sh
|
| 404 |
+
```
|
| 405 |
+
|
| 406 |
+
# Output Description
|
| 407 |
+
|
| 408 |
+
## Docking Output
|
| 409 |
+
|
| 410 |
+
The docking results from `eval_samples.sh` are saved in the directory specified by `docking_out_dir` in the script.
|
| 411 |
+
|
| 412 |
+
The main outputs include:
|
| 413 |
+
|
| 414 |
+
```text
|
| 415 |
+
Generated protein–ligand conformations
|
| 416 |
+
Confidence/scoring results
|
| 417 |
+
Runtime logs
|
| 418 |
+
Intermediate CSV
|
| 419 |
+
ESM embeddings
|
| 420 |
+
Protein surface files
|
| 421 |
+
```
|
| 422 |
+
|
| 423 |
+
## Screening Output
|
| 424 |
+
|
| 425 |
+
`screen_pipeline.sh` generates the screening results in `docking_out_dir` and uses:
|
| 426 |
+
|
| 427 |
+
```text
|
| 428 |
+
weight/screen/best_model.pt
|
| 429 |
+
```
|
| 430 |
+
|
| 431 |
+
to rescore the docking poses.
|
| 432 |
+
|
| 433 |
+
The final results can be used to rank and screen candidate small molecules.
|
| 434 |
+
|
| 435 |
+
# OneScience Official Information
|
| 436 |
+
|
| 437 |
+
| Platform | OneScience Main Repository | Skills Repository |
|
| 438 |
+
| --- | --- | --- |
|
| 439 |
+
| Gitee | https://gitee.com/onescience-ai/onescience | https://gitee.com/onescience-ai/oneskills |
|
| 440 |
+
| GitHub | https://github.com/onescience-ai/OneScience | https://github.com/onescience-ai/oneskills |
|
| 441 |
+
|
| 442 |
+
|
| 443 |
+
# Citation and License
|
| 444 |
+
|
| 445 |
+
- The official SurfDock source code repository is released under the **MIT License**, which permits use, modification, distribution, sublicensing, and commercial use. The original copyright notice and MIT License text should be retained when copying or distributing the software.
|
| 446 |
+
- PDBBind data is governed by its own license and terms of use. SurfDock's MIT License does not automatically apply to PDBBind data.
|
| 447 |
+
- This repository is a **DCU-adapted version** of SurfDock, with adjustments to parts of the runtime environment, dependency configuration, and execution workflow. The use of the repository code, model weights, and related data remains subject to the licenses and terms of use of their respective original projects.
|
conf/params_example/example.yml
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# This file is used to explain the meaning of the SurfDock parameters.
|
| 2 |
+
# If you want to learn more about the options available for these parameters, please refer ./utils/parsing.py file
|
| 3 |
+
# If the user wants to retrain the model, they can pick the right parameters to optimize in their own way
|
| 4 |
+
## General arguments
|
| 5 |
+
# CUDA optimization parameter for faster training
|
| 6 |
+
cudnn_benchmark: true
|
| 7 |
+
# use pin_memory or not in linux system
|
| 8 |
+
pin_memory: false
|
| 9 |
+
# restart dir for training, which storge the model and optimizer
|
| 10 |
+
restart_dir: ~/SurfDock/workdir/project_surface_V3_PDBBind_ema_model_pocket_8A
|
| 11 |
+
# restart learning rate
|
| 12 |
+
restart_lr: null
|
| 13 |
+
|
| 14 |
+
## dataset
|
| 15 |
+
# training data dir
|
| 16 |
+
data_dir: ~/PDBBIND/PDBBind_pocket_8A/
|
| 17 |
+
# cache path for training data, if you just use SurfDock, you can ignore this
|
| 18 |
+
cache_path: ~/PDBBIND/cache_Surface_PDBBIND_pocket_8A
|
| 19 |
+
# esm embedding path,if this is set then the LM embeddings at that path will be used for the receptor features
|
| 20 |
+
esm_embeddings_path: ~/PDBBIND/esm_embedding/esm_embedding_pocket_for_train/esm2_3billion_embeddings.pt
|
| 21 |
+
# dataset split file
|
| 22 |
+
split_test: ~/data/splits/timesplit_test
|
| 23 |
+
split_train: ~/data/splits/timesplit_no_lig_overlap_train
|
| 24 |
+
split_val: ~/data/splits/timesplit_no_lig_overlap_val
|
| 25 |
+
# use rmsd matching or not,use default value is fine
|
| 26 |
+
matching: true
|
| 27 |
+
# Differential evolution maxiter parameter in matching
|
| 28 |
+
matching_maxiter: 20
|
| 29 |
+
# the number of workers for dataloader
|
| 30 |
+
num_dataloader_workers: 1
|
| 31 |
+
# the number of complexes to inference in validation set
|
| 32 |
+
num_inference_complexes: 500
|
| 33 |
+
# the number of workers for training
|
| 34 |
+
num_workers: 1
|
| 35 |
+
|
| 36 |
+
## model
|
| 37 |
+
# if you want to use dynamic max cross, you can set this to true. this parameter can set a different max cross distance for each timestep
|
| 38 |
+
dynamic_max_cross: true
|
| 39 |
+
# scale the noise by sigma or not
|
| 40 |
+
scale_by_sigma: true
|
| 41 |
+
# Maximum sigma for rotational component
|
| 42 |
+
rot_sigma_max: 1.55
|
| 43 |
+
# Minimum sigma for rotational component
|
| 44 |
+
rot_sigma_min: 0.03
|
| 45 |
+
# Maximum sigma for torsional component
|
| 46 |
+
tor_sigma_max: 3.14
|
| 47 |
+
# Minimum sigma for torsional component
|
| 48 |
+
tor_sigma_min: 0.0314
|
| 49 |
+
# Maximum sigma for translational component
|
| 50 |
+
tr_sigma_max: 5.0
|
| 51 |
+
# Minimum sigma for translational component
|
| 52 |
+
tr_sigma_min: 0.1
|
| 53 |
+
# the weight of torsional component loss
|
| 54 |
+
tor_weight: 0.33
|
| 55 |
+
# the weight of translational component loss
|
| 56 |
+
tr_weight: 0.33
|
| 57 |
+
# the weight of rotational component loss
|
| 58 |
+
rot_weight: 0.33
|
| 59 |
+
# diffusion model type , default value is surface_score_model,when train a scoring model, you can use mdn_model
|
| 60 |
+
model_type: surface_score_model
|
| 61 |
+
# diffusion model version, use default value is 3
|
| 62 |
+
model_version: version3
|
| 63 |
+
# training epochs
|
| 64 |
+
n_epochs: 2000
|
| 65 |
+
# number of gaussians which used to MDN module for socring module
|
| 66 |
+
n_gaussians: 20
|
| 67 |
+
# use no batch norm or not
|
| 68 |
+
no_batch_norm: false
|
| 69 |
+
# use torsion or not ,default value is false
|
| 70 |
+
no_torsion: false
|
| 71 |
+
# the layer number of the model
|
| 72 |
+
num_conv_layers: 6
|
| 73 |
+
# the dimension of the scalar embedding in e3nn
|
| 74 |
+
ns: 48
|
| 75 |
+
# the dimension of the vector embedding in e3nn
|
| 76 |
+
nv: 10
|
| 77 |
+
# use the second order representation or not
|
| 78 |
+
use_second_order_repr: false
|
| 79 |
+
# embedding type
|
| 80 |
+
embedding_type: sinusoidal
|
| 81 |
+
# max number of neighbors for each atom in ligand graph
|
| 82 |
+
max_radius: 5.0
|
| 83 |
+
batch_size: 12 # batch size
|
| 84 |
+
# the radius of the receptor graph
|
| 85 |
+
receptor_radius: 15.0
|
| 86 |
+
# max number of neighbors for each C-alpha atom(residue graph)
|
| 87 |
+
c_alpha_max_neighbors: 24
|
| 88 |
+
# Maxximum inter-distance about different node types
|
| 89 |
+
cross_max_distance: 80
|
| 90 |
+
# cross distance embed dimension
|
| 91 |
+
cross_distance_embed_dim: 32
|
| 92 |
+
# intra-distance embed dimension
|
| 93 |
+
distance_embed_dim: 32
|
| 94 |
+
# Size of the embedding of the diffusion time
|
| 95 |
+
sigma_embed_dim: 32
|
| 96 |
+
# Parameter of the diffusion time embedding
|
| 97 |
+
embedding_scale: 1000
|
| 98 |
+
# dropout rate for dropout layer in diffusion module
|
| 99 |
+
dropout: 0.1
|
| 100 |
+
# the dropout rate for scoring module
|
| 101 |
+
mdn_dropout: 0.1
|
| 102 |
+
# use the ema model or not
|
| 103 |
+
use_ema: false
|
| 104 |
+
# exponential moving average rate
|
| 105 |
+
ema_rate: 0.999
|
| 106 |
+
# learning rate ,use default value is fine
|
| 107 |
+
lr: 0.001
|
| 108 |
+
# the learning rate scheduler
|
| 109 |
+
scheduler: plateau
|
| 110 |
+
# the weight decay factor, use default value is fine
|
| 111 |
+
w_decay: 0.0
|
| 112 |
+
# the patience of the learning rate scheduler
|
| 113 |
+
scheduler_patience: 50
|
| 114 |
+
# earlystop goal use max or min
|
| 115 |
+
inference_earlystop_goal: max
|
| 116 |
+
# inference earlystop metric
|
| 117 |
+
inference_earlystop_metric: valinf_rmsds_lt2
|
| 118 |
+
# denoise steps in inference stage
|
| 119 |
+
inference_steps: 20
|
| 120 |
+
# the early stop goal for training scoring module
|
| 121 |
+
mdn_early_stop_patience: 30
|
| 122 |
+
# remove hydrogen or not
|
| 123 |
+
remove_hs: true
|
| 124 |
+
# validation inference frequency,default is 20 epochs
|
| 125 |
+
val_inference_freq: 20
|
| 126 |
+
# top-N atoms with the smallest distances with surface node for mdn calculate in scoring model
|
| 127 |
+
topN: 1
|
| 128 |
+
# predict bond type or not in training scoring model stage
|
| 129 |
+
bond_type_prediction: true
|
| 130 |
+
# atom type prediction or not in training scoring model stage
|
| 131 |
+
atom_type_prediction: true
|
| 132 |
+
|
| 133 |
+
## wandb log
|
| 134 |
+
# use wandb to log or not
|
| 135 |
+
wandb: true
|
| 136 |
+
# wandb dir
|
| 137 |
+
wandb_dir: ~/wandb/SurfDock
|
| 138 |
+
# the project name in wandb
|
| 139 |
+
project: SurfDock_V3_PDBBind_ema_model_pocket_8A
|
| 140 |
+
# the run name in wandb
|
| 141 |
+
run_name: project_surface_V3_PDBBind_ema_model_pocket_8A
|
| 142 |
+
# dir of log files
|
| 143 |
+
log_dir: ~/wandb/SurfDock/workdir
|
| 144 |
+
|
| 145 |
+
|
| 146 |
+
|
config.json
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"directories": {
|
| 3 |
+
"conf": "Environment files and example parameter files",
|
| 4 |
+
"model": "SurfDock source modules, bundled data, surface tools, and assets",
|
| 5 |
+
"scripts": "Python entry points and shell workflows",
|
| 6 |
+
"weight": "Pretrained SurfDock, pose prediction, and screening weights"
|
| 7 |
+
},
|
| 8 |
+
"entrypoints": {
|
| 9 |
+
"inference": "scripts/inference_accelerate.py",
|
| 10 |
+
"evaluate": "scripts/evaluate_accelarate.py",
|
| 11 |
+
"score_in_place": "scripts/evaluate_score_in_place.py",
|
| 12 |
+
"train_docking": "scripts/train_accelarete.py",
|
| 13 |
+
"train_score": "scripts/train_mdn_accelarete.py"
|
| 14 |
+
},
|
| 15 |
+
"source": "model",
|
| 16 |
+
"weights": "weight"
|
| 17 |
+
}
|
environment.yaml
ADDED
|
@@ -0,0 +1,434 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
name: SurfDock
|
| 2 |
+
channels:
|
| 3 |
+
- mx
|
| 4 |
+
- pyg
|
| 5 |
+
- pytorch
|
| 6 |
+
- nvidia
|
| 7 |
+
- defaults
|
| 8 |
+
- conda-forge
|
| 9 |
+
dependencies:
|
| 10 |
+
- _libgcc_mutex=0.1=conda_forge
|
| 11 |
+
- _openmp_mutex=4.5=2_kmp_llvm
|
| 12 |
+
- aiohttp=3.9.3=py310h2372a71_1
|
| 13 |
+
- aiosignal=1.3.1=pyhd8ed1ab_0
|
| 14 |
+
- ambertools=22.5=py310hd182041_0
|
| 15 |
+
- annotated-types=0.6.0=pyhd8ed1ab_0
|
| 16 |
+
- anyio=4.3.0=pyhd8ed1ab_0
|
| 17 |
+
- archspec=0.2.3=pyhd8ed1ab_0
|
| 18 |
+
- argon2-cffi=23.1.0=pyhd8ed1ab_0
|
| 19 |
+
- argon2-cffi-bindings=21.2.0=py310h2372a71_4
|
| 20 |
+
- arpack=3.7.0=hdefa2d7_2
|
| 21 |
+
- arrow=1.3.0=pyhd8ed1ab_0
|
| 22 |
+
- asttokens=2.4.1=pyhd8ed1ab_0
|
| 23 |
+
- astunparse=1.6.3=pyhd8ed1ab_0
|
| 24 |
+
- async-lru=2.0.4=pyhd8ed1ab_0
|
| 25 |
+
- async-timeout=4.0.3=pyhd8ed1ab_0
|
| 26 |
+
- attrs=23.2.0=pyh71513ae_0
|
| 27 |
+
- babel=2.13.1=pyhd8ed1ab_0
|
| 28 |
+
- beautifulsoup4=4.12.3=pyha770c72_0
|
| 29 |
+
- biopandas=0.4.1=pyhd8ed1ab_1
|
| 30 |
+
- blas=2.116=mkl
|
| 31 |
+
- blas-devel=3.9.0=16_linux64_mkl
|
| 32 |
+
- bleach=6.1.0=pyhd8ed1ab_0
|
| 33 |
+
- blosc=1.21.5=hc2324a3_1
|
| 34 |
+
- boltons=24.0.0=pyhd8ed1ab_0
|
| 35 |
+
- boost=1.78.0=py310hcb52e73_5
|
| 36 |
+
- boost-cpp=1.78.0=h2c5509c_4
|
| 37 |
+
- brotli=1.1.0=hd590300_1
|
| 38 |
+
- brotli-bin=1.1.0=hd590300_1
|
| 39 |
+
- brotli-python=1.1.0=py310hc6cd4ac_1
|
| 40 |
+
- bson=0.5.9=py_0
|
| 41 |
+
- bzip2=1.0.8=hd590300_5
|
| 42 |
+
- c-ares=1.28.1=hd590300_0
|
| 43 |
+
- c-blosc2=2.14.4=hb4ffafa_1
|
| 44 |
+
- ca-certificates=2024.8.30=hbcca054_0
|
| 45 |
+
- cached-property=1.5.2=hd8ed1ab_1
|
| 46 |
+
- cached_property=1.5.2=pyha770c72_1
|
| 47 |
+
- cachetools=5.3.3=pyhd8ed1ab_0
|
| 48 |
+
- cairo=1.18.0=h3faef2a_0
|
| 49 |
+
- certifi=2024.8.30=pyhd8ed1ab_0
|
| 50 |
+
- cffi=1.16.0=py310h2fee648_0
|
| 51 |
+
- charset-normalizer=3.3.2=pyhd8ed1ab_0
|
| 52 |
+
- colorama=0.4.6=pyhd8ed1ab_0
|
| 53 |
+
- comm=0.2.2=pyhd8ed1ab_0
|
| 54 |
+
- conda=24.5.0=py310h06a4308_0
|
| 55 |
+
- conda-libmamba-solver=24.1.0=pyhd8ed1ab_0
|
| 56 |
+
- conda-package-handling=2.2.0=pyh38be061_0
|
| 57 |
+
- conda-package-streaming=0.9.0=pyhd8ed1ab_0
|
| 58 |
+
- contourpy=1.2.1=py310hd41b1e2_0
|
| 59 |
+
- cuda-cudart=12.1.105=0
|
| 60 |
+
- cuda-cupti=12.1.105=0
|
| 61 |
+
- cuda-libraries=12.1.0=0
|
| 62 |
+
- cuda-nvrtc=12.1.105=0
|
| 63 |
+
- cuda-nvtx=12.1.105=0
|
| 64 |
+
- cuda-opencl=12.4.127=0
|
| 65 |
+
- cuda-runtime=12.1.0=0
|
| 66 |
+
- cudatoolkit=11.8.0=h4ba93d1_13
|
| 67 |
+
- cycler=0.12.1=pyhd8ed1ab_0
|
| 68 |
+
- cython=3.0.10=py310hc6cd4ac_0
|
| 69 |
+
- debugpy=1.8.1=py310hc6cd4ac_0
|
| 70 |
+
- decorator=5.1.1=pyhd8ed1ab_0
|
| 71 |
+
- defusedxml=0.7.1=pyhd8ed1ab_0
|
| 72 |
+
- distro=1.9.0=pyhd8ed1ab_0
|
| 73 |
+
- entrypoints=0.4=pyhd8ed1ab_0
|
| 74 |
+
- exceptiongroup=1.2.0=pyhd8ed1ab_2
|
| 75 |
+
- executing=2.0.1=pyhd8ed1ab_0
|
| 76 |
+
- expat=2.6.2=h59595ed_0
|
| 77 |
+
- ffmpeg=4.3=hf484d3e_0
|
| 78 |
+
- fftw=3.3.10=nompi_hc118613_108
|
| 79 |
+
- filelock=3.13.4=pyhd8ed1ab_0
|
| 80 |
+
- fmt=10.2.1=h00ab1b0_0
|
| 81 |
+
- font-ttf-dejavu-sans-mono=2.37=hab24e00_0
|
| 82 |
+
- font-ttf-inconsolata=3.000=h77eed37_0
|
| 83 |
+
- font-ttf-source-code-pro=2.038=h77eed37_0
|
| 84 |
+
- font-ttf-ubuntu=0.83=h77eed37_1
|
| 85 |
+
- fontconfig=2.14.2=h14ed4e7_0
|
| 86 |
+
- fonts-conda-ecosystem=1=0
|
| 87 |
+
- fonts-conda-forge=1=0
|
| 88 |
+
- fonttools=4.51.0=py310h2372a71_0
|
| 89 |
+
- fqdn=1.5.1=pyhd8ed1ab_0
|
| 90 |
+
- freetype=2.12.1=h267a509_2
|
| 91 |
+
- frozendict=2.4.2=py310h5eee18b_0
|
| 92 |
+
- frozenlist=1.4.1=py310h2372a71_0
|
| 93 |
+
- fsspec=2024.3.1=pyhca7485f_0
|
| 94 |
+
- gmp=6.3.0=h59595ed_1
|
| 95 |
+
- gmpy2=2.1.2=py310h3ec546c_1
|
| 96 |
+
- gnutls=3.6.13=h85f3911_1
|
| 97 |
+
- greenlet=3.0.3=py310hc6cd4ac_0
|
| 98 |
+
- h11=0.14.0=pyhd8ed1ab_0
|
| 99 |
+
- h2=4.1.0=pyhd8ed1ab_0
|
| 100 |
+
- hdf4=4.2.15=h9772cbc_5
|
| 101 |
+
- hdf5=1.14.3=nompi_h4f84152_100
|
| 102 |
+
- hpack=4.0.0=pyh9f0ad1d_0
|
| 103 |
+
- httpcore=1.0.5=pyhd8ed1ab_0
|
| 104 |
+
- httpx=0.27.0=pyhd8ed1ab_0
|
| 105 |
+
- hyperframe=6.0.1=pyhd8ed1ab_0
|
| 106 |
+
- icu=73.2=h59595ed_0
|
| 107 |
+
- idna=3.6=pyhd8ed1ab_0
|
| 108 |
+
- importlib-metadata=7.1.0=pyha770c72_0
|
| 109 |
+
- importlib_metadata=7.1.0=hd8ed1ab_0
|
| 110 |
+
- importlib_resources=6.4.0=pyhd8ed1ab_0
|
| 111 |
+
- ipykernel=6.29.3=pyhd33586a_0
|
| 112 |
+
- ipython=8.22.2=pyh707e725_0
|
| 113 |
+
- ipywidgets=8.1.2=pyhd8ed1ab_0
|
| 114 |
+
- isoduration=20.11.0=pyhd8ed1ab_0
|
| 115 |
+
- jedi=0.19.1=pyhd8ed1ab_0
|
| 116 |
+
- jinja2=3.1.3=pyhd8ed1ab_0
|
| 117 |
+
- joblib=1.4.0=pyhd8ed1ab_0
|
| 118 |
+
- jpeg=9e=h166bdaf_2
|
| 119 |
+
- json5=0.9.24=pyhd8ed1ab_0
|
| 120 |
+
- jsonpatch=1.33=pyhd8ed1ab_0
|
| 121 |
+
- jsonpointer=2.4=py310hff52083_3
|
| 122 |
+
- jsonschema=4.21.1=pyhd8ed1ab_0
|
| 123 |
+
- jsonschema-specifications=2023.12.1=pyhd8ed1ab_0
|
| 124 |
+
- jsonschema-with-format-nongpl=4.21.1=pyhd8ed1ab_0
|
| 125 |
+
- jupyter-lsp=2.2.5=pyhd8ed1ab_0
|
| 126 |
+
- jupyter_client=8.6.1=pyhd8ed1ab_0
|
| 127 |
+
- jupyter_core=5.7.2=py310hff52083_0
|
| 128 |
+
- jupyter_events=0.10.0=pyhd8ed1ab_0
|
| 129 |
+
- jupyter_server=2.14.0=pyhd8ed1ab_0
|
| 130 |
+
- jupyter_server_terminals=0.5.3=pyhd8ed1ab_0
|
| 131 |
+
- jupyterlab=4.1.6=pyhd8ed1ab_0
|
| 132 |
+
- jupyterlab_pygments=0.3.0=pyhd8ed1ab_1
|
| 133 |
+
- jupyterlab_server=2.26.0=pyhd8ed1ab_0
|
| 134 |
+
- jupyterlab_widgets=3.0.10=pyhd8ed1ab_0
|
| 135 |
+
- keyutils=1.6.1=h166bdaf_0
|
| 136 |
+
- kiwisolver=1.4.5=py310hd41b1e2_1
|
| 137 |
+
- krb5=1.21.2=h659d440_0
|
| 138 |
+
- lame=3.100=h166bdaf_1003
|
| 139 |
+
- lcms2=2.12=hddcbb42_0
|
| 140 |
+
- ld_impl_linux-64=2.40=h41732ed_0
|
| 141 |
+
- lerc=3.0=h9c3ff4c_0
|
| 142 |
+
- libaec=1.1.3=h59595ed_0
|
| 143 |
+
- libarchive=3.7.2=h2aa1ff5_1
|
| 144 |
+
- libblas=3.9.0=16_linux64_mkl
|
| 145 |
+
- libbrotlicommon=1.1.0=hd590300_1
|
| 146 |
+
- libbrotlidec=1.1.0=hd590300_1
|
| 147 |
+
- libbrotlienc=1.1.0=hd590300_1
|
| 148 |
+
- libcblas=3.9.0=16_linux64_mkl
|
| 149 |
+
- libcublas=12.1.0.26=0
|
| 150 |
+
- libcufft=11.0.2.4=0
|
| 151 |
+
- libcufile=1.9.1.3=0
|
| 152 |
+
- libcurand=10.3.5.147=0
|
| 153 |
+
- libcurl=8.7.1=hca28451_0
|
| 154 |
+
- libcusolver=11.4.4.55=0
|
| 155 |
+
- libcusparse=12.0.2.55=0
|
| 156 |
+
- libdeflate=1.10=h7f98852_0
|
| 157 |
+
- libedit=3.1.20191231=he28a2e2_2
|
| 158 |
+
- libev=4.33=hd590300_2
|
| 159 |
+
- libexpat=2.6.2=h59595ed_0
|
| 160 |
+
- libffi=3.4.2=h7f98852_5
|
| 161 |
+
- libgcc=14.2.0=h77fa898_1
|
| 162 |
+
- libgcc-ng=14.2.0=h69a702a_1
|
| 163 |
+
- libgfortran-ng=13.2.0=h69a702a_5
|
| 164 |
+
- libgfortran5=13.2.0=ha4646dd_5
|
| 165 |
+
- libglib=2.80.0=hf2295e7_4
|
| 166 |
+
- libgomp=14.2.0=h77fa898_1
|
| 167 |
+
- libhwloc=2.9.3=default_h554bfaf_1009
|
| 168 |
+
- libiconv=1.17=hd590300_2
|
| 169 |
+
- libjpeg-turbo=2.0.0=h9bf148f_0
|
| 170 |
+
- liblapack=3.9.0=16_linux64_mkl
|
| 171 |
+
- liblapacke=3.9.0=16_linux64_mkl
|
| 172 |
+
- libmamba=1.5.8=had39da4_0
|
| 173 |
+
- libmambapy=1.5.8=py310h39ff949_0
|
| 174 |
+
- libnetcdf=4.9.2=nompi_h9612171_113
|
| 175 |
+
- libnghttp2=1.58.0=h47da74e_1
|
| 176 |
+
- libnpp=12.0.2.50=0
|
| 177 |
+
- libnsl=2.0.1=hd590300_0
|
| 178 |
+
- libnvjitlink=12.1.105=0
|
| 179 |
+
- libnvjpeg=12.1.1.14=0
|
| 180 |
+
- libpng=1.6.43=h2797004_0
|
| 181 |
+
- libsodium=1.0.18=h36c2ea0_1
|
| 182 |
+
- libsolv=0.7.28=hfc55251_2
|
| 183 |
+
- libsqlite=3.45.2=h2797004_0
|
| 184 |
+
- libssh2=1.11.0=h0841786_0
|
| 185 |
+
- libstdcxx-ng=13.2.0=h7e041cc_5
|
| 186 |
+
- libtiff=4.3.0=h0fcbabc_4
|
| 187 |
+
- libuuid=2.38.1=h0b41bf4_0
|
| 188 |
+
- libwebp-base=1.3.2=hd590300_1
|
| 189 |
+
- libxcb=1.15=h0b41bf4_0
|
| 190 |
+
- libxcrypt=4.4.36=hd590300_1
|
| 191 |
+
- libxml2=2.12.6=h232c23b_1
|
| 192 |
+
- libxslt=1.1.39=h76b75d6_0
|
| 193 |
+
- libzip=1.10.1=h2629f0a_3
|
| 194 |
+
- libzlib=1.2.13=hd590300_5
|
| 195 |
+
- lightning-utilities=0.11.2=pyhd8ed1ab_0
|
| 196 |
+
- llvm-openmp=15.0.7=h0cdce71_0
|
| 197 |
+
- loguru=0.7.2=py310hff52083_2
|
| 198 |
+
- lxml=5.1.0=py310hcfd0673_0
|
| 199 |
+
- lz4-c=1.9.4=hcb278e6_0
|
| 200 |
+
- lzo=2.10=h516909a_1000
|
| 201 |
+
- mamba=1.5.8=py310h51d5547_0
|
| 202 |
+
- markupsafe=2.1.5=py310h2372a71_0
|
| 203 |
+
- matplotlib-base=3.8.4=py310h62c0568_0
|
| 204 |
+
- matplotlib-inline=0.1.6=pyhd8ed1ab_0
|
| 205 |
+
- mda-xdrlib=0.2.0=pyhd8ed1ab_0
|
| 206 |
+
- mdtraj=1.9.9=py310h523e8d7_1
|
| 207 |
+
- menuinst=2.0.2=py310hff52083_0
|
| 208 |
+
- mistune=3.0.2=pyhd8ed1ab_0
|
| 209 |
+
- mkl=2022.1.0=h84fe81f_915
|
| 210 |
+
- mkl-devel=2022.1.0=ha770c72_916
|
| 211 |
+
- mkl-include=2022.1.0=h84fe81f_915
|
| 212 |
+
- mpc=1.3.1=hfe3b2da_0
|
| 213 |
+
- mpfr=4.2.1=h9458935_1
|
| 214 |
+
- mpmath=1.3.0=pyhd8ed1ab_0
|
| 215 |
+
- multidict=6.0.5=py310h2372a71_0
|
| 216 |
+
- munkres=1.1.4=pyh9f0ad1d_0
|
| 217 |
+
- nbclient=0.10.0=pyhd8ed1ab_0
|
| 218 |
+
- nbconvert-core=7.16.3=pyhd8ed1ab_1
|
| 219 |
+
- nbformat=5.10.4=pyhd8ed1ab_0
|
| 220 |
+
- ncurses=6.4.20240210=h59595ed_0
|
| 221 |
+
- nest-asyncio=1.6.0=pyhd8ed1ab_0
|
| 222 |
+
- netcdf-fortran=4.6.1=nompi_hacb5139_103
|
| 223 |
+
- nettle=3.6=he412f7d_0
|
| 224 |
+
- networkx=3.2=pyhd8ed1ab_0
|
| 225 |
+
- notebook=7.1.2=pyhd8ed1ab_0
|
| 226 |
+
- notebook-shim=0.2.4=pyhd8ed1ab_0
|
| 227 |
+
- ocl-icd=2.3.2=hd590300_1
|
| 228 |
+
- ocl-icd-system=1.0.0=1
|
| 229 |
+
- olefile=0.47=pyhd8ed1ab_0
|
| 230 |
+
- openbabel=3.1.1=py310hbff9852_9
|
| 231 |
+
- openff-amber-ff-ports=0.0.4=pyhca7485f_0
|
| 232 |
+
- openff-forcefields=2024.03.0=pyhca7485f_0
|
| 233 |
+
- openff-interchange=0.3.25=pyhd8ed1ab_1
|
| 234 |
+
- openff-interchange-base=0.3.25=pyhd8ed1ab_1
|
| 235 |
+
- openff-models=0.1.2=pyhca7485f_0
|
| 236 |
+
- openff-toolkit=0.15.2=pyhd8ed1ab_0
|
| 237 |
+
- openff-toolkit-base=0.15.2=pyhd8ed1ab_0
|
| 238 |
+
- openff-units=0.2.2=pyhca7485f_0
|
| 239 |
+
- openff-utilities=0.1.12=pyhd8ed1ab_0
|
| 240 |
+
- openh264=2.1.1=h780b84a_0
|
| 241 |
+
- openjpeg=2.5.0=h7d73246_0
|
| 242 |
+
- openmm=8.1.1=py310h43b6314_1
|
| 243 |
+
- openmmforcefields=0.12.0=pyhd8ed1ab_0
|
| 244 |
+
- openssl=3.4.0=hb9d3cd8_0
|
| 245 |
+
- overrides=7.7.0=pyhd8ed1ab_0
|
| 246 |
+
- packaging=24.0=pyhd8ed1ab_0
|
| 247 |
+
- packmol=20.010=h86c2bf4_0
|
| 248 |
+
- pandas=2.1.2=py310hcc13569_0
|
| 249 |
+
- pandocfilters=1.5.0=pyhd8ed1ab_0
|
| 250 |
+
- panedr=0.8.0=pyhd8ed1ab_0
|
| 251 |
+
- parmed=4.2.2=py310hc6cd4ac_1
|
| 252 |
+
- parso=0.8.4=pyhd8ed1ab_0
|
| 253 |
+
- pcre2=10.43=hcad00b1_0
|
| 254 |
+
- pdbfixer=1.9=pyh1a96a4e_0
|
| 255 |
+
- perl=5.32.1=7_hd590300_perl5
|
| 256 |
+
- pexpect=4.9.0=pyhd8ed1ab_0
|
| 257 |
+
- pickleshare=0.7.5=py_1003
|
| 258 |
+
- pillow=8.4.0=py310h07f4688_0
|
| 259 |
+
- pint=0.23=pyhd8ed1ab_0
|
| 260 |
+
- pip=24.0=pyhd8ed1ab_0
|
| 261 |
+
- pixman=0.43.2=h59595ed_0
|
| 262 |
+
- pkgutil-resolve-name=1.3.10=pyhd8ed1ab_1
|
| 263 |
+
- platformdirs=4.2.0=pyhd8ed1ab_0
|
| 264 |
+
- pluggy=1.4.0=pyhd8ed1ab_0
|
| 265 |
+
- plyfile=1.0.1=pyhd8ed1ab_0
|
| 266 |
+
- prody=2.4.0=py310heca2aa9_0
|
| 267 |
+
- prometheus_client=0.20.0=pyhd8ed1ab_0
|
| 268 |
+
- prompt-toolkit=3.0.42=pyha770c72_0
|
| 269 |
+
- psutil=5.9.8=py310h2372a71_0
|
| 270 |
+
- pthread-stubs=0.4=h36c2ea0_1001
|
| 271 |
+
- ptyprocess=0.7.0=pyhd3deb0d_0
|
| 272 |
+
- pure_eval=0.2.2=pyhd8ed1ab_0
|
| 273 |
+
- py-cpuinfo=9.0.0=pyhd8ed1ab_0
|
| 274 |
+
- pybind11-abi=4=hd8ed1ab_3
|
| 275 |
+
- pycairo=1.26.0=py310hda9f760_0
|
| 276 |
+
- pycosat=0.6.6=py310h2372a71_0
|
| 277 |
+
- pycparser=2.22=pyhd8ed1ab_0
|
| 278 |
+
- pydantic=2.7.0=pyhd8ed1ab_0
|
| 279 |
+
- pydantic-core=2.18.1=py310hcb5633a_0
|
| 280 |
+
- pyedr=0.8.0=pyhd8ed1ab_0
|
| 281 |
+
- pyg=2.5.2=py310_torch_2.2.0_cu121
|
| 282 |
+
- pygments=2.17.2=pyhd8ed1ab_0
|
| 283 |
+
- pyparsing=3.1.2=pyhd8ed1ab_0
|
| 284 |
+
- pysocks=1.7.1=pyha2e5f31_6
|
| 285 |
+
- pytables=3.9.2=py310hd76cd5d_2
|
| 286 |
+
- python=3.10.0=h543edf9_3_cpython
|
| 287 |
+
- python-constraint=1.4.0=py_0
|
| 288 |
+
- python-dateutil=2.9.0=pyhd8ed1ab_0
|
| 289 |
+
- python-fastjsonschema=2.19.1=pyhd8ed1ab_0
|
| 290 |
+
- python-json-logger=2.0.7=pyhd8ed1ab_0
|
| 291 |
+
- python-tzdata=2024.1=pyhd8ed1ab_0
|
| 292 |
+
- python_abi=3.10=4_cp310
|
| 293 |
+
- pytorch=2.2.2=py3.10_cuda12.1_cudnn8.9.2_0
|
| 294 |
+
- pytorch-cuda=12.1=ha16c6d3_5
|
| 295 |
+
- pytorch-mutex=1.0=cuda
|
| 296 |
+
- pytz=2024.1=pyhd8ed1ab_0
|
| 297 |
+
- pyyaml=6.0.1=py310h2372a71_1
|
| 298 |
+
- pyzmq=25.1.2=py310h795f18f_0
|
| 299 |
+
- readline=8.2=h8228510_1
|
| 300 |
+
- reduce=3.24=0
|
| 301 |
+
- referencing=0.34.0=pyhd8ed1ab_0
|
| 302 |
+
- reportlab=3.5.68=py310h94fcab3_1
|
| 303 |
+
- reproc=14.2.4.post0=hd590300_1
|
| 304 |
+
- reproc-cpp=14.2.4.post0=h59595ed_1
|
| 305 |
+
- requests=2.31.0=pyhd8ed1ab_0
|
| 306 |
+
- rfc3339-validator=0.1.4=pyhd8ed1ab_0
|
| 307 |
+
- rfc3986-validator=0.1.1=pyh9f0ad1d_0
|
| 308 |
+
- rpds-py=0.18.0=py310hcb5633a_0
|
| 309 |
+
- ruamel.yaml=0.18.6=py310h2372a71_0
|
| 310 |
+
- ruamel.yaml.clib=0.2.8=py310h2372a71_0
|
| 311 |
+
- scipy=1.8.1=py310hdfbd76f_2
|
| 312 |
+
- send2trash=1.8.3=pyh0d859eb_0
|
| 313 |
+
- setuptools=69.2.0=pyhd8ed1ab_0
|
| 314 |
+
- six=1.16.0=pyh6c4a22f_0
|
| 315 |
+
- smirnoff99frosst=1.1.0=pyh44b312d_0
|
| 316 |
+
- snappy=1.2.0=hdb0a2a9_1
|
| 317 |
+
- sniffio=1.3.1=pyhd8ed1ab_0
|
| 318 |
+
- soupsieve=2.5=pyhd8ed1ab_1
|
| 319 |
+
- sqlalchemy=2.0.29=py310h2372a71_0
|
| 320 |
+
- sqlite=3.45.2=h2c6b66d_0
|
| 321 |
+
- stack_data=0.6.2=pyhd8ed1ab_0
|
| 322 |
+
- sympy=1.12=pypyh9d50eac_103
|
| 323 |
+
- tbb=2021.11.0=h00ab1b0_1
|
| 324 |
+
- terminado=0.18.1=pyh0d859eb_0
|
| 325 |
+
- threadpoolctl=3.4.0=pyhc1e730c_0
|
| 326 |
+
- tinycss2=1.2.1=pyhd8ed1ab_0
|
| 327 |
+
- tinydb=4.8.0=pyhd8ed1ab_0
|
| 328 |
+
- tk=8.6.13=noxft_h4845f30_101
|
| 329 |
+
- tomli=2.0.1=pyhd8ed1ab_0
|
| 330 |
+
- torch-ema=0.3=pyhd8ed1ab_0
|
| 331 |
+
- torchaudio=2.2.2=py310_cu121
|
| 332 |
+
- torchmetrics=1.2.1=pyhd8ed1ab_0
|
| 333 |
+
- torchtriton=2.2.0=py310
|
| 334 |
+
- torchvision=0.17.2=py310_cu121
|
| 335 |
+
- tornado=6.4=py310h2372a71_0
|
| 336 |
+
- tqdm=4.66.2=pyhd8ed1ab_0
|
| 337 |
+
- traitlets=5.14.2=pyhd8ed1ab_0
|
| 338 |
+
- truststore=0.8.0=pyhd8ed1ab_0
|
| 339 |
+
- types-python-dateutil=2.9.0.20240316=pyhd8ed1ab_0
|
| 340 |
+
- typing-extensions=4.11.0=hd8ed1ab_0
|
| 341 |
+
- typing_extensions=4.11.0=pyha770c72_0
|
| 342 |
+
- typing_utils=0.1.0=pyhd8ed1ab_0
|
| 343 |
+
- tzdata=2024a=h0c530f3_0
|
| 344 |
+
- unicodedata2=15.1.0=py310h2372a71_0
|
| 345 |
+
- uri-template=1.3.0=pyhd8ed1ab_0
|
| 346 |
+
- urllib3=2.2.1=pyhd8ed1ab_0
|
| 347 |
+
- validators=0.28.0=pyhd8ed1ab_0
|
| 348 |
+
- wcwidth=0.2.13=pyhd8ed1ab_0
|
| 349 |
+
- webcolors=1.13=pyhd8ed1ab_0
|
| 350 |
+
- webencodings=0.5.1=pyhd8ed1ab_2
|
| 351 |
+
- websocket-client=1.7.0=pyhd8ed1ab_0
|
| 352 |
+
- wheel=0.43.0=pyhd8ed1ab_1
|
| 353 |
+
- widgetsnbextension=4.0.10=pyhd8ed1ab_0
|
| 354 |
+
- xmltodict=0.13.0=pyhd8ed1ab_0
|
| 355 |
+
- xorg-kbproto=1.0.7=h7f98852_1002
|
| 356 |
+
- xorg-libice=1.1.1=hd590300_0
|
| 357 |
+
- xorg-libsm=1.2.4=h7391055_0
|
| 358 |
+
- xorg-libx11=1.8.9=h8ee46fc_0
|
| 359 |
+
- xorg-libxau=1.0.11=hd590300_0
|
| 360 |
+
- xorg-libxdmcp=1.1.3=h7f98852_0
|
| 361 |
+
- xorg-libxext=1.3.4=h0b41bf4_2
|
| 362 |
+
- xorg-libxrender=0.9.11=hd590300_0
|
| 363 |
+
- xorg-libxt=1.3.0=hd590300_1
|
| 364 |
+
- xorg-renderproto=0.11.1=h7f98852_1002
|
| 365 |
+
- xorg-xextproto=7.3.0=h0b41bf4_1003
|
| 366 |
+
- xorg-xproto=7.0.31=h7f98852_1007
|
| 367 |
+
- xz=5.2.6=h166bdaf_0
|
| 368 |
+
- yaml=0.2.5=h7f98852_2
|
| 369 |
+
- yaml-cpp=0.8.0=h59595ed_0
|
| 370 |
+
- yarl=1.9.4=py310h2372a71_0
|
| 371 |
+
- zeromq=4.3.5=h59595ed_1
|
| 372 |
+
- zipp=3.17.0=pyhd8ed1ab_0
|
| 373 |
+
- zlib=1.2.13=hd590300_5
|
| 374 |
+
- zlib-ng=2.0.7=h0b41bf4_0
|
| 375 |
+
- zstandard=0.22.0=py310h1275a96_0
|
| 376 |
+
- zstd=1.5.5=hfc55251_0
|
| 377 |
+
- pip:
|
| 378 |
+
- accelerate==0.15.0
|
| 379 |
+
- amberlite==22.0
|
| 380 |
+
- amberutils==21.0
|
| 381 |
+
- appdirs==1.4.4
|
| 382 |
+
- biopython==1.79
|
| 383 |
+
- click==8.1.7
|
| 384 |
+
- dimorphite-dl==1.3.2
|
| 385 |
+
- docker-pycreds==0.4.0
|
| 386 |
+
- e3nn==0.5.1
|
| 387 |
+
- et-xmlfile==1.1.0
|
| 388 |
+
- fair-esm==2.0.1
|
| 389 |
+
- fasteners==0.19
|
| 390 |
+
- gitdb==4.0.11
|
| 391 |
+
- gitpython==3.1.43
|
| 392 |
+
- griddataformats==1.0.2
|
| 393 |
+
- gsd==3.2.1
|
| 394 |
+
- huggingface-hub==0.17.3
|
| 395 |
+
- jupyter==1.0.0
|
| 396 |
+
- jupyter-console==6.6.3
|
| 397 |
+
- mdanalysis==2.4.0
|
| 398 |
+
- mmpbsa-py==16.0
|
| 399 |
+
- mmtf-python==1.1.3
|
| 400 |
+
- mrcfile==1.5.0
|
| 401 |
+
- msgpack==1.0.8
|
| 402 |
+
- numexpr==2.10.0
|
| 403 |
+
- numpy==1.24.4
|
| 404 |
+
- openpyxl==3.1.3
|
| 405 |
+
- opt-einsum==3.3.0
|
| 406 |
+
- opt-einsum-fx==0.1.4
|
| 407 |
+
- packmol-memgen==1.2.3rc0
|
| 408 |
+
- pdb4amber==22.0
|
| 409 |
+
- posebusters==0.2.13
|
| 410 |
+
- prefetch-generator==1.0.3
|
| 411 |
+
- protobuf==4.25.3
|
| 412 |
+
- pyg-lib==0.4.0+pt22cu121
|
| 413 |
+
- pymesh==1.0.2
|
| 414 |
+
- pymesh2==0.3.1
|
| 415 |
+
- pympler==1.0.1
|
| 416 |
+
- pytraj==2.0.6
|
| 417 |
+
- qtconsole==5.5.2
|
| 418 |
+
- qtpy==2.4.1
|
| 419 |
+
- rdkit==2023.3.1
|
| 420 |
+
- rdkit-pypi==2022.9.5
|
| 421 |
+
- regex==2023.12.25
|
| 422 |
+
- sander==22.0
|
| 423 |
+
- scikit-learn==1.3.2
|
| 424 |
+
- sentry-sdk==1.45.0
|
| 425 |
+
- setproctitle==1.3.3
|
| 426 |
+
- smmap==5.0.1
|
| 427 |
+
- spyrmsd==0.7.0
|
| 428 |
+
- tokenizers==0.13.3
|
| 429 |
+
- torch-cluster==1.6.3+pt22cu121
|
| 430 |
+
- torch-scatter==2.1.2+pt22cu121
|
| 431 |
+
- torch-sparse==0.6.18+pt22cu121
|
| 432 |
+
- torch-spline-conv==1.2.2+pt22cu121
|
| 433 |
+
- transformers==4.29.2
|
| 434 |
+
- wandb==0.16.1
|
model/comp_surface/prepare_target/__init_.py
ADDED
|
File without changes
|
model/comp_surface/prepare_target/computeAPBS.py
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import numpy
|
| 3 |
+
from subprocess import Popen, PIPE
|
| 4 |
+
import pymesh
|
| 5 |
+
import tempfile
|
| 6 |
+
|
| 7 |
+
from default_config.global_vars import apbs_bin, pdb2pqr_bin, multivalue_bin
|
| 8 |
+
import random
|
| 9 |
+
|
| 10 |
+
"""
|
| 11 |
+
Modified from:
|
| 12 |
+
computeAPBS.py: Wrapper function to compute the Poisson Boltzmann electrostatics for a surface using APBS.
|
| 13 |
+
Pablo Gainza - LPDI STI EPFL 2019
|
| 14 |
+
"""
|
| 15 |
+
|
| 16 |
+
def computeAPBS(vertices, pdb_file, tmp_file_base,clear=False):
|
| 17 |
+
"""
|
| 18 |
+
Calls APBS, pdb2pqr, and multivalue and returns the charges per vertex
|
| 19 |
+
"""
|
| 20 |
+
if not clear:
|
| 21 |
+
pdb2pqr = pdb2pqr_bin + " --ff=parse --whitespace --noopt --apbs-input %s %s"# + tempfile.mktemp()
|
| 22 |
+
# pdb2pqr = pdb2pqr_bin + " --clean --whitespace --noopt --apbs-input %s %s"# + tempfile.mktemp() # 上一行由于确实太多办法计算表面的时候再用这个
|
| 23 |
+
else:
|
| 24 |
+
pdb2pqr = pdb2pqr_bin + " --clean --whitespace --noopt --apbs-input %s %s"# + tempfile.mktemp() # 上一行由于确实太多办法计算表面的时候再用这个
|
| 25 |
+
make_pqr = pdb2pqr % (pdb_file, tmp_file_base)
|
| 26 |
+
os.system(make_pqr)
|
| 27 |
+
print('os.system(make_pqr)',os.system(make_pqr))
|
| 28 |
+
|
| 29 |
+
apbs = apbs_bin + " %s"
|
| 30 |
+
make_apbs = apbs % (tmp_file_base+".in")
|
| 31 |
+
# os.system(make_apbs)
|
| 32 |
+
print(make_apbs)
|
| 33 |
+
print('os.system(make_apbs)',os.system(make_apbs))
|
| 34 |
+
|
| 35 |
+
vertfile = open(tmp_file_base + ".csv", "w")
|
| 36 |
+
for vert in vertices:
|
| 37 |
+
vertfile.write("{},{},{}\n".format(vert[0], vert[1], vert[2]))
|
| 38 |
+
vertfile.close()
|
| 39 |
+
|
| 40 |
+
multivalue = multivalue_bin + " %s %s %s"
|
| 41 |
+
make_multivalue = multivalue % (tmp_file_base+".csv", tmp_file_base+".dx", tmp_file_base+"_out.csv")
|
| 42 |
+
# print(make_multivalue)
|
| 43 |
+
try:
|
| 44 |
+
os.system(make_multivalue)
|
| 45 |
+
except Exception as e:
|
| 46 |
+
print(e)
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
# Read the charge file
|
| 50 |
+
chargefile = open(tmp_file_base + "_out.csv")
|
| 51 |
+
charges = numpy.array([0.0] * len(vertices))
|
| 52 |
+
for ix, line in enumerate(chargefile.readlines()):
|
| 53 |
+
charges[ix] = float(line.split(",")[3])
|
| 54 |
+
# os.system("rm " + tmp_file_base + "*")
|
| 55 |
+
# os.system("rm io.mc")
|
| 56 |
+
|
| 57 |
+
return charges
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
|
| 61 |
+
""" ORIGINAL FUNCTION
|
| 62 |
+
'''
|
| 63 |
+
computeAPBS.py: Wrapper function to compute the Poisson Boltzmann electrostatics for a surface using APBS.
|
| 64 |
+
Pablo Gainza - LPDI STI EPFL 2019
|
| 65 |
+
This file is part of MaSIF.
|
| 66 |
+
Released under an Apache License 2.0
|
| 67 |
+
'''
|
| 68 |
+
|
| 69 |
+
def computeAPBS(vertices, pdb_file, tmp_file_base = tempfile.mktemp()):
|
| 70 |
+
|
| 71 |
+
#Calls APBS, pdb2pqr, and multivalue and returns the charges per vertex
|
| 72 |
+
|
| 73 |
+
#fields = tmp_file_base.split("/")[0:-1]
|
| 74 |
+
#directory = "/".join(fields) + "/"
|
| 75 |
+
fields = tmp_file_base
|
| 76 |
+
directory = str(fields) + "/"
|
| 77 |
+
filename_base = tmp_file_base.split("/")[-1]
|
| 78 |
+
pdbname = pdb_file.split("/")[-1]
|
| 79 |
+
args = [
|
| 80 |
+
pdb2pqr_bin,
|
| 81 |
+
"--ff=parse",
|
| 82 |
+
"--whitespace",
|
| 83 |
+
"--noopt",
|
| 84 |
+
"--apbs-input",
|
| 85 |
+
pdbname,
|
| 86 |
+
filename_base,
|
| 87 |
+
]
|
| 88 |
+
p2 = Popen(args, stdout=PIPE, stderr=PIPE, cwd=directory)
|
| 89 |
+
stdout, stderr = p2.communicate()
|
| 90 |
+
|
| 91 |
+
args = [apbs_bin, filename_base + ".in"]
|
| 92 |
+
p2 = Popen(args, stdout=PIPE, stderr=PIPE, cwd=directory)
|
| 93 |
+
stdout, stderr = p2.communicate()
|
| 94 |
+
|
| 95 |
+
vertfile = open(directory + "/" + filename_base + ".csv", "w")
|
| 96 |
+
for vert in vertices:
|
| 97 |
+
vertfile.write("{},{},{}\n".format(vert[0], vert[1], vert[2]))
|
| 98 |
+
vertfile.close()
|
| 99 |
+
|
| 100 |
+
args = [
|
| 101 |
+
multivalue_bin,
|
| 102 |
+
filename_base + ".csv",
|
| 103 |
+
filename_base + ".dx",
|
| 104 |
+
filename_base + "_out.csv",
|
| 105 |
+
]
|
| 106 |
+
p2 = Popen(args, stdout=PIPE, stderr=PIPE, cwd=directory)
|
| 107 |
+
stdout, stderr = p2.communicate()
|
| 108 |
+
|
| 109 |
+
# Read the charge file
|
| 110 |
+
chargefile = open(tmp_file_base + "_out.csv")
|
| 111 |
+
charges = numpy.array([0.0] * len(vertices))
|
| 112 |
+
for ix, line in enumerate(chargefile.readlines()):
|
| 113 |
+
charges[ix] = float(line.split(",")[3])
|
| 114 |
+
|
| 115 |
+
return charges
|
| 116 |
+
"""
|
model/comp_surface/prepare_target/computeCharges.py
ADDED
|
@@ -0,0 +1,219 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from Bio.PDB import *
|
| 2 |
+
import numpy as np
|
| 3 |
+
from sklearn.neighbors import KDTree
|
| 4 |
+
|
| 5 |
+
"""
|
| 6 |
+
Modified from:
|
| 7 |
+
computeCharges.py - MaSIF
|
| 8 |
+
Pablo Gainza - LPDI STI EPFL 2019
|
| 9 |
+
"""
|
| 10 |
+
|
| 11 |
+
"""
|
| 12 |
+
computeCharges.py: Wrapper function to compute hydrogen bond potential (free electrons/protons) in the surface
|
| 13 |
+
Pablo Gainza - LPDI STI EPFL 2019
|
| 14 |
+
This file is part of MaSIF.
|
| 15 |
+
Released under an Apache License 2.0
|
| 16 |
+
"""
|
| 17 |
+
|
| 18 |
+
from default_config.chemistry import (
|
| 19 |
+
polarHydrogens,
|
| 20 |
+
radii,
|
| 21 |
+
acceptorAngleAtom,
|
| 22 |
+
acceptorPlaneAtom,
|
| 23 |
+
hbond_std_dev,
|
| 24 |
+
donorAtom,
|
| 25 |
+
)
|
| 26 |
+
|
| 27 |
+
# Compute vertex charges based on hydrogen bond potential.
|
| 28 |
+
# pdb_filename: The filename of the protonated protein.
|
| 29 |
+
# vertices: The surface vertices of the protonated protein
|
| 30 |
+
# The name of each vertex in the format, example: B_125_x_ASN_ND2_Green
|
| 31 |
+
# where B is chain, 125 res id, x the insertion, ASN aatype, ND2 the name of the
|
| 32 |
+
# atom, and green is not used anymore.
|
| 33 |
+
def computeCharges(pdb_filename, vertices, names):
|
| 34 |
+
parser = PDBParser(QUIET=True)
|
| 35 |
+
struct = parser.get_structure(pdb_filename, pdb_filename + ".pdb")
|
| 36 |
+
residues = {}
|
| 37 |
+
for res in struct.get_residues():
|
| 38 |
+
chain_id = res.get_parent().get_id()
|
| 39 |
+
if chain_id == "":
|
| 40 |
+
chain_id = " "
|
| 41 |
+
residues[(chain_id, res.get_id())] = res
|
| 42 |
+
|
| 43 |
+
#atoms = Selection.unfold_entities(struct, "A")
|
| 44 |
+
atoms = struct.get_atoms()
|
| 45 |
+
satisfied_CO, satisfied_HN = computeSatisfied_CO_HN(atoms)
|
| 46 |
+
|
| 47 |
+
charge = np.array([0.0] * len(vertices))
|
| 48 |
+
# Go over every vertex
|
| 49 |
+
for ix, name in enumerate(names):
|
| 50 |
+
fields = name.split("_")
|
| 51 |
+
chain_id = fields[0]
|
| 52 |
+
if chain_id == "":
|
| 53 |
+
chain_id = " "
|
| 54 |
+
if fields[2] == "x":
|
| 55 |
+
fields[2] = " "
|
| 56 |
+
res_id = (" ", int(fields[1]), fields[2])
|
| 57 |
+
aa = fields[3]
|
| 58 |
+
atom_name = fields[4]
|
| 59 |
+
# Ignore atom if it is BB and it is already satisfied.
|
| 60 |
+
if atom_name == "H" and res_id in satisfied_HN:
|
| 61 |
+
continue
|
| 62 |
+
if atom_name == "O" and res_id in satisfied_CO:
|
| 63 |
+
continue
|
| 64 |
+
# Compute the charge of the vertex
|
| 65 |
+
charge[ix] = computeChargeHelper(
|
| 66 |
+
atom_name, residues[(chain_id, res_id)], vertices[ix]
|
| 67 |
+
)
|
| 68 |
+
|
| 69 |
+
return charge
|
| 70 |
+
|
| 71 |
+
|
| 72 |
+
# Compute the charge of a vertex in a residue.
|
| 73 |
+
def computeChargeHelper(atom_name, res, v):
|
| 74 |
+
res_type = res.get_resname()
|
| 75 |
+
# Check if it is a polar hydrogen.
|
| 76 |
+
if isPolarHydrogen(atom_name, res):
|
| 77 |
+
donor_atom_name = donorAtom[atom_name]
|
| 78 |
+
a = res[donor_atom_name].get_coord() # N/O
|
| 79 |
+
b = res[atom_name].get_coord() # H
|
| 80 |
+
# Donor-H is always 180.0 degrees, = pi
|
| 81 |
+
angle_deviation = computeAngleDeviation(a, b, v, np.pi)
|
| 82 |
+
angle_penalty = computeAnglePenalty(angle_deviation)
|
| 83 |
+
return 1.0 * angle_penalty
|
| 84 |
+
# Check if it is an acceptor oxygen or nitrogen
|
| 85 |
+
elif isAcceptorAtom(atom_name, res):
|
| 86 |
+
acceptor_atom = res[atom_name]
|
| 87 |
+
b = acceptor_atom.get_coord()
|
| 88 |
+
a = res[acceptorAngleAtom[atom_name]].get_coord()
|
| 89 |
+
# 120 degress for acceptor
|
| 90 |
+
angle_deviation = computeAngleDeviation(a, b, v, 2 * np.pi / 3)
|
| 91 |
+
# TODO: This should not be 120 for all atoms, i.e. for HIS it should be
|
| 92 |
+
# ~125.0
|
| 93 |
+
angle_penalty = computeAnglePenalty(angle_deviation)
|
| 94 |
+
plane_penalty = 1.0
|
| 95 |
+
if atom_name in acceptorPlaneAtom:
|
| 96 |
+
try:
|
| 97 |
+
d = res[acceptorPlaneAtom[atom_name]].get_coord()
|
| 98 |
+
except:
|
| 99 |
+
return 0.0
|
| 100 |
+
plane_deviation = computePlaneDeviation(d, a, b, v)
|
| 101 |
+
plane_penalty = computeAnglePenalty(plane_deviation)
|
| 102 |
+
return -1.0 * angle_penalty * plane_penalty
|
| 103 |
+
# Compute the
|
| 104 |
+
return 0.0
|
| 105 |
+
|
| 106 |
+
|
| 107 |
+
# Compute the absolute value of the deviation from theta
|
| 108 |
+
def computeAngleDeviation(a, b, c, theta):
|
| 109 |
+
return abs(calc_angle(Vector(a), Vector(b), Vector(c)) - theta)
|
| 110 |
+
|
| 111 |
+
|
| 112 |
+
# Compute the angle deviation from a plane
|
| 113 |
+
def computePlaneDeviation(a, b, c, d):
|
| 114 |
+
dih = calc_dihedral(Vector(a), Vector(b), Vector(c), Vector(d))
|
| 115 |
+
dev1 = abs(dih)
|
| 116 |
+
dev2 = np.pi - abs(dih)
|
| 117 |
+
return min(dev1, dev2)
|
| 118 |
+
|
| 119 |
+
|
| 120 |
+
# angle_deviation from ideal value. TODO: do a more data-based solution
|
| 121 |
+
def computeAnglePenalty(angle_deviation):
|
| 122 |
+
# Standard deviation: hbond_std_dev
|
| 123 |
+
return max(0.0, 1.0 - (angle_deviation / (hbond_std_dev)) ** 2)
|
| 124 |
+
|
| 125 |
+
|
| 126 |
+
def isPolarHydrogen(atom_name, res):
|
| 127 |
+
if atom_name in polarHydrogens[res.get_resname()]:
|
| 128 |
+
return True
|
| 129 |
+
else:
|
| 130 |
+
return False
|
| 131 |
+
|
| 132 |
+
|
| 133 |
+
def isAcceptorAtom(atom_name, res):
|
| 134 |
+
if atom_name.startswith("O"):
|
| 135 |
+
return True
|
| 136 |
+
else:
|
| 137 |
+
if res.get_resname() == "HIS":
|
| 138 |
+
if atom_name == "ND1" and "HD1" not in res:
|
| 139 |
+
return True
|
| 140 |
+
if atom_name == "NE2" and "HE2" not in res:
|
| 141 |
+
return True
|
| 142 |
+
return False
|
| 143 |
+
|
| 144 |
+
|
| 145 |
+
# Compute the list of backbone C=O:H-N that are satisfied. These will be ignored.
|
| 146 |
+
def computeSatisfied_CO_HN(atoms):
|
| 147 |
+
ns = NeighborSearch(atoms)
|
| 148 |
+
satisfied_CO = set()
|
| 149 |
+
satisfied_HN = set()
|
| 150 |
+
for atom1 in atoms:
|
| 151 |
+
res1 = atom1.get_parent()
|
| 152 |
+
if atom1.get_id() == "O":
|
| 153 |
+
neigh_atoms = ns.search(atom1.get_coord(), 2.5, level="A")
|
| 154 |
+
for atom2 in neigh_atoms:
|
| 155 |
+
if atom2.get_id() == "H":
|
| 156 |
+
res2 = atom2.get_parent()
|
| 157 |
+
# Ensure they belong to different residues.
|
| 158 |
+
if res2.get_id() != res1.get_id():
|
| 159 |
+
# Compute the angle N-H:O, ideal value is 180 (but in
|
| 160 |
+
# helices it is typically 160) 180 +-30 = pi
|
| 161 |
+
angle_N_H_O_dev = computeAngleDeviation(
|
| 162 |
+
res2["N"].get_coord(),
|
| 163 |
+
atom2.get_coord(),
|
| 164 |
+
atom1.get_coord(),
|
| 165 |
+
np.pi,
|
| 166 |
+
)
|
| 167 |
+
# Compute angle H:O=C, ideal value is ~160 +- 20 = 8*pi/9
|
| 168 |
+
angle_H_O_C_dev = computeAngleDeviation(
|
| 169 |
+
atom2.get_coord(),
|
| 170 |
+
atom1.get_coord(),
|
| 171 |
+
res1["C"].get_coord(),
|
| 172 |
+
8 * np.pi / 9,
|
| 173 |
+
)
|
| 174 |
+
## Allowed deviations: 30 degrees (pi/6) and 20 degrees
|
| 175 |
+
# (pi/9)
|
| 176 |
+
if (
|
| 177 |
+
angle_N_H_O_dev - np.pi / 6 < 0
|
| 178 |
+
and angle_H_O_C_dev - np.pi / 9 < 0.0
|
| 179 |
+
):
|
| 180 |
+
satisfied_CO.add(res1.get_id())
|
| 181 |
+
satisfied_HN.add(res2.get_id())
|
| 182 |
+
return satisfied_CO, satisfied_HN
|
| 183 |
+
|
| 184 |
+
|
| 185 |
+
# Compute the charge of a new mesh, based on the charge of an old mesh.
|
| 186 |
+
# Use the top vertex in distance, for now (later this should be smoothed over 3
|
| 187 |
+
# or 4 vertices)
|
| 188 |
+
def assignChargesToNewMesh(new_vertices, old_vertices, old_charges, seeder_opts):
|
| 189 |
+
dataset = old_vertices
|
| 190 |
+
testset = new_vertices
|
| 191 |
+
new_charges = np.zeros(len(new_vertices))
|
| 192 |
+
if seeder_opts["feature_interpolation"]:
|
| 193 |
+
num_inter = 4 # Number of interpolation features
|
| 194 |
+
# Assign k old vertices to each new vertex.
|
| 195 |
+
kdt = KDTree(dataset)
|
| 196 |
+
dists, result = kdt.query(testset, k=num_inter)
|
| 197 |
+
# Square the distances (as in the original pyflann)
|
| 198 |
+
dists = np.square(dists)
|
| 199 |
+
# The size of result is the same as new_vertices
|
| 200 |
+
for vi_new in range(len(result)):
|
| 201 |
+
vi_old = result[vi_new]
|
| 202 |
+
dist_old = dists[vi_new]
|
| 203 |
+
# If one vertex is right on top, ignore the rest.
|
| 204 |
+
if dist_old[0] == 0.0:
|
| 205 |
+
new_charges[vi_new] = old_charges[vi_old[0]]
|
| 206 |
+
continue
|
| 207 |
+
|
| 208 |
+
total_dist = np.sum(1 / dist_old)
|
| 209 |
+
for i in range(num_inter):
|
| 210 |
+
new_charges[vi_new] += (
|
| 211 |
+
old_charges[vi_old[i]] * (1 / dist_old[i]) / total_dist
|
| 212 |
+
)
|
| 213 |
+
else:
|
| 214 |
+
# Assign k old vertices to each new vertex.
|
| 215 |
+
kdt = KDTree(dataset)
|
| 216 |
+
dists, result = kdt.query(testset)
|
| 217 |
+
new_charges = old_charges[result]
|
| 218 |
+
return new_charges
|
| 219 |
+
|
model/comp_surface/prepare_target/computeHydrophobicity.py
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import numpy as np
|
| 2 |
+
|
| 3 |
+
"""
|
| 4 |
+
Taken from:
|
| 5 |
+
computeHydrophobicity.py - MaSIF
|
| 6 |
+
Pablo Gainza - LPDI STI EPFL 2019
|
| 7 |
+
"""
|
| 8 |
+
|
| 9 |
+
# Kyte Doolittle scale
|
| 10 |
+
kd_scale = {}
|
| 11 |
+
kd_scale["ILE"] = 4.5
|
| 12 |
+
kd_scale["VAL"] = 4.2
|
| 13 |
+
kd_scale["LEU"] = 3.8
|
| 14 |
+
kd_scale["PHE"] = 2.8
|
| 15 |
+
kd_scale["CYS"] = 2.5
|
| 16 |
+
kd_scale["MET"] = 1.9
|
| 17 |
+
kd_scale["ALA"] = 1.8
|
| 18 |
+
kd_scale["GLY"] = -0.4
|
| 19 |
+
kd_scale["THR"] = -0.7
|
| 20 |
+
kd_scale["SER"] = -0.8
|
| 21 |
+
kd_scale["TRP"] = -0.9
|
| 22 |
+
kd_scale["TYR"] = -1.3
|
| 23 |
+
kd_scale["PRO"] = -1.6
|
| 24 |
+
kd_scale["HIS"] = -3.2
|
| 25 |
+
kd_scale["GLU"] = -3.5
|
| 26 |
+
kd_scale["GLN"] = -3.5
|
| 27 |
+
kd_scale["ASP"] = -3.5
|
| 28 |
+
kd_scale["ASN"] = -3.5
|
| 29 |
+
kd_scale["LYS"] = -3.9
|
| 30 |
+
kd_scale["ARG"] = -4.5
|
| 31 |
+
|
| 32 |
+
# For each vertex in names, compute
|
| 33 |
+
def computeHydrophobicity(names):
|
| 34 |
+
hp = np.zeros(len(names))
|
| 35 |
+
for ix, name in enumerate(names):
|
| 36 |
+
aa = name.split("_")[3]
|
| 37 |
+
hp[ix] = kd_scale[aa]
|
| 38 |
+
return hp
|
| 39 |
+
|
model/comp_surface/prepare_target/computeMSMS.py
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
from subprocess import Popen, PIPE
|
| 3 |
+
|
| 4 |
+
from input_output.read_msms import read_msms
|
| 5 |
+
from triangulation.xyzrn import output_pdb_as_xyzrn
|
| 6 |
+
from default_config.global_vars import msms_bin
|
| 7 |
+
from default_config.masif_opts import masif_opts
|
| 8 |
+
import random
|
| 9 |
+
|
| 10 |
+
"""
|
| 11 |
+
Modified from:
|
| 12 |
+
computeMSMS.py - MaSIF
|
| 13 |
+
Pablo Gainza - LPDI STI EPFL 2019
|
| 14 |
+
"""
|
| 15 |
+
|
| 16 |
+
# Pablo Gainza LPDI EPFL 2017-2019
|
| 17 |
+
# Calls MSMS and returns the vertices.
|
| 18 |
+
# Special atoms are atoms with a reduced radius.
|
| 19 |
+
import time
|
| 20 |
+
def computeMSMS(pdb_file, protonate=True, one_cavity=None):
|
| 21 |
+
randnum = random.randint(1,10000000) #+ time.time() + os.getpid()
|
| 22 |
+
file_base = masif_opts['tmp_dir']+"/msms_"+str(randnum)
|
| 23 |
+
out_xyzrn = file_base+".xyzrn"
|
| 24 |
+
|
| 25 |
+
if protonate:
|
| 26 |
+
output_pdb_as_xyzrn(pdb_file, out_xyzrn)
|
| 27 |
+
else:
|
| 28 |
+
print("Error - pdb2xyzrn is deprecated.")
|
| 29 |
+
sys.exit(1)
|
| 30 |
+
# Now run MSMS on xyzrn file
|
| 31 |
+
FNULL = open(os.devnull, 'w')
|
| 32 |
+
if one_cavity is not None:
|
| 33 |
+
args = [msms_bin, "-density", "3.0", "-hdensity", "3.0", "-probe", "1.5",\
|
| 34 |
+
"-one_cavity", str(1), str(one_cavity),\
|
| 35 |
+
"-if",out_xyzrn,"-of",file_base, "-af", file_base]
|
| 36 |
+
else:
|
| 37 |
+
args = [msms_bin, "-density", "3.0", "-hdensity", "3.0", "-probe",\
|
| 38 |
+
"1.5", "-all_components", "-if",out_xyzrn,"-of",file_base, "-af", file_base]
|
| 39 |
+
#print msms_bin+" "+`args`
|
| 40 |
+
p2 = Popen(args, stdout=PIPE, stderr=PIPE)
|
| 41 |
+
stdout, stderr = p2.communicate()
|
| 42 |
+
print(stdout, stderr)
|
| 43 |
+
|
| 44 |
+
vertices, faces, normals, names = read_msms(file_base)
|
| 45 |
+
areas = {}
|
| 46 |
+
ses_file = open(file_base+".area")
|
| 47 |
+
next(ses_file) # ignore header line
|
| 48 |
+
for line in ses_file:
|
| 49 |
+
fields = line.split()
|
| 50 |
+
areas[fields[3]] = fields[1]
|
| 51 |
+
# os.system("rm " + file_base + "*")
|
| 52 |
+
return vertices, faces, normals, names, areas
|
| 53 |
+
|
model/comp_surface/prepare_target/computeTargetMesh.py
ADDED
|
@@ -0,0 +1,254 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import sys
|
| 3 |
+
import numpy as np
|
| 4 |
+
import shutil
|
| 5 |
+
import pymesh
|
| 6 |
+
import Bio.PDB
|
| 7 |
+
from Bio.PDB import *
|
| 8 |
+
from rdkit import Chem
|
| 9 |
+
import warnings
|
| 10 |
+
warnings.filterwarnings("ignore")
|
| 11 |
+
from IPython.utils import io
|
| 12 |
+
from sklearn.neighbors import KDTree
|
| 13 |
+
from scipy.spatial import distance
|
| 14 |
+
|
| 15 |
+
sys.path.append('/home/caoduanhua/DeepDock')
|
| 16 |
+
import deepdock
|
| 17 |
+
sys.path.insert(0, deepdock.__path__[0]+'/masif/source')
|
| 18 |
+
|
| 19 |
+
from default_config.masif_opts import masif_opts
|
| 20 |
+
from deepdock.prepare_target.compute_normal import compute_normal
|
| 21 |
+
from deepdock.prepare_target.computeAPBS import computeAPBS
|
| 22 |
+
from deepdock.prepare_target.computeCharges import computeCharges, assignChargesToNewMesh
|
| 23 |
+
from deepdock.prepare_target.computeHydrophobicity import computeHydrophobicity
|
| 24 |
+
from deepdock.prepare_target.computeMSMS import computeMSMS
|
| 25 |
+
from deepdock.prepare_target.fixmesh import fix_mesh
|
| 26 |
+
from deepdock.prepare_target.save_ply import save_ply
|
| 27 |
+
from deepdock.utils.mol2graph import *
|
| 28 |
+
|
| 29 |
+
def compute_inp_surface(target_filename, ligand_filename,out_dir = None, dist_threshold=10):
|
| 30 |
+
# try:
|
| 31 |
+
sufix = '_'+str(dist_threshold+5)+'A.pdb'
|
| 32 |
+
# out_filename = os.path.splitext(target_filename)[0]
|
| 33 |
+
if out_dir is not None:
|
| 34 |
+
out_filename = os.path.join(out_dir,target_filename.split('/')[-2])
|
| 35 |
+
os.makedirs(out_filename,exist_ok=True)
|
| 36 |
+
sufix = '/' + os.path.splitext(target_filename)[0].split('/')[-1] + '_'+str(dist_threshold+5)+'A.pdb'
|
| 37 |
+
else:
|
| 38 |
+
out_filename = os.path.splitext(target_filename)[0]
|
| 39 |
+
if os.path.exists(out_filename+f"/{sufix.split('.')[0]}.ply"):
|
| 40 |
+
print('have done skip!')
|
| 41 |
+
return 0
|
| 42 |
+
input_filename = os.path.splitext(target_filename)[0]
|
| 43 |
+
# Get atom coordinates
|
| 44 |
+
# try:
|
| 45 |
+
if ligand_filename.endswith('.mol2'):
|
| 46 |
+
mol = Chem.MolFromMol2File(ligand_filename, sanitize=False, cleanupSubstructures=False)
|
| 47 |
+
if ligand_filename.endswith('.sdf'):
|
| 48 |
+
# print('mol2 faild try sdf')
|
| 49 |
+
mol = Chem.SDMolSupplier(ligand_filename, sanitize=False,removeHs = False)[0]
|
| 50 |
+
g = mol_to_nx(mol)
|
| 51 |
+
atomCoords = np.array([g.nodes[i]['pos'].tolist() for i in g.nodes])
|
| 52 |
+
|
| 53 |
+
# Read protein and select aminino acids in the binding pocket
|
| 54 |
+
parser = Bio.PDB.PDBParser(QUIET=True) # QUIET=True avoids comments on errors in the pdb.
|
| 55 |
+
|
| 56 |
+
structures = parser.get_structure('target', input_filename+'.pdb')
|
| 57 |
+
structure = structures[0] # 'structures' may contain several proteins in this case only one.
|
| 58 |
+
|
| 59 |
+
atoms = Bio.PDB.Selection.unfold_entities(structure, 'A')
|
| 60 |
+
ns = Bio.PDB.NeighborSearch(atoms)
|
| 61 |
+
|
| 62 |
+
close_residues= []
|
| 63 |
+
for a in atomCoords:
|
| 64 |
+
close_residues.extend(ns.search(a, dist_threshold+5, level='R'))
|
| 65 |
+
close_residues = Bio.PDB.Selection.uniqueify(close_residues)
|
| 66 |
+
|
| 67 |
+
class SelectNeighbors(Select):
|
| 68 |
+
def accept_residue(self, residue):
|
| 69 |
+
if residue in close_residues:
|
| 70 |
+
if all(a in [i.get_name() for i in residue.get_unpacked_list()] for a in ['N', 'CA', 'C', 'O']) or residue.resname=='HOH':
|
| 71 |
+
return True
|
| 72 |
+
else:
|
| 73 |
+
return False
|
| 74 |
+
else:
|
| 75 |
+
return False
|
| 76 |
+
|
| 77 |
+
pdbio = PDBIO()
|
| 78 |
+
pdbio.set_structure(structure)
|
| 79 |
+
pdbio.save(out_filename+sufix, SelectNeighbors())
|
| 80 |
+
|
| 81 |
+
# Identify closes atom to the ligand
|
| 82 |
+
structures = parser.get_structure('target', out_filename+sufix)
|
| 83 |
+
structure = structures[0] # 'structures' may contain several proteins in this case only one.
|
| 84 |
+
atoms = Bio.PDB.Selection.unfold_entities(structure, 'A')
|
| 85 |
+
|
| 86 |
+
#dist = [distance.euclidean(atomCoords.mean(axis=0), a.get_coord()) for a in atoms]
|
| 87 |
+
#atom_idx = np.argmin(dist)
|
| 88 |
+
#dist = [[distance.euclidean(ac, a.get_coord()) for ac in atomCoords] for a in atoms]
|
| 89 |
+
#atom_idx = np.argsort(np.min(dist, axis=1))[0]
|
| 90 |
+
# Compute MSMS of surface w/hydrogens,
|
| 91 |
+
try:
|
| 92 |
+
dist = [distance.euclidean(atomCoords.mean(axis=0), a.get_coord()) for a in atoms]
|
| 93 |
+
atom_idx = np.argmin(dist)
|
| 94 |
+
vertices1, faces1, normals1, names1, areas1 = computeMSMS(out_filename+sufix,\
|
| 95 |
+
protonate=True, one_cavity=atom_idx)
|
| 96 |
+
|
| 97 |
+
# Find the distance between every vertex in binding site surface and each atom in the ligand.
|
| 98 |
+
kdt = KDTree(atomCoords)
|
| 99 |
+
d, r = kdt.query(vertices1)
|
| 100 |
+
assert(len(d) == len(vertices1))
|
| 101 |
+
iface_v = np.where(d <= dist_threshold)[0]
|
| 102 |
+
faces_to_keep = [idx for idx, face in enumerate(faces1) if all(v in iface_v for v in face)]
|
| 103 |
+
|
| 104 |
+
# Compute "charged" vertices
|
| 105 |
+
if masif_opts['use_hbond']:
|
| 106 |
+
vertex_hbond = computeCharges(input_filename, vertices1, names1)
|
| 107 |
+
|
| 108 |
+
# For each surface residue, assign the hydrophobicity of its amino acid.
|
| 109 |
+
if masif_opts['use_hphob']:
|
| 110 |
+
vertex_hphobicity = computeHydrophobicity(names1)
|
| 111 |
+
|
| 112 |
+
# If protonate = false, recompute MSMS of surface, but without hydrogens (set radius of hydrogens to 0).
|
| 113 |
+
vertices2 = vertices1
|
| 114 |
+
faces2 = faces1
|
| 115 |
+
|
| 116 |
+
# Fix the mesh.
|
| 117 |
+
mesh = pymesh.form_mesh(vertices2, faces2)
|
| 118 |
+
mesh = pymesh.submesh(mesh, faces_to_keep, 0)
|
| 119 |
+
with io.capture_output() as captured:
|
| 120 |
+
regular_mesh = fix_mesh(mesh, masif_opts['mesh_res'])
|
| 121 |
+
|
| 122 |
+
except:
|
| 123 |
+
try:
|
| 124 |
+
dist = [[distance.euclidean(ac, a.get_coord()) for ac in atomCoords] for a in atoms]
|
| 125 |
+
atom_idx = np.argsort(np.min(dist, axis=1))[0]
|
| 126 |
+
vertices1, faces1, normals1, names1, areas1 = computeMSMS(out_filename+sufix,\
|
| 127 |
+
protonate=True, one_cavity=atom_idx)
|
| 128 |
+
|
| 129 |
+
# Find the distance between every vertex in binding site surface and each atom in the ligand.
|
| 130 |
+
kdt = KDTree(atomCoords)
|
| 131 |
+
d, r = kdt.query(vertices1)
|
| 132 |
+
assert(len(d) == len(vertices1))
|
| 133 |
+
iface_v = np.where(d <= dist_threshold)[0]
|
| 134 |
+
faces_to_keep = [idx for idx, face in enumerate(faces1) if all(v in iface_v for v in face)]
|
| 135 |
+
|
| 136 |
+
# Compute "charged" vertices
|
| 137 |
+
if masif_opts['use_hbond']:
|
| 138 |
+
vertex_hbond = computeCharges(input_filename, vertices1, names1)
|
| 139 |
+
|
| 140 |
+
# For each surface residue, assign the hydrophobicity of its amino acid.
|
| 141 |
+
if masif_opts['use_hphob']:
|
| 142 |
+
vertex_hphobicity = computeHydrophobicity(names1)
|
| 143 |
+
|
| 144 |
+
# If protonate = false, recompute MSMS of surface, but without hydrogens (set radius of hydrogens to 0).
|
| 145 |
+
vertices2 = vertices1
|
| 146 |
+
faces2 = faces1
|
| 147 |
+
|
| 148 |
+
# Fix the mesh.
|
| 149 |
+
mesh = pymesh.form_mesh(vertices2, faces2)
|
| 150 |
+
mesh = pymesh.submesh(mesh, faces_to_keep, 0)
|
| 151 |
+
with io.capture_output() as captured:
|
| 152 |
+
regular_mesh = fix_mesh(mesh, masif_opts['mesh_res'])
|
| 153 |
+
|
| 154 |
+
except:
|
| 155 |
+
vertices1, faces1, normals1, names1, areas1 = computeMSMS(out_filename+sufix,\
|
| 156 |
+
protonate=True, one_cavity=None)
|
| 157 |
+
|
| 158 |
+
# Find the distance between every vertex in binding site surface and each atom in the ligand.
|
| 159 |
+
kdt = KDTree(atomCoords)
|
| 160 |
+
d, r = kdt.query(vertices1)
|
| 161 |
+
assert(len(d) == len(vertices1))
|
| 162 |
+
iface_v = np.where(d <= dist_threshold)[0]
|
| 163 |
+
faces_to_keep = [idx for idx, face in enumerate(faces1) if all(v in iface_v for v in face)]
|
| 164 |
+
|
| 165 |
+
# Compute "charged" vertices
|
| 166 |
+
if masif_opts['use_hbond']:
|
| 167 |
+
vertex_hbond = computeCharges(input_filename, vertices1, names1)
|
| 168 |
+
|
| 169 |
+
# For each surface residue, assign the hydrophobicity of its amino acid.
|
| 170 |
+
if masif_opts['use_hphob']:
|
| 171 |
+
vertex_hphobicity = computeHydrophobicity(names1)
|
| 172 |
+
|
| 173 |
+
# If protonate = false, recompute MSMS of surface, but without hydrogens (set radius of hydrogens to 0).
|
| 174 |
+
vertices2 = vertices1
|
| 175 |
+
faces2 = faces1
|
| 176 |
+
|
| 177 |
+
# Fix the mesh.
|
| 178 |
+
mesh = pymesh.form_mesh(vertices2, faces2)
|
| 179 |
+
mesh = pymesh.submesh(mesh, faces_to_keep, 0)
|
| 180 |
+
with io.capture_output() as captured:
|
| 181 |
+
regular_mesh = fix_mesh(mesh, masif_opts['mesh_res'])
|
| 182 |
+
|
| 183 |
+
# Compute the normals
|
| 184 |
+
vertex_normal = compute_normal(regular_mesh.vertices, regular_mesh.faces)
|
| 185 |
+
# Assign charges on new vertices based on charges of old vertices (nearest
|
| 186 |
+
# neighbor)
|
| 187 |
+
|
| 188 |
+
if masif_opts['use_hbond']:
|
| 189 |
+
vertex_hbond = assignChargesToNewMesh(regular_mesh.vertices, vertices1,\
|
| 190 |
+
vertex_hbond, masif_opts)
|
| 191 |
+
|
| 192 |
+
if masif_opts['use_hphob']:
|
| 193 |
+
vertex_hphobicity = assignChargesToNewMesh(regular_mesh.vertices, vertices1,\
|
| 194 |
+
vertex_hphobicity, masif_opts)
|
| 195 |
+
|
| 196 |
+
if masif_opts['use_apbs']:
|
| 197 |
+
vertex_charges = computeAPBS(regular_mesh.vertices, out_filename+sufix, out_filename+"_temp")
|
| 198 |
+
|
| 199 |
+
# Compute the principal curvature components for the shape index.
|
| 200 |
+
regular_mesh.add_attribute("vertex_mean_curvature")
|
| 201 |
+
H = regular_mesh.get_attribute("vertex_mean_curvature")
|
| 202 |
+
regular_mesh.add_attribute("vertex_gaussian_curvature")
|
| 203 |
+
K = regular_mesh.get_attribute("vertex_gaussian_curvature")
|
| 204 |
+
elem = np.square(H) - K
|
| 205 |
+
# In some cases this equation is less than zero, likely due to the method that computes the mean and gaussian curvature.
|
| 206 |
+
# set to an epsilon.
|
| 207 |
+
elem[elem<0] = 1e-8
|
| 208 |
+
k1 = H + np.sqrt(elem)
|
| 209 |
+
k2 = H - np.sqrt(elem)
|
| 210 |
+
# Compute the shape index
|
| 211 |
+
si = (k1+k2)/(k1-k2)
|
| 212 |
+
si = np.arctan(si)*(2/np.pi)
|
| 213 |
+
|
| 214 |
+
# Convert to ply and save.
|
| 215 |
+
save_ply(out_filename+f"/{sufix.split('.')[0]}.ply", regular_mesh.vertices,\
|
| 216 |
+
regular_mesh.faces, normals=vertex_normal, charges=vertex_charges,\
|
| 217 |
+
normalize_charges=True, hbond=vertex_hbond, hphob=vertex_hphobicity,\
|
| 218 |
+
si=si)
|
| 219 |
+
os.system("rm " + f"{out_dir}/{target_filename.split('/')[-2]}*")
|
| 220 |
+
return 0
|
| 221 |
+
# except:
|
| 222 |
+
# return target_filename
|
| 223 |
+
|
| 224 |
+
|
| 225 |
+
if __name__ == "__main__":
|
| 226 |
+
from joblib import delayed,Parallel
|
| 227 |
+
|
| 228 |
+
|
| 229 |
+
surface_dist = 10
|
| 230 |
+
data_dir = '~/dockingModelTestDataset/'
|
| 231 |
+
|
| 232 |
+
out_dir = ' '
|
| 233 |
+
# 在out_dir 文件夹下执行
|
| 234 |
+
sys.path.append(out_dir)
|
| 235 |
+
from tqdm import tqdm
|
| 236 |
+
import glob
|
| 237 |
+
args_list = []
|
| 238 |
+
for protein in tqdm(os.listdir(data_dir)):
|
| 239 |
+
if os.path.isdir(os.path.join(data_dir,protein)):
|
| 240 |
+
|
| 241 |
+
if protein in ['3TGG']:
|
| 242 |
+
|
| 243 |
+
target_filename = os.path.join(data_dir,protein,f'{protein}_PRO.pdb')
|
| 244 |
+
if os.path.exists(os.path.join(data_dir,protein,f'{protein}_LIG_raw.sdf')):
|
| 245 |
+
ligand_filename = os.path.join(data_dir,protein,f'{protein}_LIG_raw.sdf')
|
| 246 |
+
else:
|
| 247 |
+
print(glob.glob(os.path.join(data_dir,protein,f'*_LIG.sdf')))
|
| 248 |
+
print(protein)
|
| 249 |
+
ligand_filename = glob.glob(os.path.join(data_dir,protein,'*_LIG.sdf'))[0]
|
| 250 |
+
args_list.append((target_filename,ligand_filename))
|
| 251 |
+
|
| 252 |
+
results = Parallel(n_jobs = 30)(delayed(compute_inp_surface)(target_filename, ligand_filename,out_dir, dist_threshold=surface_dist-5) for (target_filename, ligand_filename) in tqdm(args_list))
|
| 253 |
+
|
| 254 |
+
print('sucess num : ',len([i for i in results if i == 0]),'all num : ',len(results))
|
model/comp_surface/prepare_target/computeTargetMesh_test_samples.py
ADDED
|
@@ -0,0 +1,262 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import sys
|
| 3 |
+
import numpy as np
|
| 4 |
+
import shutil
|
| 5 |
+
import glob
|
| 6 |
+
import pymesh
|
| 7 |
+
import Bio.PDB
|
| 8 |
+
from Bio.PDB import *
|
| 9 |
+
from rdkit import Chem
|
| 10 |
+
import warnings
|
| 11 |
+
warnings.filterwarnings("ignore")
|
| 12 |
+
from IPython.utils import io
|
| 13 |
+
from sklearn.neighbors import KDTree
|
| 14 |
+
from scipy.spatial import distance
|
| 15 |
+
|
| 16 |
+
from default_config.masif_opts import masif_opts
|
| 17 |
+
from compute_normal import compute_normal
|
| 18 |
+
from computeAPBS import computeAPBS
|
| 19 |
+
from computeCharges import computeCharges, assignChargesToNewMesh
|
| 20 |
+
from computeHydrophobicity import computeHydrophobicity
|
| 21 |
+
from computeMSMS import computeMSMS
|
| 22 |
+
from fixmesh import fix_mesh
|
| 23 |
+
from save_ply import save_ply
|
| 24 |
+
from mol2graph import *
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
def compute_inp_surface(target_filename, ligand_filename,out_dir = None, dist_threshold=10):
|
| 28 |
+
try:
|
| 29 |
+
|
| 30 |
+
sufix = '_'+str(dist_threshold)+'A.pdb'
|
| 31 |
+
# out_filename = os.path.splitext(target_filename)[0]
|
| 32 |
+
if out_dir is not None:
|
| 33 |
+
out_filename = os.path.join(out_dir,ligand_filename.split('/')[-2])
|
| 34 |
+
os.makedirs(out_filename,exist_ok=True)
|
| 35 |
+
sufix = '/' + os.path.splitext(target_filename)[0].split('/')[-1] + '_'+str(dist_threshold)+'A.pdb'
|
| 36 |
+
else:
|
| 37 |
+
out_filename = os.path.splitext(ligand_filename)[0]
|
| 38 |
+
if os.path.exists(out_filename+f"/{sufix.split('.pdb')[0]}.ply"):
|
| 39 |
+
print('have done skip!')
|
| 40 |
+
return 0
|
| 41 |
+
input_filename = os.path.splitext(target_filename)[0]
|
| 42 |
+
# Get atom coordinates
|
| 43 |
+
# try:
|
| 44 |
+
# mol = Chem.MolFromMol2File(ligand_filename, sanitize=False, cleanupSubstructures=False)
|
| 45 |
+
# except:
|
| 46 |
+
# print('mol2 faild try sdf')
|
| 47 |
+
if ligand_filename.endswith('.sdf'):
|
| 48 |
+
mol = Chem.SDMolSupplier(ligand_filename, sanitize=False)[0]
|
| 49 |
+
elif ligand_filename.endswith('.pdb'):
|
| 50 |
+
mol = Chem.MolFromPDBFile(ligand_filename, sanitize=False)
|
| 51 |
+
g = mol_to_nx(mol)
|
| 52 |
+
atomCoords = np.array([g.nodes[i]['pos'].tolist() for i in g.nodes])
|
| 53 |
+
|
| 54 |
+
# Read protein and select aminino acids in the binding pocket
|
| 55 |
+
parser = Bio.PDB.PDBParser(QUIET=True) # QUIET=True avoids comments on errors in the pdb.
|
| 56 |
+
|
| 57 |
+
structures = parser.get_structure('target', input_filename+'.pdb')
|
| 58 |
+
structure = structures[0] # 'structures' may contain several proteins in this case only one.
|
| 59 |
+
|
| 60 |
+
atoms = Bio.PDB.Selection.unfold_entities(structure, 'A')
|
| 61 |
+
ns = Bio.PDB.NeighborSearch(atoms)
|
| 62 |
+
|
| 63 |
+
close_residues= []
|
| 64 |
+
for a in atomCoords:
|
| 65 |
+
close_residues.extend(ns.search(a, dist_threshold, level='R'))
|
| 66 |
+
close_residues = Bio.PDB.Selection.uniqueify(close_residues)
|
| 67 |
+
|
| 68 |
+
class SelectNeighbors(Select):
|
| 69 |
+
def accept_residue(self, residue):
|
| 70 |
+
if residue in close_residues:
|
| 71 |
+
if all(a in [i.get_name() for i in residue.get_unpacked_list()] for a in ['N', 'CA', 'C', 'O']) or residue.resname=='HOH':
|
| 72 |
+
return True
|
| 73 |
+
else:
|
| 74 |
+
return False
|
| 75 |
+
else:
|
| 76 |
+
return False
|
| 77 |
+
|
| 78 |
+
pdbio = PDBIO()
|
| 79 |
+
pdbio.set_structure(structure)
|
| 80 |
+
pdbio.save(out_filename+sufix, SelectNeighbors())
|
| 81 |
+
|
| 82 |
+
# Identify closes atom to the ligand
|
| 83 |
+
structures = parser.get_structure('target', out_filename+sufix)
|
| 84 |
+
structure = structures[0] # 'structures' may contain several proteins in this case only one.
|
| 85 |
+
atoms = Bio.PDB.Selection.unfold_entities(structure, 'A')
|
| 86 |
+
|
| 87 |
+
#dist = [distance.euclidean(atomCoords.mean(axis=0), a.get_coord()) for a in atoms]
|
| 88 |
+
#atom_idx = np.argmin(dist)
|
| 89 |
+
#dist = [[distance.euclidean(ac, a.get_coord()) for ac in atomCoords] for a in atoms]
|
| 90 |
+
#atom_idx = np.argsort(np.min(dist, axis=1))[0]
|
| 91 |
+
|
| 92 |
+
# Compute MSMS of surface w/hydrogens,
|
| 93 |
+
try:
|
| 94 |
+
dist = [distance.euclidean(atomCoords.mean(axis=0), a.get_coord()) for a in atoms]
|
| 95 |
+
atom_idx = np.argmin(dist)
|
| 96 |
+
vertices1, faces1, normals1, names1, areas1 = computeMSMS(out_filename+sufix,\
|
| 97 |
+
protonate=True, one_cavity=atom_idx)
|
| 98 |
+
|
| 99 |
+
# Find the distance between every vertex in binding site surface and each atom in the ligand.
|
| 100 |
+
kdt = KDTree(atomCoords)
|
| 101 |
+
d, r = kdt.query(vertices1)
|
| 102 |
+
assert(len(d) == len(vertices1))
|
| 103 |
+
iface_v = np.where(d <= dist_threshold-5)[0]
|
| 104 |
+
faces_to_keep = [idx for idx, face in enumerate(faces1) if all(v in iface_v for v in face)]
|
| 105 |
+
|
| 106 |
+
# Compute "charged" vertices
|
| 107 |
+
if masif_opts['use_hbond']:
|
| 108 |
+
vertex_hbond = computeCharges(input_filename, vertices1, names1)
|
| 109 |
+
|
| 110 |
+
# For each surface residue, assign the hydrophobicity of its amino acid.
|
| 111 |
+
if masif_opts['use_hphob']:
|
| 112 |
+
vertex_hphobicity = computeHydrophobicity(names1)
|
| 113 |
+
|
| 114 |
+
# If protonate = false, recompute MSMS of surface, but without hydrogens (set radius of hydrogens to 0).
|
| 115 |
+
vertices2 = vertices1
|
| 116 |
+
faces2 = faces1
|
| 117 |
+
|
| 118 |
+
# Fix the mesh.
|
| 119 |
+
mesh = pymesh.form_mesh(vertices2, faces2)
|
| 120 |
+
mesh = pymesh.submesh(mesh, faces_to_keep, 0)
|
| 121 |
+
with io.capture_output() as captured:
|
| 122 |
+
regular_mesh = fix_mesh(mesh, masif_opts['mesh_res'])
|
| 123 |
+
|
| 124 |
+
except:
|
| 125 |
+
try:
|
| 126 |
+
dist = [[distance.euclidean(ac, a.get_coord()) for ac in atomCoords] for a in atoms]
|
| 127 |
+
atom_idx = np.argsort(np.min(dist, axis=1))[0]
|
| 128 |
+
vertices1, faces1, normals1, names1, areas1 = computeMSMS(out_filename+sufix,\
|
| 129 |
+
protonate=True, one_cavity=atom_idx)
|
| 130 |
+
|
| 131 |
+
# Find the distance between every vertex in binding site surface and each atom in the ligand.
|
| 132 |
+
kdt = KDTree(atomCoords)
|
| 133 |
+
d, r = kdt.query(vertices1)
|
| 134 |
+
assert(len(d) == len(vertices1))
|
| 135 |
+
iface_v = np.where(d <= dist_threshold-5)[0]
|
| 136 |
+
faces_to_keep = [idx for idx, face in enumerate(faces1) if all(v in iface_v for v in face)]
|
| 137 |
+
|
| 138 |
+
# Compute "charged" vertices
|
| 139 |
+
if masif_opts['use_hbond']:
|
| 140 |
+
vertex_hbond = computeCharges(input_filename, vertices1, names1)
|
| 141 |
+
|
| 142 |
+
# For each surface residue, assign the hydrophobicity of its amino acid.
|
| 143 |
+
if masif_opts['use_hphob']:
|
| 144 |
+
vertex_hphobicity = computeHydrophobicity(names1)
|
| 145 |
+
|
| 146 |
+
# If protonate = false, recompute MSMS of surface, but without hydrogens (set radius of hydrogens to 0).
|
| 147 |
+
vertices2 = vertices1
|
| 148 |
+
faces2 = faces1
|
| 149 |
+
|
| 150 |
+
# Fix the mesh.
|
| 151 |
+
mesh = pymesh.form_mesh(vertices2, faces2)
|
| 152 |
+
mesh = pymesh.submesh(mesh, faces_to_keep, 0)
|
| 153 |
+
with io.capture_output() as captured:
|
| 154 |
+
regular_mesh = fix_mesh(mesh, masif_opts['mesh_res'])
|
| 155 |
+
|
| 156 |
+
except:
|
| 157 |
+
vertices1, faces1, normals1, names1, areas1 = computeMSMS(out_filename+sufix,\
|
| 158 |
+
protonate=True, one_cavity=None)
|
| 159 |
+
|
| 160 |
+
# Find the distance between every vertex in binding site surface and each atom in the ligand.
|
| 161 |
+
kdt = KDTree(atomCoords)
|
| 162 |
+
d, r = kdt.query(vertices1)
|
| 163 |
+
assert(len(d) == len(vertices1))
|
| 164 |
+
iface_v = np.where(d <= dist_threshold-5)[0]
|
| 165 |
+
faces_to_keep = [idx for idx, face in enumerate(faces1) if all(v in iface_v for v in face)]
|
| 166 |
+
|
| 167 |
+
# Compute "charged" vertices
|
| 168 |
+
if masif_opts['use_hbond']:
|
| 169 |
+
vertex_hbond = computeCharges(input_filename, vertices1, names1)
|
| 170 |
+
|
| 171 |
+
# For each surface residue, assign the hydrophobicity of its amino acid.
|
| 172 |
+
if masif_opts['use_hphob']:
|
| 173 |
+
vertex_hphobicity = computeHydrophobicity(names1)
|
| 174 |
+
|
| 175 |
+
# If protonate = false, recompute MSMS of surface, but without hydrogens (set radius of hydrogens to 0).
|
| 176 |
+
vertices2 = vertices1
|
| 177 |
+
faces2 = faces1
|
| 178 |
+
|
| 179 |
+
# Fix the mesh.
|
| 180 |
+
mesh = pymesh.form_mesh(vertices2, faces2)
|
| 181 |
+
mesh = pymesh.submesh(mesh, faces_to_keep, 0)
|
| 182 |
+
with io.capture_output() as captured:
|
| 183 |
+
regular_mesh = fix_mesh(mesh, masif_opts['mesh_res'])
|
| 184 |
+
|
| 185 |
+
# Compute the normals
|
| 186 |
+
vertex_normal = compute_normal(regular_mesh.vertices, regular_mesh.faces)
|
| 187 |
+
# Assign charges on new vertices based on charges of old vertices (nearest
|
| 188 |
+
# neighbor)
|
| 189 |
+
|
| 190 |
+
if masif_opts['use_hbond']:
|
| 191 |
+
vertex_hbond = assignChargesToNewMesh(regular_mesh.vertices, vertices1,\
|
| 192 |
+
vertex_hbond, masif_opts)
|
| 193 |
+
|
| 194 |
+
if masif_opts['use_hphob']:
|
| 195 |
+
vertex_hphobicity = assignChargesToNewMesh(regular_mesh.vertices, vertices1,\
|
| 196 |
+
vertex_hphobicity, masif_opts)
|
| 197 |
+
|
| 198 |
+
if masif_opts['use_apbs']:
|
| 199 |
+
vertex_charges = computeAPBS(regular_mesh.vertices, out_filename+sufix, out_filename+"_temp")
|
| 200 |
+
|
| 201 |
+
# Compute the principal curvature components for the shape index.
|
| 202 |
+
regular_mesh.add_attribute("vertex_mean_curvature")
|
| 203 |
+
H = regular_mesh.get_attribute("vertex_mean_curvature")
|
| 204 |
+
regular_mesh.add_attribute("vertex_gaussian_curvature")
|
| 205 |
+
K = regular_mesh.get_attribute("vertex_gaussian_curvature")
|
| 206 |
+
elem = np.square(H) - K
|
| 207 |
+
# In some cases this equation is less than zero, likely due to the method that computes the mean and gaussian curvature.
|
| 208 |
+
# set to an epsilon.
|
| 209 |
+
elem[elem<0] = 1e-8
|
| 210 |
+
k1 = H + np.sqrt(elem)
|
| 211 |
+
k2 = H - np.sqrt(elem)
|
| 212 |
+
# Compute the shape index
|
| 213 |
+
si = (k1+k2)/(k1-k2)
|
| 214 |
+
si = np.arctan(si)*(2/np.pi)
|
| 215 |
+
|
| 216 |
+
# Convert to ply and save.
|
| 217 |
+
save_ply(out_filename+f"/{sufix.split('.pdb')[0]}.ply", regular_mesh.vertices,\
|
| 218 |
+
regular_mesh.faces, normals=vertex_normal, charges=vertex_charges,\
|
| 219 |
+
normalize_charges=True, hbond=vertex_hbond, hphob=vertex_hphobicity,\
|
| 220 |
+
si=si)
|
| 221 |
+
|
| 222 |
+
return 0
|
| 223 |
+
except:
|
| 224 |
+
return target_filename
|
| 225 |
+
|
| 226 |
+
|
| 227 |
+
if __name__ == "__main__":
|
| 228 |
+
from joblib import delayed,Parallel
|
| 229 |
+
# arguments
|
| 230 |
+
from argparse import ArgumentParser, Namespace, FileType
|
| 231 |
+
parser = ArgumentParser()
|
| 232 |
+
parser.add_argument('--data_dir', type=str, default='~/SurfDock/model/data/test_samples', help='')
|
| 233 |
+
parser.add_argument('--out_dir', type=str, default='~/SurfDock/model/data/test_samples_8A_surface', help='')
|
| 234 |
+
parser.add_argument('--n_jobs',type=int, default=1, help='Number of parallel jobs (-1 for all CPUs)')
|
| 235 |
+
args = parser.parse_args()
|
| 236 |
+
os.makedirs(args.out_dir,exist_ok=True)
|
| 237 |
+
|
| 238 |
+
sys.path.append(args.out_dir)
|
| 239 |
+
from tqdm import tqdm
|
| 240 |
+
args_list = []
|
| 241 |
+
for protein in tqdm(os.listdir(args.data_dir)):
|
| 242 |
+
if os.path.exists(os.path.join(args.out_dir,protein,f'{protein}_protein_processed_obabel_reduce_obabel.pdb')):
|
| 243 |
+
target_filename = os.path.join(args.out_dir,protein,f'{protein}_protein_processed_obabel_reduce_obabel.pdb')
|
| 244 |
+
elif os.path.exists(os.path.join(args.data_dir,protein,f'{protein}_protein_processed.pdb')):
|
| 245 |
+
target_filename = os.path.join(args.data_dir,protein,f'{protein}_protein_processed.pdb')
|
| 246 |
+
print(f'{protein} use {target_filename}; Please check this protein file was processed by openbabel reduce! in protein_process')
|
| 247 |
+
else:
|
| 248 |
+
print(f'{protein} not exists , Please check file name or path')
|
| 249 |
+
continue
|
| 250 |
+
ligand_filename = os.path.join(args.data_dir,protein,f'{protein}_ligand.sdf')
|
| 251 |
+
if not os.path.exists(ligand_filename):
|
| 252 |
+
ligand_filename = os.path.join(args.data_dir,protein,f'{protein}_ligand.mol2')
|
| 253 |
+
args_list.append((target_filename,ligand_filename))
|
| 254 |
+
print(f'number {len(args_list)} need to processed.....')
|
| 255 |
+
results = Parallel(n_jobs = args.n_jobs,backend = 'multiprocessing')(delayed(compute_inp_surface)(target_filename, ligand_filename,args.out_dir, dist_threshold=8) for (target_filename, ligand_filename) in tqdm(args_list))
|
| 256 |
+
# print(results)
|
| 257 |
+
# Find all files in args.out_dir that end with _temp
|
| 258 |
+
|
| 259 |
+
files = glob.glob(os.path.join(args.out_dir, '*_temp*')) + glob.glob(os.path.join(args.out_dir, '*msms*'))
|
| 260 |
+
# Delete all found files
|
| 261 |
+
for f in files:
|
| 262 |
+
os.remove(f)
|
model/comp_surface/prepare_target/compute_normal.py
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import numpy as np
|
| 2 |
+
from numpy.matlib import repmat
|
| 3 |
+
"""
|
| 4 |
+
compute_normal.py: Compute the normals of a closed shape.
|
| 5 |
+
Pablo Gainza - LPDI STI EPFL 2019
|
| 6 |
+
This file is part of MaSIF, based on previous matlab code by Gabriel Peyre, converted to Python by Pablo Gainza
|
| 7 |
+
"""
|
| 8 |
+
|
| 9 |
+
###
|
| 10 |
+
from default_config.global_vars import epsilon as eps
|
| 11 |
+
|
| 12 |
+
"""
|
| 13 |
+
Taken from:
|
| 14 |
+
compute_normal.py - MaSIF
|
| 15 |
+
Pablo Gainza - LPDI STI EPFL 2019
|
| 16 |
+
"""
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
def compute_normal(vertex, face):
|
| 20 |
+
|
| 21 |
+
"""
|
| 22 |
+
compute_normal - compute the normal of a triangulation
|
| 23 |
+
vertex: 3xn matrix of vertices
|
| 24 |
+
face: 3xm matrix of face indices.
|
| 25 |
+
|
| 26 |
+
normal,normalf = compute_normal(vertex,face)
|
| 27 |
+
|
| 28 |
+
normal(i,:) is the normal at vertex i.
|
| 29 |
+
normalf(j,:) is the normal at face j.
|
| 30 |
+
|
| 31 |
+
Copyright (c) 2004 Gabriel Peyr
|
| 32 |
+
Converted to Python by Pablo Gainza LPDI EPFL 2017
|
| 33 |
+
"""
|
| 34 |
+
|
| 35 |
+
vertex = vertex.T
|
| 36 |
+
face = face.T
|
| 37 |
+
nface = np.size(face, 1)
|
| 38 |
+
nvert = np.size(vertex, 1)
|
| 39 |
+
normal = np.zeros((3, nvert))
|
| 40 |
+
# unit normals to the faces
|
| 41 |
+
normalf = crossp(
|
| 42 |
+
vertex[:, face[1, :]] - vertex[:, face[0, :]],
|
| 43 |
+
vertex[:, face[2, :]] - vertex[:, face[0, :]],
|
| 44 |
+
)
|
| 45 |
+
sum_squares = np.sum(normalf ** 2, 0)
|
| 46 |
+
d = np.sqrt(sum_squares)
|
| 47 |
+
d[d < eps] = 1
|
| 48 |
+
normalf = normalf / repmat(d, 3, 1)
|
| 49 |
+
# unit normal to the vertex
|
| 50 |
+
normal = np.zeros((3, nvert))
|
| 51 |
+
for i in np.arange(0, nface):
|
| 52 |
+
f = face[:, i]
|
| 53 |
+
for j in np.arange(3):
|
| 54 |
+
normal[:, f[j]] = normal[:, f[j]] + normalf[:, i]
|
| 55 |
+
|
| 56 |
+
# normalize
|
| 57 |
+
d = np.sqrt(np.sum(normal ** 2, 0))
|
| 58 |
+
d[d < eps] = 1
|
| 59 |
+
normal = normal / repmat(d, 3, 1)
|
| 60 |
+
# enforce that the normal are outward
|
| 61 |
+
vertex_means = np.mean(vertex, 0)
|
| 62 |
+
v = vertex - repmat(vertex_means, 3, 1)
|
| 63 |
+
s = np.sum(np.multiply(v, normal), 1)
|
| 64 |
+
if np.sum(s > 0) < np.sum(s < 0):
|
| 65 |
+
# flip
|
| 66 |
+
normal = -normal
|
| 67 |
+
normalf = -normalf
|
| 68 |
+
return normal.T
|
| 69 |
+
|
| 70 |
+
|
| 71 |
+
def crossp(x, y):
|
| 72 |
+
|
| 73 |
+
# x and y are (m,3) dimensional
|
| 74 |
+
z = np.zeros((x.shape))
|
| 75 |
+
z[0, :] = np.multiply(x[1, :], y[2, :]) - np.multiply(x[2, :], y[1, :])
|
| 76 |
+
z[1, :] = np.multiply(x[2, :], y[0, :]) - np.multiply(x[0, :], y[2, :])
|
| 77 |
+
z[2, :] = np.multiply(x[0, :], y[1, :]) - np.multiply(x[1, :], y[0, :])
|
| 78 |
+
return z
|
model/comp_surface/prepare_target/default_config/README.md
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
### source/default_config/
|
| 2 |
+
Contains MaSIF's default configuration options, and other parameters such as atom radiuses, the definition of polar hydrogens,
|
| 3 |
+
and the name of environment variables with external programs used by MaSIF.
|
model/comp_surface/prepare_target/default_config/__init__.py
ADDED
|
File without changes
|
model/comp_surface/prepare_target/default_config/chemistry.py
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# chemistry.py: Chemical parameters for MaSIF.
|
| 2 |
+
# Pablo Gainza - LPDI STI EPFL 2018-2019
|
| 3 |
+
# Released under an Apache License 2.0
|
| 4 |
+
|
| 5 |
+
import numpy as np
|
| 6 |
+
|
| 7 |
+
# radii for atoms in explicit case.
|
| 8 |
+
radii = {}
|
| 9 |
+
radii["N"] = "1.540000"
|
| 10 |
+
radii["N"] = "1.540000"
|
| 11 |
+
radii["O"] = "1.400000"
|
| 12 |
+
radii["C"] = "1.740000"
|
| 13 |
+
radii["H"] = "1.200000"
|
| 14 |
+
radii["S"] = "1.800000"
|
| 15 |
+
radii["P"] = "1.800000"
|
| 16 |
+
radii["Z"] = "1.39"
|
| 17 |
+
radii["X"] = "0.770000" ## Radii of CB or CA in disembodied case.
|
| 18 |
+
# This polar hydrogen's names correspond to that of the program Reduce.
|
| 19 |
+
polarHydrogens = {}
|
| 20 |
+
polarHydrogens["ALA"] = ["H"]
|
| 21 |
+
polarHydrogens["GLY"] = ["H"]
|
| 22 |
+
polarHydrogens["SER"] = ["H", "HG"]
|
| 23 |
+
polarHydrogens["THR"] = ["H", "HG1"]
|
| 24 |
+
polarHydrogens["LEU"] = ["H"]
|
| 25 |
+
polarHydrogens["ILE"] = ["H"]
|
| 26 |
+
polarHydrogens["VAL"] = ["H"]
|
| 27 |
+
polarHydrogens["ASN"] = ["H", "HD21", "HD22"]
|
| 28 |
+
polarHydrogens["GLN"] = ["H", "HE21", "HE22"]
|
| 29 |
+
polarHydrogens["ARG"] = ["H", "HH11", "HH12", "HH21", "HH22", "HE"]
|
| 30 |
+
polarHydrogens["HIS"] = ["H", "HD1", "HE2"]
|
| 31 |
+
polarHydrogens["TRP"] = ["H", "HE1"]
|
| 32 |
+
polarHydrogens["PHE"] = ["H"]
|
| 33 |
+
polarHydrogens["TYR"] = ["H", "HH"]
|
| 34 |
+
polarHydrogens["GLU"] = ["H"]
|
| 35 |
+
polarHydrogens["ASP"] = ["H"]
|
| 36 |
+
polarHydrogens["LYS"] = ["H", "HZ1", "HZ2", "HZ3"]
|
| 37 |
+
polarHydrogens["PRO"] = []
|
| 38 |
+
polarHydrogens["CYS"] = ["H"]
|
| 39 |
+
polarHydrogens["MET"] = ["H"]
|
| 40 |
+
|
| 41 |
+
hbond_std_dev = np.pi / 3
|
| 42 |
+
|
| 43 |
+
# Dictionary from an acceptor atom to its directly bonded atom on which to
|
| 44 |
+
# compute the angle.
|
| 45 |
+
acceptorAngleAtom = {}
|
| 46 |
+
acceptorAngleAtom["O"] = "C"
|
| 47 |
+
acceptorAngleAtom["O1"] = "C"
|
| 48 |
+
acceptorAngleAtom["O2"] = "C"
|
| 49 |
+
acceptorAngleAtom["OXT"] = "C"
|
| 50 |
+
acceptorAngleAtom["OT1"] = "C"
|
| 51 |
+
acceptorAngleAtom["OT2"] = "C"
|
| 52 |
+
# Dictionary from acceptor atom to a third atom on which to compute the plane.
|
| 53 |
+
acceptorPlaneAtom = {}
|
| 54 |
+
acceptorPlaneAtom["O"] = "CA"
|
| 55 |
+
# Dictionary from an H atom to its donor atom.
|
| 56 |
+
donorAtom = {}
|
| 57 |
+
donorAtom["H"] = "N"
|
| 58 |
+
# Hydrogen bond information.
|
| 59 |
+
# ARG
|
| 60 |
+
# ARG NHX
|
| 61 |
+
# Angle: NH1, HH1X, point and NH2, HH2X, point 180 degrees.
|
| 62 |
+
# radii from HH: radii[H]
|
| 63 |
+
# ARG NE
|
| 64 |
+
# Angle: ~ 120 NE, HE, point, 180 degrees
|
| 65 |
+
donorAtom["HH11"] = "NH1"
|
| 66 |
+
donorAtom["HH12"] = "NH1"
|
| 67 |
+
donorAtom["HH21"] = "NH2"
|
| 68 |
+
donorAtom["HH22"] = "NH2"
|
| 69 |
+
donorAtom["HE"] = "NE"
|
| 70 |
+
|
| 71 |
+
# ASN
|
| 72 |
+
# Angle ND2,HD2X: 180
|
| 73 |
+
# Plane: CG,ND2,OD1
|
| 74 |
+
# Angle CG-OD1-X: 120
|
| 75 |
+
donorAtom["HD21"] = "ND2"
|
| 76 |
+
donorAtom["HD22"] = "ND2"
|
| 77 |
+
# ASN Acceptor
|
| 78 |
+
acceptorAngleAtom["OD1"] = "CG"
|
| 79 |
+
acceptorPlaneAtom["OD1"] = "CB"
|
| 80 |
+
|
| 81 |
+
# ASP
|
| 82 |
+
# Plane: CB-CG-OD1
|
| 83 |
+
# Angle CG-ODX-point: 120
|
| 84 |
+
acceptorAngleAtom["OD2"] = "CG"
|
| 85 |
+
acceptorPlaneAtom["OD2"] = "CB"
|
| 86 |
+
|
| 87 |
+
# GLU
|
| 88 |
+
# PLANE: CD-OE1-OE2
|
| 89 |
+
# ANGLE: CD-OEX: 120
|
| 90 |
+
# GLN
|
| 91 |
+
# PLANE: CD-OE1-NE2
|
| 92 |
+
# Angle NE2,HE2X: 180
|
| 93 |
+
# ANGLE: CD-OE1: 120
|
| 94 |
+
donorAtom["HE21"] = "NE2"
|
| 95 |
+
donorAtom["HE22"] = "NE2"
|
| 96 |
+
acceptorAngleAtom["OE1"] = "CD"
|
| 97 |
+
acceptorAngleAtom["OE2"] = "CD"
|
| 98 |
+
acceptorPlaneAtom["OE1"] = "CG"
|
| 99 |
+
acceptorPlaneAtom["OE2"] = "CG"
|
| 100 |
+
|
| 101 |
+
# HIS Acceptors: ND1, NE2
|
| 102 |
+
# Plane ND1-CE1-NE2
|
| 103 |
+
# Angle: ND1-CE1 : 125.5
|
| 104 |
+
# Angle: NE2-CE1 : 125.5
|
| 105 |
+
acceptorAngleAtom["ND1"] = "CE1"
|
| 106 |
+
acceptorAngleAtom["NE2"] = "CE1"
|
| 107 |
+
acceptorPlaneAtom["ND1"] = "NE2"
|
| 108 |
+
acceptorPlaneAtom["NE2"] = "ND1"
|
| 109 |
+
|
| 110 |
+
# HIS Donors: ND1, NE2
|
| 111 |
+
# Angle ND1-HD1 : 180
|
| 112 |
+
# Angle NE2-HE2 : 180
|
| 113 |
+
donorAtom["HD1"] = "ND1"
|
| 114 |
+
donorAtom["HE2"] = "NE2"
|
| 115 |
+
|
| 116 |
+
# TRP Donor: NE1-HE1
|
| 117 |
+
# Angle NE1-HE1 : 180
|
| 118 |
+
donorAtom["HE1"] = "NE1"
|
| 119 |
+
|
| 120 |
+
# LYS Donor NZ-HZX
|
| 121 |
+
# Angle NZ-HZX : 180
|
| 122 |
+
donorAtom["HZ1"] = "NZ"
|
| 123 |
+
donorAtom["HZ2"] = "NZ"
|
| 124 |
+
donorAtom["HZ3"] = "NZ"
|
| 125 |
+
|
| 126 |
+
# TYR acceptor OH
|
| 127 |
+
# Plane: CE1-CZ-OH
|
| 128 |
+
# Angle: CZ-OH 120
|
| 129 |
+
acceptorAngleAtom["OH"] = "CZ"
|
| 130 |
+
acceptorPlaneAtom["OH"] = "CE1"
|
| 131 |
+
|
| 132 |
+
# TYR donor: OH-HH
|
| 133 |
+
# Angle: OH-HH 180
|
| 134 |
+
donorAtom["HH"] = "OH"
|
| 135 |
+
acceptorPlaneAtom["OH"] = "CE1"
|
| 136 |
+
|
| 137 |
+
# SER acceptor:
|
| 138 |
+
# Angle CB-OG-X: 120
|
| 139 |
+
acceptorAngleAtom["OG"] = "CB"
|
| 140 |
+
|
| 141 |
+
# SER donor:
|
| 142 |
+
# Angle: OG-HG-X: 180
|
| 143 |
+
donorAtom["HG"] = "OG"
|
| 144 |
+
|
| 145 |
+
# THR acceptor:
|
| 146 |
+
# Angle: CB-OG1-X: 120
|
| 147 |
+
acceptorAngleAtom["OG1"] = "CB"
|
| 148 |
+
|
| 149 |
+
# THR donor:
|
| 150 |
+
# Angle: OG1-HG1-X: 180
|
| 151 |
+
donorAtom["HG1"] = "OG1"
|
| 152 |
+
|
model/comp_surface/prepare_target/default_config/global_vars.py
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
from pathlib import Path
|
| 3 |
+
import sys
|
| 4 |
+
|
| 5 |
+
epsilon = 1.0e-6
|
| 6 |
+
|
| 7 |
+
PROJECT_ROOT = Path(__file__).resolve().parents[4]
|
| 8 |
+
TOOLS_ROOT = PROJECT_ROOT / "model" / "comp_surface" / "tools"
|
| 9 |
+
if (TOOLS_ROOT / "transfer").exists():
|
| 10 |
+
TOOLS_ROOT = TOOLS_ROOT / "transfer"
|
| 11 |
+
|
| 12 |
+
msms_bin = str(TOOLS_ROOT / "APBS-3.4.1.Linux" / "bin" / "msms")
|
| 13 |
+
pdb2pqr_bin = str(TOOLS_ROOT / "pdb2pqr-linux-bin64-2.1.1" / "pdb2pqr")
|
| 14 |
+
apbs_bin = str(TOOLS_ROOT / "APBS-3.4.1.Linux" / "bin" / "apbs")
|
| 15 |
+
multivalue_bin = str(TOOLS_ROOT / "APBS-3.4.1.Linux" / "share" / "apbs" / "tools" / "bin" / "multivalue")
|
| 16 |
+
|
| 17 |
+
os.environ["MSMS_BIN"] = msms_bin
|
| 18 |
+
os.environ["PDB2PQR_BIN"] = pdb2pqr_bin
|
| 19 |
+
os.environ["APBS_BIN"] = apbs_bin
|
| 20 |
+
os.environ["MULTIVALUE_BIN"] = multivalue_bin
|
| 21 |
+
|
| 22 |
+
for name, path in {
|
| 23 |
+
"MSMS_BIN": msms_bin,
|
| 24 |
+
"PDB2PQR_BIN": pdb2pqr_bin,
|
| 25 |
+
"APBS_BIN": apbs_bin,
|
| 26 |
+
"MULTIVALUE_BIN": multivalue_bin,
|
| 27 |
+
}.items():
|
| 28 |
+
if not os.path.exists(path):
|
| 29 |
+
print(f"ERROR: {name} does not exist: {path}", file=sys.stderr)
|
| 30 |
+
|
| 31 |
+
class NoSolutionError(Exception):
|
| 32 |
+
pass
|
model/comp_surface/prepare_target/default_config/masif_opts.py
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import tempfile
|
| 2 |
+
|
| 3 |
+
masif_opts = {}
|
| 4 |
+
# Default directories
|
| 5 |
+
masif_opts["raw_pdb_dir"] = "data_preparation/00-raw_pdbs/"
|
| 6 |
+
masif_opts["pdb_chain_dir"] = "data_preparation/01-benchmark_pdbs/"
|
| 7 |
+
masif_opts["ply_chain_dir"] = "data_preparation/01-benchmark_surfaces/"
|
| 8 |
+
masif_opts["tmp_dir"] = tempfile.gettempdir()
|
| 9 |
+
masif_opts["ply_file_template"] = masif_opts["ply_chain_dir"] + "/{}_{}.ply"
|
| 10 |
+
|
| 11 |
+
# Surface features
|
| 12 |
+
masif_opts["use_hbond"] = True
|
| 13 |
+
masif_opts["use_hphob"] = True
|
| 14 |
+
masif_opts["use_apbs"] = True
|
| 15 |
+
masif_opts["compute_iface"] = True
|
| 16 |
+
# Mesh resolution. Everything gets very slow if it is lower than 1.0
|
| 17 |
+
masif_opts["mesh_res"] = 1.0
|
| 18 |
+
masif_opts["feature_interpolation"] = True
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
# Coords params
|
| 22 |
+
masif_opts["radius"] = 12.0
|
| 23 |
+
|
| 24 |
+
# Neural network patch application specific parameters.
|
| 25 |
+
masif_opts["ppi_search"] = {}
|
| 26 |
+
masif_opts["ppi_search"]["training_list"] = "lists/training.txt"
|
| 27 |
+
masif_opts["ppi_search"]["testing_list"] = "lists/testing.txt"
|
| 28 |
+
masif_opts["ppi_search"]["max_shape_size"] = 200
|
| 29 |
+
masif_opts["ppi_search"]["max_distance"] = 12.0 # Radius for the neural network.
|
| 30 |
+
masif_opts["ppi_search"][
|
| 31 |
+
"masif_precomputation_dir"
|
| 32 |
+
] = "data_preparation/04b-precomputation_12A/precomputation/"
|
| 33 |
+
masif_opts["ppi_search"]["feat_mask"] = [1.0] * 5
|
| 34 |
+
masif_opts["ppi_search"]["max_sc_filt"] = 1.0
|
| 35 |
+
masif_opts["ppi_search"]["min_sc_filt"] = 0.5
|
| 36 |
+
masif_opts["ppi_search"]["pos_surf_accept_probability"] = 1.0
|
| 37 |
+
masif_opts["ppi_search"]["pos_interface_cutoff"] = 1.0
|
| 38 |
+
masif_opts["ppi_search"]["range_val_samples"] = 0.9 # 0.9 to 1.0
|
| 39 |
+
masif_opts["ppi_search"]["cache_dir"] = "nn_models/sc05/cache/"
|
| 40 |
+
masif_opts["ppi_search"]["model_dir"] = "nn_models/sc05/all_feat/model_data/"
|
| 41 |
+
masif_opts["ppi_search"]["desc_dir"] = "descriptors/sc05/all_feat/"
|
| 42 |
+
masif_opts["ppi_search"]["gif_descriptors_out"] = "gif_descriptors/"
|
| 43 |
+
# Parameters for shape complementarity calculations.
|
| 44 |
+
masif_opts["ppi_search"]["sc_radius"] = 12.0
|
| 45 |
+
masif_opts["ppi_search"]["sc_interaction_cutoff"] = 1.5
|
| 46 |
+
masif_opts["ppi_search"]["sc_w"] = 0.25
|
| 47 |
+
|
| 48 |
+
# Neural network patch application specific parameters.
|
| 49 |
+
masif_opts["site"] = {}
|
| 50 |
+
masif_opts["site"]["training_list"] = "lists/training.txt"
|
| 51 |
+
masif_opts["site"]["testing_list"] = "lists/testing.txt"
|
| 52 |
+
masif_opts["site"]["max_shape_size"] = 100
|
| 53 |
+
masif_opts["site"]["n_conv_layers"] = 3
|
| 54 |
+
masif_opts["site"]["max_distance"] = 9.0 # Radius for the neural network.
|
| 55 |
+
masif_opts["site"][
|
| 56 |
+
"masif_precomputation_dir"
|
| 57 |
+
] = "data_preparation/04a-precomputation_9A/precomputation/"
|
| 58 |
+
masif_opts["site"]["range_val_samples"] = 0.9 # 0.9 to 1.0
|
| 59 |
+
masif_opts["site"]["model_dir"] = "nn_models/all_feat_3l/model_data/"
|
| 60 |
+
masif_opts["site"]["out_pred_dir"] = "output/all_feat_3l/pred_data/"
|
| 61 |
+
masif_opts["site"]["out_surf_dir"] = "output/all_feat_3l/pred_surfaces/"
|
| 62 |
+
masif_opts["site"]["feat_mask"] = [1.0] * 5
|
| 63 |
+
|
| 64 |
+
# Neural network ligand application specific parameters.
|
| 65 |
+
masif_opts["ligand"] = {}
|
| 66 |
+
masif_opts["ligand"]["assembly_dir"] = "data_preparation/00b-pdbs_assembly"
|
| 67 |
+
masif_opts["ligand"]["ligand_coords_dir"] = "data_preparation/00c-ligand_coords"
|
| 68 |
+
masif_opts["ligand"][
|
| 69 |
+
"masif_precomputation_dir"
|
| 70 |
+
] = "data_preparation/04a-precomputation_12A/precomputation/"
|
| 71 |
+
masif_opts["ligand"]["max_shape_size"] = 200
|
| 72 |
+
masif_opts["ligand"]["feat_mask"] = [1.0] * 5
|
| 73 |
+
masif_opts["ligand"]["train_fract"] = 0.9 * 0.8
|
| 74 |
+
masif_opts["ligand"]["val_fract"] = 0.1 * 0.8
|
| 75 |
+
masif_opts["ligand"]["test_fract"] = 0.2
|
| 76 |
+
masif_opts["ligand"]["tfrecords_dir"] = "data_preparation/tfrecords"
|
| 77 |
+
masif_opts["ligand"]["max_distance"] = 12.0
|
| 78 |
+
masif_opts["ligand"]["n_classes"] = 7
|
| 79 |
+
masif_opts["ligand"]["feat_mask"] = [1.0, 1.0, 1.0, 1.0, 1.0]
|
| 80 |
+
masif_opts["ligand"]["costfun"] = "dprime"
|
| 81 |
+
masif_opts["ligand"]["model_dir"] = "nn_models/all_feat/"
|
| 82 |
+
masif_opts["ligand"]["test_set_out_dir"] = "test_set_predictions/"
|
| 83 |
+
|
model/comp_surface/prepare_target/fix_pdb.py
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from pdbfixer import PDBFixer
|
| 2 |
+
from openmm.app import PDBFile
|
| 3 |
+
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
# Load the PDB file
|
| 7 |
+
|
| 8 |
+
fixer = PDBFixer(filename='your_file.pdb')
|
| 9 |
+
|
| 10 |
+
# Find missing residues
|
| 11 |
+
fixer.findMissingResidues()
|
| 12 |
+
|
| 13 |
+
# Replace nonstandard residues
|
| 14 |
+
fixer.findNonstandardResidues()
|
| 15 |
+
fixer.replaceNonstandardResidues()
|
| 16 |
+
|
| 17 |
+
# Find missing atoms and add them
|
| 18 |
+
fixer.findMissingAtoms()
|
| 19 |
+
fixer.addMissingAtoms()
|
| 20 |
+
|
| 21 |
+
# Write the fixed PDB file
|
| 22 |
+
PDBFile.writeFile(fixer.topology, fixer.positions, open('fixed_pdb.pdb', 'w'))
|
model/comp_surface/prepare_target/fixmesh.py
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import numpy as np
|
| 2 |
+
from numpy.linalg import norm
|
| 3 |
+
import pymesh
|
| 4 |
+
|
| 5 |
+
"""
|
| 6 |
+
Modified from:
|
| 7 |
+
fixmesh.py - MaSIF
|
| 8 |
+
Pablo Gainza - LPDI STI EPFL 2019
|
| 9 |
+
"""
|
| 10 |
+
|
| 11 |
+
"""
|
| 12 |
+
fixmesh.py: Regularize a protein surface mesh.
|
| 13 |
+
- based on code from the PyMESH documentation.
|
| 14 |
+
"""
|
| 15 |
+
|
| 16 |
+
def fix_mesh(mesh, resolution, detail="normal"):
|
| 17 |
+
bbox_min, bbox_max = mesh.bbox;
|
| 18 |
+
diag_len = norm(bbox_max - bbox_min);
|
| 19 |
+
if detail == "normal":
|
| 20 |
+
target_len = diag_len * 5e-3;
|
| 21 |
+
elif detail == "high":
|
| 22 |
+
target_len = diag_len * 2.5e-3;
|
| 23 |
+
elif detail == "low":
|
| 24 |
+
target_len = diag_len * 1e-2;
|
| 25 |
+
|
| 26 |
+
target_len = resolution
|
| 27 |
+
#print("Target resolution: {} mm".format(target_len));
|
| 28 |
+
# PGC 2017: Remove duplicated vertices first
|
| 29 |
+
mesh, _ = pymesh.remove_duplicated_vertices(mesh, 0.001)
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
count = 0;
|
| 33 |
+
print("Removing degenerated triangles")
|
| 34 |
+
mesh, __ = pymesh.remove_degenerated_triangles(mesh, 100);
|
| 35 |
+
mesh, __ = pymesh.split_long_edges(mesh, target_len);
|
| 36 |
+
num_vertices = mesh.num_vertices;
|
| 37 |
+
while True:
|
| 38 |
+
mesh, __ = pymesh.collapse_short_edges(mesh, 1e-6);
|
| 39 |
+
mesh, __ = pymesh.collapse_short_edges(mesh, target_len,
|
| 40 |
+
preserve_feature=True);
|
| 41 |
+
mesh, __ = pymesh.remove_obtuse_triangles(mesh, 150.0, 100);
|
| 42 |
+
if mesh.num_vertices == num_vertices:
|
| 43 |
+
break;
|
| 44 |
+
|
| 45 |
+
num_vertices = mesh.num_vertices;
|
| 46 |
+
#print("#v: {}".format(num_vertices));
|
| 47 |
+
count += 1;
|
| 48 |
+
if count > 10: break;
|
| 49 |
+
|
| 50 |
+
mesh = pymesh.resolve_self_intersection(mesh);
|
| 51 |
+
mesh, __ = pymesh.remove_duplicated_faces(mesh);
|
| 52 |
+
#mesh = pymesh.compute_outer_hull(mesh);
|
| 53 |
+
|
| 54 |
+
############ Added by Oscar Mendez Lucio ##############
|
| 55 |
+
mesh = pymesh.compute_outer_hull(mesh, all_layers=True);
|
| 56 |
+
num_nodes = [i.num_nodes for i in mesh]
|
| 57 |
+
mesh = mesh[np.argmax(num_nodes)]
|
| 58 |
+
############################################################
|
| 59 |
+
|
| 60 |
+
mesh, __ = pymesh.remove_duplicated_faces(mesh);
|
| 61 |
+
mesh, __ = pymesh.remove_obtuse_triangles(mesh, 179.0, 5);
|
| 62 |
+
mesh, __ = pymesh.remove_isolated_vertices(mesh);
|
| 63 |
+
mesh, _ = pymesh.remove_duplicated_vertices(mesh, 0.001)
|
| 64 |
+
|
| 65 |
+
############ Added by Oscar Mendez Lucio ##############
|
| 66 |
+
mesh = pymesh.separate_mesh(mesh)
|
| 67 |
+
num_nodes = [i.num_nodes for i in mesh]
|
| 68 |
+
mesh = mesh[np.argmax(num_nodes)]
|
| 69 |
+
############################################################
|
| 70 |
+
|
| 71 |
+
return mesh
|
model/comp_surface/prepare_target/input_output/README.md
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
### source/input_output/
|
| 2 |
+
Contains functions to read/write surface files, protonate PDBs and extract PDB chains.
|
model/comp_surface/prepare_target/input_output/__init__.py
ADDED
|
File without changes
|
model/comp_surface/prepare_target/input_output/extractHelix.py
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from Bio.PDB import *
|
| 2 |
+
|
| 3 |
+
# Exclude disordered atoms.
|
| 4 |
+
class NotDisordered(Select):
|
| 5 |
+
def accept_atom(self, atom):
|
| 6 |
+
return not atom.is_disordered() or atom.get_altloc() == 'A'
|
| 7 |
+
|
| 8 |
+
def extractHelix(helix, infilename, outfilename, chain_ids=None, includeWaters=False,\
|
| 9 |
+
invert=False):
|
| 10 |
+
parser = PDBParser(QUIET=True)
|
| 11 |
+
struct = parser.get_structure(infilename, infilename)
|
| 12 |
+
model = Selection.unfold_entities(struct, 'M')[0]
|
| 13 |
+
chains = Selection.unfold_entities(struct, 'C')
|
| 14 |
+
# Select residues to extract and build new structure
|
| 15 |
+
structBuild = StructureBuilder.StructureBuilder()
|
| 16 |
+
structBuild.init_structure("output")
|
| 17 |
+
structBuild.init_seg(" ")
|
| 18 |
+
structBuild.init_model(0)
|
| 19 |
+
outputStruct = structBuild.get_structure()
|
| 20 |
+
for chain in model:
|
| 21 |
+
if chain.get_id() in chain_ids:
|
| 22 |
+
structBuild.init_chain(chain.get_id())
|
| 23 |
+
for residue in chain:
|
| 24 |
+
het = residue.get_id()
|
| 25 |
+
if het[0] == ' ' and het in helix:
|
| 26 |
+
outputStruct[0][chain.get_id()].add(residue)
|
| 27 |
+
|
| 28 |
+
# Output the selected residues
|
| 29 |
+
pdbio = PDBIO()
|
| 30 |
+
pdbio.set_structure(outputStruct)
|
| 31 |
+
pdbio.save(outfilename, select=NotDisordered())
|
| 32 |
+
|
model/comp_surface/prepare_target/input_output/extractPDB.py
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
extractPDB.py: Extract selected chains from a PDB and save the extracted chains to an output file.
|
| 3 |
+
Pablo Gainza - LPDI STI EPFL 2019
|
| 4 |
+
Released under an Apache License 2.0
|
| 5 |
+
"""
|
| 6 |
+
from Bio.PDB import *
|
| 7 |
+
|
| 8 |
+
from Bio.SeqUtils import IUPACData
|
| 9 |
+
PROTEIN_LETTERS = [x.upper() for x in IUPACData.protein_letters_3to1.keys()]
|
| 10 |
+
|
| 11 |
+
# Exclude disordered atoms.
|
| 12 |
+
class NotDisordered(Select):
|
| 13 |
+
def accept_atom(self, atom):
|
| 14 |
+
return not atom.is_disordered() or atom.get_altloc() == "A" or atom.get_altloc() == "1"
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
def find_modified_amino_acids(path):
|
| 18 |
+
"""
|
| 19 |
+
Contributed by github user jomimc - find modified amino acids in the PDB (e.g. MSE)
|
| 20 |
+
"""
|
| 21 |
+
res_set = set()
|
| 22 |
+
for line in open(path, 'r'):
|
| 23 |
+
if line[:6] == 'SEQRES':
|
| 24 |
+
for res in line.split()[4:]:
|
| 25 |
+
res_set.add(res)
|
| 26 |
+
for res in list(res_set):
|
| 27 |
+
if res in PROTEIN_LETTERS:
|
| 28 |
+
res_set.remove(res)
|
| 29 |
+
return res_set
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
def extractPDB(
|
| 33 |
+
infilename, outfilename, chain_ids=None
|
| 34 |
+
):
|
| 35 |
+
# extract the chain_ids from infilename and save in outfilename.
|
| 36 |
+
parser = PDBParser(QUIET=True)
|
| 37 |
+
struct = parser.get_structure(infilename, infilename)
|
| 38 |
+
model = Selection.unfold_entities(struct, "M")[0]
|
| 39 |
+
chains = Selection.unfold_entities(struct, "C")
|
| 40 |
+
# Select residues to extract and build new structure
|
| 41 |
+
structBuild = StructureBuilder.StructureBuilder()
|
| 42 |
+
structBuild.init_structure("output")
|
| 43 |
+
structBuild.init_seg(" ")
|
| 44 |
+
structBuild.init_model(0)
|
| 45 |
+
outputStruct = structBuild.get_structure()
|
| 46 |
+
|
| 47 |
+
# Load a list of non-standard amino acid names -- these are
|
| 48 |
+
# typically listed under HETATM, so they would be typically
|
| 49 |
+
# ignored by the orginal algorithm
|
| 50 |
+
modified_amino_acids = find_modified_amino_acids(infilename)
|
| 51 |
+
|
| 52 |
+
for chain in model:
|
| 53 |
+
if (
|
| 54 |
+
chain_ids == None
|
| 55 |
+
or chain.get_id() in chain_ids
|
| 56 |
+
):
|
| 57 |
+
structBuild.init_chain(chain.get_id())
|
| 58 |
+
for residue in chain:
|
| 59 |
+
het = residue.get_id()
|
| 60 |
+
if het[0] == " ":
|
| 61 |
+
outputStruct[0][chain.get_id()].add(residue)
|
| 62 |
+
elif het[0][-3:] in modified_amino_acids:
|
| 63 |
+
outputStruct[0][chain.get_id()].add(residue)
|
| 64 |
+
|
| 65 |
+
# Output the selected residues
|
| 66 |
+
pdbio = PDBIO()
|
| 67 |
+
pdbio.set_structure(outputStruct)
|
| 68 |
+
pdbio.save(outfilename, select=NotDisordered())
|
| 69 |
+
|
model/comp_surface/prepare_target/input_output/protonate.py
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
protonate.py: Wrapper method for the reduce program: protonate (i.e., add hydrogens) a pdb using reduce
|
| 3 |
+
and save to an output file.
|
| 4 |
+
Pablo Gainza - LPDI STI EPFL 2019
|
| 5 |
+
Released under an Apache License 2.0
|
| 6 |
+
"""
|
| 7 |
+
|
| 8 |
+
from subprocess import Popen, PIPE
|
| 9 |
+
from IPython.core.debugger import set_trace
|
| 10 |
+
import os
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
def protonate(in_pdb_file, out_pdb_file):
|
| 14 |
+
# protonate (i.e., add hydrogens) a pdb using reduce and save to an output file.
|
| 15 |
+
# in_pdb_file: file to protonate.
|
| 16 |
+
# out_pdb_file: output file where to save the protonated pdb file.
|
| 17 |
+
|
| 18 |
+
# Remove protons first, in case the structure is already protonated
|
| 19 |
+
args = ["reduce", "-Trim", in_pdb_file]
|
| 20 |
+
p2 = Popen(args, stdout=PIPE, stderr=PIPE)
|
| 21 |
+
stdout, stderr = p2.communicate()
|
| 22 |
+
outfile = open(out_pdb_file, "w")
|
| 23 |
+
outfile.write(stdout.decode('utf-8').rstrip())
|
| 24 |
+
outfile.close()
|
| 25 |
+
# Now add them again.
|
| 26 |
+
args = ["reduce", "-HIS", out_pdb_file]
|
| 27 |
+
p2 = Popen(args, stdout=PIPE, stderr=PIPE)
|
| 28 |
+
stdout, stderr = p2.communicate()
|
| 29 |
+
outfile = open(out_pdb_file, "w")
|
| 30 |
+
outfile.write(stdout.decode('utf-8'))
|
| 31 |
+
outfile.close()
|
| 32 |
+
|
model/comp_surface/prepare_target/input_output/read_msms.py
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import numpy as np
|
| 2 |
+
"""
|
| 3 |
+
read_msms.py: Read an msms output file that was output by MSMS (MSMS is the program we use to build a surface)
|
| 4 |
+
Pablo Gainza - LPDI STI EPFL 2019
|
| 5 |
+
Released under an Apache License 2.0
|
| 6 |
+
"""
|
| 7 |
+
|
| 8 |
+
def read_msms(file_root):
|
| 9 |
+
# read the surface from the msms output. MSMS outputs two files: {file_root}.vert and {file_root}.face
|
| 10 |
+
|
| 11 |
+
vertfile = open(file_root + ".vert")
|
| 12 |
+
meshdata = (vertfile.read().rstrip()).split("\n")
|
| 13 |
+
vertfile.close()
|
| 14 |
+
|
| 15 |
+
# Read number of vertices.
|
| 16 |
+
count = {}
|
| 17 |
+
header = meshdata[2].split()
|
| 18 |
+
count["vertices"] = int(header[0])
|
| 19 |
+
## Data Structures
|
| 20 |
+
vertices = np.zeros((count["vertices"], 3))
|
| 21 |
+
normalv = np.zeros((count["vertices"], 3))
|
| 22 |
+
atom_id = [""] * count["vertices"]
|
| 23 |
+
res_id = [""] * count["vertices"]
|
| 24 |
+
for i in range(3, len(meshdata)):
|
| 25 |
+
fields = meshdata[i].split()
|
| 26 |
+
vi = i - 3
|
| 27 |
+
vertices[vi][0] = float(fields[0])
|
| 28 |
+
vertices[vi][1] = float(fields[1])
|
| 29 |
+
vertices[vi][2] = float(fields[2])
|
| 30 |
+
normalv[vi][0] = float(fields[3])
|
| 31 |
+
normalv[vi][1] = float(fields[4])
|
| 32 |
+
normalv[vi][2] = float(fields[5])
|
| 33 |
+
atom_id[vi] = fields[7]
|
| 34 |
+
res_id[vi] = fields[9]
|
| 35 |
+
count["vertices"] -= 1
|
| 36 |
+
|
| 37 |
+
# Read faces.
|
| 38 |
+
facefile = open(file_root + ".face")
|
| 39 |
+
meshdata = (facefile.read().rstrip()).split("\n")
|
| 40 |
+
facefile.close()
|
| 41 |
+
|
| 42 |
+
# Read number of vertices.
|
| 43 |
+
header = meshdata[2].split()
|
| 44 |
+
count["faces"] = int(header[0])
|
| 45 |
+
faces = np.zeros((count["faces"], 3), dtype=int)
|
| 46 |
+
normalf = np.zeros((count["faces"], 3))
|
| 47 |
+
|
| 48 |
+
for i in range(3, len(meshdata)):
|
| 49 |
+
fi = i - 3
|
| 50 |
+
fields = meshdata[i].split()
|
| 51 |
+
faces[fi][0] = int(fields[0]) - 1
|
| 52 |
+
faces[fi][1] = int(fields[1]) - 1
|
| 53 |
+
faces[fi][2] = int(fields[2]) - 1
|
| 54 |
+
count["faces"] -= 1
|
| 55 |
+
|
| 56 |
+
assert count["vertices"] == 0
|
| 57 |
+
assert count["faces"] == 0
|
| 58 |
+
|
| 59 |
+
return vertices, faces, normalv, res_id
|
| 60 |
+
|
model/comp_surface/prepare_target/input_output/read_ply.py
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import pymesh
|
| 2 |
+
import numpy
|
| 3 |
+
"""
|
| 4 |
+
read_ply.py: Read a ply file from disk using pymesh and load the attributes used by MaSIF.
|
| 5 |
+
Pablo Gainza - LPDI STI EPFL 2019
|
| 6 |
+
Released under an Apache License 2.0
|
| 7 |
+
"""
|
| 8 |
+
|
| 9 |
+
def read_ply(filename):
|
| 10 |
+
# Read a ply file from disk using pymesh and load the attributes used by MaSIF.
|
| 11 |
+
# filename: the input ply file.
|
| 12 |
+
# returns data as tuple.
|
| 13 |
+
mesh = pymesh.load_mesh(filename)
|
| 14 |
+
|
| 15 |
+
attributes = mesh.get_attribute_names()
|
| 16 |
+
if "vertex_nx" in attributes:
|
| 17 |
+
nx = mesh.get_attribute("vertex_nx")
|
| 18 |
+
ny = mesh.get_attribute("vertex_ny")
|
| 19 |
+
nz = mesh.get_attribute("vertex_nz")
|
| 20 |
+
|
| 21 |
+
normals = numpy.column_stack((nx, ny, nz))
|
| 22 |
+
else:
|
| 23 |
+
normals = None
|
| 24 |
+
if "vertex_charge" in attributes:
|
| 25 |
+
charge = mesh.get_attribute("vertex_charge")
|
| 26 |
+
else:
|
| 27 |
+
charge = numpy.array([0.0] * len(mesh.vertices))
|
| 28 |
+
|
| 29 |
+
if "vertex_cb" in attributes:
|
| 30 |
+
vertex_cb = mesh.get_attribute("vertex_cb")
|
| 31 |
+
else:
|
| 32 |
+
vertex_cb = numpy.array([0.0] * len(mesh.vertices))
|
| 33 |
+
|
| 34 |
+
if "vertex_hbond" in attributes:
|
| 35 |
+
vertex_hbond = mesh.get_attribute("vertex_hbond")
|
| 36 |
+
else:
|
| 37 |
+
vertex_hbond = numpy.array([0.0] * len(mesh.vertices))
|
| 38 |
+
|
| 39 |
+
if "vertex_hphob" in attributes:
|
| 40 |
+
vertex_hphob = mesh.get_attribute("vertex_hphob")
|
| 41 |
+
else:
|
| 42 |
+
vertex_hphob = numpy.array([0.0] * len(mesh.vertices))
|
| 43 |
+
|
| 44 |
+
return (
|
| 45 |
+
mesh.vertices,
|
| 46 |
+
mesh.faces,
|
| 47 |
+
normals,
|
| 48 |
+
charge,
|
| 49 |
+
vertex_cb,
|
| 50 |
+
vertex_hbond,
|
| 51 |
+
vertex_hphob,
|
| 52 |
+
)
|
| 53 |
+
|
model/comp_surface/prepare_target/input_output/save_ply.py
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import pymesh
|
| 2 |
+
import numpy
|
| 3 |
+
"""
|
| 4 |
+
read_ply.py: Save a ply file to disk using pymesh and load the attributes used by MaSIF.
|
| 5 |
+
Pablo Gainza - LPDI STI EPFL 2019
|
| 6 |
+
Released under an Apache License 2.0
|
| 7 |
+
"""
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
def save_ply(
|
| 11 |
+
filename,
|
| 12 |
+
vertices,
|
| 13 |
+
faces=[],
|
| 14 |
+
normals=None,
|
| 15 |
+
charges=None,
|
| 16 |
+
vertex_cb=None,
|
| 17 |
+
hbond=None,
|
| 18 |
+
hphob=None,
|
| 19 |
+
iface=None,
|
| 20 |
+
normalize_charges=False,
|
| 21 |
+
):
|
| 22 |
+
""" Save vertices, mesh in ply format.
|
| 23 |
+
vertices: coordinates of vertices
|
| 24 |
+
faces: mesh
|
| 25 |
+
"""
|
| 26 |
+
mesh = pymesh.form_mesh(vertices, faces)
|
| 27 |
+
if normals is not None:
|
| 28 |
+
n1 = normals[:, 0]
|
| 29 |
+
n2 = normals[:, 1]
|
| 30 |
+
n3 = normals[:, 2]
|
| 31 |
+
mesh.add_attribute("vertex_nx")
|
| 32 |
+
mesh.set_attribute("vertex_nx", n1)
|
| 33 |
+
mesh.add_attribute("vertex_ny")
|
| 34 |
+
mesh.set_attribute("vertex_ny", n2)
|
| 35 |
+
mesh.add_attribute("vertex_nz")
|
| 36 |
+
mesh.set_attribute("vertex_nz", n3)
|
| 37 |
+
if charges is not None:
|
| 38 |
+
mesh.add_attribute("charge")
|
| 39 |
+
if normalize_charges:
|
| 40 |
+
charges = charges / 10
|
| 41 |
+
mesh.set_attribute("charge", charges)
|
| 42 |
+
if hbond is not None:
|
| 43 |
+
mesh.add_attribute("hbond")
|
| 44 |
+
mesh.set_attribute("hbond", hbond)
|
| 45 |
+
if vertex_cb is not None:
|
| 46 |
+
mesh.add_attribute("vertex_cb")
|
| 47 |
+
mesh.set_attribute("vertex_cb", vertex_cb)
|
| 48 |
+
if hphob is not None:
|
| 49 |
+
mesh.add_attribute("vertex_hphob")
|
| 50 |
+
mesh.set_attribute("vertex_hphob", hphob)
|
| 51 |
+
if iface is not None:
|
| 52 |
+
mesh.add_attribute("vertex_iface")
|
| 53 |
+
mesh.set_attribute("vertex_iface", iface)
|
| 54 |
+
|
| 55 |
+
pymesh.save_mesh(
|
| 56 |
+
filename, mesh, *mesh.get_attribute_names(), use_float=True, ascii=True
|
| 57 |
+
)
|
| 58 |
+
|
model/comp_surface/prepare_target/mol2graph.py
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import numpy as np
|
| 2 |
+
from rdkit.Chem import AllChem, Draw, Descriptors, rdMolTransforms
|
| 3 |
+
import rdkit.Chem as Chem
|
| 4 |
+
import rdkit.Chem.rdMolDescriptors as rdMolDescriptors
|
| 5 |
+
import rdkit.Chem.EState as EState
|
| 6 |
+
import rdkit.Chem.rdPartialCharges as rdPartialCharges
|
| 7 |
+
import rdkit.Chem.rdChemReactions as rdRxns
|
| 8 |
+
import copy
|
| 9 |
+
att_dtype = np.float32
|
| 10 |
+
|
| 11 |
+
import networkx as nx
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
def oneHotVector(val, lst):
|
| 15 |
+
'''Converts a value to a one-hot vector based on options in lst'''
|
| 16 |
+
if val not in lst:
|
| 17 |
+
val = lst[-1]
|
| 18 |
+
return map(lambda x: x == val, lst)
|
| 19 |
+
|
| 20 |
+
def mol_to_nx(mol):
|
| 21 |
+
G = nx. Graph()
|
| 22 |
+
|
| 23 |
+
# Globals.
|
| 24 |
+
G.graph["features"] = np.array([None], dtype = np.float32)
|
| 25 |
+
atomCoords = mol.GetConformer().GetPositions()
|
| 26 |
+
|
| 27 |
+
for i, atom in enumerate(mol.GetAtoms()):
|
| 28 |
+
if atom.GetAtomicNum() == 1: continue
|
| 29 |
+
G.add_node(atom.GetIdx(),
|
| 30 |
+
pos = atomCoords[i],
|
| 31 |
+
x=np.array(list(oneHotVector(atom.GetAtomicNum(),
|
| 32 |
+
[4, 5, 6, 7, 8, 9, 12, 14, 15, 16, 17, 23, 26, 27, 29, 30, 33, 34, 35, 44, 45, 51, 53, 75, 76, 77, 78, 80])),
|
| 33 |
+
dtype = np.float32))
|
| 34 |
+
|
| 35 |
+
for bond in mol.GetBonds():
|
| 36 |
+
if mol.GetAtomWithIdx(bond.GetBeginAtomIdx()).GetAtomicNum() == 1: continue
|
| 37 |
+
if mol.GetAtomWithIdx(bond.GetEndAtomIdx()).GetAtomicNum() == 1: continue
|
| 38 |
+
isConjugated = 1 if bond.GetIsConjugated() and not bond.GetIsAromatic() else 0
|
| 39 |
+
G.add_edge(bond.GetBeginAtomIdx(),
|
| 40 |
+
bond.GetEndAtomIdx(),
|
| 41 |
+
edge_attr=np.array(list(oneHotVector(bond.GetBondTypeAsDouble(),
|
| 42 |
+
[1.0, 1.5, 2.0, 3.0, 99.0]))+[isConjugated],
|
| 43 |
+
dtype = np.float32))
|
| 44 |
+
'''
|
| 45 |
+
try:
|
| 46 |
+
conf = mol.GetConformer()
|
| 47 |
+
for i in range(0, mol.GetNumAtoms()-1):
|
| 48 |
+
for j in range(i+1,mol.GetNumAtoms()):
|
| 49 |
+
if mol.GetBondBetweenAtoms(i,j)==None:
|
| 50 |
+
ShortestPath = Chem.rdmolops.GetShortestPath(mol, i,j)
|
| 51 |
+
dist=Chem.rdMolTransforms.GetBondLength(conf,i,j)
|
| 52 |
+
if (dist <= 10. and len(ShortestPath) > 4):
|
| 53 |
+
G.add_edge(i, j, bond_type=None, features=np.array([0.,0.,0.,0.,0.,dist], dtype = np.float32))
|
| 54 |
+
except:pass
|
| 55 |
+
'''
|
| 56 |
+
return G
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
def get_bonds(mol_list, bidirectional=True):
|
| 60 |
+
atom_counter=0
|
| 61 |
+
bonds = []
|
| 62 |
+
dist = []
|
| 63 |
+
for m in mol_list:
|
| 64 |
+
for x in m.GetBonds():
|
| 65 |
+
conf = m.GetConformer()
|
| 66 |
+
bonds.extend([(x.GetBeginAtomIdx()+atom_counter, x.GetEndAtomIdx()+atom_counter)])
|
| 67 |
+
dist.extend([rdMolTransforms.GetBondLength(conf,x.GetBeginAtomIdx(), x.GetEndAtomIdx())])
|
| 68 |
+
if bidirectional:
|
| 69 |
+
bonds.extend([(x.GetEndAtomIdx()+atom_counter, x.GetBeginAtomIdx()+atom_counter)])
|
| 70 |
+
dist.extend([rdMolTransforms.GetBondLength(conf,x.GetEndAtomIdx(), x.GetBeginAtomIdx())])
|
| 71 |
+
atom_counter += m.GetNumAtoms()
|
| 72 |
+
return bonds, dist
|
| 73 |
+
|
| 74 |
+
|
| 75 |
+
def get_angles(mol_list, bidirectional=True):
|
| 76 |
+
atom_counter = 0
|
| 77 |
+
bendList = []
|
| 78 |
+
angleList = []
|
| 79 |
+
for m in mol_list:
|
| 80 |
+
bendSmarts = '*~*~*'
|
| 81 |
+
bendQuery = Chem.MolFromSmarts(bendSmarts)
|
| 82 |
+
matches = m.GetSubstructMatches(bendQuery)
|
| 83 |
+
conf = m.GetConformer()
|
| 84 |
+
for match in matches:
|
| 85 |
+
idx0 = match[0]
|
| 86 |
+
idx1 = match[1]
|
| 87 |
+
idx2 = match[2]
|
| 88 |
+
bendList.append((idx0+atom_counter, idx1+atom_counter, idx2+atom_counter))
|
| 89 |
+
angleList.append(rdMolTransforms.GetAngleRad(conf, idx0, idx1, idx2))
|
| 90 |
+
if bidirectional:
|
| 91 |
+
bendList.append((idx2+atom_counter, idx1+atom_counter, idx0+atom_counter))
|
| 92 |
+
angleList.append(rdMolTransforms.GetAngleRad(conf, idx2, idx1, idx0))
|
| 93 |
+
atom_counter += m.GetNumAtoms()
|
| 94 |
+
return bendList, angleList
|
| 95 |
+
|
| 96 |
+
|
| 97 |
+
def get_torsions(mol_list, bidirectional=True):
|
| 98 |
+
atom_counter=0
|
| 99 |
+
torsionList = []
|
| 100 |
+
dihedralList = []
|
| 101 |
+
for m in mol_list:
|
| 102 |
+
torsionSmarts = '[!$(*#*)&!D1]~[!$(*#*)&!D1]'
|
| 103 |
+
torsionQuery = Chem.MolFromSmarts(torsionSmarts)
|
| 104 |
+
matches = m.GetSubstructMatches(torsionQuery)
|
| 105 |
+
conf = m.GetConformer()
|
| 106 |
+
for match in matches:
|
| 107 |
+
idx2 = match[0]
|
| 108 |
+
idx3 = match[1]
|
| 109 |
+
bond = m.GetBondBetweenAtoms(idx2, idx3)
|
| 110 |
+
jAtom = m.GetAtomWithIdx(idx2)
|
| 111 |
+
kAtom = m.GetAtomWithIdx(idx3)
|
| 112 |
+
if (((jAtom.GetHybridization() != Chem.HybridizationType.SP2)
|
| 113 |
+
and (jAtom.GetHybridization() != Chem.HybridizationType.SP3))
|
| 114 |
+
or ((kAtom.GetHybridization() != Chem.HybridizationType.SP2)
|
| 115 |
+
and (kAtom.GetHybridization() != Chem.HybridizationType.SP3))):
|
| 116 |
+
continue
|
| 117 |
+
for b1 in jAtom.GetBonds():
|
| 118 |
+
if (b1.GetIdx() == bond.GetIdx()):
|
| 119 |
+
continue
|
| 120 |
+
idx1 = b1.GetOtherAtomIdx(idx2)
|
| 121 |
+
for b2 in kAtom.GetBonds():
|
| 122 |
+
if ((b2.GetIdx() == bond.GetIdx())
|
| 123 |
+
or (b2.GetIdx() == b1.GetIdx())):
|
| 124 |
+
continue
|
| 125 |
+
idx4 = b2.GetOtherAtomIdx(idx3)
|
| 126 |
+
# skip 3-membered rings
|
| 127 |
+
if (idx4 == idx1):
|
| 128 |
+
continue
|
| 129 |
+
torsionList.append((idx1+atom_counter, idx2+atom_counter, idx3+atom_counter, idx4+atom_counter))
|
| 130 |
+
dihedralList.append(rdMolTransforms.GetDihedralRad(conf, idx1, idx2, idx3, idx4))
|
| 131 |
+
if bidirectional:
|
| 132 |
+
torsionList.append((idx4+atom_counter, idx3+atom_counter, idx2+atom_counter, idx1+atom_counter))
|
| 133 |
+
dihedralList.append(rdMolTransforms.GetDihedralRad(conf, idx4, idx3, idx2, idx1))
|
| 134 |
+
atom_counter += m.GetNumAtoms()
|
| 135 |
+
return torsionList, dihedralList
|
| 136 |
+
|
| 137 |
+
|
| 138 |
+
def mol_with_atom_index( mol ):
|
| 139 |
+
atoms = mol.GetNumAtoms()
|
| 140 |
+
for idx in range( atoms ):
|
| 141 |
+
mol.GetAtomWithIdx( idx ).SetProp( 'molAtomMapNumber', str( mol.GetAtomWithIdx( idx ).GetIdx() ) )
|
| 142 |
+
return mol
|
| 143 |
+
|
| 144 |
+
def atomenvironments(mol, radius=3):
|
| 145 |
+
envs = []
|
| 146 |
+
for a in mol.GetAtoms():
|
| 147 |
+
idx = a.GetIdx()
|
| 148 |
+
env = Chem.FindAtomEnvironmentOfRadiusN(mol, radius, idx)
|
| 149 |
+
amap = {}
|
| 150 |
+
submol=Chem.PathToSubmol(mol, env, atomMap=amap)
|
| 151 |
+
if amap.get(idx) is not None:
|
| 152 |
+
envs.append(Chem.MolToSmarts(submol))
|
| 153 |
+
return envs
|
model/comp_surface/prepare_target/save_ply.py
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import pymesh
|
| 2 |
+
import numpy
|
| 3 |
+
"""
|
| 4 |
+
Modified from:
|
| 5 |
+
save_ply.py - MaSIF
|
| 6 |
+
Pablo Gainza - LPDI STI EPFL 2019
|
| 7 |
+
"""
|
| 8 |
+
|
| 9 |
+
"""
|
| 10 |
+
read_ply.py: Save a ply file to disk using pymesh and load the attributes used by MaSIF.
|
| 11 |
+
Pablo Gainza - LPDI STI EPFL 2019
|
| 12 |
+
Released under an Apache License 2.0
|
| 13 |
+
"""
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
def save_ply(
|
| 17 |
+
filename,
|
| 18 |
+
vertices,
|
| 19 |
+
faces=[],
|
| 20 |
+
normals=None,
|
| 21 |
+
charges=None,
|
| 22 |
+
vertex_cb=None,
|
| 23 |
+
hbond=None,
|
| 24 |
+
hphob=None,
|
| 25 |
+
iface=None,
|
| 26 |
+
si=None,
|
| 27 |
+
normalize_charges=False,
|
| 28 |
+
):
|
| 29 |
+
""" Save vertices, mesh in ply format.
|
| 30 |
+
vertices: coordinates of vertices
|
| 31 |
+
faces: mesh
|
| 32 |
+
"""
|
| 33 |
+
mesh = pymesh.form_mesh(vertices, faces)
|
| 34 |
+
if normals is not None:
|
| 35 |
+
n1 = normals[:, 0]
|
| 36 |
+
n2 = normals[:, 1]
|
| 37 |
+
n3 = normals[:, 2]
|
| 38 |
+
mesh.add_attribute("vertex_nx")
|
| 39 |
+
mesh.set_attribute("vertex_nx", n1)
|
| 40 |
+
mesh.add_attribute("vertex_ny")
|
| 41 |
+
mesh.set_attribute("vertex_ny", n2)
|
| 42 |
+
mesh.add_attribute("vertex_nz")
|
| 43 |
+
mesh.set_attribute("vertex_nz", n3)
|
| 44 |
+
if charges is not None:
|
| 45 |
+
mesh.add_attribute("charge")
|
| 46 |
+
if normalize_charges:
|
| 47 |
+
charges = charges / 10
|
| 48 |
+
mesh.set_attribute("charge", charges)
|
| 49 |
+
if hbond is not None:
|
| 50 |
+
mesh.add_attribute("hbond")
|
| 51 |
+
mesh.set_attribute("hbond", hbond)
|
| 52 |
+
if vertex_cb is not None:
|
| 53 |
+
mesh.add_attribute("vertex_cb")
|
| 54 |
+
mesh.set_attribute("vertex_cb", vertex_cb)
|
| 55 |
+
if hphob is not None:
|
| 56 |
+
mesh.add_attribute("vertex_hphob")
|
| 57 |
+
mesh.set_attribute("vertex_hphob", hphob)
|
| 58 |
+
if iface is not None:
|
| 59 |
+
mesh.add_attribute("vertex_iface")
|
| 60 |
+
mesh.set_attribute("vertex_iface", iface)
|
| 61 |
+
if si is not None:
|
| 62 |
+
mesh.add_attribute("vertex_si")
|
| 63 |
+
mesh.set_attribute("vertex_si", si)
|
| 64 |
+
|
| 65 |
+
pymesh.save_mesh(
|
| 66 |
+
filename, mesh, *mesh.get_attribute_names(), use_float=True, ascii=True
|
| 67 |
+
)
|
| 68 |
+
|
model/comp_surface/prepare_target/triangulation/README.md
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
### source/triangulation
|
| 2 |
+
Functions used by MaSIF to triangulate proteins (through MSMS), regularize these meshes, and compute chemical charges.
|
| 3 |
+
|
| 4 |
+
+ *computeAPBS.py*: Wrapper function to compute the Poisson Boltzmann electrostatics for a surface using APBS.
|
| 5 |
+
+ *computeCharges.py*: Compute the free electrons/protons in the surface.
|
| 6 |
+
+ *computeHydrophobicity.py*: Compute the hydrophobicity of each vertex.
|
| 7 |
+
+ *computeMSMS.py*: Compute the MSMS surface of a protein.
|
| 8 |
+
+ *compute_normal.py*: Compute the normals of the surface.
|
| 9 |
+
+ *fixmesh.py*: Regularize an MSMS mesh
|
| 10 |
+
+ *xyzrn.py*: Output a PDB in the input format used by MSMS
|
| 11 |
+
|
| 12 |
+
|
model/comp_surface/prepare_target/triangulation/__init__.py
ADDED
|
File without changes
|
model/comp_surface/prepare_target/triangulation/computeAPBS.py
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import numpy
|
| 3 |
+
from subprocess import Popen, PIPE
|
| 4 |
+
import pymesh
|
| 5 |
+
|
| 6 |
+
from default_config.global_vars import apbs_bin, pdb2pqr_bin, multivalue_bin
|
| 7 |
+
import random
|
| 8 |
+
|
| 9 |
+
"""
|
| 10 |
+
computeAPBS.py: Wrapper function to compute the Poisson Boltzmann electrostatics for a surface using APBS.
|
| 11 |
+
Pablo Gainza - LPDI STI EPFL 2019
|
| 12 |
+
This file is part of MaSIF.
|
| 13 |
+
Released under an Apache License 2.0
|
| 14 |
+
"""
|
| 15 |
+
|
| 16 |
+
def computeAPBS(vertices, pdb_file, tmp_file_base):
|
| 17 |
+
"""
|
| 18 |
+
Calls APBS, pdb2pqr, and multivalue and returns the charges per vertex
|
| 19 |
+
"""
|
| 20 |
+
fields = tmp_file_base.split("/")[0:-1]
|
| 21 |
+
directory = "/".join(fields) + "/"
|
| 22 |
+
filename_base = tmp_file_base.split("/")[-1]
|
| 23 |
+
pdbname = pdb_file.split("/")[-1]
|
| 24 |
+
args = [
|
| 25 |
+
pdb2pqr_bin,
|
| 26 |
+
"--ff=parse",
|
| 27 |
+
"--whitespace",
|
| 28 |
+
"--noopt",
|
| 29 |
+
"--apbs-input",
|
| 30 |
+
pdbname,
|
| 31 |
+
filename_base,
|
| 32 |
+
]
|
| 33 |
+
p2 = Popen(args, stdout=PIPE, stderr=PIPE, cwd=directory)
|
| 34 |
+
stdout, stderr = p2.communicate()
|
| 35 |
+
|
| 36 |
+
args = [apbs_bin, filename_base + ".in"]
|
| 37 |
+
p2 = Popen(args, stdout=PIPE, stderr=PIPE, cwd=directory)
|
| 38 |
+
stdout, stderr = p2.communicate()
|
| 39 |
+
|
| 40 |
+
vertfile = open(directory + "/" + filename_base + ".csv", "w")
|
| 41 |
+
for vert in vertices:
|
| 42 |
+
vertfile.write("{},{},{}\n".format(vert[0], vert[1], vert[2]))
|
| 43 |
+
vertfile.close()
|
| 44 |
+
|
| 45 |
+
args = [
|
| 46 |
+
multivalue_bin,
|
| 47 |
+
filename_base + ".csv",
|
| 48 |
+
filename_base + ".dx",
|
| 49 |
+
filename_base + "_out.csv",
|
| 50 |
+
]
|
| 51 |
+
p2 = Popen(args, stdout=PIPE, stderr=PIPE, cwd=directory)
|
| 52 |
+
stdout, stderr = p2.communicate()
|
| 53 |
+
|
| 54 |
+
# Read the charge file
|
| 55 |
+
chargefile = open(tmp_file_base + "_out.csv")
|
| 56 |
+
charges = numpy.array([0.0] * len(vertices))
|
| 57 |
+
for ix, line in enumerate(chargefile.readlines()):
|
| 58 |
+
charges[ix] = float(line.split(",")[3])
|
| 59 |
+
|
| 60 |
+
remove_fn = os.path.join(directory, filename_base)
|
| 61 |
+
os.remove(remove_fn)
|
| 62 |
+
os.remove(remove_fn+'.csv')
|
| 63 |
+
os.remove(remove_fn+'.dx')
|
| 64 |
+
os.remove(remove_fn+'.in')
|
| 65 |
+
os.remove(remove_fn+'-input.p')
|
| 66 |
+
os.remove(remove_fn+'_out.csv')
|
| 67 |
+
|
| 68 |
+
return charges
|
model/comp_surface/prepare_target/triangulation/computeCharges.py
ADDED
|
@@ -0,0 +1,215 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from Bio.PDB import *
|
| 2 |
+
import numpy as np
|
| 3 |
+
from sklearn.neighbors import KDTree
|
| 4 |
+
|
| 5 |
+
"""
|
| 6 |
+
computeCharges.py: Wrapper function to compute hydrogen bond potential (free electrons/protons) in the surface
|
| 7 |
+
Pablo Gainza - LPDI STI EPFL 2019
|
| 8 |
+
This file is part of MaSIF.
|
| 9 |
+
Released under an Apache License 2.0
|
| 10 |
+
"""
|
| 11 |
+
|
| 12 |
+
from default_config.chemistry import (
|
| 13 |
+
polarHydrogens,
|
| 14 |
+
radii,
|
| 15 |
+
acceptorAngleAtom,
|
| 16 |
+
acceptorPlaneAtom,
|
| 17 |
+
hbond_std_dev,
|
| 18 |
+
donorAtom,
|
| 19 |
+
)
|
| 20 |
+
|
| 21 |
+
# Compute vertex charges based on hydrogen bond potential.
|
| 22 |
+
# pdb_filename: The filename of the protonated protein.
|
| 23 |
+
# vertices: The surface vertices of the protonated protein
|
| 24 |
+
# The name of each vertex in the format, example: B_125_x_ASN_ND2_Green
|
| 25 |
+
# where B is chain, 125 res id, x the insertion, ASN aatype, ND2 the name of the
|
| 26 |
+
# atom, and green is not used anymore.
|
| 27 |
+
def computeCharges(pdb_filename, vertices, names):
|
| 28 |
+
parser = PDBParser(QUIET=True)
|
| 29 |
+
struct = parser.get_structure(pdb_filename, pdb_filename + ".pdb")
|
| 30 |
+
residues = {}
|
| 31 |
+
for res in struct.get_residues():
|
| 32 |
+
chain_id = res.get_parent().get_id()
|
| 33 |
+
if chain_id == "":
|
| 34 |
+
chain_id = " "
|
| 35 |
+
residues[(chain_id, res.get_id())] = res
|
| 36 |
+
|
| 37 |
+
atoms = Selection.unfold_entities(struct, "A")
|
| 38 |
+
satisfied_CO, satisfied_HN = computeSatisfied_CO_HN(atoms)
|
| 39 |
+
|
| 40 |
+
charge = np.array([0.0] * len(vertices))
|
| 41 |
+
# Go over every vertex
|
| 42 |
+
for ix, name in enumerate(names):
|
| 43 |
+
fields = name.split("_")
|
| 44 |
+
chain_id = fields[0]
|
| 45 |
+
if chain_id == "":
|
| 46 |
+
chain_id = " "
|
| 47 |
+
if fields[2] == "x":
|
| 48 |
+
fields[2] = " "
|
| 49 |
+
res_id = (" ", int(fields[1]), fields[2])
|
| 50 |
+
aa = fields[3]
|
| 51 |
+
atom_name = fields[4]
|
| 52 |
+
# Ignore atom if it is BB and it is already satisfied.
|
| 53 |
+
if atom_name == "H" and res_id in satisfied_HN:
|
| 54 |
+
continue
|
| 55 |
+
if atom_name == "O" and res_id in satisfied_CO:
|
| 56 |
+
continue
|
| 57 |
+
# Compute the charge of the vertex
|
| 58 |
+
charge[ix] = computeChargeHelper(
|
| 59 |
+
atom_name, residues[(chain_id, res_id)], vertices[ix]
|
| 60 |
+
)
|
| 61 |
+
|
| 62 |
+
return charge
|
| 63 |
+
|
| 64 |
+
|
| 65 |
+
# Compute the charge of a vertex in a residue.
|
| 66 |
+
def computeChargeHelper(atom_name, res, v):
|
| 67 |
+
res_type = res.get_resname()
|
| 68 |
+
# Check if it is a polar hydrogen.
|
| 69 |
+
if isPolarHydrogen(atom_name, res):
|
| 70 |
+
donor_atom_name = donorAtom[atom_name]
|
| 71 |
+
a = res[donor_atom_name].get_coord() # N/O
|
| 72 |
+
b = res[atom_name].get_coord() # H
|
| 73 |
+
# Donor-H is always 180.0 degrees, = pi
|
| 74 |
+
angle_deviation = computeAngleDeviation(a, b, v, np.pi)
|
| 75 |
+
angle_penalty = computeAnglePenalty(angle_deviation)
|
| 76 |
+
return 1.0 * angle_penalty
|
| 77 |
+
# Check if it is an acceptor oxygen or nitrogen
|
| 78 |
+
elif isAcceptorAtom(atom_name, res):
|
| 79 |
+
acceptor_atom = res[atom_name]
|
| 80 |
+
b = acceptor_atom.get_coord()
|
| 81 |
+
try:
|
| 82 |
+
a = res[acceptorAngleAtom[atom_name]].get_coord()
|
| 83 |
+
except:
|
| 84 |
+
return 0.0
|
| 85 |
+
# 120 degress for acceptor
|
| 86 |
+
angle_deviation = computeAngleDeviation(a, b, v, 2 * np.pi / 3)
|
| 87 |
+
# TODO: This should not be 120 for all atoms, i.e. for HIS it should be
|
| 88 |
+
# ~125.0
|
| 89 |
+
angle_penalty = computeAnglePenalty(angle_deviation)
|
| 90 |
+
plane_penalty = 1.0
|
| 91 |
+
if atom_name in acceptorPlaneAtom:
|
| 92 |
+
try:
|
| 93 |
+
d = res[acceptorPlaneAtom[atom_name]].get_coord()
|
| 94 |
+
except:
|
| 95 |
+
return 0.0
|
| 96 |
+
plane_deviation = computePlaneDeviation(d, a, b, v)
|
| 97 |
+
plane_penalty = computeAnglePenalty(plane_deviation)
|
| 98 |
+
return -1.0 * angle_penalty * plane_penalty
|
| 99 |
+
# Compute the
|
| 100 |
+
return 0.0
|
| 101 |
+
|
| 102 |
+
|
| 103 |
+
# Compute the absolute value of the deviation from theta
|
| 104 |
+
def computeAngleDeviation(a, b, c, theta):
|
| 105 |
+
return abs(calc_angle(Vector(a), Vector(b), Vector(c)) - theta)
|
| 106 |
+
|
| 107 |
+
|
| 108 |
+
# Compute the angle deviation from a plane
|
| 109 |
+
def computePlaneDeviation(a, b, c, d):
|
| 110 |
+
dih = calc_dihedral(Vector(a), Vector(b), Vector(c), Vector(d))
|
| 111 |
+
dev1 = abs(dih)
|
| 112 |
+
dev2 = np.pi - abs(dih)
|
| 113 |
+
return min(dev1, dev2)
|
| 114 |
+
|
| 115 |
+
|
| 116 |
+
# angle_deviation from ideal value. TODO: do a more data-based solution
|
| 117 |
+
def computeAnglePenalty(angle_deviation):
|
| 118 |
+
# Standard deviation: hbond_std_dev
|
| 119 |
+
return max(0.0, 1.0 - (angle_deviation / (hbond_std_dev)) ** 2)
|
| 120 |
+
|
| 121 |
+
|
| 122 |
+
def isPolarHydrogen(atom_name, res):
|
| 123 |
+
if atom_name in polarHydrogens[res.get_resname()]:
|
| 124 |
+
return True
|
| 125 |
+
else:
|
| 126 |
+
return False
|
| 127 |
+
|
| 128 |
+
|
| 129 |
+
def isAcceptorAtom(atom_name, res):
|
| 130 |
+
if atom_name.startswith("O"):
|
| 131 |
+
return True
|
| 132 |
+
else:
|
| 133 |
+
if res.get_resname() == "HIS":
|
| 134 |
+
if atom_name == "ND1" and "HD1" not in res:
|
| 135 |
+
return True
|
| 136 |
+
if atom_name == "NE2" and "HE2" not in res:
|
| 137 |
+
return True
|
| 138 |
+
return False
|
| 139 |
+
|
| 140 |
+
|
| 141 |
+
# Compute the list of backbone C=O:H-N that are satisfied. These will be ignored.
|
| 142 |
+
def computeSatisfied_CO_HN(atoms):
|
| 143 |
+
ns = NeighborSearch(atoms)
|
| 144 |
+
satisfied_CO = set()
|
| 145 |
+
satisfied_HN = set()
|
| 146 |
+
for atom1 in atoms:
|
| 147 |
+
res1 = atom1.get_parent()
|
| 148 |
+
if atom1.get_id() == "O":
|
| 149 |
+
neigh_atoms = ns.search(atom1.get_coord(), 2.5, level="A")
|
| 150 |
+
for atom2 in neigh_atoms:
|
| 151 |
+
if atom2.get_id() == "H":
|
| 152 |
+
res2 = atom2.get_parent()
|
| 153 |
+
# Ensure they belong to different residues.
|
| 154 |
+
if res2.get_id() != res1.get_id():
|
| 155 |
+
# Compute the angle N-H:O, ideal value is 180 (but in
|
| 156 |
+
# helices it is typically 160) 180 +-30 = pi
|
| 157 |
+
angle_N_H_O_dev = computeAngleDeviation(
|
| 158 |
+
res2["N"].get_coord(),
|
| 159 |
+
atom2.get_coord(),
|
| 160 |
+
atom1.get_coord(),
|
| 161 |
+
np.pi,
|
| 162 |
+
)
|
| 163 |
+
# Compute angle H:O=C, ideal value is ~160 +- 20 = 8*pi/9
|
| 164 |
+
angle_H_O_C_dev = computeAngleDeviation(
|
| 165 |
+
atom2.get_coord(),
|
| 166 |
+
atom1.get_coord(),
|
| 167 |
+
res1["C"].get_coord(),
|
| 168 |
+
8 * np.pi / 9,
|
| 169 |
+
)
|
| 170 |
+
## Allowed deviations: 30 degrees (pi/6) and 20 degrees
|
| 171 |
+
# (pi/9)
|
| 172 |
+
if (
|
| 173 |
+
angle_N_H_O_dev - np.pi / 6 < 0
|
| 174 |
+
and angle_H_O_C_dev - np.pi / 9 < 0.0
|
| 175 |
+
):
|
| 176 |
+
satisfied_CO.add(res1.get_id())
|
| 177 |
+
satisfied_HN.add(res2.get_id())
|
| 178 |
+
return satisfied_CO, satisfied_HN
|
| 179 |
+
|
| 180 |
+
|
| 181 |
+
# Compute the charge of a new mesh, based on the charge of an old mesh.
|
| 182 |
+
# Use the top vertex in distance, for now (later this should be smoothed over 3
|
| 183 |
+
# or 4 vertices)
|
| 184 |
+
def assignChargesToNewMesh(new_vertices, old_vertices, old_charges, seeder_opts):
|
| 185 |
+
dataset = old_vertices
|
| 186 |
+
testset = new_vertices
|
| 187 |
+
new_charges = np.zeros(len(new_vertices))
|
| 188 |
+
if seeder_opts["feature_interpolation"]:
|
| 189 |
+
num_inter = 4 # Number of interpolation features
|
| 190 |
+
# Assign k old vertices to each new vertex.
|
| 191 |
+
kdt = KDTree(dataset)
|
| 192 |
+
dists, result = kdt.query(testset, k=num_inter)
|
| 193 |
+
# Square the distances (as in the original pyflann)
|
| 194 |
+
dists = np.square(dists)
|
| 195 |
+
# The size of result is the same as new_vertices
|
| 196 |
+
for vi_new in range(len(result)):
|
| 197 |
+
vi_old = result[vi_new]
|
| 198 |
+
dist_old = dists[vi_new]
|
| 199 |
+
# If one vertex is right on top, ignore the rest.
|
| 200 |
+
if dist_old[0] == 0.0:
|
| 201 |
+
new_charges[vi_new] = old_charges[vi_old[0]]
|
| 202 |
+
continue
|
| 203 |
+
|
| 204 |
+
total_dist = np.sum(1 / dist_old)
|
| 205 |
+
for i in range(num_inter):
|
| 206 |
+
new_charges[vi_new] += (
|
| 207 |
+
old_charges[vi_old[i]] * (1 / dist_old[i]) / total_dist
|
| 208 |
+
)
|
| 209 |
+
else:
|
| 210 |
+
# Assign k old vertices to each new vertex.
|
| 211 |
+
kdt = KDTree(dataset)
|
| 212 |
+
dists, result = kdt.query(testset)
|
| 213 |
+
new_charges = old_charges[result]
|
| 214 |
+
return new_charges
|
| 215 |
+
|
model/comp_surface/prepare_target/triangulation/computeHydrophobicity.py
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import numpy as np
|
| 2 |
+
|
| 3 |
+
# Kyte Doolittle scale
|
| 4 |
+
kd_scale = {}
|
| 5 |
+
kd_scale["ILE"] = 4.5
|
| 6 |
+
kd_scale["VAL"] = 4.2
|
| 7 |
+
kd_scale["LEU"] = 3.8
|
| 8 |
+
kd_scale["PHE"] = 2.8
|
| 9 |
+
kd_scale["CYS"] = 2.5
|
| 10 |
+
kd_scale["MET"] = 1.9
|
| 11 |
+
kd_scale["ALA"] = 1.8
|
| 12 |
+
kd_scale["GLY"] = -0.4
|
| 13 |
+
kd_scale["THR"] = -0.7
|
| 14 |
+
kd_scale["SER"] = -0.8
|
| 15 |
+
kd_scale["TRP"] = -0.9
|
| 16 |
+
kd_scale["TYR"] = -1.3
|
| 17 |
+
kd_scale["PRO"] = -1.6
|
| 18 |
+
kd_scale["HIS"] = -3.2
|
| 19 |
+
kd_scale["GLU"] = -3.5
|
| 20 |
+
kd_scale["GLN"] = -3.5
|
| 21 |
+
kd_scale["ASP"] = -3.5
|
| 22 |
+
kd_scale["ASN"] = -3.5
|
| 23 |
+
kd_scale["LYS"] = -3.9
|
| 24 |
+
kd_scale["ARG"] = -4.5
|
| 25 |
+
|
| 26 |
+
# For each vertex in names, compute
|
| 27 |
+
def computeHydrophobicity(names):
|
| 28 |
+
hp = np.zeros(len(names))
|
| 29 |
+
for ix, name in enumerate(names):
|
| 30 |
+
aa = name.split("_")[3]
|
| 31 |
+
hp[ix] = kd_scale[aa]
|
| 32 |
+
return hp
|
| 33 |
+
|
model/comp_surface/prepare_target/triangulation/computeMSMS.py
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
from subprocess import Popen, PIPE
|
| 3 |
+
|
| 4 |
+
from input_output.read_msms import read_msms
|
| 5 |
+
from triangulation.xyzrn import output_pdb_as_xyzrn
|
| 6 |
+
from default_config.global_vars import msms_bin
|
| 7 |
+
from default_config.masif_opts import masif_opts
|
| 8 |
+
import random
|
| 9 |
+
|
| 10 |
+
# Pablo Gainza LPDI EPFL 2017-2019
|
| 11 |
+
# Calls MSMS and returns the vertices.
|
| 12 |
+
# Special atoms are atoms with a reduced radius.
|
| 13 |
+
def computeMSMS(pdb_file, protonate=True):
|
| 14 |
+
randnum = random.randint(1,10000000)
|
| 15 |
+
file_base = masif_opts['tmp_dir']+"/msms_"+str(randnum)
|
| 16 |
+
out_xyzrn = file_base+".xyzrn"
|
| 17 |
+
|
| 18 |
+
if protonate:
|
| 19 |
+
output_pdb_as_xyzrn(pdb_file, out_xyzrn)
|
| 20 |
+
else:
|
| 21 |
+
print("Error - pdb2xyzrn is deprecated.")
|
| 22 |
+
sys.exit(1)
|
| 23 |
+
# Now run MSMS on xyzrn file
|
| 24 |
+
FNULL = open(os.devnull, 'w')
|
| 25 |
+
args = [msms_bin, "-density", "3.0", "-hdensity", "3.0", "-probe",\
|
| 26 |
+
"1.5", "-if",out_xyzrn,"-of",file_base, "-af", file_base]
|
| 27 |
+
#print msms_bin+" "+`args`
|
| 28 |
+
p2 = Popen(args, stdout=PIPE, stderr=PIPE)
|
| 29 |
+
stdout, stderr = p2.communicate()
|
| 30 |
+
|
| 31 |
+
vertices, faces, normals, names = read_msms(file_base)
|
| 32 |
+
areas = {}
|
| 33 |
+
ses_file = open(file_base+".area")
|
| 34 |
+
next(ses_file) # ignore header line
|
| 35 |
+
for line in ses_file:
|
| 36 |
+
fields = line.split()
|
| 37 |
+
areas[fields[3]] = fields[1]
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
# Remove temporary files.
|
| 41 |
+
os.remove(file_base+'.area')
|
| 42 |
+
os.remove(file_base+'.xyzrn')
|
| 43 |
+
os.remove(file_base+'.vert')
|
| 44 |
+
os.remove(file_base+'.face')
|
| 45 |
+
return vertices, faces, normals, names, areas
|
| 46 |
+
|
model/comp_surface/prepare_target/triangulation/compute_normal.py
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import numpy as np
|
| 2 |
+
from numpy.matlib import repmat
|
| 3 |
+
"""
|
| 4 |
+
compute_normal.py: Compute the normals of a closed shape.
|
| 5 |
+
Pablo Gainza - LPDI STI EPFL 2019
|
| 6 |
+
This file is part of MaSIF, based on previous matlab code by Gabriel Peyre, converted to Python by Pablo Gainza
|
| 7 |
+
"""
|
| 8 |
+
|
| 9 |
+
###
|
| 10 |
+
from default_config.global_vars import epsilon as eps
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
def compute_normal(vertex, face):
|
| 14 |
+
|
| 15 |
+
"""
|
| 16 |
+
compute_normal - compute the normal of a triangulation
|
| 17 |
+
vertex: 3xn matrix of vertices
|
| 18 |
+
face: 3xm matrix of face indices.
|
| 19 |
+
|
| 20 |
+
normal,normalf = compute_normal(vertex,face)
|
| 21 |
+
|
| 22 |
+
normal(i,:) is the normal at vertex i.
|
| 23 |
+
normalf(j,:) is the normal at face j.
|
| 24 |
+
|
| 25 |
+
Copyright (c) 2004 Gabriel Peyr
|
| 26 |
+
Converted to Python by Pablo Gainza LPDI EPFL 2017
|
| 27 |
+
"""
|
| 28 |
+
|
| 29 |
+
vertex = vertex.T
|
| 30 |
+
face = face.T
|
| 31 |
+
nface = np.size(face, 1)
|
| 32 |
+
nvert = np.size(vertex, 1)
|
| 33 |
+
normal = np.zeros((3, nvert))
|
| 34 |
+
# unit normals to the faces
|
| 35 |
+
normalf = crossp(
|
| 36 |
+
vertex[:, face[1, :]] - vertex[:, face[0, :]],
|
| 37 |
+
vertex[:, face[2, :]] - vertex[:, face[0, :]],
|
| 38 |
+
)
|
| 39 |
+
sum_squares = np.sum(normalf ** 2, 0)
|
| 40 |
+
d = np.sqrt(sum_squares)
|
| 41 |
+
d[d < eps] = 1
|
| 42 |
+
normalf = normalf / repmat(d, 3, 1)
|
| 43 |
+
# unit normal to the vertex
|
| 44 |
+
normal = np.zeros((3, nvert))
|
| 45 |
+
for i in np.arange(0, nface):
|
| 46 |
+
f = face[:, i]
|
| 47 |
+
for j in np.arange(3):
|
| 48 |
+
normal[:, f[j]] = normal[:, f[j]] + normalf[:, i]
|
| 49 |
+
|
| 50 |
+
# normalize
|
| 51 |
+
d = np.sqrt(np.sum(normal ** 2, 0))
|
| 52 |
+
d[d < eps] = 1
|
| 53 |
+
normal = normal / repmat(d, 3, 1)
|
| 54 |
+
# enforce that the normal are outward
|
| 55 |
+
vertex_means = np.mean(vertex, 0)
|
| 56 |
+
v = vertex - repmat(vertex_means, 3, 1)
|
| 57 |
+
s = np.sum(np.multiply(v, normal), 1)
|
| 58 |
+
if np.sum(s > 0) < np.sum(s < 0):
|
| 59 |
+
# flip
|
| 60 |
+
normal = -normal
|
| 61 |
+
normalf = -normalf
|
| 62 |
+
return normal.T
|
| 63 |
+
|
| 64 |
+
|
| 65 |
+
def crossp(x, y):
|
| 66 |
+
|
| 67 |
+
# x and y are (m,3) dimensional
|
| 68 |
+
z = np.zeros((x.shape))
|
| 69 |
+
z[0, :] = np.multiply(x[1, :], y[2, :]) - np.multiply(x[2, :], y[1, :])
|
| 70 |
+
z[1, :] = np.multiply(x[2, :], y[0, :]) - np.multiply(x[0, :], y[2, :])
|
| 71 |
+
z[2, :] = np.multiply(x[0, :], y[1, :]) - np.multiply(x[1, :], y[0, :])
|
| 72 |
+
return z
|
model/comp_surface/prepare_target/triangulation/fixmesh.py
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import numpy as np
|
| 2 |
+
from numpy.linalg import norm
|
| 3 |
+
import pymesh
|
| 4 |
+
|
| 5 |
+
"""
|
| 6 |
+
fixmesh.py: Regularize a protein surface mesh.
|
| 7 |
+
- based on code from the PyMESH documentation.
|
| 8 |
+
"""
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
def fix_mesh(mesh, resolution, detail="normal"):
|
| 12 |
+
bbox_min, bbox_max = mesh.bbox;
|
| 13 |
+
diag_len = norm(bbox_max - bbox_min);
|
| 14 |
+
if detail == "normal":
|
| 15 |
+
target_len = diag_len * 5e-3;
|
| 16 |
+
elif detail == "high":
|
| 17 |
+
target_len = diag_len * 2.5e-3;
|
| 18 |
+
elif detail == "low":
|
| 19 |
+
target_len = diag_len * 1e-2;
|
| 20 |
+
|
| 21 |
+
target_len = resolution
|
| 22 |
+
#print("Target resolution: {} mm".format(target_len));
|
| 23 |
+
# PGC 2017: Remove duplicated vertices first
|
| 24 |
+
mesh, _ = pymesh.remove_duplicated_vertices(mesh, 0.001)
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
count = 0;
|
| 28 |
+
print("Removing degenerated triangles")
|
| 29 |
+
mesh, __ = pymesh.remove_degenerated_triangles(mesh, 100);
|
| 30 |
+
mesh, __ = pymesh.split_long_edges(mesh, target_len);
|
| 31 |
+
num_vertices = mesh.num_vertices;
|
| 32 |
+
while True:
|
| 33 |
+
mesh, __ = pymesh.collapse_short_edges(mesh, 1e-6);
|
| 34 |
+
mesh, __ = pymesh.collapse_short_edges(mesh, target_len,
|
| 35 |
+
preserve_feature=True);
|
| 36 |
+
mesh, __ = pymesh.remove_obtuse_triangles(mesh, 150.0, 100);
|
| 37 |
+
if mesh.num_vertices == num_vertices:
|
| 38 |
+
break;
|
| 39 |
+
|
| 40 |
+
num_vertices = mesh.num_vertices;
|
| 41 |
+
#print("#v: {}".format(num_vertices));
|
| 42 |
+
count += 1;
|
| 43 |
+
if count > 10: break;
|
| 44 |
+
|
| 45 |
+
mesh = pymesh.resolve_self_intersection(mesh);
|
| 46 |
+
mesh, __ = pymesh.remove_duplicated_faces(mesh);
|
| 47 |
+
mesh = pymesh.compute_outer_hull(mesh);
|
| 48 |
+
mesh, __ = pymesh.remove_duplicated_faces(mesh);
|
| 49 |
+
mesh, __ = pymesh.remove_obtuse_triangles(mesh, 179.0, 5);
|
| 50 |
+
mesh, __ = pymesh.remove_isolated_vertices(mesh);
|
| 51 |
+
mesh, _ = pymesh.remove_duplicated_vertices(mesh, 0.001)
|
| 52 |
+
|
| 53 |
+
return mesh
|
model/comp_surface/prepare_target/triangulation/xyzrn.py
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from Bio.PDB import *
|
| 2 |
+
from default_config.chemistry import radii, polarHydrogens
|
| 3 |
+
|
| 4 |
+
"""
|
| 5 |
+
xyzrn.py: Read a pdb file and output it is in xyzrn for use in MSMS
|
| 6 |
+
Pablo Gainza - LPDI STI EPFL 2019
|
| 7 |
+
This file is part of MaSIF.
|
| 8 |
+
Released under an Apache License 2.0
|
| 9 |
+
"""
|
| 10 |
+
|
| 11 |
+
def output_pdb_as_xyzrn(pdbfilename, xyzrnfilename):
|
| 12 |
+
"""
|
| 13 |
+
pdbfilename: input pdb filename
|
| 14 |
+
xyzrnfilename: output in xyzrn format.
|
| 15 |
+
"""
|
| 16 |
+
parser = PDBParser()
|
| 17 |
+
struct = parser.get_structure(pdbfilename, pdbfilename)
|
| 18 |
+
outfile = open(xyzrnfilename, "w")
|
| 19 |
+
for atom in struct.get_atoms():
|
| 20 |
+
name = atom.get_name()
|
| 21 |
+
residue = atom.get_parent()
|
| 22 |
+
# Ignore hetatms.
|
| 23 |
+
if residue.get_id()[0] != " ":
|
| 24 |
+
continue
|
| 25 |
+
resname = residue.get_resname()
|
| 26 |
+
reskey = residue.get_id()[1]
|
| 27 |
+
chain = residue.get_parent().get_id()
|
| 28 |
+
atomtype = name[0]
|
| 29 |
+
|
| 30 |
+
color = "Green"
|
| 31 |
+
coords = None
|
| 32 |
+
if atomtype in radii and resname in polarHydrogens:
|
| 33 |
+
if atomtype == "O":
|
| 34 |
+
color = "Red"
|
| 35 |
+
if atomtype == "N":
|
| 36 |
+
color = "Blue"
|
| 37 |
+
if atomtype == "H":
|
| 38 |
+
if name in polarHydrogens[resname]:
|
| 39 |
+
color = "Blue" # Polar hydrogens
|
| 40 |
+
coords = "{:.06f} {:.06f} {:.06f}".format(
|
| 41 |
+
atom.get_coord()[0], atom.get_coord()[1], atom.get_coord()[2]
|
| 42 |
+
)
|
| 43 |
+
insertion = "x"
|
| 44 |
+
if residue.get_id()[2] != " ":
|
| 45 |
+
insertion = residue.get_id()[2]
|
| 46 |
+
full_id = "{}_{:d}_{}_{}_{}_{}".format(
|
| 47 |
+
chain, residue.get_id()[1], insertion, resname, name, color
|
| 48 |
+
)
|
| 49 |
+
if coords is not None:
|
| 50 |
+
outfile.write(coords + " " + radii[atomtype] + " 1 " + full_id + "\n")
|
| 51 |
+
|
model/comp_surface/protein_process/openbabel_reduce_openbabel.py
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import subprocess
|
| 3 |
+
import time
|
| 4 |
+
from tqdm import tqdm
|
| 5 |
+
from openbabel import openbabel
|
| 6 |
+
from joblib import Parallel, delayed
|
| 7 |
+
|
| 8 |
+
def process_protein(name, data_path, save_path):
|
| 9 |
+
mol = openbabel.OBMol()
|
| 10 |
+
conv = openbabel.OBConversion()
|
| 11 |
+
conv.SetInAndOutFormats("pdb", "pdb")
|
| 12 |
+
|
| 13 |
+
os.makedirs(os.path.join(save_path, name), exist_ok=True)
|
| 14 |
+
result_path = os.path.join(save_path, name, f'{name}_protein_processed_obabel_reduce_obabel.pdb')
|
| 15 |
+
if os.path.exists(result_path):
|
| 16 |
+
return name
|
| 17 |
+
|
| 18 |
+
# step 1 openbabel
|
| 19 |
+
rec_path = os.path.join(data_path, name, f'{name}_protein_processed.pdb')
|
| 20 |
+
conv.ReadFile(mol, rec_path)
|
| 21 |
+
|
| 22 |
+
out_path = os.path.join(save_path, name, f'{name}_protein_processed_obabel.pdb')
|
| 23 |
+
conv.WriteFile(mol, out_path)
|
| 24 |
+
|
| 25 |
+
# step 2 reduce
|
| 26 |
+
rec_path = os.path.join(save_path, name, f'{name}_protein_processed_obabel.pdb')
|
| 27 |
+
subprocess.run(
|
| 28 |
+
f"reduce -Trim {rec_path} > {os.path.join(save_path, name, f'{name}_protein_processed_obabel_tmp.pdb')}", shell=True)
|
| 29 |
+
|
| 30 |
+
subprocess.run(
|
| 31 |
+
f"reduce -HIS {os.path.join(save_path, name, f'{name}_protein_processed_obabel_tmp.pdb')} > {os.path.join(save_path, name, f'{name}_protein_processed_obabel_reduce.pdb')}", shell=True)
|
| 32 |
+
|
| 33 |
+
subprocess.run(
|
| 34 |
+
f"rm {os.path.join(save_path, name, f'{name}_protein_processed_obabel_tmp.pdb')}",
|
| 35 |
+
shell=True)
|
| 36 |
+
|
| 37 |
+
# step 3 openbabel
|
| 38 |
+
rec_path = os.path.join(save_path, name, f'{name}_protein_processed_obabel_reduce.pdb')
|
| 39 |
+
conv.ReadFile(mol, rec_path)
|
| 40 |
+
|
| 41 |
+
out_path = os.path.join(save_path, name, f'{name}_protein_processed_obabel_reduce_obabel.pdb')
|
| 42 |
+
conv.WriteFile(mol, out_path)
|
| 43 |
+
|
| 44 |
+
return name
|
| 45 |
+
|
| 46 |
+
def main(data_path, save_path, n_jobs):
|
| 47 |
+
start_time = time.time()
|
| 48 |
+
names = sorted(os.listdir(data_path))
|
| 49 |
+
os.makedirs(save_path, exist_ok=True)
|
| 50 |
+
|
| 51 |
+
sucessed_names = Parallel(n_jobs=n_jobs)(
|
| 52 |
+
delayed(process_protein)(name, data_path, save_path) for name in tqdm(names)
|
| 53 |
+
)
|
| 54 |
+
|
| 55 |
+
print("--- %s seconds ---" % (time.time() - start_time))
|
| 56 |
+
print(f"sucessed_names: {list(filter(None, sucessed_names))}")
|
| 57 |
+
|
| 58 |
+
if __name__ == "__main__":
|
| 59 |
+
import argparse
|
| 60 |
+
parser = argparse.ArgumentParser()
|
| 61 |
+
parser.add_argument('--data_path', type=str, default='', help='Path to the data directory')
|
| 62 |
+
parser.add_argument('--save_path', type=str, default='', help='Path to the save directory')
|
| 63 |
+
parser.add_argument('--n_jobs', type=int, default=1, help='Number of parallel jobs (-1 for all CPUs)')
|
| 64 |
+
args = parser.parse_args()
|
| 65 |
+
|
| 66 |
+
if not os.path.exists(args.data_path):
|
| 67 |
+
raise ValueError(f"Data path {args.data_path} does not exist.")
|
| 68 |
+
main(args.data_path, args.save_path, args.n_jobs)
|
model/comp_surface/tools/transfer/APBS-3.4.1.Linux/bin/GeometricFlow
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:4aba4866ec410705f81cdb68fe5474c046b0c237757a50c6aeba012ad1fe3fc7
|
| 3 |
+
size 166208
|
model/comp_surface/tools/transfer/APBS-3.4.1.Linux/bin/GeometricFlowWrap
ADDED
|
Binary file (96.6 kB). View file
|
|
|
model/comp_surface/tools/transfer/APBS-3.4.1.Linux/bin/NanoShaper
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:6d41b6f0ddd400aa5713d08b3a178884bfff4c7ae826530ab73549aa93584baf
|
| 3 |
+
size 3383549
|
model/comp_surface/tools/transfer/APBS-3.4.1.Linux/bin/apbs
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:6ebdacce26e31aa01cd221a534147218088de9d55ff111a1c8bbea56a60a32bd
|
| 3 |
+
size 29850192
|
model/comp_surface/tools/transfer/APBS-3.4.1.Linux/bin/msms
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:739b88d8195b89ee5a9c00ef7b986f6bb9d32f7d3b200f457781c98b95958088
|
| 3 |
+
size 943144
|
model/comp_surface/tools/transfer/APBS-3.4.1.Linux/bin/tabipb
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:2e3b2ef3016982438401896ad0817fda5095b3042dc23a601e4e9e96406e0a9b
|
| 3 |
+
size 149728
|
model/comp_surface/tools/transfer/APBS-3.4.1.Linux/include/apbs.h
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/**
|
| 2 |
+
* @defgroup Header dependencies
|
| 3 |
+
*/
|
| 4 |
+
|
| 5 |
+
/**
|
| 6 |
+
* @file apbs.h
|
| 7 |
+
* @author Nathan Baker
|
| 8 |
+
* @brief Header file for header dependencies
|
| 9 |
+
* @ingroup Frontend
|
| 10 |
+
* @version $Id$
|
| 11 |
+
* @attention
|
| 12 |
+
* @verbatim
|
| 13 |
+
*
|
| 14 |
+
* APBS -- Adaptive Poisson-Boltzmann Solver
|
| 15 |
+
*
|
| 16 |
+
* Nathan A. Baker (nathan.baker@pnnl.gov)
|
| 17 |
+
* Pacific Northwest National Laboratory
|
| 18 |
+
*
|
| 19 |
+
* Additional contributing authors listed in the code documentation.
|
| 20 |
+
*
|
| 21 |
+
* Copyright (c) 2010-2020 Battelle Memorial Institute. Developed at the
|
| 22 |
+
* Pacific Northwest National Laboratory, operated by Battelle Memorial
|
| 23 |
+
* Institute, Pacific Northwest Division for the U.S. Department of Energy.
|
| 24 |
+
*
|
| 25 |
+
* Portions Copyright (c) 2002-2010, Washington University in St. Louis.
|
| 26 |
+
* Portions Copyright (c) 2002-2010, Nathan A. Baker.
|
| 27 |
+
* Portions Copyright (c) 1999-2002, The Regents of the University of
|
| 28 |
+
* California.
|
| 29 |
+
* Portions Copyright (c) 1995, Michael Holst.
|
| 30 |
+
* All rights reserved.
|
| 31 |
+
*
|
| 32 |
+
* Redistribution and use in source and binary forms, with or without
|
| 33 |
+
* modification, are permitted provided that the following conditions are met:
|
| 34 |
+
*
|
| 35 |
+
* Redistributions of source code must retain the above copyright notice, this
|
| 36 |
+
* list of conditions and the following disclaimer.
|
| 37 |
+
*
|
| 38 |
+
* Redistributions in binary form must reproduce the above copyright notice,
|
| 39 |
+
* this list of conditions and the following disclaimer in the documentation
|
| 40 |
+
* and/or other materials provided with the distribution.
|
| 41 |
+
*
|
| 42 |
+
* Neither the name of the developer nor the names of its contributors may be
|
| 43 |
+
* used to endorse or promote products derived from this software without
|
| 44 |
+
* specific prior written permission.
|
| 45 |
+
*
|
| 46 |
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 47 |
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 48 |
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 49 |
+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
| 50 |
+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| 51 |
+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| 52 |
+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| 53 |
+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| 54 |
+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| 55 |
+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
| 56 |
+
* THE POSSIBILITY OF SUCH DAMAGE.
|
| 57 |
+
*
|
| 58 |
+
* @endverbatim
|
| 59 |
+
*/
|
| 60 |
+
|
| 61 |
+
#ifndef _APBSHEADERS_H_
|
| 62 |
+
#define _APBSHEADERS_H_
|
| 63 |
+
|
| 64 |
+
#include "apbscfg.h"
|
| 65 |
+
|
| 66 |
+
/* MALOC headers */
|
| 67 |
+
#include "maloc/maloc.h"
|
| 68 |
+
|
| 69 |
+
/* Generic headers */
|
| 70 |
+
#include "generic/nosh.h"
|
| 71 |
+
#include "generic/mgparm.h"
|
| 72 |
+
#include "generic/pbeparm.h"
|
| 73 |
+
#include "generic/femparm.h"
|
| 74 |
+
#include "generic/bemparm.h"
|
| 75 |
+
#include "generic/geoflowparm.h"
|
| 76 |
+
#include "generic/vacc.h"
|
| 77 |
+
#include "generic/valist.h"
|
| 78 |
+
#include "generic/vatom.h"
|
| 79 |
+
#include "generic/vcap.h"
|
| 80 |
+
#include "generic/vhal.h"
|
| 81 |
+
#include "generic/vpbe.h"
|
| 82 |
+
#include "generic/vstring.h"
|
| 83 |
+
#include "generic/vunit.h"
|
| 84 |
+
#include "generic/vparam.h"
|
| 85 |
+
#include "generic/vgreen.h"
|
| 86 |
+
|
| 87 |
+
//#include "geoflow/cpbconcz2.h"
|
| 88 |
+
|
| 89 |
+
/* MG headers */
|
| 90 |
+
#include "mg/vgrid.h"
|
| 91 |
+
#include "mg/vmgrid.h"
|
| 92 |
+
#include "mg/vopot.h"
|
| 93 |
+
#include "mg/vpmg.h"
|
| 94 |
+
#include "mg/vpmgp.h"
|
| 95 |
+
|
| 96 |
+
/* FEM headers */
|
| 97 |
+
#include "fem/vfetk.h"
|
| 98 |
+
#include "fem/vpee.h"
|
| 99 |
+
|
| 100 |
+
#endif /* _APBSHEADERS_H_ */
|
model/comp_surface/tools/transfer/APBS-3.4.1.Linux/include/apbscfg.h
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// apbs configuration header generated by CMake
|
| 2 |
+
|
| 3 |
+
// apbs version string
|
| 4 |
+
#define PACKAGE_STRING "APBS 3.4.1"
|
| 5 |
+
|
| 6 |
+
// apbs fast mode
|
| 7 |
+
/* #undef APBS_FAST */
|
| 8 |
+
|
| 9 |
+
// apbs debugging mode
|
| 10 |
+
/* #undef DEBUG */
|
| 11 |
+
|
| 12 |
+
// prints verbose debugging information
|
| 13 |
+
#define VERBOSE_DEBUG
|
| 14 |
+
|
| 15 |
+
// apbs quiet mode
|
| 16 |
+
/* #undef VAPBSQUIET */
|
| 17 |
+
|
| 18 |
+
// time function available
|
| 19 |
+
#define HAVE_TIME_FUNC
|
| 20 |
+
|
| 21 |
+
// rand function available
|
| 22 |
+
#define HAVE_RAND_FUNC
|
| 23 |
+
|
| 24 |
+
// srand function available
|
| 25 |
+
#define HAVE_SRAND_FUNC
|
| 26 |
+
|
| 27 |
+
// readline library is available
|
| 28 |
+
/* #undef HAVE_LIBREADLINE */
|
| 29 |
+
|
| 30 |
+
// do not inline functions
|
| 31 |
+
#define APBS_NOINLINE
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
// Is macro embedding availble?
|
| 36 |
+
/* #undef HAVE_EMBED */
|
| 37 |
+
|
| 38 |
+
// zlib compression is available
|
| 39 |
+
/* #undef HAVE_ZLIB */
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
|
| 43 |
+
// have FEtk component PUNC
|
| 44 |
+
#define HAVE_PUNC
|
| 45 |
+
|
| 46 |
+
// have FEtk component MCX
|
| 47 |
+
/* #undef HAVE_MCX */
|
| 48 |
+
|
| 49 |
+
// have FEtk component MC
|
| 50 |
+
#define HAVE_MC
|
| 51 |
+
|
| 52 |
+
// have fetk component GAMER
|
| 53 |
+
#define HAVE_GAMER
|
| 54 |
+
|
| 55 |
+
/* #undef HAVE_MPI_H */
|
| 56 |
+
|
| 57 |
+
// The floating point epsilon for the current machine
|
| 58 |
+
#define FLOAT_EPSILON 2.220446e-16
|
| 59 |
+
|
| 60 |
+
// The double precision epsilon for the current machine
|
| 61 |
+
#define DOUBLE_EPSILON 2.220446e-16
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
|
| 65 |
+
|
| 66 |
+
// Remain for use be determined.
|
| 67 |
+
|
| 68 |
+
/* Define to 1 if you have the <inttypes.h> header file. */
|
| 69 |
+
//#undef HAVE_INTTYPES_H
|
| 70 |
+
|
| 71 |
+
/* Define to 1 if you have the <memory.h> header file. */
|
| 72 |
+
//#undef HAVE_MEMORY_H
|
| 73 |
+
|
| 74 |
+
/* have the MPI library */
|
| 75 |
+
//#undef HAVE_MPI_H
|
| 76 |
+
/* Define to 1 if you have the <stdint.h> header file. */
|
| 77 |
+
//#undef HAVE_STDINT_H
|
| 78 |
+
|
| 79 |
+
/* Define to 1 if you have the <stdlib.h> header file. */
|
| 80 |
+
//#undef HAVE_STDLIB_H
|
| 81 |
+
|
| 82 |
+
/* have machine-supplied strcasecmp */
|
| 83 |
+
//#undef HAVE_STRCASECMP
|
| 84 |
+
|
| 85 |
+
/* Define to 1 if you have the <strings.h> header file. */
|
| 86 |
+
//#undef HAVE_STRINGS_H
|
| 87 |
+
|
| 88 |
+
/* Define to 1 if you have the <string.h> header file. */
|
| 89 |
+
//#undef HAVE_STRING_H
|
| 90 |
+
|
| 91 |
+
/* Define to 1 if you have the <sys/stat.h> header file. */
|
| 92 |
+
//#undef HAVE_SYS_STAT_H
|
| 93 |
+
|
| 94 |
+
/* Define to 1 if you have the <sys/types.h> header file. */
|
| 95 |
+
//#undef HAVE_SYS_TYPES_H
|
| 96 |
+
|
| 97 |
+
/* Define to 1 if you have the <unistd.h> header file. */
|
| 98 |
+
//#undef HAVE_UNISTD_H
|
| 99 |
+
|
| 100 |
+
/* Define to the sub-directory in which libtool stores uninstalled libraries.
|
| 101 |
+
*/
|
| 102 |
+
//#undef LT_OBJDIR
|
| 103 |
+
|
| 104 |
+
/* Name of package */
|
| 105 |
+
//#undef PACKAGE
|
| 106 |
+
|
| 107 |
+
/* Define to the address where bug reports for this package should be sent. */
|
| 108 |
+
//#undef PACKAGE_BUGREPORT
|
| 109 |
+
|
| 110 |
+
/* Define to the full name of this package. */
|
| 111 |
+
//#undef PACKAGE_NAME
|
| 112 |
+
|
| 113 |
+
/* Define to the full name and version of this package. */
|
| 114 |
+
//#undef PACKAGE_STRING
|
| 115 |
+
|
| 116 |
+
/* Define to the one symbol short name of this package. */
|
| 117 |
+
//#undef PACKAGE_TARNAME
|
| 118 |
+
|
| 119 |
+
/* Define to the home page for this package. */
|
| 120 |
+
//#undef PACKAGE_URL
|
| 121 |
+
|
| 122 |
+
/* Define to the version of this package. */
|
| 123 |
+
//#undef PACKAGE_VERSION
|
| 124 |
+
|
| 125 |
+
/* Define to 1 if you have the ANSI C header files. */
|
| 126 |
+
//#undef STDC_HEADERS
|
| 127 |
+
|
| 128 |
+
/* use hierarchical basis method */
|
| 129 |
+
//#undef USE_HB
|
| 130 |
+
|
| 131 |
+
/* Version number of package */
|
| 132 |
+
//#undef VERSION
|