Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 73 additions & 42 deletions extensions/ducksmiles/description.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
extension:
name: ducksmiles
description: Cheminformatics toolkit for DuckDB - SMILES, InChI, MOL/SDF, PDB, SELFIES, Wildman-Crippen LogP, Morgan/ECFP fingerprints, and Tanimoto similarity from SQL
version: 0.4.0
description: Cheminformatics toolkit for DuckDB - SMILES, InChI, MOL/SDF, PDB, SELFIES; descriptors (LogP, TPSA, QED), Morgan/MACCS fingerprints + similarity, drug-likeness/toxicophore filters, and a native in-silico docking pipeline, from SQL
version: 0.5.0
language: C++
build: cmake
license: MIT
Expand All @@ -10,7 +10,7 @@ extension:

repo:
github: nkwork9999/duckSMILES
ref: 51c796e9340e70c0ff8592771782916954fb4b08
ref: 96c85cc2c895e5fdaecb3e2e30009d1201fa5103

docs:
hello_world: |
Expand All @@ -22,21 +22,32 @@ docs:
SELECT round(mol_weight('c1ccccc1'), 2);
-- 78.11

-- Wildman-Crippen LogP (matches RDKit)
SELECT round(logp_crippen('CCO'), 4);
-- -0.0014
-- Wildman-Crippen LogP and molar refractivity (match RDKit)
SELECT round(logp_crippen('CCO'), 4), round(mol_mr('c1ccccc1'), 3);
-- -0.0014, 26.442

-- Morgan/ECFP fingerprint as 2048-bit BLOB (ECFP4 default)
SELECT bit_count(CAST(morgan_fp_bits('CC(=O)Oc1ccccc1C(=O)O') AS BIT));
-- 26 (aspirin popcount)
-- QED drug-likeness score (RDKit Chem.QED, weights_mean)
SELECT round(qed('CC(=O)Oc1ccccc1C(=O)O'), 3);
-- 0.550 (aspirin)

-- Tanimoto similarity between two fingerprint BLOBs (no CAST AS BIT needed)
-- Drug-likeness rule panels + toxicophore alerts
SELECT lipinski_violations('CC(=O)Oc1ccccc1C(=O)O'),
druglikeness_pass('CC(=O)Oc1ccccc1C(=O)O', 'veber'),
structural_alerts_json('O=Cc1ccccc1');
-- 0, 1, ["aldehyde","aldehyde_any"]

-- Morgan/ECFP fingerprint + similarity between two BLOBs
SELECT round(tanimoto_bit(morgan_fp_bits('CCO'), morgan_fp_bits('CCN')), 4);
-- 0.3333

-- Validate and extract InChI layers
SELECT inchi_formula('InChI=1S/C2H4O2/c1-2(3)4/h1H3,(H,3,4)');
-- C2H4O2
-- In-silico docking: SMILES ligand vs PDB receptor -> ranked poses (JSON)
SELECT dock('CCO', :receptor_pdb, 1.7,0.2,0.5, 8,8,8, 20, 42);

-- Retrospective virtual-screening enrichment over a docked, labelled library
SELECT roc_auc(list(score), list(is_active)),
enrichment_factor(list(score), list(is_active), 0.01),
bedroc(list(score), list(is_active), 20.0)
FROM docked_library;

-- Convert SMILES to SELFIES (ML-friendly notation)
SELECT smiles_to_selfies('CCO');
Expand All @@ -47,32 +58,52 @@ docs:
library dependencies (no RDKit required).

**Supported Formats:**
- SMILES: Molecular validation, formula, weight, atom/bond counts, LogP
- InChI/InChIKey: Layer extraction, stereochemistry detection, skeleton matching
- MOL/SDF: V2000/V3000 block parsing, molecule counting
- PDB/CIF/XYZ: Protein structure analysis (atom, chain, residue, model counts)
- SELFIES: Bidirectional SMILES-SELFIES conversion for ML pipelines

**39 scalar SQL functions** for molecular property extraction, format conversion,
structural comparison, and physicochemical property prediction. Ideal for
cheminformatics datasets, drug discovery pipelines, and molecular ML feature
engineering.

**LogP:** `logp_crippen()` implements the Wildman-Crippen atom-contribution
method (110 SMARTS patterns, 68 atom types) and matches RDKit's
`Crippen.MolLogP` exactly for small molecules.

