Skip to main content
The Trajectory class provides efficient reading and streaming of molecular dynamics trajectory files in multiple formats.

Opening Trajectories

open_xtc

Trajectory.open_xtc(path: str, system: System) -> Trajectory
Open a GROMACS XTC (compressed trajectory) file.
path
str
required
Path to the XTC file
system
System
required
System object with matching atom count
trajectory
Trajectory
Trajectory reader object
from warp_md import System, Trajectory

system = System.from_pdb("protein.pdb")
traj = Trajectory.open_xtc("trajectory.xtc", system)

open_dcd

Trajectory.open_dcd(
    path: str,
    system: System,
    length_scale: float | None = None
) -> Trajectory
Open a CHARMM/NAMD DCD trajectory file.
path
str
required
Path to the DCD file
system
System
required
System object with matching atom count
length_scale
float
default:"1.0"
Optional scaling factor for coordinates. Use 1.0 for Angstroms (CHARMM/NAMD), 10.0 for nanometers.
trajectory
Trajectory
Trajectory reader object
from warp_md import System, Trajectory

system = System.from_pdb("protein.pdb")

# CHARMM/NAMD format (Angstroms)
traj = Trajectory.open_dcd("trajectory.dcd", system)

# If DCD is in nanometers
traj = Trajectory.open_dcd("trajectory.dcd", system, length_scale=10.0)

open_pdb

Trajectory.open_pdb(path: str, system: System) -> Trajectory
Open a multi-model PDB file as a trajectory.
path
str
required
Path to the PDB file with multiple MODEL records
system
System
required
System object with matching atom count
trajectory
Trajectory
Trajectory reader object
from warp_md import System, Trajectory

system = System.from_pdb("first_frame.pdb")
traj = Trajectory.open_pdb("trajectory.pdb", system)

open_pdbqt

Trajectory.open_pdbqt(path: str, system: System) -> Trajectory
Open a PDBQT file as a trajectory (typically for docking poses).
path
str
required
Path to the PDBQT file
system
System
required
System object with matching atom count
trajectory
Trajectory
Trajectory reader object
from warp_md import System, Trajectory

system = System.from_pdbqt("ligand.pdbqt")
traj = Trajectory.open_pdbqt("docking_poses.pdbqt", system)

Reading Frames

read_chunk

traj.read_chunk(
    max_frames: int | None = None,
    include_box: bool = True,
    include_box_matrix: bool = True,
    include_time: bool = True,
    atom_indices: list[int] | None = None
) -> dict | None
Read a chunk of frames from the trajectory.
max_frames
int
default:"auto"
Maximum number of frames to read. If None, uses an automatic chunk size optimized for the trajectory format.
include_box
bool
default:"true"
Include periodic box dimensions (lx, ly, lz) if available
include_box_matrix
bool
default:"true"
Include full 3x3 box matrix for triclinic cells
include_time
bool
default:"true"
Include simulation time in picoseconds
atom_indices
list[int]
default:"None"
Optional list of atom indices to read (subset selection). If None, reads all atoms.
chunk
dict | None
Dictionary containing:
  • coords: np.ndarray of shape (frames, atoms, 3) - coordinates in Angstroms
  • box: np.ndarray of shape (frames, 3) - box dimensions [lx, ly, lz] or None
  • box_matrix: np.ndarray of shape (frames, 3, 3) - full box matrix or None
  • time_ps: np.ndarray of shape (frames,) - time in picoseconds or None
  • frames: int - number of frames read
Returns None when end of trajectory is reached.
# Read all frames in chunks
while (chunk := traj.read_chunk()) is not None:
    coords = chunk['coords']  # (frames, atoms, 3)
    print(f"Read {chunk['frames']} frames")
    print(f"Coords shape: {coords.shape}")
Automatic chunk sizing optimizes memory usage and I/O performance based on the trajectory format and number of atoms.

read_chunk_into

