anzhi2710gmailcom commited on
Commit
96272bc
·
verified ·
1 Parent(s): 15a1e1d

Upload folder using huggingface_hub

Browse files
.gitattributes CHANGED
@@ -1,35 +1,47 @@
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
  *.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
+ *.bin.* filter=lfs diff=lfs merge=lfs -text
5
  *.bz2 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
  *.model filter=lfs diff=lfs merge=lfs -text
12
  *.msgpack filter=lfs diff=lfs merge=lfs -text
 
 
13
  *.onnx filter=lfs diff=lfs merge=lfs -text
14
  *.ot filter=lfs diff=lfs merge=lfs -text
15
  *.parquet filter=lfs diff=lfs merge=lfs -text
16
  *.pb filter=lfs diff=lfs merge=lfs -text
 
 
17
  *.pt filter=lfs diff=lfs merge=lfs -text
18
  *.pth filter=lfs diff=lfs merge=lfs -text
19
  *.rar filter=lfs diff=lfs merge=lfs -text
 
20
  saved_model/**/* filter=lfs diff=lfs merge=lfs -text
21
  *.tar.* filter=lfs diff=lfs merge=lfs -text
 
22
  *.tflite filter=lfs diff=lfs merge=lfs -text
23
  *.tgz filter=lfs diff=lfs merge=lfs -text
 
24
  *.xz filter=lfs diff=lfs merge=lfs -text
25
  *.zip filter=lfs diff=lfs merge=lfs -text
