Moltemplate CLI¶
MolPy ships a native moltemplate engine. The molpy moltemplate subcommand parses .lt scripts and emits ready-to-run inputs for LAMMPS, OpenMM, GROMACS — or MolPy's canonical XML force-field format, or a self-contained MolPy Python script.
Quick start¶
# Summarise a script (atom types, molecule count, styles)
molpy moltemplate info water.lt
# Generate LAMMPS inputs (data + in.settings + in.init + starter in)
molpy moltemplate run water.lt --emit lammps --out-dir out/
# Generate every engine at once
molpy moltemplate run water.lt --emit all --out-dir out/
# FF-only: convert .lt force field to MolPy XML
molpy moltemplate convert gaff2.lt gaff2.xml
# .lt → MolPy Python script (inverse of moltemplate — hand-editable)
molpy moltemplate convert water.lt water.py
# MolPy system → .lt (ltemplify: bundle an Atomistic+ForceField back as .lt)
molpy moltemplate ltemplify water.lt water_regen.lt
# Dump parsed IR (debug)
molpy moltemplate parse water.lt --json ir.json
Subcommands¶
run — emit engine inputs¶
| Engine | Files produced (given --prefix system) |
|---|---|
lammps |
system.data, system.in.settings, system.in.init, system.in |
openmm |
system.xml, system.pdb, system.py |
gromacs |
system.gro, system.top, em.mdp, nvt.mdp |
xml |
system.xml, system.pdb (MolPy canonical) |
all |
every engine above |
--emit may be repeated: --emit lammps --emit openmm.
parse — debug the IR¶
Without --json, prints a one-line-per-kind statement summary.
info — one-liner summary¶
Prints atom-type/atom/bond/angle/dihedral counts after all new instances are expanded.
convert — transform .lt into XML or Python¶
Output format is inferred from the destination extension:
| Extension | Output |
|---|---|
.xml |
MolPy canonical XML force field (FF-only). |
.py |
Self-contained MolPy Python script with build_forcefield(), one build_<ClassName>() per moltemplate class, and a top-level build_system(). The emitted script has no runtime dependency on the original .lt file — users can edit freely. |
ltemplify — .lt / .data → .lt¶
molpy moltemplate ltemplify SRC.lt DST.lt [--class-name NAME]
molpy moltemplate ltemplify SRC.data DST.lt --ff SRC.in.settings
Serialise an Atomistic + ForceField back into a moltemplate template. The first form re-emits a .lt after parsing; the second converts a LAMMPS data file plus a coefficients file.
Round-trip read_moltemplate_system → ltemplify is count-preserving on atoms / bonds / angles / dihedrals / impropers. It does not reconstruct the class hierarchy — everything is flattened into a single class.
Supported moltemplate features¶
Tested against real examples in the
moltemplate/examples
directory. Coverage is intentionally incremental — the table below tracks
what has been validated on upstream fixtures versus what silently degrades.
| Feature | Status |
|---|---|
ClassName { ... }, nested classes |
✔ |
inherits Parent1, Parent2 |
✔ |
import "file.lt" (recursive) |
✔ |
write("..."), write_once("...") |
✔ |
write('...') single-quoted section names |
✔ |
Section names containing (...) |
✔ |
Data Masses, Data Charges, In Charges |
✔ |
In Settings coeff lines (pair/bond/angle/…) |
✔ |
Data Atoms, Data Bonds, Data Angles |
✔ |
Data Dihedrals, Data Impropers |
✔ |
inst = new Cls |
✔ |
.move(x,y,z), .rot(θ,ax,ay,az), .scale(s) |
✔ |
new Cls [N].move(dx,dy,dz) 1-D array |
✔ |
new Cls [N].move(...) [M].move(...) [K].move(...) (3-D array) |
✔ |
.rotvv(v1,v2) |
partial (parsed but unused) |
new random([Cls1, Cls2], [w1, w2] [, seed]) |
✔ |
$atom:submol/atom scoped references |
✔ |
Data Bond List (no @bond:T column) |
✔ |
Bonds/Angles/Dihedrals/Impropers By Type wildcards |
✔ (rule matching applied after auto-topology) |
replace{ @atom:A @atom:B } |
✔ (decoration applied during Data Atoms) |
create_var, delete_var, category |
✘ (silently ignored) |
Impropers as first-class Improper link |
✔ |
| oplsaa.lt (full ~10k line file) | parses; FF load OK; bond/angle/dihedral types resolved via By-Type wildcards |
Honest caveat¶
tip3p_2004_oplsaa.lt + oplsaa2024.lt (the real moltemplate OPLS file,
~10k lines) parse end-to-end and produce a ForceField with thousands of
AtomType entries. replace{ @atom:A @atom:B } decoration is applied so
atom types carry their bond / angle / dihedral / improper partners, and
the Bonds/Angles/Dihedrals/Impropers By Type wildcard rules are
consulted after auto-topology to fill in the concrete type name on each
bond/angle/dihedral/improper. Edge cases where the wildcard does not
match still fall back to the synthetic placeholder name generated from
In Settings coeffs, so downstream emitters never crash.
Verifying your own .lt file¶
molpy moltemplate parse my_system.lt # IR summary
molpy moltemplate info my_system.lt # atom/bond counts after expansion
molpy moltemplate run my_system.lt --emit lammps --out-dir out/
Python API¶
Everything the CLI does is available programmatically.
from molpy.io.forcefield.moltemplate import read_moltemplate_system
from molpy.io.emit import emit, emit_all
from molpy.parser.moltemplate import (
emit_python, # .lt → .py
ltemplify, # (atomistic, ff) → .lt string
parse_file, # .lt → IR Document
write_moltemplate, # (atomistic, ff) → .lt file
)
atomistic, ff = read_moltemplate_system("water.lt")
# Single engine
emit("lammps", atomistic, ff, "out/", prefix="w")
# All engines
emit_all(atomistic, ff, "out/", prefix="w")
# .lt → .py
emit_python(parse_file("water.lt"), "water.py")
# ltemplify: back to a .lt template
write_moltemplate(atomistic, ff, "water_regen.lt", class_name="Water")
Python hooks: moltemplate's own include "foo.py" mechanism is not
supported directly. Instead, use molpy moltemplate convert foo.lt foo.py
and edit the emitted script — the output is plain MolPy so every MolPy
Python API (builders, reacter, compute, wrapper) becomes available at the
same composition point you used to attach Python logic in moltemplate.
Core editing primitives on Atomistic / CoarseGrain / ForceField (see core.atomistic, core.cg, core.forcefield) include:
del_atom,del_bond,del_angle,del_dihedralrename_type(old, new, *, kind=Atom)set_property(selector, key, value, *, kind=Atom)select(predicate) -> AtomisticForceField.rename_type / remove_type / remove_style
These are kernel-level operations usable outside the moltemplate pipeline.