orthonym.rules.bicyclo#
Note
Internal API. Names and behaviour may change between releases.
Bicyclo compound naming according to IUPAC 2013 nomenclature.
Implements bicyclo[x.y.z] descriptor generation for bridged bicyclic hydrocarbons.
IUPAC Reference: Blue Book 2013, (Bridged bicyclic hydrocarbons)
The bicyclo descriptor format is bicyclo[x.y.z] where: - x, y, z are the number of atoms in each bridge BETWEEN the bridgeheads
(i.e., path length - 2, excluding the bridgehead atoms)
Values are sorted in descending order: x >= y >= z
Total ring atoms = x + y + z + 2 (the +2 accounts for bridgehead atoms)
Examples: - Norbornane: bicyclo[2.2.1]heptane (bridges: 2, 2, 1; total: 7 carbons) - Bicyclo[2.2.2]octane (bridges: 2, 2, 2; total: 8 carbons)
- orthonym.rules.bicyclo.find_true_bridgeheads(mol)#
Find the true bridgehead atoms in a bicyclic system.
For a simple bicyclic system, bridgehead atoms are: 1. In 2 or more rings 2. Have 3 neighbors all within the ring system
This is more specific than get_bridgehead_atoms which returns all atoms in multiple rings.
- Parameters:
mol – RDKit Mol object
- Returns:
Set of atom indices that are true bridgeheads
- Return type:
Set[int]
Examples
>>> mol = Chem.MolFromSmiles('C1CC2CCC1C2') # norbornane >>> find_true_bridgeheads(mol) {2, 5} # or similar indices for the bridgehead carbons
- orthonym.rules.bicyclo.is_bicyclo_system(mol)#
Check if a molecule is a simple bicyclo (bridged) system.
A bicyclo system has: - Exactly 2 true bridgehead atoms - No spiro centers - At least 2 rings - Not an aromatic fused system (naphthalene, etc.) - Not a zero-bridge fused system (decalin, etc.)
Note: Aromatic fused systems like naphthalene are technically bicyclic (bicyclo[4.4.0]decapentaene) but IUPAC prefers their retained names. This function excludes aromatic fused systems.
Systems with a zero-length bridge (bicyclo[x.y.0]) are edge-fused and should use fused nomenclature (e.g., decahydronaphthalene).
- Parameters:
mol – RDKit Mol object
- Returns:
True if molecule is a bicyclo system suitable for bicyclo[x.y.z] naming
- Return type:
bool
Examples
>>> mol = Chem.MolFromSmiles('C1CC2CCC1C2') # norbornane >>> is_bicyclo_system(mol) True >>> mol = Chem.MolFromSmiles('C1CCCCC1') # cyclohexane >>> is_bicyclo_system(mol) False >>> mol = Chem.MolFromSmiles('c1ccc2ccccc2c1') # naphthalene (aromatic fused) >>> is_bicyclo_system(mol) False >>> mol = Chem.MolFromSmiles('C1CCC2CCCCC2C1') # decalin (zero-bridge fused) >>> is_bicyclo_system(mol) False
- orthonym.rules.bicyclo.find_bridge_paths(mol, bridgehead1, bridgehead2)#
Find all paths between two bridgehead atoms.
Uses BFS to find all simple paths between the bridgeheads. For a bicyclo system, there should be exactly 3 paths.
- Parameters:
mol – RDKit Mol object
bridgehead1 (int) – Index of first bridgehead atom
bridgehead2 (int) – Index of second bridgehead atom
- Returns:
List of paths, where each path is a list of atom indices including both bridgeheads
- Return type:
List[List[int]]
Examples
>>> mol = Chem.MolFromSmiles('C1CC2CCC1C2') # norbornane >>> bridgeheads = list(find_true_bridgeheads(mol)) >>> paths = find_bridge_paths(mol, bridgeheads[0], bridgeheads[1]) >>> len(paths) 3
- orthonym.rules.bicyclo.get_bridge_lengths(mol, bridgehead1, bridgehead2)#
Calculate the bridge lengths between two bridgehead atoms.
Bridge length = number of atoms BETWEEN bridgeheads (path length - 2). Returns lengths sorted in descending order: x >= y >= z.
- Parameters:
mol – RDKit Mol object
bridgehead1 (int) – Index of first bridgehead atom
bridgehead2 (int) – Index of second bridgehead atom
- Returns:
List of bridge lengths sorted descending
- Return type:
List[int]
Examples
>>> mol = Chem.MolFromSmiles('C1CC2CCC1C2') # norbornane >>> bridgeheads = list(find_true_bridgeheads(mol)) >>> get_bridge_lengths(mol, bridgeheads[0], bridgeheads[1]) [2, 2, 1] # bicyclo[2.2.1]
- orthonym.rules.bicyclo.generate_bicyclo_descriptor(mol)#
Generate the bicyclo[x.y.z] descriptor for a molecule.
- Parameters:
mol – RDKit Mol object
- Returns:
Descriptor string like “bicyclo[2.2.1]”, or None if not a bicyclo system
- Return type:
str | None
Examples
>>> mol = Chem.MolFromSmiles('C1CC2CCC1C2') # norbornane >>> generate_bicyclo_descriptor(mol) 'bicyclo[2.2.1]' >>> mol = Chem.MolFromSmiles('C1CC2CCC1CC2') # bicyclo[2.2.2]octane >>> generate_bicyclo_descriptor(mol) 'bicyclo[2.2.2]'
- orthonym.rules.bicyclo.name_bicyclo_system(mol)#
Generate the full IUPAC name for a bicyclo system.
Checks for retained names first, then generates systematic name.
- Parameters:
mol – RDKit Mol object
- Returns:
Full IUPAC name like “bicyclo[2.2.1]heptane” or “norbornane”, or None if not a bicyclo system
- Return type:
str | None
Examples
>>> mol = Chem.MolFromSmiles('C1CC2CCC1C2') # norbornane >>> name_bicyclo_system(mol) 'norbornane' # or 'bicyclo[2.2.1]heptane' depending on retained name preference >>> mol = Chem.MolFromSmiles('C1CC2CCC1CC2') >>> name_bicyclo_system(mol) 'bicyclo[2.2.2]octane'
- orthonym.rules.bicyclo.get_bicyclo_ring_atoms(mol)#
Get all atoms in the bicyclo ring system.
- Parameters:
mol – RDKit Mol object
- Returns:
Set of atom indices in the ring system, or None if not bicyclo
- Return type:
Set[int] | None
Examples
>>> mol = Chem.MolFromSmiles('C1CC2CCC1C2') # norbornane >>> get_bicyclo_ring_atoms(mol) {0, 1, 2, 3, 4, 5, 6}
- orthonym.rules.bicyclo.get_bicyclo_numbering(mol, suffix_ring_atoms=None)#
Generate IUPAC numbering for a bicyclo system.
suffix_ring_atoms(/ ring-construction fix): ring atoms that bear the principal characteristic group (e.g. the ring carbon double-bonded to =O of a ketone, or the ring carbon bearing an exocyclic -OH). When given, the admissible numbering that gives those atoms the lowest locants (after heteroatoms) is chosen per (c).IUPAC bicyclo numbering rules: 1. Start at one bridgehead atom (position 1) 2. Number along the longest bridge to the other bridgehead 3. Continue along the second longest bridge back toward position 1 4. Number the shortest bridge last (back to neighbors of position 1)
For bicyclo[2.2.1]heptane (norbornane): - Bridgeheads are positions 1 and 4 - Longest bridge (2 atoms): 1 -> 2 -> 3 -> 4 - Second longest (2 atoms): 4 -> 5 -> 6 -> 1 - Shortest (1 atom): 1 -> 7 -> 4
- Parameters:
mol – RDKit Mol object
- Returns:
Dict mapping atom_idx -> IUPAC locant (1-indexed), or None if not bicyclo
- Return type:
Dict[int, int] | None
Examples
>>> mol = Chem.MolFromSmiles('C1CC2CCC1C2') # norbornane >>> numbering = get_bicyclo_numbering(mol) >>> len(numbering) 7
- orthonym.rules.bicyclo.get_bicyclo_substituents(mol, ring_atoms)#
Find all substituents attached to a bicyclo ring system.
For each ring atom, finds atoms connected to it that are NOT part of the ring system. Groups substituents by their attachment point.
- Parameters:
mol – RDKit Mol object
ring_atoms (Set[int]) – Set of atom indices in the bicyclo ring
- Returns:
- Dict mapping ring_atom_idx -> list of substituent info dicts.
Each substituent dict contains: - ‘atoms’: list of atom indices in substituent - ‘carbon_count’: number of carbons in substituent - ‘attachment’: ring atom index where substituent attaches - ‘first_atom’: first atom of substituent (directly bonded to ring) and, when the attachment bond is NOT single, exactly one of: - ‘prefix_name’: the
-ylidene/-ylidyneprefix to use verbatim - ‘unnameable’: True – the consumer MUST decline the whole parent
note.
carbon_countalone cannot tell-CH3from=CH2, so a- Return type:
Dict[int, List[Dict]]
consumer that builds a prefix from it names a different molecule whenever the attachment bond is double:
C=C1CC2CCC1C2came out as2-methylbicyclo[2.2.1]heptane, which is C8H14 for a C8H12 input. The bond order is therefore read HERE, once, through the shared primitive, and the verdict is carried in the dict so every consumer inherits it rather than re-deriving it (or forgetting to).Examples
>>> mol = Chem.MolFromSmiles('CC1CC2CCC1C2') # methylnorbornane >>> ring_atoms = get_bicyclo_ring_atoms(mol) >>> subs = get_bicyclo_substituents(mol, ring_atoms) >>> # Should find methyl substituent
- orthonym.rules.bicyclo.detect_bicyclo_unsaturation(mol, ring_atoms)#
Detect double and triple bonds within a bicyclo ring system.
Scans all bonds between atoms in the ring and identifies multiple bonds.
- Parameters:
mol – RDKit Mol object
ring_atoms (Set[int]) – Set of atom indices in the bicyclo ring
- Returns:
Dict with –
‘double_bonds’: list of (atom_idx1, atom_idx2) tuples for double bonds
’triple_bonds’: list of (atom_idx1, atom_idx2) tuples for triple bonds
- Return type:
Dict
Examples
>>> mol = Chem.MolFromSmiles('C1=CC2CCC1C2') # norbornene >>> ring_atoms = get_bicyclo_ring_atoms(mol) >>> unsat = detect_bicyclo_unsaturation(mol, ring_atoms) >>> len(unsat['double_bonds']) 1
- orthonym.rules.bicyclo.get_complete_bicyclo_data(mol, suffix_ring_atoms=None)#
Generate complete bicyclo naming data including substituents and unsaturation.
This is the comprehensive data structure needed for full IUPAC naming.
- Parameters:
mol – RDKit Mol object
- Returns:
Dict with all naming data, or None if not a bicyclo system –
‘base_name’: systematic base name (e.g., ‘bicyclo[2.2.1]heptane’)
’descriptor’: bicyclo descriptor (e.g., ‘bicyclo[2.2.1]’)
’ring_atoms’: set of ring atom indices
’atom_to_locant’: dict mapping atom_idx -> IUPAC locant
’substituents’: substituent data from get_bicyclo_substituents
’unsaturation’: unsaturation data from detect_bicyclo_unsaturation
’bridgeheads’: set of bridgehead atom indices
’retained_name’: retained name if applicable, else None
- Return type:
Dict | None