Skip to content

torsion Module

The torsion module provides tools for calculating and analyzing the dihedral angles that define protein backbone and side-chain conformations.

Overview

Dihedral (torsion) angles are the most important degrees of freedom in a protein. This module extracts these angles from Biotite structures, enabling Ramachandran analysis and torsion-space modeling.

Key Features

  • Backbone Torsions: Calculation of \(\phi\) (phi), \(\psi\) (psi), and \(\omega\) (omega) angles.
  • Side-Chain Torsions: Extraction of \(\chi_1, \chi_2, \chi_3, \chi_4\) angles.
  • Statistics: Tools for comparing synthetic torsion distributions against experimental libraries.

API Reference

torsion

Functions

calculate_torsion_angles(atom_array)

Calculate backbone torsion angles (phi, psi, omega) for a given structure.

Parameters:

Name Type Description Default
atom_array AtomArray

Biotite AtomArray containing the protein structure.

required

Returns:

Type Description
list[dict[str, Any]]

List of dictionaries, one per residue, containing:

list[dict[str, Any]]
  • residue: 3-letter code
list[dict[str, Any]]
  • res_id: Residue number
list[dict[str, Any]]
  • phi: Phi angle in degrees (or None)
list[dict[str, Any]]
  • psi: Psi angle in degrees (or None)
list[dict[str, Any]]
  • omega: Omega angle in degrees (or None)
Source code in synth_pdb/torsion.py
def calculate_torsion_angles(atom_array: struc.AtomArray) -> list[dict[str, Any]]:
    """Calculate backbone torsion angles (phi, psi, omega) for a given structure.

    Args:
        atom_array: Biotite AtomArray containing the protein structure.

    Returns:
        List of dictionaries, one per residue, containing:
        - residue: 3-letter code
        - res_id: Residue number
        - phi: Phi angle in degrees (or None)
        - psi: Psi angle in degrees (or None)
        - omega: Omega angle in degrees (or None)

    """
    logger.info("Calculating backbone torsion angles...")

    # Calculate angles using Biotite
    # dihedral_backbone returns (phi, psi, omega) in RADIANS for each residue.
    # Note: biotite.structure.dihedral_backbone calculates phi, psi, omega for each residue.
    # The first residue's phi is usually NaN, last residue's psi is NaN.

    phi, psi, omega = struc.dihedral_backbone(atom_array)

    # Convert to degrees
    phi_deg = np.degrees(phi)
    psi_deg = np.degrees(psi)
    omega_deg = np.degrees(omega)

    # Get residue identifiers
    # We iterate through indices corresponding to the backbone results
    # Ideally should use residue iterator to be safe, but backbone arrays map to residues.

    # Get unique residue IDs to map back
    residue_starts = struc.get_residue_starts(atom_array)

    results = []

    for i, start_idx in enumerate(residue_starts):
        res_name = atom_array.res_name[start_idx]
        res_id = int(atom_array.res_id[start_idx])

        # Handle NaN values (convert to None for JSON compliance)
        p = phi_deg[i]
        ps = psi_deg[i]
        o = omega_deg[i]

        if np.isnan(p):
            p = None
        if np.isnan(ps):
            ps = None
        if np.isnan(o):
            o = None

        entry = {"residue": res_name, "res_id": res_id, "phi": p, "psi": ps, "omega": o}
        results.append(entry)

    logger.info(f"Calculated angles for {len(results)} residues.")
    return results

Scientific Principles

Dihedral Definition

A dihedral angle is defined by four consecutive atoms (\(A-B-C-D\)). It is the angle between the plane containing \(A, B, C\) and the plane containing \(B, C, D\).

  • \(\phi\) (Phi): \(C_{i-1} - N_i - C\alpha_i - C_i\)
  • \(\psi\) (Psi): \(N_i - C\alpha_i - C_i - N_{i+1}\)
  • \(\omega\) (Omega): \(C\alpha_i - C_i - N_{i+1} - C\alpha_{i+1}\)

The Ramachandran Plot

By plotting \(\phi\) vs. \(\psi\), we can visualize the allowed conformational space of a protein. Helices and sheets appear as distinct clusters on this plot. The torsion module provides the raw data needed to generate these visualizations.

Usage Example

from synth_pdb.generator import PeptideGenerator
from synth_pdb.torsion import calculate_torsion_angles

# 1. Generate a structure
gen = PeptideGenerator("MEELQK")
structure = gen.generate(conformation="alpha")

# 2. Calculate backbone torsions
angles = calculate_torsion_angles(structure)

for res in angles:
    print(f"Residue {res['res_id']} ({res['res_name']}):")
    print(f"  Phi: {res['phi']:.1f}Β°, Psi: {res['psi']:.1f}Β°")