Explore a TTDPSFLGRY interface#

Inspect observed atom/residue contacts, chemical types, per-residue potential contributions, structural alanine contrasts and frozen local contact enrichment. All scientific quantities come from TCRen CLI commands or public APIs; the notebook selects and displays their tables.

Input: supply one alpha/beta TCR–pMHC PDB/mmCIF model whose observed peptide is TTDPSFLGRY. This notebook does not distribute that structure or assert that a public TTD coordinate download is available. Use only coordinates you are authorized to access. No experimental binding label is inferred from the input.

Install tcren[notebooks], choose that environment’s kernel, and prepare references with tcren build-mhc-ref and ARDA’s documented setup. Reference acquisition/index construction is setup work; no query-cohort fitting or control generation occurs here.

[ ]:
# Report the kernel and scientific package versions before importing numerical APIs.
import os, sys, json, tempfile, subprocess, time
from pathlib import Path
from importlib.metadata import version
from importlib.resources import files
import tcren
import polars as pl
from IPython.display import display
print({"python": sys.version.split()[0], **{name: version(name) for name in ("tcren", "polars", "numpy", "biopython")}})

Parameters and a fresh run directory#

Set TCREN_TTD_STRUCTURE or edit STRUCTURE below. THREADS=0 uses allocated CPUs; use a positive number for an explicit bound. Optional paths are existing recorded screen output and supplied generator confidence. The single-model representative score is off unless explicitly enabled; it is separate from default cohort scoring.

Every run creates a new temporary output directory. Requested tables and their provenance remain there for inspection; a later run rebuilds them instead of reusing feature rows.

[ ]:
# Configure one supplied structure; optional inputs never trigger a cohort benchmark.
STRUCTURE = Path(os.environ.get("TCREN_TTD_STRUCTURE", "model.pdb")).expanduser().resolve()
THREADS = int(os.environ.get("TCREN_TTD_THREADS", "0"))
COHORT_SCORES = os.environ.get("TCREN_TTD_COHORT_SCORES", "")
SINGLE_CONFIDENCE = os.environ.get("TCREN_TTD_CONFIDENCE", "")
RUN_REPRESENTATIVE = os.environ.get("TCREN_TTD_REPRESENTATIVE", "0") == "1"
assert STRUCTURE.is_file(), "Supply TCREN_TTD_STRUCTURE or edit STRUCTURE to your authorized TTD model."
assert THREADS >= 0, "THREADS must be zero or positive."
work = Path(tempfile.mkdtemp(prefix="tcren-ttd-"))
stages = []
def cli(label, *arguments):
    started = time.perf_counter()
    with (work / (label + ".log")).open("w") as log:
        subprocess.run([sys.executable, "-m", "tcren.cli", *map(str, arguments)],
                       check=True, stdout=log, stderr=subprocess.STDOUT, timeout=180)
    stages.append({"stage": label, "wall_s": time.perf_counter() - started})
print("Fresh local output directory:", work)

Export the observed interface#

Each command receives the complete query set (one model here). The installed CLI owns batched annotation, heavy-atom selection and contact definitions. Atomic contacts retain all six CDR loops; the inventory also retains observed noncontacting atoms. The fixed 5 Å cutoff matches the bundled enrichment reference. No threshold sweep is performed.

[ ]:
# Export coordinates-derived tables with explicit potential and interface choices.
for quantity, filename in (("atom-inventory", "atoms.parquet"), ("contact-atoms", "contacts.parquet"),
                           ("residue", "residue.tsv"), ("position", "position.tsv")):
    arguments = ["export", "-s", STRUCTURE, "--quantity", quantity, "--interface", "tcr_peptide",
                 "--cutoff", "5", "-t", THREADS, "-o", work / filename]
    if quantity in ("residue", "position"):
        arguments += ["--potential", "tcren2"]
    cli(quantity, *arguments)
    ledger = pl.read_csv(str(work / filename) + ".accounting.tsv", separator="\t")
    assert ledger.height == 1 and ledger["status"].to_list() == ["ok"], "Inspect the local accounting and log before proceeding."
atoms = pl.read_parquet(work / "atoms.parquet")
contacts = pl.read_parquet(work / "contacts.parquet")
identity = atoms.filter(pl.col("chain.type") == "PEPTIDE").select(
    "chain.id", "residue.index", "residue.aa").unique().sort("residue.index")
assert identity["chain.id"].n_unique() == 1
assert "".join(identity["residue.aa"]) == "TTDPSFLGRY", "The supplied observed peptide is not TTDPSFLGRY."
MODEL_ID = atoms["pdb.id"].unique().item()
display(identity)

Atom pairs, residue pairs and chemistry#

These are different observation counts. The CLI summary separates atom and residue pairs, with exact structure support. Chemical flags are multi-label distance/type heuristics; a hydrogen-bond-compatible flag is not explicit-hydrogen/angle validation. The closest atom pair alone need not reveal every chemical interaction between two residues. Tables below can be filtered or sorted in the notebook without recalculating the score.

[ ]:
# Read the CLI's existing atom/residue chemical summary and inspect physical atom witnesses.
summary = pl.read_csv(str(work / "contacts.parquet") + ".summary.tsv", separator="\t")
display(summary)
flags = [column for column in contacts.columns if column.startswith("is_")]
display(contacts.select("chain.id.from", "region.type.from", "residue.index.from", "residue.aa.from", "atom.from",
                        "chain.id.to", "residue.index.to", "residue.aa.to", "atom.to", "dist", *flags).sort("dist").head(40))

Per-residue potential contributions#

