Screen a cohort#

tcren screen ranks separately modelled candidate complexes for one task. It reports each model’s components, a frozen task-matched combination where the cohort supports one, and the reasons a score is unavailable.

$ tcren screen -s models.tar.gz -o scores.tsv
$ tcren screen -s models.tar.gz --confidence confidence.tsv -o scores.tsv

Choose the task and cohort#

A cohort holds one side fixed: one receptor with varying peptides is epitope ranking; one pMHC with varying receptors is TCR ranking. Automatic detection uses the annotated peptide sequence and CDR3 pair. Keep the MHC background consistent; this identity check does not establish experimental restriction or binding. A mixed set, or a set in which neither side varies, is refused with a diagnostic. --task epitope or --task tcr declares a task but does not override that check.

Two ranking tasks select different structural references, followed by component reporting and a scorable-cohort check.

The four exposed components#

Confidence: iptm is the generator’s interface predicted TM score, supplied from the input set’s metadata or a unique complex.id/iptm table passed with --confidence. tcren does not compute it. Missing confidence is reported.

Energy: a directed statistical contact potential sums residue-pair entries on the observed TCR:peptide contact map:

\[\Phi_{\mathrm{TP}}(x)=\sum_{(u,v)\in\mathcal C_{\mathrm{TP}}(x)}\phi_{a_u b_v}, \qquad \Delta_s\Phi_{\mathrm{TP}}(x)=\Phi_{\mathrm{TP}}(x)-\Phi_{\mathrm{TP}}(A_s x).\]

Here \(x\) is one annotated structure, \(\mathcal C_{\mathrm{TP}}(x)\) its residue contacts at a closest-heavy-atom cutoff of 5 Å, \(u\) a TCR residue, \(v\) a peptide residue, and \(a_u,b_v\) their amino-acid identities. \(\phi_{ab}\) is the directed TCRen2 table entry. \(A_s\) truncates the selected side \(s\) to alanine in three dimensions, retaining backbone and Cβ atoms, and rebuilds the map at the same cutoff. The energy is a dimensionless statistical contact quantity; lower differences are the declared favourable direction.

Truncate side chains in coordinates, rebuild the contact map, and subtract reference energy from real energy.

The substituted side follows the side that varies. Epitope ranking uses dPhi_tcr_pep from peptide substitution; TCR ranking uses dFT_tcr_pep_cdr from CDR substitution. A fixed-map virtual identity substitution is a different quantity. screen always computes the structural reference.

Geometry: sc_shape is the Pearson correlation between finite paired height samples of the pMHC face and receptor underside in the same frame:

\[r_h=\frac{\sum_{k\in\mathcal K}(h_k-\bar h)(t_k-\bar t)} {\sqrt{\sum_{k\in\mathcal K}(h_k-\bar h)^2}\sqrt{\sum_{k\in\mathcal K}(t_k-\bar t)^2}}.\]

\(\mathcal K\) contains the paired interface cells, \(h_k,t_k\) are their heights in Å and the bars denote means on those cells. The correlation is dimensionless; degenerate or insufficient samples are unavailable, not neutral zero. See tcren.topology.surface for grid and contact-plane definitions.

Topology: g_cyclo_frac is the CDR:pMHC residue-graph cycle fraction:

\[g_{\mathrm{cyclo}}=\frac{E-V+C}{E}, \qquad E>0.\]

\(E\) counts unique residue-contact edges, \(V\) contacted vertices and \(C\) connected components. The graph contains CDR:peptide and CDR:MHC edges. This dimensionless graph quantity is carried in the TCR-ranking combination; topology is excluded from the epitope-ranking combination.

Frozen standardization and combination#

For each observed component \(i\), its frozen mean \(\mu_i\), positive scale \(\sigma_i\), declared direction \(d_i\in\{-1,+1\}\) and fixed weight \(w_i\geq0\) give

\[z_i=d_i\frac{x_i-\mu_i}{\sigma_i}, \qquad S=\frac{\sum_{i\in\mathcal O}w_i z_i}{\sqrt{\sum_{i\in\mathcal O}w_i^2}}.\]

