Official code repository for "A Unified 3D Generative Model for Synthesizable Structure-Based Drug Design". LDDM is a pocket-conditioned generative model that supports a broad range of molecular modeling tasks within a single model:
- De novo design
- Fragment growing
- Fragment linking
- Docking
- Partial docking (e.g. for covalent ligands)
- Locally programmable design
- Synthesizable design in virtual chemical spaces
We have tested many of these capabilities in prospective ligand design case studies. Read more about our experimental results on bioRxiv.
Clone the repository:
git clone https://github.com/LPDI-EPFL/lddm.git
cd lddmThen, install the CUDA environment for all workflows:
uv sync --extra cuda --frozenThis installs packages in .venv in the work directory. The cpu and cuda extras are mutually exclusive, and installation takes about 3 to 4 minutes.
To use the environment, run scripts with:
uv run --extra cuda path/to/script.pyor activate the environment before running python:
source .venv/bin/activate
python path/to/script.pyLDDM 0.1.0 was tested on Red Hat Enterprise Linux 9.4 (x86-64) with uv 0.11.32, Python 3.11.15, NumPy 1.26.4, and RDKit 2023.9.6. The CUDA environment used PyTorch 2.6.0+cu124 and torch-scatter 2.1.2+pt26cu124; the CPU environment used PyTorch 2.6.0+cpu and torch-scatter 2.1.2+pt26cpu. The pinned dependencies for both environments are recorded in uv.lock.
Sampling with the CPU environment takes 5-10x longer than with an accelerator.
All runtime estimates in this README include program startup. GPU estimates refer to one NVIDIA H100 2g.24GB MIG partition with four CPU cores and 20 GB of system memory. CPU estimates refer to eight Intel Xeon Platinum 8360Y cores and 32 GB of system memory.
The four basic examples below (de novo design, fragment-based design, docking, and partial docking) can also run without a GPU. From the repository root, install the CPU environment:
uv sync --extra cpu --frozen
source .venv/bin/activateRun any of the four basic example commands with --device cpu added. If using uv run instead of activating .venv, use uv run --extra cpu python scripts/sample.py ... --device cpu.
In case you don't have uv installed, we also provide a lightweight Docker container, which can be used as a starting working environment.
In addition to uv, Gnina and Reduce are already pre-installed, which are required for the programmable design workflows. The Python packages must be installed separately via uv sync --extra cuda --frozen, as described above.
You can pull the image from Docker Hub:
docker pull schneuing/lddm:0.1.0For CUDA workflows, give the container access to your system's GPU and the .venv folder.
Download a pretrained checkpoint from Zenodo:
wget -P checkpoints/ https://zenodo.org/records/22754501/files/lddm.ckptWe provide two checkpoints with different licenses. The main checkpoint (CD+BB+BN) was partially trained on BindingNet which was published with a more restrictive CC-BY-NC 4.0 license. The checkpoint without BindingNet is released under MIT License.
| Model | Link | Description | License |
|---|---|---|---|
CD+BB+BN |
https://zenodo.org/records/22754501/files/lddm.ckpt | Model used for experiments in the paper | CC-BY-NC 4.0 |
CD+BB |
https://zenodo.org/records/22754501/files/lddm_CDBB.ckpt | Model trained without BindingNet | MIT |
For programmable design, synthesizable design, or 3D validity evaluation, download the geometry reference from Zenodo:
wget -P data/validity3d/ https://zenodo.org/records/22754501/files/ligands.sdfpython scripts/sample.py design \
--protein examples/kras.pdb \
--ref_ligand examples/kras_ref_ligand.sdf \
--checkpoint checkpoints/lddm.ckpt \
--output examples/de_novo_samples.sdfEstimated runtime: about 1 minute 20 seconds on the H100 or about 12 minutes on the eight-core CPU setup, producing an SDF with 10 molecule records at examples/de_novo_samples.sdf.
python scripts/sample.py design \
--protein examples/kras.pdb \
--ref_ligand examples/kras_ref_ligand.sdf \
--ligand examples/kras_frag.sdf \
--checkpoint checkpoints/lddm.ckpt \
--output examples/grown_samples.sdfEstimated runtime: about 50 seconds on the H100 or about 14 minutes on the eight-core CPU setup, producing an SDF with 10 molecule records at examples/grown_samples.sdf.
python scripts/sample.py dock \
--protein examples/kras.pdb \
--ref_ligand examples/kras_ref_ligand.sdf \
--ligand examples/kras_ref_ligand.sdf \
--checkpoint checkpoints/lddm.ckpt \
--output examples/docked_samples.sdfEstimated runtime: about 55 seconds on the H100 or about 6 minutes on the eight-core CPU setup, producing an SDF with 10 molecule records at examples/docked_samples.sdf.
python scripts/sample.py dock \
--protein examples/kras.pdb \
--ref_ligand examples/kras_ref_ligand.sdf \
--ligand examples/kras_ref_ligand.sdf \
--atoms_to_dock 16 17 18 19 20 21 24 25 26 27 28 29 30 31 \
--checkpoint checkpoints/lddm.ckpt \
--output examples/partially_docked_samples.sdfEstimated runtime: about 45 seconds on the H100 or about 5 minutes 30 seconds on the eight-core CPU setup, producing an SDF with 10 molecule records at examples/partially_docked_samples.sdf.
| Parameter | Mode | Default | Description |
|---|---|---|---|
--n_samples |
both | 10 |
Number of molecules to generate. |
--molecule_size |
design | histogram | Target ligand size: an integer, uniform_<low>_<high>, or omit to sample from the pocket-conditioned size histogram. In dock the size is fixed to the input molecule. |
--atoms_to_dock |
dock | whole molecule | Atom indices whose positions are generated (partial docking); all other atoms keep their input coordinates. |
--n_steps |
both | 100 |
Number of integration steps of the sampling process (higher = slower, usually better). |
--sampler |
both | ForwardEuler |
ODE sampler: ForwardEuler or HeunSampler. |
--sampling_noise |
both | 5.0 |
Scale of the stochastic noise injected into atom coordinates during sampling. |
--batch_size |
both | --n_samples |
Number of samples generated per forward pass (lower it if you hit OOM). |
--n_frames |
both | None |
If set, save a sampling trajectory with this many frames (one sample only) instead of a batch of final molecules. |
--return_projected_final |
both | off | With --n_frames, project each frame onto the clean final prediction instead of the raw noisy state. |
--seed |
both | None |
Random seed for reproducible sampling. |
--device |
both | cuda:0 |
Device to run on, e.g. cuda:0 or cpu. |
Note
On first use, the geometry evaluator compiles reference distributions and caches
them beside data/validity3d/ligands.sdf. This can take substantial time before sampling starts.
python scripts/generate_programmable_design.py configs/controlled_generation/programmable_design.ymlEstimated runtime: about 7 minutes for the default KRAS example. Our reference run produced an SDF with 144 molecules at output/kras_programmable_samples.sdf, plus a pocket PDB and per-molecule CSV in output/.
Enamine REAL reactions and building blocks require a license and cannot be redistributed here. For this demonstration, we provide a smaller chemical space of 44,944 building blocks and three reactions derived from SynSpace, with precomputed reaction-to-building-block mappings. If you want to use synthesizable design with Enamine REAL, please request a license directly from Enamine and refer to the REAL Input Data (RID) reference guide for more information.
Download the SynSpace data from Zenodo:
wget -P data/synspace/ https://zenodo.org/records/22754501/files/building_blocks.csv
wget -P data/synspace/ https://zenodo.org/records/22754501/files/building_blocks.pkl
wget -P data/synspace/ https://zenodo.org/records/22754501/files/reactions.json
wget -P data/synspace/ https://zenodo.org/records/22754501/files/reaction_to_building_blocks.csv
wget -P data/synspace/ https://zenodo.org/records/22754501/files/reaction_to_building_blocks.pklFor your own chemical space, provide a building-block CSV with unique id and
smiles columns and a reaction JSON list. Each reaction must have two reactants
and one product, for example:
[
{
"id": "amide",
"reaction": "[C:1](=[O:2])[O;H1].[N;H1,H2:3]>>[C:1](=[O:2])[N:3]",
"explicit_hs": false
}
]python scripts/prepare_chemical_space.py \
--building-blocks path/to/building_blocks.csv \
--reactions path/to/reactions.json \
--output data/chemical_spaces/customThe script validates the molecules, computes fingerprints, and assigns blocks to
reaction roles by SMARTS matching. To preserve curated assignments, add
--memberships path/to/memberships.csv with columns reaction_id, reactant_role
(0 or 1, in SMARTS order), and building_block_id. Set the resulting paths in
configs/controlled_generation/synthesizable_design.yml:
itergen_params:
reaction_path: data/chemical_spaces/custom/reactions.json
building_blocks_path: data/chemical_spaces/custom/building_blocks.pkl
reaction_to_compound_path: data/chemical_spaces/custom/reaction_to_building_blocks.pklRun synthesizable design with the following command:
python scripts/generate_programmable_design.py configs/controlled_generation/synthesizable_design.ymlEstimated runtime: about 22 minutes for the default KRAS example. Our reference run produced an SDF with 27 molecules at output/kras_synthesizable_samples.sdf, plus a pocket PDB and per-molecule CSV in output/.
When using LDDM in your research, please cite our paper:
@article{igashov2026lddm,
title={A Unified 3D Generative Model for Synthesizable Structure-Based Drug Design},
author={Igashov, Ilia and Schneuing, Arne and Dobbelstein, Adrian W. and Morozova, Irina and Neeser, Rebecca M. and Zielinski, Kara and Abriata, Luciano Andres and Petruzzella, Aaron S. and Pavel Iosub, David R. and Gampp, Olivia and Lyubimov, Artem Y. and Elizarova, Evgenia and Ferrara, Isabella and Sousa, Pedro M. F. and Lemos, Ana R. and Testori, Fabio and Miranda Herrera, Pierre A. and Kanis, Laurin and Schmidt, Joseph and Braza, Mac Kevin E. and Amaro, Rommie E. and Thom{\"a}, Nicolas and Ferraris, Davide M. and Riek, Roland and Fraser, James S. and Schwaller, Philippe and Bronstein, Michael and Correia, Bruno},
year = {2026},
doi = {10.64898/2026.09.15.751537},
publisher = {Cold Spring Harbor Laboratory},
URL = {https://www.biorxiv.org/content/early/2026/09/18/2026.09.15.751537},
journal = {bioRxiv}
}Samples/metrics for reproducing computational benchmarks and experimental raw data can be downloaded from zenodo.org/records/23097713/files/data-20261002T080534Z-1-001.zip.

