orthonym.rules.fusion_descriptors#

Note

Internal API. Names and behaviour may change between releases.

Fusion descriptor generation for systematic fusion names.

Generates IUPAC fusion descriptors for naming fused ring systems when no retained name exists. Used for systematic names like benzo[a]anthracene, naphtho[2,1-b]furan, etc.

IUPAC 2013 Fusion Descriptor Rules: - Letter locants (a, b, c…) designate edges of the PARENT ring - Edge ‘a’ is between atoms 1-2, edge ‘b’ is between 2-3, etc. - Numerical locants indicate which atoms of the CHILD ring are fused - Format: child[child_locants-letter]parent (e.g., benzo[a]anthracene) - IUPAC 2013: ‘o’ in fusion prefix is NOT elided before vowels

Reference: IUPAC 2013 Blue Book, Section (Fused Ring Systems)

orthonym.rules.fusion_descriptors.get_fusion_edge(parent_ring, atom1, atom2)#

Find which edge (bond) in the parent ring is shared.

An edge is defined by two adjacent atoms in the ring. Edge numbering follows ring atom order: edge 0 is between atoms at positions 0-1, edge 1 is between positions 1-2, etc.

Parameters:
  • parent_ring (List[int]) – List of atom indices in the parent ring (ordered)

  • atom1 (int) – First shared atom index

  • atom2 (int) – Second shared atom index

Returns:

0-indexed edge number, or -1 if atoms are not adjacent in ring

Return type:

int

Examples

>>> get_fusion_edge([0, 1, 2, 3, 4, 5], 0, 1)
0
>>> get_fusion_edge([0, 1, 2, 3, 4, 5], 1, 2)
1
>>> get_fusion_edge([0, 1, 2, 3, 4, 5], 5, 0) # wraparound
5
orthonym.rules.fusion_descriptors.get_fusion_letter(parent_ring, shared_atoms)#

Get the fusion letter locant for the parent ring edge.

Converts edge index to letter: edge 0 -> ‘a’, edge 1 -> ‘b’, etc.

Parameters:
  • parent_ring (List[int]) – List of atom indices in the parent ring

  • shared_atoms (Tuple[int, int]) – Tuple of (atom1, atom2) shared between rings

Returns:

Fusion letter (‘a’, ‘b’, etc.) or empty string if edge not found

Return type:

str

Examples

>>> get_fusion_letter([0, 1, 2, 3, 4, 5], (0, 1))
'a'
>>> get_fusion_letter([0, 1, 2, 3, 4, 5], (3, 4))
'd'
orthonym.rules.fusion_descriptors.get_child_locants(child_ring, shared_atoms)#

Find positions of shared atoms in child ring numbering.

Returns positions as 1-indexed locants (IUPAC convention).

Parameters:
  • child_ring (List[int]) – List of atom indices in the child ring

  • shared_atoms (Tuple[int, int]) – Tuple of (atom1, atom2) shared between rings

Returns:

Tuple of (lower_locant, higher_locant), 1-indexed Returns (0, 0) if atoms not found

Return type:

Tuple[int, int]

Examples

>>> get_child_locants([0, 1, 2, 3, 4], (3, 4))
(4, 5)
>>> get_child_locants([6, 7, 8, 9, 10], (6, 7))
(1, 2)
orthonym.rules.fusion_descriptors.generate_fusion_descriptor(parent_ring, child_ring, shared_atoms, child_is_benzene=False)#

Generate the fusion descriptor [num,num-letter] format.

Child locants are ordered according to IUPAC convention: the child position bonded to the lower-numbered parent edge atom is listed first, then the child position bonded to the higher-numbered parent edge atom. This can produce ascending [2,3-b] or descending [3,2-b] depending on the relative orientation of parent and child numbering.

For benzene as child (all positions equivalent), child locants are omitted and only the edge letter is used: [b] instead of [1,2-b].

Parameters:
  • parent_ring (List[int]) – List of atom indices in the parent ring (IUPAC order)

  • child_ring (List[int]) – List of atom indices in the child ring (IUPAC order)

  • shared_atoms (Set[int]) – Set of atom indices shared between rings

  • child_is_benzene (bool) – If True, omit child locants (all equivalent)

Returns:

Fusion descriptor string like “[3,2-b]” or “[b]” for benzene child Returns empty string if descriptor cannot be generated

Return type:

str

Examples

>>> generate_fusion_descriptor([0,1,2,3,4,5], [6,7,8,9,10], {0,1})
'[1,2-a]'
orthonym.rules.fusion_descriptors.get_fusion_prefix(ring_name)#

Convert ring name to its fusion prefix form.

Uses lookup table for known rings, then applies general rules for unknown rings.

Parameters:

ring_name (str) – The name of the ring (e.g., ‘benzene’, ‘furan’)

Returns:

Fusion prefix form (e.g., ‘benzo’, ‘furo’)

Return type:

str

Examples