\(x_i\) is the raw value and \(\mathcal O\) contains the observed components. Missing values are omitted from both sums. The combination is unavailable when no weighted contribution remains. Higher \(S\) is the declared favourable direction. It is dimensionless and unbounded, not a binding free energy or a calibrated probability. Dependence among components is not a claim of independent evidence or a calibrated Stouffer significance test.

The bundled references use confidence weight 0.8 for TCR ranking; energy, geometry and topology share the remaining 0.2 equally. Epitope ranking uses confidence and energy with weights 0.5 each. --weight explicitly changes the confidence weight within [0,1]; the structural components share the remainder.

Means and scales are empirical reference dependencies estimated on a held-out pool of 729 models over 14 off-panel epitopes, without reading labels for those moments. Signs are declared a priori; saved labelled training diagnostics check them. The TCR confidence weight is an explicit design choice informed by recorded evaluation, not a prospectively validated learned coefficient. See SOURCES and Final fit-free calculations for the dependency contract. Query rows never re-estimate these constants, so a row’s numerical combination does not depend on its neighbours. The cohort governs whether that score is emitted.

Experimental template-availability gate#

For TCR ranking, an explicit native-crystal inventory can gate the structural contribution without changing its components or frozen scales:

$ tcren screen -s models.tar.gz --confidence confidence.tsv \
    --template-metadata Native2026/metadata.tsv --weight 0.6 -o diagnostic.tsv

--template-metadata requires an epitope column and an explicit --weight. An epitope present in that inventory uses the requested confidence weight; an absent epitope uses weight 1 (standardized ipTM alone). Membership strips outer whitespace and ignores case. The inventory’s SHA256, epitope, membership and requested/effective weights are recorded; native_template and confidence_weight accompany the rows. Pin the inventory revision as well as its hash when reproducing a result. There is no implicit download or inferred template match. Availability is epitope-level: it does not establish matching MHC, construct correspondence or an accurate predicted pose.

The example’s 0.6 is an evaluation-selected diagnostic, not a bundled default or an independently validated coefficient. The unchanged TCR default remains 0.8; the gate is opt-in. The epitope-ranking path does not accept this gate. No gate is selected from a query’s labels or its descriptor distribution.

The observed-channel Stouffer denominator still applies. If ipTM is absent when the gate selects confidence alone, the score is null with no weighted component observed; structural values stay visible but cannot silently restore that score. A covered epitope with missing ipTM can still score on observed, positively weighted structural channels. Zero-contact discard, the cohort floor and reporting-only flags continue to apply. Explicit flag responses remain separate user choices and are recorded in the output.

Energy, orientation and target relief#

Keep the structural alanine energy alongside ipTM and the aggregate: it measures CDR:peptide chemistry for receptor ranking and peptide chemistry for epitope ranking. A gate that omits energy from one aggregate does not invalidate its separate readout or establish that confidence is always stronger.

The geometry component sc_shape measures receptor–pMHC height-field complementarity. TCR:MHC orientation (crossing angle, docking torsion and height) and receptor-free pMHC topography (surface relief, accessible peptide and surface chemistry) remain distinct toolkit outputs; they are not additional terms in this aggregate. pitch is excluded as generator-confidence leakage. The graph topology and surface geometry can both describe packing and interface size, so their presence does not establish independent evidence. Near-orthogonal confidence and structural directions motivate a standardized sum, but do not make its denominator a calibrated significance test. Inspect the individual channels, their missingness, the target surface and docking geometry with flags before interpreting a ranking.

Optional confidence orthogonalization#

A reference may carry a frozen confidence_rho on a structural component. Where it does, that component enters the combination with its confidence-explained part removed and an explicit rescaling applied:

\[z_i^{\perp}=\frac{z_i-\rho_i z_{\mathrm{conf}}}{\sqrt{1-\rho_i^{2}}}, \qquad \rho_i\in(-1,1).\]

