Basic NMR Prediction Tutorial¶
Welcome to synth-nmr! This notebook demonstrates the core functionality of the package: parsing a 3D structural model and predicting its corresponding NMR experimental observables.
This tutorial is designed to run completely inside Google Colab (or any Jupyter environment).
1. Installation & Environment Setup¶
First, we'll install synth-nmr and its structural biology dependency, biotite. We'll also install torch to enable the high-accuracy Neural Network chemical shift predictor.
!pip install -q synth-nmr biotite torch
2. Download a Test Structure¶
NMR observables heavily depend on the exact positions of Hydrogen atoms. Therefore, your input PDB must contain hydrogen coordinates.
For this tutorial, we will directly download Ubiquitin (1D3Z). This is a classic NMR structure ensemble, which means it naturally contains all expertly assigned hydrogens.
!wget -q https://files.rcsb.org/download/1D3Z.pdb -O ubiquitin.pdb
3. Load the Structure into Biotite¶
We use biotite to load the PDB file and extract the first model from the ensemble.
import biotite.structure.io as strucio
# Load the multi-model NMR ensemble
ensemble = strucio.load_structure("ubiquitin.pdb")
# Extract only the first model for our calculations
structure = ensemble[0]
print(f"Loaded {len(structure)} atoms for Ubiquitin Model 1.")
print(f"Contains Hydrogens? {'H' in structure.element}")
4. Predict Chemical Shifts (Neural Predictor)¶
synth-nmr features a state-of-the-art Neural Network predictor that evaluates 3D coordinates, torsion angles, distances, and Coulomb matrices to output highly accurate Chemical Shifts.
Under the hood, if torch isn't available, it will transparently fall back to an empirical SPARTA+ algorithm!
from synth_nmr import predict_chemical_shifts
shifts = predict_chemical_shifts(structure)
# Let's inspect the predicted C-alpha (CA) and Amide (N) shifts for Residue 10 (Glycine)
print("Predicted Chemical Shifts for Residue 10 (Glycine):")
print(f" CA: {shifts['A'][10]['CA']} ppm")
print(f" N: {shifts['A'][10]['N']} ppm")
5. Extract Synthetic NOE Distance Restraints¶
The Nuclear Overhauser Effect (NOE) is proportional to $r^{-6}$ (where r is the distance between two protons). We can extract all pairs of protons that are within a realistic NOE generation radius (typically < 5.0 Å).
from synth_nmr import calculate_synthetic_noes
# Exclude intra-residue connections since they aren't useful for 3D folding
noes = calculate_synthetic_noes(structure, cutoff=5.0, exclude_intra_residue=True)
print(f"Found {len(noes)} inter-residue NOE distance restraints!")
print("\nFirst 3 NOEs:")
for _i, noe in enumerate(noes[:3]):
print(
f" {noe['index_1']} {noe['atom_name_1']} <--> {noe['index_2']} {noe['atom_name_2']}: {noe['distance']:.2f} Å"
)
6. Calculate J-Couplings¶
Scalar J-couplings (specifically $^3J_{HN-H\alpha}$) correlate strongly with the backbone $\phi$ dihedral angle via the Karplus equation.
from synth_nmr import calculate_hn_ha_coupling
j_couplings = calculate_hn_ha_coupling(structure)
print("Predicted 3J(HN-HA) Couplings:")
for res_id in [10, 11, 12]:
print(f" Residue {res_id}: {j_couplings['A'][res_id]:.2f} Hz")
Next Steps¶
You've successfully simulated a basic set of NMR observables for a protein! You can also explore Residual Dipolar Couplings (RDCs), Relaxation (R1, R2, S2), and NEF export formatting in the package.
Check out the other tutorials on the synth-nmr documentation site.