Typifier¶
Graph typification and force-field parameter assignment.
The contract¶
A typifier is MolGraph -> MolGraph: it takes a molecular graph and returns a
new one whose elements carry force-field types and parameters. Every typifier
runs the same flow — copy, match, write the annotations back — so typify() is
written once, on the base class, and match() is the single abstract step.
class Typifier[G: MolGraph](ABC):
def typify(self, graph: G) -> G: ... # concrete: copy, match, write back
@abstractmethod
def match(self, graph: G) -> Match: ... # the only thing that differs
The pipeline is generic over the graph. An Atomistic and a CoarseGrain are
both molrs graph leaves, and a concrete typifier specialises G to the one it
understands. Nothing in the contract mentions bonds, angles or dihedrals: that
decomposition belongs to a force field, not to typification.
Typifiers are named after the force field or the tool that decides the types.
There is no "typifier" that merely spends a type it was given — that is a
component, ForceFieldParams.
Quick reference¶
| Symbol | Summary | Preferred for |
|---|---|---|
Typifier |
The contract: one abstract match |
Writing your own |
OPLSAATypifier |
Full OPLS-AA typing pipeline re-exported from molrs.typifier |
OPLS-AA all-atom force fields |
MMFFTypifier |
Full MMFF94 typing pipeline re-exported from molrs.typifier |
MMFF all-atom force fields |
ClpTypifier |
CL&P ionic-liquid overlay: molrs SMARTS types + MolPy parameters | Ionic-liquid force fields |
AmberToolsTypifier |
GAFF atom types via antechamber; accumulates the force field it discovers | GAFF / AmberTools |
ForceFieldParams |
Not a typifier. Annotates pair and bonded terms from node types | A graph whose types are already known |
UFF lives in molrs (Rust / WASM UFFTypifier); MolPy re-exports it when the
published molrs minor exposes a Python binding.
Canonical example¶
import molpy as mp
from molpy.typifier import OPLSAATypifier
typifier = OPLSAATypifier(strict=True)
typed_mol = typifier.typify(mol) # returns a new Atomistic
frame = typed_mol.to_frame()
Key behavior¶
typify()returns a new graph — the original is not modified- A typifier never asks whether its graph is a fragment. Truncation is a fact
about provenance, not something readable off a graph's valences: a radical is a
perfectly good molecule. The party that cut the graph completes it — see
RegionTypes.of, which caps every region it types because every region is a cut - A term the force field does not parameterise is left undecided, never
stamped with
None - SMARTS matching is implemented in molrs; MolPy no longer carries a matcher
Writing a typifier¶
Implement match and stop. It returns the annotations each node and each link
should receive, positional against graph.nodes and graph.links.bucket(cls).
from molpy.typifier import ForceFieldParams, Match, Typifier
class MyTypifier(Typifier[mp.Atomistic]):
def __init__(self, forcefield):
self._params = ForceFieldParams(forcefield)
def match(self, graph):
node_types = [{"type": decide(atom)} for atom in graph.atoms]
return self._params.match(graph, node_types)
ForceFieldParams is the tail every force-field typifier ends with. It is also
the one place in MolPy that knows a Bond is parameterised by a BondType —
arity cannot decide that, since a dihedral and an improper both span four atoms.
Related¶
Full API¶
Contract¶
base ¶
What a typifier is: MolGraph -> MolGraph.
One pipeline, one hook. Every typifier copies the graph, matches it, and writes
the annotations back — and the only step that differs between an OPLS typifier, an
antechamber typifier and a coarse-grained typifier is the match. So
:meth:Typifier.typify is concrete and shared, and :meth:Typifier.match is the
single abstract method.
A typifier does not ask whether the graph it was handed is a fragment. Whether
a graph was cut out of a larger one is a fact about its provenance, not something
readable off its valences: a radical is a perfectly good molecule, and a
connectivity graph with no bond orders looks under-coordinated everywhere. Guessing
it would be guessing an identity. The party that cut the graph knows, and it is
the one that completes it — see
:meth:~molpy.typifier.region.RegionTypes.of, which caps every region it types
because every region is, by construction, a cut.
The pipeline is generic over the graph: an :class:~molpy.core.atomistic.Atomistic
and a :class:~molpy.core.cg.CoarseGrain are both molrs.Graph leaves, and a
concrete typifier specialises G to the one it types. Nothing here knows what
a bond, an angle or a dihedral is — that is a fact about a force field, and it
lives in :mod:molpy.typifier.forcefield.
Typifiers are named after the force field or the tool that decides the types:
:class:~molpy.typifier.clp.ClpTypifier,
:class:~molpy.typifier.ambertools.AmberToolsTypifier, OPLSAATypifier,
MMFFTypifier. "Assign parameters to a graph whose types are already known" is
not a typifier — it is the second half of one, and it is
:class:~molpy.typifier.forcefield.ForceFieldParams.
Match
dataclass
¶
The annotations matching a graph produced, ready to be written back.
nodes is positional against graph.nodes; links maps each link
class to a tuple positional against graph.links.bucket(cls). A match taken
from a valence-completed graph may be written onto the graph it completed:
the completion keeps the original elements first and appends the caps, so the
write is a prefix copy and the caps fall off the end.
An empty mapping in either sequence means "this element got nothing", which
is how an unparameterised term stays untyped instead of being stamped with
None.
write_onto ¶
Write this match onto graph, whose elements are a prefix of the
matched graph's.
Raises:
| Type | Description |
|---|---|
ValueError
|
if the match is shorter than the graph it is written onto — the two came from different graphs, and a silent truncation would leave elements untyped for no stated reason. |
Typifier ¶
Bases: Typifier, ABC
Assign force-field types and parameters to a molecular graph.
Subclasses implement :meth:match and nothing else. Specialise G to the
graph kind the typifier understands.
match
abstractmethod
¶
Decide what every element of graph should be annotated with.
graph arrives valence-completed and is a private copy, so an
implementation may write intermediate results onto it — writing the node
types it just decided, for instance, so that the bonded terms can be
matched against them.
typify ¶
Return a new graph carrying types and parameters; graph is untouched.
graph is taken at face value: whatever it is, that is the molecule
being typed. A caller holding a fragment completes its valences first —
a matcher shown a raw slice sees radicals where the cut fell, and types
the interior against them.
Force-field parameters¶
forcefield ¶
Turn node types into force-field parameters.
:class:ForceFieldParams is not a typifier — it decides nothing about what
an atom is. It is the second half of every force-field typifier: given a graph
whose nodes already carry a type, it looks each pair and bonded term up in a
force field and annotates it. ClpTypifier and AmberToolsTypifier differ
only in how they obtain those node types; both hand the result to this class.
It is also the one place in molpy that knows a :class:~molpy.core.atomistic.Bond
is parameterised by a :class:~molpy.core.forcefield.BondType. That mapping
cannot be derived from arity — a dihedral and an improper both span four atoms —
so it is written down once, in :data:_FF_TYPE_OF. When a coarse-grained force
field grows a CGBondType, one line is added there and nothing else changes.
ForceFieldParams ¶
Annotate a graph's pair and bonded terms from its node types.
Not a :class:~molpy.typifier.base.Typifier: it never decides a node's type,
it only spends one. Use it as the tail of a typifier's match (via
:meth:match), or on its own when the node types are already on the graph
(via :meth:assign).
A kind the force field declares no types for is not parameterised by it, and
its terms are left alone — that is a fact about the force field, not a
failure. A term the force field should cover but does not is an error when
strict is on.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
forcefield
|
ForceField
|
The force field to look types and parameters up in. |
required |
strict
|
bool
|
Raise on a term this force field ought to parameterise but does not, rather than leaving it untyped. |
True
|
assign ¶
Return a copy of graph with its pair and bonded terms parameterised.
For a graph whose node types are already known — the output of an
AmberTools run, say, whose topology was then regenerated. Replaces the
old Atomistic.assign_bonded_types, which matched force-field type
names by splitting them on "-" (no wildcards, no classes, no overlay
layers) and left a term it could not match silently unlabelled.
match ¶
Annotate graph's nodes and links.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
graph
|
Any
|
The graph to annotate. It is written to: the node types are stamped on so the bonded terms can be matched against them. Callers pass the private valence-completed copy a typifier owns. |
required |
node_types
|
Sequence[Mapping[str, Annotation]] | None
|
Per-node annotations the caller's matcher decided
( |
None
|
Raises:
| Type | Description |
|---|---|
TypeError
|
if |
CL&P Typifier¶
clp ¶
CL&P ionic-liquid force-field typifier.
CL&P stays in molpy (OPLS-AA moved to molrs). It is an OPLS-AA overlay: the
built-in force field is oplsaa.xml with clp.xml layered on top (layer 1),
so CL&P atom types (imidazolium ring, alkyl chain, and the BF4/PF6/NTf2/FSI/dca
anions) override the OPLS base while OPLS remains the fallback.
Atom typing itself is SMARTS-based and that matcher is owned by molrs, so the
only thing this typifier's match does is ask molrs for the atom types and
hand them to :class:~molpy.typifier.forcefield.ForceFieldParams — exactly the
"SMARTS owned by molrs, CL&P parameters stay a molpy overlay" split.
ClpTypifier ¶
CL&P ionic-liquid typifier — molrs SMARTS atom typing + molpy parameters.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
forcefield
|
ForceField | None
|
The CL&P-over-OPLS overlay; the built-in one by default. |
None
|
strict
|
bool
|
Raise on an atom no SMARTS pattern matches, or a bonded term the force field does not parameterise. |
True
|
load_forcefield
staticmethod
¶
Load the built-in CL&P force field as an OPLS-AA overlay.
AmberTools Typifier¶
ambertools ¶
GAFF typifier backed by AmberTools.
Decoupled from :class:~molpy.builder.ambertools.AmberTools (the raw
antechamber/parmchk2/tleap wrapper): this is the typifier. Its match drives
antechamber over the graph, reads back the GAFF atom types, and hands them to
:class:~molpy.typifier.forcefield.ForceFieldParams like every other force-field
typifier does.
Types only, not charges. Atom types + bonded params are charge-method
independent, so the graph is typed with gas charges — no sqm/AM1-BCC
solve. Recomputing charges from a capped fragment would be both non-local and
biased (adding H to a cut ether-O makes antechamber see a hydroxyl); charge is
instead conserved by construction, by folding each cap's charge onto its site
atom on the template so a deleted atom carries exactly zero. This typifier
never writes a charge back.
Valence completion is not this class's business either: antechamber cannot
parameterise a sliced fragment, but whether a graph is a fragment is known to
whoever cut it. :meth:~molpy.typifier.region.RegionTypes.of completes every
region before typing it; a caller typing a whole molecule has nothing to complete.
AmberToolsTypifier ¶
Type a graph's atoms with GAFF via antechamber; accumulate its force field.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
amber
|
AmberTools
|
The antechamber/parmchk2/tleap wrapper. |
required |