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

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-protein-rigid, converted from odesign_base_prot_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
protein_designer oteam/proteinmpnn mit
ligand_designer oteam/ligandmpnn mit
Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Paper for oteam/odesign-protein-rigid