Fast algorithms for MD trajectories
Project description
Rust Simulation Tools
High-performance molecular dynamics analysis library with a Python API. Written in Rust for speed, exposed to Python via PyO3.
Installation
From PyPI using uv:
uv pip install rust-simulation-tools
For the latest version which may not be on PyPI yet, make sure you have cloned this repo and have
maturin installed to your environment of choice:
uv venv /path/to/env
source /path/to/env/bin/activate
uv pip install maturin
git clone https://github.com/msinclair-py/rust-simulation-tools.git
cd rust-simulation-tools
maturin develop --release
Features
- File I/O: AMBER topology/coordinates, DCD and MDCRD trajectories; PDB, mmCIF, mol2, SDF structures
- System building: tleap-style
SystemBuilder— force fields, solvation, ions, prmtop/inpcrd output - Ligand parameterization: built-in antechamber — GAFF2 atom typing + AM1-BCC charges (no AmberTools needed)
- Selections: VMD-style atom selection with property access
- Analysis: SASA, trajectory unwrapping, Kabsch alignment
- Fingerprints: Per-residue interaction energies (LJ + electrostatic)
- Minimization: Steepest-descent + conjugate-gradient with optional restraints
- MM-PBSA/GBSA: Binding free energy with per-residue decomposition
- Interface scoring: ipSAE, pDockQ, pDockQ2, LIS, ipTM for predicted complexes
Quick Start
Load a System
from rust_simulation_tools import read_prmtop, read_inpcrd, DcdReader
# Load topology and coordinates
topo = read_prmtop("system.prmtop")
coords, box = read_inpcrd("system.inpcrd")
# Load trajectory
dcd = DcdReader("trajectory.dcd")
trajectory, boxes = dcd.read_all()
Build a System
The SystemBuilder parameterizes structures and writes simulation-ready AMBER
files — no AmberTools install required.
from rust_simulation_tools import SystemBuilder
builder = SystemBuilder()
builder.load_protein_ff19sb() # protein force field
builder.load_gaff2() # small-molecule force field
builder.load_water_opc() # OPC water model
# Load structures (PDB / mmCIF for proteins, mol2/SDF for ligands)
protein = builder.load_pdb("protein.pdb")
ligand = builder.load_ligand("ligand.sdf", net_charge=0) # auto GAFF2 + AM1-BCC
# Combine, solvate, ionize
system = builder.combine([protein, ligand])
builder.solvate_box(system, buffer=12.0)
builder.add_salt(system, "Na+", "Cl-", concentration=0.150) # neutralize + 150 mM
# Write output
builder.write_amber(system, "complex.prmtop", "complex.inpcrd")
builder.write_pdb(system, "complex.pdb")
For implicit solvent, skip load_water_opc/solvation and write the topology
directly. See examples/example_explicit_solvent.py,
example_implicit_solvent.py, and example_protein_ligand.py.
Parameterize a Ligand
import rust_simulation_tools as rst
# Standalone: write a parameterized mol2 (GAFF2 types + charges)
rst.parameterize_ligand(
"ligand.sdf", "ligand_gaff2.mol2",
net_charge=0,
charge_method="am1bcc", # or "gasteiger" (faster, less accurate)
)
# Raw AM1 Mulliken charges from atomic numbers + coordinates
import numpy as np
charges = rst.compute_am1_charges(
np.array([8, 1, 1], dtype=np.int64), # O, H, H
np.array([[0, 0, 0], [0, 0.757, 0.587], [0, -0.757, 0.587]], dtype=float),
charge=0,
)
Atom Selection
Select atoms using VMD-style expressions. The select() method returns a Selection object with direct property access.
# Select protein backbone
backbone = topo.select("backbone")
print(f"{backbone.n_atoms} atoms, {backbone.n_residues} residues")
# Access properties directly
ca = topo.select("protein and name CA")
print(ca.masses) # numpy array of masses
print(ca.charges) # numpy array of charges
print(ca.total_mass()) # sum of masses
# Distance-based selection (requires coordinates)
near_lig = topo.select("protein and within 5.0 of resname LIG", coordinates=coords)
# Set operations
charged = topo.select("charge < -0.5 or charge > 0.5")
sidechain = topo.select("sidechain")
charged_sidechain = sidechain & charged # intersection
Supported selection keywords:
protein,backbone,sidechain,watername CA,resname ALA,resid 1-50charge > 0.5,mass < 2.0within 5.0 of resname LIG- Boolean:
and,or,not
SASA Calculation
from rust_simulation_tools import compute_sasa_from_topology
# Single frame
sasa = compute_sasa_from_topology(topo, coords)
print(f"Total SASA: {sasa['total']:.1f} A^2") # float
print(f"Per-atom: {sasa['per_atom'].shape}") # ndarray (n_atoms,)
print(f"Per-residue: {sasa['per_residue'].shape}") # ndarray (n_residues,), by residue index
# Trajectory: total -> ndarray (n_frames,), per_residue -> list of per-frame dicts
traj_sasa = compute_sasa_trajectory_from_topology(topo, trajectory)
Trajectory Alignment
from rust_simulation_tools import kabsch_align
# Align trajectory to first frame using backbone atoms
backbone = topo.select("backbone")
aligned = kabsch_align(trajectory, trajectory[0], backbone.indices)
Trajectory Unwrapping
from rust_simulation_tools import unwrap_dcd
# Remove periodic boundary artifacts
unwrapped, boxes = unwrap_dcd("trajectory.dcd")
Interaction Fingerprints
Calculate per-residue LJ and electrostatic interactions between a target and partner.
from rust_simulation_tools import FingerprintSession, FingerprintMode
session = FingerprintSession("system.prmtop", "trajectory.dcd")
session.set_target_residues(range(10)) # residues to fingerprint
session.set_binder_residues(range(10, 100)) # interaction partner
# Iterate over frames
for lj_fp, es_fp in session:
print(f"LJ: {lj_fp.sum():.2f}, ES: {es_fp.sum():.2f} kJ/mol")
# Switch perspective: fingerprint binder residues instead
session.set_fingerprint_mode(FingerprintMode.Binder)
session.seek(0)
MM-PBSA/GBSA Binding Energy
Calculate binding free energy with Generalized Born or Poisson-Boltzmann solvation.
from rust_simulation_tools import (
compute_binding_energy,
decompose_binding_energy,
GbModel, GbParams, PbParams, SaParams,
)
# MM-GBSA over trajectory
result = compute_binding_energy(
topo,
trajectory_path="trajectory.dcd",
receptor_residues=list(range(0, 250)),
ligand_residues=list(range(250, 251)),
gb_params=GbParams(model=GbModel.ObcII, salt_concentration=0.15),
sa_params=SaParams(),
trajectory_format="dcd",
)
print(f"Delta G: {result.mean_delta_total:.2f} +/- {result.std_delta_total:.2f} kcal/mol")
print(f" MM: {result.mean_delta_mm:.2f}")
print(f" GB: {result.mean_delta_gb:.2f}")
print(f" SA: {result.mean_delta_sa:.2f}")
# MM-PBSA (use pb_params instead of gb_params)
pb_result = compute_binding_energy(
topo, "trajectory.dcd",
receptor_residues=list(range(0, 250)),
ligand_residues=list(range(250, 251)),
pb_params=PbParams(grid_spacing=0.5, salt_concentration=0.15),
)
# Per-residue decomposition
decomp = decompose_binding_energy(
topo, coords,
receptor_residues=list(range(0, 250)),
ligand_residues=list(range(250, 251)),
)
for res in sorted(decomp.receptor_residues, key=lambda r: r.total())[:5]:
print(f"{res.residue_label}{res.residue_index}: {res.total():.2f} kcal/mol")
Energy Minimization
Steepest-descent + conjugate-gradient minimization with optional positional restraints and a full energy-component breakdown.
from rust_simulation_tools import minimize, MinimizeConfig
config = MinimizeConfig(
max_cycles=5000,
sd_cycles=100, # initial steepest-descent steps
convergence_rms=0.01,
cutoff=10.0,
restraint_mask="backbone", # optional; omit for unrestrained
restraint_weight=10.0,
)
result = minimize("system.prmtop", "system.inpcrd", config=config, output="min.inpcrd")
print(f"Energy: {result.final_energy:.2f} kcal/mol converged={result.converged}")
ec = result.energy_components # bond, angle, dihedral, vdw,
print(ec.total(), ec.vdw, ec.elec_recip) # elec_direct, elec_recip, vdw_14, elec_14
Use minimize_topology(topo, "system.inpcrd", ...) to reuse a pre-loaded
topology. See examples/example_minimization.py.
Interface Scoring (ipSAE)
Score predicted complexes (AlphaFold-Multimer, Boltz, Chai) from pLDDT and PAE.
import numpy as np
from rust_simulation_tools import compute_ipsae
plddt = np.load("plddt.npy") # per-residue, 0-100 scale, shape (N,)
pae = np.load("pae.npy").flatten() # predicted aligned error, flattened (N*N,)
results = compute_ipsae("model.pdb", plddt, pae) # PDB or CIF
for pair in results["max_pairs"]: # also "directed_pairs"
print(f"{pair['chain1']}-{pair['chain2']}: "
f"ipSAE={pair['ipSAE']:.3f} pDockQ={pair['pDockQ']:.3f} LIS={pair['LIS']:.3f}")
compute_ipsae_from_arrays(coords, chains, chain_types, plddt, pae) does the same
from in-memory arrays. See examples/example_ipsae.py.
API Reference
File I/O
| Function | Description |
|---|---|
read_prmtop(path) |
Load AMBER topology, returns AmberTopology |
read_inpcrd(path) |
Load AMBER coordinates, returns (coords, box) |
DcdReader(path) |
DCD trajectory reader |
MdcrdReader(path, n_atoms, has_box) |
AMBER ASCII trajectory reader |
System Building
| Method | Description |
|---|---|
SystemBuilder() |
Create a tleap-style builder |
.load_protein_ff19sb(), .load_gaff2(), .load_water_opc() |
Load force fields / water model |
.load_custom_frcmod(path), .load_custom_lib(path) |
Load custom ligand parameters |
.load_pdb(path), .load_mmcif(path), .load_mol2(path) |
Load a structure, returns System |
.load_ligand(path, net_charge=0) |
Load + parameterize a ligand (GAFF2 + AM1-BCC) |
.combine([systems]) |
Merge systems into one System |
.solvate_box(system, buffer=12.0, closeness=1.0) |
Solvate in an OPC water box |
.add_ions(system, ion, count=None) |
Add ions ("neutralize", int count, or float conc.) |
.add_salt(system, cation="Na+", anion="Cl-", concentration=0.150) |
Neutralize + add salt |
.write_amber(system, prmtop, inpcrd), .write_prmtop/.write_inpcrd/.write_pdb |
Write output |
System exposes .n_atoms, .n_residues, .total_charge, .box_dimensions,
.box_angles.
Parameterization
| Function | Description |
|---|---|
parameterize_ligand(input, output, net_charge=0, charge_method="am1bcc") |
Write a GAFF2/charge-assigned mol2 ("am1bcc" or "gasteiger") |
compute_am1_charges(atomic_numbers, coords, charge=0) |
Raw AM1 Mulliken charges |
AmberTopology
| Property/Method | Description |
|---|---|
.n_atoms, .n_residues |
System size |
.atom_names, .residue_labels |
Atom/residue names |
.charges(), .sigmas(), .epsilons() |
Force field parameters |
.select(expression, coordinates=None) |
VMD-style selection, returns Selection |
.bonds() |
List of bonded atom pairs |
Selection
| Property/Method | Description |
|---|---|
.n_atoms, .n_residues |
Selection size |
.indices |
Atom indices (numpy array) |
.masses, .charges, .radii |
Per-atom properties |
.atom_names, .residue_names |
Names as lists |
.positions |
Coordinates (if provided during selection) |
.total_mass(), .total_charge() |
Aggregate properties |
&, |, - |
Set operations (intersection, union, difference) |
DcdReader
| Property/Method | Description |
|---|---|
.n_frames, .n_atoms |
Trajectory size |
.read_frame() |
Read next frame, returns (coords, box) |
.read_all() |
Read all frames, returns (trajectory, boxes) |
.seek(frame) |
Jump to frame index |
Analysis Functions
| Function | Description |
|---|---|
compute_sasa_from_topology(topo, coords) |
SASA using topology for radii |
compute_sasa_trajectory_from_topology(topo, trajectory) |
Per-frame SASA over a trajectory |
calculate_sasa(coords, radii, residue_indices) |
SASA with explicit radii |
kabsch_align(trajectory, reference, align_indices) |
RMSD-minimizing alignment |
unwrap_dcd(path) |
Remove PBC artifacts from DCD |
unwrap_system(trajectory, boxes) |
Remove PBC artifacts |
FingerprintSession(prmtop, trajectory) |
Per-residue LJ/electrostatic fingerprints |
Minimization
| Function | Description |
|---|---|
minimize(prmtop, inpcrd, config=None, output=None) |
Minimize from files, returns MinimizeResult |
minimize_topology(topo, inpcrd, config=None, output=None) |
Minimize with a pre-loaded topology |
MinimizeConfig(max_cycles, sd_cycles, convergence_rms, cutoff, restraint_mask, restraint_weight, initial_step_size) |
Minimization settings |
MinimizeResult exposes .final_energy, .final_rms, .cycles, .converged,
.energy_components (.bond, .angle, .dihedral, .vdw, .elec_direct,
.elec_recip, .vdw_14, .elec_14, .total()).
MM-PBSA/GBSA
| Function | Description |
|---|---|
compute_binding_energy(...) |
Trajectory-averaged binding energy |
compute_binding_energy_single_frame(...) |
Single frame binding energy |
decompose_binding_energy(...) |
Per-residue energy decomposition |
compute_mm_energy(topo, coords) |
Molecular mechanics energy |
compute_gb_energy(topo, coords, params) |
GB solvation energy |
compute_pb_energy(topo, coords, params) |
PB solvation energy |
compute_sa_energy(topo, coords, params) |
Nonpolar surface-area energy |
interaction_entropy(frames, temperature) |
Interaction-entropy correction |
quasi_harmonic_entropy(...) |
Quasi-harmonic entropy estimate |
Parameter objects: GbParams, PbParams, SaParams, GbModel.
Interface Scoring
| Function | Description |
|---|---|
compute_ipsae(structure_path, plddt, pae, pdockq_cutoff=8.0, pae_cutoff=12.0) |
ipSAE/pDockQ/LIS/ipTM from a PDB/CIF file |
compute_ipsae_from_arrays(coords, chains, chain_types, plddt, pae, ...) |
Same, from in-memory arrays |
Agent Skills
The skills/ directory contains agent skills that
teach AI coding assistants (e.g. Claude Code) how to use this package — system
building, ligand parameterization, trajectory analysis, MM-PBSA, minimization,
and ipSAE scoring. They are mirrored under .claude/skills/ so they load
automatically when working in this repo. See skills/README.md
for the full list and how to install them elsewhere.
Development
git clone https://github.com/msinclair-py/rust-simulation-tools.git
cd rust-simulation-tools
pip install maturin pytest numpy
maturin develop --release
pytest tests/ -v
License
MIT License
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file rust_simulation_tools-0.2.5.tar.gz.
File metadata
- Download URL: rust_simulation_tools-0.2.5.tar.gz
- Upload date:
- Size: 1.2 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: maturin/1.14.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
06c0e58782f44f5179c9528c81f8f62b1c8b5d0d50c98aadf18d0b3f39b45def
|
|
| MD5 |
21bf2e4972cab1cdc2fc21626d17c5be
|
|
| BLAKE2b-256 |
4dbc9b1f68c8526479597e08fbd00ce2768f0807631760ddc4891c3d8f41a966
|
File details
Details for the file rust_simulation_tools-0.2.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: rust_simulation_tools-0.2.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 2.3 MB
- Tags: CPython 3.13, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: maturin/1.14.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ac5c990ac53e10dff6a6bd5e3c9582519999b8aeafe001bc6a5eacd07e1bcf58
|
|
| MD5 |
a946b6174ecb15c6d5f4f3cf63cbf27d
|
|
| BLAKE2b-256 |
1d74d7779427b4e0e212808b2aa78bc73a6811bc212c168d80a3762985117769
|
File details
Details for the file rust_simulation_tools-0.2.5-cp313-cp313-macosx_11_0_arm64.whl.
File metadata
- Download URL: rust_simulation_tools-0.2.5-cp313-cp313-macosx_11_0_arm64.whl
- Upload date:
- Size: 2.1 MB
- Tags: CPython 3.13, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: maturin/1.14.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
36fa6c5e21b6b1e4581811f6870c501bdf689cdd58bc925aeb24e5b273decfe1
|
|
| MD5 |
6dbb836222f7877d7b1453e960fe9ea1
|
|
| BLAKE2b-256 |
56c2530758d85199e98d5033159659f32b9f8e8b395043e9c4f42ab18d81d7ae
|
File details
Details for the file rust_simulation_tools-0.2.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: rust_simulation_tools-0.2.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 2.3 MB
- Tags: CPython 3.12, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: maturin/1.14.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b76f4e4da1c4c977b5ae55d307af1587a6aad20de623fd184122531d34084268
|
|
| MD5 |
0f1001636bad5f115552dcd90818d592
|
|
| BLAKE2b-256 |
843755f133c1eb47a76c85333ccbaa892b6e014e83f767e21163aefb8820056a
|
File details
Details for the file rust_simulation_tools-0.2.5-cp312-cp312-macosx_11_0_arm64.whl.
File metadata
- Download URL: rust_simulation_tools-0.2.5-cp312-cp312-macosx_11_0_arm64.whl
- Upload date:
- Size: 2.1 MB
- Tags: CPython 3.12, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: maturin/1.14.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
da5c7cea80c6be5d8c74e2da891720db021b281e2bd24f5043f01f0ac1a1cbbf
|
|
| MD5 |
7a97632e2e02268cb71cb97afcd21921
|
|
| BLAKE2b-256 |
8c40439c095989a79e7a258e4095ecbd45883f6fcc6e120a5c48ccaf2872f918
|
File details
Details for the file rust_simulation_tools-0.2.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: rust_simulation_tools-0.2.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 2.3 MB
- Tags: CPython 3.11, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: maturin/1.14.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
11fefdda040db14a37450f50a5d8df80166302ce64ff31161c7aa460ba6735ee
|
|
| MD5 |
11cdf0daae0aaeba9655e4ec1deb6e76
|
|
| BLAKE2b-256 |
da21b355a4b892a23d2b46756601089a740e207a3fa2fbb20940ad62bed02553
|
File details
Details for the file rust_simulation_tools-0.2.5-cp311-cp311-macosx_11_0_arm64.whl.
File metadata
- Download URL: rust_simulation_tools-0.2.5-cp311-cp311-macosx_11_0_arm64.whl
- Upload date:
- Size: 2.1 MB
- Tags: CPython 3.11, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: maturin/1.14.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f8c9dad2dff5bf58b709a01bf35f130e42830fbe8f94e5632d0c6a4c0c5df0a3
|
|
| MD5 |
440767c7ebfcac336ea0aa1ee9b00f1c
|
|
| BLAKE2b-256 |
05d8bcb1e20da1069317ddc03b3c790ca2f0b6ebc3299bf2d4ace3e225917cae
|
File details
Details for the file rust_simulation_tools-0.2.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: rust_simulation_tools-0.2.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 2.3 MB
- Tags: CPython 3.10, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: maturin/1.14.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
474106764d9afa705d8a7fb4289a9731554806b77211bd15172ce8ad86204608
|
|
| MD5 |
22e1bf5c4c0cee238b02c9dc66c854f9
|
|
| BLAKE2b-256 |
3d16056134be59e9eb673fce3b86a5cc5f8b347d896a0ae83d3d7b3b14c7c6a2
|
File details
Details for the file rust_simulation_tools-0.2.5-cp310-cp310-macosx_11_0_arm64.whl.
File metadata
- Download URL: rust_simulation_tools-0.2.5-cp310-cp310-macosx_11_0_arm64.whl
- Upload date:
- Size: 2.1 MB
- Tags: CPython 3.10, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: maturin/1.14.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8708508a8b64c50ecbc45a566eb407d7741c9d653dda8f767bb04b67bdefb1fe
|
|
| MD5 |
96b867e027c3993aa7a8d2d8b09a23e1
|
|
| BLAKE2b-256 |
ba7937ff369c2b41d6b2deeebfb806fda350bd9fd77c46baee6e4a05548836f4
|