molforge.design¶
design ¶
The protein-design loop: generate → fold → (dock) → score → iterate.
Real protein engineering is a loop. You propose sequences for a scaffold,
predict what they fold to, check whether the prediction actually matches
the scaffold you designed for, keep the winners, and design again from
them. Every piece already exists as a molforge wrapper — a sequence
designer (ProteinMPNN, ESM-IF1), a folding engine (ESMFold, AlphaFold,
Boltz), optionally a docking engine — but nothing glues them into the
loop. :class:DesignLoop is that glue:
from molforge.design import DesignLoop
from molforge.wrappers.generative import ProteinMPNN
from molforge.wrappers.folding import ESMFold
loop = DesignLoop(designer=ProteinMPNN(), folder=ESMFold(), n_rounds=3)
table = loop.run(backbone) # a Protein or a PDB path
best = table.best # highest self-consistency design
rows = table.to_records() # flat dicts → drop into a DataFrame
The default objective is self-consistency: fold each designed
sequence and measure how well the prediction superposes on the backbone
it was designed for (scTM / scRMSD). This is the metric the
RFdiffusion / ProteinMPNN / AlphaFold design pipelines are graded on, and
it falls straight out of the corrected :func:~molforge.metrics.tm_score
and :func:~molforge.structure.rmsd. Other built-in objectives score by
folding confidence ("plddt") or docked affinity ("affinity"), and
a custom callable covers everything else.
Folding can be a single engine or a list — pass a list and each
candidate is folded with :func:~molforge.ensembles.cross_engine_fold,
scored against the cross-engine consensus, with the per-residue
cross-engine disagreement recorded as an extra confidence signal.
Iteration is genuine: round r+1 re-designs onto the folded structures
of the top select_top candidates from round r, so the scaffold
refines as the loop runs. The :class:DesignTable accumulates every
candidate across every round, ranked best-first.
Scope (v1): the designer produces sequences for a provided backbone.
The generator slot (round-0 backbone generation, e.g. RFdiffusion) is
part of the signature but raises :class:NotImplementedError — its
configuration surface (contigs, targets, symmetry) is too engine-specific
to wire generically yet.
DesignCandidate
dataclass
¶
DesignCandidate(
sequence: str,
round: int,
backbone: Protein | None = None,
structure: Protein | None = None,
docking: DockingResult | None = None,
metrics: dict[str, float] = dict(),
score: float = math.nan,
metadata: dict[str, object] = dict(),
)
One design as it flows through the loop, accumulating results.
Attributes:
| Name | Type | Description |
|---|---|---|
sequence |
str
|
The designed one-letter sequence. |
round |
int
|
0-indexed loop round that produced it. |
backbone |
Protein | None
|
The scaffold this sequence was designed onto — the user's input backbone in round 0, a previous round's folded winner thereafter. The reference for self-consistency. |
structure |
Protein | None
|
The folded (predicted) structure. |
docking |
DockingResult | None
|
The docking result against the receptor, if a |
metrics |
dict[str, float]
|
Named scalar measurements — |
score |
float
|
The objective value; higher is better. |
metadata |
dict[str, object]
|
Free-form extras. |
DesignTable
dataclass
¶
The ranked output of a :meth:DesignLoop.run.
Candidates from every round, sorted best-first by objective score
(nan scores sort last).
Attributes:
| Name | Type | Description |
|---|---|---|
candidates |
list[DesignCandidate]
|
All designs, best-first. |
rounds |
int
|
Number of rounds that ran. |
objective |
str
|
The objective name (or |
to_records ¶
Flatten to a list of row dicts — pandas.DataFrame(...)-ready.
Each row has round, score, sequence, and one column per
metric key present across the candidates (missing values filled
with nan).
DesignLoop ¶
DesignLoop(
*,
designer: GenerativeEngine,
folder: FoldingEngine | Sequence[FoldingEngine],
docker: DockingEngine | None = None,
generator: GenerativeEngine | None = None,
objective: DesignObjective
| Callable[[DesignCandidate], float]
| Scorer = "self_consistency",
n_designs: int = 8,
n_rounds: int = 1,
select_top: int = 4,
workers: int | None = None,
backend: Backend | None = None,
)
Orchestrate generate → fold → (dock) → score → iterate.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
designer
|
GenerativeEngine
|
A sequence-design engine — any object with
|
required |
folder
|
FoldingEngine | Sequence[FoldingEngine]
|
A folding engine, or a list of them. A single engine folds
each sequence with |
required |
docker
|
DockingEngine | None
|
Optional docking engine. When set, each folded structure is
docked against |
None
|
generator
|
GenerativeEngine | None
|
Reserved for round-0 backbone generation (RFdiffusion).
Supplying it raises :class: |
None
|
objective
|
DesignObjective | Callable[[DesignCandidate], float] | Scorer
|
|
'self_consistency'
|
n_designs
|
int
|
Max designed sequences to carry forward per backbone per
round (the designer may propose more; the top |
8
|
n_rounds
|
int
|
Number of design rounds. |
1
|
select_top
|
int
|
Winners carried as next-round seeds (their folded structures become the scaffolds redesigned onto). |
4
|
workers
|
int | None
|
Parallel-fold worker count (see :func: |
None
|
backend
|
Backend | None
|
Parallel-fold backend override; defaults to the folding
engine's |
None
|
Raises:
| Type | Description |
|---|---|
NotImplementedError
|
If |
ValueError
|
If |
run ¶
run(
backbone: Protein | str | PathLike[str],
*,
receptor: Protein | None = None,
designer_kwargs: dict[str, Any] | None = None,
fold_kwargs: dict[str, Any] | None = None,
dock_kwargs: dict[str, Any] | None = None,
) -> DesignTable
Run the loop and return a ranked :class:DesignTable.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
backbone
|
Protein | str | PathLike[str]
|
The scaffold to design onto — a :class: |
required |
receptor
|
Protein | None
|
The docking receptor; required if a |
None
|
designer_kwargs
|
dict[str, Any] | None
|
Extra kwargs forwarded to |
None
|
fold_kwargs
|
dict[str, Any] | None
|
Extra kwargs forwarded to the folding call(s). |
None
|
dock_kwargs
|
dict[str, Any] | None
|
Extra kwargs forwarded to |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
A |
DesignTable
|
class: |
DesignTable
|
best-first. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If a |