Skip to content

Latest commit

 

History

5 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Binder Filter

Binder Filter is a reproducible GPU pipeline for prioritizing generated target-binder complexes from PocketXMol and BoltzGen. It validates and normalizes source structures, independently refolds target-binder sequences with Protenix-v2 and full ESMFold2, calculates confidence and geometry metrics, applies a binary pass/fail decision, and selects a diverse final set.

Scientific scope: Binder Filter performs computational prioritization. A pass is not proof of binding, affinity, specificity, stability, expression, solubility, permeability, activity, safety, or synthetic accessibility. Experimental validation remains required. Production molecular dynamics is deliberately outside this pipeline.

Project status

Version 0.2.0 implements a mode-specific interaction and filtering contract. All three binder modes require median ipSAE_min >= 0.60 from both Protenix-v2 and full ESMFold2, plus ESMFold2 median exact actifpTM >= 0.93. Miniproteins additionally require a separate apo-fold gate. Peptide cross-model and source-pose RMSDs are limited to 1.25 A and 1.50 A, respectively. Legacy YAML field names are rejected rather than silently migrated.

The production run, resume, and report commands are active. They perform strict configuration validation, source ingestion and normalization, immutable model/MSA fetch locking, sequential dual-model GPU inference, exact artifact validation, ipSAE and exact probability-based actifpTM where available, structural/geometry analysis, binary filtering, ranking/diversity selection, deterministic CSV/mmCIF export, and a verified multi-page PDF. Mock-worker output remains unmistakably non-scientific.

A clean one-candidate BoltzGen end-to-end acceptance run completed with genuine Protenix-v2 and full ESMFold2 artifacts, then resumed without changing completed-job timestamps or CSV hashes. These checks demonstrate execution and resume integrity, not biological validity.

A 10-candidate BoltzGen cyclic-peptide smoke run also completed on an A100 with 10/10 valid Protenix-v2 jobs, 10/10 valid full-ESMFold2 jobs, and explicit cyclic closure in all 20 prediction records. Its historical one-seed result identified two provisional passers, but it no longer qualifies as a scientific cyclic pass under the required 3-of-5 valid confirmation-seed and terminal-bond geometry contract. This diagnostic run caught an exporter bug that had compared the 64-bin structure distogram with the unrelated 39-bin confidence-head grid.

The completed first BoltzGen PD-L1 run in /workspace/results predates the v0.2.0 cutoff change. Its predictions remain valid reusable evidence, but its stored pass flags describe the older scientific hash. Do not compare those flags directly with a new v0.2.0 run.

Supported inputs and modes

Source Required metadata Structures Cyclic topology
PocketXMol gen_info.csv Peptide/miniprotein PDB Cyclic mode: matching _mol.sdf with closure; other modes: not required
BoltzGen Metrics CSV Generated complex PDB or mmCIF Closure in mmCIF or explicit sidecar

Supported binder modes are exact:

  • linear_peptide: 5-30 canonical residues, no polymer closure.
  • cyclic_peptide: 5-30 canonical residues, exactly one last-C/first-N amide closure.
  • miniprotein: 31-150 canonical residues in one binder chain.

Mode and source are required in YAML and are never inferred.

Cyclic mode additionally requires five confirmation seeds with at least three valid seeds per predictor. The explicit last-C/first-N connection must measure 1.20-1.45 A in the normalized source, every valid prediction, and the final consensus structure. A connection record with implausible coordinates is rejected.

Structure sources may be directories, direct files, glob patterns, or ZIP archives. Archive members can be indexed directly from a ZIP central directory; full extraction is not required. A file inside an archive can be addressed as path/to/archive.zip::member/path/file.csv.

Prepare a campaign

  1. Place the canonical target PDB/mmCIF and immutable generator outputs outside the Git checkout. Never copy model weights or a 30,000-structure campaign into this repository.
  2. For PocketXMol, provide gen_info.csv and every generated PDB; cyclic mode also requires the matching <PDB stem>_mol.sdf. Non-cyclic PocketXMol validation does not require an SDF. For BoltzGen, provide its metrics CSV and generated complex PDB/mmCIF files; ambiguous cyclic connectivity requires a sidecar.
  3. Copy the matching example from configs/, set an explicit input.source, input.mode, target chains, source columns, paths, run name, and output root. Relative paths resolve relative to the YAML file. Unknown or misspelled fields are fatal.
  4. Run validate, then doctor, then fetch. Inspect config.resolved.yaml, weights.lock.json, and msa.lock.json before expensive inference.
  5. Launch run. If interrupted, use resume <run-directory>; do not create a second process against the same directory.

