Skip to main content

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

foldmetrics
Testing CI
Package PyPI Latest Release Python versions PyPI total downloads
Meta License - BSD 3-Clause Ruff

Download statistics: PyPI totals (Pepy).

🧬 What is it?

foldmetrics ingests the raw output folders of the mainstream structure predictors — AlphaFold2 / AlphaFold-Multimer, ColabFold, AlphaFold3, Boltz, Chai-1, Protenix, OpenDDE, HelixFold3, SeedFold — and computes a consistent set of quality metrics for monomers and complexes (protein, nucleic acid and small-molecule ligands), for a single model or whole batches:

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
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, optional

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 enumerates the pairs, computes each MSA once and drives all of these engines from one panel; its output is what foldmetrics reads here.

📦 Installation

pip install foldmetrics

With DockQ support (reference-based scoring):

pip install "foldmetrics[dockq]"

Figures need nothing more: the structure panel is drawn by a built-in ribbon renderer on every platform. For ray-traced PyMOL cartoons instead, add the optional extra:

pip install "foldmetrics[pymol]"

That works on Linux, macOS and Windows. It installs pymol-open-source-whl — an unofficial, cibuildwheel build of the unmodified open-source PyMOL, chosen because Schrödinger's own PyPI package is alpha-only and its macOS wheels do not import. Verified end to end here on Linux and macOS: figures, metrics and .pse sessions from a bare pip install. A PyMOL from Homebrew (brew install pymol) or conda-forge (conda install -c conda-forge pymol-open-source) is found just as well if you already have one.

Development install:

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:

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

# one metric only — every metric name is also a subcommand
fmx ipsae examples/data
fmx score examples/data --metrics ipsae,pdockq2,lis

# campaign view: aggregate seeds/samples per target and tool
fmx score preds/ --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:

import foldmetrics as fmx

df = fmx.evaluate("examples/data")  # one row per model
print(df[["model", "tool", "iptm", "ipsae", "pdockq2"]].round(3))
#                                model       tool   iptm  ipsae  pdockq2
#           model_1_multimer_v3_pred_0 alphafold2  0.937  0.897    0.952
#                    mpro_nirmatrelvir alphafold3  0.970  0.836      NaN
#    fold_barnase_barstar_s318_model_0 alphafold3  0.930  0.890    0.944
#              barnase_barstar_model_0      boltz  0.959  0.935    0.939

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/ — real example predictions are included there, so every command runs as-is straight after cloning.

🛠️ Command-line reference

paths accepts anything: a directory (scanned recursively; different tools can be mixed freely), one specific model file, or several paths at once.

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, 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, 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 rewrite the inferred target from a regex, to unify job names that differ between tools
--plot DIR score, metric subcommands, contacts write figures into DIR (contacts also writes a .pml)
--pae-cutoff Å score family (default 10, for ipSAE) · contacts (default 12; negative disables) PAE confidence threshold
--dist-cutoff Å score family, contacts (default 8) contact-atom distance threshold
--renderer {auto,pymol,ribbon,trace} score family, plot, contacts structure panel: PyMOL cartoon when available, else the built-in ribbon
--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 / --low-memory / --capri-peptide dockq skip alignment · reduce memory · 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.

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, best pDockQ2, and the name 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:

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 every metric subcommand) 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 has two depictions. The built-in ribbon needs only matplotlib and draws on every platform, headless or not: 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), no DSSP binary needed — arrowheads on strand ends, depth shading, and the molecule oriented to show its widest face, as PyMOL's orient would. With PyMOL installed, auto (the default) uses its ray-traced cartoon instead. The panel title says which one you are looking at.

--renderer pymol insists on PyMOL and, when it is missing or fails, leaves the panel with the reason and the install command for this platform rather than a picture. --renderer ribbon and --renderer trace pick the built-in depictions directly (trace is the older pLDDT-colored polyline).

PyMOL is looked for in this order: FOLDMETRICS_PYMOL, a pymol console script next to the running interpreter, pymol on PATH, an importable pymol module run through the current interpreter (this is how the [pymol] extra is found — it ships no console script), then the usual conda and application locations.

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

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

per-model summary

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

per-target comparison

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

batch overview

