Quickstart¶
A Rust packing job has three parts:
- Build one
Targetper molecule species. - Attach at least one spatial restraint to each mobile target, or use a packer-level global restraint.
- Run
Molpack::pack(&targets, max_loops).
One molecule type in a box¶
use molpack::{InsideBoxRestraint, Molpack, Target};
let water_positions = [
[0.0, 0.0, 0.0],
[0.96, 0.0, 0.0],
[-0.24, 0.93, 0.0],
];
let water_radii = [1.52, 1.20, 1.20];
let water = Target::from_coords(&water_positions, &water_radii, 100)
.with_name("water")
.with_restraint(InsideBoxRestraint::new(
[0.0, 0.0, 0.0],
[40.0, 40.0, 40.0],
[false, false, false],
));
let mut packer = Molpack::new()
.with_tolerance(2.0)
.with_seed(42);
let frame = packer.pack(&[water], 200)?;
let natoms = frame.get("atoms").and_then(|b| b.nrows()).unwrap_or(0);
println!("packed {natoms} atoms");
pack() returns a packed molrs::Frame. Use pack_with_report() if you also
need convergence fields:
let mut packer = Molpack::new().with_seed(42);
let result = packer.pack_with_report(&targets, 200)?;
println!("converged={} fdist={} frest={}", result.converged, result.fdist, result.frest);
Builder defaults¶
Every tuning knob except max_loops has a Packmol-compatible default. Set a
builder value only when you need to change the default:
let packer = Molpack::new()
.with_tolerance(2.0)
.with_precision(0.01)
.with_inner_iterations(20)
.with_seed(42);
max_loops is positional because the right iteration budget depends on system
size and packing difficulty.
Targets are snapshots¶
Target is a builder value. pack() snapshots the target slice at call time;
mutating or rebuilding a target after that does not affect an already running
pack.