ワンクリックで
tcren
tcren — TCR-pMHC contact potential (TCRen) pipeline; conventions and public API
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
tcren — TCR-pMHC contact potential (TCRen) pipeline; conventions and public API
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
| name | tcren |
| description | tcren — TCR-pMHC contact potential (TCRen) pipeline; conventions and public API |
tcren reproduces and extends the TCRen contact-energy potential (Nat Comput Sci 2022)
on a pure-Python pipeline (structure parsing → contacts → TCR/MHC annotation → potential
derivation → epitope-ranking benchmarks). Annotation uses the arda package
(mmseqs2-backed), a runtime dependency published to PyPI as arda-mapper (imports as arda,
>=2.5.6) — no separate checkout and no ARDA_HOME (arda auto-fetches its reference into
~/.cache/arda on first use). Conda env tcren (bash setup.sh).
All structure annotation (TCR chain typing AND MHC allele mapping) must gather every sequence first, make ONE batched mmseqs2 call, then map the output back for downstream per-structure analysis. mmseqs2 parallelises internally across threads — that is the parallel layer; Python orchestration is a single call.
ProcessPoolExecutor(fork) over structures deadlocks (fork after mmseqs2/BLAS
spawn threads). A ThreadPoolExecutor runs but still pays the fixed cost N times.paper/helpers.py::_batch_annotate does TCR annotation for a whole dataset in 2 arda
calls (human + mouse). MHC annotation uses the same pattern: mhc.annotate_mhc_batch(structures)
— ONE mmseqs search over every candidate MHC chain, sliced back per structure.Reference: arda.annotate_sequences([(id, seq), ...]) — one call, threads internally.
ProcessPoolExecutor/workers.orient.run_folder(threads=…) threads
the parse and the align+write stages (default os.cpu_count()); annotation between them is
the single batched pass. tcren orient -t N. superimpose is the same: run_superimpose
batch-annotates all inputs, then threads the mmseqs-free ensemble alignment + write
(superimpose(..., annotate=False) on the pre-annotated structures). tcren superimpose -t N.
-s accepts file / dir / .tar.gz / glob; -o is a directory, or a single structure file
(one input) whose extension must match --mmCIF/--compress (validated by _output_target).superimpose vs orienttcren superimpose / tcren.orient.superimpose(s, db_dir=…) — bring a NEW structure into
the canonical frame against a canonical database (default data/Canonical2026). It detects
the input's MHC class + species, selects every DB member of that class+species (from the DB's
orient_metadata.json), superposes the query groove Cα onto each, and averages the rigid
transforms (chordal/SVD mean rotation + mean translation) into one consensus placement. The
matching DB subset is batch-annotated once and cached per process.tcren orient / tcren.orient.run_folder(...) — BUILD a canonical DB from native
complexes using the per-class derived frame (how Canonical2026 is produced). Not for orienting
a single new structure — use superimpose for that.--push-to-hub was removed; maintainers run
scripts/push_canonical_to_hub.py instead.tcren.run_pipeline / tcren pipelinerun_pipeline(structure, superimpose=True, db_dir=…) → PipelineResult: import → annotate
(alleles + chains + MHC groove) → superimpose onto the canonical DB (canonical Cα) → resmarkup
total (sum of the residue-pair potential over each interface's
contacts). CLI tcren pipeline -s … -o scores.csv writes one row per structure.tcren._align, tcren._refine (pybind11 / scikit-build-core)CMakeLists.txt (pybind11_add_module each, install(TARGETS _align _refine …)): src/_align/align.cpp (MHC pseudoseq fitting alignment) and src/_refine/refine.cpp
(potential-guided peptide refinement). Adding a third = same pattern.src/_align/align.cpp,
CMakeLists.txt). Build backend is scikit-build-core (not hatchling); pip install -e .
builds it (editable.rebuild on import). Funcs: fitting_score, best_hit (GIL released over
candidates), align (traceback). Scoring matches Bio.Align's fitting config EXACTLY (BLOSUM62,
placed-gap open -11/extend -1, free target + end gaps), so tcren.mhc.pseudo falls back to
Biopython transparently when the ext is absent. ~40 ms vs Bio 59 ms vs pure-Python 15 s for 4k
candidates (a modest 1.5x — Bio's aligner is already C). editable.rebuild = false in
pyproject: the ext is built once at pip install -e . (do NOT rebuild on import — that needs
cmake on PATH at import time and breaks pytest/CI). CI installs --no-deps + explicit runtime
deps (so arda-backed tests skip) and pip install cmake ninja to build the ext.tcren.refine (tcren refine)substitute_peptide(structure, new_peptide) — backbone-preserving identity swap on the peptide
chain (keep N/Cα/C/O+Cβ, drop side-chain beyond Cβ); pure data-model, no atoms moved. score_peptides
is virtual (matrix lookup over the fixed contact map) — substitution is only needed to then refine.refine_peptide(structure, restraint_w=0.5, …) → (structure, energy): knowledge-based rigid-body
Metropolis MC of the peptide via the _refine C++ kernel. Energy = DOPE atom-level
distance-dependent statistical potential (Shen & Sali 2006) over all peptide↔partner heavy-atom
pairs (chain-agnostic, atom-class × distance lookup with linear interp) + harmonic restraint to
the input pose. DOPE is used ONLY for refinement — deliberately decoupled from the TCRen/MJ
potentials tcren scores with (no circularity: don't refine and score against the same quantity).
DOPE's short-range bins are repulsive, so it supplies its own clash term (no separate clash). The
restraint keeps it local (without it the search can drift to another favourable pocket). Partners =
all non-peptide chains within a 12 Å shell. NOT physics MD; Rosetta FlexPepDock is the deferred path.src/tcren/data/dope_potential.npz (158 atom classes × 29 bins 0.75–14.75 Å), built by
scripts/build_dope.py from the pymod/altmod MODELLER libraries; tcren.refine._dope() loads it.tcren refine -s … -o … [--substitute PEP] [--steps N] [--restraint W]. Native pose ≈ stays
(RMSD ~0.2 Å); a buried/clashed peptide relaxes locally. Deterministic given seed.tcren.clashes, tcren.refine.registerQC for generated (AlphaFold/TCRmodel) complexes: their peptide-swap poses are routinely non-physical (forced poses), which corrupts the contact energy the score reads.
interface_clashes(structure, tolerance=0.4, severe=0.6) -> ClashReport — numpy-only, no kernel.
Heavy-atom vdW overlaps (Bondi radii) between the peptide chain and its partners, broken down by
partner chain_type (by_partner), with n_clashes/n_severe/max_overlap/clash_score + the
worst residue pairs. has_clashes(structure) is the bool convenience. Self-check python -m tcren.clashes.check_register(model, reference=None) -> RegisterReport — always reports the clash burden; with a
correctly-registered reference (crystal / trusted pose) it adds the anchor-Cα RMSD in the
MHC-groove frame (peptide_rmsd) → wrong_register (True/False; None without a reference).
A heavy clash burden alone is NOT a register call — AF swap models are routinely clashy; register
needs the reference. (The ila1 CPL lesson: forced pose → raw TCRen ROC 0.35, recovered to ≈0.77 on the crystal register.)fix_register(model, template, engine="ccd") -> ModelResult — re-threads the model's peptide sequence
onto template's correctly-registered backbone and re-refines via model_peptide (the
FlexPepDock-functional path; needs the _refine/_fold kernel). Equal peptide length required.
Template-free re-docking (CCD to canonical anchor targets) is the future extension.tcren.ddg.reference_delta (geometry-normalized TCRen)reference_delta(cm, peptide, pot, interface="tcr_peptide", reference_aa="A") -> float = ΔΦ = Φ(peptide)
− Φ(all-reference_aa peptide). It is the full-peptide alanine scan (== sum of alanine_scan().ddG)
and subtracts the pose's identity-independent geometry baseline Φ(polyAla).scripts/ala_reference_sweep.py
(manuscript repo). It is NOT an affinity ΔΔG (dimensionless contact-preference, no free energy).scripts/atlas_tcren.py + atlas_within_series.py, manuscript repo).
Turning ATLAS Garcia-like (thread a within-TCR panel on one pose) partly recovers the signal — proof
it's the task setup (within-receptor ranking vs cross-complex affinity), not the potential.tcren.mechanics (koff/kinetics, NOT ΔG)weight="invdist2" = multiplicity/dist²).
Pure-numpy, single structure, no MD. Public API:
interface_springs(structure, cutoff=8.0, weight='invdist2') -> InterfaceSprings(a, b, k, rest, axis)
— the TCR-side/pMHC-side Cα anchors, spring stiffnesses, rest lengths, and the unit docking axis
(TCR→pMHC). Raises if no peptide chain.stiffness_tensor(structure, cutoff, weight) -> dict — linear-response K = Σ kᵢ ûᵢ⊗ûᵢ:
S_tot (trace), K_tens (along docking axis), K_shear (S_tot − K_tens), aniso
(K_shear/K_tens), lam_max/lam_min, n_spring. All nan if < 3 springs.rupture(structure, direction='tensile'|'shear'|'auto', cutoff, weight, break_strain=0.5, steps=80) -> dict
— steered-unbinding cartoon (rigidly pull pMHC off, break springs past strain): rupture_force
(peak resisting force), rupture_work (∫ force·displacement), n_spring, break_strain.
"auto" = min-force of tensile/shear.coupling_residues(structure, cutoff=5.0) -> dict — residues in both an intra-body scaffold
contact and the interface: couple_pep/couple_mhc/couple_tcr, couple_total, n_interface.conda run -n tcren-fold python -m tcren.mechanics.tcren.orient.docking + tcren.orient.tcrdock_geometrydocking_angles(structure) -> DockingAngles(crossing_angle, crossing_angle_signed, incident_angle, ...). crossing_angle = the groove-plane "scanning" angle,
incident_angle = the tilt. Computed from the Vα→Vβ axis in the groove frame; no reference DB.tcrdock_geometry.py): docking_geometry(structure) -> DockingGeometry(d, torsion, tcr_unit_y, tcr_unit_z, mhc_unit_y, mhc_unit_z) — native reimplementation of TCRdock
(phbradley/TCRdock, MIT, commit c5a7af4; see THIRD_PARTY_NOTICES.md). MHC + TCR symmetry stubs (β-sheet
floor / Vα-Vβ two-fold), MHC-I core by BLOSUM-align to TCRdock's template, TCR core by conserved IMGT
framework positions from arda region markup. Needs a chain-typed + MHC-annotated structure; class-I only
(class-II raises).scanning_angle is reproducible (= crossing_angle, r≈0.88), but its
pitch_angle is NOT any clean geometric angle (best correlate d, r≈0.42) and out-discriminates every
clean docking feature on TCRvdb (macro-PR≈0.72 vs d≈0.64 / torsion≈0.62 / tilt≈0.58) → its extra signal
is AlphaFold-confidence contamination, not geometry. Prefer the documented d/torsion/crossing/
incident over the opaque upstream pitch_angle.tcren.contact_types (DSSP-style, dep-light)contact_type_counts(cm, interface='tcr_peptide', tcr_regions='all') -> {n_<type>, pairs_<type>} and
classify_contacts(interface_df) -> df + 'contact.type'. Types by priority: salt_bridge, hydrogen_bond,
aromatic, hydrophobic, other, from heavy-atom geometry (no H, no external DSSP). pairs_hydrogen_bond
is the documented, reproducible replacement for the lost ad-hoc n_hbond (tracks it at r≈0.68).tcren.shuffle (tcren shuffle)make_decoys(structures, n_per=10, within_class=True, seed=0) / graft_tcr(pmhc_source, tcr_source) /
run_shuffle(dir, out, n=10, ...). Keep each oriented complex's pMHC intact, graft on a different
complex's TCR (within-MHC-class derangement, no real pairing) → wrong-TCR-on-real-pMHC negatives. Real
(label 1) vs decoy (label 0) trains a label-free TCR-recognition classifier; peptide:MHC energy is
invariant under the graft (built-in control), TCR:peptide/TCR:MHC contacts are new.orient.substitute_tcr. Inputs must be canonically oriented (one common
frame); the graft copies chains with no per-pair alignment, so each grafted TCR keeps its native MHC–TCR
docking angle → the decoy set spans the real docking-angle variance (substitute_tcr would collapse every
donor onto the host's MHC pose). CLI: tcren orient -s natives/ -o oriented/ && tcren shuffle -s oriented/ -o shuffled/ --n 10.tcren.recognition.GaussianBNClassifier): pure-numpy conditional-linear-Gaussian Bayes
net — DAG over standardized features (BIC hill-climb on within-class-centred data) + class y and MHC class
as discrete parent nodes; classifies by the Gaussian log-likelihood ratio. fit/predict_proba, gzip-JSON
save/load, to_dot (graphviz). Trained model shipped at src/tcren/data/shuffle_bn.json.gz; the
reproducible appendix (train+eval, gnuplot ROC/PR + balanced metrics, graphviz BN, marginals) is
appendix/shuffle_bn/ (make). Decoys are regenerable (tcren shuffle --seed 0 --n 10); manifest committed,
full PDBs belong on HF (351 MB).tcren.recognition.BayesianLogisticRecognizer + encode_features): a
discriminative alternative to the BN. encode_features maps each feature by its natural family — circular
dock_torsion → (cos, sin) von-Mises stats, chain_balance → logit, counts/continuous linear, drops the
duplicate n_hbond — then a Bayesian logistic (PyMC NUTS, weakly-informative or horseshoe prior) is fit and
its posterior mean frozen into src/tcren/data/shuffle_logistic.json.gz (dep-light numpy predict_proba).
Real-vs-shuffled 5-fold CV ROC-AUC 0.885 (matches RF, > BN 0.865 / raw-logistic 0.870). On TCRvdb a
supervised refit with the encoding gives 0.860 pooled (> AF 0.794, raw-feature logistic 0.855); the
frozen real-vs-shuffled transfer does NOT carry (0.53, crystal→AF shift, same as the BN). Appendix
appendix/logistic_stan/ (make PY=<pymc-venv>; ROC/PR + posterior-forest gnuplot, encoding table).tcren recognize / recognition_features (2026-07-06): recognition.recognition_features(struct)
ports the manuscript's 35-descriptor extractor into tcren (docking geometry + TCRen/MJ F & poly-Ala dF +
contact tallies + biopython ΔSASA burial + mhc_class_bin) — verified byte-exact vs
canonical2026_features.csv (burial max diff 4e-11). Uses import_structure (C-gene trimmed) to match
training; no _geom C-ext needed (only arda for annotation). frozen_recognizers() loads both
shipped models; real_probability(rows) → {"logistic","bn"} P(real). CLI tcren recognize -s pdbs/ -o out.tsv writes one TSV row/PDB = 35 descriptors + p_real + p_real_bn (--features-only skips models).
The user-facing "one TSV for a/b/d" answer; ddF (ala) stays tcren ddg, koff stays tcren mechanics.--full feature table (2026-07-13): recognition_features(struct, full=True) / tcren recognize --full
append the 18 CDR3-frame (cdr3{a,b}_{reach,ou,ow,on,au,aw,an,topep,ext}, FramePose groove-frame
projection — the cdr3b_* strain signal) + 12 matrix-swap ({tcren,mj,d}_{tp,cdr12,cdr3a,cdr3b},
TCRen−MJ contrast) descriptors → 65 features total. Tuples: RECOGNITION_FEATURES (35),
CDR3_FRAME_FEATURES (18), MATRIX_SWAP_FEATURES (12), FULL_FEATURES (65). Both families verified
byte-exact (max|Δ|=0) vs the manuscript's cached *_cdr3.csv / tcrvdb_matrix_swap.csv.--scores good-results scores (2026-07-13): tcren recognize --scores (implies --full) also emits
p_bind (binder.binder_score, TCRvdb denoised AUC 0.928) and p_forced
(recognition.forced_pose_score / FORCED_POSE_MODEL, a frozen 6-feature strain logistic: crystal-natural
vs AF-forced, 5-fold AUC 0.762 — the "too-good-to-be-true" hallucination flag). Cohort-relative z-combos
(Φ_bind, the crystal<af_real<af_decoy strain gradient) stay analysis-side, computed from these features.
Full column reference: docs/features.rst.kit_score — AF×tcren synergy (2026-07-13): recognition.kit_score(p_bind, iptm) = cohort-relative
z(p_bind)+z(iptm), the fixed no-fit combination of the tcren binder score with the AF ipTM. On TCRvdb raw
labels it beats either alone at precision (macro-PR 0.847 vs 0.782/0.804; P@10% 0.969; Δ vs ipTM +0.041
CI [+0.006,+0.074]) and corrects AF errors (strain flags AF false-positives 0.633; p_bind rescues AF
false-negatives 0.732>ipTM 0.697). The "kit for AI-generated structures" decision procedure is docs/kit.rst.
(No synergy on VDJdb real-vs-mock — there tcren's role is the forced-pose gradient, not discrimination.)mhc.reference.reference_db()easy_search(query, reference_fasta()) rebuilt the 28k-allele target DB + k-mer index on EVERY
call (~4.5 s). reference_db() runs createdb + createindex once into gitignored
data/mhc_cache (the index is the real cost); map_mhc / annotate_mhc_batch pass that DB →
repeated single-structure searches drop to ~0.9 s (5×). Rebuilds if the FASTA is newer.annotate, no separate mhctcren annotate -s … [--regions all|tcr|mhc|peptide] [--pseudo] emits ONE per-residue markup
covering TCR (CDR/FR), MHC groove (HELIX/FLOOR) and peptide. --regions filters by chain class;
--pseudo adds MPS rows. The old tcren mhc command was removed — its allele/class info is
available in the library via mhc.map_mhc / mhc.annotate_mhc.tcren.mhc.annotate_pseudoMPS).
Committed FASTAs src/tcren/data/{mhci,mhcii}_pseudo.fa (built by scripts/build_pseudo_fasta.py
from NetMHCpan tables; unique seqs, header <allele>|n=<count>).notebooks/mhc_pseudosequence_mps.ipynb: MPS residues vs. 5 Å peptide
contacts (~half are direct contacts; the rest line the groove toward the TCR).--mmCIF / --compressorient, superimpose) outputs plain .pdb by
default; --mmCIF switches to .cif, --compress adds a trailing .gz. In the library:
structure_output_path(dir, id, mmcif=…, compress=…) + write_structure(s, path) (dispatches
PDB/mmCIF by suffix; a minimal _atom_site mmCIF loop that round-trips through Biopython).tcren fetch-recent / tcren.recenttcren fetch-recent [--discover --after YYYY-MM-DD] → data/pdb_recent/ (gitignored):
downloads PDB ids (Native2026 seed; --discover adds an RCSB full-text TCR:pMHC search) as
mmCIF .cif.gz (the PDB deprecates split .pdb; handles extended >4-char ids), then
keeps only complexes with all 5 required chains (MHCa + b2m/MHCb + peptide + TCR pair),
validated by one batched annotation pass. tcren.recent.{fetch_ids,discover_similar,native2026_ids}.tcren.paper)from tcren.paper import (
bootstrap, fetch_hf_structures, fetch_vdjdb, fetch_pdb_dates,
copy_external_inputs, copy_legacy_results,
contact_table, # mir extract_contact_map replacement (per structure)
annotate_structure_set, # batched TCR annotation over a folder -> (contacts, markup)
mhc_annotation, # per-structure MHC allele + class over a folder
compare,
)
notebooks/natcompsci2022/. HF structure sets are fetched (gitignored) into
per-set folders directly under notebooks/data/ — notebooks/data/Native2022,
notebooks/data/Native2026, notebooks/data/PolyV2022, notebooks/data/Bobisse,
notebooks/data/Bigot (no structures/ wrapper). Canonical2026 is Native2026 after
tcren orient. All structures are gzipped (*.pdb.gz).notebooks/natcompsci2022/data_legacy/ (vdjdb, Birnbaum, MJ/Keskin, IEDB, epitope lists,
TCRpMHCmodels.tar.gz, PDB dates, mir/R oracle) — never a pipeline input. results_new/ is computed.data/ holds the library dataset (gitignored structures): Native2026 (orientation
references), Canonical2026 (the default superimpose database), PDB_date.tsv,
orient_metadata.json, TCRen_potential.csv. setup.sh runs tcren fetch-data at install to
populate Native2026 + Canonical2026 from HF (or lazily on first superimpose/orient).
Orientation references load 1ao7/1fyt from data/Native2026 via tcren.paths. The numerical
regression oracle (legacy mir/R outputs: contact_maps_PDB.csv, tcren_am/tcren.txt, the
example/ set) lives under tests/assets/oracle/; the legacy R/Java pipeline was deleted.from tcren.project2d import region_pair_contacts, region_pair_summary # needs chain-typed + MHC-annotated structure
from tcren.orient import docking_angles
region_pair_summary(s, kind="closest"|"cb"|"ca") — inter-chain contact counts for every
region pair (CDR↔peptide, peptide↔MHC, TCR↔MHC, intra-TCR …), not just one interface. Three
contact definitions: closest (5 Å closest heavy-atom pair — the original TCRen definition, the
only kind that carries a contact_type bond classification), cb (8 Å Cβ, Cα fallback for Gly),
ca (12 Å Cα). Region-pair labels are ordered canonically (direction-independent).project2d.classify_contact (salt_bridge /
hydrogen_bond / aromatic / hydrophobic / polar). The external biotite.structure.hbond
(Baker-Hubbard) needs explicit hydrogens — it returns 0 on X-ray crystals (no H), so it is
only useful on protonated / NMR / MD structures. Use the heuristic for crystal structures.docking_angles(s) — TCR crossing + incident angle from a groove frame built from the peptide
principal axis + peptide→TCR normal (NOT the whole-complex PCA basis, which the Vα–Vβ spread
contaminates). ~20–70° crossing for αβ; requires a peptide chain (γδ without peptide raises).--ExecutePreprocessor.kernel_name=python3 (or =tcren-nb) or cells silently don't run.HLA-A*02:608N); for
IEDB-style matching, truncate to 2-field group (HLA-A*02).