traj.read_chunk_into(
    coords: np.ndarray,
    box_out: np.ndarray | None = None,
    time_out: np.ndarray | None = None,
    max_frames: int | None = None,
    atom_indices: list[int] | None = None
) -> int
Read frames directly into pre-allocated NumPy arrays (zero-copy for XTC/DCD).
coords
np.ndarray
required
Pre-allocated float32 array of shape (max_frames, n_atoms, 3) to store coordinates
box_out
np.ndarray
default:"None"
Optional pre-allocated float32 array of shape (max_frames, 3) for box dimensions
time_out
np.ndarray
default:"None"
Optional pre-allocated float32 array of shape (max_frames,) for time values
max_frames
int
default:"coords.shape[0]"
Maximum number of frames to read (defaults to size of coords array)
atom_indices
list[int]
default:"None"
Optional list of atom indices to read
frames_read
int
Number of frames actually read (0 when end of trajectory reached)
import numpy as np

# Pre-allocate buffers
n_atoms = system.n_atoms()
max_chunk = 1000
coords = np.empty((max_chunk, n_atoms, 3), dtype=np.float32)
box = np.empty((max_chunk, 3), dtype=np.float32)

# Read without intermediate allocations
while (n_read := traj.read_chunk_into(coords, box_out=box)) > 0:
    # Process only the frames actually read
    process_frames(coords[:n_read], box[:n_read])
Arrays must be C-contiguous float32. The atom dimension must match the trajectory or the requested atom_indices.

Trajectory Control

reset

traj.reset() -> None
Reset the trajectory reader to the beginning.
# First pass
while (chunk := traj.read_chunk()) is not None:
    first_pass_analysis(chunk)

# Reset and second pass
traj.reset()
while (chunk := traj.read_chunk()) is not None:
    second_pass_analysis(chunk)

n_atoms

traj.n_atoms() -> int
Get the number of atoms in the trajectory.
count
int
Number of atoms per frame
count = traj.n_atoms()
assert count == system.n_atoms(), "Atom count mismatch!"

Complete Example

from warp_md import System, Trajectory
import numpy as np

# Setup
system = System.from_pdb("protein.pdb")
traj = Trajectory.open_xtc("trajectory.xtc", system)
backbone = system.select("backbone")

# Method 1: Simple chunked reading
all_coords = []
while (chunk := traj.read_chunk(atom_indices=backbone.indices)) is not None:
    all_coords.append(chunk['coords'])
    print(f"Read {chunk['frames']} frames, time: {chunk['time_ps']}")

coords = np.concatenate(all_coords, axis=0)
print(f"Total frames: {coords.shape[0]}")

# Reset for second analysis
traj.reset()

# Method 2: Zero-copy for memory efficiency
n_backbone = len(backbone.indices)
coords_buffer = np.empty((1000, n_backbone, 3), dtype=np.float32)

frame_count = 0
while (n := traj.read_chunk_into(
    coords_buffer,
    atom_indices=backbone.indices
)) > 0:
    frame_count += n
    # Process in-place
    rmsd = compute_rmsd(coords_buffer[:n])

print(f"Processed {frame_count} frames with zero-copy")

Helper Functions

open_trajectory_auto

from warp_md.io import open_trajectory_auto

traj = open_trajectory_auto(
    path: str,
    system: System,
    format: str | None = None,
    length_scale: float | None = None
) -> Trajectory
Automatically detect trajectory format from file extension and open it.
path
str
required
Path to trajectory file (.xtc, .dcd, .pdb, .pdbqt)
system
System
required
System object
format
str
default:"auto"
Force specific format (“xtc”, “dcd”, “pdb”, “pdbqt”). If None, detects from extension.
length_scale
float
default:"1.0"
Length scale for DCD files (ignored for other formats)
from warp_md import System
from warp_md.io import open_trajectory_auto

system = System.from_pdb("protein.pdb")

# Auto-detect format
traj = open_trajectory_auto("trajectory.xtc", system)

# Force format for non-standard extension
traj = open_trajectory_auto("traj.dat", system, format="dcd")

Build docs developers (and LLMs) love