molforge.wrappers.freeenergy¶
freeenergy ¶
Concrete endpoint free-energy engines and result parsers.
Wrappers for the external MM/PB(GB)SA tools — Amber's MMPBSA.py and
gmx_MMPBSA — that implement :class:molforge.freeenergy.MMGBSAEngine.
Currently exposes the Amber output parser; the engines that build inputs
and invoke the tools are layered on top.
AmberMMGBSA ¶
AmberMMGBSA(
*,
mmpbsa_executable: str = "MMPBSA.py",
antemmpbsa_executable: str = "ante-MMPBSA.py",
igb: int = 5,
strip_mask: str | None = ":WAT,HOH,Na+,Cl-,K+",
verbose: bool = False,
)
Bases: MMGBSAEngine
Endpoint free energy via Amber's MMPBSA.py.
Post-processes an MD trajectory: splits the complex topology into
complex/receptor/ligand with ante-MMPBSA.py (using masks derived
from the receptor / ligand selections), runs MMPBSA.py,
and parses its FINAL_RESULTS_MMPBSA.dat.
This engine orchestrates the tools; it does not parameterize a
system. It needs an Amber topology (prmtop) and a matching
trajectory file on disk — either passed explicitly or carried by a
trajectory produced by :class:molforge.wrappers.md.AMBER (whose
metadata records the run directory holding system.prmtop and
prod.nc). Anything else raises a clear error rather than trying
to build a topology.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
mmpbsa_executable
|
str
|
|
'MMPBSA.py'
|
antemmpbsa_executable
|
str
|
|
'ante-MMPBSA.py'
|
igb
|
int
|
Generalized Born model index passed to MM/GBSA runs. |
5
|
strip_mask
|
str | None
|
Amber mask of atoms stripped from the complex before
splitting (solvent/ions), or |
':WAT,HOH,Na+,Cl-,K+'
|
verbose
|
bool
|
If true, stream tool stdout/stderr instead of capturing. |
False
|
run ¶
run(
trajectory: Trajectory,
*,
receptor: Selection,
ligand: Selection,
solvent_model: str = "gb",
prmtop: str | PathLike[str] | None = None,
trajectory_file: str | PathLike[str] | None = None,
start_frame: int = 1,
end_frame: int | None = None,
interval: int = 1,
salt_conc: float = 0.0,
idecomp: int = 0,
print_res: str = "within 6",
**_kwargs: object,
) -> FreeEnergyResult
Estimate ΔG_bind from trajectory with MM/GBSA or MM/PBSA.
Results are cached on the run's :class:~molforge.core.Provenance;
an identical repeat returns the cached result without invoking the
tools.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
trajectory
|
Trajectory
|
The ensemble to average over; its topology defines the complex and its metadata may locate the Amber inputs. |
required |
receptor
|
Selection
|
Selection identifying the receptor atoms. |
required |
ligand
|
Selection
|
Selection identifying the ligand atoms. |
required |
solvent_model
|
str
|
|
'gb'
|
prmtop
|
str | PathLike[str] | None
|
Explicit Amber complex topology; overrides metadata. |
None
|
trajectory_file
|
str | PathLike[str] | None
|
Explicit trajectory file; overrides metadata. |
None
|
start_frame
|
int
|
First frame to analyze (1-based). |
1
|
end_frame
|
int | None
|
Last frame to analyze; defaults to the trajectory length. |
None
|
interval
|
int
|
Stride between analyzed frames. |
1
|
salt_conc
|
float
|
Salt concentration (mol/L). |
0.0
|
idecomp
|
int
|
Per-residue decomposition scheme ( |
0
|
print_res
|
str
|
Which residues to decompose ( |
'within 6'
|
Returns:
| Name | Type | Description |
|---|---|---|
A |
FreeEnergyResult
|
class: |
FreeEnergyResult
|
provenance attached (and a decomposition if |
Raises:
| Type | Description |
|---|---|
ValueError
|
If a selection is empty/splits a residue, or the Amber topology / trajectory file can't be located. |
MMGBSAEngineNotInstalledError
|
If the tools aren't installed. |
GromacsMMGBSA ¶
Bases: MMGBSAEngine
Endpoint free energy via gmx_MMPBSA (the GROMACS sibling).
Post-processes a GROMACS MD trajectory: resolves the receptor /
ligand selections to .ndx index groups, runs gmx_MMPBSA,
and parses its FINAL_RESULTS_MMPBSA.dat. Like the Amber engine it
orchestrates the tool rather than parameterizing a system: it needs
a GROMACS structure (.tpr) and trajectory (.xtc/.trr) on
disk — passed explicitly or carried by a trajectory produced by
:class:molforge.wrappers.md.GROMACS (whose metadata records the run
directory holding md.tpr, md.xtc and topol.top). A
topology (.top) is used with -cp when available. Results are
cached on the run's :class:~molforge.core.Provenance.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
executable
|
str
|
|
'gmx_MMPBSA'
|
igb
|
int
|
Generalized Born model index passed to MM/GBSA runs. |
5
|
verbose
|
bool
|
If true, stream tool stdout/stderr instead of capturing. |
False
|
run ¶
run(
trajectory: Trajectory,
*,
receptor: Selection,
ligand: Selection,
solvent_model: str = "gb",
structure: str | PathLike[str] | None = None,
trajectory_file: str | PathLike[str] | None = None,
topology: str | PathLike[str] | None = None,
start_frame: int = 1,
end_frame: int | None = None,
interval: int = 1,
salt_conc: float = 0.0,
idecomp: int = 0,
print_res: str = "within 6",
**_kwargs: object,
) -> FreeEnergyResult
Estimate ΔG_bind from trajectory with gmx_MMPBSA.
An identical repeat returns the cached result without invoking the tool.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
trajectory
|
Trajectory
|
The ensemble to average over; its topology defines the atom numbering and its metadata may locate the GROMACS inputs. |
required |
receptor
|
Selection
|
Selection identifying the receptor atoms. |
required |
ligand
|
Selection
|
Selection identifying the ligand atoms. |
required |
solvent_model
|
str
|
|
'gb'
|
structure
|
str | PathLike[str] | None
|
Explicit GROMACS structure ( |
None
|
trajectory_file
|
str | PathLike[str] | None
|
Explicit trajectory ( |
None
|
topology
|
str | PathLike[str] | None
|
Explicit GROMACS topology ( |
None
|
start_frame
|
int
|
First frame to analyze (1-based). |
1
|
end_frame
|
int | None
|
Last frame to analyze; defaults to the length. |
None
|
interval
|
int
|
Stride between analyzed frames. |
1
|
salt_conc
|
float
|
Salt concentration (mol/L). |
0.0
|
idecomp
|
int
|
Per-residue decomposition scheme ( |
0
|
print_res
|
str
|
Which residues to decompose ( |
'within 6'
|
Returns:
| Name | Type | Description |
|---|---|---|
A |
FreeEnergyResult
|
class: |
FreeEnergyResult
|
provenance attached (and a decomposition if |
Raises:
| Type | Description |
|---|---|
ValueError
|
If a selection is empty, or the structure / trajectory can't be located. |
MMGBSAEngineNotInstalledError
|
If |
absolute_binding_free_energy ¶
absolute_binding_free_energy(
complex_leg: FreeEnergyResult,
solvent_leg: FreeEnergyResult,
*,
restraint_correction: FreeEnergyResult | float = 0.0,
method: str = "ABFE",
metadata: Mapping[str, object] | None = None,
) -> FreeEnergyResult
Close a double-decoupling cycle into an absolute binding ΔG.
Absolute binding free energy (ABFE) by double decoupling annihilates the ligand's interactions with its environment in two phases — restrained in the complex, and free in solvent — and adds a standard-state restraint correction. The thermodynamic cycle gives
ΔG_bind = ΔG_solvent − ΔG_complex + restraint_correction
where the two legs are decoupling free energies (coupled →
non-interacting): a strong binder is hard to decouple from the complex
(large positive ΔG_complex), so ΔG_solvent − ΔG_complex comes
out negative — favorable — as it should.
Unlike the relative cycle, this yields an absolute ΔG_bind, so the
result is a :class:FreeEnergyResult that ranks directly.
Convention notes:
- Pass the legs as decoupling free energies. If your λ schedule runs
the other way (coupling), negate them (or reverse the λ order before
:func:
from_alchemlyb). restraint_correctionis a signed contribution added as-is — supply it with the sign your protocol uses (e.g. a Boresch standard-state correction). It may be a float or a :class:FreeEnergyResult(whose uncertainty then propagates).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
complex_leg
|
FreeEnergyResult
|
ΔG of decoupling the (restrained) ligand in the complex. |
required |
solvent_leg
|
FreeEnergyResult
|
ΔG of decoupling the ligand in solvent. |
required |
restraint_correction
|
FreeEnergyResult | float
|
Signed standard-state / restraint term. |
0.0
|
method
|
str
|
Value for :attr: |
'ABFE'
|
metadata
|
Mapping[str, object] | None
|
Extra items merged into the result's metadata. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
A |
FreeEnergyResult
|
class: |
FreeEnergyResult
|
( |
|
FreeEnergyResult
|
in quadrature. |
from_alchemlyb ¶
from_alchemlyb(
estimator: Any,
*,
temperature: float | None = None,
energy_unit: str | None = None,
method: str | None = None,
metadata: Mapping[str, object] | None = None,
) -> FreeEnergyResult
Ingest a fitted alchemlyb estimator into a :class:FreeEnergyResult.
Reads estimator.delta_f_ / estimator.d_delta_f_ and, unless
overridden, labels the result with the estimator's class name
("MBAR", "BAR", "TI", …).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
estimator
|
Any
|
A fitted alchemlyb estimator (anything exposing
|
required |
temperature
|
float | None
|
See :func: |
None
|
energy_unit
|
str | None
|
See :func: |
None
|
method
|
str | None
|
Overrides the estimator-class-name default. |
None
|
metadata
|
Mapping[str, object] | None
|
Extra items merged into the result's metadata; the
estimator name is always recorded under |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
A |
FreeEnergyResult
|
class: |
Raises:
| Type | Description |
|---|---|
AttributeError
|
If |
ValueError
|
Propagated from :func: |
from_delta_f ¶
from_delta_f(
delta_f: Any,
d_delta_f: Any,
*,
temperature: float | None = None,
energy_unit: str | None = None,
method: str = "FEP",
metadata: Mapping[str, object] | None = None,
) -> FreeEnergyResult
Ingest alchemlyb delta_f_ / d_delta_f_ matrices.
Takes the full first-state → last-state transformation (the [0, -1]
corner) and its error, converting to kcal/mol.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
delta_f
|
Any
|
The estimator's |
required |
d_delta_f
|
Any
|
The matching |
required |
temperature
|
float | None
|
Temperature in K, needed only when the unit is kT and
the matrix doesn't carry a |
None
|
energy_unit
|
str | None
|
|
None
|
method
|
str
|
Value for :attr: |
'FEP'
|
metadata
|
Mapping[str, object] | None
|
Extra items merged into the result's metadata. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
A |
FreeEnergyResult
|
class: |
FreeEnergyResult
|
kcal/mol and |
|
FreeEnergyResult
|
a single number, not an MM/GBSA-style term breakdown. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If a matrix isn't 2-D, the unit is unknown, or a kT
matrix has no temperature (neither argument nor |
relative_binding_free_energy ¶
relative_binding_free_energy(
complex_leg: FreeEnergyResult,
solvent_leg: FreeEnergyResult,
*,
reference: str,
other: str,
) -> DeltaDeltaG
Close a relative-FEP thermodynamic cycle into a binding ΔΔG.
A relative FEP perturbation transforms one ligand into another
(reference → other) along two legs: bound to the receptor (the
complex leg) and free in solution (the solvent leg). The
thermodynamic cycle gives the relative binding free energy
ΔΔG_bind = ΔG_complex − ΔG_solvent
= ΔG_bind(other) − ΔG_bind(reference)
so a single perturbation's two ingested legs become the binding ΔΔG between the two ligands — the quantity relative FEP actually reports. A single leg's ΔG is not a binding affinity; only the cycle is.
Both legs must be the same perturbation direction (reference →
other) and in the same units (kcal/mol, as returned by
:func:from_alchemlyb / :func:from_delta_f).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
complex_leg
|
FreeEnergyResult
|
ΔG of the reference → other transformation in the complex. |
required |
solvent_leg
|
FreeEnergyResult
|
ΔG of the same transformation in solvent. |
required |
reference
|
str
|
Label of the reference ligand. |
required |
other
|
str
|
Label of the ligand it is perturbed into. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
A |
DeltaDeltaG
|
class: |
DeltaDeltaG
|
(negative means |
|
DeltaDeltaG
|
errors propagated in quadrature. Treat a difference within its |
|
DeltaDeltaG
|
uncertainty as a tie. |
build_mmpbsa_input ¶
build_mmpbsa_input(
*,
solvent_model: str = "gb",
start_frame: int = 1,
end_frame: int,
interval: int = 1,
salt_conc: float = 0.0,
igb: int = 5,
verbose: int = 1,
idecomp: int = 0,
dec_verbose: int = 0,
print_res: str = "within 6",
) -> str
Build the mmpbsa.in namelist text for an MM/PB(GB)SA run.
Shared by the Amber and gmx_MMPBSA engines — both consume the same
&general / &gb / &pb (and optional &decomp) namelists.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
solvent_model
|
str
|
|
'gb'
|
start_frame
|
int
|
First trajectory frame to analyze (1-based). |
1
|
end_frame
|
int
|
Last trajectory frame to analyze (inclusive). |
required |
interval
|
int
|
Stride between analyzed frames. |
1
|
salt_conc
|
float
|
Salt concentration in mol/L ( |
0.0
|
igb
|
int
|
Generalized Born model index (GB only; 5 = OBC-II). |
5
|
verbose
|
int
|
MMPBSA |
1
|
idecomp
|
int
|
Per-residue decomposition scheme. |
0
|
dec_verbose
|
int
|
|
0
|
print_res
|
str
|
Which residues to decompose ( |
'within 6'
|
Returns:
| Type | Description |
|---|---|
str
|
The input-file text, ready to write to |
Raises:
| Type | Description |
|---|---|
ValueError
|
On an unknown |
parse_mmpbsa_dat ¶
Parse MMPBSA.py output text into a :class:FreeEnergyResult.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
Full contents of a |
required |
solvent_model
|
str
|
|
'gb'
|
Returns:
| Type | Description |
|---|---|
FreeEnergyResult
|
A result whose |
FreeEnergyResult
|
|
FreeEnergyResult
|
|
FreeEnergyResult
|
|
FreeEnergyResult
|
|
FreeEnergyResult
|
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
parse_mmpbsa_decomp ¶
Parse a MMPBSA.py per-residue decomposition.
Reads FINAL_DECOMP_MMPBSA.dat (written when idecomp is set) and
returns the per-residue contributions from the requested species'
"Total Energy Decomposition" block. The default "delta" section is
the binding contribution (complex − receptor − ligand) — the one that
answers which residues drive the affinity.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
Contents of |
required |
section
|
str
|
Which species block to read — |
'delta'
|
Returns:
| Name | Type | Description |
|---|---|---|
A |
Decomposition
|
class: |
Decomposition
|
that block, in report order. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
selection_to_amber_mask ¶
Convert a molforge selection to an Amber residue mask.
The selection (a field-filter mapping like {"entity_type":
"ligand"}, forwarded to :meth:~molforge.core.AtomArray.where, or a
boolean atom mask) is resolved against topology and expressed as a
residue-number mask over the topology's sequential 1-based residue
numbering — e.g. ":1-120" or ":121". This is the numbering
Amber's ambmask uses, and the form MM/PB(GB)SA expects for
splitting a complex into receptor and ligand.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
topology
|
Protein
|
Structure the selection is resolved against (the complex). |
required |
selection
|
Selection
|
Field filters or a boolean atom mask. |
required |
Returns:
| Type | Description |
|---|---|
str
|
An Amber residue mask string beginning with |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the selection matches no atoms, or splits a residue (endpoint masks must cover whole residues). |
from_cinnabar ¶
from_cinnabar(
source: Any,
*,
computational_only: bool = True,
method: str = "FEP (network)",
metadata: Mapping[str, object] | None = None,
) -> dict[str, FreeEnergyResult]
Ingest cinnabar's per-ligand absolute estimates.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
source
|
Any
|
Either a cinnabar |
required |
computational_only
|
bool
|
Keep only calculated ligands, dropping any
experimental reference rows (the |
True
|
method
|
str
|
Value for :attr: |
'FEP (network)'
|
metadata
|
Mapping[str, object] | None
|
Extra items merged into every result's metadata. |
None
|
Returns:
| Type | Description |
|---|---|
dict[str, FreeEnergyResult]
|
|
dict[str, FreeEnergyResult]
|
|
dict[str, FreeEnergyResult]
|
to rank. Because the absolute values share one network offset, |
dict[str, FreeEnergyResult]
|
ranking and every pairwise ΔΔG are unaffected by it. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the label / ΔG / uncertainty columns can't be found. |
parse_gmx_mmpbsa_dat ¶
Parse gmx_MMPBSA output text into a :class:FreeEnergyResult.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
Full contents of a |
required |
solvent_model
|
str
|
|
'gb'
|
Returns:
| Type | Description |
|---|---|
FreeEnergyResult
|
A result whose |
FreeEnergyResult
|
|
FreeEnergyResult
|
|
FreeEnergyResult
|
|
FreeEnergyResult
|
are recorded in |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
parse_gmx_mmpbsa_decomp ¶
Parse a gmx_MMPBSA per-residue decomposition.
gmx_MMPBSA writes the same FINAL_DECOMP_MMPBSA.dat structure as
MMPBSA.py (it reuses that writer), so this reads the requested
species' "Total Energy Decomposition" block just like
:func:~molforge.wrappers.freeenergy.parse_mmpbsa_decomp. The default
"delta" section is the per-residue binding contribution.
gmx's delta rows carry an extra Location column (the residue's spot
in the receptor/ligand topology); it is dropped, and the residue keeps
its complex-numbering resname resnum label.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
Contents of |
required |
section
|
str
|
Which species block to read — |
'delta'
|
Returns:
| Name | Type | Description |
|---|---|---|
A |
Decomposition
|
class: |
Decomposition
|
that block, in report order. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
selection_to_ndx_group ¶
selection_to_ndx_group(
topology: Protein,
selection: Selection,
name: str,
*,
per_line: int = 15,
) -> str
Render a molforge selection as a GROMACS .ndx index group.
gmx_MMPBSA identifies the receptor and ligand by index-group number
(-cg <receptor> <ligand>), so a selection is resolved against the
topology and written as a named group of 1-based atom numbers — the
numbering GROMACS uses, which matches the topology's atom order (as
produced by the GROMACS MD wrapper).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
topology
|
Protein
|
Structure the selection is resolved against. |
required |
selection
|
Selection
|
Field filters or a boolean atom mask. |
required |
name
|
str
|
Group name, written as |
required |
per_line
|
int
|
Atom numbers per line (GROMACS wraps long groups). |
15
|
Returns:
| Type | Description |
|---|---|
str
|
The |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the selection matches no atoms. |