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/-ylidyne prefix to use verbatim - ‘unnameable’: True – the consumer MUST decline the whole parent

note. carbon_count alone cannot tell -CH3 from =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=C1CC2CCC1C2 came out as 2-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