\(\rho_i\) is a caller-supplied frozen coefficient. If both standardized variables have unit variance and \(\rho_i\) is their correlation in the same frozen reference population, the residual is uncorrelated with confidence and the division restores unit variance in that population. Global frozen scales do not ensure unit variance within each cohort, and uncorrelated channels need not be independent. Do not estimate this coefficient from query rows.

This is an explicit change of basis, not new evidence. Keeping the same weights can change rankings after subtraction or rescaling; neither guarantees predictive improvement. The reference must document the coefficient’s population and meaning.

Rows whose confidence is missing keep \(z_i\) unchanged — there is nothing to project out of them — and confidence_orthogonalized reports per row whether the correction was applied. The column is emitted only by a reference that carries the key. The bundled references do not, so their scores are unchanged.

Discard and cohort floor#

Models with zero TCR:peptide contacts remain in output with no_interface true and a reason in score_unavailable, but no score. They do not count toward --min-cohort (default 30). Below the floor every row retains its component readouts without a combined score. A flag response cannot restore discarded or withheld scores or erase their original unavailability reasons.

Generator confidence reports pose quality; a binder-labelled pair may still have an off-groove prediction. Reversing such a score would reward modelling failure. Inspect model quality and provenance before interpreting discordant labels.

Flags and explicit responses#

Flags report by default. small_cohort describes the scorable floor; no_interface reports zero-contact models; low_confidence compares cohort mean ipTM with the frozen reference distribution; confidence_disagrees reports opposing confidence and structure rankings. forced_pose is unavailable unless strain is standardized against the population used for its reference cut.

cohort_confidence_z is the standardized cohort mean, using the frozen per-epitope mean 0.74562 and scale 0.035717; low_confidence fires below -0.6. These stored constants describe the reference, not query-derived parameters. A flag is an applicability observation, not a binding label or a validated correction.

--on-flag controls the response to low confidence:

  • report (default): retain the score and report the flags.

  • structure: omit confidence from the combination.

  • geometry: report the standardized geometry contribution as the score.

  • withhold: withhold the combined score.

  • reverse: negate the score; opt-in and not recommended as a modelling correction.

Responses change only the combined score. Raw components and missingness remain visible; flag_response and flag_response_reason record an applied response. References lacking a geometry component cannot use the geometry response.

Output and interpretation#

The TSV keeps complex.id, raw components, z_* contributions, missing_* flags, n_components, screen_score and score_unavailable. Cohort flags, confidence statistics and zero-contact counts accompany each row. The provenance sidecar records the task, reference hash, confidence weight, floor and flag response.

For receptor ranking, keep ipTM primary and read the structural components beside it. The combination is complementary evidence, not an established universal improvement. Report template coverage separately. Peptide-intrinsic surface properties and a high CPL ranking alone do not establish receptor specificity. Scientific evaluation, figures and historical results belong to the manuscript and benchmark records; this page specifies the software’s current behavior.

Library API#

Task-matched cohort screening with frozen references and explicit availability.

Peptide ranking fixes a receptor and varies epitopes; receptor ranking fixes a pMHC and varies receptors. The structural alanine reference follows the varying side. Topology is included only for the receptor-ranking task.

The weighted Stouffer readout combines direction-corrected standardized components against a frozen task reference. ipTM is caller-supplied and remains the primary receptor-ranking comparator. The combined score is dimensionless, not a calibrated probability or a physical binding free energy.

Models with no TCR:peptide contacts are retained with discard reasons and do not count toward the cohort floor. Below the default 30-model floor, components are reported without a combined score. Cohort flags report by default; explicit responses preserve discarded and withheld rows. No query-cohort normalization or fitting is performed. Equations and output semantics: docs/screening.rst.

tcren.screen.MIN_COHORT = 30#

Below this many models the combined score is withheld; see the module docstring.

tcren.screen.DEFAULT_WEIGHT = 0.8#

Fallback confidence weight when a reference does not declare one. Each shipped reference carries its own default_weight, because the right weight is task-specific: ipTM is much the strongest input for TCR ranking and the energy is stronger for epitope ranking.

class tcren.screen.CohortKind(*values)[source]#

Which side varies across the cohort, and therefore which score applies.