🤝 Confident interface contacts

A contact is an inter-chain residue (or ligand-atom) pair within --dist-cutoff 8 Å whose PAE is below --pae-cutoff 12 Å in both directions (negative disables the PAE filter).

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: double-click to open the styled interface scene, with if_A / if_B / hotspots / interface selections ready (--no-sessions skips)
  • *_contacts.pml / *_contacts.cxc — the same scene as plain scripts, always written

contact map

🎯 DockQ against a reference

When an experimental (or otherwise trusted) structure exists, fmx dockq computes the actual interface accuracy via the official DockQ implementation (install with pip install "foldmetrics[dockq]"):

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), --low-memory (huge complexes), --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 fitted sigmoid and its PAE term, but not which atom defines a contact, which atom's pLDDT to read, or whether the partner chain contributes to the pLDDT average. 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

The gap is ~0.005 on real AlphaFold3 output, because CA and CB contacts describe different interfaces (33 vs 53 pairs on barnase–barstar). It only matters for engines with per-atom pLDDT: pDockQ2 was fitted on AlphaFold2, where pLDDT is constant within a residue and all readings coincide. Pass variant= to foldmetrics.metrics.pdockq2_asym to choose; pdockq2_ab/pdockq2_ba are the per-chain values the paper defines, and the aggregate pdockq2 is their maximum, which is our convention — the paper defines no interface-level aggregate.

Single scores can mislead — pDockQ ignores PAE and can stay 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_model_idx_*.npz yes yes yes
Protenix *summary_confidence*.json + matching .cif (+ *full_data*.json with token_pair_pae) 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 (e.g. Boltz complex_iplddt/ligand_iptm, AF3 chain_pair_pae_min, Chai clash flags) are preserved on Prediction.extras and chain-pair ipTM is surfaced as iptm_native in the interface table.

Forks are a real problem here: OpenDDE writes Protenix's exact layout, file names and confidence keys, and SeedFold writes Boltz's. They are separated by whatever provenance the output actually carries — the mmCIF data block for the Protenix family, the absence of Boltz's own .npz files for SeedFold — never by guessing from the directory name.

✅ Validation

  • Numerical parity with the ipsae.py reference implementation (Dunbrack Lab) verified digit-for-digit on real AlphaFold3 server output: ipSAE (both directions and d0chn variant), pDockQ, pDockQ2 and LIS all match to 6 decimal places at the default cutoffs (10/10).
  • Batch-tested on 720+ real predictions across AlphaFold2-Multimer, AlphaFold3 (server + local), Boltz-2, Chai-1, ColabFold, Protenix, OpenDDE and SeedFold — including protein–small-molecule complexes, homodimers, monomers and negative controls — with zero parse errors; known binders score ipSAE 0.9+, decoy pairs < 0.1, monomers report NA. On one panel of three two-chain complexes, OpenDDE and Protenix given the same MSAs agree to within 0.02 on pTM, ipTM, ipSAE, pDockQ2 and pLDDT — two independent parses of two engines' own output.
  • Layout-tested on native, untouched output directories from every supported engine, including multi-seed/multi-sample campaigns where the seed directory sits above the job directory; each engine's duplicate copies of the same model (AF2 ranked_*, AF3's top-level model, HelixFold3's -rank<N> directories) are counted once. HelixFold3 is so far validated at this level only: its file layout and key names come from a real run, but that run was made without MSAs, so its confidence values were not in a regime worth checking.
  • Cross-implementation agreement: on real ColabFold 1.6 output our ipSAE/pDockQ/pDockQ2 reproduce ColabFold's own embedded values to ~1e-5 (bounded only by the 2-decimal PAE rounding in its JSON) — a CI regression test enforces this parity on every commit.

📋 What each metric needs

The structure file is always required (it defines chains and tokens); the table shows which additional inputs each metric consumes. When an input is missing the metric is NA and a note lands in the warnings column — nothing crashes.

