The packing API provides a Python interface to pack molecules into simulation boxes using Packmol-inspired algorithms. It supports complex constraints, multiple structure types, and various output formats.
Quick Start
from warp_md.pack import PackConfig, Structure, Box, run, export
# Define structures to pack
structures = [
Structure(path="protein.pdb", count=1, fixed=True),
Structure(path="water.pdb", count=5000)
]
# Create configuration
config = PackConfig(
structures=structures,
box=Box(size=(50.0, 50.0, 50.0)),
min_distance=2.0,
seed=12345
)
# Run packing
result = run(config)
# Export to PDB
export(result, fmt="pdb", path="packed.pdb")
Core Classes
PackConfig
Main configuration class for packing simulations.
List of structures to pack into the box
Simulation box specification
Random seed for reproducibility
Maximum packing attempts per molecule
Minimum distance between molecules (Angstroms)
Enable periodic boundary conditions
Override file format detection (e.g., “pdb”, “xyz”)
Add box dimensions to output file
Add AMBER-style TER records
Output file specification (alternative to using export())
Advanced Parameters
Maximum iterations for optimization
Number of optimization loops
Check for overlaps during packing
Coordinate precision for optimization
Checkpoint file to restart from
Checkpoint file to save to
Methods
def validate() -> None:
"""Validate configuration parameters."""
def to_dict() -> Dict[str, Any]:
"""Convert to dictionary representation."""
@classmethod
def from_dict(cls, data: Dict[str, Any]) -> PackConfig:
"""Create from dictionary."""
Structure
Defines a molecular structure to pack.
Path to structure file (PDB, XYZ, etc.)
Optional structure name/label
Keep structure fixed in space (no rotation/translation)
Center structure before packing
positions
List[Tuple[float, float, float]]
Fixed positions for each copy
translate
Tuple[float, float, float]
Translation vector to apply
Spatial constraints for packing
Override minimum distance for this structure
Example: Constrained Packing
from warp_md.pack import Structure, Constraint
# Pack 100 waters inside a sphere
water = Structure(
path="water.pdb",
count=100,
constraints=[
Constraint(
mode="inside",
shape="sphere",
center=(25.0, 25.0, 25.0),
radius=15.0
)
]
)
# Pack protein outside the sphere
protein = Structure(
path="protein.pdb",
count=1,
fixed=True,
constraints=[
Constraint(
mode="outside",
shape="sphere",
center=(25.0, 25.0, 25.0),
radius=15.0
)
]
)
Box
Simulation box specification.
size
Tuple[float, float, float]
required
Box dimensions (x, y, z) in Angstroms
shape
str
default:"orthorhombic"
Box shape: “orthorhombic”, “cubic”, or “triclinic”
# Cubic box
box = Box(size=(50.0, 50.0, 50.0), shape="cubic")
# Rectangular box
box = Box(size=(60.0, 40.0, 40.0), shape="orthorhombic")
Constraint
Spatial constraints for structure placement.
Constraint mode: “inside”, “outside”, “fixed”, “over”, “below”
Constraint shape: “box”, “sphere”, “cylinder”, “cube”, “ellipsoid”, “gaussian”, “plane”
Shape Parameters
Box:
min
Tuple[float, float, float]
required
Minimum corner coordinates
max
Tuple[float, float, float]
required
Maximum corner coordinates
Sphere:
center
Tuple[float, float, float]
required
Center coordinates
Cylinder:
base
Tuple[float, float, float]
required
Base point coordinates
axis
Tuple[float, float, float]
required
Cylinder axis vector
Plane:
point
Tuple[float, float, float]
required
Point on the plane
normal
Tuple[float, float, float]
required
Plane normal vector
PackResult
Packing result containing packed system data.
Atomic coordinates (N x 3 array)
box
Tuple[float, float, float]
Final box dimensions
Functions
run
Execute packing with given configuration.
def run(cfg: Union[PackConfig, Dict[str, Any]]) -> PackResult:
"""Run packing simulation.
Args:
cfg: PackConfig object or dictionary representation
Returns:
PackResult containing packed system
Raises:
RuntimeError: If native bindings unavailable
ValidationError: If configuration invalid
"""
Example:
from warp_md.pack import PackConfig, Structure, Box, run
config = PackConfig(
structures=[Structure(path="mol.pdb", count=10)],
box=Box(size=(30.0, 30.0, 30.0)),
seed=42
)
result = run(config)
print(f"Packed {len(result.coords)} atoms")
export
Export packing result to file.
def export(
result: PackResult,
fmt: str,
path: str,
scale: Optional[float] = None,
*,
add_box_sides: bool = False,
box_sides_fix: float = 0.0,
write_conect: bool = True,
hexadecimal_indices: bool = False
) -> None:
"""Export packed system to file.
Args:
result: PackResult to export
fmt: Output format (pdb, xyz, gro, cif, mol2, crd)
path: Output file path
scale: Coordinate scaling factor
add_box_sides: Include box dimensions in output
box_sides_fix: Box dimension adjustment
write_conect: Write connectivity records
hexadecimal_indices: Use hex indices for PDB
"""
Supported formats:
pdb - Protein Data Bank format
xyz - XYZ coordinates
gro - GROMACS format
cif / mmcif - Crystallographic Information File
mol2 - Tripos MOL2 format
crd - CHARMM/AMBER coordinate file
lammps / lammps-data - LAMMPS data file
Example:
from warp_md.pack import run, export
result = run(config)
# Export to PDB with box info
export(result, fmt="pdb", path="system.pdb", add_box_sides=True)
# Export to GROMACS format
export(result, fmt="gro", path="system.gro")
# Export with coordinate scaling
export(result, fmt="xyz", path="system.xyz", scale=0.1) # nm instead of Angstrom
run_inp
Run packing from Packmol .inp file.
def run_inp(path: str) -> PackResult:
"""Run packing from Packmol-format input file.
Args:
path: Path to .inp file
Returns:
PackResult containing packed system
"""
Example:
from warp_md.pack import run_inp, export
# Run from existing Packmol input
result = run_inp("system.inp")
export(result, fmt="pdb", path="output.pdb")
parse_inp
Parse Packmol .inp file to Python dict.
def parse_inp(path: str) -> Dict[str, Any]:
"""Parse Packmol input file to configuration dict.
Args:
path: Path to .inp file
Returns:
Dictionary representation of configuration
"""
Example:
from warp_md.pack import parse_inp, PackConfig, run
# Parse and modify configuration
config_dict = parse_inp("template.inp")
config_dict["seed"] = 999
config_dict["min_distance"] = 2.5
# Create config and run
config = PackConfig.from_dict(config_dict)
result = run(config)
Complete Example
from warp_md.pack import (
PackConfig, Structure, Box, Constraint,
run, export, water_pdb
)
# Get bundled water model
water_path = water_pdb("tip3p")
# Define membrane in center
membrane = Structure(
path="membrane.pdb",
count=1,
fixed=True,
center=True
)
# Pack water above and below membrane
water_above = Structure(
path=water_path,
count=2000,
constraints=[
Constraint(
mode="over",
shape="plane",
point=(0.0, 0.0, 5.0),
normal=(0.0, 0.0, 1.0)
)
]
)
water_below = Structure(
path=water_path,
count=2000,
constraints=[
Constraint(
mode="below",
shape="plane",
point=(0.0, 0.0, -5.0),
normal=(0.0, 0.0, 1.0)
)
]
)
# Configure and run
config = PackConfig(
structures=[membrane, water_above, water_below],
box=Box(size=(80.0, 80.0, 100.0)),
min_distance=2.0,
seed=12345,
pbc=True
)
result = run(config)
# Export with box info for MD
export(
result,
fmt="pdb",
path="membrane_system.pdb",
add_box_sides=True,
write_conect=True
)
print(f"Packed system: {len(result.coords)} atoms")
print(f"Box: {result.box}")
Water Models
Bundled water models are available:
from warp_md.pack import water_pdb, available_water_models
# List available models
print(available_water_models()) # ['tip3p', 'tip4p', 'spce', ...]
# Get path to water model
tip3p = water_pdb("tip3p")
spce = water_pdb("spce")
Error Handling
from warp_md.pack import PackConfig, ValidationError
try:
config = PackConfig(
structures=[], # Empty - invalid!
box=Box(size=(10.0, 10.0, 10.0))
)
config.validate()
except ValidationError as e:
print(f"Invalid configuration: {e}")
See Also