anzhi2710gmailcom commited on
Commit
10f2621
·
verified ·
1 Parent(s): 1155afd

Upload folder using huggingface_hub

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitattributes +31 -34
  2. .gitignore +186 -0
  3. LICENSE +21 -0
  4. README.md +447 -0
  5. conf/params_example/example.yml +146 -0
  6. config.json +17 -0
  7. environment.yaml +434 -0
  8. model/comp_surface/prepare_target/__init_.py +0 -0
  9. model/comp_surface/prepare_target/computeAPBS.py +116 -0
  10. model/comp_surface/prepare_target/computeCharges.py +219 -0
  11. model/comp_surface/prepare_target/computeHydrophobicity.py +39 -0
  12. model/comp_surface/prepare_target/computeMSMS.py +53 -0
  13. model/comp_surface/prepare_target/computeTargetMesh.py +254 -0
  14. model/comp_surface/prepare_target/computeTargetMesh_test_samples.py +262 -0
  15. model/comp_surface/prepare_target/compute_normal.py +78 -0
  16. model/comp_surface/prepare_target/default_config/README.md +3 -0
  17. model/comp_surface/prepare_target/default_config/__init__.py +0 -0
  18. model/comp_surface/prepare_target/default_config/chemistry.py +152 -0
  19. model/comp_surface/prepare_target/default_config/global_vars.py +32 -0
  20. model/comp_surface/prepare_target/default_config/masif_opts.py +83 -0
  21. model/comp_surface/prepare_target/fix_pdb.py +22 -0
  22. model/comp_surface/prepare_target/fixmesh.py +71 -0
  23. model/comp_surface/prepare_target/input_output/README.md +2 -0
  24. model/comp_surface/prepare_target/input_output/__init__.py +0 -0
  25. model/comp_surface/prepare_target/input_output/extractHelix.py +32 -0
  26. model/comp_surface/prepare_target/input_output/extractPDB.py +69 -0
  27. model/comp_surface/prepare_target/input_output/protonate.py +32 -0
  28. model/comp_surface/prepare_target/input_output/read_msms.py +60 -0
  29. model/comp_surface/prepare_target/input_output/read_ply.py +53 -0
  30. model/comp_surface/prepare_target/input_output/save_ply.py +58 -0
  31. model/comp_surface/prepare_target/mol2graph.py +153 -0
  32. model/comp_surface/prepare_target/save_ply.py +68 -0
  33. model/comp_surface/prepare_target/triangulation/README.md +12 -0
  34. model/comp_surface/prepare_target/triangulation/__init__.py +0 -0
  35. model/comp_surface/prepare_target/triangulation/computeAPBS.py +68 -0
  36. model/comp_surface/prepare_target/triangulation/computeCharges.py +215 -0
  37. model/comp_surface/prepare_target/triangulation/computeHydrophobicity.py +33 -0
  38. model/comp_surface/prepare_target/triangulation/computeMSMS.py +46 -0
  39. model/comp_surface/prepare_target/triangulation/compute_normal.py +72 -0
  40. model/comp_surface/prepare_target/triangulation/fixmesh.py +53 -0
  41. model/comp_surface/prepare_target/triangulation/xyzrn.py +51 -0
  42. model/comp_surface/protein_process/openbabel_reduce_openbabel.py +68 -0
  43. model/comp_surface/tools/transfer/APBS-3.4.1.Linux/bin/GeometricFlow +3 -0
  44. model/comp_surface/tools/transfer/APBS-3.4.1.Linux/bin/GeometricFlowWrap +0 -0
  45. model/comp_surface/tools/transfer/APBS-3.4.1.Linux/bin/NanoShaper +3 -0
  46. model/comp_surface/tools/transfer/APBS-3.4.1.Linux/bin/apbs +3 -0
  47. model/comp_surface/tools/transfer/APBS-3.4.1.Linux/bin/msms +3 -0
  48. model/comp_surface/tools/transfer/APBS-3.4.1.Linux/bin/tabipb +3 -0
  49. model/comp_surface/tools/transfer/APBS-3.4.1.Linux/include/apbs.h +100 -0
  50. model/comp_surface/tools/transfer/APBS-3.4.1.Linux/include/apbscfg.h +132 -0
.gitattributes CHANGED
@@ -1,35 +1,32 @@
1
- *.7z filter=lfs diff=lfs merge=lfs -text
2
- *.arrow filter=lfs diff=lfs merge=lfs -text
3
- *.bin filter=lfs diff=lfs merge=lfs -text
4
- *.bz2 filter=lfs diff=lfs merge=lfs -text
5
- *.ckpt filter=lfs diff=lfs merge=lfs -text
6
- *.ftz filter=lfs diff=lfs merge=lfs -text
7
- *.gz filter=lfs diff=lfs merge=lfs -text
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
- *.pth filter=lfs diff=lfs merge=lfs -text
24
- *.rar filter=lfs diff=lfs merge=lfs -text
25
- *.safetensors filter=lfs diff=lfs merge=lfs -text
26
- saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
- *.tar.* filter=lfs diff=lfs merge=lfs -text
28
- *.tar filter=lfs diff=lfs merge=lfs -text
29
- *.tflite filter=lfs diff=lfs merge=lfs -text
30
- *.tgz filter=lfs diff=lfs merge=lfs -text
31
- *.wasm filter=lfs diff=lfs merge=lfs -text
32
- *.xz filter=lfs diff=lfs merge=lfs -text
33
- *.zip filter=lfs diff=lfs merge=lfs -text
34
- *.zst filter=lfs diff=lfs merge=lfs -text
35
- *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
 
 
 
 
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