Skip to content

Typifier

Graph typification and force-field parameter assignment.

The contract

A typifier is Atomistic -> Atomistic: it takes a molecular graph and returns a typed copy whose atoms and links carry force-field types and parameters. Every typifier runs the same flow — copy, match, write the annotations back and define the types — so typify() is written once, on the base class, and match() is the single step a typifier implements.

class Typifier:
    def typify(self, mol) -> Atomistic       # final: copy, match, write back
    def match(self, graph) -> Match          # the only thing that differs
    def library(self) -> ForceField          # optional: what the output declares
    def forcefield(self) -> ForceField       # the union of every type typify assigned

typify is final — a subclass that defines it raises TypeError at class creation — and it is the only writer of forcefield().

Typifiers are named after the force field or the tool that decides the types.

Quick reference

Symbol Summary Preferred for
Typifier The contract: implement match (and optionally library) Writing your own
Match What match returns: node and link annotations, styles, pair rows Writing your own
OPLSAATypifier Full OPLS-AA typing pipeline (native) OPLS-AA all-atom force fields
MMFF94Typifier / MMFF94STypifier Full MMFF94 / MMFF94s typing pipeline (native) MMFF all-atom force fields
ElementTypifier type labels from element symbols; defines no force field Writers that need labels on an untyped molecule
AtdTypifier AtdTypifier(parameter_set="gaff2"): antechamber's atom-type tables (gaff, gaff2, amber, bcc, …) evaluated natively — atom types only, no charges or parameters GAFF / GAFF2 or BCC atom types without running antechamber
AntechamberTypifier antechamber → parmchk2 → tleap for one complete molecule GAFF / GAFF2 small molecules and monomers
TLeapTypifier tleap alone over a finished graph that already carries AMBER types and charges (a graph with ports is refused) Re-parameterising a typed molecule

