core-score 0.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of core-score might be problematic. Click here for more details.
- core_score-0.4.0/LICENSE +28 -0
- core_score-0.4.0/PKG-INFO +382 -0
- core_score-0.4.0/README.md +356 -0
- core_score-0.4.0/pyproject.toml +42 -0
- core_score-0.4.0/setup.cfg +4 -0
- core_score-0.4.0/src/core_score/__init__.py +8 -0
- core_score-0.4.0/src/core_score/__main__.py +3 -0
- core_score-0.4.0/src/core_score/analysis/__init__.py +1 -0
- core_score-0.4.0/src/core_score/analysis/core.py +61 -0
- core_score-0.4.0/src/core_score/analysis/ost.py +79 -0
- core_score-0.4.0/src/core_score/analysis/pairs.py +119 -0
- core_score-0.4.0/src/core_score/analysis/posebusters.py +65 -0
- core_score-0.4.0/src/core_score/analysis/reference.py +59 -0
- core_score-0.4.0/src/core_score/cli.py +90 -0
- core_score-0.4.0/src/core_score/inputs/__init__.py +1 -0
- core_score-0.4.0/src/core_score/inputs/inputs.py +113 -0
- core_score-0.4.0/src/core_score/inputs/make_csv.py +209 -0
- core_score-0.4.0/src/core_score/inputs/prepare.py +108 -0
- core_score-0.4.0/src/core_score/inputs/sites.py +115 -0
- core_score-0.4.0/src/core_score/inputs/structures.py +357 -0
- core_score-0.4.0/src/core_score/outputs/__init__.py +1 -0
- core_score-0.4.0/src/core_score/outputs/files.py +63 -0
- core_score-0.4.0/src/core_score/outputs/plot.py +77 -0
- core_score-0.4.0/src/core_score/outputs/report.py +104 -0
- core_score-0.4.0/src/core_score/pipeline.py +102 -0
- core_score-0.4.0/src/core_score.egg-info/PKG-INFO +382 -0
- core_score-0.4.0/src/core_score.egg-info/SOURCES.txt +38 -0
- core_score-0.4.0/src/core_score.egg-info/dependency_links.txt +1 -0
- core_score-0.4.0/src/core_score.egg-info/entry_points.txt +3 -0
- core_score-0.4.0/src/core_score.egg-info/requires.txt +12 -0
- core_score-0.4.0/src/core_score.egg-info/top_level.txt +1 -0
- core_score-0.4.0/tests/test_chemistry.py +178 -0
- core_score-0.4.0/tests/test_cli_entrypoint.py +49 -0
- core_score-0.4.0/tests/test_invariants.py +155 -0
- core_score-0.4.0/tests/test_make_csv.py +89 -0
- core_score-0.4.0/tests/test_radius.py +81 -0
- core_score-0.4.0/tests/test_site_preparation.py +67 -0
- core_score-0.4.0/tests/test_sites.py +9 -0
- core_score-0.4.0/tests/test_workflow.py +264 -0
- core_score-0.4.0/tests/test_workflow_inputs.py +108 -0
core_score-0.4.0/LICENSE
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026, Henry Broster
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
|
7
|
+
|
|
8
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
9
|
+
list of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
12
|
+
this list of conditions and the following disclaimer in the documentation
|
|
13
|
+
and/or other materials provided with the distribution.
|
|
14
|
+
|
|
15
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
16
|
+
contributors may be used to endorse or promote products derived from
|
|
17
|
+
this software without specific prior written permission.
|
|
18
|
+
|
|
19
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
20
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
21
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
22
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
23
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
24
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
25
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
26
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
27
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
28
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: core-score
|
|
3
|
+
Version: 0.4.0
|
|
4
|
+
Summary: CORE Score: agreement within an ensemble of predicted protein-ligand poses
|
|
5
|
+
Author: Henry Broster
|
|
6
|
+
License-Expression: BSD-3-Clause
|
|
7
|
+
Project-URL: Repository, https://github.com/James-Broster/core-score
|
|
8
|
+
Keywords: co-folding,protein-ligand,structure prediction,confidence,AlphaFold3
|
|
9
|
+
Classifier: Intended Audience :: Science/Research
|
|
10
|
+
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Requires-Python: >=3.11
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
License-File: LICENSE
|
|
15
|
+
Requires-Dist: numpy>=2
|
|
16
|
+
Requires-Dist: scipy>=1.13
|
|
17
|
+
Requires-Dist: gemmi<0.8,>=0.7.5
|
|
18
|
+
Requires-Dist: rdkit>=2025.3
|
|
19
|
+
Requires-Dist: pandas>=2.2
|
|
20
|
+
Requires-Dist: posebusters<0.7,>=0.6.5
|
|
21
|
+
Provides-Extra: plot
|
|
22
|
+
Requires-Dist: matplotlib>=3.8; extra == "plot"
|
|
23
|
+
Provides-Extra: test
|
|
24
|
+
Requires-Dist: pytest>=8; extra == "test"
|
|
25
|
+
Dynamic: license-file
|
|
26
|
+
|
|
27
|
+
# CORE Score
|
|
28
|
+
|
|
29
|
+
A Python package for prediction-only ensemble agreement. It prepares protein–ligand
|
|
30
|
+
structures, runs PoseBusters `dock` checks, compares every pair of poses with
|
|
31
|
+
OpenStructure, and calculates CORE from the complete pairwise ligand-RMSD matrix.
|
|
32
|
+
Experimental references are optional and never enter the CORE calculation.
|
|
33
|
+
|
|
34
|
+
See [validation](https://github.com/James-Broster/core-score/blob/main/docs/validation.md) for what has been checked.
|
|
35
|
+
|
|
36
|
+
## CORE Score
|
|
37
|
+
|
|
38
|
+
For each pose *i* in an ensemble of *N* poses, δ*ᵢ,ₘ* is the ligand RMSD to its *m*th
|
|
39
|
+
closest other pose, for its three closest other poses. Each distance is capped at a
|
|
40
|
+
threshold *T* and divided by *T*, so a pose reproduced exactly by its three closest poses
|
|
41
|
+
has penalty 0 and a pose with no other pose within *T* has penalty 1. CORE is one minus
|
|
42
|
+
the mean penalty.
|
|
43
|
+
|
|
44
|
+
```text
|
|
45
|
+
S = 1 − (1/3N) Σᵢ Σₘ min(δᵢ,ₘ, T) / T
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Equivalently S = f (1 − ν/T), where f is the fraction of closest-pose distances δᵢ,ₘ
|
|
49
|
+
within T and ν is the mean of those distances. Using three closest poses means a pose
|
|
50
|
+
scores highly only when at least four poses agree closely. The default T is 2 Å, the RMSD
|
|
51
|
+
threshold for a correct prediction. CORE uses every pose in the ensemble, including
|
|
52
|
+
poses that fail PoseBusters checks, because they still sample the model's output
|
|
53
|
+
distribution. Validity filtering belongs downstream, for example when choosing the
|
|
54
|
+
top-ranked prediction.
|
|
55
|
+
|
|
56
|
+
CORE needs at least four poses per ensemble, so that every pose has three others to be
|
|
57
|
+
scored against. An ensemble with fewer is rejected before anything runs.
|
|
58
|
+
|
|
59
|
+
Each pair of poses is compared once with OpenStructure. Poses are ordered by path, and
|
|
60
|
+
the earlier pose of each pair is the OST model, so the same poses always give the same
|
|
61
|
+
scores whatever order they are listed in.
|
|
62
|
+
|
|
63
|
+
## Install
|
|
64
|
+
|
|
65
|
+
CORE Score needs OpenStructure 2.12, which is installed with conda. Then install the
|
|
66
|
+
package with pip.
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
conda create -n core-score -c conda-forge -c bioconda python=3.12 openstructure=2.12
|
|
70
|
+
conda activate core-score
|
|
71
|
+
pip install "core-score[plot]"
|
|
72
|
+
core-score --help
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
`plot` adds matplotlib for `--plot`. Plain `pip install core-score` installs the
|
|
76
|
+
pipeline alone. The package is `core_score`. It installs two commands, `core-score` and
|
|
77
|
+
`core-score-csv`.
|
|
78
|
+
|
|
79
|
+
To work on the package itself, clone the repository and use its environment, which
|
|
80
|
+
installs it in editable mode with the tests.
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
conda env create -f environment.yml
|
|
84
|
+
conda activate core-score
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
The conda solve has been checked on macOS ARM. Other platforms need an available
|
|
88
|
+
OpenStructure 2.12 build. Dependencies track current releases, including PoseBusters
|
|
89
|
+
0.6 and pandas 3. OpenStructure is an external executable. `ost` is launched from PATH
|
|
90
|
+
and finds its chemical library itself or through `OST_COMPOUNDS_CHEMLIB`.
|
|
91
|
+
|
|
92
|
+
## What you give, what you get
|
|
93
|
+
|
|
94
|
+
| You give | You get |
|
|
95
|
+
| --- | --- |
|
|
96
|
+
| At least four predicted structures per ensemble, and the ligand's SMILES | CORE Score per ensemble, and PoseBusters validity per pose |
|
|
97
|
+
| \+ a confidence per pose (read automatically by `core-score-csv`) | \+ the top-ranked pose, the PoseBusters-valid pose with the highest confidence |
|
|
98
|
+
| \+ a ground-truth structure per ensemble | \+ ligand RMSD, lDDT-PLI and whether each pose is correct, and whether the top-ranked pose is |
|
|
99
|
+
|
|
100
|
+
An ensemble is a set of predictions of the same protein–ligand system to compare
|
|
101
|
+
together, usually every seed and sample one model made for one target. Keep different
|
|
102
|
+
models in separate ensembles to score them separately.
|
|
103
|
+
|
|
104
|
+
## Walkthrough
|
|
105
|
+
|
|
106
|
+
**1. Put each ensemble's predictions in a folder named for it.** Leave the files exactly
|
|
107
|
+
as the model wrote them. Any folders inside are searched.
|
|
108
|
+
|
|
109
|
+
```text
|
|
110
|
+
predictions/
|
|
111
|
+
7ly6/
|
|
112
|
+
seed-1_sample-0/7ly6_seed-1_sample-0_model.cif
|
|
113
|
+
seed-1_sample-1/7ly6_seed-1_sample-1_model.cif
|
|
114
|
+
...
|
|
115
|
+
7uy4/
|
|
116
|
+
...
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
**2. Write each ensemble's ligand SMILES in a CSV.**
|
|
120
|
+
|
|
121
|
+
```text
|
|
122
|
+
ensemble,smiles
|
|
123
|
+
7ly6,Cc1cc2nc3c(=O)[nH]c(=O)nc-3n(C[C@H](O)[C@H](O)[C@H](O)COP(=O)(O)O)c2cc1C
|
|
124
|
+
7uy4,CN[C@@H]1[C@H](O)[C@H](NC)[C@H]2O[C@]3(O)[C@H](O[C@@H]2[C@H]1O)O[C@H](C)CC3(O)O
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
**3. Make the input CSV.**
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
core-score-csv --predictions predictions/ --smiles smiles.csv --output inputs.csv
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
This finds every structure, lists a structure found twice with the same coordinates
|
|
134
|
+
once (AlphaFold3 writes a copy of its top model beside the seed folders), and reads each
|
|
135
|
+
pose's confidence from the file the model wrote beside it. It stops and lists every
|
|
136
|
+
problem, such as an ensemble without a SMILES or with fewer than four structures. Add
|
|
137
|
+
`--references references/`, a folder holding `<ensemble>.cif` or `<ensemble>.pdb`, to
|
|
138
|
+
evaluate the predictions against ground truth.
|
|
139
|
+
|
|
140
|
+
The confidence is the ligand's ipTM as in Runs N' Poses, the mean chain-pair ipTM between
|
|
141
|
+
the ligand chain and each receptor chain, also averaged over the ligand's copies when it
|
|
142
|
+
has several. It is read from these files.
|
|
143
|
+
|
|
144
|
+
| Model | Structure | Confidence file |
|
|
145
|
+
| --- | --- | --- |
|
|
146
|
+
| AlphaFold3 | `*model.cif` | `*summary_confidences.json` |
|
|
147
|
+
| Boltz | `<name>_model_<k>.cif` | `confidence_<name>_model_<k>.json` |
|
|
148
|
+
| Chai-1 | `pred.model_idx_<k>.cif` | `scores.model_idx_<k>.npz` |
|
|
149
|
+
| Protenix | `<name>_sample_<k>.cif` | `<name>_summary_confidence_sample_<k>.json` |
|
|
150
|
+
| OpenFold3 | `*model.cif` | `*confidences_aggregated.json` |
|
|
151
|
+
|
|
152
|
+
For any other method, the confidence column is left out and you can add your own.
|
|
153
|
+
|
|
154
|
+
**4. Run CORE Score.**
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
core-score inputs.csv --out results/ --workers 8
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
**5. Read `results/core_scores.csv`**, one row per ensemble, highest CORE first, and
|
|
161
|
+
`results/poses.csv`, one row per pose. [Outputs](#outputs) describes every column.
|
|
162
|
+
|
|
163
|
+
## The input CSV
|
|
164
|
+
|
|
165
|
+
`core-score-csv` writes this file, and you can also write it yourself. It needs three
|
|
166
|
+
columns. A row names one structure, or many with a wildcard.
|
|
167
|
+
|
|
168
|
+
```text
|
|
169
|
+
ensemble,smiles,poses
|
|
170
|
+
target1,CC(=O)Nc1ccc(O)cc1,predictions/target1/*.cif
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
| Column | Meaning |
|
|
174
|
+
| --- | --- |
|
|
175
|
+
| `ensemble` | The ensemble's name. Rows with the same name form one ensemble. |
|
|
176
|
+
| `smiles` | The ligand's SMILES, the same on every row of an ensemble. |
|
|
177
|
+
| `poses` | A structure file, or a wildcard matching several (`**` searches folders inside). PDB, CIF and mmCIF, one model per file. |
|
|
178
|
+
| `confidence` | Optional. The model's own score for the pose, higher meaning more confident. One pose per row, and given for every pose of an ensemble or for none. |
|
|
179
|
+
| `reference` | Optional. The ground-truth structure, the same on every row of an ensemble. |
|
|
180
|
+
| `ligand_chain` | Optional. The ligand's chain, or chains separated by spaces for several identical copies. |
|
|
181
|
+
| `ligand_sdf` | Optional. The ligand as an SDF in the structure's frame, for tools such as docking that write it separately. One pose per row. |
|
|
182
|
+
|
|
183
|
+
Paths are relative to the CSV. Pose IDs are the structure paths relative to the CSV.
|
|
184
|
+
See [the example](https://github.com/James-Broster/core-score/blob/main/examples/inputs.csv), which uses every column a CSV usually needs.
|
|
185
|
+
Coordinates are never aligned or changed.
|
|
186
|
+
|
|
187
|
+
The ligand is found in each structure by its SMILES heavy-atom composition, and
|
|
188
|
+
`ligand_chain` narrows that down. Missing ligands are reported, not guessed. Composition
|
|
189
|
+
only selects residues. Preparation separately verifies the chemistry against the SMILES.
|
|
190
|
+
|
|
191
|
+
Structure files given directly form one ensemble.
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
core-score poses/*.cif --smiles 'CCO' --out results/
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
The same runs from Python:
|
|
198
|
+
|
|
199
|
+
```python
|
|
200
|
+
import core_score
|
|
201
|
+
|
|
202
|
+
core_score.run("inputs.csv", "results/", workers=8)
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
`core_score.score(matrix, threshold=2.0)` scores a pairwise RMSD matrix you have
|
|
206
|
+
computed yourself. `neighbours=3` is the number of closest poses each pose is scored against.
|
|
207
|
+
|
|
208
|
+
## Options
|
|
209
|
+
|
|
210
|
+
| Option | Meaning |
|
|
211
|
+
| --- | --- |
|
|
212
|
+
| `--workers N` | At most N simultaneous OST comparisons (default 1). Each OST process uses one numerical-library thread. |
|
|
213
|
+
| `--timeout SECONDS` | Limit per OST call. Default is no limit. |
|
|
214
|
+
| `--rmsd-thresholds 0.5 1 2` | Thresholds T in Å. CORE is calculated at each from the same matrix, and a pose is correct at T when its RMSD to the reference is below T and its lDDT-PLI above 0.8. Default 2. |
|
|
215
|
+
| `--core-cutoffs 0.5 0.7 0.9` | CORE cutoffs to report against. A complex at or above a cutoff is above it. Default 0.5, 0.6, 0.7, 0.8 and 0.9. |
|
|
216
|
+
| `--no-radius-fallback` | Disable the 4 → 6 → 8 Å binding-site recovery. |
|
|
217
|
+
| `--skip-posebusters` | Do not run PoseBusters, which runs by default. CORE is unaffected, but there is no top-ranked pose. |
|
|
218
|
+
| `--plot` | Also save `core_scores.png`, a dot per complex ordered by CORE Score. Needs matplotlib. |
|
|
219
|
+
| `--smiles`, `--ligand-chain`, `--reference` | The ligand's SMILES and chains, and the ground truth, for structure files given directly. A CSV sets its own. |
|
|
220
|
+
|
|
221
|
+
## PoseBusters
|
|
222
|
+
|
|
223
|
+
PoseBusters runs once per selected ligand copy against its predicted environment,
|
|
224
|
+
using the official API with `config='dock'`. A pose is valid only if every copy passes
|
|
225
|
+
every dock binary check. If none fail but any are unknown, the pose is unknown,
|
|
226
|
+
never valid. Missing chemical information is unknown, not a pass. Each check's result
|
|
227
|
+
for a pose combines its copies the same way. No pose is removed.
|
|
228
|
+
|
|
229
|
+
## Binding-site recovery
|
|
230
|
+
|
|
231
|
+
When OST cannot score a pair because of a binding-site failure, the comparison is
|
|
232
|
+
retried at 6 Å and then 8 Å. Graph errors and general failures are not retried. The
|
|
233
|
+
ligand and pocket RMSD can come from the larger radius, but lDDT-PLI always stays
|
|
234
|
+
from the original 4 Å call. The standard RMSD, chosen radius and every attempt are
|
|
235
|
+
recorded.
|
|
236
|
+
|
|
237
|
+
## Multiple identical copies
|
|
238
|
+
|
|
239
|
+
When each prediction contains several copies of the ligand, every pose is superposed
|
|
240
|
+
onto the anchor pose by OST's rigid protein alignment. Constrained k-means then gives
|
|
241
|
+
each copy a site label consistent across the ensemble, and each site gets its own
|
|
242
|
+
matrix and CORE Score. Confidence and ground truth are not used. Different copy
|
|
243
|
+
counts or alignment failures block the ensemble and are reported. Site labels are
|
|
244
|
+
arbitrary and do not prove biological correspondence. Transforms, costs and the
|
|
245
|
+
anchor are saved in `sites.json`. The sites of ensemble `7ly6` are reported as
|
|
246
|
+
`7ly6_site_1`, `7ly6_site_2` and so on.
|
|
247
|
+
|
|
248
|
+
## Identical chains
|
|
249
|
+
|
|
250
|
+
OpenStructure treats chains of different mmCIF entities as different molecules when it
|
|
251
|
+
maps one structure's chains onto another's. AlphaFold3 writes an entity per chain listed
|
|
252
|
+
in its input, so the two chains of a homodimer could never swap places and pockets
|
|
253
|
+
between them would be scored wrongly. Before comparison, polymer chains with the same
|
|
254
|
+
sequence are given one entity. Only entity IDs change.
|
|
255
|
+
|
|
256
|
+
## Reference evaluation
|
|
257
|
+
|
|
258
|
+
```bash
|
|
259
|
+
core-score inputs.csv --out results/ --rmsd-thresholds 0.5 1 1.5 2
|
|
260
|
+
core-score poses/*.cif --smiles 'CCO' --reference experimental.cif --out results/
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
Predictions are compared with the reference wherever their ensemble has one, set by the
|
|
264
|
+
`reference` column or by `--reference`. Each prediction is compared with OST's
|
|
265
|
+
`compare-ligand-structures`, giving the ligand RMSD after binding-site superposition and
|
|
266
|
+
lDDT-PLI. A pose is **correct** at T when its RMSD is below T and its lDDT-PLI is above
|
|
267
|
+
0.8, the definition used in the paper. A multi-copy comparison has no label unless OST
|
|
268
|
+
assigns exactly one pair. A failed comparison, or one missing either score, is unknown,
|
|
269
|
+
never wrong.
|
|
270
|
+
|
|
271
|
+
## Top-ranked pose
|
|
272
|
+
|
|
273
|
+
When confidences are given, the top-ranked pose of each complex is its
|
|
274
|
+
PoseBusters-valid pose with the highest confidence, as in the paper. Ties go to the
|
|
275
|
+
earlier pose. A complex with no valid pose, no confidences, or PoseBusters skipped has
|
|
276
|
+
no top pose, and `note` in `core_scores.csv` says why.
|
|
277
|
+
|
|
278
|
+
## Running
|
|
279
|
+
|
|
280
|
+
Every run loads and checks the inputs, prepares structures, runs PoseBusters, assigns
|
|
281
|
+
sites where needed, compares every pair, calculates CORE, evaluates references when
|
|
282
|
+
given, and writes the report. Each run is fresh and needs a new or empty
|
|
283
|
+
output directory. A missing or failed comparison prevents that ensemble's CORE
|
|
284
|
+
Score. Nothing is averaged over a subset or filled in. Other ensembles carry on, and
|
|
285
|
+
their results and diagnostics are saved. The exit code is 0 when everything
|
|
286
|
+
completed, 1 when anything is incomplete and 2 for invalid input.
|
|
287
|
+
|
|
288
|
+
## Outputs
|
|
289
|
+
|
|
290
|
+
A complex is one ensemble, or one ligand site of a multi-copy ensemble.
|
|
291
|
+
|
|
292
|
+
```text
|
|
293
|
+
results/
|
|
294
|
+
core_scores.csv one row per complex
|
|
295
|
+
poses.csv one row per pose
|
|
296
|
+
core_scores.png every complex ordered by CORE Score, with --plot
|
|
297
|
+
details/ the evidence behind them
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
**`core_scores.csv`** has one row per complex and T, highest CORE first and unscored
|
|
301
|
+
complexes last.
|
|
302
|
+
|
|
303
|
+
| Column | Meaning |
|
|
304
|
+
| --- | --- |
|
|
305
|
+
| `ensemble` | The complex, either the ensemble's name or `<ensemble>_site_<n>` for each site of a ligand with several copies. |
|
|
306
|
+
| `threshold_angstrom`, `core_score` | T and CORE at T. Blank when CORE could not be calculated. |
|
|
307
|
+
| `above_0.5` … `above_0.9` | True when CORE ≥ that cutoff, one column per cutoff. |
|
|
308
|
+
| `pose_count`, `valid_pose_count` | Poses in the complex and how many are PoseBusters-valid. |
|
|
309
|
+
| `top_pose`, `top_pose_confidence` | The top-ranked pose, when confidences are given. |
|
|
310
|
+
| `fraction_correct`, `top_pose_correct` | With references, the fraction of poses correct at T and whether the top pose is. |
|
|
311
|
+
| `note` | Why CORE or the top pose is missing. |
|
|
312
|
+
|
|
313
|
+
**`poses.csv`** has one row per pose, in path order.
|
|
314
|
+
|
|
315
|
+
| Column | Meaning |
|
|
316
|
+
| --- | --- |
|
|
317
|
+
| `ensemble`, `pose_id` | The pose. |
|
|
318
|
+
| `confidence` | The model's own score, when confidences are given. |
|
|
319
|
+
| `pb_valid` | True when PoseBusters passed every dock check on every ligand copy. Which checks failed is in `details/posebusters.json`. |
|
|
320
|
+
| `rmsd`, `lddt_pli` | To the reference, when there is one. |
|
|
321
|
+
| `correct_2A` | Whether the pose is correct at T, RMSD below T and lDDT-PLI above 0.8, one column per T. |
|
|
322
|
+
| `note` | Why a result is missing. |
|
|
323
|
+
|
|
324
|
+
A blank is unknown, never a pass or a failure.
|
|
325
|
+
|
|
326
|
+
**`core_scores.png`**, with `--plot`, is a dot per complex, ordered by CORE Score, one PNG
|
|
327
|
+
per T, with a dashed line at each cutoff saying how many complexes reach it. It is set in
|
|
328
|
+
Optima where that font is installed, otherwise the nearest humanist sans the machine has.
|
|
329
|
+
It needs matplotlib, from `pip install '.[plot]'`.
|
|
330
|
+
|
|
331
|
+
**`details/`** holds the evidence behind those files.
|
|
332
|
+
|
|
333
|
+
| File | Contents |
|
|
334
|
+
| --- | --- |
|
|
335
|
+
| `pairs.csv` | Ligand RMSD, pocket backbone RMSD, pocket lDDT and lDDT-PLI per pair, with radius recovery fields |
|
|
336
|
+
| `ligand_details.jsonl` | Raw OST results, commands and output for every pair |
|
|
337
|
+
| `posebusters.json` | PoseBusters validity, every dock check and every raw result per pose and copy |
|
|
338
|
+
| `reference_details.json`, `references/` | Raw reference comparisons and prepared references |
|
|
339
|
+
| `prepared_manifest.json`, `prepared/` | Prepared structures, SDFs and receptors |
|
|
340
|
+
| `sites.json` | Site assignments for multi-copy ensembles |
|
|
341
|
+
| `run.json`, `status.json` | Settings and completion counts |
|
|
342
|
+
|
|
343
|
+
Every failure records its stage, error and traceback, plus any evidence such as the
|
|
344
|
+
OST command and output.
|
|
345
|
+
|
|
346
|
+
## Code layout
|
|
347
|
+
|
|
348
|
+
`pipeline.py` runs the steps in order. Each folder holds one phase of the run.
|
|
349
|
+
|
|
350
|
+
```text
|
|
351
|
+
src/core_score/
|
|
352
|
+
cli.py the core-score command
|
|
353
|
+
pipeline.py run() and execute(): every step in order
|
|
354
|
+
inputs/
|
|
355
|
+
make_csv.py the core-score-csv command, which writes the input CSV
|
|
356
|
+
inputs.py load and check the CSV or structure inputs
|
|
357
|
+
structures.py read structure records, select ligands, write ligand SDFs
|
|
358
|
+
prepare.py prepare every pose for OST and PoseBusters
|
|
359
|
+
sites.py one ensemble per ligand site
|
|
360
|
+
analysis/
|
|
361
|
+
posebusters.py dock checks for every pose
|
|
362
|
+
ost.py every OpenStructure call
|
|
363
|
+
pairs.py every pair of poses, with binding-site recovery
|
|
364
|
+
core.py RMSD matrix and CORE per threshold
|
|
365
|
+
reference.py optional comparison with the ground truth
|
|
366
|
+
outputs/
|
|
367
|
+
report.py core_scores.csv and poses.csv
|
|
368
|
+
plot.py core_scores.png, with --plot
|
|
369
|
+
files.py output writers, failure records, output folders
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
[The code map](https://github.com/James-Broster/core-score/blob/main/docs/code-map.md) draws the whole run, then each stage, function by
|
|
373
|
+
function, and lists every check.
|
|
374
|
+
|
|
375
|
+
## Tests
|
|
376
|
+
|
|
377
|
+
```bash
|
|
378
|
+
python -m pytest
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
Real OST tests are separate because they need OST and structure fixtures. See
|
|
382
|
+
[validation](https://github.com/James-Broster/core-score/blob/main/docs/validation.md).
|