ODesign
Native PyTorch implementation of the four released ODesign backbone artifacts and their released ProteinMPNN, LigandMPNN, gRNAde, and OInvFold compositions.
Disclaimer
This is an unofficial OFoldX implementation of ODesign. The upstream authors did not write, review, or endorse this implementation or model card.
Model Details
ODesign is an all-atom coordinate-diffusion model for biomolecular interaction
design. One ODesignModel graph serves four released artifacts; receptor mode
and generated chemistry are Processor facts, not switches that change the model
topology.
Variants
| Released artifact | Processor | Concrete composition |
|---|---|---|
Protein flex (protein_flex) |
ODesignProcessor |
ProteinMPNN without ligand atom context, otherwise LigandMPNN |
Protein rigid (protein_rigid) |
ODesignProcessor |
ProteinMPNN without ligand atom context, otherwise LigandMPNN |
Nucleic-acid rigid (nucleic_acid_rigid) |
ODesignProcessor |
DNA uses OInvFold; RNA uses gRNAde |
| Ligand rigid | ODesignLigandProcessor |
Ligand OInvFold assigns provisional atom elements |
Select the polymer artifact through its configuration, for example
ODesignProcessor(ODesignProcessorConfig(artifact="protein_rigid")).
DNA and RNA are separate concrete Pipelines because their inverse-folding
models differ. ODesignOInvFoldProteinPipeline and
ODesignOInvFoldRnaPipeline retain the independently runnable OInvFold
alternatives without presenting them as the official ODesign routes.
Protein, DNA, and RNA results contain canonical Structure predictions. Ligand
results remain provisional: they retain ordered coordinates, predicted elements,
per-atom probabilities, and generated-slot pair bond logits, but do not invent
bonds, formal charges, or a chemical-component identity.
Links
- Code: ofoldx.models.odesign
- Paper: ODesign: A World Model for Biomolecular Interaction Design
- Original Repository: The-Institute-for-AI-Molecular-Design/ODesign
Usage
The model depends on the ofoldx
library. Install it with pip:
pip install ofoldx
Polymer design
The conditioning complex is a Structure, or the polymer sequences it is built
from (a de-novo chain is one of unknown residues). The generated positions are
named by an ordinary PositionSelection; without one every position of the
route's monomer type is generated:
import ofoldx
from ofoldx.chemistry import polymer_sequence
from ofoldx.data import MonomerType
pipeline = ofoldx.pipeline("design", model="oteam/odesign-protein-flex")
chain = polymer_sequence("X" * 100, MonomerType.PROTEIN)
result = pipeline.design(chain, num_backbones=2, num_sequences=4)
Use the DNA or RNA repository with a typed PolymerSequence of that polymer for
those concrete routes.
The same operation is available through pipeline(...) and through three
explicit stages:
from ofoldx.models.design import PositionSelection
prepared = pipeline.prepare(chain, design=PositionSelection(), num_backbones=2, seed=42)
candidates = pipeline.forward(prepared)
result = pipeline.postprocess(prepared, candidates)
Every polymer composition prepares an ODesignPolymerPipelineInput: the
conditioning structure, the selected positions, the resolved MSA and seeds, and
the requested sample counts. forward returns candidates in seed-major,
backbone-major, sequence-rank order, each the children's final target with their
design records; postprocess assembles the ODesignPolymerResult.
For OInvFold compositions, num_sequences is a per-backbone beam budget, and
greedy decoding returns one assignment; its polymer workflow has no sampling
temperature, while ProteinMPNN, LigandMPNN and gRNAde retain theirs.
Provisional ligand design
Ligand atom count is the direct public argument. An integer fixes it; a range
lets the Processor sample it from the caller's generator.
The route conditions on a Structure only: its context is what is observed.
import ofoldx
from ofoldx.io import read_structure
pipeline = ofoldx.pipeline("design", model="oteam/odesign-ligand-rigid")
pocket, report = read_structure("pocket.cif")
result = pipeline.design(pocket, generated_atoms=range(8, 17))
Its prepare stage returns an ODesignLigandPipelineInput, and forward
returns the provisional candidate tuple for postprocess to assemble into an
ODesignLigandResult. num_coordinate_samples counts provisional coordinate samples,
and num_assignments is their per-sample element-assignment budget. Both counts
and use_beam are preparation arguments;
probability_temperature controls only the returned element-probability view; diffusion-step controls belong to forward.
Components and repositories
Each complete repository stores its polymer backbone or ligand
coordinate_generator component in backbone/. Protein
compositions also contain protein_designer/ and ligand_designer/; DNA, RNA and
the alternative polymer compositions contain sequence_designer/; provisional
ligand compositions contain element_designer/. Load the complete repository
with its concrete Pipeline class or with ofoldx.pipeline("design", model=...).
An individual component is independently loadable from that complete repository:
from ofoldx.models.odesign import ODesignProteinPipeline
backbone = ODesignProteinPipeline.component_from_repository("oteam/odesign-protein-flex", role="backbone")
The polymer-backbone and ligand-coordinate components expose prepare and
postprocess around model.sample; they retain their Model–Processor lifecycle.
The Model uses num_trunk_evaluations for repeated trunk evaluations and
num_samples for coordinate samples within each evaluation.
Identity and coordinate contract
A generated position keeps its canonical chemistry in the target and hides it from the features: the unknown class of its monomer type, no formal charge, and the design-state plane. A generated protein position is addressed as N, CA, C and O only, so the model places that backbone and the position's other atoms are withdrawn by the decode. Identities are assigned by the child family through the one design producer, which states per position whether the source was retained, retained under its encoding, or replaced.
Model row validity, reference availability, source coordinate availability, and fixed coordinates have separate masks. Provisional ligand rows have no canonical atom identity and do not create chemical vertices. Available numeric inputs must be finite; unavailable payload is selected out before geometry and dtype conversion. Finite values outside the model dtype's range are refused. The task's regeneration scope is fixed at preparation: every atom of a generated position and, for a flexible-receptor artifact, every atom of a context component the model moves — a hydrogen the layout excludes is invalidated with the component it belongs to rather than kept at a coordinate of a moved frame. A fixed atom and, for a rigid-receptor artifact, the whole context stay outside it and keep their own coordinates and observations. The element feature's category 128 means unavailable element information. It represents both canonical unknown elements and deliberately hidden elements; neither case asserts hydrogen or creates a chemical element. Canonical Z=0 remains unknown, while the distinct hydrogen descriptor remains category 0.
Training Details
Training Data
Refer to the ODesign paper for the upstream training corpora and data construction. OFoldX does not redistribute those corpora.
Training Procedure
ODesignProcessor.prepare_training produces the prepared input and its
StructureTarget, and target_tensors the model's tensor target. An optional
target supplies independent coordinates matched by instance, component ordinal
and atom name. For provisional ligand training,
ODesignLigandProcessor.prepare_training(context, target=truth, generated_target_instance_ids=("L",))
derives the generated atom count and returns an ODesignLigandTarget with
coordinate and covalent supervision. Truth stays separate from input features;
context and generated truth share a Cartesian frame, and fixed coordinates come
from the input. ODesignModel.forward implements stochastic target
corruption and differentiable denoising. odesign_loss combines the five
released objectives: weighted coordinate error, covalent-bond distance, smooth
lDDT, distogram classification, and binary token-bond prediction. A caller may
use those functions in a custom training loop; this does not reproduce the
upstream training-set construction, data curation, or complete training
program.
Explicitly zero-occupancy coordinates are unresolved by default for both
conditioning and training targets. Set filter_by_occupancy=False only when the
source occupancy field should be ignored.
Citation
@misc{zhang2025odesign,
title={ODesign: A World Model for Biomolecular Interaction Design},
author={Zhang, Odin and Zhang, Xujun and Lin, Haitao and others},
year={2025},
eprint={2510.22304},
archivePrefix={arXiv},
primaryClass={q-bio.BM}
}
Contact
Please use OFoldX GitHub issues for questions about this implementation or model card.
License
This model implementation is licensed under the GNU Affero General Public License.
SPDX-License-Identifier: AGPL-3.0-or-later
Converted checkpoint
This repository contains oteam/odesign-rna-rigid, converted from odesign_base_na_rigid.pt. The ODesign coordinate parameters retain Apache-2.0 in LICENSE. Embedded inverse-folding models retain their original licenses and notices inside each component directory and in the corresponding root LICENSE-* file. OFoldX implementation licensing is described separately in license.md and license-faq.md.
| Component | Converted repository | Weight license |
|---|---|---|
| backbone | ODesign coordinate model | Apache-2.0 |
| sequence_designer | oteam/grnade-odesign | mit |