orthonym.rules.benzene#
Note
Internal API. Names and behaviour may change between releases.
Benzene naming rules according to IUPAC 2013 (Blue Book).
Handles: - Monosubstituted benzenes (chlorobenzene, nitrobenzene) - Polysubstituted benzenes with numeric locants (1,4-dimethylbenzene) - Benzene ring orientation for lowest locants - Alphabetical ordering of substituents - Suffix functional groups on benzene (carboxylic acid, amide, sulfonamide, etc.)
IUPAC 2013 PIN Rules: - Numeric locants are REQUIRED (not ortho/meta/para) - Toluene is retained ONLY for unsubstituted methylbenzene - Substituted methylbenzene uses “methylbenzene” (not “toluene”) - Position 1 assigned to give lowest locants via first-point-of-difference - Ring-attached principal groups use suffix form - benzamide = retained name for C6H5CONH2
- orthonym.rules.benzene.benzene_prefix_suffix_promotion(suffix_names, prefix_names, detected_fgs=None, has_amine_candidates=False)#
THE single authority on which detachable prefix becomes the ring suffix.
Two questions must give the same answer and were previously computed twice:
name_substituted_benzene– which prefix does the NAME promote to the suffix? (a ring -OH is perceived as the prefixhydroxyand only becomes-olhere; likewise a promotable amine becomes-amine/aniline.)principal_group_ring_atoms– which ring atoms may criterion (c) therefore minimise the locants of?
⚠ Phase C Task 9b, root cause of C-2: (2) used to answer “the principal group has a prefix form that appears on this ring”, which is true for 76 of the 136 seniority names (every entry with both a ring suffix and a prefix) while (1) only ever promotes two of them. For the other 74, criterion (c) minimised the locant of a group the name still spells as a detachable prefix – INVERTING (f)/(g). Two answers that must agree and are computed twice is the defect shape, so both callers now read this one function.
- Parameters:
suffix_names – the suffix names already present (
suffix_groupskeys).prefix_names – the detachable prefix names present (
prefix_groupskeys).detected_fgs –
features.functional_groups, for the functional-class guard.has_amine_candidates (bool) – whether any ring amine carries the
amine_candidatepayload_identify_nitrogen_groupsets.
- Returns:
(promoted_suffix, promoted_prefix_names).(None, frozenset)when no promotion happens. For the amine promotion the prefix set is empty because the promoted atoms are identified by theamine_candidatemarker (the prefix may beamino,(N-methylamino),…), not by one name.- Return type:
Tuple[str | None, frozenset]
- orthonym.rules.benzene.is_benzene_ring(mol, ring_atoms)#
Check if a ring is a benzene ring (6-membered aromatic carbocycle).
- Parameters:
mol – RDKit Mol object
ring_atoms (Tuple[int, ...]) – Tuple of atom indices in the ring
- Returns:
True if ring is benzene (6 aromatic carbons)
- Return type:
bool
- orthonym.rules.benzene.didehydro_benzene_name(mol, ring_atoms)#
(Wave-2 completion): a bare benzene ring in which 2 (or 4) ring carbons carry NO hydrogen (RDKit perceives benzyne as an aromatic C6 ring with a triple bond) is the didehydrobenzene parent: ‘1,2-didehydrobenzene’ (BB verbatim; was ‘benzene’ -> unknown).
Fail-closed: exactly 6 neutral ring carbons, no exocyclic heavy neighbour anywhere (substituted didehydrobenzenes are not built), every ring atom has 0 or 1 H, dehydro count in {2, 4}. Locants = the minimal tuple over all 12 ring walks.
- orthonym.rules.benzene.get_benzene_ring(mol)#
Find the benzene ring in a molecule.
- Parameters:
mol – RDKit Mol object
- Returns:
Tuple of atom indices in the benzene ring, or None if not found
- Return type:
Tuple[int, …] | None
- orthonym.rules.benzene.get_benzene_substituents(mol, ring_atoms)#
Find substituents attached to each benzene carbon.
- Parameters:
mol – RDKit Mol object
ring_atoms (Tuple[int, ...]) – Tuple of atom indices in the benzene ring
- Returns:
Dict mapping ring atom index to list of substituent info dicts. Each dict has keys: ‘name’ (str), ‘atoms’ (list of atom indices)
- Return type:
Dict[int, List[Dict]]
- orthonym.rules.benzene.molecule_principal_group_and_fgs(mol)#
The molecule-level principal group AND the detected FGs, in ONE perception.
principal_group_ring_atomsneeds both, and detecting the functional groups twice for one molecule is the only reason the two were ever separate. Routes through the sameseniority.get_principal_groupauthority the namer uses, so the answer cannot diverge fromfeatures.principal_group. Fails closed to(None, None)(= legacy numbering) on any perception failure.
- orthonym.rules.benzene.principal_group_ring_atoms(mol, ring_atoms, substituents, principal_group=None, detected_fgs=None)#
(c): the ring atoms bearing the PRINCIPAL characteristic group.
This is the input to
orient_benzene’s criterion-0 tier. § “NUMBERING” (heading at the Blue Book) states at the Blue Book: “When several structural features appear in cyclic and acyclic compounds, low locants are assigned to them in the following decreasing order of seniority:”. That order ranks (c) principal characteristic groups and free valences (suffixes); (the Blue Book) four places ABOVE (f) detachable alphabetized prefixes, all considered together in a series of increasing numerical order; (the Blue Book) and five above (g) lowest locants for the substituent cited first as a prefix in the name; (the Blue Book). So the suffix locant set is minimised FIRST and the prefixes take what is left. Benzene has no fixed numbering (a, the Blue Book) and no indicated hydrogen (b, the Blue Book), so (c) decides whenever it applies.Every caller used to derive this set from the
is_suffixmarker alone, which made it EMPTY for phenols: a ring -OH is still spelled as the prefixhydroxywhen the ring is numbered and is promoted to the-olsuffix only later, insidename_substituted_benzene. Criterion (c) therefore never ran and criterion (f) handed locant 1 to the prefix – emitting1-chlorobenzene-2,3,4,5,6-pentolfor the PIN6-chlorobenzene-1,2,3,4,5-pentol.Whether the group IS promoted is not decided here: it is asked of
benzene_prefix_suffix_promotion, the single authorityname_substituted_benzenealso reads.⚠ Phase C Task 9b: this used to ask the seniority tables directly – “does
get_suffix(pg, is_ring=True)exist and isget_prefix(pg)on this ring?” – which is a test for promotion ELIGIBILITY, not promotion. 76 of the 136 seniority entries have both a ring suffix and a prefix form and only two are ever promoted, so for the other 74 criterion (c) was minimising the locant of a group the name still spells as a detachable prefix, inverting (f) and (g). The decision is still LOCANT-FREE – it depends only on WHICH groups are present, never on where – which is what lets it be consulted BEFORE the ring is numbered.is respected: only the SENIOR group is the principal characteristic
group.
principal_groupis the molecule-level answer fromseniority.get_principal_group, so a ring carrying both -ol and -thiol yields the -ol atoms only (matching the emitted2-sulfanylphenol, whose numbering hint previously contradicted the name by anchoring the thiol).FAILS TOWARD CURRENT BEHAVIOUR: whenever the answer is not available (no principal group, no ring suffix for it, nothing promoted,…) this returns the legacy
is_suffixunion, so the change is a strict improvement rather than a coin flip. In particular a ring with NO principal characteristic group –Cc1c(C)c(C)c(C)c(C)c1Cl– hasprincipal_group is Noneand returns the empty set, leaving criterion (c) vacuous and (f)+(g) legitimately in charge of1-chloro-2,3,4,5,6-pentamethylbenzene.- Parameters:
mol – RDKit Mol object (unused today; kept so callers pass the full context and a future rule can consult the graph without a signature change).
ring_atoms (Tuple[int, ...]) – The benzene ring’s atom indices.
substituents (Dict[int, List[Dict]]) – Dict from
get_benzene_substituents.principal_group (str | None) –
features.principal_group– the molecule-level PCG name fromseniority.get_principal_group.Nonedisables the promotion tier (legacy behaviour).detected_fgs (Dict | None) –
features.functional_groups, used only for the shared functional-class guard.
- Returns:
Set of ring atom indices bearing the principal characteristic group; empty when criterion (c) does not apply.
- Return type:
Set[int]
- orthonym.rules.benzene.benzene_prefix_citation_locants(oriented, substituents, principal_group_positions=None)#
(g): the per-prefix locant sets, in alphabetical CITATION order.
§** “NUMBERING”** (
the Blue Book Blue Book) criterion (g) (:3307) reads verbatim:(g) lowest locants for the substituent cited first as a prefix in the name;
worked at
:33154-methyl-5-nitrooctanedioic acid (PIN)and, decisively for a ring, at:33171-methyl-4-nitronaphthalene (PIN) (not 4-methyl-1-nitronaphthalene). The same rule is stated a second time, with a benzene worked example, as §** “Low locants are assigned to the prefix cited first in the name”** (:26085):1-bromo-2-chloroethane (PIN)and1-azido-4-isocyanatobenzene (PIN)(:26094).“Cited first” is the alphanumerical order, so the sequence is keyed on the shared
alpha_sort_key(di/tri ignored, iso/neo/cyclo/sec/tert included) rather than a hand-rolled sort. Every candidate orientation of one molecule carries the SAME set of prefix names, so only the locants differ and the returned tuple can be compared lexicographically.- A substituent is a prefix here unless it is the suffix:
atoms in
principal_group_positionsbear the principal characteristic group, so the group itself is criterion (c)’s business, not (g)’s – BUT any italic-N substituent it carries IS cited as a prefix in the name (N-(4-aminophenyl)-...) and therefore enters at that locant. Without this, two suffix instances distinguished ONLY by their N-substituents give an empty (g) key and the tie falls through to the canonical last resort, which orders by symmetry class rather than by citation – measured: it namedNc1ccc(Nc2ccc(Nc3ccccc3)cc2)cc1with(4-aminophenyl)on the HIGHER nitrogen, thoughaminoanilinois cited beforeanilino.an
is_suffixsubstituent outside that set is a JUNIOR suffix thatname_substituted_benzenedemotes back to its own prefix form, so it IS cited as a prefix and enters under_SUFFIX_TO_PREFIX;when no PCG set is supplied every
is_suffixsubstituent is the suffix, so all of them are excluded.
For a single-instance suffix this is a no-op: criterion (c) has already fixed that locant, so the entry is identical in every surviving candidate.
- Returns:
Tuple of locant tuples, ordered by the prefix’s citation position.
- Return type:
Tuple[Tuple[int, …], …]
- orthonym.rules.benzene.orient_benzene(mol, ring_atoms, substituents, principal_group_positions=None)#
Orient benzene ring to give lowest locants to substituents.
§** “NUMBERING”** (
the Blue Book Blue Book) is an ORDERED cascade. Benzene has no fixed numbering (a,:3227), no indicated hydrogen (b,:3246), no added indicated hydrogen (d,:3270), no saturation/unsaturation choice (e,:3288) and no skeletal atom in a nonstandard valence state (h,:3320), so the applicable criteria are exactly (c), (f), (g) – and the cascade must then TERMINATE IN THE STRUCTURE, never in the order RDKit happened to enumerate the ring:(c)
:3256principal characteristic groups and free valences (suffixes) – lowest locant SET for the principal characteristic group, four places above (f). Applied only whenprincipal_group_positionsis supplied;Nonedisables the tier.(f)
:3301detachable alphabetized prefixes, all considered together in a series of increasing numerical order, worked at:3305(“the locant set ‘4,5,8’ is lower than ‘4,7,8’”) – first point of difference over the substituted positions.(g)
:3307lowest locants for the substituent cited first as a prefix in the name, worked at:3315and:3317(1-methyl-4-nitronaphthalene (PIN) (not 4-methyl-1-nitronaphthalene)); restated as §:26085with the benzene PIN1-azido-4-isocyanatobenzene(:26094). Seebenzene_prefix_citation_locants.last resort canonical symmetry-class orbits (
_canonical_orbit_key) – a structure-derived invariant, so the answer cannot depend on how the molecule was spelled.
⚠ Phase C Task 9b: tiers 2 and 3 are new. Before them the cascade ended at (f) plus a crude “position 1 goes to the alphabetically first substituent AT position 1” heuristic, and fell through to candidate-enumeration order – which made the emitted name a function of the input SMILES. Tier 2 subsumes that heuristic: a (g) tie means every prefix holds the same locants in every surviving candidate, so the substituent at position 1 is the same too and the heuristic could not have discriminated either.
Monosubstituted rings short-circuit (the substituent is at locant 1), and an unsubstituted ring returns the input order because every orientation is the same name.
- Parameters:
mol – RDKit Mol object (required for the canonical last-resort tier)
ring_atoms (Tuple[int, ...]) – Tuple of atom indices in the benzene ring (ordered)
substituents (Dict[int, List[Dict]]) – Dict from get_benzene_substituents
principal_group_positions (Set[int] | None) – Optional set of ring atom indices bearing the principal characteristic group (c)). Default None = no PCG tier.
- Returns:
List of ring atom indices reordered so position 1 is first
- Return type:
List[int]
- orthonym.rules.benzene.name_substituted_benzene(mol, ring_atoms, oriented_ring, substituents, detected_fgs=None)#
Generate systematic name for substituted benzene.
IUPAC 2013 PIN Rules: - Use numeric locants (not ortho/meta/para) for polysubstituted - Monosubstituted benzenes do NOT include locant (it’s always 1) - Alphabetize substituent prefixes - Use multiplicative prefixes (di-, tri-) for repeated substituents - Format: locants-substituent-benzene (or just substituent-benzene for mono) - Special case: benzonitrile (C6H5CN) uses suffix-style naming per - Ring-attached principal groups use suffix form
- Parameters:
mol – RDKit Mol object
ring_atoms (Tuple[int, ...]) – Original ring atom tuple
oriented_ring (List[int]) – Oriented ring from orient_benzene
substituents (Dict[int, List[Dict]]) – Dict from get_benzene_substituents
- Returns:
IUPAC name string (e.g., “chlorobenzene” or “1,4-dimethylbenzene”), or None when any substituent is an unnameable sentinel (Wave2 T3a conservation guard: emitting without it would drop its atoms).
- Return type:
str
- orthonym.rules.benzene.name_benzene_derivative(mol)#
Generate name for a benzene derivative.
This is the main entry point for benzene naming.
- Parameters:
mol – RDKit Mol object
- Returns:
IUPAC name string, or None if not a benzene derivative
- Return type:
str | None