For a cyclic BoltzGen structure whose file format cannot carry connectivity, the optional sidecar is a strict YAML/JSON map from source ID (or structure filename/stem) to the source binder chain ID:

schema_version: 1
head_to_tail:
  design_0001: A
  design_0002.cif: A

The sidecar declares only the last-C/first-N bond. Any other binder polymer connection is rejected.

Cyclic PocketXMol validation requires one coordinate conformer, an exact heavy-atom PDB/SDF mapping within 0.05 A, and the exact expected inter-residue peptide-bond graph. BoltzGen validation matches generated target chains to the configured canonical target assembly by sequence, preserves deterministic mappings for identical target copies, and rejects unintended binder connections. Invalid source rows remain in the manifest with diagnostics.

The target MSA is queried once per unique target-chain sequence and cached by sequence SHA-256. Designed binder sequences are always single-sequence and are never sent to an MSA service.

Project and data layout

Keep generated data and model caches outside the Git checkout:

binder-filter/                 # this repository
  configs/                     # documented YAML examples
  envs/                        # three isolated Conda environments
  scripts/                     # noninteractive bootstrap/validation entrypoints
  src/binder_filter/           # production package
  tests/                       # immutable small fixtures and tests
/data/binder-filter-inputs/
  targets/
  pocketxmol/<campaign>/
  boltzgen/<campaign>/

/workspace/models/binder-filter/       # immutable snapshots and checksums
/workspace/cache/binder-filter/msa/    # target-only MSA cache
/workspace/results/<job-name>/         # run directories

Source CSV, PDB, CIF, SDF, ZIP, and model files are read-only inputs. Binder Filter does not modify them.

Repository map

binder-filter/
  README.md                     operator guide and scientific interpretation
  pyproject.toml                core package and exact direct dependencies
  configs/                      strict, runnable source-specific YAML examples
  envs/                         Conda specs and model-environment lock files
  scripts/bootstrap_linux.sh    noninteractive, idempotent environment bootstrap
  scripts/smoke_uploaded_outputs.py
  src/binder_filter/
    cli.py                      public command dispatch
    config.py                   strict Pydantic schema and scientific hash
    artifacts.py                directory/file/glob/ZIP indexing
    adapters/                   BoltzGen and PocketXMol input boundaries
    normalization.py            canonical T1...Tn/B1 mmCIF conversion
    msa.py                      target-only MSA cache
    fetch.py                    immutable model/asset locks
    jobs.py                     versioned jobs and atomic completion validation
    protenix_worker.py          isolated Protenix-v2 inference
    esmfold2_worker.py          isolated full ESMFold2 inference/probability export
    metrics.py                  ipSAE, exact actifpTM, RMSD, geometry and descriptors
    analysis.py                 promotion, strict binary filters and analysis CSVs
    selection.py                Pareto ranking and deterministic diversity selection
    output.py                   final CSV/mmCIF/PDF export and PDF verification
    runner.py                   resumable end-to-end orchestration and GPU lock
  tests/                        deterministic unit/integration regression tests
  tests/fixtures/               immutable scientific and cutoff boundary fixtures

The sibling upstream repositories and uploaded campaigns are references or input data; they are intentionally excluded from this package and must not become runtime imports.

Installation and environments

The bootstrap command is non-interactive and idempotent. It uses Conda from PATH or, when Conda is unavailable, provisions the pinned Miniforge release beneath the selected prefix:

bash scripts/bootstrap_linux.sh --prefix /data/binder-filter

The script creates three environments without downloading the full Protenix sequence databases:

Environment Python Responsibility
bf-core 3.11 CLI, ingestion, structures, metrics, filtering, CSV/PDF output
bf-protenix 3.11 Pinned Protenix-v2 inference and remote target MSA client
bf-esmfold2 3.12 Full ESMFold2 and pinned Biohub Transformers

