Skip to main content

pdbcheck

Fast inter-chain steric clash screening for PDB structures.

CI PyPI Python License

pdbcheck reads one PDB file, or a directory of them, and writes a CSV naming every pair of atoms from different chains that sit closer together than chemistry allows.

It exists for triaging the output of structure predictors — AlphaFold, Chai-1, Boltz, RFdiffusion — where the question is which of five hundred models to throw away, not how a deposited structure scored. For authoritative validation of an experimental structure, use MolProbity: it places hydrogens, computes a normalised clashscore, and is what the PDB itself reports. pdbcheck deliberately does less, and in exchange runs on heavy atoms alone, finishes a structure in milliseconds, needs no setup beyond pip install, and emits a table meant for a dataframe rather than a report meant for a human.

Installation

pip install pdbcheck

Python 3.9 or newer. numpy and scipy are the only dependencies, and they are pinned loosely so that installing into an existing environment leaves whatever is already there alone.

To get the command without adding anything to an environment:

pipx install pdbcheck

Or straight from source:

pip install git+https://github.com/LamarckLab/pdbcheck.git

Usage

Command line

pdbcheck /data/structures/model.pdb     # one file
pdbcheck /data/structures               # every .pdb in the directory

Both forms write pdb_check.csv into the directory the target lives in, replacing any report already sitting there. The directory scan is flat — subdirectories are not visited — and recognises .pdb and .PDB only.

Option Effect
-o, --out PATH write the CSV somewhere else
-q, --quiet print nothing on success
--version print the version and exit

Exit status is 0 on success, 1 when a file could not be read, and 2 when the path does not exist or holds no PDB files. Clashes do not affect it: a structure riddled with overlaps is still a successful run.

Python

from pdbcheck import check_clashes

for contact in check_clashes("model.pdb"):
    print(contact.severity, contact.distance, contact.a.chain, contact.a.resi)

check_clashes returns a list of Contact, worst first. Each carries severity, distance, and the two Atom records a and b, which hold chain, resi, resn, name, element and x/y/z.

Output

One row per clashing atom pair, ordered worst first.

Column Meaning
file name of the structure the row came from
severity steric, tight, polar, carbon, clean or error
distance centre-to-centre separation in Angstrom, two decimals
chain1 resn1 resi1 atom1 elem1 first atom of the pair
chain2 resn2 resi2 atom2 elem2 second atom of the pair
same_chain always False in this version
file      severity  distance  chain1 resn1 resi1 atom1 elem1  chain2 resn2 resi2 atom2 elem2  same_chain
1IGT.pdb  polar     2.38      D      ASN   314   ND2   N      F      NAG   1     O5    O      False
1IGT.pdb  carbon    2.81      A      GLY   91    O     O      B      TYR   100I  CD2   C      False

resi keeps the insertion code when the structure carries one, as 100I above, so Kabat and IMGT numbered antibody models survive the round trip intact.

A structure with no clashes still produces a row, with severity set to clean and the atom columns empty. A structure that could not be read produces one set to error. A batch report therefore accounts for every file it was handed, and a missing row means a file was never seen rather than that it was fine.

The criterion

Nitrogen, oxygen and sulfur form hydrogen bonds. Carbon does not. A nitrogen and an oxygen 2.8 Å apart are a textbook hydrogen bond; a carbon 2.8 Å from anything is a modelling error. No single distance cut-off can express both, so the thresholds split on whether a carbon takes part.

Separation (Å) Carbon involved No carbon (N/O/S only)
d < 2.2 steric tight
2.2 <= d < 2.6 polar polar
2.6 <= d < 3.0 carbon healthy
d >= 3.0 healthy healthy

steric and tight are the verdicts worth acting on. polar and carbon mark contacts that are tighter than average but do occur in well refined structures; read them as a count, not as a list of defects.

The outer thresholds reproduce the 0.4 Å van der Waals overlap criterion MolProbity uses. Two carbons sum to 3.40 Å, and 3.40 − 0.4 = 3.00. Nitrogen and oxygen sum to 3.07 Å, and 3.07 − 0.4 = 2.67, rounded down to 2.6 here so that the grade errs toward silence. Below 2.2 Å nothing survives: the shortest known low barrier hydrogen bond is near 2.4 Å, so a non-bonded pair closer than 2.2 Å has no physical account at all.

The split at 2.2 Å separates a certain error from a contact that still deserves an eye. A carbon that close is overlap and nothing else, so it is graded steric; the same distance between polar atoms is graded tight, because an extreme salt bridge or a metal site can in principle reach it.

What is excluded