tcren.screen.bundled_reference(task)[source]#

The shipped frozen reference for one task, with its own hash for provenance.

Parameters:

task (CohortKind)

Return type:

dict

tcren.screen.template_coverage(peptide, metadata)[source]#

Epitope-level crystal availability from an explicit, hash-recorded metadata TSV.

The caller supplies a native-crystal inventory (for example Native2026), not model metadata. Membership is case-insensitive; it does not establish matching MHC, construct correspondence or pose accuracy. No network lookup is performed.

Parameters:
  • peptide (str)

  • metadata (Path)

Return type:

dict

tcren.screen.orthogonalize(z, z_confidence, rho)[source]#

Remove the confidence-explained part of a standardized component and restore unit scale.

\[z^{\perp} = \frac{z - \rho\, z_{\mathrm{conf}}}{\sqrt{1 - \rho^{2}}}\]

\(\rho\) is a caller-supplied frozen coefficient. If both variables have unit variance and rho is their correlation in the same frozen reference population, the result is uncorrelated with confidence and has unit variance in that population. Frozen global scales do not imply unit within-cohort variances, and uncorrelated quantities need not be independent.

This is an explicit change of basis, not new evidence. With fixed weights, subtraction and rescaling can change rankings; neither operation guarantees a predictive improvement. The bundled references carry no such coefficient.

Rows whose confidence is missing keep z unchanged – there is nothing to project out of them – rather than being dropped or imputed.

Parameters:
  • z (ndarray)

  • z_confidence (ndarray)

  • rho (float)

Return type:

ndarray

tcren.screen.stouffer(z, weights)[source]#

Weighted Stouffer combination, sum(w_i z_i) / sqrt(sum w_i^2), row-wise.

Reduces to plain Stouffer when the weights are equal. Rows are combined over the columns that are finite, so a missing component is dropped from both sums rather than imputed; a row with nothing finite returns NaN.

Parameters:
  • z (ndarray) – (n_rows, n_components) standardized, direction-corrected values.

  • weights (ndarray) – one non-negative weight per component.

Return type:

ndarray

tcren.screen.cohort_signature(peptides, receptors)[source]#

Decide which side is held fixed, or refuse and say what differs.

Parameters:
  • peptides – one peptide identity per structure, in input order.

  • receptors – one receptor identity per structure, typically the (CDR3a, CDR3b) pair read off the annotated FR3/FR4 boundaries. Never reconstruct a junction as "C" + cdr3 + "F"; the anchors are a lookup.

Returns:

The cohort kind and a summary dict with the distinct counts actually observed.

Return type:

tuple[CohortKind, dict]

tcren.screen.identities(structures)[source]#

Per structure, the peptide sequence and the (CDR3a, CDR3b) pair.

The CDR3s are read off the annotated CDR3 regions, whose boundaries come from the FR3/FR4 markup. They are never reconstructed as "C" + cdr3 + "F" – the junction anchors are a lookup, and that shortcut breaks on tryptophan anchors and on CDR3s ending in F.

Raises:

ValueError – if a structure carries no peptide chain or no CDR3 on either TCR chain, which means it cannot be placed in a cohort.

Return type:

tuple[list[str], list[tuple[str, str]]]

tcren.screen.FLAGS = {'confidence_disagrees': 'ipTM and the structural block rank this cohort differently, so at most one of them can be right about it', 'forced_pose': "the cohort's mean interface strain is above the reference cut: the generator had to force these poses, and the contact energy is known to invert on forced poses", 'low_confidence': "the cohort's mean ipTM sits well below the reference distribution of per-epitope means, the regime where the generator's own ranking is least reliable; read cohort_confidence_z for how far below", 'no_interface': 'models in this cohort have no TCR:peptide contact at all -- the receptor was not placed on the groove, so every structural component for them is meaningless', 'small_cohort': 'fewer models than --min-cohort, so the combined score is withheld and only the components are reported'}#

What each flag means, in the order a reader should read them. Kept here so the CLI, the docs and the tests cannot drift apart.

