orthonym.rules.ions#
Note
Internal API. Names and behaviour may change between releases.
Ion naming rules per IUPAC 2013.
Handles naming of: - Anions: carboxylates (-ate), alkoxides (-olate), phenolates, aminides, carbanions (-ide) - Cations: aminium (-aminium), carbenium/ylium (-ylium), onium, diazonium
IUPAC 2013 References: -: Anion nomenclature -: Cation nomenclature
Key naming patterns: - Carboxylate anions: acetic acid -> acetate - Alkoxide anions: methanol -> methanolate (PIN) or methoxide (acceptable) - Aminium cations: amine -> aminium (protonated amine) - Carbenium cations: alkane -> ylium (loss of H-)
- orthonym.rules.ions.classify_anion(mol, anion_site)#
Classify anion type based on the anionic atom environment.
Examines the local chemical environment of the anionic atom to determine the appropriate naming suffix.
- Parameters:
mol – RDKit Mol object
anion_site (Dict[str, Any]) – Dictionary from get_ion_sites containing: - atom_idx: int - charge: int - element: str - hybridization: str - n_hydrogens: int
- Returns:
One of –
- ‘carboxylate’, ‘alkoxide’, ‘phenolate’, ‘aminide’,
’carbanion’, ‘thiolate’, or ‘unknown’
- Return type:
str
Example
>>> mol = Chem.MolFromSmiles('CC(=O)[O-]') >>> sites = get_ion_sites(mol) >>> classify_anion(mol, sites['anions'][0]) 'carboxylate'
- orthonym.rules.ions.classify_cation(mol, cation_site)#
Classify cation type based on the cationic atom environment.
Examines the local chemical environment of the cationic atom to determine the appropriate naming suffix.
- Parameters:
mol – RDKit Mol object
cation_site (Dict[str, Any]) – Dictionary from get_ion_sites containing: - atom_idx: int - charge: int - element: str - hybridization: str - n_hydrogens: int
- Returns:
One of – ‘aminium’, ‘ylium’, ‘onium’, ‘diazonium’, or ‘unknown’
- Return type:
str
Example
>>> mol = Chem.MolFromSmiles('[NH4+]') >>> sites = get_ion_sites(mol) >>> classify_cation(mol, sites['cations'][0]) 'aminium'
- orthonym.rules.ions.name_carboxylate_anion(parent_name)#
Convert carboxylic acid name to carboxylate anion name.
Transformation rules: - ‘ic acid’ -> ‘ate’ (e.g., acetic acid -> acetate) - ‘oic acid’ -> ‘oate’ (e.g., propanoic acid -> propanoate)
- Parameters:
parent_name (str) – Parent acid name (e.g., ‘acetic acid’, ‘propanoic acid’)
- Returns:
Anion name (e.g., ‘acetate’, ‘propanoate’)
- Return type:
str
Example
>>> name_carboxylate_anion('acetic acid') 'acetate' >>> name_carboxylate_anion('propanoic acid') 'propanoate'
- orthonym.rules.ions.name_alkoxide_anion(parent_name, style='pin')#
Convert alcohol name to alkoxide anion name.
IUPAC 2013 PIN style uses -olate (methanolate, ethanolate). Common style uses -oxide (methoxide, ethoxide).
- Parameters:
parent_name (str) – Parent alcohol name (e.g., ‘methanol’, ‘ethanol’)
style (str) – ‘pin’ for -olate, ‘common’ for -oxide
- Returns:
Anion name
- Return type:
str
Example
>>> name_alkoxide_anion('methanol') 'methanolate' >>> name_alkoxide_anion('methanol', style='common') 'methoxide'
- orthonym.rules.ions.name_phenolate_anion(parent_name)#
Convert phenol name to phenolate anion name.
- Parameters:
parent_name (str) – Parent phenol name (e.g., ‘phenol’)
- Returns:
Anion name (e.g., ‘phenolate’)
- Return type:
str
Example
>>> name_phenolate_anion('phenol') 'phenolate'
- orthonym.rules.ions.name_aminium_cation(parent_name)#
Convert amine name to aminium cation name.
- Parameters:
parent_name (str) – Parent amine name (e.g., ‘methanamine’, ‘ethylamine’)
- Returns:
Cation name (e.g., ‘methanaminium’, ‘ethylaminium’)
- Return type:
str
Example
>>> name_aminium_cation('methanamine') 'methanaminium' >>> name_aminium_cation('ammonia') 'ammonium'
- orthonym.rules.ions.name_carbenium_cation(parent_name)#
Convert alkane/alkyl name to carbenium (ylium) cation name.
The ylium suffix indicates loss of hydride (H-) from the parent.
- Parameters:
parent_name (str) – Parent name (e.g., ‘methane’, ‘methyl’)
- Returns:
Cation name (e.g., ‘methylium’)
- Return type:
str
Example
>>> name_carbenium_cation('methane') 'methylium' >>> name_carbenium_cation('ethane') 'ethylium'
- orthonym.rules.ions.get_anion_suffix(anion_type)#
Get the appropriate suffix for an anion type.
- Parameters:
anion_type (str) – Type from classify_anion
- Returns:
Suffix string (e.g., ‘ate’, ‘olate’, ‘ide’)
- Return type:
str
- orthonym.rules.ions.get_cation_suffix(cation_type)#
Get the appropriate suffix for a cation type.
- Parameters:
cation_type (str) – Type from classify_cation
- Returns:
Suffix string (e.g., ‘ium’, ‘ylium’, ‘aminium’)
- Return type:
str
- orthonym.rules.ions.emit_bis_quaternary_aminium(mol, cation_sites)#
Substitutive ‘-bis(aminium)’ PIN for two quaternary ammonium centres on the ends of a straight carbon chain:
C[N+](C)(C)CCCCCC[N+](C)(C)C -> N1,N1,N1,N6,N6,N6-hexamethylhexane-1,6-bis(aminium)
The rule: an N+ carrying carbon groups is a cationic AMINE, named by the cationic suffix ‘aminium’, the Blue Book; ‘N,*N*,*N*- trimethylmethanaminium (PIN)’:41438, not ‘tetramethylazanium’:41354). Two of them on one chain take the suffix twice: “Polycations with cationic centers on characteristic groups are named by substitutive nomenclature or multiplicative nomenclature” (:42138), with the quaternary ‘*N*^1,*N*^1,*N*^3,*N*^3,*N*^3-hexamethylpropanebis(amidium) (PIN)’ (:42154) and ‘butanebis(nitrilium) (PIN)’ beside the non-PIN multiplicative ‘butanediylidynebis(azanium)’ (:42160,:42162); ‘3-(azaniumylmethyl) pentane-1,5-bis(aminium) (PIN)’ (:42366). The chain between the two N is the parent: it is the only chain that carries both suffixes. The N-substituents take N-locants with the chain locant as superscript (written ‘N1’, ‘N6’;:26348), in alphanumerical order.
SCOPE (fail closed, ‘’ on anything else): exactly two acyclic N+ with no H and four carbon neighbours; one unbranched saturated all-carbon bridge of >= 2 atoms between them (
_walk_linear_carbon_bridge); the same multiset of N-substituent names on both ends, so the bridge’s two numbering directions are equivalent. The name ships only on a full-InChIKey round trip.
- orthonym.rules.ions.emit_bis_quaternary_ammonium(mol, cation_sites)#
/ (a phase): a SYMMETRIC dication with exactly two IDENTICAL quaternary-ammonium centres joined by a straight, saturated, unbranched, unsubstituted all-carbon bridge is named as a multiplicative assembly of parent cations:
{bridge parent-diyl}bis({onium unit}) C[N+](C)(C)CCCCCC[N+](C)(C)C -> hexane-1,6-diylbis(trimethylazanium)
(BB, cf. the PIN example ‘(1,4-phenylene)bis(phosphanium)’ and ‘4,4′-(ethane-1,2-diyl)bis(1-methylpyridin-1-ium)’.)
SCOPE (fail closed, i.e. return ‘’, on anything else — asymmetric onium substituents, >2 cations, a ring-borne cationic centre, or a branched/heteroatom-bearing/unsaturated bridge; the caller’s existing fallback then owns the molecule unchanged):
exactly 2 cation sites, each N, formal charge +1, 0 attached H, degree 4 (quaternary,, NOT in a ring.
the two nitrogens are joined by a SINGLE simple, unbranched, saturated, acyclic, all-carbon bridge (
_walk_linear_carbon_bridge) of length >= 2 – this both bounds scope and guarantees the bridge is trivially symmetric (its two numbering directions are equivalent by construction, so locants 1 and n are forced with no orientation choice to make).the two onium substituent sets (
cation_to_prefix(..., as_free_ion= True)on each N, reusing the existing zwitterion-onium-prefix machinery) must be BYTE-IDENTICAL strings – the “two units identical” requirement.
- orthonym.rules.ions.name_anion(mol, style='pin', _depth=0, retained_only=False)#
Generate IUPAC name for an anionic molecule.
Workflow: 1. Get canonical SMILES 2. Check retained names (unless systematic style) 3. Detect anion sites 4. Classify anion type 5. Generate systematic name
- Parameters:
mol – RDKit Mol object (must have negative charge)
style (str) – Naming style (‘pin’, ‘systematic’, ‘common’)
_depth (int) – Internal recursion depth guard (do not set manually)
retained_only (bool) – If True, only check retained names and return None if no retained name found (used for namer.py fall-through).
- Returns:
Anion name (e.g., ‘acetate’, ‘methoxide’, ‘phenolate’), or empty string if naming fails. When retained_only=True, returns None if no retained name found.
- Return type:
str
Example
>>> mol = Chem.MolFromSmiles('CC(=O)[O-]') >>> name_anion(mol) 'acetate'
- orthonym.rules.ions.name_cation(mol, style='pin', _depth=0, retained_only=False)#
Generate IUPAC name for a cationic molecule.
Workflow: 1. Get canonical SMILES 2. Check retained names (unless systematic style) 3. Detect cation sites 4. Classify cation type 5. Generate systematic name
- Parameters:
mol – RDKit Mol object (must have positive charge)
style (str) – Naming style (‘pin’, ‘systematic’, ‘common’)
_depth (int) – Internal recursion depth guard (do not set manually)
retained_only (bool) – If True, only check retained names and return None if no retained name found (used for namer.py fall-through).
- Returns:
Cation name (e.g., ‘ammonium’, ‘methylammonium’, ‘methylium’), or empty string if naming fails. When retained_only=True, returns None if no retained name found.
- Return type:
str
Example
>>> mol = Chem.MolFromSmiles('[NH4+]') >>> name_cation(mol) 'ammonium'
- orthonym.rules.ions.apply_ion_suffix_to_name(name, total_charge, allowed_suffixes=None, cation_class=None)#
The SINGLE ionic-suffix re-application primitive for every charged class.
Generalized from
_ionize_acid_name(169.6-02 / CHOKE-02). Re-applies the class-correct ionic suffix to a re-entered NEUTRAL name (the output ofOrthonym(style).name(neutral_smiles)). Drives the structured resolvers seam (_apply_anion_modification/_apply_cation_modificationoff the canonical_ANION_SUFFIX_MAP/_CATION_SUFFIX_MAP) — single source of truth, NEVER a per-molecule.replaceband-aid (fix-methodology.md).Two paths:
cation_classin {ylium, acylium, diazonium} -> the class-keyed transform table_CLASS_KEYED_CATION_TRANSFORMS(these are NOT plain suffix swaps and depend on the neutralized form, internal notes):ylium (carbenium): parent-hydride
ane->``ylium`` (methane->``methylium``;;methyliumis the PIN).acylium: on the ACID name,
oic acid->``oylium`` /carboxylic acid->``carbonylium``.diazonium: append
diazoniumto the hydride name.
Otherwise the generic map-driven path (anion/protonated-amine etc.): longest trailing neutral suffix in the relevant SUFFIX_MAP wins.
allowed_suffixes(GUARD 1 — theheptanolatefix): when given, ONLY those neutral suffixes are eligible for the trailing match, so a name ending “…sulfonic acid” withallowed_suffixes={"ol"}returns ‘’ (it cannot mis-fire to-olate).classify_anionpasses the per-class subset so a sulfonate stem can never be mistaken for an alkoxide. Applies to the generic (map) path only; the class-keyed cation path is already class-gated.Returns the ionized name, or ‘’ if no canonical transform applies (the caller then falls through to the existing cascade — byte-identical contract).
The ion keeps the neutral name’s PIN status: a recorded non-PIN fragment in
name(decision A’s demoted ‘N-<acyl>’ float,…) does not survive the suffix swap, so the ionized name is recorded too (metrics.provenance.record_derived_non_pin_fragment).
- orthonym.rules.ions.emit_parent_hydride_cumulative_suffix(mol, center_idx, suffix)#
Name a parent hydride with a cumulative anionic / radical / cationic suffix on a single carbon centre, with a FIRST-CLASS locant.
- suffix in {‘ide’, ‘ium’, ‘yl’, ‘ylidene’, ‘ylidyne’}.
‘ide’ -> / Table 3.4 (anion, loss of H+) ‘yl’/’ylidene’/’ylidyne’ -> / Table 3.4 (radical, loss of H.) ‘ium’ -> (cation; reserved for later reuse)
center_idx is the atom index OF THE CHARGED/RADICAL CARBON ON
mol(the index-preserving mol passed in — NOT a freshly canonicalized copy; canonical SMILES reorders atoms, RESEARCH Pitfall 1). The centre gets the LOWEST locant over the re-found chain, competing with unsaturation and substituents per/ (
orient_chaincriterion (a), principal_group_atoms ={center_idx}). This is a NEW numbering call (“locants identify positions of the negative charges”, the Blue Book lines 40876-40902), NOT a reused -ol / FG anchor and NOT a hand-rolled carbon-counting scan.
Returns ‘’ on any failure (caller falls through to legacy).
- orthonym.rules.ions.emit_mono_ionized_polyfunctional(mol, ion_idx, kind)#
Name a mono-ionized ACYCLIC polyfunctional chain, demoting the identical NEUTRAL sibling groups to prefixes (see _MONO_IONIZED_SPEC / /.
ion_idxis the charged heteroatom index on the index-preservingmol. Fail-closed (’’ -> caller keeps the legacy single-group path) for any shape outside the tight scope: a ring, a substituted / secondary sibling, no sibling (the ordinary single-group case), an extra substituent on the chain, or a chain the acyclic machinery cannot number. Accuracy first: never emit a wrong name.
- orthonym.rules.ions.emit_parent_hydride_polyvalent_suffixes(mol, centers)#
/ multi-site free-valence (polyradical) PIN on ONE acyclic all-carbon parent hydride.
centers=[(atom_idx, n_electrons)]withn_electrons in {1, 2, 3}and >= 2 DISTINCT centers (the single-center case isemit_parent_hydride_cumulative_suffix’s job). Returns the polyradical PIN (ethane-1,2-diyl,propane-1,2,3-triyl,pentane-2,4-diylidene, the mixedethan-1-yl-2-ylidene, …) or''(fail closed) on anything out of scope.Generalizes the single-center primitive above to N carbon free-valence centers: saturate every centre on one index-preserving RWMol, choose the longest carbon chain carrying ALL centers (a): the parent must retain the maximum radical centers — demoting a centre to an off-parent prefix is out of v1 scope, so refuse rather than drop), then number by
— “low locants to the free valences as a SET, then in the order
‘yl’, ‘ylidene’, ‘ylidyne’”. Substituents/unsaturation reuse the same machinery as the single-center primitive. ‘’ on any unnameable piece.
- orthonym.rules.ions.emit_poly_carbanion_ide(mol, centers)#
(BB 40902): a MULTI-carbanion on one acyclic all-carbon parent hydride — >= 2 carbon -ide centres — named with the ‘-ide’ suffix and the numerical multiplier ‘di’/’tri’: ‘ide’ takes basic multipliers).
centers= the carbanion atom indices. Returns e.g. ethynediide ([C-]#[C-], BB 40918), methanediide ([CH2-2]), butane-1,4-diide, or ‘’ on any out-of-scope shape (fail closed).Mirrors emit_parent_hydride_polyvalent_suffixes (saturate every centre on one index-preserving RWMol -> longest chain carrying ALL centres -> orient for lowest locants to the -ide set), but the ending is ‘-<locs>-<mult>ide’. Locant elision, ‘no ambiguity’): the anionic locants are OMITTED when they occupy EVERY carbon of the chain (a single unambiguous placement: ethyne->ethynediide, methane->methanediide); the unsaturation locant is likewise omitted for a 2-carbon parent (ethyne/ethene carry none).
- orthonym.rules.ions.emit_poly_cation_ylium(mol, centers)#
(the Blue Book): a MULTI-carbenium on one acyclic all-carbon parent hydride — carbon -ylium free valences totalling >= 2 across ring-free carbons that each lost a hydride H- — named with the ‘-ylium’ compound suffix multiplied by ‘bis’/’tris’ (the Blue Book note: ‘bis(ylium)’ NOT ‘diylium’, so the COMPLEX multiplier series, mirroring the poly-aminium ‘bis(aminium)’ rule, not the basic ‘di’ the -ide anion uses).
centers= the carbenium atom indices; a centre bearing charge +2 counts as TWO -ylium valences on one atom (the geminal degenerate, C[C+2]C). Returns e.g.ethane-1,2-bis(ylium)([CH2+][CH2+]),propane-1,3-bis(ylium)([CH2+]C[CH2+]),propane-2,2-bis(ylium)(C[C+2]C), or ‘’ on any out-of-scope shape (fail closed -> caller abstains, never a wrong bis-name).Mirrors
emit_poly_carbanion_ide(saturate every centre — +1 H per unit of positive charge — on one index-preserving RWMol -> longest chain carrying ALL centres -> orient for lowest locants to the -ylium set), but the ending is ‘-<locs>-<bis/tris>(ylium)’. Unlike the -ide anion, the ylium locants are ALWAYS cited (never elided): the examples keep them even when the set covers every carbon (ethane-1,2-bis(ylium), notethanebis(ylium)).
- orthonym.rules.ions.emit_halogen_onium(mol, center_idx)#
(the Blue Book “diphenyliodanium (PIN)”, the Blue Book “…are the preferred IUPAC names and not those given in Table 7.3”): name a disubstituted halogen(III) cation R2X+ on the halogen parent hydride with the ‘-ium’ suffix. The exact CATION mirror of
_emit_group13_uide(which buildsdiphenyliodanuideon the anion side): ligands become prefixes on the ‘-ium’ parent cation.(C6H5)2I+ -> diphenyliodanium (PIN) [the Blue Book]
Scope (fail closed, so a mono-coordinate halonium / a genuine radical cation / any non-halogen never matches): the centre is a halogen in
_HALOGEN_ONIUM_STEMS(I/Br/Cl/F), formal charge +1, and degree >= 2 (a hypervalent halonium — a 1-coordinate R-X+ is a distinct sulfanylium-style species and is excluded). Every heavy atom must be covered by the emitted ligand set (atom-drop veto, identical to the uide emitter —classify_substituentnames carbon groups by carbon count and silently drops a heteroatom in the branch, so a mismatch declines).Named DIRECTLY: a drop-charge neutralize yields an invalid neutral halogen radical, and an add-H neutralize yields the λ-parent whose ‘-ium’ form (
…-λ3-iodanium, a 4-coordinate [IH2+]) is NOT the PIN. No λ-convention is used —diphenyliodanium(the Blue Book) carries none, exactly asdiphenyliodanuide(the Blue Book) carries none. Returns ‘’ on any decline (the caller falls through).
- orthonym.rules.ions.emit_chalcogen_ylium(mol, center_idx)#
(BB 41565 phenylsulfanylium PIN): name a 1-coordinate chalcogen cation R-S+ / R-Se+ as
<R-prefix>sulfanylium/<R-prefix>selanylium.Scope (tight, so oxonium/sulfonium/phosphonium are never disturbed — they return ‘’ here): the centre is S or Se, formal charge +1, ZERO hydrogens, and exactly ONE heavy neighbour which is a CARBON substituent R (alkyl/aryl). R is named via classify_substituent; a complex R gets enclosing marks: (2,2-dichloroethyl)sulfanylium). Acyl R (R-CO-S+) and R-S-S+ (disulfanylium) are out of scope -> ‘’. Returns ‘’ on any decline (caller falls through).
- orthonym.rules.ions.emit_onium_hydride_parent(mol, center_idx)#
(the Blue Book “Cationic compounds derived from… suffixes”; “ethylideneoxidanium (PIN)”:41463, “acetyloxidanium (PIN)”:41474): a single mononuclear chalcogen cation centre (O/S/Se/Te, +1, NOT in a ring, NOT bonded to another chalcogen) carrying substituents (alkyl / acyl / alkylidene) + optional remaining H is named on the mononuclear parent hydride oxidane/sulfane/selane/tellane + ‘-ium’, its substituents cited as detachable prefixes – the systematic PIN, NOT the Table-7.3 ‘-onium’ spelling , general only) nor the ‘-a’/’-onia’-replacement form: CC=[OH+] -> ethylideneoxidanium, not 1-oxaprop-1-en-1-ium.
Mirrors
emit_halogen_onium/_emit_group13_uidein SHAPE: substituents named by TYPE from the bond order to the centre (classify_substituentmis-names the ylidene =CHCH3 and the acyl CH3CO- both ‘ethyl’), an atom-drop veto over the whole heavy-atom count, and ‘’ on ANY decline so the caller’s RT gate can never be handed a mis-built name. The substituent-prefix assembly (citation order, multipliers, and the enclosing marks that make ‘benzoyldi(methyl)sulfanium’, BB 16286 ‘tert-butyldi(methyl)phosphane’) follows the same rules ascatenated_hydrides._try_aba_parent(called fromname_heterochalcogen_aba) – the sibling substituent-prefix assembler – via the shared naming_utils primitives, so no ordering or marking rule is re-spelled here; the ~18-line assembly loop below is a PARALLEL implementation of that sequence (generalized from its local count table to get_multiplier_prefix), not a call into shared code – part of the deferred locant/prefix-render duplication (internal notes). A catenated chalcogen-chalcogen cation (dioxidane, disulfane; the ‘-C(=O)-O-[OH2+]’ -> dioxidan-1-ium family) is out of scope and declines. Returns ‘’ on any decline.
- orthonym.rules.ions.emit_catenated_hydride_cation(mol, center_idx)#
(the Blue Book “General rule for systematically naming cationic centers in parent hydrides”; examples:41386-41390): a CATENATED homonuclear parent-hydride cation, or a SUBSTITUTED mononuclear pnictogen cation, named on the parent hydride + ‘-ium’ at the cationic-centre locant.
CN(C)[N+](C)(C)C -> pentamethylhydrazinium (PIN) CS[S+](C)SC -> 1,2,3-trimethyltrisulfan-2-ium (PIN) C[P+](C)(C)Cl -> chlorotri(methyl)phosphanium (PIN) C[P+](C)(C)P(Cl)Cl -> 2,2-dichloro-1,1,1-trimethyldiphosphan-1-ium (PIN) O=C(O[OH2+])c1ccccc1 -> 2-benzoyldioxidan-1-ium (PIN)
Approach (a trace-confirmed: neutralize-re-enter is structurally impossible for a 0-H fully-substituted onium/quaternary centre, and even where a neutral is formable the neutral namer names a DIFFERENT parent – benzenecarboperoxoic acid, not benzoyldioxidane): name the BARE homonuclear parent chain by re-entering the neutral namer (
_bare_parent_hydride_name-> trisulfane / hydrazine / diphosphane / dioxidane / phosphane – so the multiplier / retained tables are NOT re-spelled here), number the chain giving the cationic centre the lowest locant /, cite the substituents as detachable prefixes, and append ‘-{loc}-ium’ with ‘e’-elision. Substituents named by TYPE (halogen / acyl-on-chalcogen / organyl) with a whole-heavy-atom drop veto; ‘’ on ANY decline so the caller’s RT gate never sees a mis-built name. A chalcogen MONONUCLEAR onium is out of scope (emit_onium_hydride_parent owns it) as is a mononuclear N (the aminium path).The hydrazine (retained N-N parent) fully-substituted cation omits all locants per the example ‘pentamethylhydrazinium (PIN)’ (and: every substitutable position of hydrazinium bears the one identical group).
- orthonym.rules.ions.emit_zwitterion_ring_carboxylate(mol, cation_idx, anion_idx)#
F- (DD3,: a zwitterion whose cationic centre is a RING atom of the same ring that bears a carboxylate anion -> the cumulative
<prefixes><ring>-<cation-locant>-ium-<carboxyl-locant>-carboxylatename, the cationic suffix cited before the anionic one.[O-]C(=O)c1ccc[nH+]c1 -> pyridin-1-ium-3-carboxylate C[n+]1ccccc1C(=O)[O-] -> 1-methylpyridin-1-ium-2-carboxylate C[n+]1c(C(=O)[O-])cc(-c2ccccc2)cc1-c1ccccc1 -> 1-methyl-4,6-diphenylpyridin-1-ium-2-carboxylate
the last being the Blue Book’s own worked (PIN) example,
:42456, under ** “Zwitterionic compounds with at least one ionic center on a characteristic group”** (heading:42445).ONE numbering for the whole name. This emitter previously ran two branches that each took the ring numbering from the namer’s neutral-ring supplier and then concatenated a separately-built cation-substituent prefix onto the resulting substituted ring name. Two different numberings met in one string. Measured consequences on the DEFAULT path, all of which round-trip cleanly through OPSIN — the molecule is right and only the spelling is wrong, so neither the round-trip metric nor could see them:
1-methyl4-methylpyridin-1-ium-2-carboxylate— no hyphen, and1-methyl+4-methylnever merged to1,4-dimethyl;1-methyl4-bromopyridin-1-ium-2-carboxylate— ‘bromo’ must precede ‘methyl’ alphanumerical order);1-methyl2,4-dimethylpyridin-1-ium-6-carboxylate— the carboxylate numbered 6 where:42447requires 2.
and one that did catch, turning it into an abstention rather than a wrong molecule:
1-propylpyridin-1-ium-2-carboxylatefor an isopropyl group, because the old branch named substituents with the carbon-countingclassify_substituent.- So the numbering is now derived ONCE over the ORIGINAL charged mol, with the
anion-attachment criterion
(
_charged_ring_locants(..., anion_attach_idx=...)); every ring substituent is located in THAT numbering by_p74_ring_substituent_prefix; and the stem comes from a ring stripped of all of them.Fails closed (‘’) whenever a part is uncorroborated — a fused/bridged ring (no simple cycle, so no numbering), a substituent the authoritative namer cannot spell, or a formal charge anywhere outside the cation/anion pair. The caller then falls through to the legacy path.
- orthonym.rules.ions.express_junior_anionic_chalcogens(mol, anions, ionized)#
The name of a multi-anion whose parent is an S/P-oxoacid anion and whose other anionic centres are chalcogen anions (-O-/-S-): the junior centres are cited by their anionic prefixes, ‘oxido’ / ‘sulfido’,:41223 “–O– oxido (preselected prefix)”,:41225 “–S– sulfido (preselected prefix)”), never by the neutral ‘hydroxy’ / ‘sulfanyl’, which drops a charge and denotes a different molecule (‘5-hydroxybenzene-1,3-disulfonate’ is the dianion, not the trianion).
ionizedis the neutral acid name with its parent suffix already made anionic (‘5-hydroxybenzene-1,3-disulfonate’). Returns ‘’ unless:every anionic centre is either an S/P-oxoacid centre (sulfonate / sulfinate / phosphonate: the parent) or a chalcogen anion of ONE kind (phenolate/alkoxide -> oxido, or thiolate -> sulfido); a carboxylate belongs to the carboxylate path;
(:41261, “CHOICE OF AN ANIONIC PARENT STRUCTURE”) picks the oxoacid parent: (a):41265 “parent with the maximum number of anionic centers, including anionic suffixes” – so the junior centres may not outnumber the oxoacid centres (for [O-]CC([O-])CS(=O)(=O)[O-] the bis(olate) parent has more centres; that shape is left to a producer that builds it); a tie goes on to (d):41281 (O > S: a sulfonate beats a thiolate) and (e):41289, the suffix seniority of (sulfonic and phosphonic acids are senior to alcohols), as in the BB’s “3-oxidonaphthalene-2-carboxylate (PIN) (carboxylate senior to olate)” (:41295);
the neutral prefix occurs exactly as often as there are junior centres (a genuine neutral -OH / -SH is never converted);
the result round-trips to the input at the full InChIKey.
A swap that may change the prefix citation order is shipped demoted, never as pin_verified (
_demote_if_swap_changes_citation_rank).
- orthonym.rules.ions.emit_uronium(mol, sites)#
(the Blue Book) substituted URONIUM / THIOURONIUM cation.
Task 8B RC3. A cation formed by adding a hydron to (iso)urea — a carbon bonded to exactly two N and one O (uronium) or one S (thiouronium), one C=heteroatom double bond, net +1 on the skeleton — is named on the retained parent cation
uronium/thiouronium: numerical locants are dropped in the PIN; the N/N’/O/S locants follow urea/isourea). ->CNC(=[NH+]C)Oc1ccccc1 -> N,N’-dimethyl-O-phenyluronium (the Blue Book) CNC(=[NH+]c1ccccc1)SC -> N,S-dimethyl-N’-phenylthiouronium (the Blue Book)
The neutralize -> re-name -> re-suffix path CANNOT reach this class: the neutral isourea names as a carbamimidate ESTER (
phenyl N,N'-dimethylcarbamimidate), not a uronium-convertible amine. So this is a bespoke skeleton producer.Locant priming: the two nitrogens are N / N’; the nitrogen bearing the alphabetically-earliest substituent takes the unprimed N (lowest locant to the prefix cited first). The chalcogen is O or S. Identical substituents group under one multiplier (
N,N'-dimethyl); the C-substituent prefixes alphabetise.Scope (build-the-class-or-degrade): requires >= 1 substituent (the UNSUBSTITUTED parent keeps its retained-name routing) and a single skeleton cation, else returns ‘’ (fail closed). Guanidinium (three N) never matches. The caller RT-gates the result, so a mis-built name fails closed rather than shipping a wrong structure.
- orthonym.rules.ions.name_quaternary_aminium(mol, cation_site)#
Systematic
-aminiumPIN for a STANDALONE quaternary ammonium cation.a phase.1 method (1) + Table 7.4; the Blue Book:41354, 41429-41438): a quaternary N (formal charge +1, 0 H, degree >= 4) is named by treating the SENIOR carbon chain through N as the amine parent (
-aminesuffix), the other three N-branches asN,N,N-/N,N-/N-substituent prefixes, then appending-ium(methanamine->methanaminium):C[N+](C)(C)C -> ‘N,N,N-trimethylmethanaminium’ OCC[N+](C)(C)C -> ‘2-hydroxy-N,N,N-trimethylethan-1-aminium’ CC[N+](C)(C)CC -> ‘N-ethyl-N,N-dimethylethanaminium’
Mechanism : the quaternary N CANNOT be neutralized — removing a (non-existent) proton leaves an over-valent neutral N and SanitizeMol raises (RESEARCH Pitfall 2). Instead the N is DEMOTED to a neutral carbon-context amine parent: a
tertiary_aminefunctional-group match is injected on the ORIGINAL (still-charged) mol and forced as the principal group, sofind_principal_chainselects the senior chain THROUGH N as the parent and the remaining N-branches become N-locant prefixes (NOTselect_parent, NOT theazaniumylprefix). The well-formed neutral amine name is then converted to-aminiumvianame_aminium_cation(the existing amine->aminium text transform). NO postprocessor, NO regex band-aid, NO per-molecule.replace.Returns ‘’ (fail-closed) when the cation is NOT a quaternary N or any step fails, so callers fall through to the proven aminium / legacy cascade (the no-crash byte-identical contract).
- orthonym.rules.ions.emit_cumulative_ium_ide(mol)#
cumulative same-parent zwitterion: one cationic (‘-ium’) and one anionic (‘-ide’) skeletal centre on the SAME homogeneous heteroatom chain parent hydride. Covers amine imides, azo/azomethine imides /.2) and carbonyl oxides:
C[N-][N+](C)(C)C -> 1,2,2,2-tetramethylhydrazin-2-ium-1-ide (BB 42423) C[N+]([N-]C)=NC -> 1,2,3-trimethyltriaz-2-en-2-ium-1-ide (BB 43121) C[N-][N+](=C)C -> 1,2-dimethyl-2-methylidenehydrazin-2-ium-1-ide (BB 43143) CC(C)=[O+][O-] -> 2-(propan-2-ylidene)dioxidan-2-ium-1-ide (BB 43187)
Numbering: anionic suffixes get seniority for low locants (so the ‘-ide’ locant is minimised before the ‘-ium’ locant); the cationic suffix is cited FIRST in the name (‘<stem>-<ium>-ium-<ide>-ide’). Fail-closed (None).
- orthonym.rules.ions.emit_ylide(mol)#
‘ylide’: a closed-shell onium cation X+ (X = N/P/O/S/…, no free H) bonded directly to a carbanion Y-. Named (method 1 = PIN) as the carbanion ‘-ide’ parent hydride with the onium cation as an ‘<…>-aniumyl’ prefix:
C[N+](C)(C)[C-](C)C -> 2-(trimethylazaniumyl)propan-2-ide C[P+](C)(C)[C-](C)C -> 2-(trimethylphosphaniumyl)propan-2-ide (BB 42526) CC[C-](CC)[O+](C)C -> 3-(dimethyloxidaniumyl)pentan-3-ide CC[C-](CC)[S+](C)C -> 3-(dimethylsulfaniumyl)pentan-3-ide C[N-][O+]=C(C)C -> N-[(propan-2-ylidene)oxidaniumyl]methanaminide
The anion parent is a carbanion (‘-ide’) OR a nitrogen aminide (‘-aminide’, ; the latter carries the cation prefix at the ‘N’ locant.
The nitrogen PIN is the amine-based ‘2-(N,N-dimethylmethanaminiumyl)propan-2- ide’, but that form is OPSIN-unparseable; the azane-based ‘trimethylazaniumyl’ equivalent (which OPSIN accepts) is emitted instead (W4-I4). Fail-closed.