Skip to content

molforge.freeenergy

freeenergy

Binding free energy: result types, ranking, and engine base.

An endpoint binding free energy method estimates the free energy of association ΔG_bind for a receptor–ligand complex from an ensemble of structures (typically an MD trajectory), without the alchemical machinery of FEP/TI. The workhorse is MM/GBSA (and its Poisson– Boltzmann sibling MM/PBSA): molecular-mechanics interaction energy plus an implicit-solvent correction, averaged over frames.

molforge treats these as post-processors over a :class:molforge.md.Trajectory: the MD layer produces the ensemble, this layer consumes it and returns a :class:FreeEnergyResult. Concrete engines that invoke MMPBSA.py / gmx_MMPBSA live under :mod:molforge.wrappers.freeenergy; this module holds the shared types and the :class:MMGBSAEngine base they implement.

A word on what these numbers are worth. Endpoint methods are notoriously poor at absolute affinities — the implicit-solvent term is systematically biased and the configurational entropy is usually dropped — but the rank order across a congeneric series is often useful. The types here lean into that: every result carries an uncertainty, entropy is explicitly None when it wasn't computed (rather than silently zero), and :class:FreeEnergyRanking exposes pairwise ΔΔG with propagated error rather than a bare ordering, so ties within the error bars stay visible.

FreeEnergyComponents dataclass

FreeEnergyComponents(
    vdw: float,
    electrostatic: float,
    polar_solvation: float,
    nonpolar_solvation: float,
    entropy: float | None = None,
)

Per-term decomposition of a binding free energy, in kcal/mol.

The four energetic terms are the standard MM/PB(GB)SA breakdown; each is a difference (complex − receptor − ligand). entropy is the configurational entropy contribution −TΔS, carried separately because it comes from a distinct calculation (normal-mode or quasi-harmonic) that single-trajectory runs usually skip.

Attributes:

Name Type Description
vdw float

Van der Waals interaction energy.

electrostatic float

Electrostatic (Coulomb) interaction energy.

polar_solvation float

Polar solvation free energy (GB or PB term).

nonpolar_solvation float

Nonpolar / cavity + dispersion solvation term.

entropy float | None

The −TΔS contribution, or None when entropy was not computed. None is deliberately distinct from 0.0: a dropped entropy term is unknown, not zero.

enthalpy property

enthalpy: float

Interaction enthalpy: the sum of the four energetic terms.

This is the ΔH part of ΔG = ΔH − TΔS. When entropy is None, this equals the reported binding free energy (endpoint runs without an entropy calculation report ΔH as ΔG).

FreeEnergyResult dataclass

FreeEnergyResult(
    delta_g: float,
    uncertainty: float,
    method: str,
    components: FreeEnergyComponents | None = None,
    convergence: NDArray[float64] | None = None,
    provenance: Provenance | None = None,
    metadata: dict[str, object] = dict(),
    decomposition: Decomposition | None = None,
)

A binding free energy estimate with its uncertainty.

Attributes:

Name Type Description
delta_g float

Binding free energy ΔG_bind in kcal/mol. Lower (more negative) means tighter binding.

uncertainty float

Standard error of delta_g in kcal/mol, from the spread across frames or blocks. A ΔG without this is close to meaningless, so it is required.

method str

Method label, e.g. "MM/GBSA" or "MM/PBSA".

components FreeEnergyComponents | None

Per-term :class:FreeEnergyComponents, or None if the engine did not report a breakdown.

convergence NDArray[float64] | None

Optional (n_frames,) running estimate of delta_g as frames accumulate — a flat tail indicates a converged average. None when not tracked.

provenance Provenance | None

Optional :class:molforge.core.Provenance recording the engine, parameters and inputs that produced this result.

metadata dict[str, object]

Engine-specific extras (per-term std devs, frame count, solvent model, walltime, ...).

decomposition Decomposition | None

Optional per-residue :class:Decomposition from an idecomp run — which residues drive the affinity. None when decomposition was not requested.

DeltaDeltaG dataclass

DeltaDeltaG(
    reference: str,
    other: str,
    value: float,
    uncertainty: float,
    tighter: str,
)

A relative binding free energy between two ligands, with error.

Attributes:

Name Type Description
reference str

Label of the reference ligand.

other str

Label of the other ligand.

value float

ΔΔG = ΔG(other) − ΔG(reference) in kcal/mol. Negative means other binds more tightly than reference.

uncertainty float

Propagated standard error, sqrt(σ_reference² + σ_other²) (the two estimates come from independent runs).

tighter str

Label of the tighter-binding ligand (the lower ΔG). On an exact tie this is reference; consult value and uncertainty to judge whether a difference is real.

FreeEnergyRanking

FreeEnergyRanking(results: Mapping[str, FreeEnergyResult])

An affinity ranking over labelled :class:FreeEnergyResult\ s.

Ranking — "which of these ligands binds tightest?" — is the tractable job for endpoint methods, so this is the headline output over a congeneric series. Results are ordered by delta_g ascending (tightest first). Comparisons are exposed as :class:DeltaDeltaG with propagated uncertainty rather than a bare rank, so a pair that is tied within error stays visibly tied. Deliberately absent: any significance verdict — the right test depends on assumptions (frame correlation, Gaussianity) molforge should not bake in.