tcren.screen.cohort_flags(table, reference, *, min_cohort=30, strain=None, calibrated=False)[source]#

Label-free warnings about the cohort as a whole. Advisory, never applied to the score.

Every flag reads the cohort’s own descriptors and no outcome, so all of them are available on an unseen epitope. They mark a regime, not a verdict: a flagged cohort is one where the evidence says a ranking may be untrustworthy, and the right response is to look rather than to accept a number.

They do not act on the score unless a caller asks. Applicability observations do not validate an automatic corrective response: see WITHHOLDING_FLAGS.

Parameters:
  • table (DataFrame) – the same descriptor table passed to screen_scores().

  • reference (dict) – the frozen reference, whose cohort_confidence moments and forced_pose cut supply the thresholds.

  • min_cohort (int) – the floor below which a score is withheld.

  • strain (ndarray | None) – optional per-model interface strain, from tcren.cohort.strain_z(). Without it the forced-pose flag is reported as unavailable rather than guessed.

  • calibrated (bool) – whether strain was standardized against the same population the reference cut came from. It is not comparable otherwise, so the flag stays unavailable.

Returns:

A dict of flag name to bool (or None where the inputs for that flag were absent), alongside the statistics the flags were derived from.

Return type:

dict

tcren.screen.WITHHOLDING_FLAGS: dict[CohortKind, tuple[str, ...]] = {CohortKind.EPITOPE_RANKING: (), CohortKind.TCR_RANKING: ()}#

No cohort flag automatically withholds a score. Responses remain explicit; the no-interface discard and cohort floor apply independently on both tasks.

tcren.screen.withhold_reason(flags, task)[source]#

The first withholding flag that fired for this task, as the reason text, or None.

Parameters:
Return type:

str | None

class tcren.screen.FlagResponse(*values)[source]#

Explicit responses to a low-confidence cohort; REPORT leaves scores unchanged.

Alternatives change only the combined score. Components, missingness and original reasons for unavailable scores remain visible. Reversal is not a validated correction for modelling failure.

tcren.screen.apply_flag_response(scored, table, reference, *, response, reason)[source]#

Rewrite screen_score according to response, recording what was done and why.

The components are never rewritten – only the combined score – so a reader can always see the evidence the response was applied to.

Parameters:
  • scored (DataFrame)

  • table (DataFrame)

  • reference (dict)

  • response (FlagResponse)

  • reason (str)

Return type:

DataFrame

tcren.screen.screen_scores(table, reference, *, weight=None, native_template=None, min_cohort=30, suppress=None)[source]#

Score one cohort, one row per model, in input order.

Parameters:
  • table (DataFrame) – descriptor table keyed by a unique nonempty complex.id, carrying every component column the reference names.

  • reference (dict) – a frozen reference dict, normally from bundled_reference().

  • weight (float | None) – confidence weight in the Stouffer combination, in [0, 1]. None takes the reference’s own default_weight, which is task-specific.

  • native_template (bool | None) – optional TCR-ranking applicability gate. False uses confidence alone; True uses the requested weight. None keeps historical behavior. Components remain visible regardless of the gate. This is crystal availability, not a pose-quality judgement.

  • min_cohort (int) – below this many scorable rows the combined score is withheld. Models with no TCR:peptide interface are discarded and do not count toward it.

  • suppress (str | None) – when set, withhold the combined score for every row and record this as the reason. Used to act on a cohort flag – see withhold_reason().

Returns:

each component’s raw value, its standardized contribution and a missingness flag, n_components, no_interface, screen_score and score_unavailable. A row scores null rather than taking a neutral default when it has no observed component, when its receptor was never modelled on the groove, or when the cohort has fewer than min_cohort scorable models. Discarded rows are kept in the output so that nothing disappears silently.

Return type:

Per model

tcren.screen.describe_reference(reference)[source]#

One line per component: its name, column, direction and frozen scale.

Parameters:

reference (dict)

Return type:

str

tcren.screen.read_reference(path)[source]#

Load a reference from disk, recording its hash the same way the bundled one does.

Parameters:

path (Path)

Return type:

dict