Skip to content

Quickstart

Pack 100 water molecules into a 40 Å cube. This walkthrough uses the Python package — the shortest path from a loaded frame to a packed result. The same model is available as a CLI script or the Rust builder.

1. Install

pip install molcrafts-molpack

This installs the packing engine and pulls in molcrafts-molrs for the frame type plus PDB/XYZ I/O.

2. Load or build a template

import molrs

frame = molrs.io.read_pdb("water.pdb")
import molrs
import numpy as np

frame = molrs.Frame.from_dict({
    "blocks": {
        "atoms": {
            "x": np.array([0.00, 0.96, -0.24]),
            "y": np.array([0.00, 0.00, 0.93]),
            "z": np.zeros(3),
            "element": ["O", "H", "H"],
        }
    },
    "meta": {},
})

3. Define the target

A Target is one molecule species plus the number of copies to place. Every mobile target needs a spatial restraint:

from molpack import InsideBoxRestraint, Target

water = (
    Target(frame, count=100)
    .with_name("water")
    .with_restraint(InsideBoxRestraint([0.0, 0.0, 0.0], [40.0, 40.0, 40.0]))
)

Missing restraints

Without a spatial restraint (or a global PBC box), initial placement has to invent a huge free-space region and the run can become impractical.

4. Pack

from molpack import Molpack

result = (
    Molpack()
    .with_tolerance(2.0)
    .with_seed(42)
    .pack_with_report([water], max_loops=200)
)

print(result.converged, result.natoms, result.fdist, result.frest)
packed = result.frame
Field Meaning
converged Both objectives fell below the packer precision threshold
fdist Pair-distance (overlap) violations
frest Restraint violations
frame Topology-complete packed molrs.Frame

For a frame-only return, use Molpack().pack([water], max_loops=200).

5. Save

import molrs

molrs.io.write_pdb("water_box.pdb", packed)
# or: molrs.io.write_xyz("water_box.xyz", packed)

Where next