Metric (= subcommand) pLDDT Coordinates PAE Source
ptm, iptm, ranking – – – read from the tool's confidence file
plddt (mean pLDDT, ipLDDT) yes ipLDDT only – B-factors, or the tool's pLDDT file
pae (mean PAE, inter-chain PAE) – – yes tool's PAE matrix
pdockq yes yes – contacts at 8 Å between CB/C3' atoms
pdockq2 yes yes yes
ipsae, lis – – yes chain mapping from the structure
contacts reported yes recommended distance always; PAE filter when present
dockq – yes – plus a reference structure (--ref)

📁 Outputs and paths

  • Summary table → stdout; -o FILE writes it. The extension picks the format: .tsv (default), .csv, .json; missing values are NA.
  • --interfaces FILE → the per chain-pair table (same formats).
  • --plot DIR → figures as described under Visualization; contacts --plot adds <model>_contacts.png + <model>_contacts.pml. Model names are sanitized ([^\w.-] → _) for use as filenames.
  • plot -o DIR defaults to ./foldmetrics_plots/.
  • Exit codes: 0 success, 1 nothing recognized/found, 2 bad arguments or missing optional dependency.

💡 Conventions worth knowing

  • Tokens. Standard residues are one token; ligands and modified residues are one token per heavy atom (AF3-style), so token-level PAE matrices line up across tools. pLDDT is stored on the 0–100 scale everywhere (Boltz 0–1 values are rescaled).
  • Complex-level interface metrics are the best interface. For >2 chains, ipsae/pdockq/pdockq2/lis in the summary table are the maximum over chain pairs; use --interfaces for the full breakdown.
  • Ligand interfaces. pdockq/pdockq2/iplddt are defined for polymer–polymer interfaces only. For chain pairs involving a ligand chain, ipsae/lis are computed over ligand atom tokens (experimental) and marked ipsae_mode = "tokens" in the interface table.
  • ranking_score is comparable across tools. It is each tool's own ranking number, kept on 0–1. Some AlphaFold builds write ranking_confidence as a percentage (27.7 for 0.8·ipTM + 0.2·pTM = 0.277); that is rescaled, with the value as written preserved in Prediction.extras["alphafold2_ranking_confidence_raw"]. An AF2 monomer run is the exception the tool itself defines: there ranking_confidence is the mean pLDDT, and it stays on the pLDDT scale.
  • The target is the job directory, not the complex. Seed and sample directories are stripped, so all models of one job aggregate together, but two tools given different job names for the same complex stay separate until you pass --target-pattern.
  • Missing data degrades gracefully. No PAE → PAE-based metrics are NaN and a note lands in the warnings column; nothing crashes.
  • Directionality. PAE is asymmetric, so pdockq2/ipsae/lis have two directional values; the interface table reports both (*_ab, *_ba) plus the aggregate used everywhere else (max for ipSAE/pDockQ2, mean for LIS, matching the reference implementations).

📚 References

📄 License

BSD 3-Clause

Metadata

Release files for foldmetrics 0.1.9

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for foldmetrics 0.1.9
File Size Uploaded
foldmetrics-0.1.9.tar.gz 85.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for foldmetrics 0.1.9
File Interpreter ABI Platform
foldmetrics-0.1.9-py3-none-any.whl Python 3 none any Details

Total release size: 162.7 kB

Release files / foldmetrics-0.1.9.tar.gz

Download URL foldmetrics-0.1.9.tar.gz
Size 85.4 kB
Tags Source
SHA-256 checksum
How to use checksums
dc461fc57a3dd55743010a3e31ed5a810ff401a63a460254df39c80875f609aa
BLAKE2b-256 checksum
How to use checksums
03dc65b6a214385a2d6863f4ebfd2c08f82d17fb4d7aa002667571f35dd64e14
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 11, 2026.

Transparency log

Release files / foldmetrics-0.1.9-py3-none-any.whl

Download URL foldmetrics-0.1.9-py3-none-any.whl
Size 77.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
4478533eafccb9fae9895aced0e400ce80e2c30f6f3b463a23757d8470cb18ac
BLAKE2b-256 checksum
How to use checksums
76b418a6934c6cdc456dbaa0cd5f9eae36d03db6f2b084661de5af4a8664ee62
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 11, 2026.

Transparency log

Release history Release notifications | RSS feed

0.2.0

2 release files

This release

0.1.9 This release

2 release files

0.1.8

2 release files

0.1.7

2 release files

0.1.6

2 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page