---
title: Conformers & Minimization
description: 'Embed conformers with ETKDGv3, minimize under MMFF94s or fall back to UFF, pick the lowest-energy conformer from stored energies, and write them to an SDF.'
---

Conformer generation lets you turn a flat SMILES into 3D structures ready for minimization, export, and downstream docking. The embedding parameters, force field choice (MMFF94s vs UFF), and how you pick the lowest-energy conformer are what most affect the quality of the geometry you carry forward.

## Generate conformers

```python
from rdkit import Chem
from rdkit.Chem import AllChem

mol = Chem.AddHs(Chem.MolFromSmiles("CCOC(=O)C1=CC=CC=C1"))
params = AllChem.ETKDGv3()
params.numThreads = 0  # use all cores
ids = AllChem.EmbedMultipleConfs(mol, numConfs=10, params=params)
print(f"Generated {len(ids)} conformers")
```

## Minimize

```python
props = AllChem.MMFFGetMoleculeProperties(mol)
for cid in ids:
    AllChem.MMFFOptimizeMolecule(mol, confId=cid, mmffVariant="MMFF94s", nonBondedThresh=100.0, maxIters=200)
    energy = AllChem.MMFFGetMoleculeForceField(mol, props, confId=cid).CalcEnergy()
    mol.SetProp(f"energy_{cid}", f"{energy:.3f}")
```

For neutral organics, MMFF94s is usually stable. For metals or unusual valence,
fall back to UFF.

## Select the best conformer

```python
best = min(ids, key=lambda cid: float(mol.GetProp(f"energy_{cid}")))
```

## Export to SDF

```python
from rdkit.Chem import SDWriter

writer = SDWriter("/workspace/outputs/conformers.sdf")
for cid in ids:
    writer.write(mol, confId=cid)
writer.close()
```

## Tips

- Keep `EmbedMultipleConfs` deterministic by setting `params.randomSeed`.
- Sanitize inputs first: `Chem.SanitizeMol` to catch valence issues early.
- Store energies as props so downstream steps can filter without recomputing.
