Skip to main content

Hierarchical molecular identity comparison framework for untargeted metabolomics

Project description

inchi-identity

A hierarchical molecular identity comparison framework for untargeted metabolomics, implemented as a Python CLI and published on PyPI.

Instead of binary exact matching, this tool evaluates molecular equivalence across six progressive normalization layers, returning a structured equivalence profile that reflects the structural resolution actually supported by the experimental evidence. For lipids, a dedicated four-level hierarchy (Levels A–D) addresses cis/trans geometry, sn-position, intra-chain double bond position, and global sum composition.

Both InChI strings and SMILES are accepted as input — SMILES are automatically converted to canonical InChI before comparison.


Comparison Layers

Layer Name Description
1 Complete Identity Exact InChI string equality
2 Isotopic Independence Equality after /i layer removal
3 Salt Independence Equality after counterion removal (RDKit SaltRemover)
4 Charge Independence Equality after charge/protonation normalization
5 Stereochemical/Isomeric Independence Levels A–D (see below)
6 Tautomeric Independence Equality after canonical tautomer generation

Preprocessing is cumulative: each layer applies all normalizations from preceding layers before performing its own comparison.

Lipid hierarchy (Layer 5, Levels A–D)

For molecules classified as lipids, Layer 5 applies a four-level structural abstraction cascade. Level A applies to all molecule types; Levels B–D apply to lipids only.

Level Name Description
A Cis/Trans Independence Removes /b double-bond geometry layer
B sn-Position Independence Compares acyl chains as an unordered set
C Intra-Chain Position Independence Discards double bond and substituent positions within each chain
D Global Composition Retains only total carbon count and double bond count across the whole molecule

Lipid classification uses the ClassyFire API, with an RDKit-based heuristic fallback. Headgroup validation uses a library of 295 SMARTS patterns (40 manually curated + 255 generated at runtime by combining 15 glycolipid templates with 17 monosaccharide patterns).


Installation

RDKit must be installed via conda before installing this package:

git clone https://github.com/alejandraoshea/identity-levels-inchi.git
cd identity-levels-inchi
conda env create -f conda_env.yml
conda activate inchi-identity
pip install -e .

Or install directly from PyPI:

pip install inchi-identity

Verify the installation:

inchi --help

InChI Trust executable (optional, required for Layer 6)

Layer 6 uses the InChI Trust executable for canonical tautomer generation. Download it from https://www.inchi-trust.org/downloads/ and set the path:

export INCHITRUST_PATH=/path/to/inchi-1

If the executable is not available, Layer 6 automatically falls back to RDKit's TautomerEnumerator.


CLI Usage

Mode 1 — Compare two structures across all layers

inchi compare-pair "<inchi_1>" "<inchi_2>"
inchi compare-pair "<inchi_1>" "<inchi_2>" > result.json

SMILES are also accepted:

inchi compare-pair "CC(=O)O" "CC(=O)[O-].[Na+]"

Mode 2 — Compare with selected layers only

inchi compare-pair-layers "<inchi_1>" "<inchi_2>" \
    --layers isotope charge double_bond tautomer

Available layer names: isotope, salt, charge, double_bond, tautomer

Mode 3 — File-based comparison

Input files contain one InChI or SMILES per line. SMILES and InChI can be mixed.

Pairwise (entry i from file 1 vs entry i from file 2):

inchi compare file1.txt file2.txt > result_pairwise.json

Cross-comparison (all vs all, n×m pairs):

inchi compare file1.txt file2.txt --mode cross > result_cross.json

Filter to equivalent pairs only (works with both modes):

inchi compare file1.txt file2.txt --only-equal
inchi compare file1.txt file2.txt --mode cross --only-equal

When --only-equal is active, the output key changes from results to matches and only layers that evaluated to true are included.

Mode 4 — MGF spectral library unification

Normalizes molecular identifiers embedded in two MGF files at a chosen equivalence layer, producing a unified MGF file and a JSON change log. InChI and SMILES identifiers are detected automatically per entry.

inchi compare-mgf file1.mgf file2.mgf \
    --layer CHARGES_INDEPENDENCE \
    --output-mgf unified.mgf \
    --output-log unified_log.json

Available --layer values:

COMPLETE_IDENTITY
ISOTOPIC_INDEPENDENCE
SALTS_INDEPENDENCE
CHARGES_INDEPENDENCE
DOUBLE_BONDS_INDEPENDENCE
STEREOCHEMICAL_CIS_TRANS_INDEPENDENCE
TAUTOMER_INDEPENDENCE