The directly pinned core package dependencies from pyproject.toml are:

Library Version Use
Pydantic 2.11.7 strict YAML schema
gemmi 0.7.3 PDB/mmCIF parsing and writing
RDKit 2025.3.5 SDF topology and chemistry validation
NumPy 2.3.2 confidence, RMSD and geometry calculations
Hugging Face Hub 0.36.2 immutable model snapshots
hf-transfer 0.1.9 accelerated Hugging Face downloads
ReportLab 4.4.3 deterministic PDF generation
PyYAML 6.0.2 YAML parsing and resolved configuration
Poppler Conda-resolved pdfinfo parsing and full-page rendering checks

The test extra pins pytest==8.4.1 and pytest-cov==6.2.1; the package is built with Hatchling (hatchling>=1.27). PyTorch is installed separately into both model environments as torch==2.7.1, torchvision==0.22.1, and torchaudio==2.7.1. The complete transitive model-environment packages are in the two requirements lock files. Each production run also writes the resolved environment, GPU, CUDA, driver, snapshot revisions, weight checksums, and input checksums into provenance files.

Pinned model and scientific-reference revisions are:

Asset Revision
Protenix c3bfc365b3e1341a11935eddfe7bfdc308092147
Biohub ESM 26b0bc2b771e3e419ea74f445a5f35cc094a1509
Biohub Transformers ef32577f55da19a4989cd7b22e004dc43a4998cb
ESMFold2 8fc3ff471022fdce52c77030685eb775de0c00a3
ESMC-6B 45b0fa5d7fb06faefbd5e3b89bdcef35d564e79a
DunbrackLab ipSAE 6174cf9e71cb1bd660cc805856a18c4871a6dec3
ColabFold actifpTM 90327af088c51108f4779916c8f1b11ec623b18f
Protenix-v2 checkpoint Hugging Face revision 87c7a633c66f9407095649d43fb08d1a073093c6; SHA-256 8f931f9774a396b67033d0e58628e1834f4a1448165e04254b40a780b0c0d599

Resolved model-environment packages are recorded in envs/bf-protenix.requirements.lock.txt and envs/bf-esmfold2.requirements.lock.txt. PyTorch is pinned to 2.7.1: bootstrap selects its CUDA 12.6 wheel for A100/H100 and the CUDA 12.8 wheel of the same release for Blackwell sm_120 support. On Blackwell, Protenix uses its documented PyTorch triangle kernels and standard LayerNorm because its optional fused binaries lack sm_120; scientific inputs and inference settings remain unchanged.

Fresh clone or copied checkout

Model snapshots, target MSAs, uploaded campaigns, and results intentionally live outside the Git checkout. Copying this repository therefore copies the implementation, but not those large assets. On each new machine or workspace:

  1. Run the idempotent bootstrap from the new checkout.
  2. Point models.cache_dir, msa.cache_dir, input paths, and run.output_dir at durable locations outside the checkout. Prefer a local SSD path for the approximately 25 GB ESMC-6B cache; network/FUSE workspace mounts can stall large Hugging Face shard writes. Predictor scratch trees are always created on node-local temporary storage and only validated final artifacts are committed to run.output_dir. Atomic writes retain rename-and-hash validation on FUSE volumes but omit fsync, which can block forever on some attached pod-volume implementations.
  3. Run the CPU suite with the environment on PATH, then validate, fetch, and doctor in that order. fetch reuses checksum-valid snapshots and downloads only missing assets.
  4. Do not copy an old run directory into the new checkout or resume it after source, checkpoint, or scientific-contract changes. Those changes alter the scientific hash; create a new run name and preserve the old run as an archive.
  5. Before expensive inference, verify the pinned ESMFold2 head contract below. A mismatch is an installation/checkpoint error and must stop the run.
bash scripts/bootstrap_linux.sh --prefix /data/binder-filter
conda run -n bf-core pytest -m 'not gpu'
conda run -n bf-core binder-filter validate run.yaml
conda run -n bf-core binder-filter fetch run.yaml
conda run -n bf-core binder-filter doctor run.yaml

The pinned full ESMFold2 model exposes two distinct distance grids:

