orthonym.rules.phane#
Note
Internal API. Names and behaviour may change between releases.
Cyclic phane parent hydride nomenclature (IUPAC.
Detects molecules whose topology fits the IUPAC “cyclic phane” class (two or more disjoint small rings linked by acyclic chain segments of length >= 2 atoms whose linkage closes a macrocyclic ring; mutually exclusive with ring-assembly, spiro/fused/bridged- fused, and multiplicative cases).
Public API:
is_cyclophane(mol) -> bool– topology gatename_cyclophane(mol) -> Optional[str]– top-level handler_classify_phane_topology(mol) -> PhaneTopology– sub-class enum_build_composite_locant(ring_idx, ring_locant, style)– composite-locant emitter_enumerate_inter_ring_chains(mol, small_rings)– BFS chain walkerPhaneTopology– enum
Source:
155-internal notes (mutual-exclusion topology gate; corrected SSSR criterion per internal notes-A.md Critical Finding 0).
155-internal notes (sub-class enum {PARACYCLOPHANE, METACYCLOPHANE, ORTHOCYCLOPHANE, GENERIC_CYCLOPHANE}).
155-internal notes (composite-locant dual rendering: ASCII default, Unicode superscript option).
155-internal notes (mutual-exclusion contract enforced at the topology gate; a phase pattern – canonical helper reuse via
multiplicative._is_pure_single_bond_assembly).155-internal notes (root-cause-only; no postprocessor band-aids).
internal notes-A.md Critical Finding 0 (wording correction: SSSR-based criterion replaces the merged-ring-system phrasing because cyclophane macrocycles share atoms with both small rings, merging into a single ring system via
perception.rings.get_ring_systems).IUPAC 2013 Blue Book “Cyclic Phane Parent Hydrides”.
- class orthonym.rules.phane.PhaneTopology(*values)#
Bases:
EnumCyclophane sub-class per IUPAC.
Source: 155-internal notes; internal notes-A.md
- PARACYCLOPHANE = 'paracyclophane'#
- METACYCLOPHANE = 'metacyclophane'#
- ORTHOCYCLOPHANE = 'orthocyclophane'#
- GENERIC_CYCLOPHANE = 'generic'#
- orthonym.rules.phane.is_cyclophane(mol)#
Return True iff
molmatches the IUPAC cyclophane topology.Topology gate (corrected per internal notes-A.md Critical Finding 0):
>= 2 disjoint SSSR rings of size <= 8 (small / linker rings).
>= 1 macrocyclic SSSR ring of size > 8.
Shortest atom-disjoint chain between two small rings has >= 2 intermediate atoms minimum bridge length).
The chain shares atoms with at least one macrocyclic SSSR ring (i.e., the linkage closes a cycle, not an acyclic substituent).
Mutual exclusion: NOT pure single-bond ring assembly (a phase territory; canonical helper reuse via
multiplicative._is_pure_single_bond_assembly).
Returns False for None input.
Source: 155-internal notes +; internal notes-A.md Critical Finding 0.
- class orthonym.rules.phane.SkeletonClass(*values)#
Bases:
Enumsimplified-skeleton structural class. Deliberately separate from
PhaneTopology(the legacy para/meta/ortho sub-class enum used by the semi-systematic composer / is_cyclophane gate) to avoid churn in test_phane.py.- ACYCLIC = 'acyclic'#
- MONOCYCLIC = 'monocyclic'#
- VON_BAEYER = 'von_baeyer'#
- SPIRO = 'spiro'#
- class orthonym.rules.phane.Amplificant(atoms, ring_atoms_ordered, parent_name, attachment_atoms)#
Bases:
objectOne amplificant (ring/ring-system replacing a superatom) in a simplified phane skeleton.
- Variables:
atoms (FrozenSet[int]) – frozenset of atom indices making up the amplificant ring.
ring_atoms_ordered (Tuple[int, ...]) – the RDKit SSSR cyclic-order atom-index tuple for this ring (needed for _ring_distance to compute the amplificant’s OWN attachment-locant set,.
parent_name (str) – the OPSIN-parseable PIN parent-hydride name of the isolated ring (e.g. “benzene”). Task 8.1 scope this phase: benzene only – any other ring makes _simplify return None (fail closed; the disallowed-parent gate is future-phase work once more parent kinds are supported).
attachment_atoms (Tuple[int, ...]) – the (exactly 2, this phase) ring atom indices bonded to a skeleton (bridge) neighbour.
- atoms: FrozenSet[int]#
- ring_atoms_ordered: Tuple[int, ...]#
- parent_name: str#
- attachment_atoms: Tuple[int, ...]#
- class orthonym.rules.phane.PhaneStructure(mol, amplificants, bridge_atoms, skeleton_class, node_cycle)#
Bases:
objectSimplified-skeleton structure produced by _simplify (Task 8.1).
- mol: Mol#
- amplificants: Tuple[Amplificant, ...]#
- bridge_atoms: FrozenSet[int]#
- skeleton_class: SkeletonClass#
- node_cycle: Tuple[Tuple[str, int], ...] | None#
- orthonym.rules.phane.build_phane_pin(mol)#
Assemble the simplified-skeletal PIN for
mol, or None.Task 8.7 scope: MONOCYCLIC skeleton, all amplificants IDENTICAL benzene rings sharing the SAME attachment-locant set contraction). Every other class (mixed amplificants, von Baeyer/spiro skeletons, substituents, ‘a’-replacement) is fail-closed this phase – see the module docstring above Task 8.1 and Tasks 8.9-8.11.
Source: BB /.2.2.1/.2.3/.3.1/.3.2/.3.2.1/.4.1.1; anchor 1,4(1,4)-dibenzenacyclohexaphane,:14947); meta homolog 1,4(1,3)-dibenzenacyclohexaphane,:15024).
- orthonym.rules.phane.name_cyclophane(mol)#
Emit the IUPAC simplified-skeletal PIN for
mol, or None.Wave-8 P8: delegates to build_phane_pin (Task 8.7), which builds the /.3/.4 simplified-skeleton PIN (1,4(1,4)-dibenzenacyclohexaphane) for the monocyclic all-benzene-homophane class. Falls back to the legacy semi-systematic bracket-prefix composer ([m.n]paracyclophane) ONLY for topologies build_phane_pin doesn’t (yet) cover, so is_cyclophane- positive molecules outside the PIN scope still get some name from the pre-existing (production-withheld, unit-tested) composer rather than silently returning None here – the dispatch-level fail-closed decision is made in dispatch_table._handle_cyclophane (Task 8.12), not here.
Returns None for None input or non-cyclophane topology.
Source: 155-internal notes +; internal notes-A.md +; docs/the workflow tooling/plans/2026-07-16-wave8-p8-phane.md Task 8.7.
- orthonym.rules.phane.is_seven_plus_ring_assembly(mol)#
True iff
molis >= 7 ring systems joined only by single bonds (the trigger). Detection only — used by the scope guard’s contract tests; does NOT drive emission.
- orthonym.rules.phane.linear_phane_scope_guard(mol)#
Fail-closed boundary for linear-phane PIN generation.
ALWAYS returns None: the linear-phane amplification engine, >= 7 nodes) is not implemented in Wave-2 P2. Present so (a) the boundary is contract-tested and (b) a future engine has a named seam. Never emits a (possibly wrong) phane name. BB (the Blue Book).