>>> get_fusion_prefix('benzene')
'benzo'
>>> get_fusion_prefix('naphthalene')
'naphtho'
>>> get_fusion_prefix('furan')
'furo'
>>> get_fusion_prefix('pyrrole')
'pyrrolo'
orthonym.rules.fusion_descriptors.build_systematic_fusion_name(parent_name, child_name, descriptor)#

Assemble the systematic fusion name from components.

Format: {fusion_prefix}{descriptor}{parent}

IUPAC 2013 Note: The ‘o’ in fusion prefixes (benzo, naphtho) is NOT elided before vowels (unlike some older conventions).

Parameters:
  • parent_name (str) – Name of the parent ring system

  • child_name (str) – Name of the child (fused) ring

  • descriptor (str) – Fusion descriptor (e.g., ‘[a]’, ‘[2,1-b]’)

Returns:

Complete systematic fusion name

Return type:

str

Examples

>>> build_systematic_fusion_name('anthracene', 'benzene', '[a]')
'benzo[a]anthracene'
>>> build_systematic_fusion_name('furan', 'naphthalene', '[2,1-b]')
'naphtho[2,1-b]furan'
orthonym.rules.fusion_descriptors.identify_parent_and_child(mol, ring_a, ring_b)#

Determine which ring is parent and which is child for fusion naming.

Parent selection follows IUPAC 2013 seniority: 1. Heterocyclic ring is senior to carbocyclic (regardless of size) 2. Among heterocyclic: nitrogen-containing > oxygen > sulfur 3. Among same heteroatom type: larger ring > smaller ring 4. Among same size/heteroatom: more heteroatoms > fewer

The MORE SENIOR ring is the parent (base component, appears last in name). The LESS SENIOR ring is the child (becomes the fusion prefix).

Parameters:
  • mol – RDKit Mol object

  • ring_a (Set[int]) – Set of atom indices in first ring

  • ring_b (Set[int]) – Set of atom indices in second ring

Returns:

Tuple of (parent_name, child_name, parent_ring_list, child_ring_list) Returns (‘’, ‘’, , ) if rings cannot be identified

Return type:

Tuple[str, str, List[int], List[int]]

orthonym.rules.fusion_descriptors.identify_fusion_edges(mol, parent_atoms, child_atoms)#

Find which edges of parent ring are involved in fusion with child ring.

Identifies all edges (bonds) shared between the parent and child rings. An edge is defined by two adjacent atoms that appear in both rings.

Parameters:
  • mol – RDKit Mol object

  • parent_atoms (List[int]) – List of atom indices in the parent ring (ordered)

  • child_atoms (List[int]) – List of atom indices in the child ring

Returns:

List of (edge_start, edge_end) atom index pairs for shared edges Empty list if no shared edges found

Return type:

List[Tuple[int, int]]

Examples

>>> # For benzene fused to anthracene at edge 'a' (atoms 0-1)
>>> identify_fusion_edges(mol, [0,1,2,3,4,5,6,7,8,9], [0,1,10,11,12,13])
[(0, 1)]
orthonym.rules.fusion_descriptors.edge_position_to_letter(parent_ring, edge)#

Convert an edge position in a parent ring to its IUPAC letter designator.

Edge ‘a’ is between atoms at positions 0-1 (IUPAC atoms 1-2), edge ‘b’ is between positions 1-2 (IUPAC atoms 2-3), etc.

Parameters:
  • parent_ring (List[int]) – List of atom indices in the parent ring (ordered)

  • edge (Tuple[int, int]) – Tuple of (atom1, atom2) defining the edge

Returns:

Letter designator (‘a’, ‘b’, ‘c’,…) or empty string if not found

Return type:

str

Examples

>>> edge_position_to_letter([0,1,2,3,4,5], (0, 1))
'a'
>>> edge_position_to_letter([0,1,2,3,4,5], (2, 3))
'c'
orthonym.rules.fusion_descriptors.handle_duplicate_edge_fusion(edge_letters)#

Apply primed notation when same edge letter appears multiple times.

IUPAC uses primed notation (a’, a’’, b’, etc.) when the same edge letter is used for multiple fusion points. Letters are sorted alphabetically with unprimed before primed variants.

Parameters:

edge_letters (List[str]) – List of edge letters (may have duplicates)

Returns:

List of letters with primes applied where needed, sorted canonically Order: a, b, c,… a’, b’,… a’’, b’’,…

Return type:

List[str]

Examples

>>> handle_duplicate_edge_fusion(['a', 'c'])
['a', 'c']
>>> handle_duplicate_edge_fusion(['a', 'a'])
['a', "a'"]
>>> handle_duplicate_edge_fusion(['a', 'b', 'a'])
['a', 'b', "a'"]
>>> handle_duplicate_edge_fusion(['a', 'a', 'a'])
['a', "a'", "a''"]
orthonym.rules.fusion_descriptors.format_complex_fusion(child_locants, parent_letter, multi_component=None, multi_edge=None)#

Format fusion descriptor for various complexity levels.