Two filters run before any distance is measured. They are the reason the grades above mean anything, and most of the work in this package lives in them.

Atoms that never enter the search:

Dropped Reason
hydrogens every threshold above is a heavy-atom threshold
alternate conformations other than A two positions of one atom necessarily overlap
zero occupancy modelled, but flagged as not actually present
HOH WAT SO4 EDO GOL PEG CL NA MG NI ZN CA crystallisation additives and free ions
every model after the first later models are copies of the same chains, not neighbours

Pairs that are bonds rather than clashes:

Excluded Reason
any pair named in a LINK record a declared covalent link
any pair named in an SSBOND record a declared disulfide
any SG–SG pair SSBOND records go missing often enough to warrant the blanket rule
sugar C1 to ASN ND2, SER OG or THR OG1, below 1.8 Å glycosylation, which LINK rarely declares
sugar to sugar, below 1.8 Å the glycan's own backbone, likewise undeclared

Scope and limitations

Inter-chain contacts only

Contacts inside a single chain are not reported. The atoms of one chain are joined by bonds this package does not model — backbone, side chain, the proline ring — and a distance test blind to them flags every peptide bond in the structure. Doing it properly means building a connectivity graph and excluding pairs one and two bonds apart. That is planned, and it is not here yet.

The consequence is worth stating plainly: a single-chain structure always comes back clean, because it contains no inter-chain pairs at all. pdbcheck has nothing to say about a monomer in this version.

Known residual false positives

The bond exclusions are a curated list rather than a connectivity graph, so they exempt bonded atoms but not their neighbours. Around an N-linked glycan the C1–ND2 bond is excluded correctly, while ND2···O5 at 2.38 Å and CG···C1 at 2.44 Å — two bonds away, and held there by the geometry of the bond itself — are reported as polar. Six of the eight polar contacts in 1IGT arise this way. The steric and tight grades are not affected.

Setting POLAR at 2.6 Å also catches unusually short but genuine hydrogen bonds, which surface as polar between 2.5 and 2.6 Å.

Not implemented

  • hydrogen positions, and therefore any MolProbity style clashscore
  • crystallographic symmetry mates
  • metal coordination geometry, since metals are discarded with the solvent
  • mmCIF input
  • any modification or repair of the structure

Validation

Four structures from the PDB, run as one batch:

PDB Structure Chains Atoms steric tight polar carbon
1UBQ ubiquitin, 1.8 Å 1 602 0 0 0 0
1IGT intact IgG, 2.8 Å 6 10416 0 0 8 8
3HFM lysozyme–Fab complex, 3.0 Å 3 4296 0 0 6 12
6M0J SARS-CoV-2 RBD–ACE2, 2.45 Å 2 6476 0 0 0 1

No well refined structure reports a steric or tight contact, which is the property the thresholds are chosen to have. 1UBQ reports nothing at all because it is a monomer, which is the limitation above seen from the other side.

Switching the bond exclusions off raises two steric and five tight contacts on 1IGT alone — a structure carrying seventeen disulfides and glycans on two chains. That difference is the measurement that justifies the exclusion list.

The whole batch, 21790 atoms, takes 0.11 s.

Development

git clone https://github.com/LamarckLab/pdbcheck.git
cd pdbcheck
pip install -e ".[dev]"
pytest
ruff check .

License

MIT. See LICENSE.

Metadata

Release files for pdbcheck 0.1.0

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

Source distribution (sdist)

Source distribution for pdbcheck 0.1.0
File Size Uploaded
pdbcheck-0.1.0.tar.gz 14.9 kB Details

Built distribution (wheel)

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

Total release size: 27.7 kB

Release files / pdbcheck-0.1.0.tar.gz

Download URL pdbcheck-0.1.0.tar.gz
Size 14.9 kB
Tags Source
SHA-256 checksum
How to use checksums
c45d831886e0660c4fa692acd1aea37e0ef6050c8ef0307600507d1421a1a335
BLAKE2b-256 checksum
How to use checksums
5b4edaa3213eef7d82f1b36008a2506b47c7cc3b0f421c23321573e1302ccef4
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 Oct 7, 2026.

Transparency log

Release files / pdbcheck-0.1.0-py3-none-any.whl

Download URL pdbcheck-0.1.0-py3-none-any.whl
Size 12.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e3d7c455258c8db4b6cb0df9835937508dc958dc8d6b0919d561dae0d8e59f78
BLAKE2b-256 checksum
How to use checksums
a9e2fdfaae42b00dfa1502f3f1bdc5aefb2240125cb3ad293f3f13f5b120a3f7
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 Oct 7, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.0 This release

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