Skip to content

Engine wrappers

molforge doesn't reimplement folding models, MD engines, or docking binaries. It wraps them behind small, typed interfaces so engines are swappable from user code.

There are four wrapper categories, each with a stable base class and one or more concrete engines:

Category Base class Engines
Folding FoldingEngine ESMFold, AlphaFold, Boltz, RoseTTAFold
Docking DockingEngine Vina, DiffDock
MD MDEngine OpenMM (stub: GROMACS)
Generative GenerativeEngine RFdiffusion, ProteinMPNN

Each base class defines a small predict / dock / simulate / generate method that returns a molforge type (Protein, DockingResult, Trajectory, etc.) — so a pipeline that uses one engine can swap to another with a one-line change.

Lazy heavy imports

Wrappers never import their heavy dependencies (torch, transformers, vina, openmm, colabfold) at module load time. Heavy imports happen inside method bodies, so import molforge.wrappers stays fast and the dependencies are only required when the corresponding engine is actually used.

If you try to call a wrapper whose dependency is missing, the wrapper raises an *EngineNotInstalledError with a clear message:

from molforge.wrappers.folding import ESMFold

try:
    folded = ESMFold().predict("MKTV...")
except FoldingEngineNotInstalledError as e:
    print(e)   # "ESMFold requires torch + transformers; pip install 'molforge[ml]'"

A worked example — folding

from molforge.wrappers.folding import ESMFold
from molforge.io import save

engine = ESMFold(device="cuda")          # or "cpu"
folded = engine.predict("MKTVRQERLKSIVRILERSKEPVSGAQLAEELSVS...")

# Per-residue pLDDT lives in metadata (same convention across all
# folding engines — see molforge.wrappers.folding docstring)
plddt = folded.metadata["confidence_per_residue"]

save(folded, "candidate.pdb")

To switch to AlphaFold, replace one line:

from molforge.wrappers.folding import AlphaFold

engine = AlphaFold(...)
folded = engine.predict("MKTV...")    # same return type, same metadata key

That's the whole point of the wrapper pattern.

The escape hatch

For the rare case where you need engine-specific functionality not in the base interface, MDEngine-derived simulations expose Simulation.engine_handle: object | None — the raw underlying object (an openmm.Simulation, a gromacs.Process, etc.). This is an explicit "you're going off the supported surface" handle; use it sparingly, and only when the wrapper genuinely doesn't expose what you need.

API status

engine_handle is intentionally typed as object | None to signal that the contents are engine-specific. The handle is retained for the lifetime of the Simulation; it's never invalidated underneath you.

Reference