From bc74cc4d0a12d3cb7b0415f43734ec5c3d4e1af8 Mon Sep 17 00:00:00 2001 From: hechth Date: Wed, 8 Jul 2026 13:40:10 +0200 Subject: [PATCH 1/3] [New Tool Request]: RDKit Chem calculate structural similarity Fixes #746 --- tools/rdkit/.shed.yml | 12 + tools/rdkit/macros.xml | 65 ++++ tools/rdkit/rdkit_structsim.xml | 184 ++++++++++ tools/rdkit/rdkit_structsim_wrapper.py | 343 ++++++++++++++++++ tools/rdkit/test-data/output_cosine_maccs.tsv | 11 + tools/rdkit/test-data/output_dice_rdkit.tsv | 6 + .../test-data/output_tanimoto_morgan.tsv | 26 ++ tools/rdkit/test-data/queries.inchi | 2 + tools/rdkit/test-data/queries.sdf | 149 ++++++++ tools/rdkit/test-data/references.sdf | 140 +++++++ tools/rdkit/test-data/references.smi | 2 + 11 files changed, 940 insertions(+) create mode 100644 tools/rdkit/.shed.yml create mode 100644 tools/rdkit/macros.xml create mode 100644 tools/rdkit/rdkit_structsim.xml create mode 100644 tools/rdkit/rdkit_structsim_wrapper.py create mode 100644 tools/rdkit/test-data/output_cosine_maccs.tsv create mode 100644 tools/rdkit/test-data/output_dice_rdkit.tsv create mode 100644 tools/rdkit/test-data/output_tanimoto_morgan.tsv create mode 100644 tools/rdkit/test-data/queries.inchi create mode 100644 tools/rdkit/test-data/queries.sdf create mode 100644 tools/rdkit/test-data/references.sdf create mode 100644 tools/rdkit/test-data/references.smi diff --git a/tools/rdkit/.shed.yml b/tools/rdkit/.shed.yml new file mode 100644 index 000000000..abb882f13 --- /dev/null +++ b/tools/rdkit/.shed.yml @@ -0,0 +1,12 @@ +name: rdkit_structsim +description: Calculate structural similarity using RDKit fingerprints from SMILES/InChI/SDF files +long_description: | + This tool calculates structural similarity between compounds using RDKit molecular + fingerprints. It accepts SMILES (.smi), InChI (.inchi), or SDF (.sdf) files and + supports multiple fingerprint types (Morgan, RDKit, MACCS) and similarity metrics + (Tanimoto, Dice, Cosine, Soergel, Kulczynski, McConnaughey). +categories: + - Cheminformatics + - Similarity Search +owner: hechth +license: MIT diff --git a/tools/rdkit/macros.xml b/tools/rdkit/macros.xml new file mode 100644 index 000000000..1451c883e --- /dev/null +++ b/tools/rdkit/macros.xml @@ -0,0 +1,65 @@ + + 2026.03.3 + 0 + + + + + + + + + + + + RDKit + + + + + + topic_2258 + topic_0091 + + + operation_2483 + + + + + + +@article{RDKit_2024, + author = {Landrum, Gregory and others}, + title = {{RDKit: Open-source cheminformatics}}, + year = {2024}, + url = {https://www.rdkit.org} +} + + 10.1186/1758-2946-3-33 + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tools/rdkit/rdkit_structsim.xml b/tools/rdkit/rdkit_structsim.xml new file mode 100644 index 000000000..0855dbbf9 --- /dev/null +++ b/tools/rdkit/rdkit_structsim.xml @@ -0,0 +1,184 @@ + + calculate structural similarity using RDKit fingerprints from SMILES/InChI/SDF files + + macros.xml + + + + + + + + + rdkit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tools/rdkit/rdkit_structsim_wrapper.py b/tools/rdkit/rdkit_structsim_wrapper.py new file mode 100644 index 000000000..e7b1bc3a6 --- /dev/null +++ b/tools/rdkit/rdkit_structsim_wrapper.py @@ -0,0 +1,343 @@ +#!/usr/bin/env python +""" +RDKit Structural Similarity Calculator + +This script calculates structural similarity between compounds using RDKit fingerprints. +It accepts SMILES, InChI, or SDF files and outputs a table with similarity scores +and the input structures. +""" + +import argparse +import logging +import re +import sys +from typing import Callable, List, Optional, Tuple + +from rdkit import Chem, DataStructs +from rdkit.Chem import AllChem, MACCSkeys, rdFingerprintGenerator + +logger = logging.getLogger(__name__) + + +# Morgan fingerprint generator (ECFP-like) - using new API +_morgan_gen = rdFingerprintGenerator.GetMorganGenerator(radius=2, fpSize=2048) + + +def get_morgan_fingerprint(mol: Chem.Mol): + """Generate Morgan fingerprint for a molecule.""" + return _morgan_gen.GetFingerprint(mol) + + +def get_rdkit_fingerprint(mol: Chem.Mol): + """Generate RDKit fingerprint for a molecule.""" + return AllChem.RDKFingerprint(mol, maxPath=7, fpSize=2048) + + +def get_maccs_fingerprint(mol: Chem.Mol): + """Generate MACCS keys fingerprint for a molecule.""" + return MACCSkeys.GenMACCSKeys(mol) + + +def get_fingerprint(mol: Chem.Mol, fingerprint_type: str): + """ + Generate fingerprint for a molecule based on specified type. + + Args: + mol: RDKit Mol object + fingerprint_type: Type of fingerprint ("Morgan", "RDKit", or "MACCS") + + Returns: + Fingerprint bit vector or None if molecule is invalid + """ + if mol is None: + return None + + if fingerprint_type == "Morgan": + return get_morgan_fingerprint(mol) + elif fingerprint_type == "RDKit": + return get_rdkit_fingerprint(mol) + elif fingerprint_type == "MACCS": + return get_maccs_fingerprint(mol) + else: + raise ValueError(f"Unknown fingerprint type: {fingerprint_type}") + + +def detect_structure_type(structure_str: str) -> Optional[str]: + """ + Detect whether a string is a SMILES or InChI representation. + + Args: + structure_str: Structure string to analyze + + Returns: + 'SMILES', 'InChI', or None if undetectable + """ + if not structure_str: + return None + + structure_str = str(structure_str).strip() + + # Check for InChI prefix + if structure_str.startswith("InChI=") or structure_str.startswith("InChI"): + return "InChI" + + # Simple heuristic for SMILES: contains common organic element symbols + # and doesn't start with InChI + smiles_pattern = r'^[CNOcSsNnPpFxClBrIa-zA-Z0-9@+\-\[\]()\\/=]+$' + if re.match(smiles_pattern, structure_str) and len(structure_str) > 1: + return "SMILES" + + return None + + +def parse_structure(structure_str: str) -> Optional[Tuple[Chem.Mol, str]]: + """ + Parse a SMILES or InChI string into an RDKit Mol object. + Auto-detects the structure type. + + Args: + structure_str: SMILES or InChI string + + Returns: + Tuple of (RDKit Mol object, detected type) or None if parsing fails + """ + if not structure_str: + return None + + structure_str = str(structure_str).strip() + + # Try to detect type + detected_type = detect_structure_type(structure_str) + + if detected_type == "InChI": + mol = Chem.MolFromInchi(structure_str) + if mol is not None: + return (mol, "InChI") + elif detected_type == "SMILES": + mol = Chem.MolFromSmiles(structure_str) + if mol is not None: + return (mol, "SMILES") + else: + # Try SMILES first, then InChI + mol = Chem.MolFromSmiles(structure_str) + if mol is not None: + return (mol, "SMILES") + + mol = Chem.MolFromInchi(structure_str) + if mol is not None: + return (mol, "InChI") + + logger.warning(f"Could not parse structure: {structure_str[:50]}...") + return None + + +def calculate_similarity(fp1, fp2, metric: str) -> float: + """ + Calculate similarity between two fingerprints using the specified metric. + + Args: + fp1: First fingerprint + fp2: Second fingerprint + metric: Similarity metric name + + Returns: + Similarity score (0-1) + """ + if metric == "tanimoto": + return DataStructs.TanimotoSimilarity(fp1, fp2) + elif metric == "dice": + return DataStructs.DiceSimilarity(fp1, fp2) + elif metric == "cosine": + return DataStructs.CosineSimilarity(fp1, fp2) + elif metric == "soergel": + return DataStructs.SoergelSimilarity(fp1, fp2) + elif metric == "kulczynski": + return DataStructs.KulczynskiSimilarity(fp1, fp2) + elif metric == "mcconnaughey": + return DataStructs.McConnaugheySimilarity(fp1, fp2) + else: + raise ValueError(f"Unknown similarity metric: {metric}") + + +def load_compounds_from_smi_inchi(filepath: str) -> Tuple[List[Tuple[str, Chem.Mol]], str]: + """ + Load compounds from SMI or INCHI file. + + Args: + filepath: Path to input file + + Returns: + Tuple of (list of (structure_string, Mol) tuples, detected structure type) + """ + compounds = [] + detected_type = None + + with open(filepath, 'r') as f: + for line in f: + line = line.strip() + if not line or line.startswith('#'): + continue # Skip empty lines and comments + + result = parse_structure(line) + if result: + mol, struct_type = result + if detected_type is None: + detected_type = struct_type + compounds.append((line, mol)) + + if not compounds: + raise ValueError(f"No valid compounds found in {filepath}!") + + logger.info(f"Loaded {len(compounds)} compounds from {filepath} ({detected_type})") + return compounds, detected_type + + +def load_compounds_from_sdf(filepath: str) -> Tuple[List[Tuple[str, Chem.Mol]], str]: + """ + Load compounds from SDF file. Extracts SMILES from the data block. + + Args: + filepath: Path to SDF file + + Returns: + Tuple of (list of (structure_string, Mol) tuples, detected structure type) + """ + compounds = [] + detected_type = None + + suppl = Chem.SDMolSupplier(filepath, removeHs=False) + + for mol in suppl: + if mol is None: + continue + + # Try to get SMILES from the molecule + smiles = Chem.MolToSmiles(mol) + if smiles: + compounds.append((smiles, mol)) + if detected_type is None: + detected_type = "SMILES" + + if not compounds: + raise ValueError(f"No valid compounds found in {filepath}!") + + logger.info(f"Loaded {len(compounds)} compounds from {filepath} ({detected_type})") + return compounds, detected_type + + +# Mapping from file type to loader function +FILE_LOADERS: dict[str, Callable[[str], Tuple[List[Tuple[str, Chem.Mol]], str]]] = { + "smi": load_compounds_from_smi_inchi, + "inchi": load_compounds_from_smi_inchi, + "sdf": load_compounds_from_sdf, +} + + +def main(argv): + parser = argparse.ArgumentParser( + description="Calculate structural similarity between compounds using RDKit" + ) + + parser.add_argument( + "--queries", type=str, required=True, + help="Path to query compounds file" + ) + parser.add_argument( + "--queries-type", type=str, required=True, choices=["smi", "inchi", "sdf"], + help="Format of query compounds file (smi, inchi, or sdf)" + ) + parser.add_argument( + "--references", type=str, required=True, + help="Path to reference compounds file" + ) + parser.add_argument( + "--references-type", type=str, required=True, choices=["smi", "inchi", "sdf"], + help="Format of reference compounds file (smi, inchi, or sdf)" + ) + parser.add_argument( + "--similarity-metric", type=str, default="tanimoto", + choices=["tanimoto", "dice", "cosine", "soergel", "kulczynski", "mcconnaughey"], + help="Similarity metric to use (default: tanimoto)" + ) + parser.add_argument( + "--fingerprint-type", type=str, default="Morgan", + choices=["Morgan", "RDKit", "MACCS"], + help="Type of fingerprint to use (default: Morgan)" + ) + parser.add_argument( + "--output", type=str, required=True, + help="Output TSV file path for similarity results" + ) + + args = parser.parse_args(argv) + + try: + # Get loader functions based on file types + query_loader = FILE_LOADERS.get(args.queries_type) + ref_loader = FILE_LOADERS.get(args.references_type) + + if query_loader is None: + raise ValueError(f"Unsupported query file type: {args.queries_type}") + if ref_loader is None: + raise ValueError(f"Unsupported reference file type: {args.references_type}") + + # Load compounds using the specified loaders (ignoring file extension) + logger.info("Loading query compounds...") + query_compounds, query_type = query_loader(args.queries) + + logger.info("Loading reference compounds...") + ref_compounds, ref_type = ref_loader(args.references) + + # Determine output structure type preference + output_type = query_type if query_type else ref_type + logger.info(f"Using structure type: {output_type}") + + # Generate fingerprints + logger.info(f"Generating {args.fingerprint_type} fingerprints...") + query_fps = [get_fingerprint(mol, args.fingerprint_type) for _, mol in query_compounds] + ref_fps = [get_fingerprint(mol, args.fingerprint_type) for _, mol in ref_compounds] + + # Remove invalid entries + valid_queries = [(comp[0], fp) for comp, fp in zip(query_compounds, query_fps) if fp is not None] + valid_refs = [(comp[0], fp) for comp, fp in zip(ref_compounds, ref_fps) if fp is not None] + + if not valid_queries: + raise ValueError("No valid query compounds with usable fingerprints!") + if not valid_refs: + raise ValueError("No valid reference compounds with usable fingerprints!") + + logger.info( + f"Valid compounds - Queries: {len(valid_queries)}, References: {len(valid_refs)}" + ) + + logger.info(f"Calculating {args.similarity_metric} similarity...") + + # Calculate all pairwise similarities and build output + results = [] + for q_struct, q_fp in valid_queries: + for r_struct, r_fp in valid_refs: + sim = calculate_similarity(q_fp, r_fp, args.similarity_metric) + results.append({ + "query_structure": q_struct, + "reference_structure": r_struct, + "similarity": sim + }) + + # Create output - write directly to avoid pandas dependency + with open(args.output, 'w') as f: + f.write("similarity\tquery_structure\treference_structure\n") + for r in results: + f.write(f"{r['similarity']}\t{r['query_structure']}\t{r['reference_structure']}\n") + + logger.info(f"Similarity results written to {args.output}") + logger.info(f"Total comparisons: {len(results)}") + + except Exception as e: + logger.error(f"Error: {e}") + raise + + return 0 + + +if __name__ == "__main__": + sys.exit(main(sys.argv[1:])) diff --git a/tools/rdkit/test-data/output_cosine_maccs.tsv b/tools/rdkit/test-data/output_cosine_maccs.tsv new file mode 100644 index 000000000..2e4062638 --- /dev/null +++ b/tools/rdkit/test-data/output_cosine_maccs.tsv @@ -0,0 +1,11 @@ +similarity query_structure reference_structure +1.0 CC(=O)Oc1ccccc1C(=O)O CC(=O)Oc1ccccc1C(O)=O +0.6900655593423543 CC(=O)Oc1ccccc1C(=O)O Cc1ccc(cc1)C(=O)O +0.6900655593423543 Cc1ccc(C(=O)O)cc1 CC(=O)Oc1ccccc1C(O)=O +1.0 Cc1ccc(C(=O)O)cc1 Cc1ccc(cc1)C(=O)O +0.6172133998483676 CC(C)Cc1ccccc1C(C)C(=O)O CC(=O)Oc1ccccc1C(O)=O +0.7453559924999299 CC(C)Cc1ccccc1C(C)C(=O)O Cc1ccc(cc1)C(=O)O +0.4504426164614508 Cn1c(=O)c2c(ncn2C)n(C)c1=O CC(=O)Oc1ccccc1C(O)=O +0.3263766828841098 Cn1c(=O)c2c(ncn2C)n(C)c1=O Cc1ccc(cc1)C(=O)O +0.6900655593423543 Oc1ccccc1 CC(=O)Oc1ccccc1C(O)=O +0.6 Oc1ccccc1 Cc1ccc(cc1)C(=O)O diff --git a/tools/rdkit/test-data/output_dice_rdkit.tsv b/tools/rdkit/test-data/output_dice_rdkit.tsv new file mode 100644 index 000000000..79af9fa65 --- /dev/null +++ b/tools/rdkit/test-data/output_dice_rdkit.tsv @@ -0,0 +1,6 @@ +similarity query_structure reference_structure +1.0 InChI=1S/C9H8O4/c1-6(10)13-8-5-3-2-4-7(8)9(11)12/h2-5H,1H3,(H,11,12) CC(=O)Oc1ccccc1C(=O)O +0.44258872651356995 InChI=1S/C9H8O4/c1-6(10)13-8-5-3-2-4-7(8)9(11)12/h2-5H,1H3,(H,11,12) Cc1ccc(C(=O)O)cc1 +0.44145873320537427 InChI=1S/C9H8O4/c1-6(10)13-8-5-3-2-4-7(8)9(11)12/h2-5H,1H3,(H,11,12) O=C(O)c1cccc(C(=O)O)c1 +0.2978723404255319 InChI=1S/C9H8O4/c1-6(10)13-8-5-3-2-4-7(8)9(11)12/h2-5H,1H3,(H,11,12) CN(C)C(=O)c1ccccc1 +0.45414847161572053 InChI=1S/C9H8O4/c1-6(10)13-8-5-3-2-4-7(8)9(11)12/h2-5H,1H3,(H,11,12) O=C(O)c1ccccc1 diff --git a/tools/rdkit/test-data/output_tanimoto_morgan.tsv b/tools/rdkit/test-data/output_tanimoto_morgan.tsv new file mode 100644 index 000000000..dd75371f3 --- /dev/null +++ b/tools/rdkit/test-data/output_tanimoto_morgan.tsv @@ -0,0 +1,26 @@ +similarity query_structure reference_structure +1.0 CC(=O)Oc1ccccc1C(=O)O CC(=O)Oc1ccccc1C(=O)O +0.28125 CC(=O)Oc1ccccc1C(=O)O Cc1ccc(C(=O)O)cc1 +0.2903225806451613 CC(=O)Oc1ccccc1C(=O)O O=C(O)c1cccc(C(=O)O)c1 +0.30303030303030304 CC(=O)Oc1ccccc1C(=O)O CN(C)C(=O)c1ccccc1 +0.35714285714285715 CC(=O)Oc1ccccc1C(=O)O O=C(O)c1ccccc1 +0.28125 Cc1ccc(C(=O)O)cc1 CC(=O)Oc1ccccc1C(=O)O +1.0 Cc1ccc(C(=O)O)cc1 Cc1ccc(C(=O)O)cc1 +0.43478260869565216 Cc1ccc(C(=O)O)cc1 O=C(O)c1cccc(C(=O)O)c1 +0.3333333333333333 Cc1ccc(C(=O)O)cc1 CN(C)C(=O)c1ccccc1 +0.55 Cc1ccc(C(=O)O)cc1 O=C(O)c1ccccc1 +0.24390243902439024 CC(C)Cc1ccccc1C(C)C(=O)O CC(=O)Oc1ccccc1C(=O)O +0.2222222222222222 CC(C)Cc1ccccc1C(C)C(=O)O Cc1ccc(C(=O)O)cc1 +0.22857142857142856 CC(C)Cc1ccccc1C(C)C(=O)O O=C(O)c1cccc(C(=O)O)c1 +0.2777777777777778 CC(C)Cc1ccccc1C(C)C(=O)O CN(C)C(=O)c1ccccc1 +0.28125 CC(C)Cc1ccccc1C(C)C(=O)O O=C(O)c1ccccc1 +0.08888888888888889 Cn1c(=O)c2c(ncn2C)n(C)c1=O CC(=O)Oc1ccccc1C(=O)O +0.10526315789473684 Cn1c(=O)c2c(ncn2C)n(C)c1=O Cc1ccc(C(=O)O)cc1 +0.07894736842105263 Cn1c(=O)c2c(ncn2C)n(C)c1=O O=C(O)c1cccc(C(=O)O)c1 +0.1 Cn1c(=O)c2c(ncn2C)n(C)c1=O CN(C)C(=O)c1ccccc1 +0.08333333333333333 Cn1c(=O)c2c(ncn2C)n(C)c1=O O=C(O)c1ccccc1 +0.25 Oc1ccccc1 CC(=O)Oc1ccccc1C(=O)O +0.21739130434782608 Oc1ccccc1 Cc1ccc(C(=O)O)cc1 +0.2857142857142857 Oc1ccccc1 O=C(O)c1cccc(C(=O)O)c1 +0.30434782608695654 Oc1ccccc1 CN(C)C(=O)c1ccccc1 +0.3888888888888889 Oc1ccccc1 O=C(O)c1ccccc1 diff --git a/tools/rdkit/test-data/queries.inchi b/tools/rdkit/test-data/queries.inchi new file mode 100644 index 000000000..efe1f68a5 --- /dev/null +++ b/tools/rdkit/test-data/queries.inchi @@ -0,0 +1,2 @@ +InChI=1S/C9H8O4/c1-6(10)13-8-5-3-2-4-7(8)9(11)12/h2-5H,1H3,(H,11,12) +InChI=1S/C8H8O2/c1-7(9)5-6-8(2)10/h5-6H,1H3,(H,9,10) \ No newline at end of file diff --git a/tools/rdkit/test-data/queries.sdf b/tools/rdkit/test-data/queries.sdf new file mode 100644 index 000000000..86d9cce93 --- /dev/null +++ b/tools/rdkit/test-data/queries.sdf @@ -0,0 +1,149 @@ +Aspirin + RDKit 2D + + 13 13 0 0 0 0 0 0 0 0999 V2000 + 5.2500 -1.2990 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.7500 -1.2990 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.0000 -2.5981 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 3.0000 0.0000 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 1.5000 0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.7500 -1.2990 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -0.7500 -1.2990 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -1.5000 0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -0.7500 1.2990 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.7500 1.2990 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1.5000 2.5981 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.0000 2.5981 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 0.7500 3.8971 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 1 2 1 0 + 2 3 2 0 + 2 4 1 0 + 4 5 1 0 + 5 6 2 0 + 6 7 1 0 + 7 8 2 0 + 8 9 1 0 + 9 10 2 0 + 10 11 1 0 + 11 12 1 0 + 11 13 2 0 + 10 5 1 0 +M END +$$$$ +p-Toluenecarboxylic acid + RDKit 2D + + 10 10 0 0 0 0 0 0 0 0999 V2000 + 3.0000 0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1.5000 0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.7500 -1.2990 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -0.7500 -1.2990 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -1.5000 0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -0.7500 1.2990 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.7500 1.2990 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -3.0000 0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -3.7500 -1.2990 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + -3.7500 1.2990 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 1 2 1 0 + 2 3 1 0 + 3 4 2 0 + 4 5 1 0 + 5 6 2 0 + 6 7 1 0 + 5 8 1 0 + 8 9 2 0 + 8 10 1 0 + 7 2 2 0 +M END +$$$$ +Ibuprofen + RDKit 2D + + 15 15 0 0 0 0 0 0 0 0999 V2000 + 5.2500 -1.2990 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.7500 -1.2990 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.0000 -2.5981 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.0000 0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1.5000 0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.7500 -1.2990 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -0.7500 -1.2990 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -1.5000 0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -0.7500 1.2990 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.7500 1.2990 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1.5000 2.5981 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.7500 3.8971 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.0000 2.5981 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.7500 3.8971 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 3.7500 1.2990 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 1 2 1 0 + 2 3 1 0 + 2 4 1 0 + 4 5 1 0 + 5 6 2 0 + 6 7 1 0 + 7 8 2 0 + 8 9 1 0 + 9 10 2 0 + 10 11 1 0 + 11 12 1 0 + 11 13 1 0 + 13 14 1 0 + 13 15 2 0 + 10 5 1 0 +M END +$$$$ +Caffeine + RDKit 2D + + 14 15 0 0 0 0 0 0 0 0999 V2000 + 2.7760 0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1.2760 0.0000 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 + 0.3943 1.2135 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -1.0323 0.7500 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 + -1.0323 -0.7500 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.3943 -1.2135 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.7062 -2.6807 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.1328 -3.1443 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + -0.4086 -3.6844 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 + -1.8351 -3.2209 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -2.9499 -4.2246 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + -2.1470 -1.7537 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 + -3.5736 -1.2902 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -0.0967 -5.1517 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1 2 1 0 + 2 3 1 0 + 3 4 2 0 + 4 5 1 0 + 5 6 2 0 + 6 7 1 0 + 7 8 2 0 + 7 9 1 0 + 9 10 1 0 + 10 11 2 0 + 10 12 1 0 + 12 13 1 0 + 9 14 1 0 + 6 2 1 0 + 12 5 1 0 +M END +$$$$ +Phenol + RDKit 2D + + 7 7 0 0 0 0 0 0 0 0999 V2000 + 1.5000 0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.7500 -1.2990 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -0.7500 -1.2990 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -1.5000 0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -0.7500 1.2990 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.7500 1.2990 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -3.0000 0.0000 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 1 2 2 0 + 2 3 1 0 + 3 4 2 0 + 4 5 1 0 + 5 6 2 0 + 4 7 1 0 + 6 1 1 0 +M END +$$$$ diff --git a/tools/rdkit/test-data/references.sdf b/tools/rdkit/test-data/references.sdf new file mode 100644 index 000000000..74ee0f005 --- /dev/null +++ b/tools/rdkit/test-data/references.sdf @@ -0,0 +1,140 @@ +Aspirin + RDKit 2D + + 13 13 0 0 0 0 0 0 0 0999 V2000 + 5.2500 -1.2990 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.7500 -1.2990 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.0000 -2.5981 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 3.0000 0.0000 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 1.5000 0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.7500 -1.2990 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -0.7500 -1.2990 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -1.5000 0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -0.7500 1.2990 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.7500 1.2990 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1.5000 2.5981 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.0000 2.5981 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 0.7500 3.8971 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 1 2 1 0 + 2 3 2 0 + 2 4 1 0 + 4 5 1 0 + 5 6 2 0 + 6 7 1 0 + 7 8 2 0 + 8 9 1 0 + 9 10 2 0 + 10 11 1 0 + 11 12 1 0 + 11 13 2 0 + 10 5 1 0 +M END +$$$$ +p-Toluenecarboxylic acid + RDKit 2D + + 10 10 0 0 0 0 0 0 0 0999 V2000 + 3.0000 0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1.5000 0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.7500 -1.2990 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -0.7500 -1.2990 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -1.5000 0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -0.7500 1.2990 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.7500 1.2990 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -3.0000 0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -3.7500 -1.2990 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + -3.7500 1.2990 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 1 2 1 0 + 2 3 1 0 + 3 4 2 0 + 4 5 1 0 + 5 6 2 0 + 6 7 1 0 + 5 8 1 0 + 8 9 2 0 + 8 10 1 0 + 7 2 2 0 +M END +$$$$ +Phthalic acid + RDKit 2D + + 12 12 0 0 0 0 0 0 0 0999 V2000 + 3.7500 1.2990 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 3.0000 0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.7500 -1.2990 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 1.5000 0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.7500 -1.2990 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -0.7500 -1.2990 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -1.5000 0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -0.7500 1.2990 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.7500 1.2990 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -1.5000 2.5981 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -3.0000 2.5981 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + -0.7500 3.8971 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 1 2 2 0 + 2 3 1 0 + 2 4 1 0 + 4 5 1 0 + 5 6 2 0 + 6 7 1 0 + 7 8 2 0 + 8 9 1 0 + 8 10 1 0 + 10 11 2 0 + 10 12 1 0 + 9 4 2 0 +M END +$$$$ +N,N-Dimethylbenzamide + RDKit 2D + + 11 11 0 0 0 0 0 0 0 0999 V2000 + 5.2500 -1.2990 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.7500 -1.2990 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 + 3.0000 -2.5981 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.0000 0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.7500 1.2990 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 1.5000 0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.7500 -1.2990 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -0.7500 -1.2990 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -1.5000 0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -0.7500 1.2990 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.7500 1.2990 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1 2 1 0 + 2 3 1 0 + 2 4 1 0 + 4 5 2 0 + 4 6 1 0 + 6 7 2 0 + 7 8 1 0 + 8 9 2 0 + 9 10 1 0 + 10 11 2 0 + 11 6 1 0 +M END +$$$$ +Benzoic acid + RDKit 2D + + 9 9 0 0 0 0 0 0 0 0999 V2000 + 1.5000 0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.7500 -1.2990 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -0.7500 -1.2990 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -1.5000 0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -0.7500 1.2990 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.7500 1.2990 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -1.5000 -2.5981 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -0.7500 -3.8971 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + -3.0000 -2.5981 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 1 2 1 0 + 2 3 2 0 + 3 4 1 0 + 4 5 2 0 + 5 6 1 0 + 3 7 1 0 + 7 8 2 0 + 7 9 1 0 + 6 1 2 0 +M END +$$$$ diff --git a/tools/rdkit/test-data/references.smi b/tools/rdkit/test-data/references.smi new file mode 100644 index 000000000..fc06e3e88 --- /dev/null +++ b/tools/rdkit/test-data/references.smi @@ -0,0 +1,2 @@ +CC(=O)Oc1ccccc1C(O)=O +Cc1ccc(cc1)C(=O)O \ No newline at end of file From 5f8923c65949f002a7f8f8f5e579346de8f3538b Mon Sep 17 00:00:00 2001 From: hechth Date: Wed, 8 Jul 2026 13:48:07 +0200 Subject: [PATCH 2/3] updated shed.yml file --- tools/rdkit/.shed.yml | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/tools/rdkit/.shed.yml b/tools/rdkit/.shed.yml index abb882f13..ec638a1c1 100644 --- a/tools/rdkit/.shed.yml +++ b/tools/rdkit/.shed.yml @@ -1,12 +1,20 @@ -name: rdkit_structsim +name: rdkit +owner: recetox +remote_repository_url: "https://github.com/RECETOX/galaxytools/tree/master/tools/rdkit" +homepage_url: "https://www.rdkit.org" +categories: + - Cheminformatics + - Similarity Search description: Calculate structural similarity using RDKit fingerprints from SMILES/InChI/SDF files long_description: | This tool calculates structural similarity between compounds using RDKit molecular fingerprints. It accepts SMILES (.smi), InChI (.inchi), or SDF (.sdf) files and supports multiple fingerprint types (Morgan, RDKit, MACCS) and similarity metrics (Tanimoto, Dice, Cosine, Soergel, Kulczynski, McConnaughey). -categories: - - Cheminformatics - - Similarity Search -owner: hechth -license: MIT +auto_tool_repositories: + name_template: "{{ tool_id }}" + description_template: "{{ tool_name }} tool from the RDKit package" +suite: + name: suite_rdkit + description: Calculate structural similarity using RDKit fingerprints from SMILES/InChI/SDF files + type: repository_suite_definition From ffc159963a75a29f5d7559514db3afdca7b1fffe Mon Sep 17 00:00:00 2001 From: Michaela Bodova <505814@muni.cz> Date: Wed, 8 Jul 2026 14:59:19 +0200 Subject: [PATCH 3/3] Modify categories in .shed.yml Updated categories to include 'Computational chemistry' and removed 'Cheminformatics' and 'Similarity Search'. --- tools/rdkit/.shed.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tools/rdkit/.shed.yml b/tools/rdkit/.shed.yml index ec638a1c1..193e16b4d 100644 --- a/tools/rdkit/.shed.yml +++ b/tools/rdkit/.shed.yml @@ -3,8 +3,7 @@ owner: recetox remote_repository_url: "https://github.com/RECETOX/galaxytools/tree/master/tools/rdkit" homepage_url: "https://www.rdkit.org" categories: - - Cheminformatics - - Similarity Search + - Computational chemistry description: Calculate structural similarity using RDKit fingerprints from SMILES/InChI/SDF files long_description: | This tool calculates structural similarity between compounds using RDKit molecular