phi is the contact-potential attribution for each contacting residue; n_contacts is its residue-pair contact count. More negative phi is more favourable on this potential’s scale. A contact is attributed to both endpoints, so summing both sides doubles the interface total. Attribution is not a causal residue effect or measured binding energy. The position export supplies the peptide-side decomposition and physical residue keys.

[ ]:
# Display the CLI's potential decomposition, without recomputing or renormalizing it.
residue = pl.read_csv(work / "residue.tsv", separator="\t")
position = pl.read_csv(work / "position.tsv", separator="\t")
display(residue.sort("phi"))
display(position.sort("peptide.pos"))

Structural single-site alanine contrasts#

The existing ddg CLI truncates one selected side chain at a time and rebuilds the contact map. This is distinct from fixed-map virtual substitution and from the attribution above. The exported ddG is native minus alanine-mutant statistical-potential value: positive means the alanine mutant has the lower value. It is dimensionless, not kcal/mol. Peptide pos is zero-based; receptor rows also retain chain, loop and residue index. These model-based contrasts do not establish an experimental or causal binding effect.

[ ]:
# Use the library's structural alanine scan for peptide and contacted CDR residues.
cli("alanine", "ddg", "-s", STRUCTURE, "--native", "TTDPSFLGRY", "--alanine-scan", "--side", "both",
    "--regions", "cdr", "--interface", "tcr_peptide", "--potential", "tcren2", "--cutoff", "5",
    "-t", THREADS, "-o", work / "alanine.csv")
alanine = pl.read_csv(work / "alanine.csv")
display(alanine.sort("side", "pos"))

Frozen local enrichment across all six CDR loops#

residue_counts retains zero-contact CDR1/2/3 residues in both chains plus peptide residues. CDR3 uses the library’s anchor-excluded annotation. Completeness and observed heavy-atom availability remain explicit; missing atoms are not reconstructed.

score_residues reads the packaged mock histograms and reports local cycle counts, reference-residue support and inclusive empirical tails. bundled_enrichment aggregates through the existing Fisher implementation and calibrates against the packaged whole mock graphs, returning enrichment, null_models and local-test support. Local tails and whole graph enrichment are descriptive structural evidence, not binding probabilities. This is not a new control fit, a sequence repertoire motif search or a single-loop substitute.

[ ]:
# Call the public frozen-reference APIs; do not reproduce their formulas in the notebook.
from tcren.contacts.residue_surprise import residue_counts, score_residues
from tcren.contacts.motif import bundled_enrichment
local = residue_counts(atoms, contacts, atom_scope="all")
reference = json.loads(files("tcren.data").joinpath("motif_residue_reference.json").read_text())
local_support = score_residues(local, reference, "cycles")
enrichment = bundled_enrichment(local)
local_support.write_parquet(work / "local-enrichment.parquet")
enrichment.write_csv(work / "enrichment.tsv", separator="\t")
display(local_support.select("chain", "region", "residue_index", "aa", "available", "complete",
                              "occupied", "pairs", "partners", "cycles", "reference_residues",
                              "reference_mass", "tail_probability", "bits").sort("chain", "region", "residue_index"))
display(enrichment)

Read a recorded cohort score, or explicitly select a singleton representative#

The default TCR score uses the complete unlabelled fixed-pMHC cohort’s mean pLDDT, with a 30-scorable-model floor. To calculate that cohort elsewhere, supply its complete manifest and generator confidence (unique complex.id, iptm on [0,1], plddt on [0,100]):

tcren screen -s ttd-cohort.txt --task tcr --confidence confidence.tsv -t 0 -o cohort-scores.tsv

The cell below only reads an optional existing screen table. It does not run a cohort benchmark. Input IDs must match this model; inspect score_unavailable, no-contact flags, components and weights alongside the rank score. Binding labels do not enter this inspection.

For a singleton, nearest-plddt is an explicit alternative, enabled only by TCREN_TTD_REPRESENTATIVE=1 plus TCREN_TTD_CONFIDENCE. It selects a frozen representative context, not the independently measured true cohort mean. It is not the default cohort score or a calibrated binding probability. Missing pLDDT withholds this context.

[ ]:
# Optional score context: read supplied output; run a singleton alternative only on explicit opt-in.
if COHORT_SCORES:
    cohort = pl.read_csv(Path(COHORT_SCORES).expanduser(), separator="\t")
    selected = cohort.filter(pl.col("complex.id") == MODEL_ID)
    assert selected.height == 1, "Expected exactly one matching model in the recorded cohort output."
    display(selected)
if RUN_REPRESENTATIVE:
    assert SINGLE_CONFIDENCE, "Supply generator confidence explicitly for the singleton alternative."
    cli("representative", "screen", "-s", STRUCTURE, "--task", "tcr", "--confidence-context", "nearest-plddt",
        "--min-cohort", "1", "--confidence", Path(SINGLE_CONFIDENCE).expanduser(), "-t", THREADS,
        "-o", work / "representative.tsv")
    display(pl.read_csv(work / "representative.tsv", separator="\t"))
print("No cohort scoring is launched by this notebook.")

Run diagnostics and reuse#

The tables describe this supplied pose, not whether its receptor binds experimentally. Save requested final exports together with their provenance sidecars, accounting and reference hashes. Provenance can contain local paths or private identifiers; review it before sharing. No input coordinates, reference source maps or executed outputs are embedded in the distributed notebook. The documentation renders it without execution.

[ ]:
# Summarize command runtimes and requested final table sizes, without evaluating a benchmark.
display(pl.DataFrame(stages))
display(pl.DataFrame({"table": ["observed atoms", "atom contacts", "residue contributions", "alanine contrasts", "local residue evidence"],
                      "rows": [atoms.height, contacts.height, residue.height, alanine.height, local_support.height]}))
print("Inspect the fresh local output directory above for complete exports and provenance.")