Output/configuration Bins Range Purpose
raw["distogram_logits"] / structure_head.distogram_bins 64 2-22 A exported structure-contact probabilities used by exact actifpTM
confidence_head.distogram_bins 39 3.25-50.75 A predicted-coordinate embedding used internally by the confidence head

Run this static checkpoint/exporter assertion after fetch and before GPU inference:

conda run -n bf-esmfold2 python - <<'PY'
import numpy as np
from transformers.models.esmfold2.configuration_esmfold2 import ESMFold2Config
from binder_filter.esmfold2_worker import _distogram_lower_bounds

model_dir = "/data/binder-filter/models/esmfold2"  # match models.cache_dir
config = ESMFold2Config.from_pretrained(model_dir, local_files_only=True)
assert config.structure_head.distogram_bins == 64
assert config.confidence_head.distogram_bins == 39
edges = _distogram_lower_bounds(config, 64)
assert len(edges) == 64 and np.isfinite(edges).all()
assert edges[0] == 0.0 and edges[1] == 2.0 and edges[-1] == 22.0
assert (np.diff(edges) > 0).all()
print("ESMFold2 distogram contract: OK")
PY

The exporter must validate raw distogram logits against the 64-bin structure head and write lower bounds concat([0], linspace(2, 22, 63)). It must never compare those logits with the 39-bin confidence grid. PAE is separate and is validated against confidence_head.num_pae_bins. This assertion is part of fresh-checkout acceptance, not an optional diagnostic.

First PocketXMol campaign

Copy and edit configs/pocketxmol_pdl1.yaml. The uploaded PD-L1 campaign contains 30,000 unique canonical 12-residue head-to-tail cyclic peptides. Its top-100 cfd_traj cutoff is 0.614142; cfd_traj is generator self-confidence, not binding confidence or affinity.

The default compute funnel is intentionally economical:

  1. Validate all source rows and retain invalid rows with diagnostics.
  2. Remove exact sequence duplicates from prediction.
  3. Convert the source score to a within-run percentile.
  4. Select the deterministic top 100 by source percentile, source rank, and candidate ID; record diversity without allowing it to displace a higher-ranked preliminary candidate.
  5. Run seed 101 with both predictors: at most 200 preliminary jobs.
  6. Promote at most 30 candidates using conservative confidence, agreement, pose recovery, and diversity. If preliminary failures leave unused capacity, fill it deterministically by source rank so a candidate can still recover under the 3-of-5 confirmation rule.
  7. Complete seeds 101-105 with both predictors: at most 240 additional jobs.
  8. Rank passers and select at most 20 for downstream work.

This is at most 440 holo prediction jobs. The selection lists and scored inputs are persisted before GPU execution so resume never silently reruns selection.

Funnel counts must be interpreted by stage: all 100 preliminary candidates receive one seed from each predictor, but only the promoted 30 receive the five-seed confirmation needed for scientific pass/fail. The other 70 are compute-funnel exclusions, not confirmed scientific failures. Consequently, "16 of 30 pass" means 16 of the 30 fully confirmed candidates passed; the final budget of 20 remains unfilled when fewer than 20 qualify.

For multiple PocketXMol generation seeds, preserve a campaign identifier, normalize cfd_traj within each campaign, globally remove sequence duplicates, pool candidates, and make one global quality/diversity selection. A random generation seed is provenance, not evidence of quality.

BoltzGen campaign

Copy and edit configs/boltzgen_pdl1.yaml. Binder Filter preserves every source CSV field inside source_metrics_json. It prefers quality_score, then design_to_target_iptm, design_iptm, iptm, and finally inverse final_rank for within-run preselection. Those values are generator signals, not new binding evidence.

The current uploaded BoltzGen fixture contains 100 compute-ready final CIFs and 100 matching metrics rows. Its larger CSV contains 25,371 rows but does not provide all corresponding structures, so it cannot be treated as a complete 30,000-structure input.

Additional PD-L1 cyclic BoltzGen examples are included for the current campaign layout:

These examples contain machine-specific /workspace/uploads and model-cache paths; copy them and replace those paths before use on another machine.

Commands

conda run -n bf-core binder-filter validate run.yaml
conda run -n bf-core binder-filter doctor run.yaml
conda run -n bf-core binder-filter fetch run.yaml
conda run -n bf-core binder-filter run run.yaml
conda run -n bf-core binder-filter resume /workspace/results/my_run
conda run -n bf-core binder-filter report /workspace/results/my_run
conda run -n bf-core pytest -m 'not gpu'
conda run -n bf-core pytest -m gpu

