Metadata-Version: 2.5
Name: foldmetrics
Version: 0.2.2
Summary: Unified confidence metrics (pTM, ipTM, pLDDT, ipLDDT, PAE, ipSAE, ipSAE2, pDockQ, pDockQ2, LIS, DockQ) and interface contacts for AlphaFold2/3, ColabFold, Boltz, Chai-1, Protenix, Mol-1, OpenDDE, HelixFold3 and SeedFold predictions
Project-URL: Homepage, https://github.com/ChiaChunL/foldmetrics
Project-URL: Repository, https://github.com/ChiaChunL/foldmetrics
Project-URL: Issues, https://github.com/ChiaChunL/foldmetrics/issues
Author-email: Jiajun Li <ChiaChun.Le@gmail.com>
License-Expression: BSD-3-Clause AND MIT
License-File: LICENSE
License-File: src/foldmetrics/_ipsae2/LICENSE
Keywords: alphafold,bioinformatics,boltz,chai-1,helixfold3,ipsae,ipsae2,iptm,mol-1,opendde,pae,pdockq,plddt,protein-complex,protenix,seedfold,structure-prediction
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Science/Research
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
Requires-Python: >=3.10
Requires-Dist: gemmi>=0.6.4
Requires-Dist: matplotlib>=3.7
Requires-Dist: numpy>=1.23
Requires-Dist: pandas>=2.0
Provides-Extra: completion
Requires-Dist: argcomplete>=3.0; extra == 'completion'
Provides-Extra: dev
Requires-Dist: dockq>=2.0; (python_version < '3.13') and extra == 'dev'
Requires-Dist: pytest>=7.4; extra == 'dev'
Requires-Dist: ruff>=0.5; extra == 'dev'
Provides-Extra: pymol
Requires-Dist: pymol-open-source-whl>=3.2.0.2; extra == 'pymol'
Description-Content-Type: text/markdown

# foldmetrics: unified confidence metrics & interface contacts for structure-prediction models

<img src="https://raw.githubusercontent.com/ChiaChunL/foldmetrics/main/docs/assets/foldmetrics_banner.png" alt="foldmetrics" width="100%">

