jqscore 0.1.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.
- jqscore-0.1.0/LICENSE +21 -0
- jqscore-0.1.0/MANIFEST.in +2 -0
- jqscore-0.1.0/PKG-INFO +172 -0
- jqscore-0.1.0/README.md +144 -0
- jqscore-0.1.0/jqscore/__init__.py +34 -0
- jqscore-0.1.0/jqscore/benchmark.py +1007 -0
- jqscore-0.1.0/jqscore/compare.py +181 -0
- jqscore-0.1.0/jqscore/jqscore.py +1492 -0
- jqscore-0.1.0/jqscore/jqscore_cmd.py +101 -0
- jqscore-0.1.0/jqscore.egg-info/PKG-INFO +172 -0
- jqscore-0.1.0/jqscore.egg-info/SOURCES.txt +28 -0
- jqscore-0.1.0/jqscore.egg-info/dependency_links.txt +1 -0
- jqscore-0.1.0/jqscore.egg-info/entry_points.txt +4 -0
- jqscore-0.1.0/jqscore.egg-info/requires.txt +13 -0
- jqscore-0.1.0/jqscore.egg-info/top_level.txt +1 -0
- jqscore-0.1.0/pyproject.toml +48 -0
- jqscore-0.1.0/setup.cfg +4 -0
- jqscore-0.1.0/tests/__init__.py +0 -0
- jqscore-0.1.0/tests/conftest.py +75 -0
- jqscore-0.1.0/tests/data/390_7cec_A100.cif +7801 -0
- jqscore-0.1.0/tests/data/390_7cec_A100__Q__390_emd_30342_A_z4.cif +7770 -0
- jqscore-0.1.0/tests/data/390_7cec_A100__Q__390_emd_30342_A_z4_s04.cif +7776 -0
- jqscore-0.1.0/tests/data/390_emd_30342_A_z4.mrc +0 -0
- jqscore-0.1.0/tests/data/9XZK_C15.cif +263 -0
- jqscore-0.1.0/tests/data/9XZK_C15__Q__mapq_s04.cif +257 -0
- jqscore-0.1.0/tests/data/9XZK_C15_map.mrc +0 -0
- jqscore-0.1.0/tests/test_core_helpers.py +241 -0
- jqscore-0.1.0/tests/test_data_processing.py +296 -0
- jqscore-0.1.0/tests/test_integration.py +504 -0
- jqscore-0.1.0/tests/test_io.py +237 -0
jqscore-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Arthur Zalevsky
|
|
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.
|
jqscore-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: jqscore
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: JAX reimplementation of Q-score (github.com/gregdp/mapq)
|
|
5
|
+
Maintainer-email: Arthur Zalevsky <aozalevsky@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/aozalevsky/jqscore
|
|
8
|
+
Project-URL: Repository, https://github.com/aozalevsky/jqscore
|
|
9
|
+
Project-URL: Issues, https://github.com/aozalevsky/jqscore/issues
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
14
|
+
Requires-Python: >=3.10
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
License-File: LICENSE
|
|
17
|
+
Requires-Dist: numpy
|
|
18
|
+
Requires-Dist: scipy
|
|
19
|
+
Requires-Dist: jax
|
|
20
|
+
Requires-Dist: gemmi
|
|
21
|
+
Provides-Extra: gpu
|
|
22
|
+
Requires-Dist: jax[cuda13]; extra == "gpu"
|
|
23
|
+
Provides-Extra: benchmark
|
|
24
|
+
Requires-Dist: matplotlib; extra == "benchmark"
|
|
25
|
+
Provides-Extra: test
|
|
26
|
+
Requires-Dist: pytest>=7.0; extra == "test"
|
|
27
|
+
Dynamic: license-file
|
|
28
|
+
|
|
29
|
+
# jqscore
|
|
30
|
+
|
|
31
|
+
[](https://github.com/aozalevsky/jqscore/actions/workflows/tests.yml)
|
|
32
|
+
[](https://pypi.org/project/jqscore/)
|
|
33
|
+

|
|
34
|
+
|
|
35
|
+
JAX reimplementation of [Q-score](https://github.com/gregdp/mapq) — a per-atom cryo-EM map-to-model fit metric.
|
|
36
|
+
|
|
37
|
+
Q-score measures how well each atom in an atomic model fits into a cryo-EM
|
|
38
|
+
density map by comparing the observed radial density profile around each atom
|
|
39
|
+
to a theoretical Gaussian profile (Pearson correlation).
|
|
40
|
+
|
|
41
|
+
> Pintilie et al., *Nature Methods* 2020. Reference implementation: [gregdp/mapq](https://github.com/gregdp/mapq)
|
|
42
|
+
|
|
43
|
+
## Installation
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
pip install jqscore # CPU
|
|
47
|
+
pip install "jqscore[gpu]" # NVIDIA GPU: CUDA 13 build of JAX, driver ≥ 580
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
With an older driver (≥ 525), use the CUDA 12 build of JAX:
|
|
51
|
+
`pip install jqscore "jax[cuda12]"`. The development version:
|
|
52
|
+
`pip install git+https://github.com/aozalevsky/jqscore`.
|
|
53
|
+
|
|
54
|
+
## Python API
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
import jqscore
|
|
58
|
+
|
|
59
|
+
# From file paths (PDB/mmCIF + MRC/CCP4)
|
|
60
|
+
result = jqscore.run("structure.cif", "map.mrc")
|
|
61
|
+
|
|
62
|
+
# Access results
|
|
63
|
+
print(result.atom_qscores) # per-atom Q-scores (H: nearest heavy atom's in the residue)
|
|
64
|
+
print(jqscore.chain_qscores(result)) # per-chain averages
|
|
65
|
+
print(jqscore.residue_qscores(result)) # per-residue breakdown
|
|
66
|
+
|
|
67
|
+
# Lower-level: supply parsed atoms and map arrays
|
|
68
|
+
atoms = jqscore.read_cif("structure.cif")
|
|
69
|
+
data, origin, voxel_size = jqscore.read_mrc("map.mrc")
|
|
70
|
+
result = jqscore.compute_qscores(atoms, data, origin, voxel_size, sigma=0.4)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Computation modes
|
|
74
|
+
|
|
75
|
+
| Mode | What it does |
|
|
76
|
+
|------|--------------|
|
|
77
|
+
| `use_retry=True` (default) | MapQ's retry loop: up to 50 attempts with 8, 10, 12, … sphere points per shell, until ≥ 8 are clear of other atoms. Matches a float64 reference to ~1e-5, except for about 1 atom in 100,000 with a sample point within ~1e-7 Å of the exclusion cutoff, which float32 cannot decide. |
|
|
78
|
+
| `use_retry=False` | A fixed budget of `n_gen` points per shell; all clear points count. ~0.03 mean Q-score difference from retry mode. |
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
# Fast mode
|
|
82
|
+
result = jqscore.run("structure.cif", "map.mrc", use_retry=False)
|
|
83
|
+
|
|
84
|
+
# Check JAX backend
|
|
85
|
+
print(jqscore.backend()) # 'cpu', 'gpu', or 'tpu'
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Atoms are processed in batches (`batch_size`, default 32768); the map stays on
|
|
89
|
+
the GPU throughout. Lower `batch_size` if the GPU runs out of memory.
|
|
90
|
+
|
|
91
|
+
On an RTX A4000, `jqscore 36ZA.cif emd_76130.map` (11.2 M atoms, 2888
|
|
92
|
+
chains, 800³ map) takes 2 min, half of it reading the 1.2 GB mmCIF, and
|
|
93
|
+
`jqscore-cmd` with the annotated CIF written 2.5 min.
|
|
94
|
+
|
|
95
|
+
## CLI
|
|
96
|
+
|
|
97
|
+
```
|
|
98
|
+
jqscore structure.cif map.mrc [options]
|
|
99
|
+
|
|
100
|
+
options:
|
|
101
|
+
--sigma FLOAT Gaussian sigma in Å (default 0.4; use 0.6 for older datasets)
|
|
102
|
+
--num-pts INT Sample points per shell (default 8)
|
|
103
|
+
--to-rad FLOAT Max radial distance in Å
|
|
104
|
+
--d-rad FLOAT Radial shell spacing in Å
|
|
105
|
+
--no-retry Use fast fixed-budget mode
|
|
106
|
+
--max-retries INT Max retry attempts per shell (default 50)
|
|
107
|
+
--n-gen INT Sphere-point budget for --no-retry mode
|
|
108
|
+
--no-mapq-compat Interpolate the map directly instead of replicating
|
|
109
|
+
MapQ's trimmed-map resampling
|
|
110
|
+
--batch-size INT Atoms per batch (default 32768; lower for small GPUs)
|
|
111
|
+
--verbose Print progress and per-atom Q-scores
|
|
112
|
+
--output FILE Write per-residue TSV to file (default: stdout summary)
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## MapQ-compatibility mode
|
|
116
|
+
|
|
117
|
+
The `jqscore-cmd` entry point matches the argument style of the original MapQ Chimera plugin’s `mapq_cmd.py`, so tools like the [VA validation package](https://pypi.org/project/va/) can use jqscore as a drop-in replacement without changes.
|
|
118
|
+
|
|
119
|
+
**How to run:**
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
jqscore-cmd <chimera_root> map=<mapfile> cif=<cif1> [cif=<cif2> ...] [np=<n>] [res=<resolution>] [sigma=<sigma>]
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
- **Required:** `map=<path>` — path to the MRC/CCP4 density map.
|
|
126
|
+
- **Required:** `cif=<path>` — path to an mmCIF structure; repeat for multiple models.
|
|
127
|
+
- **Optional:** first positional argument is the Chimera root path (accepted but unused; jqscore does not require Chimera).
|
|
128
|
+
|
|
129
|
+
All parameters other than the map path, structure path(s), and **sigma** are accepted for compatibility but **ignored** (e.g. `np=`, `res=`, Chimera root). The optional `sigma=<float>` sets the Gaussian width in Å (default 0.4). Output CIFs with a Q-score column are written to the current working directory as `{cif_basename}__Q__{map_basename}.cif`, matching the naming expected by VA.
|
|
130
|
+
|
|
131
|
+
## Container
|
|
132
|
+
|
|
133
|
+
`container/jqscore.def` builds an Apptainer/Singularity image with the CUDA
|
|
134
|
+
build of JAX (the host needs only an NVIDIA driver, ≥ 580 for CUDA 13).
|
|
135
|
+
From the repository root:
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
apptainer build --fakeroot jqscore.sif container/jqscore.def
|
|
139
|
+
# driver older than 580: --build-arg JAX="jax[cuda12]==0.9.2"
|
|
140
|
+
|
|
141
|
+
apptainer run --nv jqscore.sif structure.cif map.mrc
|
|
142
|
+
apptainer exec --nv jqscore.sif jqscore-cmd /opt/chimera map=map.mrc cif=structure.cif
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
The build ends by running the test suite on the CPU. `apptainer run-help
|
|
146
|
+
jqscore.sif` lists the commands.
|
|
147
|
+
|
|
148
|
+
## Benchmarking against MapQ
|
|
149
|
+
|
|
150
|
+
The included benchmark script (needs `pip install "jqscore[benchmark]"` for matplotlib) downloads real PDB+EMDB structures, runs both the original [MapQ](https://github.com/gregdp/mapq) (via Singularity) and jqscore, and produces per-atom scatter plots, a summary comparison, and a markdown report.
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
# Run with default structures (7 entries):
|
|
154
|
+
python -m jqscore.benchmark
|
|
155
|
+
|
|
156
|
+
# Run on specific PDB IDs:
|
|
157
|
+
python -m jqscore.benchmark 9XZK 9UX2
|
|
158
|
+
|
|
159
|
+
# Custom output directory:
|
|
160
|
+
python -m jqscore.benchmark -o my_benchmark
|
|
161
|
+
|
|
162
|
+
# After changing jqscore: re-run it only, keeping MapQ results and times
|
|
163
|
+
python -m jqscore.benchmark --rerun-jqscore
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
The MapQ reference is invoked via the `MAPQ_CMD` environment variable (expects a Singularity container by default). A full benchmark run with all 7 default structures takes approximately 30 minutes.
|
|
167
|
+
|
|
168
|
+
Results are saved to `jqscore_mapq_benchmark/` (plots, output CIFs, and `README.md`); the latest run is in [`docs/jqscore_vs_mapq/`](https://github.com/aozalevsky/jqscore/blob/main/docs/jqscore_vs_mapq/README.md). Of the 750,165 non-H atoms of its 7 entries, 15 differ from MapQ by more than 1e-3: 5 in 3J7O where the density around the atom is flat (MapQ gives ~0.1, jqscore 0), and 10 with a sample point within ~1e-7 Å of the exclusion cutoff, a tie that MapQ also breaks differently from a float64 reference in 3 of the 10. See [`spec/benchmark.md`](https://github.com/aozalevsky/jqscore/blob/main/spec/benchmark.md) for the full specification.
|
|
169
|
+
|
|
170
|
+
## License
|
|
171
|
+
|
|
172
|
+
MIT
|
jqscore-0.1.0/README.md
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# jqscore
|
|
2
|
+
|
|
3
|
+
[](https://github.com/aozalevsky/jqscore/actions/workflows/tests.yml)
|
|
4
|
+
[](https://pypi.org/project/jqscore/)
|
|
5
|
+

|
|
6
|
+
|
|
7
|
+
JAX reimplementation of [Q-score](https://github.com/gregdp/mapq) — a per-atom cryo-EM map-to-model fit metric.
|
|
8
|
+
|
|
9
|
+
Q-score measures how well each atom in an atomic model fits into a cryo-EM
|
|
10
|
+
density map by comparing the observed radial density profile around each atom
|
|
11
|
+
to a theoretical Gaussian profile (Pearson correlation).
|
|
12
|
+
|
|
13
|
+
> Pintilie et al., *Nature Methods* 2020. Reference implementation: [gregdp/mapq](https://github.com/gregdp/mapq)
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pip install jqscore # CPU
|
|
19
|
+
pip install "jqscore[gpu]" # NVIDIA GPU: CUDA 13 build of JAX, driver ≥ 580
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
With an older driver (≥ 525), use the CUDA 12 build of JAX:
|
|
23
|
+
`pip install jqscore "jax[cuda12]"`. The development version:
|
|
24
|
+
`pip install git+https://github.com/aozalevsky/jqscore`.
|
|
25
|
+
|
|
26
|
+
## Python API
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
import jqscore
|
|
30
|
+
|
|
31
|
+
# From file paths (PDB/mmCIF + MRC/CCP4)
|
|
32
|
+
result = jqscore.run("structure.cif", "map.mrc")
|
|
33
|
+
|
|
34
|
+
# Access results
|
|
35
|
+
print(result.atom_qscores) # per-atom Q-scores (H: nearest heavy atom's in the residue)
|
|
36
|
+
print(jqscore.chain_qscores(result)) # per-chain averages
|
|
37
|
+
print(jqscore.residue_qscores(result)) # per-residue breakdown
|
|
38
|
+
|
|
39
|
+
# Lower-level: supply parsed atoms and map arrays
|
|
40
|
+
atoms = jqscore.read_cif("structure.cif")
|
|
41
|
+
data, origin, voxel_size = jqscore.read_mrc("map.mrc")
|
|
42
|
+
result = jqscore.compute_qscores(atoms, data, origin, voxel_size, sigma=0.4)
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Computation modes
|
|
46
|
+
|
|
47
|
+
| Mode | What it does |
|
|
48
|
+
|------|--------------|
|
|
49
|
+
| `use_retry=True` (default) | MapQ's retry loop: up to 50 attempts with 8, 10, 12, … sphere points per shell, until ≥ 8 are clear of other atoms. Matches a float64 reference to ~1e-5, except for about 1 atom in 100,000 with a sample point within ~1e-7 Å of the exclusion cutoff, which float32 cannot decide. |
|
|
50
|
+
| `use_retry=False` | A fixed budget of `n_gen` points per shell; all clear points count. ~0.03 mean Q-score difference from retry mode. |
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
# Fast mode
|
|
54
|
+
result = jqscore.run("structure.cif", "map.mrc", use_retry=False)
|
|
55
|
+
|
|
56
|
+
# Check JAX backend
|
|
57
|
+
print(jqscore.backend()) # 'cpu', 'gpu', or 'tpu'
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Atoms are processed in batches (`batch_size`, default 32768); the map stays on
|
|
61
|
+
the GPU throughout. Lower `batch_size` if the GPU runs out of memory.
|
|
62
|
+
|
|
63
|
+
On an RTX A4000, `jqscore 36ZA.cif emd_76130.map` (11.2 M atoms, 2888
|
|
64
|
+
chains, 800³ map) takes 2 min, half of it reading the 1.2 GB mmCIF, and
|
|
65
|
+
`jqscore-cmd` with the annotated CIF written 2.5 min.
|
|
66
|
+
|
|
67
|
+
## CLI
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
jqscore structure.cif map.mrc [options]
|
|
71
|
+
|
|
72
|
+
options:
|
|
73
|
+
--sigma FLOAT Gaussian sigma in Å (default 0.4; use 0.6 for older datasets)
|
|
74
|
+
--num-pts INT Sample points per shell (default 8)
|
|
75
|
+
--to-rad FLOAT Max radial distance in Å
|
|
76
|
+
--d-rad FLOAT Radial shell spacing in Å
|
|
77
|
+
--no-retry Use fast fixed-budget mode
|
|
78
|
+
--max-retries INT Max retry attempts per shell (default 50)
|
|
79
|
+
--n-gen INT Sphere-point budget for --no-retry mode
|
|
80
|
+
--no-mapq-compat Interpolate the map directly instead of replicating
|
|
81
|
+
MapQ's trimmed-map resampling
|
|
82
|
+
--batch-size INT Atoms per batch (default 32768; lower for small GPUs)
|
|
83
|
+
--verbose Print progress and per-atom Q-scores
|
|
84
|
+
--output FILE Write per-residue TSV to file (default: stdout summary)
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## MapQ-compatibility mode
|
|
88
|
+
|
|
89
|
+
The `jqscore-cmd` entry point matches the argument style of the original MapQ Chimera plugin’s `mapq_cmd.py`, so tools like the [VA validation package](https://pypi.org/project/va/) can use jqscore as a drop-in replacement without changes.
|
|
90
|
+
|
|
91
|
+
**How to run:**
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
jqscore-cmd <chimera_root> map=<mapfile> cif=<cif1> [cif=<cif2> ...] [np=<n>] [res=<resolution>] [sigma=<sigma>]
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
- **Required:** `map=<path>` — path to the MRC/CCP4 density map.
|
|
98
|
+
- **Required:** `cif=<path>` — path to an mmCIF structure; repeat for multiple models.
|
|
99
|
+
- **Optional:** first positional argument is the Chimera root path (accepted but unused; jqscore does not require Chimera).
|
|
100
|
+
|
|
101
|
+
All parameters other than the map path, structure path(s), and **sigma** are accepted for compatibility but **ignored** (e.g. `np=`, `res=`, Chimera root). The optional `sigma=<float>` sets the Gaussian width in Å (default 0.4). Output CIFs with a Q-score column are written to the current working directory as `{cif_basename}__Q__{map_basename}.cif`, matching the naming expected by VA.
|
|
102
|
+
|
|
103
|
+
## Container
|
|
104
|
+
|
|
105
|
+
`container/jqscore.def` builds an Apptainer/Singularity image with the CUDA
|
|
106
|
+
build of JAX (the host needs only an NVIDIA driver, ≥ 580 for CUDA 13).
|
|
107
|
+
From the repository root:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
apptainer build --fakeroot jqscore.sif container/jqscore.def
|
|
111
|
+
# driver older than 580: --build-arg JAX="jax[cuda12]==0.9.2"
|
|
112
|
+
|
|
113
|
+
apptainer run --nv jqscore.sif structure.cif map.mrc
|
|
114
|
+
apptainer exec --nv jqscore.sif jqscore-cmd /opt/chimera map=map.mrc cif=structure.cif
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
The build ends by running the test suite on the CPU. `apptainer run-help
|
|
118
|
+
jqscore.sif` lists the commands.
|
|
119
|
+
|
|
120
|
+
## Benchmarking against MapQ
|
|
121
|
+
|
|
122
|
+
The included benchmark script (needs `pip install "jqscore[benchmark]"` for matplotlib) downloads real PDB+EMDB structures, runs both the original [MapQ](https://github.com/gregdp/mapq) (via Singularity) and jqscore, and produces per-atom scatter plots, a summary comparison, and a markdown report.
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
# Run with default structures (7 entries):
|
|
126
|
+
python -m jqscore.benchmark
|
|
127
|
+
|
|
128
|
+
# Run on specific PDB IDs:
|
|
129
|
+
python -m jqscore.benchmark 9XZK 9UX2
|
|
130
|
+
|
|
131
|
+
# Custom output directory:
|
|
132
|
+
python -m jqscore.benchmark -o my_benchmark
|
|
133
|
+
|
|
134
|
+
# After changing jqscore: re-run it only, keeping MapQ results and times
|
|
135
|
+
python -m jqscore.benchmark --rerun-jqscore
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
The MapQ reference is invoked via the `MAPQ_CMD` environment variable (expects a Singularity container by default). A full benchmark run with all 7 default structures takes approximately 30 minutes.
|
|
139
|
+
|
|
140
|
+
Results are saved to `jqscore_mapq_benchmark/` (plots, output CIFs, and `README.md`); the latest run is in [`docs/jqscore_vs_mapq/`](https://github.com/aozalevsky/jqscore/blob/main/docs/jqscore_vs_mapq/README.md). Of the 750,165 non-H atoms of its 7 entries, 15 differ from MapQ by more than 1e-3: 5 in 3J7O where the density around the atom is flat (MapQ gives ~0.1, jqscore 0), and 10 with a sample point within ~1e-7 Å of the exclusion cutoff, a tie that MapQ also breaks differently from a float64 reference in 3 of the 10. See [`spec/benchmark.md`](https://github.com/aozalevsky/jqscore/blob/main/spec/benchmark.md) for the full specification.
|
|
141
|
+
|
|
142
|
+
## License
|
|
143
|
+
|
|
144
|
+
MIT
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"""jqscore — JAX-accelerated Q-score (cryo-EM atom-map fit metric)."""
|
|
2
|
+
|
|
3
|
+
from .jqscore import (
|
|
4
|
+
AtomRecord,
|
|
5
|
+
QScoreResult,
|
|
6
|
+
read_mrc,
|
|
7
|
+
read_pdb,
|
|
8
|
+
read_cif,
|
|
9
|
+
compute_qscores,
|
|
10
|
+
run,
|
|
11
|
+
write_qscore_cif,
|
|
12
|
+
residue_qscores,
|
|
13
|
+
chain_qscores,
|
|
14
|
+
backend,
|
|
15
|
+
_cli, # re-exported for the `jqscore` console_scripts entry point
|
|
16
|
+
)
|
|
17
|
+
from .compare import CompareResult, read_qscores, compare_qscores
|
|
18
|
+
|
|
19
|
+
__all__ = [
|
|
20
|
+
"AtomRecord",
|
|
21
|
+
"QScoreResult",
|
|
22
|
+
"read_mrc",
|
|
23
|
+
"read_pdb",
|
|
24
|
+
"read_cif",
|
|
25
|
+
"compute_qscores",
|
|
26
|
+
"run",
|
|
27
|
+
"write_qscore_cif",
|
|
28
|
+
"residue_qscores",
|
|
29
|
+
"chain_qscores",
|
|
30
|
+
"backend",
|
|
31
|
+
"CompareResult",
|
|
32
|
+
"read_qscores",
|
|
33
|
+
"compare_qscores",
|
|
34
|
+
]
|