Build a ranking.

Parameters:

Name Type Description Default
results Mapping[str, FreeEnergyResult]

Mapping from ligand label to its :class:FreeEnergyResult. Must be non-empty.

required

Raises:

Type Description
ValueError

If results is empty.

results property

results: dict[str, FreeEnergyResult]

A copy of the label → result mapping.

ranked property

ranked: list[tuple[str, FreeEnergyResult]]

(label, result) pairs, tightest binder first.

best property

best: tuple[str, FreeEnergyResult]

The tightest-binding (label, result) pair.

delta_delta_g

delta_delta_g(reference: str, other: str) -> DeltaDeltaG

Relative binding free energy of other vs reference.

Parameters:

Name Type Description Default
reference str

Label of the reference ligand.

required
other str

Label of the ligand compared against the reference.

required

Returns:

Name Type Description
A DeltaDeltaG

class:DeltaDeltaG with the signed ΔΔG and its propagated

DeltaDeltaG

uncertainty.

Raises:

Type Description
KeyError

If either label is not in the ranking.

ResidueContribution dataclass

ResidueContribution(
    residue: str,
    total: float,
    uncertainty: float,
    internal: float,
    vdw: float,
    electrostatic: float,
    polar_solvation: float,
    nonpolar_solvation: float,
)

One residue's contribution to the binding free energy.

From a per-residue MM/PB(GB)SA decomposition (the DELTA section): total is the residue's net contribution to ΔG_bind, split into the same energy terms as the overall estimate. A large negative total marks a binding hotspot; a positive one, a residue that opposes binding.

Attributes:

Name Type Description
residue str

Residue label, e.g. "LEU 40".

total float

Net contribution to ΔG_bind in kcal/mol (the sum of the component terms below).

uncertainty float

Standard error of total across frames.

internal float

Internal term (bond/angle/dihedral; plus 1-4 for idecomp=1).

vdw float

van der Waals contribution.

electrostatic float

Electrostatic contribution.

polar_solvation float

Polar solvation contribution.

nonpolar_solvation float

Non-polar solvation contribution.

Decomposition

Decomposition(contributions: Sequence[ResidueContribution])

A per-residue decomposition of a binding free energy.

A mapping from residue label to its :class:ResidueContribution, preserving the order the residues were reported, with :meth:hotspots to surface the residues that drive (or oppose) binding. This is the endpoint-method answer to "where does the affinity come from?" once :class:FreeEnergyRanking has answered "which ligand?".

Build a decomposition.

Parameters:

Name Type Description Default
contributions Sequence[ResidueContribution]

Per-residue contributions, in report order.

required

Raises:

Type Description
ValueError

If two contributions share a residue label.

residues property

residues: list[ResidueContribution]

All contributions, in report order.

total property

total: float

Sum of every residue's contribution (the decomposed total).

hotspots

hotspots(
    n: int | None = None, *, favorable: bool = True
) -> list[ResidueContribution]

Residues ranked by contribution.

Parameters:

Name Type Description Default
n int | None

Return at most this many; None returns all.

None
favorable bool

If true (default), most binding-favorable first (most negative total); if false, most opposing first.

True

Returns:

Type Description
list[ResidueContribution]

The ranked contributions.

MMGBSAEngine

Bases: ABC

Abstract base for endpoint binding-free-energy engines.

Concrete engines (under :mod:molforge.wrappers.freeenergy) invoke an external tool — MMPBSA.py or gmx_MMPBSA — building its input from a trajectory, running it, and parsing the results into a :class:FreeEnergyResult. They handle their own topology/endpoint marshalling rather than exposing it to callers.

Despite the name, these engines do both MM/GBSA and MM/PBSA; the solvent model is a parameter (solvent_model) that defaults to generalized Born ("gb", i.e. MM/GBSA). Poisson–Boltzmann ("pb", MM/PBSA) is the slower, off-default alternative.

Attributes:

Name Type Description
name str

Human-readable engine name (set by subclasses).

run abstractmethod

run(
    trajectory: Trajectory,
    *,
    receptor: object,
    ligand: object,
    solvent_model: str = "gb",
    **kwargs: object,
) -> FreeEnergyResult

Estimate ΔG_bind from a trajectory.

Parameters:

Name Type Description Default
trajectory Trajectory

The ensemble to average over; its topology defines the complex.

required
receptor object

Selection identifying the receptor atoms within the complex (resolved against the topology, consistent with molforge's selection machinery).

required
ligand object

Selection identifying the ligand atoms.

required
solvent_model str

"gb" for MM/GBSA (default) or "pb" for MM/PBSA.

'gb'
**kwargs object

Engine-specific options.

{}

Returns:

Name Type Description
A FreeEnergyResult

class:FreeEnergyResult with ΔG, uncertainty, and — where

FreeEnergyResult

the tool reports them — a component breakdown.

MMGBSAEngineNotInstalledError

Bases: ImportError

Raised when an endpoint-free-energy engine's tool isn't installed.

The message points at the relevant install instructions (Amber's MMPBSA.py or gmx_MMPBSA) so users can fix it without grepping the docs.