🧬 Resonance-Flow: Differentiable Protein Structure Prediction with NMR Self-Correction
Resonance-Flow is a JAX-native protein structure prediction framework that integrates differentiable biophysics with experimental NMR constraints. It allows models to "self-correct" by propagating gradients from physical violations (atomic clashes, bad geometry) and NMR observables (RDCs, NOE distances) back into the neural network architecture — end-to-end, with no manual refinement step.
🚀 Key Features
- JAX-Native Gradient Flow — End-to-end differentiability from experimental constraints to model weights via
jax.grad. - Saupe Tensor RDC Loss — Differentiable least-squares fitting of the alignment tensor at every forward pass (Bax & Tjandra 1997; Cornilescu et al. 1998).
- NOE Distance Restraints — Flat-bottomed harmonic penalty on upper-bound violations, the primary 3D information source in protein NMR (Wüthrich 1986; Güntert et al. 1997).
- Biophysically Correct Geometry — Bond length loss calibrated to the canonical Cα–Cα distance of 3.80 Å (Engh & Huber 1991).
- Differentiable Steric Clash — Harmonic atom-overlap penalty with optional AMBER/CHARMM-style 1-2/1-3 bonded exclusions, powered by
jax-md. - RDC Quality Metric — Built-in Q-factor and Q_free cross-validation (Cornilescu et al. 1998; Clore & Garrett 1999) for structural validation without additional tooling.
- Backbone Conformational Checks — Pseudo-torsion angle calculation (Oldfield & Hubbard 1994) to verify secondary structure plausibility in Cα-only models.
- PBC Support — Periodic boundary conditions for simulation-box contexts.
- Transformer-to-Coords — A pre-LN Transformer architecture that maps amino acid sequences directly to physical 3D Cα coordinates.
🧠 The Concept: "Self-Correction"
Traditional folding models are trained on static PDB snapshots. Resonance-Flow instead teaches a model to listen to physical laws and NMR data during training itself:
Sequence → [Transformer] → Cα Coordinates
│
┌────────────────────┼──────────────────────┐
▼ ▼ ▼
Steric Clash Bond Length RDC / NOE
Penalty Loss Mismatch
└────────────────────┼──────────────────────┘
│ ∇θ L_total
▼
[Optimizer Step]
Gradients from every constraint flow back simultaneously into the model weights — the model learns not just from data, but from physics.
🛠️ Installation
pip install resonance-flow
For development (includes linting, type-checking, testing, and docs):
git clone https://github.com/elkins-lab/resonance-flow.git
cd resonance-flow
pip install -e ".[dev]"
Requirements: Python 3.10+, JAX ≥ 0.4, Flax, Optax, jax-md, NumPy.
🧪 Quick Start
Run the self-correction demo
from resonance_flow.train import main
state = main(num_steps=100)
# Step 0 | Total Loss: 12.3421 | Steric: 0.0012 | Bond: 1.2034 | RDC: 0.0087
# Step 10 | Total Loss: 4.1823 | ...
# Step 100 | Total Loss: 0.0031 | ...
Use individual loss functions
import jax.numpy as jnp
from resonance_flow import (
get_steric_clash_loss,
get_bond_length_loss,
rdc_loss,
rdc_q_factor,
noe_upper_bound_loss,
estimate_nh_proxy_vectors,
)
# ── Steric clash (AMBER-style 1-2 bonded exclusion) ──────────────────────────
clash_fn = get_steric_clash_loss(exclude_bonded_range=1)
positions = jnp.array([[0.0, 0.0, 0.0], [4.0, 0.0, 0.0]])
atom_radii = jnp.array([1.5, 1.5])
clash_fn(positions, atom_radii) # → 0.0 (no overlap)
# ── Bond length (Cα–Cα virtual bond, Engh & Huber 1991) ─────────────────────
bond_fn = get_bond_length_loss() # default target = 3.8 Å
ca_chain = jnp.array([[0.0,0.0,0.0],[3.8,0.0,0.0],[7.6,0.0,0.0]])
bond_fn(ca_chain) # → ~0.0
# ── RDC loss (Saupe tensor fitting) ─────────────────────────────────────────
nh_vecs = jnp.array([[1.,0.,0.],[0.,1.,0.],[0.,0.,1.],
[0.7,0.7,0.],[0.7,0.,0.7],[0.,0.7,0.7]])
measured_rdc = jnp.array([10., -5., 2., 0., 4., 8.])
rdc_loss(nh_vecs, measured_rdc) # → scalar MSE
# ── RDC Q-factor (structure quality; Q ≤ 0.20 = high quality) ───────────────
rdc_q_factor(nh_vecs, measured_rdc) # → 0 – 1 (lower is better)
train_mask = jnp.array([True, True, True, False, False, False])
rdc_q_free(nh_vecs, measured_rdc, train_mask) # → Q-factor on held-out data
# ── N-H proxy vectors from Cα coordinates (Cα-only models) ──────────────────
ca_coords = jax.random.normal(jax.random.PRNGKey(0), (10, 3))
nh_proxy = estimate_nh_proxy_vectors(ca_coords) # → (8, 3) unit vectors
# ── NOE upper-bound distance restraints (Wüthrich 1986) ─────────────────────
noe_pairs = jnp.array([[0, 2], [1, 3]])
upper_bounds = jnp.array([5.0, 4.5])
noe_upper_bound_loss(positions, noe_pairs[:1], upper_bounds[:1]) # → 0.0
🎓 Interactive Tutorial Catalog
Experience Resonance-Flow directly in your browser via Google Colab. These interactive Jupyter Notebook tutorials cover everything from basic biophysics to advanced structural self-correction.
| Tutorial | Difficulty | Time | Action |
|---|---|---|---|
| Self-Correction Demo | ⭐ Beginner | 15 min | |
| Biophysical Constraints | ⭐ Beginner | 15 min | |
| Differentiable NMR | ⭕ Intermediate | 25 min | |
| Transformer-to-Coords | 🏔️ Advanced | 30 min |
🔬 Scientific Basis
All loss functions and validation metrics are grounded in published, peer-reviewed NMR methodology:
| Loss / Metric | Scientific Basis |
|---|---|
| RDC loss — Saupe tensor | Bax & Tjandra, J. Biomol. NMR 1997; Cornilescu et al., JACS 1998 |
| RDC Q-factor | Cornilescu et al., JACS 1998; Clore & Garrett, JACS 1999 |
| NOE distance restraints | Wüthrich, NMR of Proteins and Nucleic Acids 1986; Güntert et al., J. Mol. Biol. 1997 |
| Cα–Cα bond distance (3.8 Å) | Engh & Huber, Acta Crystallogr. A 1991 |
| N-H proxy vectors | Zweckstetter & Bax, JACS 2000 |
| Bonded exclusion (1-2/1-3) | Cornell et al. (AMBER), JACS 1995; MacKerell et al. (CHARMM), J. Phys. Chem. B 1998 |
| d_max = 21 700 Hz | Ottiger & Bax, JACS 1998 |
🧬 Architecture
TransformerCoordinatePredictor
├── Embedding (vocab_size=21, d_model=128)
├── Positional Embed (learned, max_len=512)
├── N × Pre-LN Block
│ ├── LayerNorm → MultiHeadDotProductAttention → Residual
│ └── LayerNorm → FFN (4× expand, GELU) → Residual
└── LayerNorm → Linear(3) # → (batch, seq_len, 3) Cα coordinates
The pre-LN (LayerNorm before attention) layout avoids gradient explosion and follows the convention recommended by Xiong et al. 2020.
🤝 Contributing
Contributions are welcome! Please open an issue or pull request. The project follows:
- Formatting + Linting:
ruff/ruff format - Type checking:
mypy - Testing:
pytestwith coverage
# Run the full quality pipeline before submitting a PR
ruff check resonance_flow tests
ruff format resonance_flow tests
mypy resonance_flow tests
pytest --cov=resonance_flow tests
📚 Documentation
Full theory, API reference, and examples at elkins-lab.github.io/resonance-flow.
⚖️ License
MIT © George Elkins
🔗 Related Projects
Resonance-Flow is the most complete end-to-end model in this ecosystem, depending on:
- diff-biophys — Differentiable RDC, NOE, bond-length, and clash kernels
- synth-nmr — NMR parameter libraries (chemical shifts, Karplus, RDC)
- synth-pdb — Protein structure data generation
- torsion-tuner — Single-structure refinement using similar torsion-space kinematics
- diff-ensemble — Ensemble counterpart for IDPs
📖 Citation
@software{resonance_flow,
author = {Elkins, George},
title = {Resonance-Flow: Differentiable protein structure prediction with NMR self-correction},
year = {2026},
url = {https://github.com/elkins-lab/resonance-flow},
version = {0.1.3}
}
Release files for resonance-flow 0.1.3
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| resonance_flow-0.1.3.tar.gz | 25.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| resonance_flow-0.1.3-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 38.6 kB
Release files / resonance_flow-0.1.3.tar.gz
| Download URL | resonance_flow-0.1.3.tar.gz |
|---|---|
| Size | 25.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ac543e59fed31afbaec01859c38a8a1cd1bdda01d805191f8782014eef27aa66
|
|
BLAKE2b-256 checksum How to use checksums |
1153af81a24870c227ce37a9685a18cf5c3bf127ac297f0ba3f60cc341462141
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
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 Jun 30, 2026.
Transparency logRelease files / resonance_flow-0.1.3-py3-none-any.whl
| Download URL | resonance_flow-0.1.3-py3-none-any.whl |
|---|---|
| Size | 13.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a814f6f2c3c349ed1b6d0171d0d21b09ec94f360be2905d6bf09e6b092fd1bc5
|
|
BLAKE2b-256 checksum How to use checksums |
8b6208b0ac1c7faba176fb9eed9a7243766573f15b215f5f2c11a40d2e5c8273
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
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 Jun 30, 2026.
Transparency log