The native typifiers are identity re-exports of molrs.ff.typifier. The AmberTools typifiers shell out through molpy.wrapper; see Optional external tools. A GAFF polymer is not typed by joining typed monomers (each join folds the leaving group's charge onto its anchor): build it with mp.builder.polymer.AmberPolymerBuilder, which cuts one antechamber-typed oligomer with prepgen and joins the residues with tleap — see Builder and the AmberTools guide.

UFF typing exists in the native core (Rust) but has no Python binding yet; MolPy re-exports it once one is published.

Canonical example

import molpy as mp
from molpy.typifier import OPLSAATypifier

mol, _ = mp.Conformer(add_hydrogens=True, seed=42).generate(
    mp.io.read_smiles("CCO")
)

typifier = OPLSAATypifier(strict=True)
typed_mol = typifier.typify(mol)  # returns a new Atomistic
ff = typifier.forcefield()  # the parameters of the types just assigned
frame = typed_mol.to_frame()

Key behavior

  • typify() returns a new graph — the original is not modified
  • forcefield() is the union of what every typify call assigned, as an independent copy; a definition that contradicts one already held raises
  • A term the force field does not parameterise is left undecided, never stamped with None
  • SMARTS matching is native; MolPy carries no matcher of its own

Writing a typifier

Implement match and stop. It returns a Match: one annotation mapping per node, positional against graph.atoms, and per link class one mapping per row, positional against graph.links.exact_bucket(cls). A type annotation is (style, name, endpoints, params): it stamps name and every param, and defines the type name on endpoints (atom-type names, empty for an atom type). The name is never parsed — the endpoints are required. styles declares each style used; pairs adds (style, name, endpoints, params) pair rows.

class TIP3PTypifier(mp.typifier.Typifier):
    """TIP3P water: OW / HW atoms and one OW-HW bond type."""

    SITES = {"O": ("OW", 15.999, -0.834), "H": ("HW", 1.008, 0.417)}

    def library(self):
        return mp.ForceField("tip3p", units="real")  # the output declares real units

    def match(self, graph):
        nodes = []
        for atom in graph.atoms:
            name, mass, charge = self.SITES[atom["element"]]
            nodes.append({"type": ("full", name, (), {"mass": mass}), "charge": charge})
        bonds = [
            {"type": ("harmonic", "OW-HW", ["OW", "HW"], {"k": 450.0, "r0": 0.9572})}
            for _ in graph.links.exact_bucket(mp.Bond)
        ]
        return mp.typifier.Match(
            nodes,
            {mp.Bond: bonds},
            styles=[("atom", "full", {}), ("bond", "harmonic", {}), ("pair", "lj/cut", {})],
            pairs=[
                ("lj/cut", "OW", ["OW"], {"epsilon": 0.1521, "sigma": 3.1507}),
                ("lj/cut", "HW", ["HW"], {"epsilon": 0.0, "sigma": 0.0}),
            ],
        )


tip3p = TIP3PTypifier()
water = tip3p.typify(mp.io.read_smiles("[H]O[H]"))
assert [bond["type"] for bond in water.bonds] == ["OW-HW", "OW-HW"]
assert tip3p.forcefield().get_style("bond", "harmonic").get_type_by_name("OW-HW")["k"] == 450.0

Full API

Typifiers

typifier

Force-field typification.

The native typifiers are identity re-exports of :mod:molrs.ff.typifier (mp.typifier.OPLSAATypifier is molrs.ff.typifier.OPLSAATypifier), listed one by one. Typifier is the base every typifier extends: a subclass implements match and the base owns typify and the accumulated forcefield().

:class:AntechamberTypifier and :class:TLeapTypifier type through the AmberTools executables (:mod:molpy.wrapper).

AntechamberTypifier

AntechamberTypifier(
    *,
    atom_type="gaff2",
    charge_method="bcc",
    work_dir="amber_work",
    env=None,
    env_manager=None,
)

Bases: _AmberLibrary

GAFF / GAFF2 atom types, charges and parameters for a complete molecule.

match runs antechamber (-at atom_type -c charge_method, net charge from the atoms' formal charges), parmchk2 and tleap in a per-molecule directory under work_dir, and assigns the prmtop's types, charges and bonded terms. Ports are allowed; their leaving groups are real atoms.

A polymer chain is not typed here: joining typed monomers folds each leaving group's charge onto its anchor. Build it with :class:molpy.builder.polymer.AmberPolymerBuilder, which cuts one antechamber-typed oligomer with prepgen and sequences it with tleap.

Parameters:

Name Type Description Default
atom_type Literal['gaff', 'gaff2']

The antechamber atom-type set, also the parmchk2 -s set and the leaprc tleap sources.

'gaff2'
charge_method str

The antechamber -c charge method.

'bcc'
work_dir str | Path

Where the per-molecule directories are created.

'amber_work'
env str | Path | None

AmberTools environment (see :class:~molpy.wrapper.EnvSpec).

None
env_manager str | None

Its manager ("conda" / "venv").

None
match
match(graph)

Type graph with antechamber and assign tleap's prmtop.

Raises:

Type Description
ValueError

The prmtop disagrees with the graph.

RuntimeError

An AmberTools step failed.

AtdTypifier

AtdTypifier(*, parameter_set)

Bases: Typifier[Atomistic]

antechamber atom types — one rule engine over seven ATOMTYPE_*.DEF tables.

parameter_set is the antechamber -at flag and is required: seven tables exist, they disagree, and there is no default. An atom no rule matches comes back labelled "DU" — the table's own catch-all row, not a fallback.

ElementTypifier

ElementTypifier()

Bases: Typifier[Atomistic]

molrs.ff.typifier.ElementTypifier — type labels from element symbols alone, with no force field.

Atoms get type = element (e.g. "C"); bonds, angles and dihedrals get their endpoint elements joined with - in the byte-wise smaller orientation (bond O–H is "H-O"). :meth:forcefield stays empty. Exported from :mod:molrs.ff.typifier only.

Raises

ValueError From :meth:typify, when an atom has no string element or the molecule has impropers.

MMFF94STypifier

MMFF94STypifier()

Bases: Typifier[Atomistic]

MMFF94s (Halgren 1999) — the "static" set, for energy minimization.

Differs from MMFF94Typifier only on delocalised trivalent nitrogen (MMFF numeric types 10 NC=O / 40 NC=C): 11 out-of-plane rows and 42 torsion rows are re-parameterised so the nitrogen minimizes planar. typify bakes koop = +0.015 (type 10) / +0.030 (type 40) mdArad^-2 on those centres, where the improper kernel reads it as E_oop = 0.5 * 143.9325 * koop * chi**2 (chi in radians). Every atom type and every bond / angle / stretch-bend / vdW / charge parameter is shared with MMFF94.

MMFF94Typifier

MMFF94Typifier()

Bases: Typifier[Atomistic]

MMFF94 (Halgren 1996) atom types, charges and bonded parameters.

The variant is the class, never a flag. See MMFF94STypifier for the "static" parameter set.

typify labels the graph; PotentialCompiler(forcefield()).compile(frame) compiles it. There is no one-step build — MMFF walks the same route as every other force field.

Match

Match(nodes, links=None, *, styles=(), pairs=())

What a typifier's match assigns to one graph.

nodes is positional against graph.atoms; links maps a relation class (Bond, Angle, Dihedral, Improper) to rows positional against graph.links.exact_bucket(cls) — the kind's own rows, so an improper never shifts a dihedral position. An unknown kind raises TypeError. styles are (category, style, params) to declare, in order; pairs are (style, name, endpoints, params) pair rows.

TLeapTypifier

TLeapTypifier(
    *,
    leaprc="gaff2",
    forcefield=None,
    work_dir="amber_work",
    env=None,
    env_manager=None,
)

Bases: _AmberLibrary

Parameterise an already typed graph with tleap alone.

The graph's atoms must carry AMBER atom types and charges. match writes them as mol2, writes forcefield (the templates' parameters) as a frcmod, runs tleap and assigns the prmtop's bonded terms, so junction terms come from the leaprc. It never runs antechamber or parmchk2. Types and charges are left as they are; tleap changing one raises. A graph that still has ports is refused: joining those ports would fold the leaving-group charge onto the anchors. A polymer chain is built with :class:molpy.builder.polymer.AmberPolymerBuilder, whose prepgen step spreads that charge instead.

Parameters:

Name Type Description Default
leaprc Literal['gaff', 'gaff2']

The leaprc tleap sources (source leaprc.<leaprc>).

'gaff2'
forcefield ForceField | None

Parameters tleap loads on top of the leaprc, written as a frcmod; None loads none.

None
work_dir str | Path

Where the per-graph directories are created.

'amber_work'
env str | Path | None

AmberTools environment (see :class:~molpy.wrapper.EnvSpec).

None
env_manager str | None

Its manager ("conda" / "venv").

None
match
match(graph)

Run tleap over graph's own types and charges; assign its prmtop.

Raises:

Type Description
ValueError

An atom lacks a type or charge, tleap changed one, or the prmtop disagrees with the graph.

RuntimeError

tleap failed.

Typifier

Typifier(*args, **kwargs)

The base of every graph typifier: one match hook plus the output force field its typing accumulates.

A subclass implements match (and optionally library) and nothing else; defining typify on a subclass raises TypeError at class creation. The native classes extend this base and only construct.

forcefield
forcefield()

The accumulated output — exactly the definitions typify has assigned — returned as a copy.

Edits to the copy do not reach the typifier; typify is the only writer. Before the first typify it is the seeded empty output.

library
library()

The force field this typifier matches against, returned as a copy.

The output starts as its empty likeness (name, declared units and special_bonds). A Python subclass that does not override it raises NotImplementedError, and its output starts as an empty force field named after the class.

match
match(graph)

Match graph and return what it assigns.

match may write intermediate results (generated topology, perceived bond types) onto the graph it is given; typify always gives it a private copy. The base raises NotImplementedError; a native class runs its Rust matcher.

typify
typify(mol)

Do not override; the only writer of forcefield().

Copies mol, calls match on the copy, and writes the match onto the copy and the output. Returns the typed copy; mol is untouched. mol must be an Atomistic (anything else raises TypeError). Raises NotImplementedError without a match and ValueError when the match does not fit the graph or contradicts the output (which is then unchanged).

AmberTools typifiers

ambertools

AmberTools typifiers: GAFF / GAFF2 through the AmberTools executables.

Two :class:molrs.ff.typifier.Typifier subclasses drive the :mod:molpy.wrapper shells and read tleap's prmtop back:

  • :class:AntechamberTypifier types a complete molecule from scratch: antechamber (atom types and charges) → parmchk2 (missing parameters) → tleap.
  • :class:TLeapTypifier parameterises a finished graph whose atoms already carry AMBER types and charges, with tleap alone. A graph that still has ports is refused. A polymer is built with :class:molpy.builder.polymer.AmberPolymerBuilder: antechamber, parmchk2 and prepgen on one oligomer, then tleap sequence.

Both return the prmtop's assignment as a :class:~molrs.ff.typifier.Match; the molrs base owns typify and the accumulated forcefield().

AntechamberTypifier

AntechamberTypifier(
    *,
    atom_type="gaff2",
    charge_method="bcc",
    work_dir="amber_work",
    env=None,
    env_manager=None,
)

Bases: _AmberLibrary

GAFF / GAFF2 atom types, charges and parameters for a complete molecule.

match runs antechamber (-at atom_type -c charge_method, net charge from the atoms' formal charges), parmchk2 and tleap in a per-molecule directory under work_dir, and assigns the prmtop's types, charges and bonded terms. Ports are allowed; their leaving groups are real atoms.

A polymer chain is not typed here: joining typed monomers folds each leaving group's charge onto its anchor. Build it with :class:molpy.builder.polymer.AmberPolymerBuilder, which cuts one antechamber-typed oligomer with prepgen and sequences it with tleap.

Parameters:

Name Type Description Default
atom_type Literal['gaff', 'gaff2']

The antechamber atom-type set, also the parmchk2 -s set and the leaprc tleap sources.

'gaff2'
charge_method str

The antechamber -c charge method.

'bcc'
work_dir str | Path

Where the per-molecule directories are created.

'amber_work'
env str | Path | None

AmberTools environment (see :class:~molpy.wrapper.EnvSpec).

None
env_manager str | None

Its manager ("conda" / "venv").

None
match
match(graph)

Type graph with antechamber and assign tleap's prmtop.

Raises:

Type Description
ValueError

The prmtop disagrees with the graph.

RuntimeError

An AmberTools step failed.

TLeapTypifier

TLeapTypifier(
    *,
    leaprc="gaff2",
    forcefield=None,
    work_dir="amber_work",
    env=None,
    env_manager=None,
)

Bases: _AmberLibrary

Parameterise an already typed graph with tleap alone.

The graph's atoms must carry AMBER atom types and charges. match writes them as mol2, writes forcefield (the templates' parameters) as a frcmod, runs tleap and assigns the prmtop's bonded terms, so junction terms come from the leaprc. It never runs antechamber or parmchk2. Types and charges are left as they are; tleap changing one raises. A graph that still has ports is refused: joining those ports would fold the leaving-group charge onto the anchors. A polymer chain is built with :class:molpy.builder.polymer.AmberPolymerBuilder, whose prepgen step spreads that charge instead.

Parameters:

Name Type Description Default
leaprc Literal['gaff', 'gaff2']

The leaprc tleap sources (source leaprc.<leaprc>).

'gaff2'
forcefield ForceField | None

Parameters tleap loads on top of the leaprc, written as a frcmod; None loads none.

None
work_dir str | Path

Where the per-graph directories are created.

'amber_work'
env str | Path | None

AmberTools environment (see :class:~molpy.wrapper.EnvSpec).

None
env_manager str | None

Its manager ("conda" / "venv").

None
match
match(graph)

Run tleap over graph's own types and charges; assign its prmtop.

Raises:

Type Description
ValueError

An atom lacks a type or charge, tleap changed one, or the prmtop disagrees with the graph.

RuntimeError

tleap failed.