Handles three types of fusion descriptors: 1. Standard: [2,3-b] - single fusion with child locants and parent letter 2. Multi-component: [a,c] - multiple same-type rings fused to parent 3. Multi-edge: [1,2-a:4,5-b’] - complex fusions with multiple edges

Parameters:
  • child_locants (Tuple[int, int] | None) – Tuple of (loc1, loc2) child ring locants, or None

  • parent_letter (str | None) – Parent edge letter (‘a’, ‘b’, etc.), or None

  • multi_component (List[str] | None) – List of edge letters for multi-component fusion

  • multi_edge (List[Tuple[Tuple[int, int], str]] | None) – List of ((loc1, loc2), letter) for multi-edge fusion

Returns:

Formatted fusion descriptor string

Return type:

str

Examples

>>> format_complex_fusion((2, 3), 'b')
'[2,3-b]'
>>> format_complex_fusion(None, None, multi_component=['a', 'c'])
'[a,c]'
>>> format_complex_fusion(None, None, multi_edge=[((1, 2), 'a'), ((4, 5), "b'")])
"[1,2-a:4,5-b']"
orthonym.rules.fusion_descriptors.generate_multi_fusion_descriptor(parent_ring_name, fused_components)#

Generate fusion descriptor for multi-component fusions.

For compounds like dibenzo[a,c]anthracene where multiple rings of the same type are fused to a parent ring.

Parameters:
  • parent_ring_name (str) – Name of the parent ring (e.g., ‘anthracene’)

  • fused_components (List[Tuple[str, List[int], Set[int]]]) – List of (child_name, parent_ring_atoms, shared_atoms) tuples where each tuple describes one fused component

Returns:

Multi-component descriptor like ‘[a,c]’ for dibenzo Returns empty string if descriptor cannot be generated

Return type:

str

Examples

>>> # dibenzo[a,c]anthracene: two benzene rings at edges a and c
>>> generate_multi_fusion_descriptor('anthracene', [
... ('benzene', [0,1,2,3,4,5,6,7,8,9,10,11,12,13], {0, 1}),
... ('benzene', [0,1,2,3,4,5,6,7,8,9,10,11,12,13], {4, 5})
... ])
'[a,c]'
orthonym.rules.fusion_descriptors.build_multi_component_name(parent_name, child_name, count, descriptor)#

Build name for multi-component fusion (dibenzo, dinaphtho, etc.).

Parameters:
  • parent_name (str) – Name of parent ring (e.g., ‘anthracene’)

  • child_name (str) – Name of fused ring type (e.g., ‘benzene’)

  • count (int) – Number of fused rings of this type (2 for di-, 3 for tri-)

  • descriptor (str) – Fusion descriptor (e.g., ‘[a,c]’)

Returns:

Complete multi-component name like ‘dibenzo[a,c]anthracene’

Return type:

str

Examples

>>> build_multi_component_name('anthracene', 'benzene', 2, '[a,c]')
'dibenzo[a,c]anthracene'
>>> build_multi_component_name('anthracene', 'naphthalene', 2, '[a,h]')
'dinaphtho[a,h]anthracene'
orthonym.rules.fusion_descriptors.generate_systematic_name_for_fused_pair(mol, ring1, ring2, shared_atoms, allow_skeleton_match=False)#

Generate systematic fusion name for a pair of fused rings.

This is the main entry point for generating fusion names when no retained name exists. Uses IUPAC-numbered ring ordering for correct edge letters and child locants.

Parameters:
  • mol – RDKit Mol object

  • ring1 (List[int]) – List of atom indices in first ring

  • ring2 (List[int]) – List of atom indices in second ring

  • shared_atoms (Set[int]) – Set of atom indices shared between rings

Returns:

Systematic fusion name, or None if name cannot be generated

Return type:

str | None

Examples

>>> mol = Chem.MolFromSmiles('c1ccc2cc3ccccc3cc2c1') # anthracene
>>> ri = mol.GetRingInfo
>>> # Would generate 'benzo[a]naphthalene' for benzene fused to naphthalene
orthonym.rules.fusion_descriptors.generate_multi_fusion_name(mol, parent_ring, parent_name, fused_rings)#

Generate systematic name for multiple rings fused to a parent.

Handles complex fusion scenarios like dibenzo[a,c]anthracene where multiple rings of the same type are fused at different edges.

Parameters:
  • mol – RDKit Mol object

  • parent_ring (List[int]) – List of atom indices in the parent ring

  • parent_name (str) – Name of the parent ring (e.g., ‘anthracene’)

  • fused_rings (List[Tuple[List[int], Set[int]]]) – List of (child_ring_atoms, shared_atoms) for each fusion

Returns:

Complete systematic fusion name, or None if cannot be generated

Return type:

str | None

Examples

>>> # For dibenzo[a,c]anthracene
>>> generate_multi_fusion_name(mol, anthracene_atoms, 'anthracene',
... [(benzene1_atoms, {0,1}), (benzene2_atoms, {4,5})])
'dibenzo[a,c]anthracene'