The pipeline: (1) parses both files and extracts identifiers, (2) internally normalizes each file so equivalent entries share a canonical InChI, (3) performs a cross-file comparison and replaces identifiers in file 2 with the canonical form from file 1, (4) writes the unified MGF and a JSON log recording every transformation. Entries without identifiers and all spectral peak data are preserved unchanged.


Output format

Pairwise / file comparison

{
    "inchi_1": "InChI=1S/C5H11NO2/c1-6(2,3)4-5(7)8/h4H2,1-3H3/p+1",
    "inchi_2": "InChI=1S/C5H11NO2/c1-6(2,3)4-5(7)8/h4H2,1-3H3",
    "results": {
        "COMPLETE_IDENTITY": false,
        "ISOTOPIC_INDEPENDENCE": false,
        "SALTS_INDEPENDENCE": false,
        "CHARGES_INDEPENDENCE": true,
        "DOUBLE_BONDS_INDEPENDENCE": false,
        "STEREOCHEMICAL_CIS_TRANS_INDEPENDENCE": false,
        "TAUTOMER_INDEPENDENCE": false
    }
}

With --only-equal

Only layers that evaluated to true are shown, under the matches key:

{
    "inchi_1": "InChI=1S/C5H11NO2/c1-6(2,3)4-5(7)8/h4H2,1-3H3/p+1",
    "inchi_2": "InChI=1S/C5H11NO2/c1-6(2,3)4-5(7)8/h4H2,1-3H3",
    "matches": {
        "CHARGES_INDEPENDENCE": true
    }
}

MGF change log

{
    "layer": "CHARGES_INDEPENDENCE",
    "total_changes": 3,
    "changes": [
        {
            "original_structure": "InChI=1S/C10H16N5O13P3/...p-1/t4-,6-,7-,10-/m1/s1",
            "structure_type": "INCHI",
            "smiles_to_inchi": null,
            "normalized_inchi": "InChI=1S/C10H16N5O13P3/.../t4-,6-,7-,10-/m1/s1",
            "canonical_inchi":  "InChI=1S/C10H16N5O13P3/.../t4-,6-,7-,10-/m1/s1"
        }
    ]
}

For SMILES entries, smiles_to_inchi contains the intermediate InChI produced by conversion. normalized_inchi is null when no charge layer was removed (only a SMILES→InChI conversion was performed).


Example files

The files_examples/ directory contains ready-to-use input files and expected outputs for all four comparison modes, including InChI files, SMILES files, and MGF files covering salt normalization, charge normalization, and SMILES-in-MGF cases.


Related repositories

Repository Description
inchi-identity-api Flask REST backend exposing the same comparison engine via HTTP endpoints
inchi-identity-app Interactive web frontend for browser-based comparison, file upload, and molecular visualization

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

inchi_identity-0.2.2.tar.gz (101.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

inchi_identity-0.2.2-py3-none-any.whl (35.1 kB view details)

Uploaded Python 3

File details

Details for the file inchi_identity-0.2.2.tar.gz.

File metadata

  • Download URL: inchi_identity-0.2.2.tar.gz
  • Upload date:
  • Size: 101.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.11

File hashes

Hashes for inchi_identity-0.2.2.tar.gz
Algorithm Hash digest
SHA256 6524a8a57d18c155470dabc79c6ca41274de2690839cbb557d21d2e44194a1c4
MD5 734026e0cb898310ff751adab667b692
BLAKE2b-256 8b319ac4672edfa0902519dca09b95f7a51785b45984a6b28977617aeb2712f5

See more details on using hashes here.

File details

Details for the file inchi_identity-0.2.2-py3-none-any.whl.

File metadata

  • Download URL: inchi_identity-0.2.2-py3-none-any.whl
  • Upload date:
  • Size: 35.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.11

File hashes

Hashes for inchi_identity-0.2.2-py3-none-any.whl
Algorithm Hash digest
SHA256 2b2e40271effb9c4d6a895de7714d019619867452a83000ed0de6021d35cd913
MD5 1716275349e8f23fa1ba34bad7d68540
BLAKE2b-256 0f2fbdf3f90d1e6c23d2490d67f6cebf5d67bee92fa294f560add8961f896cc2

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page