orthonym.rules.spiro_polyspiro#

Note

Internal API. Names and behaviour may change between releases.

unbranched polyspiro ring systems with different components, one of them polycyclic.

The chain builder behind spiro.name_unbranched_polyspiro_different: the components are named one by one (spiro._name_spiro_component), cited in alphanumerical order and joined by the spiro locants. It lives in its own module because spiro.py is over the size budget.

Governing rules (the Blue Book Blue Book): * ‘Unbranched polyspiro ring systems with different ring components one being a polycyclic

ring system’ (:10705): “Unbranched polyspiro ring systems with at least two different ring components and at least one of which is a polycyclic ring are named by placing the ring component names in order of their occurrence in the structure beginning with the terminal ring component lower in alphabetical order and enclosing within square brackets.”

  • (:10719): “If there is a choice of locants, the lowest set of locants for all spiro atoms is selected when compared in increasing numerical order and, if there is still a choice, in order of their citation in the name”.

  • NUMBERING (:3219), (f) “detachable alphabetized prefixes, all considered together in a series of increasing numerical order” (:3301): after the spiro atoms, a substituent takes the lowest locant its ring allows, whatever the atom order of the input.

A SUBSTITUTED system (allow_substituents): the bare ring system is named as for the unsubstituted one and its atom -> locant map is returned; the caller attaches the prefixes to that map. A ring that touches no spiro atom hangs off the chain by an exocyclic bond and is a substituent, not a component. The map is the one the descriptor cites: a fused component is re-anchored to its descriptor locant (spiro._reanchor_locmap_to_canonical_spiro), a monocycle component takes the substituent tie-break of its own namer, and two terminals with one name are ordered by spiro._terminal_orientation_key. Only the best-effort tier asks for it: the PIN path keeps the unsubstituted-only reading (the composer’s is_unbranched_polyspiro_different).

orthonym.rules.spiro_polyspiro.ring_blocks(mol)#

The ring components of mol read from its ring BONDS, not from the smallest set of smallest rings: the biconnected components of the graph of ring atoms and ring bonds, as [(atoms, spiro_atoms, ring_count)]. A spiro atom is an atom shared by two components. RDKit drops one of the equal faces of a cage (adamantane keeps 3 of its 4 six-membered rings, which ones depends on the atom order), so an atom of a cage that is a spiro atom can sit in 2 or in 3 of the rings it lists; the components do not change with the choice.

orthonym.rules.spiro_polyspiro.name_polyspiro_different_core(mol, *, allow_substituents=False, restrict_atoms=None)#

(name, all_ring_atoms, combined_locants) of the linear terminal-middle-terminal chain, or None. combined_locants maps each ring atom of the chain to its locant (an int for the first cited component, (int, "'") and (int, "''") for the next two). Fails closed unless the system is a 3-component, 2-spiro-atom chain with a polycyclic component and not all components identical (that is dispiroter). restrict_atoms: only the ring components inside this atom set count (a molecule can hold several ring systems; the floor names them one at a time).