Get aromatic rings#

Preparing ring participants from declared aromatic chemistry.

This experimental tool prepares chemical participants for later geometric calculations. It uses explicitly stored atom and bond aromaticity, without guessing it from planarity or residue names.

Added in version 1.0.0.

Basic usage#

Let us use a synthetic six-atom ring with explicit covalent and aromatic flags. We declare its supplied connectivity complete for this demonstration; the operation does not reconstruct missing chemistry.

import molsysmt as msm
import pandas as pd
from molsysmt.native import Topology

# A synthetic ring graph with explicitly supplied chemical flags.
molsys = Topology(n_atoms=6)
molsys.atoms['atom_type'] = ['C'] * 6
molsys.bonds = pd.DataFrame({
    'atom1_index': [0, 1, 2, 3, 4, 5],
    'atom2_index': [1, 2, 3, 4, 5, 0],
    'bond_type': ['covalent'] * 6,
    'is_aromatic': [True] * 6,
})
msm.set(molsys, element='atom', atom_is_aromatic=[True] * 6)
rings = msm.physchem.get_aromatic_rings(molsys, assume_complete_connectivity=True)
rings['atom_indices'], rings['atom_offsets']
(array([0, 1, 2, 3, 4, 5]), array([0, 6]))

Sparse memberships#

The offsets delimit complete participants in one int64 atom-index array. Each membership is sorted, without cyclic traversal order. These are source indices, not atom IDs. Empty results use a (0,) array and offsets [0]. Recognition examines the entire graph before filtering, and rejects a selection that intersects only part of a ring.

selected = msm.physchem.get_aromatic_rings(
    molsys, selection=[5, 4, 3, 2, 1, 0, 0],
    assume_complete_connectivity=True)
assert selected['selection_atom_indices'].tolist() == list(range(6))
empty = msm.physchem.get_aromatic_rings(molsys, selection=[], assume_complete_connectivity=True)
assert empty['atom_indices'].shape == (0,)
assert empty['atom_offsets'].tolist() == [0]

Chemical state and limits#

Choose chemical_state explicitly when several states exist. The chosen state is recorded and the reference state remains unchanged. H5MSM 0.5 index selections read chemistry without coordinates or saved analyses. Load the system explicitly before using spatial selections.

The unweighted minimum cycle basis is experimental. Tied bases need not be unique or preserve molecular symmetry; reordering atoms can change the chosen basis. A cyclic biconnected block above max_cyclic_block_size=256 raises before the basis calculation. Acyclic chains are unrestricted by that limit. This is a guard against large graph subproblems, not a RAM or runtime guarantee.

These functions accept any supported form delivering the required chemistry. ChemicalStates, typed ChemicalStatesDict and a topology-free MolSys can also supply the needed atom domain and chemical flags. Legacy TopologyDict/MolSysDict graphs do not preserve full aromatic metadata.

Aromatic and nonaromatic cycles#

Unknown aromatic flags cause an error; they are not interpreted as False. A nonaromatic cycle remains a ring in topology, but is not an aromatic participant. Atom flags alone cannot establish that the bonds between those atoms are aromatic.

nonaromatic = molsys.copy()
msm.set(nonaromatic, element='atom', atom_is_aromatic=[False] * 6)
msm.set(nonaromatic, element='bond', bond_is_aromatic=[False] * 6)
assert msm.physchem.get_aromatic_rings(
    nonaromatic, assume_complete_connectivity=True)['atom_offsets'].tolist() == [0]
assert msm.topology.get_rings(
    nonaromatic, assume_complete_connectivity=True)['atom_offsets'].tolist() == [0, 6]

For fused systems, perception runs on the aromatic bond subgraph. A nonaromatic fusion bond is excluded and can leave an aromatic perimeter cycle instead of individual subrings. This declared-bond basis is not RDKit SymmSSSR or a universal aromaticity model. Aromatic metadata with dangling bonds or isolated aromatic atoms is rejected. No pi–pi contacts are calculated by this tool.