26
+ *.zstandard filter=lfs diff=lfs merge=lfs -text
27
+ *.tfevents* filter=lfs diff=lfs merge=lfs -text
28
+ *.db* filter=lfs diff=lfs merge=lfs -text
29
+ *.ark* filter=lfs diff=lfs merge=lfs -text
30
+ **/*ckpt*data* filter=lfs diff=lfs merge=lfs -text
31
+ **/*ckpt*.meta filter=lfs diff=lfs merge=lfs -text
32
+ **/*ckpt*.index filter=lfs diff=lfs merge=lfs -text
33
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
34
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
35
+ *.gguf* filter=lfs diff=lfs merge=lfs -text
36
+ *.ggml filter=lfs diff=lfs merge=lfs -text
37
+ *.llamafile* filter=lfs diff=lfs merge=lfs -text
38
+ *.pt2 filter=lfs diff=lfs merge=lfs -text
39
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
40
+ *.npy filter=lfs diff=lfs merge=lfs -text
41
+ *.npz filter=lfs diff=lfs merge=lfs -text
42
+ *.pickle filter=lfs diff=lfs merge=lfs -text
43
+ *.pkl filter=lfs diff=lfs merge=lfs -text
44
+ *.tar filter=lfs diff=lfs merge=lfs -text
45
+ *.wasm filter=lfs diff=lfs merge=lfs -text
46
  *.zst filter=lfs diff=lfs merge=lfs -text
47
+ *tfevents* filter=lfs diff=lfs merge=lfs -textconf/fig-overview.png filter=lfs diff=lfs merge=lfs -text
.gitignore ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ output
2
+ output_saturation
3
+ analysis_output
4
+ questions
5
+ ddG-backrub-per_chain.xml
LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) 2018 Kyle Barlow
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,325 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: mit
3
+ language:
4
+ - en
5
+ - zh
6
+ tags:
7
+ - OneScience
8
+ - life-science
9
+ - protein
10
+ - binding-affinity
11
+ - mutation
12
+ - Rosetta
13
+ frameworks: Other
14
+ ---
15
+
16
+ <p align="center">
17
+ <strong>
18
+ <span style="font-size: 30px;">Flex ddG</span>
19
+ </strong>
20
+ </p>
21
+
22
+ # Model Introduction
23
+
24
+ Flex ddG is a Rosetta-based workflow for predicting the effects of mutations at protein-protein interfaces and estimating changes in binding free energy before and after mutation (interface ΔΔG). It uses the Rosetta Backrub protocol to sample local backbone conformations, then performs side-chain repacking, structural minimization, and interface energy calculations for the wild type and mutant to assess how mutations affect protein binding affinity.
25
+
26
+ Paper:
27
+
28
+ > **Flex ddG: Rosetta Ensemble-Based Estimation of Changes in Protein–Protein Binding Affinity upon Mutation**
29
+ > https://doi.org/10.1021/acs.jpcb.7b11367
30
+
31
+ # Model Description
32
+
33
+ Flex ddG is not a model that relies on neural network weights; it is a computational workflow based on the Rosetta energy function and conformational sampling. Inputs typically include a protein complex PDB file, interface chain information, and a Rosetta resfile describing the mutations. The workflow uses Backrub sampling to generate an ensemble of conformations, optimizes and calculates interface energies for the wild type and mutant separately, and ultimately produces ΔΔG.
34
+
35
+ # Use Cases
36
+
37
+ | Use case | Description |
38
+ | --- | --- |
39
+ | Protein-protein interface mutation effect prediction | Predict changes in binding free energy ΔΔG caused by mutations |
40
+ | Interface hotspot residue analysis | Evaluate the effects of mutations at specific sites on binding stability |
41
+ | Single-site saturation mutagenesis scan | Generate all 20 standard amino acid substitutions at a target site and calculate ΔΔG for each |
42
+ | Protein engineering and interface optimization | Help screen for mutations that may enhance or weaken protein interactions |
43
+
44
+ # Usage
45
+
46
+ ## 1. Using OneCode
47
+
48
+ Experience intelligent one-click AI4S programming in the OneCode online environment:
49
+
50
+ [Try intelligent one-click AI4S programming](https://web-2069360198568017922-iaaj.ksai.scnet.cn:58043/home)
51
+
52
+ ## 2. Manual Installation and Usage
53
+
54
+ **Hardware Requirements**
55
+
56
+ - The core computations in Flex ddG are performed by Rosetta CPU programs; the standard workflow does not require a GPU/DCU.
57
+ - The official Python scripts use `multiprocessing` to launch multiple Rosetta instances concurrently. Each Rosetta instance requires approximately 2 GB of memory, so set the concurrency level according to the number of CPU cores and the node's available memory.
58
+
59
+ ### Set Up the Runtime Environment
60
+
61
+ #### DCU Environment
62
+
63
+ ```bash
64
+ # Activate DTK and CONDA first
65
+ conda create -n onescience311 python=3.11 -y
66
+ conda activate onescience311
67
+
68
+ # Install with uv support
69
+ pip install onescience[bio] \
70
+ -i http://mirrors.onescience.ai:3141/pypi/simple/ \
71
+ --trusted-host mirrors.onescience.ai
72
+ ```
73
+
74
+ #### Environment Notes
75
+
76
+ - The core dependency of Flex ddG is **Rosetta**. The main workflow requires the `rosetta_scripts` executable built by Rosetta.
77
+
78
+
79
+ ### Install Rosetta
80
+
81
+ Flex ddG does not require neural network model weights or additional large datasets, but Rosetta must be installed separately.
82
+
83
+ #### 1) Install Rosetta
84
+
85
+ Rosetta must be licensed, downloaded, and installed separately according to the official RosettaCommons instructions:
86
+
87
+ ```text
88
+ https://www.rosettacommons.org/software
89
+ ```
90
+
91
+ The Rosetta license is independent of the MIT License for the Flex ddG tutorial repository. Academic and non-commercial users can apply for a non-commercial license; commercial use requires a separate license.
92
+
93
+ After installation, make sure that at least the following files exist:
94
+
95
+ ```text
96
+ /path/to/rosetta/source/bin/rosetta_scripts
97
+ /path/to/rosetta/source/bin/score_jd2
98
+ ```
99
+
100
+ #### 2) Configure the Rosetta Paths
101
+
102
+ Before running the workflow, update the following line in `scripts/run_example_1.py` and `scripts/run_example_2_saturation.py`:
103
+
104
+ ```python
105
+ rosetta_scripts_path = os.path.expanduser("~/rosetta/source/bin/rosetta_scripts")
106
+ ```
107
+
108
+ To run `scripts/extract_structures.py`, also update `score_jd2_path` in the script to the actual path of the Rosetta `score_jd2` executable.
109
+
110
+ ## 3. Quick Start
111
+
112
+ ### Download the Model Package
113
+
114
+ ```bash
115
+ hf download OneScience-Group/flex_ddG --local-dir ./flex_ddG
116
+ cd flex_ddG
117
+ ```
118
+
119
+ - Flex ddG **additionally depends on Rosetta**. Rosetta is not included in this model repository; first apply for a license and install Rosetta as described in "Install Rosetta", then configure `rosetta_scripts_path`.
120
+ - To extract PDB structures from `struct.db3`, you also need to configure the path to Rosetta's `score_jd2` executable.
121
+ - The default parameters in this document are intended only for quick functional verification and do not represent parameters for production scientific calculations.
122
+
123
+ ### Quick Verification
124
+
125
+ First, verify that the Rosetta executable is available:
126
+
127
+ ```bash
128
+ /path/to/rosetta/source/bin/rosetta_scripts -help
129
+ ```
130
+
131
+ Run the official example:
132
+
133
+ ```bash
134
+ python scripts/run_example_1.py
135
+ ```
136
+
137
+ On success, the following directory will be generated:
138
+
139
+ ```text
140
+ output/
141
+ ```
142
+
143
+ # Example Data
144
+
145
+ The official example directory is:
146
+
147
+ ```text
148
+ scripts/inputs/
149
+ └── 1JTG/
150
+ ├── 1JTG_AB.pdb
151
+ ├── chains_to_move.txt
152
+ ├── nataa_mutations.resfile
153
+ ├── mutations.resfile
154
+ ├── mutations.mutfile
155
+ ├── pdb2rosetta.resmap.json
156
+ └── rosetta2pdb.resmap.json
157
+ ```
158
+
159
+ The files are:
160
+
161
+ | File | Description |
162
+ | --- | --- |
163
+ | `1JTG_AB.pdb` | Protein complex structure |
164
+ | `chains_to_move.txt` | Defines the chain that moves as one side of the interface during calculations |
165
+ | `nataa_mutations.resfile` | The mutation resfile used by Flex ddG |
166
+ | `mutations.resfile` | Example mutation configuration |
167
+ | `mutations.mutfile` | Example mutation information |
168
+
169
+ The resfile used by Flex ddG must begin with `NATAA`. The official scripts explicitly state that it should not be replaced with `NATRO`, as this changes the repacking behavior of residues near the mutant and introduces bias into ΔΔG.
170
+
171
+ For your own tasks, you typically need at least:
172
+
173
+ ```text
174
+ Complex PDB
175
+ + Interface chain information
176
+ + A resfile describing the mutations
177
+ ```
178
+ # Inference Examples
179
+ ## Flex ddG Calculation for Specified Mutations
180
+ Make sure that the Rosetta path in `scripts/run_example_1.py` is configured correctly:
181
+
182
+ ```python
183
+ rosetta_scripts_path = "/path/to/rosetta/source/bin/rosetta_scripts"
184
+ ```
185
+
186
+ Run:
187
+
188
+ ```bash
189
+ python scripts/run_example_1.py
190
+ ```
191
+
192
+ The script reads the complex structure, `chains_to_move.txt`, and `nataa_mutations.resfile` from `scripts/inputs/`, then calls `conf/ddG-backrub.xml` to run Flex ddG.
193
+
194
+ Key parameters:
195
+
196
+ | Parameter | Default | Common production setting/meaning |
197
+ | --- | ---: | --- |
198
+ | `nstruct` | 3 | Typically about 35 or more independent replicates in production |
199
+ | `number_backrub_trials` | 10 | 35000 is commonly used in the official benchmark |
200
+ | `max_minimization_iter` | 5 | Standard value: 5000 |
201
+ | `abs_score_convergence_thresh` | 200.0 | Standard value: 1.0 |
202
+ | `backrub_trajectory_stride` | 5 | Controls the interval between Backrub trajectory checkpoints |
203
+
204
+ The small parameter values in this document are intended to shorten runtime and should not be used directly for production ΔΔG calculations.
205
+
206
+ ## Single-Site Saturation Mutagenesis
207
+
208
+ Run:
209
+
210
+ ```bash
211
+ python scripts/run_example_2_saturation.py
212
+ ```
213
+
214
+ The script sequentially generates a resfile for each of the 20 standard amino acid substitutions at the specified residue and runs Flex ddG.
215
+
216
+ Configure the target site in the script:
217
+
218
+ ```python
219
+ residue_to_mutate = ('B', 49, '')
220
+ ```
221
+
222
+ The format is:
223
+
224
+ ```text
225
+ (chain ID, PDB residue number, insertion code)
226
+ ```
227
+
228
+ Results are saved in:
229
+
230
+ ```text
231
+ output_saturation/
232
+ ```
233
+
234
+ ## Parallel Execution Recommendations
235
+
236
+ The official scripts use the following defaults:
237
+
238
+ ```python
239
+ use_multiprocessing = True
240
+ max_cpus = 2
241
+ ```
242
+
243
+ During actual execution, adjust `max_cpus` according to the allocated number of CPU cores and the node's available memory. Each Rosetta instance uses CPU and memory independently, so setting it to all available cores unconditionally is not recommended.
244
+
245
+ # Result Analysis
246
+
247
+ After Example 1 is complete:
248
+
249
+ ```bash
250
+ python scripts/analyze_flex_ddG.py output
251
+ ```
252
+
253
+ For saturation mutagenesis results:
254
+
255
+ ```bash
256
+ python scripts/analyze_flex_ddG.py output_saturation
257
+ ```
258
+
259
+ The analysis script outputs:
260
+
261
+ ```text
262
+ wt_dG
263
+ mut_dG
264
+ ΔΔG
265
+ ```
266
+
267
+ The results are written to:
268
+
269
+ ```text
270
+ analysis_output/
271
+ ```
272
+
273
+ the CSV files in this directory. It also provides reweighted mutant ΔΔG values using the GAM model fitted in the original Flex ddG paper.
274
+
275
+ To extract structures after Backrub, wild-type minimization, or mutant minimization:
276
+
277
+ ```bash
278
+ python scripts/extract_structures.py output
279
+ ```
280
+
281
+ The script looks for `struct.db3` and calls Rosetta `score_jd2` to export PDB files.
282
+
283
+ # Output Description
284
+
285
+ After running `scripts/run_example_1.py`, the main results are located at:
286
+
287
+ ```text
288
+ output/
289
+ └── <case>/
290
+ └── <replicate>/
291
+ ├── rosetta.out
292
+ ├── ddG.db3
293
+ └── struct.db3
294
+ ```
295
+
296
+ The files are:
297
+
298
+ | File | Description |
299
+ | --- | --- |
300
+ | `rosetta.out` | Rosetta run log |
301
+ | `ddG.db3` | Database of Flex ddG energy and trajectory results |
302
+ | `struct.db3` | Database of structures generated by Rosetta |
303
+ | `analysis_output/*.csv` | Summary of ΔΔG results generated by `scripts/analyze_flex_ddG.py` |
304
+
305
+ The analysis script reads the Backrub trajectory stride from the `ddG.db3` generated by each run, so you usually do not need to modify the analysis script manually. If the database does not contain a stride, use:
306
+
307
+ ```bash
308
+ python scripts/analyze_flex_ddG.py output --stride N
309
+ ```
310
+ to override it.
311
+
312
+ # Official OneScience Information
313
+
314
+ | Platform | Main OneScience repository | Skills repository |
315
+ | --- | --- | --- |
316
+ | Gitee | https://gitee.com/onescience-ai/onescience | https://gitee.com/onescience-ai/oneskills |
317
+ | GitHub | https://github.com/onescience-ai/OneScience | https://github.com/onescience-ai/oneskills |
318
+
319
+ # Citation and License
320
+
321
+ - Original Flex ddG paper: [Flex ddG: Rosetta Ensemble-Based Estimation of Changes in Protein–Protein Binding Affinity upon Mutation](https://doi.org/10.1021/acs.jpcb.7b11367).
322
+ - Flex ddG uses the Rosetta Backrub conformational sampling method. Related paper: [Backrub-Like Backbone Simulation Recapitulates Natural Protein Conformational Variability and Improves Mutant Side-Chain Prediction](https://doi.org/10.1016/j.jmb.2008.05.023).
323
+ - The official flex_ddG_tutorial source code is released under the MIT License; see `LICENSE` in the repository root.
324
+ - **Rosetta is not covered by the MIT License of the Flex ddG tutorial repository.** Rosetta is distributed under a separate software license; academic and non-commercial users can apply for a non-commercial license, while commercial use requires a separate commercial license.
325
+ - For research use, we recommend citing the relevant Flex ddG, Backrub, and Rosetta publications, and adding citations as required by the relevant OneScience project.
conf/ddG-backrub.xml ADDED
@@ -0,0 +1,114 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <ROSETTASCRIPTS>
2
+ <SCOREFXNS>
3
+ <ScoreFunction name="fa_talaris2014" weights="talaris2014"/>
4
+ <ScoreFunction name="fa_talaris2014_cst" weights="talaris2014">
5
+ <Reweight scoretype="atom_pair_constraint" weight="1.0"/>
6
+ <Set fa_max_dis="9.0"/>
7
+ </ScoreFunction>
8
+ </SCOREFXNS>
9
+
10
+ <!-- ### Only required input file (other than PDB) - mutation resfile ### -->
11
+ <!-- #### All residues must be set to be NATAA packable at top of resfile ### -->
12
+ <TASKOPERATIONS>
13
+ <ReadResfile name="res_mutate" filename="%%mutate_resfile_relpath%%"/>
14
+ </TASKOPERATIONS>
15
+
16
+ <RESIDUE_SELECTORS>
17
+ <Task name="resselector" fixed="0" packable="0" designable="1" task_operations="res_mutate"/>
18
+ <Neighborhood name="bubble" selector="resselector" distance="8.0"/>
19
+ <PrimarySequenceNeighborhood name="bubble_adjacent" selector="bubble" lower="1" upper="1"/>
20
+ <StoredResidueSubset name="restore_neighbor_shell" subset_name="neighbor_shell"/>
21
+ <Not name="everythingelse" selector="restore_neighbor_shell"/>
22
+ </RESIDUE_SELECTORS>
23
+ <TASKOPERATIONS>
24
+ <OperateOnResidueSubset name="repackonly" selector="restore_neighbor_shell">
25
+ <RestrictToRepackingRLT/>
26
+ </OperateOnResidueSubset>
27
+ <OperateOnResidueSubset name="norepack" selector="everythingelse">
28
+ <PreventRepackingRLT/>
29
+ </OperateOnResidueSubset>
30
+ <UseMultiCoolAnnealer name="multicool" states="6"/>
31
+ <ExtraChiCutoff name="extrachizero" extrachi_cutoff="0"/>
32
+ <InitializeFromCommandline name="commandline_init"/>
33
+ <RestrictToRepacking name="restrict_to_repacking"/>
34
+ </TASKOPERATIONS>
35
+
36
+ <FILTERS>
37
+ </FILTERS>
38
+
39
+ <MOVERS>
40
+ <StoreResidueSubset name="neighbor_shell_storer" subset_name="neighbor_shell" residue_selector="bubble_adjacent" />
41
+
42
+ <AddConstraintsToCurrentConformationMover name="addcst" use_distance_cst="1" coord_dev="0.5" min_seq_sep="0" max_distance="9" CA_only="1" bound_width="0.0" cst_weight="0.0"/>
43
+ <ClearConstraintsMover name="clearcst"/>
44
+ <MinMover name="minimize" scorefxn="fa_talaris2014_cst" chi="1" bb="1" type="lbfgs_armijo_nonmonotone" tolerance="0.000001" max_iter="%%max_minimization_iter%%" abs_score_convergence_threshold="%%abs_score_convergence_thresh%%"/>
45
+
46
+ <PackRotamersMover name="repack" scorefxn="fa_talaris2014" task_operations="commandline_init,repackonly,norepack,multicool"/>
47
+ <PackRotamersMover name="mutate" scorefxn="fa_talaris2014" task_operations="commandline_init,res_mutate,norepack,multicool"/>
48
+
49
+ <ReportToDB name="dbreport" batch_description="interface_ddG" database_name="ddG.db3">
50
+ <ScoreTypeFeatures/>
51
+ <ScoreFunctionFeatures scorefxn="fa_talaris2014"/>
52
+ <StructureScoresFeatures scorefxn="fa_talaris2014"/>
53
+ </ReportToDB>
54
+
55
+ <ReportToDB name="structreport" batch_description="interface_ddG_struct" database_name="struct.db3">
56
+ <PoseConformationFeatures/>
57
+ <PdbDataFeatures/>
58
+ <JobDataFeatures/>
59
+ <ResidueFeatures/>
60
+ <PoseCommentsFeatures/>
61
+ <ProteinResidueConformationFeatures/>
62
+ <ResidueConformationFeatures/>
63
+ </ReportToDB>
64
+
65
+ <SavePoseMover name="save_wt_bound_pose" restore_pose="0" reference_name="wt_bound_pose"/>
66
+ <SavePoseMover name="save_backrub_pose" restore_pose="0" reference_name="backrubpdb"/>
67
+ <SavePoseMover name="restore_backrub_pose" restore_pose="1" reference_name="backrubpdb"/>
68
+
69
+ <InterfaceDdGMover name="int_ddG_mover" wt_ref_savepose_mover="save_wt_bound_pose" chain_name="%%chainstomove%%" db_reporter="dbreport" scorefxn="fa_talaris2014"/>
70
+
71
+ <ScoreMover name="apply_score" scorefxn="fa_talaris2014_cst" verbose="0"/>
72
+
73
+ <!-- This ParsedProtocol allows the ddG calculation to take place multiple times along the backrub trajectory, if desired -->
74
+ <ParsedProtocol name="finish_ddg_post_backrub">
75
+ <Add mover_name="save_backrub_pose"/>
76
+ <Add mover_name="structreport"/>
77
+
78
+ <Add mover_name="repack"/>
79
+
80
+ <Add mover_name="addcst"/>
81
+ <Add mover_name="minimize"/>
82
+ <Add mover_name="clearcst"/>
83
+
84
+ <Add mover_name="save_wt_bound_pose"/>
85
+ <Add mover_name="structreport"/>
86
+ <Add mover_name="restore_backrub_pose"/>
87
+
88
+ <Add mover_name="mutate"/>
89
+
90
+ <Add mover_name="addcst"/>
91
+ <Add mover_name="minimize"/>
92
+ <Add mover_name="clearcst"/>
93
+ <Add mover_name="structreport"/>
94
+
95
+ <Add mover_name="int_ddG_mover"/>
96
+ </ParsedProtocol>
97
+
98
+ <BackrubProtocol name="backrub" mc_kt="1.2" ntrials="%%number_backrub_trials%%" pivot_residue_selector="restore_neighbor_shell" task_operations="restrict_to_repacking,commandline_init,extrachizero" recover_low="0" trajectory_stride="%%backrub_trajectory_stride%%" trajectory_apply_mover="finish_ddg_post_backrub"/>
99
+
100
+ </MOVERS>
101
+ <APPLY_TO_POSE>
102
+ </APPLY_TO_POSE>
103
+ <PROTOCOLS>
104
+ <Add mover_name="addcst"/>
105
+ <Add mover_name="apply_score"/> <!-- Necessary to initialize neighbor graph -->
106
+ <Add mover_name="neighbor_shell_storer"/>
107
+
108
+ <Add mover_name="minimize"/>
109
+ <Add mover_name="clearcst"/>
110
+
111
+ <Add mover_name="backrub"/>
112
+ </PROTOCOLS>
113
+ <OUTPUT />
114
+ </ROSETTASCRIPTS>
conf/ddG-no_backrub_control.xml ADDED
@@ -0,0 +1,108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <ROSETTASCRIPTS>
2
+ <SCOREFXNS>
3
+ <ScoreFunction name="fa_talaris2014" weights="talaris2014"/>
4
+ <ScoreFunction name="fa_talaris2014_cst" weights="talaris2014">
5
+ <Reweight scoretype="atom_pair_constraint" weight="1.0"/>
6
+ <Set fa_max_dis="9.0"/>
7
+ </ScoreFunction>
8
+ </SCOREFXNS>
9
+
10
+ <!-- ### Only required input file (other than PDB) - mutation resfile ### -->
11
+ <!-- #### All residues must be set to be NATAA packable at top of resfile ### -->
12
+ <TASKOPERATIONS>
13
+ <ReadResfile name="res_mutate" filename="%%mutate_resfile_relpath%%"/>
14
+ </TASKOPERATIONS>
15
+
16
+ <RESIDUE_SELECTORS>
17
+ <Task name="resselector" fixed="0" packable="0" designable="1" task_operations="res_mutate"/>
18
+ <Neighborhood name="bubble" selector="resselector" distance="8.0"/>
19
+ <PrimarySequenceNeighborhood name="bubble_adjacent" selector="bubble" lower="1" upper="1"/>
20
+ <StoredResidueSubset name="restore_neighbor_shell" subset_name="neighbor_shell"/>
21
+ <Not name="everythingelse" selector="restore_neighbor_shell"/>
22
+ </RESIDUE_SELECTORS>
23
+ <TASKOPERATIONS>
24
+ <OperateOnResidueSubset name="repackonly" selector="restore_neighbor_shell">
25
+ <RestrictToRepackingRLT/>
26
+ </OperateOnResidueSubset>
27
+ <OperateOnResidueSubset name="norepack" selector="everythingelse">
28
+ <PreventRepackingRLT/>
29
+ </OperateOnResidueSubset>
30
+ <UseMultiCoolAnnealer name="multicool" states="6"/>
31
+ <ExtraChiCutoff name="extrachizero" extrachi_cutoff="0"/>
32
+ <InitializeFromCommandline name="commandline_init"/>
33
+ <RestrictToRepacking name="restrict_to_repacking"/>
34
+ </TASKOPERATIONS>
35
+
36
+ <FILTERS>
37
+ </FILTERS>
38
+
39
+ <MOVERS>
40
+ <StoreResidueSubset name="neighbor_shell_storer" subset_name="neighbor_shell" residue_selector="bubble_adjacent" />
41
+
42
+ <AddConstraintsToCurrentConformationMover name="addcst" use_distance_cst="1" coord_dev="0.5" min_seq_sep="0" max_distance="9" CA_only="1" bound_width="0.0" cst_weight="0.0"/>
43
+ <ClearConstraintsMover name="clearcst"/>
44
+ <MinMover name="minimize" scorefxn="fa_talaris2014_cst" chi="1" bb="1" type="lbfgs_armijo_nonmonotone" tolerance="0.000001" max_iter="%%max_minimization_iter%%" abs_score_convergence_threshold="%%abs_score_convergence_thresh%%"/>
45
+
46
+ <PackRotamersMover name="repack" scorefxn="fa_talaris2014" task_operations="commandline_init,repackonly,norepack,multicool"/>
47
+ <PackRotamersMover name="mutate" scorefxn="fa_talaris2014" task_operations="commandline_init,res_mutate,norepack,multicool"/>
48
+
49
+ <ReportToDB name="dbreport" batch_description="interface_ddG" database_name="ddG.db3">
50
+ <ScoreTypeFeatures/>
51
+ <ScoreFunctionFeatures scorefxn="fa_talaris2014"/>
52
+ <StructureScoresFeatures scorefxn="fa_talaris2014"/>
53
+ </ReportToDB>
54
+
55
+ <ReportToDB name="structreport" batch_description="interface_ddG_struct" database_name="struct.db3">
56
+ <PoseConformationFeatures/>
57
+ <PdbDataFeatures/>
58
+ <JobDataFeatures/>
59
+ <ResidueFeatures/>
60
+ <PoseCommentsFeatures/>
61
+ <ProteinResidueConformationFeatures/>
62
+ <ResidueConformationFeatures/>
63
+ </ReportToDB>
64
+
65
+ <SavePoseMover name="save_wt_bound_pose" restore_pose="0" reference_name="wt_bound_pose"/>
66
+ <SavePoseMover name="save_backrub_pose" restore_pose="0" reference_name="backrubpdb"/>
67
+ <SavePoseMover name="restore_backrub_pose" restore_pose="1" reference_name="backrubpdb"/>
68
+
69
+ <InterfaceDdGMover name="int_ddG_mover" wt_ref_savepose_mover="save_wt_bound_pose" chain_name="%%chainstomove%%" db_reporter="dbreport" scorefxn="fa_talaris2014"/>
70
+
71
+ <ScoreMover name="apply_score" scorefxn="fa_talaris2014_cst" verbose="0"/>
72
+
73
+ </MOVERS>
74
+ <APPLY_TO_POSE>
75
+ </APPLY_TO_POSE>
76
+ <PROTOCOLS>
77
+ <Add mover_name="addcst"/>
78
+ <Add mover_name="apply_score"/> <!-- Necessary to initialize neighbor graph -->
79
+ <Add mover_name="neighbor_shell_storer"/>
80
+
81
+ <Add mover_name="minimize"/>
82
+ <Add mover_name="clearcst"/>
83
+
84
+ <Add mover_name="save_backrub_pose"/>
85
+ <Add mover_name="structreport"/>
86
+
87
+ <Add mover_name="repack"/>
88
+
89
+ <Add mover_name="addcst"/>
90
+ <Add mover_name="minimize"/>
91
+ <Add mover_name="clearcst"/>
92
+
93
+ <Add mover_name="save_wt_bound_pose"/>
94
+ <Add mover_name="structreport"/>
95
+ <Add mover_name="restore_backrub_pose"/>
96
+
97
+ <Add mover_name="mutate"/>
98
+
99
+ <Add mover_name="addcst"/>
100
+ <Add mover_name="minimize"/>
101
+ <Add mover_name="clearcst"/>
102
+ <Add mover_name="structreport"/>
103
+
104
+ <Add mover_name="int_ddG_mover"/>
105
+
106
+ </PROTOCOLS>
107
+ <OUTPUT />
108
+ </ROSETTASCRIPTS>
conf/fig-overview.png ADDED

Git LFS Details

  • SHA256: 80e0b0edd5e8c68ff38e91dcf72f6e73844e2d524b222a60d4c856b0096d109f
  • Pointer size: 131 Bytes
  • Size of remote file: 445 kB
conf/per_chain_rescore.xml ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <ROSETTASCRIPTS>
2
+ <!--
3
+ Reprocess an EXISTING flex ddG run to recover per-chain intramolecular energies.
4
+
5
+ No re-sampling is needed: struct.db3 already holds the coordinates of every backrub,
6
+ wild type minimized, and mutant minimized pose. This protocol reads those poses back in,
7
+ isolates one chain at a time, and reports the isolated chain's total score.
8
+
9
+ Isolating the chain matters. A Chain residue selector alone is not enough, because
10
+ struct.db3 stores the *bound* poses, so a selector-scoped metric still picks up cross-chain
11
+ pair energies (roughly half the interface energy leaks into each chain). Deleting the other
12
+ chains reproduces the separated, unrelaxed unbound state exactly, because intra-chain
13
+ energy is invariant under the rigid-body translation InterfaceDdGMover uses to unbind.
14
+
15
+ Chain selectors below are for a two chain A/B complex. Add one Chain selector, one
16
+ DeleteRegionMover, one ReportToDB and one restore/delete/report triple per extra chain.
17
+
18
+ Usage (run once per struct.db3, from the directory containing it):
19
+
20
+ rosetta_scripts -inout:dbms:database_name struct.db3 -in:use_database \
21
+ -parser:protocol per_chain_rescore.xml \
22
+ -restore_talaris_behavior -in:file:fullatom -out:nooutput
23
+
24
+ Then read per_chain.db3 with reprocess_per_chain.py.
25
+ -->
26
+ <SCOREFXNS>
27
+ <ScoreFunction name="fa_talaris2014" weights="talaris2014"/>
28
+ </SCOREFXNS>
29
+
30
+ <RESIDUE_SELECTORS>
31
+ <Chain name="chain_A" chains="A"/>
32
+ <Chain name="chain_B" chains="B"/>
33
+ <Not name="not_chain_A" selector="chain_A"/>
34
+ <Not name="not_chain_B" selector="chain_B"/>
35
+ </RESIDUE_SELECTORS>
36
+
37
+ <MOVERS>
38
+ <SavePoseMover name="save_full" reference_name="full_pose" restore_pose="0"/>
39
+ <SavePoseMover name="restore_full" reference_name="full_pose" restore_pose="1"/>
40
+
41
+ <DeleteRegionMover name="isolate_chain_A" residue_selector="not_chain_A"/>
42
+ <DeleteRegionMover name="isolate_chain_B" residue_selector="not_chain_B"/>
43
+
44
+ <ReportToDB name="chain_A_report" batch_description="per_chain" database_name="per_chain.db3">
45
+ <ScoreTypeFeatures/>
46
+ <ScoreFunctionFeatures scorefxn="fa_talaris2014"/>
47
+ <StructureScoresFeatures scorefxn="fa_talaris2014"/>
48
+ </ReportToDB>
49
+ <ReportToDB name="chain_B_report" batch_description="per_chain" database_name="per_chain.db3">
50
+ <ScoreTypeFeatures/>
51
+ <ScoreFunctionFeatures scorefxn="fa_talaris2014"/>
52
+ <StructureScoresFeatures scorefxn="fa_talaris2014"/>
53
+ </ReportToDB>
54
+ </MOVERS>
55
+
56
+ <PROTOCOLS>
57
+ <Add mover_name="save_full"/>
58
+ <Add mover_name="isolate_chain_A"/>
59
+ <Add mover_name="chain_A_report"/>
60
+
61
+ <Add mover_name="restore_full"/>
62
+ <Add mover_name="isolate_chain_B"/>
63
+ <Add mover_name="chain_B_report"/>
64
+ </PROTOCOLS>
65
+ <OUTPUT />
66
+ </ROSETTASCRIPTS>
conf/split_protocol/flex_ddG-backrub_step.xml ADDED
@@ -0,0 +1,108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <ROSETTASCRIPTS>
2
+ <SCOREFXNS>
3
+ <ScoreFunction name="fa_fxn" weights="talaris2014">
4
+ </ScoreFunction>
5
+ <ScoreFunction name="fa_fxn_cst" weights="talaris2014">
6
+ <Reweight scoretype="atom_pair_constraint" weight="1.0"/>
7
+ <Set fa_max_dis="9.0"/>
8
+ </ScoreFunction>
9
+ </SCOREFXNS>
10
+
11
+ <!-- ### Only required input - mutation resfile ### -->
12
+ <!-- #### All residues must be set to be NATAA packable at top of resfile ### -->
13
+ <TASKOPERATIONS>
14
+ <ReadResfile name="res_mutate" filename="%%mutate_resfile_relpath%%"/>
15
+ </TASKOPERATIONS>
16
+
17
+ <RESIDUE_SELECTORS>
18
+ <Task name="resselector" fixed="0" packable="0" designable="1" task_operations="res_mutate"/>
19
+ <Neighborhood name="bubble" selector="resselector" distance="%%neighbor_distance%%" include_focus_in_subset="true"/>
20
+ <PrimarySequenceNeighborhood name="bubble_adjacent" selector="bubble" lower="1" upper="1"/>
21
+ <StoredResidueSubset name="restore_neighbor_shell" subset_name="neighbor_shell"/>
22
+ <Not name="everythingelse" selector="restore_neighbor_shell"/>
23
+ </RESIDUE_SELECTORS>
24
+ <TASKOPERATIONS>
25
+ <OperateOnResidueSubset name="repackonly" selector="restore_neighbor_shell">
26
+ <RestrictToRepackingRLT/>
27
+ </OperateOnResidueSubset>
28
+ <OperateOnResidueSubset name="norepack" selector="everythingelse">
29
+ <PreventRepackingRLT/>
30
+ </OperateOnResidueSubset>
31
+ <UseMultiCoolAnnealer name="multicool" states="6"/>
32
+ <ExtraChiCutoff name="extrachizero" extrachi_cutoff="0"/>
33
+ <InitializeFromCommandline name="commandline_init"/>
34
+ <RestrictToRepacking name="restrict_to_repacking"/>
35
+ </TASKOPERATIONS>
36
+
37
+ <FILTERS>
38
+ </FILTERS>
39
+
40
+ <MOVERS>
41
+ <StoreResidueSubset name="neighbor_shell_storer" subset_name="neighbor_shell" residue_selector="bubble_adjacent" />
42
+
43
+ <AddConstraintsToCurrentConformationMover name="addcst" use_distance_cst="1" coord_dev="0.5" min_seq_sep="0" max_distance="9" CA_only="1" bound_width="0.0" cst_weight="0.0"/>
44
+ <ClearConstraintsMover name="clearcst"/>
45
+ <MinMover name="minimize" scorefxn="fa_fxn_cst" chi="1" bb="1" type="lbfgs_armijo_nonmonotone" tolerance="%%min_tolerance%%" max_iter="%%min_max_iter%%" abs_score_convergence_threshold="%%min_abs_score_convergence_threshold%%"/>
46
+
47
+ <PackRotamersMover name="repack" scorefxn="fa_fxn" task_operations="commandline_init,repackonly,norepack,multicool"/>
48
+
49
+ <SavePoseMover name="input_struct_spm" reference_name="input_struct"/>
50
+ <SavePoseMover name="input_struct_lpm" restore_pose="1" reference_name="input_struct"/>
51
+ <SavePoseMover name="min_input_struct_spm" reference_name="min_input_struct"/>
52
+ <SavePoseMover name="min_input_struct_lpm" restore_pose="1" reference_name="min_input_struct"/>
53
+
54
+ <ReportToDB name="structreport" batch_description="interface_ddG_struct" database_name="struct.db3">
55
+ <PoseConformationFeatures/>
56
+ <PdbDataFeatures/>
57
+ <JobDataFeatures/>
58
+ <ResidueFeatures/>
59
+ <PoseCommentsFeatures/>
60
+ <ProteinResidueConformationFeatures/>
61
+ <ResidueConformationFeatures/>
62
+ <RotamerFeatures/>
63
+ <ResidueBurialFeatures/>
64
+ <ProteinRMSDFeatures reference_name="min_input_struct"/>
65
+ </ReportToDB>
66
+
67
+ <ScoreMover name="apply_score" scorefxn="fa_fxn_cst" verbose="0"/>
68
+
69
+ <PDBTrajectoryRecorder name="dump_wt_minimized" stride="1" filename="wt_minimized.pdb"/>
70
+
71
+ <ParsedProtocol name="finish_wt_post_backrub">
72
+ <Add mover_name="structreport"/>
73
+
74
+ <Add mover_name="repack"/>
75
+
76
+ <Add mover_name="addcst"/>
77
+ <Add mover_name="minimize"/>
78
+ <Add mover_name="clearcst"/>
79
+
80
+ <Add mover_name="structreport"/>
81
+ <Add mover_name="dump_wt_minimized"/>
82
+ </ParsedProtocol>
83
+
84
+ <BackrubProtocol name="backrub" mc_kt="%%backrub_kt%%" ntrials="%%backrub_trials%%" pivot_residue_selector="restore_neighbor_shell" task_operations="restrict_to_repacking,commandline_init,extrachizero" recover_low="0" trajectory_stride="%%backrub_stride%%" trajectory_apply_mover="finish_wt_post_backrub" trajectory="1" scorefxn="fa_fxn"/>
85
+
86
+ </MOVERS>
87
+ <APPLY_TO_POSE>
88
+ </APPLY_TO_POSE>
89
+ <PROTOCOLS>
90
+ <Add mover_name="input_struct_spm"/>
91
+ <Add mover_name="addcst"/>
92
+ <Add mover_name="apply_score"/> <!-- Necessary to initialize neighbor graph -->
93
+ <Add mover_name="neighbor_shell_storer"/>
94
+
95
+ <Add mover_name="minimize"/>
96
+
97
+ <Add mover_name="clearcst"/>
98
+ <Add mover_name="min_input_struct_spm"/>
99
+
100
+ <Add mover_name="input_struct_lpm"/>
101
+ <Add mover_name="structreport"/>
102
+ <Add mover_name="min_input_struct_lpm"/>
103
+ <Add mover_name="structreport"/>
104
+
105
+ <Add mover_name="backrub"/>
106
+ </PROTOCOLS>
107
+ <OUTPUT />
108
+ </ROSETTASCRIPTS>
conf/split_protocol/flex_ddG-mutation_step.xml ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <ROSETTASCRIPTS>
2
+ <SCOREFXNS>
3
+ <ScoreFunction name="fa_fxn" weights="talaris2014"/>
4
+ <ScoreFunction name="fa_fxn_cst" weights="talaris2014">
5
+ <Reweight scoretype="atom_pair_constraint" weight="1.0"/>
6
+ <Set fa_max_dis="9.0"/>
7
+ </ScoreFunction>
8
+ </SCOREFXNS>
9
+
10
+ <TASKOPERATIONS>
11
+ <ReadResfile name="res_mutate" filename="%%mutate_resfile_relpath%%"/>
12
+ </TASKOPERATIONS>
13
+
14
+ <RESIDUE_SELECTORS>
15
+ <Task name="resselector" fixed="0" packable="0" designable="1" task_operations="res_mutate"/>
16
+ <Neighborhood name="bubble_helper" selector="resselector" distance="%%neighbor_distance%%" include_focus_in_subset="true"/>
17
+ <NativeSelector name="bubble" residue_selector="bubble_helper" />
18
+ <PrimarySequenceNeighborhood name="bubble_adjacent" selector="bubble" lower="1" upper="1"/>
19
+ <StoredResidueSubset name="restore_neighbor_shell" subset_name="neighbor_shell"/>
20
+ <Not name="everythingelse" selector="restore_neighbor_shell"/>
21
+ </RESIDUE_SELECTORS>
22
+ <TASKOPERATIONS>
23
+ <OperateOnResidueSubset name="repackonly" selector="restore_neighbor_shell">
24
+ <RestrictToRepackingRLT/>
25
+ </OperateOnResidueSubset>
26
+ <OperateOnResidueSubset name="norepack" selector="everythingelse">
27
+ <PreventRepackingRLT/>
28
+ </OperateOnResidueSubset>
29
+ <UseMultiCoolAnnealer name="multicool" states="6"/>
30
+ <ExtraChiCutoff name="extrachizero" extrachi_cutoff="0"/>
31
+ <InitializeFromCommandline name="commandline_init"/>
32
+ <RestrictToRepacking name="restrict_to_repacking"/>
33
+ </TASKOPERATIONS>
34
+
35
+ <MOVERS>
36
+ <AddConstraintsToCurrentConformationMover name="addcst" use_distance_cst="1" coord_dev="0.5" min_seq_sep="0" max_distance="9" CA_only="1" bound_width="0.0" cst_weight="0.0"/>
37
+ <ClearConstraintsMover name="clearcst"/>
38
+ <MinMover name="minimize" scorefxn="fa_fxn_cst" chi="1" bb="1" type="lbfgs_armijo_nonmonotone" tolerance="%%min_tolerance%%" max_iter="%%min_max_iter%%" abs_score_convergence_threshold="%%min_abs_score_convergence_threshold%%"/>
39
+
40
+ <PackRotamersMover name="mutate" scorefxn="fa_fxn" task_operations="commandline_init,res_mutate,norepack,multicool"/>
41
+
42
+ <ReportToDB name="dbreport" batch_description="interface_ddG" database_name="ddG.db3">
43
+ <ResidueFeatures/>
44
+ <ScoreTypeFeatures/>
45
+ <ScoreFunctionFeatures scorefxn="fa_fxn"/>
46
+ <StructureScoresFeatures scorefxn="fa_fxn"/>
47
+ <HBondFeatures scorefxn="fa_fxn"/>
48
+ <InterfaceFeatures scorefxn="fa_fxn" pack_together="false"/>
49
+ </ReportToDB>
50
+
51
+ <ReportToDB name="structreport" batch_description="interface_ddG_struct" database_name="struct.db3">
52
+ <PoseConformationFeatures/>
53
+ <PdbDataFeatures/>
54
+ <JobDataFeatures/>
55
+ <ResidueFeatures/>
56
+ <PoseCommentsFeatures/>
57
+ <ProteinResidueConformationFeatures/>
58
+ <ResidueConformationFeatures/>
59
+ <RotamerFeatures/>
60
+ <ResidueBurialFeatures/>
61
+ </ReportToDB>
62
+
63
+ <SavePoseMover name="save_wt_bound_pose" restore_pose="0" reference_name="wt_bound_pose"/>
64
+ <LoadPDB name="load_backrub_pdb" filename="%%backrub_pdb_path%%"/>
65
+
66
+ <InterfaceDdGMover name="int_ddG_mover" wt_ref_savepose_mover="save_wt_bound_pose" chain_name="%%chainstomove%%" db_reporter="dbreport" scorefxn="fa_fxn"/>
67
+
68
+ <ScoreMover name="apply_score" scorefxn="fa_fxn_cst" verbose="0"/>
69
+ <StoreResidueSubset name="neighbor_shell_storer" subset_name="neighbor_shell" residue_selector="bubble_adjacent" />
70
+
71
+ </MOVERS>
72
+ <APPLY_TO_POSE>
73
+ </APPLY_TO_POSE>
74
+ <PROTOCOLS>
75
+ <Add mover_name="save_wt_bound_pose"/>
76
+
77
+ <Add mover_name="load_backrub_pdb"/>
78
+ <Add mover_name="neighbor_shell_storer"/>
79
+
80
+ <Add mover_name="addcst"/>
81
+ <Add mover_name="apply_score"/>
82
+ <Add mover_name="clearcst"/>
83
+ <Add mover_name="mutate"/>
84
+
85
+ <Add mover_name="addcst"/>
86
+ <Add mover_name="minimize"/>
87
+ <Add mover_name="clearcst"/>
88
+ <Add mover_name="structreport"/>
89
+
90
+ <Add mover_name="int_ddG_mover"/>
91
+
92
+ <Add mover_name="dbreport"/>
93
+ </PROTOCOLS>
94
+ <OUTPUT />
95
+ </ROSETTASCRIPTS>
conf/split_protocol/split_commands.txt ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Backrub step command line example:
2
+
3
+ rosetta_scripts.linuxgccrelease
4
+ -parser:protocol flex_ddG-backrub_step.xml
5
+ -s wt_pdb_path # Starting WT crystal structure
6
+ -in:file:fullatom
7
+ -parser:script_vars
8
+ mutate_resfile_relpath=%s # Path to a resfile specifying mutant positions. Can be any set of mutations (only the positions matter), as mutations are made in the next step. Positions need to be known now to pick backrub region.
9
+ backrub_kt=1.2
10
+ backrub_trials=36000
11
+ backrub_stride=12000
12
+ neighbor_distance=12.0
13
+ sc_sample_rotwells_unif=0
14
+ min_tolerance=0.000001
15
+ min_max_iter=5000
16
+ min_abs_score_convergence_threshold=1.0
17
+
18
+ Mutation step command line example:
19
+
20
+ rosetta_scripts.linuxgccrelease
21
+ -parser:protocol flex_ddG-mutation_step.xml
22
+ -s wt_minimized_pdb_path # Path to the WT minimized PDB structure from the first script, needed to score ddG calculation
23
+ -native # Path to the starting WT crystal structure, needed so that same neighbor residue bubble is selected
24
+ -in:file:fullatom
25
+ -parser:script_vars
26
+ chainstomove=%s
27
+ mutate_resfile_relpath=%s # Path to resfile specifying mutations
28
+ min_tolerance=0.000001
29
+ min_max_iter=5000
30
+ neighbor_distance=12.0
31
+ min_abs_score_convergence_threshold=1.0
32
+ backrub_pdb_path=%s # Path to backrub PDB output from earlier step, mutations will be applied to this model
config.json ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "project": "flex_ddG_tutorial",
3
+ "purpose": "Directory layout metadata only. This file is not used by the runtime scripts.",
4
+ "layout": {
5
+ "conf": {
6
+ "description": "Rosetta XML protocols and related protocol configuration files.",
7
+ "paths": [
8
+ "conf/ddG-backrub.xml",
9
+ "conf/ddG-no_backrub_control.xml",
10
+ "conf/per_chain_rescore.xml",
11
+ "conf/split_protocol/",
12
+ "conf/fig-overview.png"
13
+ ]
14
+ },
15
+ "scripts": {
16
+ "description": "Python entry points, helper modules, and bundled example input data.",
17
+ "paths": [
18
+ "scripts/run_example_1.py",
19
+ "scripts/run_example_2_saturation.py",
20
+ "scripts/analyze_flex_ddG.py",
21
+ "scripts/extract_structures.py",
22
+ "scripts/inputs/"
23
+ ]
24
+ },
25
+ "root": {
26
+ "description": "Top-level documentation, license, and static overview assets.",
27
+ "paths": [
28
+ "README.md",
29
+ "LICENSE"
30
+ ]
31
+ }
32
+ }
33
+ }
scripts/analyze_flex_ddG.py ADDED
@@ -0,0 +1,344 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/python3
2
+
3
+ import sys
4
+ import os
5
+ import sqlite3
6
+ import shutil
7
+ import tempfile
8
+ from pprint import pprint
9
+ import pandas as pd
10
+ import numpy as np
11
+ import re
12
+ import argparse
13
+ import datetime
14
+ import sys
15
+ import collections
16
+ import threading
17
+
18
+ import flex_ddg_db3
19
+
20
+ rosetta_output_file_name = 'rosetta.out'
21
+ output_database_name = 'ddG.db3'
22
+ script_output_folder = 'analysis_output'
23
+
24
+ # Only a fallback. The stride each run actually used is read back out of its own ddG.db3, so
25
+ # runs with different strides analyze correctly and nothing here needs editing to match a run.
26
+ # This value is used only when the database does not record it, and a warning is printed.
27
+ default_trajectory_stride = 5
28
+
29
+ zemu_gam_params = {
30
+ 'fa_sol' : (6.940, -6.722),
31
+ 'hbond_sc' : (1.902, -1.999),
32
+ 'hbond_bb_sc' : (0.063, 0.452),
33
+ 'fa_rep' : (1.659, -0.836),
34
+ 'fa_elec' : (0.697, -0.122),
35
+ 'hbond_lr_bb' : (2.738, -1.179),
36
+ 'fa_atr' : (2.313, -1.649),
37
+ }
38
+
39
+ def gam_function(x, score_term = None ):
40
+ return -1.0 * np.exp( zemu_gam_params[score_term][0] ) + 2.0 * np.exp( zemu_gam_params[score_term][0] ) / ( 1.0 + np.exp( -1.0 * x * np.exp( zemu_gam_params[score_term][1] ) ) )
41
+
42
+ def apply_zemu_gam(scores):
43
+ new_columns = list(scores.columns)
44
+ new_columns.remove('total_score')
45
+ scores = scores.copy()[ new_columns ]
46
+ for score_term in zemu_gam_params:
47
+ assert( score_term in scores.columns )
48
+ scores[score_term] = scores[score_term].apply( gam_function, score_term = score_term )
49
+ scores[ 'total_score' ] = scores[ list(zemu_gam_params.keys()) ].sum( axis = 1 )
50
+ scores[ 'score_function_name' ] = scores[ 'score_function_name' ] + '-gam'
51
+ return scores
52
+
53
+ def rosetta_output_succeeded( potential_struct_dir ):
54
+ path_to_rosetta_output = os.path.join( potential_struct_dir, rosetta_output_file_name )
55
+ if not os.path.isfile(path_to_rosetta_output):
56
+ return False
57
+
58
+ db3_file = os.path.join( potential_struct_dir, output_database_name )
59
+ if not os.path.isfile( db3_file ):
60
+ return False
61
+
62
+ success_line_found = False
63
+ no_more_batches_line_found = False
64
+ with open( path_to_rosetta_output, 'r' ) as f:
65
+ for line in f:
66
+ if line.startswith( 'protocols.jd2.JobDistributor' ) and 'reported success in' in line:
67
+ success_line_found = True
68
+ if line.startswith( 'protocols.jd2.JobDistributor' ) and 'no more batches to process' in line:
69
+ no_more_batches_line_found = True
70
+
71
+ return no_more_batches_line_found and success_line_found
72
+
73
+ def find_finished_jobs( output_folder ):
74
+ return_dict = {}
75
+ job_dirs = [ os.path.abspath(os.path.join(output_folder, d)) for d in os.listdir(output_folder) if os.path.isdir( os.path.join(output_folder, d) )]
76
+ for job_dir in job_dirs:
77
+ completed_struct_dirs = []
78
+ for potential_struct_dir in sorted([ os.path.abspath(os.path.join(job_dir, d)) for d in os.listdir(job_dir) if os.path.isdir( os.path.join(job_dir, d) )]):
79
+ if rosetta_output_succeeded( potential_struct_dir ):
80
+ completed_struct_dirs.append( potential_struct_dir )
81
+ return_dict[job_dir] = completed_struct_dirs
82
+
83
+ return return_dict
84
+
85
+ def get_scores_from_db3_file(db3_file, struct_number, case_name, trajectory_stride):
86
+ conn = sqlite3.connect(db3_file)
87
+ conn.row_factory = sqlite3.Row
88
+ c = conn.cursor()
89
+
90
+ num_batches = c.execute('SELECT max(batch_id) from batches').fetchone()[0]
91
+
92
+ scores = pd.read_sql_query('''
93
+ SELECT batches.name, structure_scores.struct_id, score_types.score_type_name, structure_scores.score_value, score_function_method_options.score_function_name from structure_scores
94
+ INNER JOIN batches ON batches.batch_id=structure_scores.batch_id
95
+ INNER JOIN score_function_method_options ON score_function_method_options.batch_id=batches.batch_id
96
+ INNER JOIN score_types ON score_types.batch_id=structure_scores.batch_id AND score_types.score_type_id=structure_scores.score_type_id
97
+ ''', conn)
98
+
99
+ def renumber_struct_id( struct_id ):
100
+ return trajectory_stride * ( 1 + (int(struct_id-1) // num_batches) )
101
+
102
+ scores['struct_id'] = scores['struct_id'].apply( renumber_struct_id )
103
+ scores['name'] = scores['name'].apply( lambda x: x[:-9] if x.endswith('_dbreport') else x )
104
+ scores = scores.pivot_table( index = ['name', 'struct_id', 'score_function_name'], columns = 'score_type_name', values = 'score_value' ).reset_index()
105
+ scores.rename( columns = {
106
+ 'name' : 'state',
107
+ 'struct_id' : 'backrub_steps',
108
+ }, inplace=True)
109
+ scores['struct_num'] = struct_number
110
+ scores['case_name'] = case_name
111
+
112
+ conn.close()
113
+
114
+ return scores
115
+
116
+ def get_per_chain_scores_from_db3_file(db3_file, struct_number, case_name, trajectory_stride):
117
+ '''Read the per-chain intramolecular energies written by the per-chain protocol variant
118
+ (see per_chain_protocol.py). Returns None if the run did not report them.
119
+
120
+ Only the unbound states are meaningful here: the chains are 1000 A apart, so there are no
121
+ cross-chain pair energies and each value is exactly that chain's intramolecular energy. On
122
+ the bound states the value additionally carries roughly half the interface energy, because
123
+ Rosetta splits each two-body term between its two residues.
124
+
125
+ Note that chain IDs come back lowercased, because Rosetta lowercases database table names.
126
+ Chain "A" appears here as "a". per_chain_protocol.py refuses to set up a run whose chain IDs
127
+ differ only by case, so this stays unambiguous.
128
+ '''
129
+ conn = sqlite3.connect(db3_file)
130
+ conn.row_factory = sqlite3.Row
131
+ c = conn.cursor()
132
+
133
+ chain_tables = [ row[0] for row in c.execute(
134
+ "SELECT name FROM sqlite_master WHERE type='table' AND name LIKE 'chain\\_%\\_energy' ESCAPE '\\'"
135
+ ).fetchall() ]
136
+ if len(chain_tables) == 0:
137
+ conn.close()
138
+ return None
139
+
140
+ num_batches = c.execute('SELECT max(batch_id) from batches').fetchone()[0]
141
+
142
+ dfs = []
143
+ for table in chain_tables:
144
+ chain = table[len('chain_'):-len('_energy')]
145
+ df = pd.read_sql_query('''
146
+ SELECT batches.name, %s.struct_id, %s.total_energy from %s
147
+ INNER JOIN structures ON structures.struct_id=%s.struct_id
148
+ INNER JOIN batches ON batches.batch_id=structures.batch_id
149
+ ''' % (table, table, table, table), conn)
150
+ df['chain'] = chain
151
+ dfs.append(df)
152
+ conn.close()
153
+
154
+ scores = pd.concat( dfs )
155
+ scores['struct_id'] = scores['struct_id'].apply(
156
+ lambda struct_id: trajectory_stride * ( 1 + (int(struct_id-1) // num_batches) ) )
157
+ scores['name'] = scores['name'].apply( lambda x: x[:-9] if x.endswith('_dbreport') else x )
158
+ scores.rename( columns = {
159
+ 'name' : 'state',
160
+ 'struct_id' : 'backrub_steps',
161
+ 'total_energy' : 'intra_energy',
162
+ }, inplace=True)
163
+ scores['struct_num'] = struct_number
164
+ scores['case_name'] = case_name
165
+
166
+ return scores
167
+
168
+ def calc_per_chain_ddg( scores ):
169
+ '''Per-chain intramolecular ddG, read off the unbound states and averaged over nstruct.'''
170
+ unbound = scores.loc[ scores['state'].isin(['unbound_wt', 'unbound_mut']) ].copy()
171
+ if len(unbound) == 0:
172
+ return None
173
+
174
+ wide = unbound.pivot_table(
175
+ index = ['case_name', 'chain', 'backrub_steps', 'struct_num'],
176
+ columns = 'state', values = 'intra_energy' ).reset_index()
177
+ if 'unbound_wt' not in wide.columns or 'unbound_mut' not in wide.columns:
178
+ return None
179
+ wide['ddG'] = wide['unbound_mut'] - wide['unbound_wt']
180
+
181
+ summary = wide.groupby( ['case_name', 'chain', 'backrub_steps'] ).agg(
182
+ nstruct = ('ddG', 'size'),
183
+ wt_intra = ('unbound_wt', 'mean'),
184
+ mut_intra = ('unbound_mut', 'mean'),
185
+ ddG = ('ddG', 'mean'),
186
+ ddG_sd = ('ddG', 'std'),
187
+ ).reset_index()
188
+ summary['ddG_sem'] = summary['ddG_sd'] / np.sqrt( summary['nstruct'] )
189
+ return summary.round(decimals=5)
190
+
191
+ def resolve_trajectory_stride( db3_file, stride_override = None ):
192
+ '''Stride to label this database's checkpoints with, preferring what the run recorded.'''
193
+ if stride_override is not None:
194
+ return stride_override
195
+
196
+ stride = flex_ddg_db3.trajectory_stride_from_db3( db3_file )
197
+ if stride is not None:
198
+ return stride
199
+
200
+ print( 'WARNING: %s does not record backrub_trajectory_stride; assuming %d.' % (
201
+ db3_file, default_trajectory_stride ) )
202
+ print( ' If the run used a different stride, pass --stride to label the' )
203
+ print( ' checkpoints correctly. This affects labels only, not any energy.' )
204
+ return default_trajectory_stride
205
+
206
+ def process_finished_struct( output_path, case_name, stride_override = None ):
207
+ db3_file = os.path.join( output_path, output_database_name )
208
+ assert( os.path.isfile( db3_file ) )
209
+ struct_number = int( os.path.basename(output_path) )
210
+ trajectory_stride = resolve_trajectory_stride( db3_file, stride_override )
211
+ scores_df = get_scores_from_db3_file( db3_file, struct_number, case_name, trajectory_stride )
212
+ per_chain_df = get_per_chain_scores_from_db3_file( db3_file, struct_number, case_name, trajectory_stride )
213
+
214
+ return scores_df, per_chain_df
215
+
216
+ def calc_ddg( scores ):
217
+ total_structs = np.max( scores['struct_num'] )
218
+
219
+ nstructs_to_analyze = set([total_structs])
220
+ for x in range(10, total_structs):
221
+ if x % 10 == 0:
222
+ nstructs_to_analyze.add(x)
223
+ nstructs_to_analyze = sorted(nstructs_to_analyze)
224
+
225
+ all_ddg_scores = []
226
+ for nstructs in nstructs_to_analyze:
227
+ ddg_scores = scores.loc[ ((scores['state'] == 'unbound_mut') | (scores['state'] == 'bound_wt')) & (scores['struct_num'] <= nstructs) ].copy()
228
+ for column in ddg_scores.columns:
229
+ if column not in ['state', 'case_name', 'backrub_steps', 'struct_num', 'score_function_name']:
230
+ ddg_scores.loc[:,column] *= -1.0
231
+ ddg_scores = pd.concat( [ ddg_scores, scores.loc[ ((scores['state'] == 'unbound_wt') | (scores['state'] == 'bound_mut')) & (scores['struct_num'] <= nstructs) ].copy() ] )
232
+ ddg_scores = ddg_scores.groupby( ['case_name', 'backrub_steps', 'struct_num', 'score_function_name'] ).sum( numeric_only = True ).reset_index()
233
+
234
+ if nstructs == total_structs:
235
+ struct_scores = ddg_scores.copy()
236
+
237
+ ddg_scores = ddg_scores.groupby( ['case_name', 'backrub_steps', 'score_function_name'] ).mean( numeric_only = True ).round(decimals=5).reset_index()
238
+ new_columns = list(ddg_scores.columns.values)
239
+ new_columns.remove( 'struct_num' )
240
+ ddg_scores = ddg_scores[new_columns]
241
+ ddg_scores[ 'scored_state' ] = 'ddG'
242
+ ddg_scores[ 'nstruct' ] = nstructs
243
+ all_ddg_scores.append(ddg_scores)
244
+
245
+ return (pd.concat(all_ddg_scores), struct_scores)
246
+
247
+ def calc_dgs( scores ):
248
+ l = []
249
+
250
+ total_structs = np.max( scores['struct_num'] )
251
+
252
+ nstructs_to_analyze = set([total_structs])
253
+ for x in range(10, total_structs):
254
+ if x % 10 == 0:
255
+ nstructs_to_analyze.add(x)
256
+ nstructs_to_analyze = sorted(nstructs_to_analyze)
257
+
258
+ for state in ['mut', 'wt']:
259
+ for nstructs in nstructs_to_analyze:
260
+ dg_scores = scores.loc[ (scores['state'].str.endswith(state)) & (scores['state'].str.startswith('unbound')) & (scores['struct_num'] <= nstructs) ].copy()
261
+ for column in dg_scores.columns:
262
+ if column not in ['state', 'case_name', 'backrub_steps', 'struct_num', 'score_function_name']:
263
+ dg_scores.loc[:,column] *= -1.0
264
+ dg_scores = pd.concat( [ dg_scores, scores.loc[ (scores['state'].str.endswith(state)) & (scores['state'].str.startswith('bound')) & (scores['struct_num'] <= nstructs) ].copy() ] )
265
+ dg_scores = dg_scores.groupby( ['case_name', 'backrub_steps', 'struct_num', 'score_function_name'] ).sum( numeric_only = True ).reset_index()
266
+ dg_scores = dg_scores.groupby( ['case_name', 'backrub_steps', 'score_function_name'] ).mean( numeric_only = True ).round(decimals=5).reset_index()
267
+ new_columns = list(dg_scores.columns.values)
268
+ new_columns.remove( 'struct_num' )
269
+ dg_scores = dg_scores[new_columns]
270
+ dg_scores[ 'scored_state' ] = state + '_dG'
271
+ dg_scores[ 'nstruct' ] = nstructs
272
+ l.append( dg_scores )
273
+ return l
274
+
275
+ def analyze_output_folder( output_folder, stride_override = None ):
276
+ # Pass in an outer output folder. Subdirectories are considered different mutation cases, with subdirectories of different structures.
277
+ finished_jobs = find_finished_jobs( output_folder )
278
+ if len(finished_jobs) == 0:
279
+ print( 'No finished jobs found' )
280
+ return
281
+
282
+ ddg_scores_dfs = []
283
+ struct_scores_dfs = []
284
+ per_chain_dfs = []
285
+ for finished_job, finished_structs in finished_jobs.items():
286
+ inner_scores_list = []
287
+ inner_per_chain_list = []
288
+ for finished_struct in finished_structs:
289
+ inner_scores, inner_per_chain = process_finished_struct( finished_struct, os.path.basename(finished_job), stride_override )
290
+ inner_scores_list.append( inner_scores )
291
+ if inner_per_chain is not None:
292
+ inner_per_chain_list.append( inner_per_chain )
293
+ scores = pd.concat( inner_scores_list )
294
+ if len(inner_per_chain_list) > 0:
295
+ per_chain_summary = calc_per_chain_ddg( pd.concat( inner_per_chain_list ) )
296
+ if per_chain_summary is not None:
297
+ per_chain_dfs.append( per_chain_summary )
298
+ ddg_scores, struct_scores = calc_ddg( scores )
299
+ struct_scores_dfs.append( struct_scores )
300
+ ddg_scores_dfs.append( ddg_scores )
301
+ ddg_scores_dfs.append( apply_zemu_gam(ddg_scores) )
302
+ ddg_scores_dfs.extend( calc_dgs( scores ) )
303
+
304
+ if not os.path.isdir(script_output_folder):
305
+ os.makedirs(script_output_folder)
306
+ basename = os.path.basename(output_folder)
307
+
308
+ pd.concat( struct_scores_dfs ).to_csv( os.path.join(script_output_folder, basename + '-struct_scores_results.csv' ) )
309
+
310
+ df = pd.concat( ddg_scores_dfs )
311
+ df.to_csv( os.path.join(script_output_folder, basename + '-results.csv') )
312
+
313
+ display_columns = ['backrub_steps', 'case_name', 'nstruct', 'score_function_name', 'scored_state', 'total_score']
314
+ for score_type in ['mut_dG', 'wt_dG', 'ddG']:
315
+ print( score_type )
316
+ print( df.loc[ df['scored_state'] == score_type ][display_columns].head( n = 20 ) )
317
+ print( '' )
318
+
319
+ if len(per_chain_dfs) > 0:
320
+ per_chain = pd.concat( per_chain_dfs )
321
+ per_chain.to_csv( os.path.join(script_output_folder, basename + '-per_chain_results.csv'), index = False )
322
+ print( 'per-chain intramolecular ddG (from the unbound states)' )
323
+ print( per_chain.head( n = 40 ).to_string(index = False) )
324
+ print( '' )
325
+ print( 'NOTE: this is the intramolecular strain difference in the *bound* backbone' )
326
+ print( ' conformation, not a folding ddG -- the unbound state is never relaxed.' )
327
+ print( ' A chain you did not mutate should come out at ~0 +/- ddG_sem; if it does' )
328
+ print( ' not, nstruct is too low to average out the whole-pose minimization noise.' )
329
+ print( '' )
330
+
331
+ if __name__ == '__main__':
332
+ parser = argparse.ArgumentParser(
333
+ description = 'Analyze one or more flex ddG output folders (e.g. "output").' )
334
+ parser.add_argument( 'output_folders', nargs = '+', help = 'flex ddG output folder(s)' )
335
+ parser.add_argument( '--stride', type = int, default = None,
336
+ help = 'override backrub_trajectory_stride instead of reading it from'
337
+ ' each ddG.db3. Affects checkpoint labels only, not any energy.' )
338
+ parsed_args = parser.parse_args()
339
+
340
+ for folder_to_analyze in parsed_args.output_folders:
341
+ if os.path.isdir( folder_to_analyze ):
342
+ analyze_output_folder( folder_to_analyze, parsed_args.stride )
343
+ else:
344
+ print( 'ERROR: %s is not a valid directory' % folder_to_analyze )
scripts/extract_structures.py ADDED
@@ -0,0 +1,262 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+
3
+ import os
4
+ import sys
5
+ import argparse
6
+ import functools
7
+ import subprocess
8
+ import re
9
+ import shutil
10
+ import datetime
11
+ import math
12
+ import collections
13
+ import threading
14
+
15
+ import flex_ddg_db3
16
+
17
+ use_multiprocessing = False
18
+ if use_multiprocessing:
19
+ import multiprocessing
20
+
21
+ # The Reporter class is useful for printing output for tasks which will take a long time
22
+ # Really, you should just use tqdm now, but I used this before I knew about tqdm and it removes a dependency
23
+
24
+ # Time in seconds function
25
+ # Converts datetime timedelta object to number of seconds
26
+ def ts(td):
27
+ return (td.microseconds + (td.seconds + td.days * 24 * 3600) * 1e6) / 1e6
28
+
29
+ def mean(l):
30
+ # Not using numpy mean to avoid dependency
31
+ return float( sum(l) ) / float( len(l) )
32
+
33
+ class Reporter:
34
+ def __init__( self, task, entries = 'files', print_output = True, eol_char = '\r' ):
35
+ self._lock = threading.Lock()
36
+ self.print_output = print_output
37
+ self.start = datetime.datetime.now()
38
+ self.entries = entries
39
+ self.lastreport = self.start
40
+ self.task = task
41
+ self.report_interval = datetime.timedelta( seconds = 1 ) # Interval to print progress
42
+ self.n = 0
43
+ self.completion_time = None
44
+ if self.print_output:
45
+ print('\nStarting ' + task)
46
+ self.total_count = None # Total tasks to be processed
47
+ self.maximum_output_string_length = 0
48
+ self.rolling_est_total_time = collections.deque( maxlen = 50 )
49
+ self.kv_callback_results = {}
50
+ self.list_results = []
51
+ self.eol_char = eol_char
52
+
53
+ def set_total_count(self, x):
54
+ self.total_count = x
55
+ self.rolling_est_total_time = collections.deque( maxlen = max(1, int( .05 * x )) )
56
+
57
+ def decrement_total_count(self):
58
+ if self.total_count:
59
+ self.total_count -= 1
60
+
61
+ def report(self, n):
62
+ with self._lock:
63
+ self.n = n
64
+ time_now = datetime.datetime.now()
65
+ if self.print_output and self.lastreport < (time_now - self.report_interval):
66
+ self.lastreport = time_now
67
+ if self.total_count:
68
+ percent_done = float(self.n) / float(self.total_count)
69
+ est_total_time_seconds = ts(time_now - self.start) * (1.0 / percent_done)
70
+ self.rolling_est_total_time.append( est_total_time_seconds )
71
+ est_total_time = datetime.timedelta( seconds = mean(self.rolling_est_total_time) )
72
+ time_remaining = est_total_time - (time_now - self.start)
73
+ eta = time_now + time_remaining
74
+ time_remaining_str = 'ETA: %s Est. time remaining: ' % eta.strftime("%Y-%m-%d %H:%M:%S")
75
+
76
+ time_remaining_str += str( datetime.timedelta( seconds = int(ts(time_remaining)) ) )
77
+
78
+ output_string = " Processed: %d %s (%.1f%%) %s" % (n, self.entries, percent_done*100.0, time_remaining_str)
79
+ else:
80
+ output_string = " Processed: %d %s" % (n, self.entries)
81
+
82
+ output_string += self.eol_char
83
+
84
+ if len(output_string) > self.maximum_output_string_length:
85
+ self.maximum_output_string_length = len(output_string)
86
+ elif len(output_string) < self.maximum_output_string_length:
87
+ output_string = output_string.ljust(self.maximum_output_string_length)
88
+ sys.stdout.write( output_string )
89
+ sys.stdout.flush()
90
+
91
+ def increment_report(self):
92
+ self.report(self.n + 1)
93
+
94
+ def increment_report_callback(self, cb_value):
95
+ self.increment_report()
96
+
97
+ def increment_report_keyval_callback(self, kv_pair):
98
+ key, value = kv_pair
99
+ self.kv_callback_results[key] = value
100
+ self.increment_report()
101
+
102
+ def increment_report_list_callback(self, new_list_items):
103
+ self.list_results.extend(new_list_items)
104
+ self.increment_report()
105
+
106
+ def decrement_report(self):
107
+ self.report(self.n - 1)
108
+
109
+ def add_to_report(self, x):
110
+ self.report(self.n + x)
111
+
112
+ def done(self):
113
+ self.completion_time = datetime.datetime.now()
114
+ if self.print_output:
115
+ print('Done %s, processed %d %s, took %s\n' % (self.task, self.n, self.entries, self.completion_time-self.start))
116
+
117
+ def elapsed_time(self):
118
+ if self.completion_time:
119
+ return self.completion_time - self.start
120
+ else:
121
+ return datetime.datetime.now() - self.start
122
+
123
+
124
+ struct_db3_file = 'struct.db3'
125
+
126
+ # Extraction uses the score_jd2 binary, not rosetta_scripts. It is built alongside
127
+ # rosetta_scripts by the standard Rosetta build, but is a separate executable.
128
+ #score_jd2_path = os.path.expanduser( '~/rosetta/source/bin/score_jd2' )
129
+ score_jd2_path = os.path.expanduser(
130
+ "/public/home/scnb9biwet/jiangqq/flex_ddG_tutorial-master/software/rosetta3.9/main/source/bin/score_jd2.default.linuxgccrelease"
131
+ )
132
+ # Only a fallback. Extracted structures are named by how many backrub steps produced them, so
133
+ # the stride each run used is read back out of its own struct.db3. This value is used only when
134
+ # the database does not record it, and a warning is printed.
135
+ default_trajectory_stride = 5
136
+
137
+ def resolve_trajectory_stride( struct_db, stride_override = None ):
138
+ '''Stride to name this database's extracted PDBs with, preferring what the run recorded.'''
139
+ if stride_override is not None:
140
+ return stride_override
141
+
142
+ stride = flex_ddg_db3.trajectory_stride_from_db3( struct_db )
143
+ if stride is not None:
144
+ return stride
145
+
146
+ print( 'WARNING: %s does not record backrub_trajectory_stride; assuming %d.' % (
147
+ struct_db, default_trajectory_stride ) )
148
+ print( ' If the run used a different stride, pass --stride, or the extracted PDBs' )
149
+ print( ' will be named with the wrong backrub step counts.' )
150
+ return default_trajectory_stride
151
+
152
+ def recursive_find_struct_dbs( input_dir ):
153
+ return_list = []
154
+
155
+ for path in [os.path.join(input_dir, x) for x in os.listdir( input_dir )]:
156
+ if os.path.isdir( path ):
157
+ return_list.extend( recursive_find_struct_dbs( path ) )
158
+ elif os.path.isfile( path ) and os.path.basename( path ) == struct_db3_file:
159
+ return_list.append( path )
160
+
161
+ return return_list
162
+
163
+ def extract_structures( struct_db, rename_function = None ):
164
+ args = [
165
+ os.path.abspath( score_jd2_path ),
166
+ '-inout:dbms:database_name', struct_db3_file,
167
+ '-in:use_database',
168
+ '-out:pdb',
169
+ ]
170
+
171
+ working_directory = os.path.dirname( struct_db )
172
+ rosetta_outfile_path = os.path.join(working_directory, 'structure_output.txt' )
173
+ if not use_multiprocessing:
174
+ print(rosetta_outfile_path)
175
+ rosetta_outfile = open( rosetta_outfile_path, 'w')
176
+ if not use_multiprocessing:
177
+ print( ' '.join( args ) )
178
+ # No shell: joining the arguments into a string breaks as soon as a path contains a space.
179
+ rosetta_process = subprocess.Popen(
180
+ args,
181
+ stdout=rosetta_outfile, stderr=subprocess.STDOUT, close_fds = True, cwd = working_directory,
182
+ )
183
+ return_code = rosetta_process.wait()
184
+ rosetta_outfile.close()
185
+
186
+ if return_code == 0:
187
+ os.remove( rosetta_outfile_path )
188
+ else:
189
+ print( 'ERROR: score_jd2 failed on %s (exit %d) -- see %s' % (
190
+ struct_db, return_code, rosetta_outfile_path ) )
191
+ return return_code
192
+
193
+ if rename_function != None:
194
+ for path in [ os.path.join( working_directory, x ) for x in os.listdir( working_directory ) ]:
195
+ m = re.match( r'(\d+)_0001\.pdb$', os.path.basename(path) )
196
+ if m:
197
+ dest_path = os.path.join( working_directory, rename_function( int(m.group(1)) ) )
198
+ shutil.move( path, dest_path )
199
+
200
+ return return_code
201
+
202
+ def flex_ddG_rename(struct_id, trajectory_stride):
203
+ steps = [
204
+ 'backrub',
205
+ 'wt',
206
+ 'mut',
207
+ ]
208
+
209
+ return '%s_%05d.pdb' % ( steps[ (struct_id-1) % len(steps) ], (((struct_id-1) // len(steps)) + 1) * trajectory_stride )
210
+
211
+ def main( input_dir, stride_override = None ):
212
+ struct_dbs = recursive_find_struct_dbs( input_dir )
213
+ print( 'Found {:d} structure database files to extract'.format( len(struct_dbs) ) )
214
+
215
+ if use_multiprocessing:
216
+ pool = multiprocessing.Pool()
217
+ r = Reporter('extracting structure database files', entries = '.db3 files')
218
+ r.set_total_count( len(struct_dbs) )
219
+
220
+ for struct_db in struct_dbs:
221
+ # Each database is named using the stride its own run was launched with.
222
+ # functools.partial rather than a lambda, so that this stays picklable for the
223
+ # multiprocessing path below.
224
+ stride = resolve_trajectory_stride( struct_db, stride_override )
225
+ rename_function = functools.partial( flex_ddG_rename, trajectory_stride = stride )
226
+ if use_multiprocessing:
227
+ pool.apply_async(
228
+ extract_structures,
229
+ args = (struct_db,),
230
+ kwds = {'rename_function' : rename_function},
231
+ callback = r.increment_report_callback
232
+ )
233
+ else:
234
+ r.increment_report_callback(
235
+ extract_structures( struct_db, rename_function = rename_function )
236
+ )
237
+
238
+ if use_multiprocessing:
239
+ pool.close()
240
+ pool.join()
241
+ r.done()
242
+
243
+ if __name__ == '__main__':
244
+ parser = argparse.ArgumentParser(
245
+ description = 'Extract PDBs from the struct.db3 files under a flex ddG output folder.' )
246
+ parser.add_argument( 'output_folders', nargs = '+', help = 'flex ddG output folder(s)' )
247
+ parser.add_argument( '--stride', type = int, default = None,
248
+ help = 'override backrub_trajectory_stride instead of reading it from'
249
+ ' each struct.db3. Affects extracted PDB names only.' )
250
+ parsed_args = parser.parse_args()
251
+
252
+ if not os.path.isfile( score_jd2_path ):
253
+ print( 'ERROR: "score_jd2_path" variable must be set to the location of the "score_jd2" binary executable' )
254
+ print( 'This file might look something like: "score_jd2.linuxgccrelease"' )
255
+ print( 'Note that this is a different executable from the "rosetta_scripts" binary used to run flex ddG' )
256
+ raise Exception( 'score_jd2 missing' )
257
+
258
+ for x in parsed_args.output_folders:
259
+ if os.path.isdir(x):
260
+ main( x, parsed_args.stride )
261
+ else:
262
+ print( 'ERROR: %s is not a valid directory' % x )
scripts/flex_ddg_db3.py ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+
3
+ '''Small helpers shared by analyze_flex_ddG.py and extract_structures.py.
4
+
5
+ Standard library only, so that extract_structures.py keeps running without numpy or pandas.
6
+ '''
7
+
8
+ import re
9
+ import sqlite3
10
+
11
+ # Rosetta records the full option list it was invoked with in the "protocols" table of every
12
+ # features database it writes, so the stride a run actually used can be read back out of the
13
+ # output instead of being remembered and re-typed by hand.
14
+ _stride_re = re.compile( r'backrub_trajectory_stride[= ]+(\d+)' )
15
+
16
+ def trajectory_stride_from_db3( db3_file ):
17
+ '''The backrub_trajectory_stride the run in db3_file was launched with.
18
+
19
+ Returns None if it cannot be determined, which happens for databases written by Rosetta
20
+ versions that predate the protocols table, or if the stride was left at the XML default
21
+ instead of being passed on the command line. Callers should fall back to a default and say
22
+ so, because the stride does not affect any energy -- it only labels the checkpoints, so a
23
+ wrong value silently mislabels every row (and misnames every extracted PDB) rather than
24
+ causing a visible failure.
25
+ '''
26
+ try:
27
+ conn = sqlite3.connect( 'file:%s?mode=ro' % db3_file, uri = True )
28
+ except sqlite3.Error:
29
+ return None
30
+
31
+ try:
32
+ try:
33
+ rows = conn.execute( 'SELECT specified_options, command_line FROM protocols' ).fetchall()
34
+ except sqlite3.Error:
35
+ return None
36
+
37
+ strides = set()
38
+ for row in rows:
39
+ for field in row:
40
+ if field:
41
+ strides.update( int(m) for m in _stride_re.findall( field ) )
42
+ finally:
43
+ conn.close()
44
+
45
+ # More than one distinct value means the database mixes runs; we cannot label it correctly.
46
+ if len( strides ) == 1:
47
+ return strides.pop()
48
+ return None
scripts/inputs/1JTG/1JTG_AB.pdb ADDED
The diff for this file is too large to render. See raw diff
 
scripts/inputs/1JTG/chains_to_move.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ B
scripts/inputs/1JTG/mutations.mutfile ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ total 4
2
+ 4
3
+ N 351 K
4
+ D 397 K
5
+ D 425 K
6
+ V 427 K
scripts/inputs/1JTG/mutations.resfile ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ NATRO
2
+ start
3
+ 135 B PIKAA K
4
+ 163 B PIKAA K
5
+ 165 B PIKAA K
6
+ 89 B PIKAA K
scripts/inputs/1JTG/nataa_mutations.resfile ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ NATAA
2
+ start
3
+ 135 B PIKAA K
4
+ 163 B PIKAA K
5
+ 165 B PIKAA K
6
+ 89 B PIKAA K
scripts/inputs/1JTG/pdb2rosetta.resmap.json ADDED
@@ -0,0 +1,429 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "A 26 ": 1,
3
+ "A 27 ": 2,
4
+ "A 28 ": 3,
5
+ "A 29 ": 4,
6
+ "A 30 ": 5,
7
+ "A 31 ": 6,
8
+ "A 32 ": 7,
9
+ "A 33 ": 8,
10
+ "A 34 ": 9,
11
+ "A 35 ": 10,
12
+ "A 36 ": 11,
13
+ "A 37 ": 12,
14
+ "A 38 ": 13,
15
+ "A 39 ": 14,
16
+ "A 40 ": 15,
17
+ "A 41 ": 16,
18
+ "A 42 ": 17,
19
+ "A 43 ": 18,
20
+ "A 44 ": 19,
21
+ "A 45 ": 20,
22
+ "A 46 ": 21,
23
+ "A 47 ": 22,
24
+ "A 48 ": 23,
25
+ "A 49 ": 24,
26
+ "A 50 ": 25,
27
+ "A 51 ": 26,
28
+ "A 52 ": 27,
29
+ "A 53 ": 28,
30
+ "A 54 ": 29,
31
+ "A 55 ": 30,
32
+ "A 56 ": 31,
33
+ "A 57 ": 32,
34
+ "A 58 ": 33,
35
+ "A 59 ": 34,
36
+ "A 60 ": 35,
37
+ "A 61 ": 36,
38
+ "A 62 ": 37,
39
+ "A 63 ": 38,
40
+ "A 64 ": 39,
41
+ "A 65 ": 40,
42
+ "A 66 ": 41,
43
+ "A 67 ": 42,
44
+ "A 68 ": 43,
45
+ "A 69 ": 44,
46
+ "A 70 ": 45,
47
+ "A 71 ": 46,
48
+ "A 72 ": 47,
49
+ "A 73 ": 48,
50
+ "A 74 ": 49,
51
+ "A 75 ": 50,
52
+ "A 76 ": 51,
53
+ "A 77 ": 52,
54
+ "A 78 ": 53,
55
+ "A 79 ": 54,
56
+ "A 80 ": 55,
57
+ "A 81 ": 56,
58
+ "A 82 ": 57,
59
+ "A 83 ": 58,
60
+ "A 84 ": 59,
61
+ "A 85 ": 60,
62
+ "A 86 ": 61,
63
+ "A 87 ": 62,
64
+ "A 88 ": 63,
65
+ "A 89 ": 64,
66
+ "A 90 ": 65,
67
+ "A 91 ": 66,
68
+ "A 92 ": 67,
69
+ "A 93 ": 68,
70
+ "A 94 ": 69,
71
+ "A 95 ": 70,
72
+ "A 96 ": 71,
73
+ "A 97 ": 72,
74
+ "A 98 ": 73,
75
+ "A 99 ": 74,
76
+ "A 100 ": 75,
77
+ "A 101 ": 76,
78
+ "A 102 ": 77,
79
+ "A 103 ": 78,
80
+ "A 104 ": 79,
81
+ "A 105 ": 80,
82
+ "A 106 ": 81,
83
+ "A 107 ": 82,
84
+ "A 108 ": 83,
85
+ "A 109 ": 84,
86
+ "A 110 ": 85,
87
+ "A 111 ": 86,
88
+ "A 112 ": 87,
89
+ "A 113 ": 88,
90
+ "A 114 ": 89,
91
+ "A 115 ": 90,
92
+ "A 116 ": 91,
93
+ "A 117 ": 92,
94
+ "A 118 ": 93,
95
+ "A 119 ": 94,
96
+ "A 120 ": 95,
97
+ "A 121 ": 96,
98
+ "A 122 ": 97,
99
+ "A 123 ": 98,
100
+ "A 124 ": 99,
101
+ "A 125 ": 100,
102
+ "A 126 ": 101,
103
+ "A 127 ": 102,
104
+ "A 128 ": 103,
105
+ "A 129 ": 104,
106
+ "A 130 ": 105,
107
+ "A 131 ": 106,
108
+ "A 132 ": 107,
109
+ "A 133 ": 108,
110
+ "A 134 ": 109,
111
+ "A 135 ": 110,
112
+ "A 136 ": 111,
113
+ "A 137 ": 112,
114
+ "A 138 ": 113,
115
+ "A 139 ": 114,
116
+ "A 140 ": 115,
117
+ "A 141 ": 116,
118
+ "A 142 ": 117,
119
+ "A 143 ": 118,
120
+ "A 144 ": 119,
121
+ "A 145 ": 120,
122
+ "A 146 ": 121,
123
+ "A 147 ": 122,
124
+ "A 148 ": 123,
125
+ "A 149 ": 124,
126
+ "A 150 ": 125,
127
+ "A 151 ": 126,
128
+ "A 152 ": 127,
129
+ "A 153 ": 128,
130
+ "A 154 ": 129,
131
+ "A 155 ": 130,
132
+ "A 156 ": 131,
133
+ "A 157 ": 132,
134
+ "A 158 ": 133,
135
+ "A 159 ": 134,
136
+ "A 160 ": 135,
137
+ "A 161 ": 136,
138
+ "A 162 ": 137,
139
+ "A 163 ": 138,
140
+ "A 164 ": 139,
141
+ "A 165 ": 140,
142
+ "A 166 ": 141,
143
+ "A 167 ": 142,
144
+ "A 168 ": 143,
145
+ "A 169 ": 144,
146
+ "A 170 ": 145,
147
+ "A 171 ": 146,
148
+ "A 172 ": 147,
149
+ "A 173 ": 148,
150
+ "A 174 ": 149,
151
+ "A 175 ": 150,
152
+ "A 176 ": 151,
153
+ "A 177 ": 152,
154
+ "A 178 ": 153,
155
+ "A 179 ": 154,
156
+ "A 180 ": 155,
157
+ "A 181 ": 156,
158
+ "A 182 ": 157,
159
+ "A 183 ": 158,
160
+ "A 184 ": 159,
161
+ "A 185 ": 160,
162
+ "A 186 ": 161,
163
+ "A 187 ": 162,
164
+ "A 188 ": 163,
165
+ "A 189 ": 164,
166
+ "A 190 ": 165,
167
+ "A 191 ": 166,
168
+ "A 192 ": 167,
169
+ "A 193 ": 168,
170
+ "A 194 ": 169,
171
+ "A 195 ": 170,
172
+ "A 196 ": 171,
173
+ "A 197 ": 172,
174
+ "A 198 ": 173,
175
+ "A 199 ": 174,
176
+ "A 200 ": 175,
177
+ "A 201 ": 176,
178
+ "A 202 ": 177,
179
+ "A 203 ": 178,
180
+ "A 204 ": 179,
181
+ "A 205 ": 180,
182
+ "A 206 ": 181,
183
+ "A 207 ": 182,
184
+ "A 208 ": 183,
185
+ "A 209 ": 184,
186
+ "A 210 ": 185,
187
+ "A 211 ": 186,
188
+ "A 212 ": 187,
189
+ "A 213 ": 188,
190
+ "A 215 ": 189,
191
+ "A 216 ": 190,
192
+ "A 217 ": 191,
193
+ "A 218 ": 192,
194
+ "A 219 ": 193,
195
+ "A 220 ": 194,
196
+ "A 221 ": 195,
197
+ "A 222 ": 196,
198
+ "A 223 ": 197,
199
+ "A 224 ": 198,
200
+ "A 225 ": 199,
201
+ "A 226 ": 200,
202
+ "A 227 ": 201,
203
+ "A 228 ": 202,
204
+ "A 229 ": 203,
205
+ "A 230 ": 204,
206
+ "A 231 ": 205,
207
+ "A 232 ": 206,
208
+ "A 233 ": 207,
209
+ "A 234 ": 208,
210
+ "A 235 ": 209,
211
+ "A 236 ": 210,
212
+ "A 237 ": 211,
213
+ "A 238 ": 212,
214
+ "A 239 ": 213,
215
+ "A 240 ": 214,
216
+ "A 241 ": 215,
217
+ "A 242 ": 216,
218
+ "A 243 ": 217,
219
+ "A 244 ": 218,
220
+ "A 245 ": 219,
221
+ "A 246 ": 220,
222
+ "A 247 ": 221,
223
+ "A 248 ": 222,
224
+ "A 249 ": 223,
225
+ "A 250 ": 224,
226
+ "A 251 ": 225,
227
+ "A 252 ": 226,
228
+ "A 253 ": 227,
229
+ "A 254 ": 228,
230
+ "A 255 ": 229,
231
+ "A 256 ": 230,
232
+ "A 257 ": 231,
233
+ "A 258 ": 232,
234
+ "A 259 ": 233,
235
+ "A 260 ": 234,
236
+ "A 261 ": 235,
237
+ "A 262 ": 236,
238
+ "A 263 ": 237,
239
+ "A 264 ": 238,
240
+ "A 265 ": 239,
241
+ "A 266 ": 240,
242
+ "A 267 ": 241,
243
+ "A 268 ": 242,
244
+ "A 269 ": 243,
245
+ "A 270 ": 244,
246
+ "A 271 ": 245,
247
+ "A 272 ": 246,
248
+ "A 273 ": 247,
249
+ "A 274 ": 248,
250
+ "A 275 ": 249,
251
+ "A 276 ": 250,
252
+ "A 277 ": 251,
253
+ "A 278 ": 252,
254
+ "A 279 ": 253,
255
+ "A 280 ": 254,
256
+ "A 281 ": 255,
257
+ "A 282 ": 256,
258
+ "A 283 ": 257,
259
+ "A 284 ": 258,
260
+ "A 285 ": 259,
261
+ "A 286 ": 260,
262
+ "A 287 ": 261,
263
+ "A 288 ": 262,
264
+ "B 1 ": 263,
265
+ "B 2 ": 264,
266
+ "B 3 ": 265,
267
+ "B 4 ": 266,
268
+ "B 5 ": 267,
269
+ "B 6 ": 268,
270
+ "B 7 ": 269,
271
+ "B 8 ": 270,
272
+ "B 9 ": 271,
273
+ "B 10 ": 272,
274
+ "B 11 ": 273,
275
+ "B 12 ": 274,
276
+ "B 13 ": 275,
277
+ "B 14 ": 276,
278
+ "B 15 ": 277,
279
+ "B 16 ": 278,
280
+ "B 17 ": 279,
281
+ "B 18 ": 280,
282
+ "B 19 ": 281,
283
+ "B 20 ": 282,
284
+ "B 21 ": 283,
285
+ "B 22 ": 284,
286
+ "B 23 ": 285,
287
+ "B 24 ": 286,
288
+ "B 25 ": 287,
289
+ "B 26 ": 288,
290
+ "B 27 ": 289,
291
+ "B 28 ": 290,
292
+ "B 29 ": 291,
293
+ "B 30 ": 292,
294
+ "B 31 ": 293,
295
+ "B 32 ": 294,
296
+ "B 33 ": 295,
297
+ "B 34 ": 296,
298
+ "B 35 ": 297,
299
+ "B 36 ": 298,
300
+ "B 37 ": 299,
301
+ "B 38 ": 300,
302
+ "B 39 ": 301,
303
+ "B 40 ": 302,
304
+ "B 41 ": 303,
305
+ "B 42 ": 304,
306
+ "B 43 ": 305,
307
+ "B 44 ": 306,
308
+ "B 45 ": 307,
309
+ "B 46 ": 308,
310
+ "B 47 ": 309,
311
+ "B 48 ": 310,
312
+ "B 49 ": 311,
313
+ "B 50 ": 312,
314
+ "B 51 ": 313,
315
+ "B 52 ": 314,
316
+ "B 53 ": 315,
317
+ "B 54 ": 316,
318
+ "B 55 ": 317,
319
+ "B 56 ": 318,
320
+ "B 57 ": 319,
321
+ "B 58 ": 320,
322
+ "B 59 ": 321,
323
+ "B 60 ": 322,
324
+ "B 61 ": 323,
325
+ "B 62 ": 324,
326
+ "B 63 ": 325,
327
+ "B 64 ": 326,
328
+ "B 65 ": 327,
329
+ "B 66 ": 328,
330
+ "B 67 ": 329,
331
+ "B 68 ": 330,
332
+ "B 69 ": 331,
333
+ "B 70 ": 332,
334
+ "B 71 ": 333,
335
+ "B 72 ": 334,
336
+ "B 73 ": 335,
337
+ "B 74 ": 336,
338
+ "B 75 ": 337,
339
+ "B 76 ": 338,
340
+ "B 77 ": 339,
341
+ "B 78 ": 340,
342
+ "B 79 ": 341,
343
+ "B 80 ": 342,
344
+ "B 81 ": 343,
345
+ "B 82 ": 344,
346
+ "B 83 ": 345,
347
+ "B 84 ": 346,
348
+ "B 85 ": 347,
349
+ "B 86 ": 348,
350
+ "B 87 ": 349,
351
+ "B 88 ": 350,
352
+ "B 89 ": 351,
353
+ "B 90 ": 352,
354
+ "B 91 ": 353,
355
+ "B 92 ": 354,
356
+ "B 93 ": 355,
357
+ "B 94 ": 356,
358
+ "B 95 ": 357,
359
+ "B 96 ": 358,
360
+ "B 97 ": 359,
361
+ "B 98 ": 360,
362
+ "B 99 ": 361,
363
+ "B 100 ": 362,
364
+ "B 101 ": 363,
365
+ "B 102 ": 364,
366
+ "B 103 ": 365,
367
+ "B 104 ": 366,
368
+ "B 105 ": 367,
369
+ "B 106 ": 368,
370
+ "B 107 ": 369,
371
+ "B 108 ": 370,
372
+ "B 109 ": 371,
373
+ "B 110 ": 372,
374
+ "B 111 ": 373,
375
+ "B 112 ": 374,
376
+ "B 113 ": 375,
377
+ "B 114 ": 376,
378
+ "B 115 ": 377,
379
+ "B 116 ": 378,
380
+ "B 117 ": 379,
381
+ "B 118 ": 380,
382
+ "B 119 ": 381,
383
+ "B 120 ": 382,
384
+ "B 121 ": 383,
385
+ "B 122 ": 384,
386
+ "B 123 ": 385,
387
+ "B 124 ": 386,
388
+ "B 125 ": 387,
389
+ "B 126 ": 388,
390
+ "B 127 ": 389,
391
+ "B 128 ": 390,
392
+ "B 129 ": 391,
393
+ "B 130 ": 392,
394
+ "B 131 ": 393,
395
+ "B 132 ": 394,
396
+ "B 133 ": 395,
397
+ "B 134 ": 396,
398
+ "B 135 ": 397,
399
+ "B 136 ": 398,
400
+ "B 137 ": 399,
401
+ "B 138 ": 400,
402
+ "B 139 ": 401,
403
+ "B 140 ": 402,
404
+ "B 141 ": 403,
405
+ "B 142 ": 404,
406
+ "B 143 ": 405,
407
+ "B 144 ": 406,
408
+ "B 145 ": 407,
409
+ "B 146 ": 408,
410
+ "B 147 ": 409,
411
+ "B 148 ": 410,
412
+ "B 149 ": 411,
413
+ "B 150 ": 412,
414
+ "B 151 ": 413,
415
+ "B 152 ": 414,
416
+ "B 153 ": 415,
417
+ "B 154 ": 416,
418
+ "B 155 ": 417,
419
+ "B 156 ": 418,
420
+ "B 157 ": 419,
421
+ "B 158 ": 420,
422
+ "B 159 ": 421,
423
+ "B 160 ": 422,
424
+ "B 161 ": 423,
425
+ "B 162 ": 424,
426
+ "B 163 ": 425,
427
+ "B 164 ": 426,
428
+ "B 165 ": 427
429
+ }
scripts/inputs/1JTG/rosetta2pdb.resmap.json ADDED
@@ -0,0 +1,429 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "1": "A 26 ",
3
+ "2": "A 27 ",
4
+ "3": "A 28 ",
5
+ "4": "A 29 ",
6
+ "5": "A 30 ",
7
+ "6": "A 31 ",
8
+ "7": "A 32 ",
9
+ "8": "A 33 ",
10
+ "9": "A 34 ",
11
+ "10": "A 35 ",
12
+ "11": "A 36 ",
13
+ "12": "A 37 ",
14
+ "13": "A 38 ",
15
+ "14": "A 39 ",
16
+ "15": "A 40 ",
17
+ "16": "A 41 ",
18
+ "17": "A 42 ",
19
+ "18": "A 43 ",
20
+ "19": "A 44 ",
21
+ "20": "A 45 ",
22
+ "21": "A 46 ",
23
+ "22": "A 47 ",
24
+ "23": "A 48 ",
25
+ "24": "A 49 ",
26
+ "25": "A 50 ",
27
+ "26": "A 51 ",
28
+ "27": "A 52 ",
29
+ "28": "A 53 ",
30
+ "29": "A 54 ",
31
+ "30": "A 55 ",
32
+ "31": "A 56 ",
33
+ "32": "A 57 ",
34
+ "33": "A 58 ",
35
+ "34": "A 59 ",
36
+ "35": "A 60 ",
37
+ "36": "A 61 ",
38
+ "37": "A 62 ",
39
+ "38": "A 63 ",
40
+ "39": "A 64 ",
41
+ "40": "A 65 ",
42
+ "41": "A 66 ",
43
+ "42": "A 67 ",
44
+ "43": "A 68 ",
45
+ "44": "A 69 ",
46
+ "45": "A 70 ",
47
+ "46": "A 71 ",
48
+ "47": "A 72 ",
49
+ "48": "A 73 ",
50
+ "49": "A 74 ",
51
+ "50": "A 75 ",
52
+ "51": "A 76 ",
53
+ "52": "A 77 ",
54
+ "53": "A 78 ",
55
+ "54": "A 79 ",
56
+ "55": "A 80 ",
57
+ "56": "A 81 ",
58
+ "57": "A 82 ",
59
+ "58": "A 83 ",
60
+ "59": "A 84 ",
61
+ "60": "A 85 ",
62
+ "61": "A 86 ",
63
+ "62": "A 87 ",
64
+ "63": "A 88 ",
65
+ "64": "A 89 ",
66
+ "65": "A 90 ",
67
+ "66": "A 91 ",
68
+ "67": "A 92 ",
69
+ "68": "A 93 ",
70
+ "69": "A 94 ",
71
+ "70": "A 95 ",
72
+ "71": "A 96 ",
73
+ "72": "A 97 ",
74
+ "73": "A 98 ",
75
+ "74": "A 99 ",
76
+ "75": "A 100 ",
77
+ "76": "A 101 ",
78
+ "77": "A 102 ",
79
+ "78": "A 103 ",
80
+ "79": "A 104 ",
81
+ "80": "A 105 ",
82
+ "81": "A 106 ",
83
+ "82": "A 107 ",
84
+ "83": "A 108 ",
85
+ "84": "A 109 ",
86
+ "85": "A 110 ",
87
+ "86": "A 111 ",
88
+ "87": "A 112 ",
89
+ "88": "A 113 ",
90
+ "89": "A 114 ",
91
+ "90": "A 115 ",
92
+ "91": "A 116 ",
93
+ "92": "A 117 ",
94
+ "93": "A 118 ",
95
+ "94": "A 119 ",
96
+ "95": "A 120 ",
97
+ "96": "A 121 ",
98
+ "97": "A 122 ",
99
+ "98": "A 123 ",
100
+ "99": "A 124 ",
101
+ "100": "A 125 ",
102
+ "101": "A 126 ",
103
+ "102": "A 127 ",
104
+ "103": "A 128 ",
105
+ "104": "A 129 ",
106
+ "105": "A 130 ",
107
+ "106": "A 131 ",
108
+ "107": "A 132 ",
109
+ "108": "A 133 ",
110
+ "109": "A 134 ",
111
+ "110": "A 135 ",
112
+ "111": "A 136 ",
113
+ "112": "A 137 ",
114
+ "113": "A 138 ",
115
+ "114": "A 139 ",
116
+ "115": "A 140 ",
117
+ "116": "A 141 ",
118
+ "117": "A 142 ",
119
+ "118": "A 143 ",
120
+ "119": "A 144 ",
121
+ "120": "A 145 ",
122
+ "121": "A 146 ",
123
+ "122": "A 147 ",
124
+ "123": "A 148 ",
125
+ "124": "A 149 ",
126
+ "125": "A 150 ",
127
+ "126": "A 151 ",
128
+ "127": "A 152 ",
129
+ "128": "A 153 ",
130
+ "129": "A 154 ",
131
+ "130": "A 155 ",
132
+ "131": "A 156 ",
133
+ "132": "A 157 ",
134
+ "133": "A 158 ",
135
+ "134": "A 159 ",
136
+ "135": "A 160 ",
137
+ "136": "A 161 ",
138
+ "137": "A 162 ",
139
+ "138": "A 163 ",
140
+ "139": "A 164 ",
141
+ "140": "A 165 ",
142
+ "141": "A 166 ",
143
+ "142": "A 167 ",
144
+ "143": "A 168 ",
145
+ "144": "A 169 ",
146
+ "145": "A 170 ",
147
+ "146": "A 171 ",
148
+ "147": "A 172 ",
149
+ "148": "A 173 ",
150
+ "149": "A 174 ",
151
+ "150": "A 175 ",
152
+ "151": "A 176 ",
153
+ "152": "A 177 ",
154
+ "153": "A 178 ",
155
+ "154": "A 179 ",
156
+ "155": "A 180 ",
157
+ "156": "A 181 ",
158
+ "157": "A 182 ",
159
+ "158": "A 183 ",
160
+ "159": "A 184 ",
161
+ "160": "A 185 ",
162
+ "161": "A 186 ",
163
+ "162": "A 187 ",
164
+ "163": "A 188 ",
165
+ "164": "A 189 ",
166
+ "165": "A 190 ",
167
+ "166": "A 191 ",
168
+ "167": "A 192 ",
169
+ "168": "A 193 ",
170
+ "169": "A 194 ",
171
+ "170": "A 195 ",
172
+ "171": "A 196 ",
173
+ "172": "A 197 ",
174
+ "173": "A 198 ",
175
+ "174": "A 199 ",
176
+ "175": "A 200 ",
177
+ "176": "A 201 ",
178
+ "177": "A 202 ",
179
+ "178": "A 203 ",
180
+ "179": "A 204 ",
181
+ "180": "A 205 ",
182
+ "181": "A 206 ",
183
+ "182": "A 207 ",
184
+ "183": "A 208 ",
185
+ "184": "A 209 ",
186
+ "185": "A 210 ",
187
+ "186": "A 211 ",
188
+ "187": "A 212 ",
189
+ "188": "A 213 ",
190
+ "189": "A 215 ",
191
+ "190": "A 216 ",
192
+ "191": "A 217 ",
193
+ "192": "A 218 ",
194
+ "193": "A 219 ",
195
+ "194": "A 220 ",
196
+ "195": "A 221 ",
197
+ "196": "A 222 ",
198
+ "197": "A 223 ",
199
+ "198": "A 224 ",
200
+ "199": "A 225 ",
201
+ "200": "A 226 ",
202
+ "201": "A 227 ",
203
+ "202": "A 228 ",
204
+ "203": "A 229 ",
205
+ "204": "A 230 ",
206
+ "205": "A 231 ",
207
+ "206": "A 232 ",
208
+ "207": "A 233 ",
209
+ "208": "A 234 ",
210
+ "209": "A 235 ",
211
+ "210": "A 236 ",
212
+ "211": "A 237 ",
213
+ "212": "A 238 ",
214
+ "213": "A 239 ",
215
+ "214": "A 240 ",
216
+ "215": "A 241 ",
217
+ "216": "A 242 ",
218
+ "217": "A 243 ",
219
+ "218": "A 244 ",
220
+ "219": "A 245 ",
221
+ "220": "A 246 ",
222
+ "221": "A 247 ",
223
+ "222": "A 248 ",
224
+ "223": "A 249 ",
225
+ "224": "A 250 ",
226
+ "225": "A 251 ",
227
+ "226": "A 252 ",
228
+ "227": "A 253 ",
229
+ "228": "A 254 ",
230
+ "229": "A 255 ",
231
+ "230": "A 256 ",
232
+ "231": "A 257 ",
233
+ "232": "A 258 ",
234
+ "233": "A 259 ",
235
+ "234": "A 260 ",
236
+ "235": "A 261 ",
237
+ "236": "A 262 ",
238
+ "237": "A 263 ",
239
+ "238": "A 264 ",
240
+ "239": "A 265 ",
241
+ "240": "A 266 ",
242
+ "241": "A 267 ",
243
+ "242": "A 268 ",
244
+ "243": "A 269 ",
245
+ "244": "A 270 ",
246
+ "245": "A 271 ",
247
+ "246": "A 272 ",
248
+ "247": "A 273 ",
249
+ "248": "A 274 ",
250
+ "249": "A 275 ",
251
+ "250": "A 276 ",
252
+ "251": "A 277 ",
253
+ "252": "A 278 ",
254
+ "253": "A 279 ",
255
+ "254": "A 280 ",
256
+ "255": "A 281 ",
257
+ "256": "A 282 ",
258
+ "257": "A 283 ",
259
+ "258": "A 284 ",
260
+ "259": "A 285 ",
261
+ "260": "A 286 ",
262
+ "261": "A 287 ",
263
+ "262": "A 288 ",
264
+ "263": "B 1 ",
265
+ "264": "B 2 ",
266
+ "265": "B 3 ",
267
+ "266": "B 4 ",
268
+ "267": "B 5 ",
269
+ "268": "B 6 ",
270
+ "269": "B 7 ",
271
+ "270": "B 8 ",
272
+ "271": "B 9 ",
273
+ "272": "B 10 ",
274
+ "273": "B 11 ",
275
+ "274": "B 12 ",
276
+ "275": "B 13 ",
277
+ "276": "B 14 ",
278
+ "277": "B 15 ",
279
+ "278": "B 16 ",
280
+ "279": "B 17 ",
281
+ "280": "B 18 ",
282
+ "281": "B 19 ",
283
+ "282": "B 20 ",
284
+ "283": "B 21 ",
285
+ "284": "B 22 ",
286
+ "285": "B 23 ",
287
+ "286": "B 24 ",
288
+ "287": "B 25 ",
289
+ "288": "B 26 ",
290
+ "289": "B 27 ",
291
+ "290": "B 28 ",
292
+ "291": "B 29 ",
293
+ "292": "B 30 ",
294
+ "293": "B 31 ",
295
+ "294": "B 32 ",
296
+ "295": "B 33 ",
297
+ "296": "B 34 ",
298
+ "297": "B 35 ",
299
+ "298": "B 36 ",
300
+ "299": "B 37 ",
301
+ "300": "B 38 ",
302
+ "301": "B 39 ",
303
+ "302": "B 40 ",
304
+ "303": "B 41 ",
305
+ "304": "B 42 ",
306
+ "305": "B 43 ",
307
+ "306": "B 44 ",
308
+ "307": "B 45 ",
309
+ "308": "B 46 ",
310
+ "309": "B 47 ",
311
+ "310": "B 48 ",
312
+ "311": "B 49 ",
313
+ "312": "B 50 ",
314
+ "313": "B 51 ",
315
+ "314": "B 52 ",
316
+ "315": "B 53 ",
317
+ "316": "B 54 ",
318
+ "317": "B 55 ",
319
+ "318": "B 56 ",
320
+ "319": "B 57 ",
321
+ "320": "B 58 ",
322
+ "321": "B 59 ",
323
+ "322": "B 60 ",
324
+ "323": "B 61 ",
325
+ "324": "B 62 ",
326
+ "325": "B 63 ",
327
+ "326": "B 64 ",
328
+ "327": "B 65 ",
329
+ "328": "B 66 ",
330
+ "329": "B 67 ",
331
+ "330": "B 68 ",
332
+ "331": "B 69 ",
333
+ "332": "B 70 ",
334
+ "333": "B 71 ",
335
+ "334": "B 72 ",
336
+ "335": "B 73 ",
337
+ "336": "B 74 ",
338
+ "337": "B 75 ",
339
+ "338": "B 76 ",
340
+ "339": "B 77 ",
341
+ "340": "B 78 ",
342
+ "341": "B 79 ",
343
+ "342": "B 80 ",
344
+ "343": "B 81 ",
345
+ "344": "B 82 ",
346
+ "345": "B 83 ",
347
+ "346": "B 84 ",
348
+ "347": "B 85 ",
349
+ "348": "B 86 ",
350
+ "349": "B 87 ",
351
+ "350": "B 88 ",
352
+ "351": "B 89 ",
353
+ "352": "B 90 ",
354
+ "353": "B 91 ",
355
+ "354": "B 92 ",
356
+ "355": "B 93 ",
357
+ "356": "B 94 ",
358
+ "357": "B 95 ",
359
+ "358": "B 96 ",
360
+ "359": "B 97 ",
361
+ "360": "B 98 ",
362
+ "361": "B 99 ",
363
+ "362": "B 100 ",
364
+ "363": "B 101 ",
365
+ "364": "B 102 ",
366
+ "365": "B 103 ",
367
+ "366": "B 104 ",
368
+ "367": "B 105 ",
369
+ "368": "B 106 ",
370
+ "369": "B 107 ",
371
+ "370": "B 108 ",
372
+ "371": "B 109 ",
373
+ "372": "B 110 ",
374
+ "373": "B 111 ",
375
+ "374": "B 112 ",
376
+ "375": "B 113 ",
377
+ "376": "B 114 ",
378
+ "377": "B 115 ",
379
+ "378": "B 116 ",
380
+ "379": "B 117 ",
381
+ "380": "B 118 ",
382
+ "381": "B 119 ",
383
+ "382": "B 120 ",
384
+ "383": "B 121 ",
385
+ "384": "B 122 ",
386
+ "385": "B 123 ",
387
+ "386": "B 124 ",
388
+ "387": "B 125 ",
389
+ "388": "B 126 ",
390
+ "389": "B 127 ",
391
+ "390": "B 128 ",
392
+ "391": "B 129 ",
393
+ "392": "B 130 ",
394
+ "393": "B 131 ",
395
+ "394": "B 132 ",
396
+ "395": "B 133 ",
397
+ "396": "B 134 ",
398
+ "397": "B 135 ",
399
+ "398": "B 136 ",
400
+ "399": "B 137 ",
401
+ "400": "B 138 ",
402
+ "401": "B 139 ",
403
+ "402": "B 140 ",
404
+ "403": "B 141 ",
405
+ "404": "B 142 ",
406
+ "405": "B 143 ",
407
+ "406": "B 144 ",
408
+ "407": "B 145 ",
409
+ "408": "B 146 ",
410
+ "409": "B 147 ",
411
+ "410": "B 148 ",
412
+ "411": "B 149 ",
413
+ "412": "B 150 ",
414
+ "413": "B 151 ",
415
+ "414": "B 152 ",
416
+ "415": "B 153 ",
417
+ "416": "B 154 ",
418
+ "417": "B 155 ",
419
+ "418": "B 156 ",
420
+ "419": "B 157 ",
421
+ "420": "B 158 ",
422
+ "421": "B 159 ",
423
+ "422": "B 160 ",
424
+ "423": "B 161 ",
425
+ "424": "B 162 ",
426
+ "425": "B 163 ",
427
+ "426": "B 164 ",
428
+ "427": "B 165 "
429
+ }
scripts/per_chain_protocol.py ADDED
@@ -0,0 +1,116 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ Generate a copy of ddG-backrub.xml that additionally reports per-chain energies.
4
+
5
+ Why
6
+ ---
7
+ The `unbound_wt` / `unbound_mut` totals in ddG.db3 are whole-pose scores. InterfaceDdGMover
8
+ builds the unbound state by rigid-body translating the moving chain(s) 1000 A apart, without
9
+ repacking or re-minimizing, and every chain stays in the pose
10
+ (protocols/features/InterfaceDdGMover.cc::unbind). So
11
+
12
+ unbound_X_total = sum over chains of intra(chain) for X in {wt, mut}
13
+
14
+ and `unbound_mut - unbound_wt` is the summed intramolecular ddG of *every* chain, including
15
+ the ones that were never mutated. Those only differ between the wild type and mutant branches
16
+ because the whole pose is re-minimized independently in each, so they contribute artifact.
17
+
18
+ What this adds
19
+ --------------
20
+ A `TotalEnergyMetric` per chain, reported into ddG.db3 by the same ReportToDB mover that
21
+ InterfaceDdGMover already applies to all four states. This is *reporting only* -- it adds no
22
+ sampling, consumes no random numbers, and leaves ddG_bind bit-identical (verified against the
23
+ unmodified protocol with -constant_seed).
24
+
25
+ Reading the result
26
+ ------------------
27
+ On the **unbound** states the chains are 1000 A apart, so there are no cross-chain pair
28
+ energies and the reported value is exactly that chain's intramolecular energy. That is the
29
+ number to use:
30
+
31
+ per-chain ddG(chain X) = intra_mut(X) - intra_wt(X)
32
+
33
+ On the **bound** states the value is intra(chain) + roughly half the interface energy, because
34
+ Rosetta's residue_total_energies splits each two-body term between its two residues. Those rows
35
+ are useful as a cross-check (they sum to the pose total) but should not be read as per-chain
36
+ stability numbers.
37
+
38
+ Caveat this does NOT fix
39
+ ------------------------
40
+ The unbound state is still never relaxed. This gives you the intramolecular strain difference
41
+ *in the bound backbone conformation*, not a folding ddG of the free monomer. For that you want
42
+ a dedicated monomer protocol (e.g. cartesian_ddg) run on the isolated chain.
43
+ """
44
+
45
+ import os
46
+
47
+
48
+ def chains_in_pdb(pdb_path):
49
+ """Chain IDs in the order they first appear in the PDB."""
50
+ chains = []
51
+ with open(pdb_path) as f:
52
+ for line in f:
53
+ if line.startswith(('ATOM', 'HETATM')):
54
+ chain = line[21]
55
+ if chain not in chains:
56
+ chains.append(chain)
57
+ return chains
58
+
59
+
60
+ def write_per_chain_protocol(base_xml_path, chains, out_path, scorefxn='fa_talaris2014'):
61
+ """Write a copy of base_xml_path with a per-chain TotalEnergyMetric for each chain.
62
+
63
+ Each chain gets its own database table (chain_<X>_energy) with a single `total_energy`
64
+ column. Separate tables rather than one table with prefixed columns is deliberate: as of
65
+ Rosetta 2022.45, SimpleMetricFeatures builds schema column names as `custom_type + name`
66
+ but builds the INSERT as `custom_type + "_" + name`, so any non-empty custom_type produces
67
+ "table simple_metrics has no column named ..." at report time.
68
+ """
69
+ if not chains:
70
+ raise ValueError('No chains given')
71
+
72
+ # Rosetta lowercases table names, so chains differing only in case would collide.
73
+ lowered = [c.lower() for c in chains]
74
+ if len(set(lowered)) != len(lowered):
75
+ raise ValueError('Chain IDs differ only by case, which collides in table names: %s' % chains)
76
+
77
+ xml = open(base_xml_path).read()
78
+
79
+ def substitute(text, anchor, addition):
80
+ if anchor not in text:
81
+ raise ValueError('Could not find anchor in %s:\n %s' % (base_xml_path, anchor))
82
+ return text.replace(anchor, anchor + addition, 1)
83
+
84
+ selectors = ''.join(
85
+ '\n <Chain name="chain_%s" chains="%s"/>' % (c, c) for c in chains)
86
+ xml = substitute(
87
+ xml, ' <StoredResidueSubset name="restore_neighbor_shell" subset_name="neighbor_shell"/>',
88
+ selectors)
89
+
90
+ metrics = '\n'.join(
91
+ ' <TotalEnergyMetric name="chain_%s_energy" residue_selector="chain_%s" scorefxn="%s"/>'
92
+ % (c, c, scorefxn) for c in chains)
93
+ anchor = ' <FILTERS>'
94
+ if anchor not in xml:
95
+ raise ValueError('Could not find FILTERS block in %s' % base_xml_path)
96
+ xml = xml.replace(anchor, ' <SIMPLE_METRICS>\n%s\n </SIMPLE_METRICS>\n\n%s' % (metrics, anchor), 1)
97
+
98
+ reporters = ''.join(
99
+ '\n <SimpleMetricFeatures metrics="chain_%s_energy" table_name="chain_%s_energy"/>'
100
+ % (c, c) for c in chains)
101
+ xml = substitute(
102
+ xml, ' <StructureScoresFeatures scorefxn="%s"/>' % scorefxn, reporters)
103
+
104
+ with open(out_path, 'w') as f:
105
+ f.write(xml)
106
+ return out_path
107
+
108
+
109
+ if __name__ == '__main__':
110
+ import sys
111
+ if len(sys.argv) != 4:
112
+ sys.exit('usage: per_chain_protocol.py <base.xml> <input.pdb> <out.xml>')
113
+ base_xml, pdb, out = sys.argv[1:4]
114
+ found = chains_in_pdb(pdb)
115
+ write_per_chain_protocol(base_xml, found, out)
116
+ print('Wrote %s with per-chain metrics for chains: %s' % (out, ', '.join(found)))
scripts/reprocess_per_chain.py ADDED
@@ -0,0 +1,253 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ Recover per-chain intramolecular energies from an EXISTING flex ddG run.
4
+
5
+ No re-sampling is required. The backrub trajectory is the expensive part and you already ran
6
+ it: struct.db3 holds the coordinates of every backrub, wild type minimized and mutant minimized
7
+ pose. This script reads those poses back into Rosetta, isolates one chain at a time, rescores,
8
+ and reports per-chain ddG. Verified to reproduce the in-protocol per-chain metric (see
9
+ per_chain_protocol.py) to nine decimal places.
10
+
11
+ Why the chains have to be physically isolated rather than just selected: struct.db3 stores the
12
+ *bound* poses. A Chain residue selector scoped over a bound pose still picks up cross-chain pair
13
+ energies, because Rosetta's residue_total_energies splits each two-body term between its two
14
+ residues, so roughly half the interface energy leaks into each chain. Deleting the other chains
15
+ reproduces the separated unbound state exactly, since intra-chain energy is invariant under the
16
+ rigid-body translation InterfaceDdGMover uses to unbind.
17
+
18
+ What this does and does not give you
19
+ ------------------------------------
20
+ It gives you the intramolecular energy difference between the mutant and wild type in the
21
+ *bound* backbone conformation, per chain. That is a strain term. It is NOT a folding ddG of the
22
+ free monomer: the unbound state is never relaxed here, in this script or in flex ddG itself. For
23
+ a true monomer stability ddG use a dedicated protocol such as cartesian_ddg on the isolated chain.
24
+
25
+ Built-in control: a chain you did not mutate should come out at 0 within its SEM. If it does not,
26
+ nstruct is too low to average out the whole-pose minimization noise, and the mutated chain's
27
+ number is not trustworthy either.
28
+
29
+ Usage
30
+ -----
31
+ python3 reprocess_per_chain.py <output_folder> [--stride N] [--chains A,B] [--csv out.csv]
32
+
33
+ The backrub_trajectory_stride is read back out of each struct.db3, so --stride is only needed
34
+ for databases that do not record it. It affects the checkpoint labels, not any energy.
35
+ """
36
+
37
+ import argparse
38
+ import glob
39
+ import os
40
+ import re
41
+ import sqlite3
42
+ import subprocess
43
+ import sys
44
+
45
+ import numpy as np
46
+ import pandas as pd
47
+
48
+ import flex_ddg_db3
49
+
50
+ rosetta_scripts_path = os.path.expanduser('~/rosetta/source/bin/rosetta_scripts')
51
+
52
+ # Must match the score function the original run used.
53
+ rosetta_flags = [
54
+ '-restore_talaris_behavior',
55
+ '-in:file:fullatom',
56
+ '-out:nooutput',
57
+ ]
58
+
59
+ struct_db3_name = 'struct.db3'
60
+ per_chain_db3_name = 'per_chain.db3'
61
+
62
+ # flex ddG writes three poses per checkpoint, in this order.
63
+ pose_order = ['backrub', 'wt', 'mut']
64
+
65
+
66
+ def chains_in_struct_db3(struct_db3):
67
+ conn = sqlite3.connect(struct_db3)
68
+ try:
69
+ chains = [row[0] for row in conn.execute(
70
+ 'SELECT DISTINCT chain_id FROM residue_pdb_identification ORDER BY chain_id')]
71
+ finally:
72
+ conn.close()
73
+ return [c for c in chains if c and c.strip()]
74
+
75
+
76
+ def write_rescore_protocol(chains, out_path, scorefxn='fa_talaris2014'):
77
+ """Emit a RosettaScripts protocol that isolates and rescores each chain in turn."""
78
+ lowered = [c.lower() for c in chains]
79
+ if len(set(lowered)) != len(lowered):
80
+ raise ValueError('Chain IDs differ only by case, which collides in batch names: %s' % chains)
81
+
82
+ selectors = '\n'.join(
83
+ ' <Chain name="chain_%s" chains="%s"/>\n'
84
+ ' <Not name="not_chain_%s" selector="chain_%s"/>' % (c, c, c, c) for c in chains)
85
+
86
+ movers = '\n'.join(
87
+ ' <DeleteRegionMover name="isolate_chain_%s" residue_selector="not_chain_%s"/>\n'
88
+ ' <ReportToDB name="chain_%s_report" batch_description="per_chain" database_name="%s">\n'
89
+ ' <ScoreTypeFeatures/>\n'
90
+ ' <ScoreFunctionFeatures scorefxn="%s"/>\n'
91
+ ' <StructureScoresFeatures scorefxn="%s"/>\n'
92
+ ' </ReportToDB>' % (c, c, c, per_chain_db3_name, scorefxn, scorefxn) for c in chains)
93
+
94
+ steps = [' <Add mover_name="save_full"/>']
95
+ for i, c in enumerate(chains):
96
+ if i > 0:
97
+ steps.append(' <Add mover_name="restore_full"/>')
98
+ steps.append(' <Add mover_name="isolate_chain_%s"/>' % c)
99
+ steps.append(' <Add mover_name="chain_%s_report"/>' % c)
100
+
101
+ xml = '''<ROSETTASCRIPTS>
102
+ <SCOREFXNS>
103
+ <ScoreFunction name="%s" weights="talaris2014"/>
104
+ </SCOREFXNS>
105
+
106
+ <RESIDUE_SELECTORS>
107
+ %s
108
+ </RESIDUE_SELECTORS>
109
+
110
+ <MOVERS>
111
+ <SavePoseMover name="save_full" reference_name="full_pose" restore_pose="0"/>
112
+ <SavePoseMover name="restore_full" reference_name="full_pose" restore_pose="1"/>
113
+ %s
114
+ </MOVERS>
115
+
116
+ <PROTOCOLS>
117
+ %s
118
+ </PROTOCOLS>
119
+ <OUTPUT />
120
+ </ROSETTASCRIPTS>
121
+ ''' % (scorefxn, selectors, movers, '\n'.join(steps))
122
+
123
+ with open(out_path, 'w') as f:
124
+ f.write(xml)
125
+ return out_path
126
+
127
+
128
+ def rescore_one(struct_db3, protocol_path):
129
+ """Run the isolate-and-rescore protocol on one struct.db3, writing per_chain.db3 beside it."""
130
+ working_dir = os.path.dirname(os.path.abspath(struct_db3))
131
+ out_db3 = os.path.join(working_dir, per_chain_db3_name)
132
+ if os.path.isfile(out_db3):
133
+ os.remove(out_db3)
134
+
135
+ args = [
136
+ os.path.abspath(rosetta_scripts_path),
137
+ '-inout:dbms:database_name', struct_db3_name,
138
+ '-in:use_database',
139
+ '-parser:protocol', os.path.abspath(protocol_path),
140
+ ] + rosetta_flags
141
+
142
+ log_path = os.path.join(working_dir, 'per_chain_rescore.log')
143
+ with open(log_path, 'w') as log:
144
+ proc = subprocess.Popen(args, stdout=log, stderr=subprocess.STDOUT, cwd=working_dir)
145
+ returncode = proc.wait()
146
+
147
+ if returncode != 0 or not os.path.isfile(out_db3):
148
+ raise RuntimeError('Rescoring failed for %s -- see %s' % (struct_db3, log_path))
149
+ return out_db3
150
+
151
+
152
+ def read_per_chain_db3(per_chain_db3, struct_number, case_name, stride):
153
+ conn = sqlite3.connect(per_chain_db3)
154
+ df = pd.read_sql_query('''
155
+ SELECT batches.name AS batch, structures.tag AS tag, structure_scores.score_value AS energy
156
+ FROM structure_scores
157
+ INNER JOIN structures ON structures.struct_id=structure_scores.struct_id
158
+ INNER JOIN batches ON batches.batch_id=structure_scores.batch_id
159
+ INNER JOIN score_types ON score_types.batch_id=structure_scores.batch_id
160
+ AND score_types.score_type_id=structure_scores.score_type_id
161
+ WHERE score_types.score_type_name="total_score"
162
+ ''', conn)
163
+ conn.close()
164
+
165
+ # batch name is "chain_<X>_report"; tag is "<original struct.db3 struct_id>_0001"
166
+ df['chain'] = df['batch'].apply(lambda b: b[len('chain_'):-len('_report')])
167
+ original_id = df['tag'].apply(lambda t: int(re.match(r'(\d+)', t).group(1)))
168
+ df['pose'] = original_id.apply(lambda i: pose_order[(i - 1) % len(pose_order)])
169
+ df['backrub_steps'] = original_id.apply(lambda i: stride * (((i - 1) // len(pose_order)) + 1))
170
+ df['struct_num'] = struct_number
171
+ df['case_name'] = case_name
172
+ return df[['case_name', 'struct_num', 'backrub_steps', 'chain', 'pose', 'energy']]
173
+
174
+
175
+ def main():
176
+ parser = argparse.ArgumentParser(description=__doc__,
177
+ formatter_class=argparse.RawDescriptionHelpFormatter)
178
+ parser.add_argument('output_folder', help='flex ddG output folder (e.g. "output")')
179
+ parser.add_argument('--stride', type=int, default=None,
180
+ help='override backrub_trajectory_stride instead of reading it from each '
181
+ 'struct.db3. Affects checkpoint labels only, not any energy.')
182
+ parser.add_argument('--chains', default=None,
183
+ help='comma-separated chains (default: auto-detect from struct.db3)')
184
+ parser.add_argument('--csv', default=None, help='write the full per-structure table here')
185
+ parser.add_argument('--reuse', action='store_true',
186
+ help='skip Rosetta where per_chain.db3 already exists')
187
+ args = parser.parse_args()
188
+
189
+ if not os.path.isfile(rosetta_scripts_path):
190
+ sys.exit('ERROR: set rosetta_scripts_path to your compiled rosetta_scripts binary')
191
+
192
+ struct_db3s = sorted(glob.glob(os.path.join(args.output_folder, '*', '*', struct_db3_name)))
193
+ if not struct_db3s:
194
+ sys.exit('ERROR: no %s found under %s' % (struct_db3_name, args.output_folder))
195
+ print('Found %d %s files' % (len(struct_db3s), struct_db3_name))
196
+
197
+ chains = args.chains.split(',') if args.chains else chains_in_struct_db3(struct_db3s[0])
198
+ print('Chains: %s' % ', '.join(chains))
199
+
200
+ protocol_path = os.path.join(args.output_folder, 'per_chain_rescore.generated.xml')
201
+ write_rescore_protocol(chains, protocol_path)
202
+ print('Wrote protocol %s\n' % protocol_path)
203
+
204
+ frames = []
205
+ for i, struct_db3 in enumerate(struct_db3s, start=1):
206
+ struct_dir = os.path.dirname(struct_db3)
207
+ case_name = os.path.basename(os.path.dirname(struct_dir))
208
+ struct_number = os.path.basename(struct_dir)
209
+ out_db3 = os.path.join(struct_dir, per_chain_db3_name)
210
+
211
+ if args.reuse and os.path.isfile(out_db3):
212
+ print(' [%d/%d] %s (reusing)' % (i, len(struct_db3s), struct_dir))
213
+ else:
214
+ print(' [%d/%d] %s' % (i, len(struct_db3s), struct_dir))
215
+ out_db3 = rescore_one(struct_db3, protocol_path)
216
+
217
+ stride = args.stride
218
+ if stride is None:
219
+ stride = flex_ddg_db3.trajectory_stride_from_db3(struct_db3)
220
+ if stride is None:
221
+ stride = 5
222
+ print(' WARNING: %s does not record backrub_trajectory_stride; assuming %d. '
223
+ 'Pass --stride to label the checkpoints correctly.' % (struct_db3, stride))
224
+
225
+ frames.append(read_per_chain_db3(out_db3, struct_number, case_name, stride))
226
+
227
+ per_structure = pd.concat(frames)
228
+ wide = per_structure[per_structure['pose'].isin(['wt', 'mut'])].pivot_table(
229
+ index=['case_name', 'chain', 'backrub_steps', 'struct_num'],
230
+ columns='pose', values='energy').reset_index()
231
+ wide['ddG'] = wide['mut'] - wide['wt']
232
+
233
+ if args.csv:
234
+ wide.to_csv(args.csv, index=False)
235
+ print('\nWrote %s' % args.csv)
236
+
237
+ summary = wide.groupby(['case_name', 'chain', 'backrub_steps']).agg(
238
+ nstruct=('ddG', 'size'),
239
+ wt_intra=('wt', 'mean'),
240
+ mut_intra=('mut', 'mean'),
241
+ ddG=('ddG', 'mean'),
242
+ ddG_sd=('ddG', 'std'),
243
+ ).reset_index()
244
+ summary['ddG_sem'] = summary['ddG_sd'] / np.sqrt(summary['nstruct'])
245
+
246
+ print('\n=== per-chain intramolecular ddG ===')
247
+ print(summary.round(4).to_string(index=False))
248
+ print('\nA chain you did NOT mutate should read ~0 within ddG_sem.')
249
+ print('This is bound-conformation strain, not a folding ddG (see the module docstring).')
250
+
251
+
252
+ if __name__ == '__main__':
253
+ main()
scripts/run_example_1.py ADDED
@@ -0,0 +1,121 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/python
2
+
3
+ from __future__ import print_function
4
+
5
+ import socket
6
+ import sys
7
+ import os
8
+ import subprocess
9
+
10
+ script_dir = os.path.dirname(os.path.abspath(__file__))
11
+ project_root = os.path.dirname(script_dir)
12
+ conf_dir = os.path.join(project_root, 'conf')
13
+ inputs_dir = os.path.join(script_dir, 'inputs')
14
+
15
+ use_multiprocessing = True
16
+ if use_multiprocessing:
17
+ import multiprocessing
18
+ max_cpus = 2 # We might want to not run on the full number of cores, as Rosetta take about 2 Gb of memory per instance
19
+
20
+ ###################################################################################################################################################################
21
+ # Important: The variables below are set to values that will make the run complete faster (as a tutorial example), but will not give scientifically valid results.
22
+ # Please change them to the "normal" default values before a real run.
23
+ ###################################################################################################################################################################
24
+
25
+ #rosetta_scripts_path = os.path.expanduser("~/rosetta/source/bin/rosetta_scripts")
26
+ rosetta_scripts_path = os.path.expanduser(
27
+ "/public/home/scnb9biwet/jiangqq/flex_ddG_tutorial-master/software/rosetta3.9/main/source/bin/rosetta_scripts.default.linuxgccrelease"
28
+ )
29
+ nstruct = 3 # Normally 35
30
+ max_minimization_iter = 5 # Normally 5000
31
+ abs_score_convergence_thresh = 200.0 # Normally 1.0
32
+ number_backrub_trials = 10 # Normally 35000
33
+ backrub_trajectory_stride = 5 # Can be whatever you want, if you would like to see results from earlier time points in the backrub trajectory. 7000 is a reasonable number, to give you three checkpoints for a 35000 step run, but you could also set it to 35000 for quickest run time (as the final minimization and packing steps will only need to be run one time).
34
+ path_to_script = os.path.join(conf_dir, 'ddG-backrub.xml')
35
+
36
+ # Additionally report the intramolecular energy of each individual chain into ddG.db3.
37
+ # This is reporting only: it adds no sampling, consumes no random numbers, and leaves the
38
+ # binding ddG bit-identical. Read the per-chain numbers off the *unbound* states, where the
39
+ # chains are 1000 A apart and the value is exactly that chain's intramolecular energy.
40
+ # See per_chain_protocol.py for the full explanation and caveats.
41
+ report_per_chain_energies = False
42
+
43
+ if not os.path.isfile(rosetta_scripts_path):
44
+ print('ERROR: "rosetta_scripts_path" variable must be set to the location of the "rosetta_scripts" binary executable')
45
+ print('This file might look something like: "rosetta_scripts.linuxgccrelease"')
46
+ raise Exception('Rosetta scripts missing')
47
+
48
+ def protocol_for( input_pdb_path ):
49
+ """Return the XML to run, generating the per-chain reporting variant if requested."""
50
+ if not report_per_chain_energies:
51
+ return os.path.abspath(path_to_script)
52
+
53
+ import per_chain_protocol
54
+ chains = per_chain_protocol.chains_in_pdb( input_pdb_path )
55
+ derived = os.path.abspath( os.path.splitext(path_to_script)[0] + '-per_chain.xml' )
56
+ per_chain_protocol.write_per_chain_protocol( path_to_script, chains, derived )
57
+ return derived
58
+
59
+ def run_flex_ddg( name, input_path, input_pdb_path, chains_to_move, nstruct_i ):
60
+ output_directory = os.path.join( project_root, 'output', os.path.join( name, '%02d' % nstruct_i ) )
61
+ if not os.path.isdir(output_directory):
62
+ os.makedirs(output_directory)
63
+
64
+ flex_ddg_args = [
65
+ os.path.abspath(rosetta_scripts_path),
66
+ "-s %s" % os.path.abspath(input_pdb_path),
67
+ '-parser:protocol', protocol_for( input_pdb_path ),
68
+ '-parser:script_vars',
69
+ 'chainstomove=' + chains_to_move,
70
+ 'mutate_resfile_relpath=' + os.path.abspath( os.path.join( input_path, 'nataa_mutations.resfile' ) ),
71
+ 'number_backrub_trials=%d' % number_backrub_trials,
72
+ 'max_minimization_iter=%d' % max_minimization_iter,
73
+ 'abs_score_convergence_thresh=%.1f' % abs_score_convergence_thresh,
74
+ 'backrub_trajectory_stride=%d' % backrub_trajectory_stride ,
75
+ '-restore_talaris_behavior',
76
+ '-in:file:fullatom',
77
+ '-ignore_unrecognized_res',
78
+ '-ignore_zero_occupancy false',
79
+ '-ex1',
80
+ '-ex2',
81
+ ]
82
+
83
+ log_path = os.path.join(output_directory, 'rosetta.out')
84
+
85
+ print( 'Running Rosetta with args:' )
86
+ print( ' '.join(flex_ddg_args) )
87
+ print( 'Output logged to:', os.path.abspath(log_path) )
88
+ print()
89
+
90
+ outfile = open(log_path, 'w')
91
+ process = subprocess.Popen(flex_ddg_args, stdout=outfile, stderr=subprocess.STDOUT, close_fds = True, cwd = output_directory)
92
+ returncode = process.wait()
93
+ outfile.close()
94
+
95
+ if __name__ == '__main__':
96
+ cases = []
97
+ for nstruct_i in range(1, nstruct + 1 ):
98
+ for case_name in os.listdir(inputs_dir):
99
+ case_path = os.path.join( inputs_dir, case_name )
100
+ for f in os.listdir(case_path):
101
+ if f.endswith('.pdb'):
102
+ input_pdb_path = os.path.join( case_path, f )
103
+ break
104
+
105
+ with open( os.path.join( case_path, 'chains_to_move.txt' ), 'r' ) as f:
106
+ chains_to_move = f.readlines()[0].strip()
107
+
108
+ cases.append( (case_name, case_path, input_pdb_path, chains_to_move, nstruct_i) )
109
+
110
+ if use_multiprocessing:
111
+ pool = multiprocessing.Pool( processes = min(max_cpus, multiprocessing.cpu_count()) )
112
+
113
+ for args in cases:
114
+ if use_multiprocessing:
115
+ pool.apply_async( run_flex_ddg, args = args )
116
+ else:
117
+ run_flex_ddg( *args )
118
+
119
+ if use_multiprocessing:
120
+ pool.close()
121
+ pool.join()
scripts/run_example_2_saturation.py ADDED
@@ -0,0 +1,116 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/python
2
+
3
+ from __future__ import print_function
4
+
5
+ import socket
6
+ import sys
7
+ import os
8
+ import subprocess
9
+
10
+ script_dir = os.path.dirname(os.path.abspath(__file__))
11
+ project_root = os.path.dirname(script_dir)
12
+ conf_dir = os.path.join(project_root, 'conf')
13
+ inputs_dir = os.path.join(script_dir, 'inputs')
14
+
15
+ use_multiprocessing = True
16
+ if use_multiprocessing:
17
+ import multiprocessing
18
+ max_cpus = 2 # We might want to not run on the full number of cores, as Rosetta take about 2 Gb of memory per instance
19
+
20
+ ###################################################################################################################################################################
21
+ # Important: The variables below are set to values that will make the run complete faster (as a tutorial example), but will not give scientifically valid results.
22
+ # Please change them to the "normal" default values before a real run.
23
+ ###################################################################################################################################################################
24
+
25
+ #rosetta_scripts_path = os.path.expanduser("~/rosetta/source/bin/rosetta_scripts")
26
+ rosetta_scripts_path = os.path.expanduser(
27
+ "/public/home/scnb9biwet/jiangqq/flex_ddG_tutorial-master/software/rosetta3.9/main/source/bin/rosetta_scripts.default.linuxgccrelease"
28
+ )
29
+ nstruct = 3 # Normally 35
30
+ max_minimization_iter = 5 # Normally 5000
31
+ abs_score_convergence_thresh = 200.0 # Normally 1.0
32
+ number_backrub_trials = 10 # Normally 35000
33
+ backrub_trajectory_stride = 5 # Can be whatever you want, if you would like to see results from earlier time points in the backrub trajectory. 7000 is a reasonable number, to give you three checkpoints for a 35000 step run, but you could also set it to 35000 for quickest run time (as the final minimization and packing steps will only need to be run one time).
34
+ path_to_script = os.path.join(conf_dir, 'ddG-backrub.xml')
35
+ residue_to_mutate = ('B', 49, '') # Residue position to perfrom saturation mutatagenesis. Format: (Chain, PDB residue number, insertion code).
36
+
37
+ if not os.path.isfile(rosetta_scripts_path):
38
+ print('ERROR: "rosetta_scripts_path" variable must be set to the location of the "rosetta_scripts" binary executable')
39
+ print('This file might look something like: "rosetta_scripts.linuxgccrelease"')
40
+ raise Exception('Rosetta scripts missing')
41
+
42
+ def run_flex_ddg_saturation( name, input_path, input_pdb_path, chains_to_move, mut_aa, nstruct_i ):
43
+ output_directory = os.path.join( project_root, 'output_saturation', os.path.join( '%s_%s' % (name, mut_aa), '%02d' % nstruct_i ) )
44
+ if not os.path.isdir(output_directory):
45
+ os.makedirs(output_directory)
46
+
47
+ mutation_chain, mutation_resi, mutation_icode = residue_to_mutate
48
+ resfile_path = os.path.join( output_directory, 'mutate_%s%d%s_to_%s.resfile' % (mutation_chain, mutation_resi, mutation_icode, mut_aa) )
49
+ with open( resfile_path, 'w') as f:
50
+ # Header must be NATAA, not NATRO. This resfile is used both to pick the mutated
51
+ # position and as the task operation for the mutant PackRotamersMover. With NATRO,
52
+ # the mutant branch freezes the 8 A neighbor shell while the wild type branch
53
+ # repacks it, which biases every ddG upwards by several REU (a self-mutation to the
54
+ # native amino acid comes out at +6 instead of 0).
55
+ f.write( 'NATAA\nstart\n%d%s %s PIKAA %s\n' % (mutation_resi, mutation_icode, mutation_chain, mut_aa) )
56
+
57
+ flex_ddg_args = [
58
+ os.path.abspath(rosetta_scripts_path),
59
+ "-s %s" % os.path.abspath(input_pdb_path),
60
+ '-parser:protocol', os.path.abspath(path_to_script),
61
+ '-parser:script_vars',
62
+ 'chainstomove=' + chains_to_move,
63
+ 'mutate_resfile_relpath=' + os.path.abspath( resfile_path ),
64
+ 'number_backrub_trials=%d' % number_backrub_trials,
65
+ 'max_minimization_iter=%d' % max_minimization_iter,
66
+ 'abs_score_convergence_thresh=%.1f' % abs_score_convergence_thresh,
67
+ 'backrub_trajectory_stride=%d' % backrub_trajectory_stride ,
68
+ '-restore_talaris_behavior',
69
+ '-in:file:fullatom',
70
+ '-ignore_unrecognized_res',
71
+ '-ignore_zero_occupancy false',
72
+ '-ex1',
73
+ '-ex2',
74
+ ]
75
+
76
+ log_path = os.path.join(output_directory, 'rosetta.out')
77
+
78
+ print( 'Running Rosetta with args:' )
79
+ print( ' '.join(flex_ddg_args) )
80
+ print( 'Output logged to:', os.path.abspath(log_path) )
81
+ print()
82
+
83
+ outfile = open(log_path, 'w')
84
+ process = subprocess.Popen(flex_ddg_args, stdout=outfile, stderr=subprocess.STDOUT, close_fds = True, cwd = output_directory)
85
+ returncode = process.wait()
86
+ outfile.close()
87
+
88
+ if __name__ == '__main__':
89
+ mutation_chain, mutation_resi, mutation_icode = residue_to_mutate
90
+ cases = []
91
+ for nstruct_i in range(1, nstruct + 1 ):
92
+ for case_name in os.listdir(inputs_dir):
93
+ case_path = os.path.join( inputs_dir, case_name )
94
+ for f in os.listdir(case_path):
95
+ if f.endswith('.pdb'):
96
+ input_pdb_path = os.path.join( case_path, f )
97
+ break
98
+
99
+ with open( os.path.join( case_path, 'chains_to_move.txt' ), 'r' ) as f:
100
+ chains_to_move = f.readlines()[0].strip()
101
+
102
+ for mut_aa in 'ACDEFGHIKLMNPQRSTVWY':
103
+ cases.append( ('%s_%s%d%s' % (case_name, mutation_chain, mutation_resi, mutation_icode), case_path, input_pdb_path, chains_to_move, mut_aa, nstruct_i) )
104
+
105
+ if use_multiprocessing:
106
+ pool = multiprocessing.Pool( processes = min(max_cpus, multiprocessing.cpu_count()) )
107
+
108
+ for args in cases:
109
+ if use_multiprocessing:
110
+ pool.apply_async( run_flex_ddg_saturation, args = args )
111
+ else:
112
+ run_flex_ddg_saturation( *args )
113
+
114
+ if use_multiprocessing:
115
+ pool.close()
116
+ pool.join()