diff --git a/tools/rdkit/.shed.yml b/tools/rdkit/.shed.yml new file mode 100644 index 000000000..193e16b4d --- /dev/null +++ b/tools/rdkit/.shed.yml @@ -0,0 +1,19 @@ +name: rdkit +owner: recetox +remote_repository_url: "https://github.com/RECETOX/galaxytools/tree/master/tools/rdkit" +homepage_url: "https://www.rdkit.org" +categories: + - 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 + 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). +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 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