| Testing | [![CI](https://github.com/ChiaChunL/foldmetrics/actions/workflows/ci.yml/badge.svg)](https://github.com/ChiaChunL/foldmetrics/actions/workflows/ci.yml) |
|---|---|
| Package | [![PyPI Latest Release](https://img.shields.io/pypi/v/foldmetrics.svg)](https://pypi.org/project/foldmetrics/) [![Python versions](https://img.shields.io/pypi/pyversions/foldmetrics.svg)](https://pypi.org/project/foldmetrics/) [![PyPI total downloads](https://img.shields.io/pepy/dt/foldmetrics.svg?label=total%20downloads)](https://pepy.tech/projects/foldmetrics) |
| Meta | [![License - BSD 3-Clause](https://img.shields.io/badge/license-BSD%203--Clause-blue.svg)](LICENSE) [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff) |

Download statistics: [PyPI totals (Pepy)](https://pepy.tech/projects/foldmetrics).

## 🧬 What is it?

`foldmetrics` ingests the raw output folders of the mainstream structure
predictors — **AlphaFold2 / AlphaFold-Multimer, ColabFold, AlphaFold3, Boltz,
Chai-1, Protenix, Mol-1, OpenDDE, HelixFold3, SeedFold** — and computes a consistent set of quality metrics for
single models or whole batches, with native multi-seed and multi-sample
output support. Protein-pair metrics are the primary validated workflow;
ligand-token scores remain experimental:

| Metric | What it tells you | Source |
|---|---|---|
| `ptm`, `iptm` | global / interface predicted TM-score | read from tool output |
| `ranking_score` | tool-native model ranking (AF3 `ranking_score`, Boltz `confidence_score`, Chai `aggregate_score`, AF2 `ranking_confidence`) | read from tool output |
| `plddt_mean` | mean per-token pLDDT | computed |
| `iplddt` | mean pLDDT over interface residues (contact atoms within 8 Å across chains) | computed |
| `pae_mean`, `ipae_mean` | mean PAE (all off-diagonal / inter-chain blocks) | computed |
| `ipsae` | interface score from PAE with per-residue d0 (Dunbrack 2025) | computed |
| `ipsae2` | 2026 directional ipSAE for proteins, nucleic acids, ligands and ions | computed alongside `ipsae` |
| `pdockq` | interface score from contacts + pLDDT (Bryant 2022) | computed |
| `pdockq2` | interface score from contacts + pLDDT + PAE (Zhu 2023) | computed |
| `lis` | Local Interaction Score from PAE (Kim 2024) | computed |
| `dockq` | true interface accuracy vs a reference structure (Basu & Wallner 2016) | computed |

Beyond scores it extracts **confident interface contacts** (with
ready-to-open PyMOL/ChimeraX sessions) and renders **publication-oriented
figures**.

Point it at whatever the engine wrote — its own output tree, untouched.
To *produce* those predictions in the first place,
[foldrunner](https://github.com/ChiaChunL/foldrunner) enumerates the pairs,
computes each MSA once and drives all of these engines from one panel; its
output is what foldmetrics reads here.

## 📦 Installation

```bash
pip install foldmetrics
```

That is the whole install: every metric, DockQ included, the interface
contacts, and the figures — the structure panel is drawn by a built-in
ribbon renderer on every platform. For ray-traced PyMOL cartoons, contact
views and `.pse` sessions, add the one optional extra:

```bash
pip install "foldmetrics[pymol]"
```

The optional extra installs
[`pymol-open-source-whl`](https://github.com/urban233/pymol-open-source-whl),
an unofficial build of open-source PyMOL. Rendering has been exercised on
Linux and macOS; Windows is not currently in our CI test matrix. A PyMOL
from Homebrew or conda-forge is found as well. ChimeraX is installed separately
and is required only to generate/open its `.cxs` sessions.

Development install — adds pytest, ruff and the official `DockQ` package,
which serves only as the reference the built-in implementation is tested
against:

```bash
git clone https://github.com/ChiaChunL/foldmetrics.git
cd foldmetrics
pip install -e ".[dev]"
```

## ⚡ Quickstart

CLI (`foldmetrics`, short alias `fmx`):

Every command below runs as-is from a clone, against the bundled real
examples — swap `examples/data` for your own prediction folders or files:

```bash
# score everything (tools are auto-detected and can be mixed)
fmx score examples/data -o metrics.tsv --interfaces interfaces.tsv --plot plots/

# one model — keep the companion confidence files beside it
fmx score examples/data/af3_server/fold_barnase_barstar_s318_model_0.cif -o model.tsv

# one metric only
fmx ipsae examples/data
fmx iplddt examples/data
fmx ipae examples/data
fmx score examples/data --metrics ipsae,pdockq2,lis
fmx score examples/data --metrics ipsae,ipsae2 --by-target ipsae_by_target.tsv

# 2026 ipSAE convention: both directions, selected direction, n0 and d0
fmx ipsae2 examples/data -o ipsae2.tsv

# campaign view: aggregate seeds/samples per target and tool
fmx score examples/data --by-target summary_by_target.tsv

# confident interface contacts: table + figure + PyMOL/ChimeraX sessions
fmx contacts examples/data/af3_server -o contacts.tsv --plot plots/

# DockQ: the AlphaFold2 model against the AlphaFold-Server model as reference
fmx dockq examples/data/af2_multimer --ref examples/data/af3_server/fold_barnase_barstar_s318_model_0.cif

# what would be scored?
fmx detect examples/data
```

Python:

```python
import foldmetrics as fmx

df = fmx.evaluate("examples/data")  # one row per model
print(df[["model", "tool", "iptm", "ipsae", "ipsae2", "pdockq2"]].round(3))
# One row per real model; the two ipSAE conventions are separate columns.

dfi = fmx.evaluate_interfaces("examples/data")  # one row per chain pair
agg = fmx.aggregate_by_target(df)  # one row per target+tool over all models
pred = fmx.load_predictions("examples/data")[0]
contacts = fmx.find_contacts(pred, dist_cutoff=8.0, pae_cutoff=12.0)
```

More recipes live in [examples/](examples/) — real example predictions are
included there, so every command runs as-is straight after cloning.

## 🛠️ Command-line reference

`paths` accepts a native output directory (scanned recursively), a specific
model file, or several paths. Keep companion confidence files in their
original folders: choosing one CIF/PDB selects its model and reads those
companions automatically. `predictions/` in examples means your output folder.

| Option | Commands | Meaning |
|---|---|---|
| `paths` | all | prediction files and/or directories to process |
| `--tool NAME` | all | restrict to one tool (`colabfold`, `alphafold2`, `alphafold3`, `boltz`, `chai`, `protenix`, `mol1`, `opendde`, `helixfold3`, `seedfold`); default auto-detects |
| `-o, --out FILE` | score, metric subcommands, contacts, dockq | write the result table; format follows the extension (`.tsv`/`.csv`/`.json`) |
| `--interfaces FILE` | score, legacy metric subcommands | also write the per chain-pair table |
| `--metrics LIST` | score | report only these metrics, e.g. `--metrics ipsae,pdockq2` |
| `--by-target [FILE]` | score | also print (and optionally write) the per-target/tool aggregate over seeds and samples |
| `--target-pattern REGEX` | score, ipsae2 | rewrite the inferred `target` from a regex, to unify job names that differ between tools |
| `--plot DIR` | score, legacy metric subcommands, contacts | write figures into DIR (contacts also writes scripts) |
| `--pae-cutoff Å` | score family, ipsae2 (default 10) · contacts (default 12; negative disables) | PAE confidence threshold; ipSAE2 uses an inclusive cutoff for polymers |
| `--dist-cutoff Å` | score family, contacts (default 8) | contact-atom distance threshold; does not change ipSAE2's contact gate |
| `--renderer {auto,pymol,ribbon,trace}` | score family, plot, contacts | structure panel: PyMOL cartoon when available, else the built-in ribbon |
| `--pdockq2-variant {consensus,zhu2023}` | score family, plot | use the same pDockQ2 convention in tables and figures |
| `--format {png,pdf,svg}` / `--dpi N` | plot | figure file format and resolution |
| `--ref FILE` | dockq | reference structure to compare against (required) |
| `--mapping A:A,B:D` | dockq | model:reference chain pairing |
| `--best-mapping` | dockq | try every chain assignment, keep the best (homo-multimers) |
| `--small-molecule` | dockq | also score small-molecule ligand poses |
| `--no-align` / `--capri-peptide` | dockq | pair residues by numbering instead of by alignment · CAPRI peptide criteria |

`fmx <command> --help` prints the complete option list for any command.

Shell tab-completion is available via `pip install "foldmetrics[completion]"`
followed by `activate-global-python-argcomplete`.

### ipSAE2 (2026)

The [2026 ipSAE extension](https://doi.org/10.64898/2026.11.02.763449)
makes the direction of PAE explicit and defines scoring rules for proteins,
nucleic acids, ligands and ions. foldmetrics follows the
[IPSAE2 v0.1.10 reference](https://github.com/DunbrackLab/IPSAE2/tree/e537196e76ed71483d8a8c91c24622b3f6f8e0b4)
in a separate **`ipsae2` column**; **`ipsae` keeps the 2025 definition**.
Both appear in default scoring, Python tables and figures.

Keep the **structure and its original token-level PAE file** together,
including token/frame metadata when provided by the predictor. No pLDDT is
needed; native ipTM confidence files are optional for the extra diagnostics.
Missing PAE gives NA with a status and warning, not a zero score.

```bash
# Single models or whole native output trees; compare both versions
fmx score examples/data --metrics ipsae,ipsae2 -o scores.tsv \
  --interfaces interfaces.tsv --by-target targets.tsv --plot figures/

# Detailed directional pair table, without figures or target aggregation
fmx ipsae2 examples/data -o ipsae2_pairs.tsv
```

`--interfaces` includes `ipsae2_ab`, `ipsae2_ba` and diagnostic fields;
A→B means align on A and score B. `--by-target` adds `ipsae2_mean`,
`ipsae2_std`, `ipsae2_max` and `ipsae2_count`, excluding NA. In Python,
use `fmx.evaluate()` for model rows or `fmx.evaluate_ipsae2()` for detailed
pair rows.

Defaults are PAE ≤10 Å for polymers and a 5 Å heavy-atom contact gate.
The dedicated command also accepts `--contact-cutoff`, `--all-pairs`,
`--group H+L` for combined chains, or `--pae FILE` for an explicitly paired
structure. See the [method and input guide](https://github.com/ChiaChunL/foldmetrics/blob/main/docs/ipsae2-review.md)
for direction, frame and molecule-specific rules. These are confidence
scores, not binding affinities; validation remains strongest for protein pairs.

### Screening many seeds and samples

Large campaigns produce many models per complex. `--by-target` collapses
them into one row per target and tool — model count, mean/std/max ipTM
and ipSAE/ipSAE2, the valid ipSAE2 count, best pDockQ2, and the name and
`best_source` path of the best model (by
ranking_score, else ipSAE, else ipTM):

```
         target       tool  n_models                         best_model  iptm_mean  iptm_std  ipsae_mean  ipsae_max
barnase_barstar alphafold3        16 barnase_barstar_seed-1030_sample-2      0.930     0.000       0.888      0.893
```

The standard deviations show how stable the prediction is across seeds —
a low mean with high spread is a very different situation from a
consistently low one. The same table is available in Python as
`fmx.aggregate_by_target(df)`.

The target is inferred from the job directory, so tools that were given
different job names for the same complex (`1brs` here, `1brs_barnase_barstar`
there) land in different rows. `--target-pattern` reduces the names to the
part that identifies the complex, which puts every method back on one row:

```bash
fmx score runs/ --target-pattern '^(\w{4})' --by-target by_target.tsv
```

The first capturing group becomes the new target; names the pattern does
not match are left alone. In Python: `fmx.apply_target_pattern(df, pattern)`.

## 🖼️ Visualization

`--plot DIR` (on `score` and legacy metric subcommands) or the `plot`
subcommand renders figures that adapt automatically to the shape of the
batch:

| Input shape | Figures written into DIR |
|---|---|
| every model | `<model>.png` — pLDDT-colored structure + pLDDT track + PAE heatmap + metrics panel |
| more than one model | plus `batch_overview.png` — ranked confidence dot plot + mean pLDDT bars |
| more than one target and/or tool | plus `comparison.png` — one panel per metric, grouped by target, one color per tool |

The structure panel is a **ray-traced PyMOL cartoon** when PyMOL is
installed and otherwise the **built-in ribbon**: a spline through the
CA / C1' trace, widened where the chain is helix or strand (assigned from CA
geometry alone with P-SEA, Labesse 1997), oriented to its widest face as
PyMOL's `orient` would. The panel title says which one you are looking at.
`--renderer pymol` insists on PyMOL and explains when it cannot,
`--renderer ribbon` picks the built-in one, and `FOLDMETRICS_PYMOL` points
at a specific PyMOL executable.

`plot` also takes `--format png|pdf|svg` and `--dpi`.

Single model (AlphaFold3, SARS-CoV-2 Mpro + nirmatrelvir):

![per-model summary](https://raw.githubusercontent.com/ChiaChunL/foldmetrics/main/docs/assets/demo_summary.png)

Targets × methods comparison (real batch: 10 complexes × 4 tools):

![per-target comparison](https://raw.githubusercontent.com/ChiaChunL/foldmetrics/main/docs/assets/demo_comparison.png)

Batch overview (one target, AlphaFold2 + AlphaFold3 models):

![batch overview](https://raw.githubusercontent.com/ChiaChunL/foldmetrics/main/docs/assets/demo_batch.png)

## 🤝 Confident interface contacts

A contact is an inter-chain residue (or ligand-atom) pair within
**`--dist-cutoff` 8 Å** whose
[PAE](https://doi.org/10.1038/s41586-021-03819-2) is below
**`--pae-cutoff` 12 Å in both directions** (negative disables the PAE
filter).

```bash
fmx contacts examples/data/af3_server -o contacts.tsv --plot plots/
```

`-o` writes the contact table; `--plot DIR` adds, per model:

- `*_contacts.png` — the figure below
- `*_contacts.pse` / `*_contacts.cxs` — PyMOL / ChimeraX **sessions**, generated
  when the respective application is installed and runs successfully
  (`--no-sessions` skips). Open in that application to see the styled scene.
- `*_contacts.pml` / `*_contacts.cxc` — the same scene as plain scripts,
  always written

![contact map](https://raw.githubusercontent.com/ChiaChunL/foldmetrics/main/docs/assets/demo_contacts.png)

## 🎯 DockQ against a reference

When an experimental (or otherwise trusted) structure exists, `fmx dockq`
computes the *actual* interface accuracy. The implementation is
foldmetrics' own — it needs only numpy and gemmi, so it installs
everywhere — and reproduces the official DockQ v2 package field for field
(see Validation):

```bash
fmx dockq preds/ --ref 1brs.pdb -o dockq.tsv
fmx dockq preds/ --ref native.cif --mapping A:A,B:D   # explicit chain pairing
fmx dockq preds/ --ref homodimer.cif --best-mapping   # search all assignments
fmx dockq preds/ --ref complex.cif --small-molecule   # score ligand poses too
```

Reports DockQ, fnat, iRMSD, LRMSD, the CAPRI-style class and the chain
`mapping` used, per interface. Chains are matched by name when both
structures share names, otherwise by order — mmCIF label vs auth chain ids
differ between tools, so check the `mapping` column. Override explicitly
with `--mapping MODEL:REF,...`, or let `--best-mapping` try every
assignment and keep the best total DockQ (recommended for homo-multimers;
refused above 5 chains). Additional switches: `--no-align` (skip sequence
alignment when residue numbering already matches) and `--capri-peptide`
(protein–peptide criteria).

## 📊 How to read the scores

| Score | Guidance | Basis |
|---|---|---|
| pLDDT | > 90 very high (side chains reliable); 70–90 backbone confident; 50–70 low; < 50 likely disordered | AlphaFold confidence bands (Jumper 2021) |
| pTM / ipTM | > 0.8 confident; 0.6–0.8 gray zone, inspect; < 0.6 likely wrong (interface) | AlphaFold-Multimer / AF3 guidance |
| PAE | < 5 Å: relative placement of the two positions is reliable; > ~15 Å: unreliable | AlphaFold documentation |
| pDockQ | > 0.23 acceptable or better; > 0.5 confident | Bryant 2022 |
| pDockQ2 | estimates DockQ, so DockQ classes apply: < 0.23 incorrect; ≥ 0.23 acceptable; ≥ 0.49 medium; ≥ 0.80 high | Zhu 2023; Basu & Wallner 2016 |
| ipSAE | no published universal cutoff; in our 720-model validation known binders scored ≥ 0.88 and decoys ≤ 0.10 — values above ≈ 0.5 indicate a confidently predicted interface | Dunbrack 2025 + our validation |
| LIS | higher is better; the authors propose ≈ 0.2 as the interaction cutoff | Kim 2024 |
| DockQ | < 0.23 incorrect; 0.23–0.49 acceptable; 0.49–0.80 medium; ≥ 0.80 high | Basu & Wallner 2016 (CAPRI classes) |

### pDockQ2 has two established readings

Zhu 2023 fixes pDockQ2's sigmoid and PAE term but not which atom defines a
contact, whose pLDDT is read, or whether the partner chain enters the
average, and implementations diverge:

| | contact atom | pLDDT | interface residues |
|---|---|---|---|
| Dunbrack `ipsae.py`, ColabFold — **our default** | CB (CA for Gly) | that residue's CB | union of both chains, counted once |
| the paper's own `pdockq2.py` (`variant="zhu2023"`) | CA | that residue's CA | scored chain only, weighted by contacts |

Differences depend on the model. Uniform per-residue pLDDT in AlphaFold2
removes the CA/CB pLDDT difference, but contact geometry and residue weighting
can still differ. `variant=` on
`foldmetrics.metrics.pdockq2_asym` selects; `pdockq2` in the tables is the
maximum of the two directional values (the paper defines no interface-level
aggregate).

Single scores can mislead — pDockQ ignores PAE and stays deceptively high
on confidently-folded but wrongly-docked chains, which pDockQ2/ipSAE
expose. Read them together; that is rather the point of this package.

## 🧰 Supported tools and files

| Tool | Detected files | pTM/ipTM | pLDDT | PAE |
|---|---|---|---|---|
| ColabFold | `*_scores_rank_*.json` + `*_(un)relaxed_rank_*.pdb` | yes | yes | yes |
| AlphaFold2 (pickle layout) | `result_model_*.pkl` + `unrelaxed_*.pdb` / `ranked_*.pdb` | yes | yes | yes |
| AlphaFold2 (JSON layout) | `iptm_ptm.json` + `confidence_*.json` / `pae_*.json` + `unrelaxed_*.cif/.pdb` | yes | yes | yes |
| AlphaFold3 (server/local) | `*model*.cif` + `*summary_confidences*.json` + `*confidences*/full_data*.json` | yes | yes | yes |
| Boltz-1/2 | `confidence_*_model_*.json` + `*_model_*.cif` + `pae_*.npz` / `plddt_*.npz` | yes | yes | yes |
| Chai-1 | `scores.model_idx_*.npz` + `pred.model_idx_*.cif`; PAE in scores, per-model NPZ or stacked `pae.npz` | yes | yes | yes |
| Protenix | `*summary_confidence*.json` + matching `.cif` (+ `*full_data*.json` with `token_pair_pae`) | yes | yes | yes |
| Mol-1 | Protenix-compatible files; mmCIF data block `..._predicted_by_mol` (`--tool mol1`) | yes | yes | yes |
| OpenDDE | Protenix layout and keys; told apart by the mmCIF data block `..._predicted_by_opendde` | yes | yes | yes |
| HelixFold3 | `<job>/<job>-pred-<I>-<S>/all_results.json` + `predicted_structure.cif` (the `-rank<N>` copies are dropped) | yes | yes | yes |
| SeedFold | `confidence_*_model_*.json` + `*_model_*.cif` (Boltz-shaped, no `.npz`) | yes | yes | no |

Native per-tool extras (Boltz `complex_iplddt`, AF3 `chain_pair_pae_min`,
Chai clash flags, …) are kept on `Prediction.extras`, and chain-pair ipTM is
surfaced as `iptm_native` in the interface table. Mol-1 and OpenDDE are
distinguished from Protenix by their CIF provenance markers. Keep Boltz and SeedFold exports intact for reliable detection.

## ✅ Validation

- ipSAE, pDockQ, pDockQ2 and LIS match the Dunbrack Lab `ipsae.py`
  reference digit for digit on real AlphaFold3 server output (both
  directions, d0chn variant, default cutoffs 10/10).
- On real ColabFold 1.6 output they reproduce ColabFold's own embedded
  values to ~1e-5 (bounded by the 2-decimal PAE in its JSON); a CI test
  enforces this on every commit.
- DockQ reproduces the official DockQ v2 package to 1e-4 (the reference
  computes in float32) on real predictions — DockQ, fnat, fnonnat, F1,
  iRMSD, LRMSD, clashes and chain roles — including a reference with
  missing residues and shifted numbering, the CAPRI peptide thresholds,
  pairing by numbering, and symmetry-corrected ligand RMSD; the parity
  tests run against the official package wherever it installs.
- Earlier releases were batch-tested on 720+ real predictions across supported engines,
  including protein–ligand complexes, homodimers, monomers and negative
  controls, with zero parse errors in those datasets.
- Mol-1: five real protein-pair samples parsed without warnings; regression
  tests cover multiple seeds/samples and single-file versus batch scoring.
- IPSAE2 v0.1.10: 326 real models agree with the pinned reference within
  absolute `1e-12`; 15 SeedFold outputs without PAE report NA. The combined
  column and per-target statistics were also checked on the 330-model native
  campaign. See the [validation scope](https://github.com/ChiaChunL/foldmetrics/blob/main/docs/ipsae2-review.md#validation-of-this-integration).
- Layout-tested on untouched native output trees, including multi-seed /
  multi-sample campaigns; each engine's duplicate copies of a model (AF2
  `ranked_*`, AF3's top-level model, HelixFold3's `-rank<N>` directories)
  are counted once. HelixFold3 is validated for layout and keys only — its
  confidence values came from a run without MSAs.

## 📋 What each metric needs

Keep the **structure + companion confidence files** listed above together.
A standalone CIF/PDB does not contain every metric; native pTM/ipTM cannot
be recovered exactly from coordinates or mean PAE.

| Command / metric | Required data beyond the structure |
|---|---|
| `ptm`, `iptm`, `ranking` | native confidence JSON/NPZ, or AF2 result pickle |
| `plddt` | predicted pLDDT in B-factors or a confidence file |
| `iplddt`, `pdockq` | pLDDT; contacts are calculated from coordinates |
| `pae`, `ipae`, `ipsae`, `lis` | PAE matrix in JSON/NPZ, or AF2 result pickle |
| `ipsae2` | raw token-level PAE and matching coordinates; no pLDDT required; native ipTM file optional |
| `pdockq2` | pLDDT + PAE matrix |
| `dockq` | reference structure supplied with `--ref FILE` |
| `contacts` | coordinates; PAE enables confidence filtering |

`score` reports the standard confidence metrics including both ipSAE versions;
use `--metrics` to select columns. The dedicated `ipsae2` command provides its
full pair table and advanced options. DockQ runs separately with its reference.
Missing PAE gives `NA` and a warning; current SeedFold web exports have no PAE.
Monomers have no inter-chain interface metrics. ipSAE describes confidence,
not binding affinity.

**Boltz-2 affinity:** optional `affinity_<job>.json` values are retained as
`boltz_*` keys in `Prediction.extras`. They are native protein–small-molecule
predictions, separate from confidence scores and not included in the default
summary table. See the [Boltz documentation](https://github.com/jwohlwend/boltz#binding-affinity-prediction).

## 📁 Outputs and paths

- Summary table → stdout; `-o FILE` writes it, the extension picking
  `.tsv` (default), `.csv` or `.json`; missing values are `NA`.
  `--interfaces FILE` writes the per chain-pair table the same way.
- `--plot DIR` → the figures above; `contacts --plot` adds
  `<model>_contacts.png/.pml/.cxc` (+ `.pse/.cxs` when their applications run).
  Names are sanitized for filenames; colliding names within a batch gain
  a tool/source suffix so different seeds and methods do not overwrite each
  other. `plots_manifest.tsv` / `contacts_manifest.tsv` map filenames back
  to source structures. Interface, contact and DockQ tables retain `source`.
  `plot -o DIR` defaults to `./foldmetrics_plots/`.
- Exit codes: `0` success, `1` nothing recognized/found (or an invalid model
  in an `ipsae2` batch), `2` bad arguments.

## 💡 Conventions worth knowing

- **Tokens.** One per standard residue; one per heavy atom for ligands and
  modified residues (AF3-style), so token-level PAE lines up across tools.
  pLDDT is 0–100 everywhere (Boltz's 0–1 is rescaled).
- **Complex-level interface metrics are the best interface.** With more
  than two chains, `ipsae`/`ipsae2`/`pdockq`/`pdockq2`/`lis` in the summary
  are the maximum over eligible chain pairs; `--interfaces` has the full
  breakdown. ipSAE2 uses its own 5 Å heavy-atom contact gate.
- **Ligand interfaces.** `pdockq`/`pdockq2`/`iplddt` are polymer–polymer
  only; for pairs involving a ligand chain, `ipsae`/`lis` run over ligand
  atom tokens (experimental, `ipsae_mode = "tokens"`).
- **`ranking_score` is tool-specific**, not calibrated across engines. AlphaFold
  builds that write `ranking_confidence` as a percentage are rescaled (the
  raw value stays in `extras`); an AF2 *monomer* keeps its mean-pLDDT
  ranking on the pLDDT scale, as the tool defines it.
- **`target` identifies the job.** ColabFold uses its filename prefix; otherwise
  the job directory is inferred. Seed and sample directories are
  stripped so a job's models aggregate together; tools that name the same
  complex differently stay apart until `--target-pattern`.
- **Missing data degrades gracefully:** no PAE → PAE-based metrics are NaN
  plus a note in `warnings`; nothing crashes.
- **Directionality.** PAE is asymmetric, so `pdockq2`/`ipsae`/`lis` have two
  directional values. The interface table reports both for ipSAE/pDockQ2
  and their maximum; LIS reports the directional mean. For ipSAE, `ab`
  means align on chain A and score chain B.
- **ipSAE version.** The `ipsae` column retains the 2025 definition. `ipsae2` uses the
  [2026 extension](https://doi.org/10.64898/2026.11.02.763449)
  (IPSAE2 v0.1.10): same-type maximum, molecule-dependent mixed-pair
  direction, fixed nonprotein d0, valid alignment frames and an inclusive
  PAE cutoff. The version is recorded in its output. Protein results can
  differ at the cutoff or with invalid frames; this is an explicit choice.
  Combined tables read original native companions for ipSAE2; unavailable or
  invalid data stays NA with `ipsae2_status` and a warning. In Python,
  `include_ipsae2=False` skips this additional file-based calculation.

## 📚 References

- Jumper J et al. [*Highly accurate protein structure prediction with
  AlphaFold.*](https://doi.org/10.1038/s41586-021-03819-2) Nature 596,
  583–589 (2021). — pLDDT / PAE and their confidence bands
- Evans R et al. [*Protein complex prediction with
  AlphaFold-Multimer.*](https://doi.org/10.1101/2021.10.04.463034)
  bioRxiv (2021, preprint). — ipTM
- Bryant P, Pozzati G, Elofsson A. [*Improved prediction of protein-protein
  interactions using AlphaFold2.*](https://doi.org/10.1038/s41467-022-28865-w)
  Nat Commun 13, 1265 (2022). — pDockQ
- Zhu W, Shenoy A, Kundrotas P, Elofsson A. [*Evaluation of AlphaFold-Multimer
  prediction on multi-chain protein complexes.*](https://doi.org/10.1093/bioinformatics/btad424)
  Bioinformatics 39, btad424 (2023). — pDockQ2
- Dunbrack RL Jr. [*Rēs ipSAE loquuntur: What's wrong with AlphaFold's
  ipTM score and how to fix it.*](https://doi.org/10.1101/2025.02.10.637595)
  bioRxiv (2025, preprint). — legacy `ipsae` calculation
- Dunbrack RL Jr. [*Rēs ipSAE adhūc loquuntur: What the directionality of
  predicted aligned error in cofolding models can tell us about scoring
  diverse molecular complexes.*](https://doi.org/10.64898/2026.11.02.763449)
  bioRxiv (2026, preprint). — `ipsae2` directional scoring
- Kim AR et al. [*Enhanced protein-protein interaction discovery via
  AlphaFold-Multimer.*](https://doi.org/10.1101/2024.02.19.580970) bioRxiv
  (2024, preprint). — LIS
- Basu S, Wallner B. [*DockQ: A quality measure for protein-protein docking
  models.*](https://doi.org/10.1371/journal.pone.0161879) PLoS ONE 11,
  e0161879 (2016). — DockQ
- Mirabello C, Wallner B. [*DockQ v2: improved automatic quality measure
  for protein multimers, nucleic acids, and small
  molecules.*](https://doi.org/10.1093/bioinformatics/btae586)
  Bioinformatics 40, btae586 (2024). — DockQ v2

## 📄 License

[BSD 3-Clause](LICENSE)

The adapted IPSAE2 routines retain the upstream [MIT license](https://github.com/ChiaChunL/foldmetrics/blob/main/src/foldmetrics/_ipsae2/LICENSE).
