Skip to content

omgkit

A cheminformatics toolkit written in Rust, with Python bindings.

Structures drawn by omgkit

Every structure on this site was drawn by omgkit itself — no other chemistry library is involved. The script that produces them is docs/figures/make_figures.py.

import omgkit

m = omgkit.parse_smiles("OC(=O)c1ccccc1N")
m.sanitize()
m.to_canonical_smiles()          # 'c1cccc(c1C(O)=O)N'

Status: under development

The API still changes between commits. Every layer is checked against an external reference implementation record by record, but the surface is not yet stable enough for production use. Bug reports are welcome.

What it does

Read and write SMILES Tetrahedral chirality, double-bond geometry, dative bonds, explicit hydrogens, canonical output
Sanitize Valence, implicit hydrogens, ring perception, kekulization, aromaticity, conjugation, hybridization
Match substructures SMARTS parsing, VF2++-style ordering, optionally stereo-aware, SMARTS writing for molecules and reactions
Apply reaction templates Product generation with optional atom-atom mapping
Reconstruct byproducts The water an esterification drops, rebuilt as a real molecule — or an explicit cannot tell when the record itself does not balance
Read and write .mol / .sdf V2000 molblocks and multi-record SDF, in 2D and 3D, with stereochemistry read and written both ways
Draw structures 2D coordinates and SVG/PNG/JPEG output, in two drawing styles — with an explicit report of anything it could not draw well
Generate 3D structures One deterministic conformer per molecule — no random seed, no retry loop
Featurize for ML Twelve per-atom and seven per-bond descriptors a graph neural network reads, Gasteiger partial charges included
Work in batches A columnar MolBatch with zero-copy per-molecule views

What makes it different

A molecule's properties are decided by the molecule, not by how someone chose to write it down. Two SMILES strings for the same structure must sanitize to the same thing, match the same queries, and react the same way. That sounds obvious; it is where a surprising number of edge cases hide, and it is the invariant every layer here is checked against.

Three consequences you can see from the outside:

Product count comes from the graph, not from the template. A reaction template rewrites one graph. How many product molecules come out is decided by how many connected components that rewritten graph has — not by how many product templates the author happened to write. This is a deliberate divergence from the common implementation, and it is why applying a template that cuts a ring bond does not silently duplicate atoms.

Discarded atoms are accounted for. When a template drops fragments, omgkit records exactly which atoms were dropped, and can close them into balanced byproduct molecules. When the record does not balance — a reducing agent missing from the reaction, say — it says so explicitly instead of guessing.

3D structures without a retry loop. Generating one conformer is deterministic — no random seed, no 10×N re-draws when a randomly sampled distance table turns out to be unsatisfiable. On the same 8831-molecule corpus, RDKit ETKDGv3 2025.09.2 fails on 36 molecules (0.41%) and omgkit on 1 (0.01%). See 3D structures.

And it draws them. Space-filling, ball-and-stick, stick and wireframe, in CPK colours, with the viewpoint set from the molecule's principal axes — and never mirrored, because in a 3D figure the configuration is the coordinates themselves. See 3D molecule figures.

Aspirin in four 3D styles

Every claim has a judge behind it. Correctness is not asserted, it is checked record by record against an external implementation, and each judge has to prove it does not pass vacuously. The whole suite runs on every push. See Correctness.

Install

pip install omgkit

One wheel covers Python 3.9 and up, and there are no system dependencies.

[dependencies]
omgkit-core   = "0.0.7"
omgkit-io     = "0.0.7"
omgkit-chem   = "0.0.7"
omgkit-match  = "0.0.7"
omgkit-conf   = "0.0.7"
omgkit-depict = "0.0.7"

Take only the layers you need; each depends only on the ones below it. Full instructions in Installation.

Where to go next

  • Quickstart — parse, sanitize, match and react in five minutes
  • Guides — one page per capability, task first
  • Descriptors for ML — the per-atom and per-bond values a graph model reads, and why they come back as names rather than one-hot vectors
  • Python API — every callable, with signatures
  • Developing — build, test, and the full pre-push gate suite

License

BSD-3-Clause. Test corpora and the element table are redistributed from other projects and carry their own terms; each file is traced to its origin in THIRD-PARTY-NOTICES.md.