fetch downloads only pinned inference assets and queries the remote MSA service once per unique uppercase target-chain sequence. Designed binder sequences are never submitted to an MSA service. Single-sequence fallback is fatal unless explicitly enabled in YAML. run performs fetch, normalization, the persisted preliminary/confirmation funnel, both predictor families under one GPU lock, analysis, and final export. resume validates the scientific configuration hash, implementation-source hash, source inventory, provenance, and every completed artifact before reuse; interrupted or partial jobs alone are rerun. Worker metadata cross-checks normalized-input/MSA/parameter/output checksums, while deterministic model-local failures are terminal and process-level OOM failures receive one batch-size-one retry. report regenerates and Poppler-verifies the PDF from the existing scientific results without launching prediction.

Metrics and hard cutoffs

All medians use valid confirmation seeds. A hard-filter model median requires at least three valid seeds.

Rule Cutoff
Valid holo seeds at least 3/5 from each model
Peptide interaction confidence all three required: Protenix-v2 median ipSAE_min >= 0.60, ESMFold2 median ipSAE_min >= 0.60, and ESMFold2 median exact actifpTM >= 0.93
Miniprotein interaction confidence all three required: Protenix-v2 median ipSAE_min >= 0.60, ESMFold2 median ipSAE_min >= 0.60, and ESMFold2 median exact actifpTM >= 0.93
Peptide cross-model binder RMSD <= 1.25 A
Peptide source-pose recovery RMSD <= 1.50 A
Miniprotein cross-model/source-pose RMSD <= 2.5 A for each
Severe nonbonded C-alpha distance < 2.5 A
Severe target-binder heavy-atom overlap < 0.65 * summed vdW radii
Ordinary reported overlap < 0.80 * summed vdW radii
Miniprotein apo pTM >= 0.70
Miniprotein apo binder pLDDT >= 75
Miniprotein apo-holo RMSD <= 2.5 A

ipSAE uses the pinned official equations with a 10 A PAE cutoff and 15 A structure-distance cutoff, treating all target chains as one partner and B1 as the other. ipSAE_min is the smaller directional value.

actifpTM is calculated only from the real probability pathway required by the pinned ColabFold reference. Expected PAE alone is insufficient and is never relabelled as actifpTM. If ESMFold2 exact probability inputs are unavailable, the value is null and a interaction gate fails. Every mode also requires ipSAE from both model families. The 0.93 actifpTM cutoff is a campaign-prioritization heuristic chosen after sensitivity analysis of the first BoltzGen PD-L1 run; it is not an affinity threshold and has not been experimentally calibrated across targets.

The stricter gate is intentionally conjunctive. A high score from one predictor cannot rescue weak or unavailable evidence from the other. Retrospectively, combining Protenix and ESMFold2 ipSAE_min >= 0.60, exact ESMFold2 actifpTM >= 0.93, cross-model RMSD <= 1.25 A, source-pose RMSD <= 1.50 A, and zero severe clashes retained 16 of the 30 confirmed candidates in the first BoltzGen PD-L1 campaign, compared with 29 under the former permissive rule.

Native ipTM is always recorded and is never a hard gate.

Ranking and output

Non-passers cannot enter the final set. Passers are ranked without a weighted composite score using exactly five evidence dimensions:

  1. Higher Protenix-v2 median ipSAE_min.
  2. Higher full ESMFold2 median ipSAE_min.
  3. Lower cross-model binder RMSD.
  4. Lower source-pose binder RMSD.
  5. Lower worst-family seed variability: the larger within-model median RMSD from the two predictor families.

A candidate belongs to Pareto front 1 when no other passer is at least as good on every dimension and better on at least one. Removing that front and repeating produces fronts 2, 3, and so on. Within a front, each dimension receives a dense ordinal rank; candidates are ordered by their worst of the five ranks, then median rank, then stable candidate ID. This quality_rank is computational evidence priority, not predicted affinity.