**Morgan / ECFP fingerprint:** `morgan_fp_bits()` ports RDKit's MorganGenerator
(layered BFS + hash_combine + dead-atom dedup) to Rust and returns a fixed-width
bit vector as `BLOB`. Defaults to ECFP4 (radius=2, 2048 bit); 3-arg overload
`morgan_fp_bits(smi, radius, n_bits)` exposes full control.

**Tanimoto similarity:** `tanimoto_bit(BLOB, BLOB) -> DOUBLE` computes
`popcount(a & b) / popcount(a | b)` directly on raw BLOB bytes (no
`CAST AS BIT` round-trip), processing 8 bytes at a time via `count_ones()`
so it lowers to POPCNT on x86_64 / CNT on aarch64. Mismatched lengths raise
a clear `InvalidInputException`; empty-vs-empty returns `0.0` (RDKit
convention). The SQL-level `bit_count(a & b)::DOUBLE / bit_count(a | b)`
is still available and produces bit-exact identical results.

**Architecture:** Rust (core logic, 5 crates) + C++ (DuckDB integration via FFI)
- SMILES: validation, formula, weight, atom/bond counts, canonicalization, aromaticity
- InChI/InChIKey: layer extraction, stereochemistry detection, skeleton matching
- MOL/SDF: V2000/V3000 block parsing, 3D geometry, molecule counting
- PDB/CIF/XYZ: protein structure analysis (atom, chain, residue, model counts)
- SELFIES: bidirectional SMILES-SELFIES conversion for ML pipelines

**130+ scalar SQL functions** for molecular property extraction, format conversion,
structural comparison, fingerprinting, similarity search, drug-likeness /
toxicophore filtering, and structure-based virtual screening.

**Descriptors (RDKit-faithful ports):**
- `logp_crippen()` / `mol_mr()` - Wildman-Crippen LogP and molar refractivity.
- `tpsa()` - Ertl topological polar surface area.
- `qed()` - QED drug-likeness (Bickerton 2012), a port of RDKit `Chem.QED`.
- Lipinski set: `num_h_donors()`, `num_h_acceptors()`, `num_rotatable_bonds()`,
`fraction_csp3()`, `num_heteroatoms()`, and the full ring-count descriptor family.

**Fingerprints & similarity:**
- `morgan_fp_bits()` (RDKit MorganGenerator, ECFP4 / 2048-bit default) and
`maccs_keys()` (167-bit MACCS).
- Full bit-fingerprint similarity family over raw BLOBs, faithful to RDKit
`DataStructs/BitOps.cpp`: `tanimoto_bit`, `dice_bit`, `cosine_bit`, `kulczynski_bit`,
`sokal_bit`, `mcconnaughey_bit`, `asymmetric_bit`, `braun_blanquet_bit`,
`russel_bit`, and asymmetric `tversky_bit(a, b, alpha, beta)`.

**Structure tools:** SMARTS substructure search/counting, Bemis-Murcko and generic
scaffolds, scaffold networks, ring-system extraction, maximum common substructure
(MCS), and MolHash standardization.

**Drug-likeness & toxicophore filtering:**
- `admet_json()` - a full report: descriptors plus six drug-likeness rule panels.
- `druglikeness_pass(smiles, rule)` for Lipinski, Veber, Ghose, Egan, Muegge and
Lead-likeness; `lipinski_violations()` for the Rule-of-Five count.
- `structural_alerts_json()` / `structural_alert_count()` over a curated
Brenk / PAINS reactive-group toxicophore catalogue.

**In-silico docking pipeline (structure-based virtual screening, end-to-end in SQL):**
- `smiles_to_pdbqt()` - 3D conformer generation (distance geometry + an L-BFGS-
minimised lite force field with aromatic-ring planarity) emitted as PDBQT.
- `prepare_receptor(pdb, ph)` - pH-dependent protonation states + polar-hydrogen
addition, so the receptor can donate H-bonds.
- `dock(smiles, pdb, cx, cy, cz, sx, sy, sz, n_runs, seed [, ph])` - flexible
torsion-tree docking with an AutoDock-Vina-style scoring function and 3D affinity
maps; returns ranked poses with coordinates as JSON.
- Retrospective-validation harness: `roc_auc`, `enrichment_factor(fraction)`,
`bedroc(alpha)` to measure how well a docked library enriches known actives.

**Architecture:** Rust (core logic, zero external chemistry crates) + C++ (DuckDB
integration via FFI).
Loading