Performance#
Per-stage wall time (best of n) on one TCR-pMHC complex (1ao7), Apple M-series, single thread. Reproduce the core stages with:
$ RUN_BENCHMARK=1 pytest -k benchmark -s
stage |
time |
notes |
|---|---|---|
parse a gzipped structure |
~17 ms |
|
contact map (5 Å, cKDTree) |
~9 ms |
per structure |
score 1000 candidate peptides |
~11 ms |
~10 µs/peptide (vectorised) |
ΔΔG alanine scan (9-mer) |
~11 ms |
virtual-matrix path; no atoms move |
binder P(bind) (features + model) |
~49 ms |
native geometry, no external tool |
peptide refine (2000-step DOPE MC) |
~320 ms |
knowledge-based rigid-body refinement |
annotate — MHC map (1 structure) |
~670 ms |
one mmseqs2 search |
annotate — TCR (arda, 1 structure) |
~1.5 s |
mmseqs2 startup-bound; ~0.2 s/str batched |
full pipeline (no superimpose) |
~2.2 s |
parse → annotate → contacts → score |
superimpose onto the canonical DB (per query) |
~2.8 s |
aligns to every same-class DB structure |
Peak resident memory#
workload |
peak RSS |
notes |
|---|---|---|
single-structure pipeline (no orient) |
~200 MB |
parse → annotate → contacts → score → refine |
|
~780 MB |
holds the Canonical2026 reference set in RAM |
Well under the 32 GB workstation ceiling either way. If you are only scoring or computing ΔΔG,
skip superimpose (tcren scoring --no-superimpose) to stay at the ~200 MB working set.
Threading model#
Annotation (TCR chain typing + MHC mapping) is the only compute-heavy step. It is always run as a single batched mmseqs2 search over every chain in the input set — mmseqs2 parallelises internally, so it is never called per structure and never wrapped in Python threads (a fork-based pool would also deadlock after mmseqs2/BLAS spawn their own threads). Batching amortises the fixed ~1.5 s mmseqs2 startup: ~0.2 s/structure across a set, versus ~1.5 s/structure one at a time.
Threads (tcren.orient.run_folder()’s threads / tcren orient -t N) are used only for
the embarrassingly-parallel, mmseqs-free stages — structure parsing, the Kabsch/SVD alignment, and
writing oriented files — and, by extension, any PyMOL/Rosetta/FlexPepDock rendering and relaxation.
Scaling a screen#
Placing pMHCs against a TCR panel, refining, and scoring each complex is embarrassingly parallel:
references are annotated/oriented once (not per complex), so the hot loop is only
refine + contacts + score (~0.3–0.9 s/complex here). Distribute complexes across cores/machines —
throughput scales linearly with no shared state.