Exact ESMFold2 actifpTM and ipSAE from both model families are mandatory interaction evidence for pass/fail in every mode, but their margins are not mixed numerically. Native ipTM, generator score/source rank, hydrophobic patch, liabilities, delta-SASA, contacts, hydrogen bonds, and salt bridges remain report fields and do not affect default final rank. Generator scores are used only for the preliminary compute funnel.

Final selection also has no 90/10 or other weighted utility. Pareto fronts are processed in order, so a lower front cannot displace an available higher-front candidate. Within a front, the strongest weakest-link candidate is selected first. Each subsequent candidate maximizes its minimum joint novelty to the selected set, where pairwise joint novelty is the smaller of sequence-identity distance and target-contact Jaccard distance. Cyclic sequence identity is rotation-aware. Diversity changes selection only; it never changes pass/fail, Pareto front, or quality rank.

This deliberately follows the hard-filter/refold-consistency emphasis of RFdiffusion, the independent confidence/geometry checks used by RFdiffusion3, and BoltzGen's useful worst-ordinal-rank idea, while removing hand-selected metric weights. The BindCraft study also cautions that ipTM can prioritize likely binding but is not an affinity rank. A learned ranking model should replace this default only after multi-target wet-lab calibration with held-out targets.

run.output_dir names the shared results root and run.name is appended automatically. For example, output_dir: /workspace/results and name: pdl1_screen write only beneath /workspace/results/pdl1_screen/. Each job contains resolved configuration and hashes, provenance, normalized structures, selections, predictions, analysis, and final exports:

<run.name>/
  config.resolved.yaml
  provenance.json
  weights.lock.json
  msa.lock.json
  normalized/
    manifest.csv
    structures/<candidate>.cif
    source_cache/
  work/
    state.json
    gpu.lock
    selection/preliminary.json
    selection/confirmation.json
    predictions/
      protenix_v2/<candidate>/<context>/seed_<seed>/
      esmfold2/<candidate>/<context>/seed_<seed>/
    report_render/page-*.png
  analysis/
    per_seed_metrics.csv
    failures.csv
    diversity_clusters.csv
    summary.json
  final_validation/
    all_designs_metrics.csv
    passed_designs_metrics.csv
    final_designs_metrics_<budget>.csv
    passed_complexes/rank0001_<candidate>.cif
    results_overview.pdf
    COMPLETED.json

This follows BoltzGen's useful output convention: deterministic rank-prefixed structures, an all-designs CSV, a budget-specific final CSV, and a PDF overview. Binder Filter does not reuse BoltzGen's scientific ranking or pass logic. The copied structures are only Binder Filter passers, and the final-budget CSV marks the diversity-selected subset. The output convention was reviewed against HannesStark/boltzgen commit a3149cf18eeb58648d1abbb27539bd73f746cdda, particularly src/boltzgen/task/filter/filter.py. Binder Filter has no runtime dependency on that checkout.

Known limitations in this release

  • Peptide modes have genuine dual-model GPU smoke coverage and a completed BoltzGen production campaign. A PocketXMol cyclic production campaign must be rerun under the v0.2.0 scientific hash after the cutoff change.
  • Miniprotein support is implemented end to end: schema, ingestion, normalized structures, the isolated-binder apo confirmation stage (seeds 101-105 for both predictors), and the pass_miniprotein_apo gate (at least one model with median apo pTM >= 0.70, apo binder pLDDT >= 75, and binder-aligned apo-holo RMSD <= 2.5 A), with unit and synthetic end-to-end coverage. It has not yet passed a genuine GPU acceptance run. Do not describe miniprotein support as accepted production coverage until its GPU acceptance test passes.
  • Screening relaxation is unavailable and enabled: true is rejected. Final structures are unmodified consensus medoids and are not MD-ready systems.
  • Protenix does not expose the exact probability tensors required by the pinned actifpTM pathway. Every mode therefore requires ipSAE from both predictors plus ESMFold2 exact actifpTM.
  • Confidence metrics prioritize candidates; they are not affinity, specificity, or experimental-success probabilities.

License and attribution

Binder Filter source code is provided under the included Apache-2.0 license. Upstream code, model weights, data, and generated campaigns remain subject to their respective licenses and terms. Any independently reimplemented upstream algorithm retains its pinned revision, license notice, provenance, and regression fixtures.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages