Before you can simulate anything, you need atoms arranged in a box. warp-pack is a CPU-first packing engine that speaks Packmol’s language but runs in pure Rust.
warp-pack is a Packmol-compatible packing engine with JSON/YAML configs, bundled water templates, and restart file support.
Quick Start
CLI
Python API
Fluent Builder
# From JSON config
warp-pack --config pack.json --output packed.pdb --format pdb
# Packmol-style inputs also work
warp-pack --config packmol.inp
from warp_md.pack import Box, Structure, PackConfig
from warp_md.pack.runner import run
from warp_md.pack.export import export
cfg = PackConfig(
structures = [
Structure( "water.pdb" , count = 200 ),
Structure( "ethanol.pdb" , count = 20 ),
],
box = Box(( 40.0 , 40.0 , 40.0 )),
min_distance = 2.0 ,
add_box_sides = True ,
)
result = run(cfg)
export(result, "pdb" , "packed.pdb" )
from warp_md.pack import PackConfigBuilder, water_pdb
from warp_md.pack.runner import run
from warp_md.pack.export import export
cfg = (
PackConfigBuilder()
.box( 40.0 , 40.0 , 40.0 )
.add( "protein.pdb" , count = 1 )
.fixed()
.done()
.add(water_pdb( "tip3p" ), count = 1000 )
.done()
.min_distance( 2.0 )
.add_box_sides( True )
.build()
)
result = run(cfg)
export(result, "pdb" , "packed.pdb" )
JSON Configuration
{
"box" : { "size" : [ 40.0 , 40.0 , 40.0 ], "shape" : "orthorhombic" },
"seed" : 0 ,
"min_distance" : 2.0 ,
"add_box_sides" : true ,
"writeout" : 30.0 ,
"writebad" : true ,
"restart_to" : "packed.restart" ,
"relax_steps" : 10 ,
"relax_step" : 0.5 ,
"output" : { "path" : "packed.pdb" , "format" : "pdb" },
"structures" : [
{
"path" : "water.pdb" ,
"count" : 200 ,
"rotate" : true ,
"constraints" : [
{
"mode" : "inside" ,
"shape" : "sphere" ,
"center" : [ 20.0 , 20.0 , 20.0 ],
"radius" : 18.0
}
]
},
{
"path" : "ethanol.mol2" ,
"count" : 20 ,
"filetype" : "mol2" ,
"changechains" : true
}
]
}
Bundled Water Templates
warp-pack ships with single-molecule water templates - no hunting for PDB files:
from warp_md.pack import water_pdb, Structure, PackConfig, Box
from warp_md.pack.runner import run
cfg = PackConfig(
structures = [Structure(water_pdb( "tip3p" ), count = 1000 )],
box = Box(( 40.0 , 40.0 , 40.0 )),
min_distance = 2.0 ,
)
result = run(cfg)
Bundled water_pdb(...) templates are single-molecule PDBs. Perfect for packing, not for direct simulation.
Available models:
from warp_md.pack import available_water_models
print (available_water_models()) # ['tip3p', 'tip4p', 'spc', 'spce', ...]
Restart Files
Resume packing or reuse placements with Packmol-style restart files:
{
"restart_from" : "all.restart" ,
"restart_to" : "all.out.restart" ,
"structures" : [
{
"path" : "water.pdb" ,
"count" : 200 ,
"restart_from" : "water.restart"
}
]
}
Format : One line per molecule with six floats: x y z beta gamma theta
Input Formats
pdb
xyz
mol2
pdbx / cif / mmcif
gro
lammps / lammps-data / lmp
crd
tinker / txyz
amber / inpcrd / rst / rst7
Output Formats
pdb (CONECT, TER, CRYST1)
xyz
pdbx / cif / mmcif
gro
lammps / lammps-data / lmp
mol2
crd
Configuration Reference
Option What It Does boxBox dimensions and shape seedRandom seed for reproducibility min_distanceHard minimum distance between atoms writeoutWrite periodic snapshots (seconds) writebadWrite partial structure on failure restart_from / restart_toPackmol restart files relax_steps / relax_stepPost-pack overlap relaxation add_box_sidesAdd box dimensions to outputs pbc_min / pbc_maxExplicit PBC bounds
Option What It Does pathPath to structure file countNumber of copies to place rotateAllow random rotation filetypeOverride file type detection constraintsPlacement constraints radius / fscalePer-atom radius defaults changechainsAssign unique chain IDs rot_boundsConstrain Euler rotation ranges fixed_eulersFix orientation (with positions)
// Inside a sphere
{ "mode" : "inside" , "shape" : "sphere" , "center" : [ 20 , 20 , 20 ], "radius" : 18 }
// Outside a box
{ "mode" : "outside" , "shape" : "box" , "min" : [ 0 , 0 , 0 ], "max" : [ 10 , 10 , 10 ] }
// Fixed position
{ "mode" : "fixed" , "position" : [ 20 , 20 , 20 ] }
// Inside cylinder
{ "mode" : "inside" , "shape" : "cylinder" , "base" : [ 0 , 0 , 0 ], "axis" : [ 0 , 0 , 1 ], "radius" : 10 , "height" : 20 }
// Inside ellipsoid
{ "mode" : "inside" , "shape" : "ellipsoid" , "center" : [ 20 , 20 , 20 ], "radii" : [ 10 , 10 , 15 ] }
Example: Solvated Protein
from warp_md.pack import Box, Structure, PackConfig, water_pdb
from warp_md.pack.runner import run
from warp_md.pack.export import export
cfg = PackConfig(
structures = [
# Protein at center (fixed)
Structure( "protein.pdb" , count = 1 , constraints = [
{ "mode" : "fixed" , "position" : [ 25.0 , 25.0 , 25.0 ]}
]),
# Water molecules around protein
Structure(water_pdb( "tip3p" ), count = 5000 , constraints = [
{ "mode" : "outside" , "shape" : "sphere" , "center" : [ 25 , 25 , 25 ], "radius" : 15 }
]),
],
box = Box(( 50.0 , 50.0 , 50.0 )),
min_distance = 2.5 ,
add_box_sides = True ,
)
result = run(cfg)
export(result, "pdb" , "solvated_protein.pdb" )
print ( f "Packed { result.total_atoms } atoms in { result.total_molecules } molecules" )
Fluent Builder API
Chainable, readable packing configurations:
from warp_md.pack import PackConfigBuilder, water_pdb
from warp_md.pack.runner import run
from warp_md.pack.export import export
cfg = (
PackConfigBuilder()
.box( 50.0 , 50.0 , 50.0 )
.seed( 42 )
.min_distance( 2.5 )
.add( "protein.pdb" , count = 1 )
.fixed()
.done()
.add(water_pdb( "tip3p" ), count = 5000 )
.outside_sphere([ 25 , 25 , 25 ], radius = 15 )
.done()
.add_box_sides( True )
.build()
)
result = run(cfg)
export(result, "pdb" , "solvated.pdb" )
Integration with Peptide Builder
Pack a peptide structure generated by warp-pep:
import subprocess
from warp_md.pack import Box, Structure, PackConfig, water_pdb
from warp_md.pack.runner import run
from warp_md.pack.export import export
# Step 1: Build peptide
subprocess.run([
"warp-pep" , "build" ,
"-s" , "ACDEFGHIKLMNPQRSTVWY" ,
"--preset" , "alpha-helix" ,
"--oxt" ,
"-o" , "peptide.pdb"
], check = True )
# Step 2: Pack with water
cfg = PackConfig(
structures = [
Structure( "peptide.pdb" , count = 1 ),
Structure(water_pdb( "tip3p" ), count = 1000 ),
],
box = Box(( 40.0 , 40.0 , 40.0 )),
min_distance = 2.0 ,
)
result = run(cfg)
export(result, "pdb" , "solvated.pdb" )
See Peptide Builder Guide for full peptide construction workflows.
Streaming Progress
Real-time progress tracking for agent integration:
warp-pack --config pack.json --stream
Emits NDJSON events to stderr:
{ "event" : "pack_started" , "total_molecules" : 150 , "box_size" :[ 50 , 50 , 50 ]}
{ "event" : "molecule_placed" , "molecule_index" : 10 , "total_molecules" : 150 , "progress_pct" : 6.7 }
{ "event" : "gencan_iteration" , "iteration" : 100 , "obj_value" : 2.1e-3 , "progress_pct" : 10.0 }
{ "event" : "pack_complete" , "total_atoms" : 4500 , "elapsed_ms" : 52000 }
See Streaming Progress API for full integration guide.
See Also