Skip to content

Use rdkit for SSSR and RCs (bug fix + Python upgrade) #2796

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
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
2 changes: 1 addition & 1 deletion .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["3.9"]
python-version: ["3.9", "3.10", "3.11", "3.12"]
os: [macos-13, macos-latest, ubuntu-latest]
include-rms: ["", "with RMS"]
exclude:
Expand Down
1 change: 0 additions & 1 deletion environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@ dependencies:
# bug in quantities, see:
# https://github.com/ReactionMechanismGenerator/RMG-Py/pull/2694#issuecomment-2489286263
- conda-forge::quantities !=0.16.0,!=0.16.1
- conda-forge::ringdecomposerlib-python

# packages we maintain
- rmg::pydas >=1.0.3
Expand Down
107 changes: 48 additions & 59 deletions rmgpy/molecule/graph.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ are the components of a graph.

import itertools

import py_rdl
from rdkit import Chem

from rmgpy.molecule.vf2 cimport VF2

Expand Down Expand Up @@ -971,68 +971,57 @@ cdef class Graph(object):

cpdef list get_smallest_set_of_smallest_rings(self):
"""
Returns the smallest set of smallest rings as a list of lists.
Uses RingDecomposerLib for ring perception.

Kolodzik, A.; Urbaczek, S.; Rarey, M.
Unique Ring Families: A Chemically Meaningful Description
of Molecular Ring Topologies.
J. Chem. Inf. Model., 2012, 52 (8), pp 2013-2021

Flachsenberg, F.; Andresen, N.; Rarey, M.
RingDecomposerLib: An Open-Source Implementation of
Unique Ring Families and Other Cycle Bases.
J. Chem. Inf. Model., 2017, 57 (2), pp 122-126
"""
cdef list sssr
cdef object graph, data, cycle

graph = py_rdl.Graph.from_edges(
self.get_all_edges(),
_get_edge_vertex1,
_get_edge_vertex2,
)

data = py_rdl.wrapper.DataInternal(graph.get_nof_nodes(), graph.get_edges().keys())
data.calculate()

sssr = []
for cycle in data.get_sssr():
sssr.append(self.sort_cyclic_vertices([graph.get_node_for_index(i) for i in cycle.nodes]))

Returns the smallest set of smallest rings (SSSR) as a list of lists of atom indices.
Uses RDKit's built-in ring perception (GetSymmSSSR).

References:
Kolodzik, A.; Urbaczek, S.; Rarey, M.
Unique Ring Families: A Chemically Meaningful Description
of Molecular Ring Topologies.
J. Chem. Inf. Model., 2012, 52 (8), pp 2013-2021

Flachsenberg, F.; Andresen, N.; Rarey, M.
RingDecomposerLib: An Open-Source Implementation of
Unique Ring Families and Other Cycle Bases.
J. Chem. Inf. Model., 2017, 57 (2), pp 122-126
"""
cdef list sssr = []
cdef object ring_info, ring
# Get the symmetric SSSR using RDKit
ring_info = Chem.GetSymmSSSR(self)
for ring in ring_info:
# Convert ring (tuple of atom indices) to sorted list
sorted_ring = self.sort_cyclic_vertices(list(ring))
sssr.append(sorted_ring)
return sssr

cpdef list get_relevant_cycles(self):
"""
Returns the set of relevant cycles as a list of lists.
Uses RingDecomposerLib for ring perception.

Kolodzik, A.; Urbaczek, S.; Rarey, M.
Unique Ring Families: A Chemically Meaningful Description
of Molecular Ring Topologies.
J. Chem. Inf. Model., 2012, 52 (8), pp 2013-2021

Flachsenberg, F.; Andresen, N.; Rarey, M.
RingDecomposerLib: An Open-Source Implementation of
Unique Ring Families and Other Cycle Bases.
J. Chem. Inf. Model., 2017, 57 (2), pp 122-126
"""
cdef list rc
cdef object graph, data, cycle

graph = py_rdl.Graph.from_edges(
self.get_all_edges(),
_get_edge_vertex1,
_get_edge_vertex2,
)

data = py_rdl.wrapper.DataInternal(graph.get_nof_nodes(), graph.get_edges().keys())
data.calculate()

rc = []
for cycle in data.get_rcs():
rc.append(self.sort_cyclic_vertices([graph.get_node_for_index(i) for i in cycle.nodes]))

Returns the set of relevant cycles as a list of lists of atom indices.
Uses RDKit's RingInfo to approximate relevant cycles.

References:
Kolodzik, A.; Urbaczek, S.; Rarey, M.
Unique Ring Families: A Chemically Meaningful Description
of Molecular Ring Topologies.
J. Chem. Inf. Model., 2012, 52 (8), pp 2013-2021

Flachsenberg, F.; Andresen, N.; Rarey, M.
RingDecomposerLib: An Open-Source Implementation of
Unique Ring Families and Other Cycle Bases.
J. Chem. Inf. Model., 2017, 57 (2), pp 122-126
"""
cdef list rc = []
cdef object mol = self
cdef object ring_info = mol.GetRingInfo()
cdef object atom_rings = ring_info.AtomRings()
cdef object ring
for ring in atom_rings:
# Convert ring (tuple of atom indices) to sorted list
sorted_ring = self.sort_cyclic_vertices(list(ring))
# Filter for "relevant" cycles (e.g., rings up to size 7)
if len(sorted_ring) <= 7:
rc.append(sorted_ring)
return rc

cpdef list sort_cyclic_vertices(self, list vertices):
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@
author='William H. Green and the RMG Team',
author_email='[email protected]',
url='http://reactionmechanismgenerator.github.io',
python_requires='>=3.9,<3.10',
python_requires='>=3.9,<3.13',
packages=find_packages(where='.', include=["rmgpy*"]) + find_packages(where='.', include=["arkane*"]),
scripts=scripts,
include_package_data=True,
Expand Down
17 changes: 0 additions & 17 deletions utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ def check_dependencies():
missing = {
'openbabel': _check_openbabel(),
'pydqed': _check_pydqed(),
'pyrdl': _check_pyrdl(),
'rdkit': _check_rdkit(),
'symmetry': _check_symmetry(),
}
Expand Down Expand Up @@ -104,22 +103,6 @@ def _check_pydqed():
return missing


def _check_pyrdl():
"""Check for pyrdl"""
missing = False

try:
import py_rdl
except ImportError:
print('{0:<30}{1}'.format('pyrdl', 'Not found. Necessary for ring perception algorithms.'))
missing = True
else:
location = py_rdl.__file__
print('{0:<30}{1}'.format('pyrdl', location))

return missing


def _check_rdkit():
"""Check for RDKit"""
missing = False
Expand Down
Loading