Nomenclature and CXSMILES

LipidOracle emits Shorthand2020 names — the notation defined by Liebisch et al. — as the canonical value of the name column, and extended CXSMILES as the canonical structure. Where the evidence does not determine a structure, the notation says so explicitly rather than guessing.

1. Shorthand 2020 conventions

Chain notation: C:DB(positions)

Each acyl or sphingoid chain is written as carbon count, double-bond count, and optionally the explicit double-bond positions in Δ-numbering from the carboxyl carbon.

Separator semantics: / vs _

The separator between chains carries the regiochemistry, and is not cosmetic.

SeparatorMeaningExample
/sn-positions determinedPC 16:0/18:1(9Z)
_sn-positions not determinedPC 16:0_18:1(9)
nonespecies level — only the totals are knownPC 34:1

A species-level name is a valid annotation but has no structure: the chain split is not determined, so SMILES generation returns nothing rather than inventing one.

Modifications

Functional groups follow a semicolon, with the position in front of the abbreviation, comma-separated within a group type: ;11OH,15OH;9oxo. Every group in Table 1A of Liebisch et al. that substitutes a single chain carbon is supported — hydroxyl, ketone, methyl, ethyl, methoxy, hydroperoxy, amino, thiol, nitrile, nitro, extra carboxyl, phosphate, sulfate and the halogens. Rings come from Table 1B: ;5Ep for an epoxide, ;[11-13cy3:0] for a carbocycle.

Legacy spellings are accepted and normalised. ;OH(11), ;hydroxy(11), ;oxo(5), ;ep(5) and ;cyc(3) all convert to the Table 1A form on input. Nothing in an existing library or config file needs rewriting.

Some names are rejected on purpose rather than guessed at:

2. Encoding ambiguity in CXSMILES

MS2 spectra frequently fail to determine a structure completely. Rather than picking one candidate arbitrarily, LipidOracle writes what was measured and marks what was not. Each kind of missing knowledge gets its own construct: where the CXSMILES standard has one, it is used as-is; where it has none, LipidOracle adds a token after the closing |, in the SMILES title field.

constrain(...), swappable(...), dbPos(...), and mPos(...) are non-standard extensions introduced by LipidOracle to describe properties that are not supported by the SMILES or CXSMILES standards.

UndeterminedEncoded asSource
Double-bond geometrybare C=Cplain SMILES
Double-bond positionSg: flexible runCXSMILES standard
…and the length of that runconstrain(a+b=15)LipidOracle extension
Modification positionm: position variationCXSMILES standard
sn assignment$snN$ atom labelsCXSMILES standard
…and permission to permute themswappable(sn1,sn2)LipidOracle extension
Confidence behind a double-bond calldbPos(sn1:9@92,12@88)LipidOracle extension
Confidence behind a modification's positionmPos(sn1:11OH@64)LipidOracle extension

The two "…and" rows are the pattern in miniature: CXSMILES can mark a variable run but not say how long it is, and can label an atom but not say the labels may trade places. The structural half goes inside the |...| block, correct and complete; the half the standard cannot express goes after it.

A fully determined structure has no |...| tail at all. The presence of a tail is itself a signal that something was left open.

sn-position undetermined → sn* labels

When chains are separated by _, the molecule is written out completely, with one representative assignment, and two annotations say the assignment is a choice rather than a measurement.

PC 16:0_18:1(9)
↓
C(COP(=O)([O-])OCC[N+](C)(C)C)(OC(=O)CCCCCCCC=CCCCCCCCC)COC(=O)CCCCCCCCCCCCCCC
|$;;;;;;;;;;;;;sn2;;;;;;;;;;;;;;;;;;;;;sn1$| swappable(sn1,sn2)

Why this shape. Two earlier encodings tried to keep the chains outside the molecule so the ambiguity would be structural — first an f: component group, then an RG: R-group with the chains as alternative definitions. Both were unreadable to common tooling, and decisively, the RG: form could not coexist with Sg:: CDK rejects a nested CXSMILES block inside an R-group definition, so a name carrying both kinds of ambiguity had to abandon one. An R-group also states the wrong cardinality — read the ordinary way it admits PC 16:0/16:0 as well, and 27 assignments for a TG where the name allows 6. Labelling a complete molecule gives up the formal Markush semantics and gets back everything else: every toolkit reads the structure, and the ambiguities compose freely.

What it does not say. swappable(...) permits any permutation of the labelled positions. For two chains that is exactly right; for four (cardiolipin) it is weaker than the truth.

Double-bond position undetermined → Sg: block

LipidOracle does not guess a position. Every unlocalised double bond contributes a flexible-run marker plus an algebraic size constraint tying the markers together.

FA 20:4   (20 carbons, 4 double bonds, positions unknown)
↓
OC(=O)CC=CC=CC=CC=CC |Sg:n:3:a:ht,Sg:n:5:b:ht,Sg:n:7:c:ht,Sg:n:9:d:ht,Sg:n:12:e:ht| constrain(a+b+c+d+e=14)

Five markers for four double bonds — one run before the first bond, then one per bond. constrain(a+b+c+d+e=14) requires the five variable runs to sum to 14 carbons, so the chain still totals 20 carbons with exactly 4 double bonds somewhere in it.

Modification position undetermined → m: block

A modification written with a position (;5OH) is drawn at that carbon and gets no block at all. Only the position-less form needs one.

DG 18:0/18:2(9,12);OH
↓
C(CO)(OC(=O)CCCCCCCC=CCC=CCCCCC.*O)COC(=O)CCCCCCCCCCCCCCCCC
|m:23:6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22|

The hydroxyl is appended as its own *O component, and m: — a CXSMILES position-variation bond — says atom 23 attaches to exactly one of the listed carbons, C2 through C18. C1 is excluded: it is the ester carbonyl, not a substitutable methylene.

Atom 23 is the *, not the oxygen. A position-variation bond's variable end must be a dummy atom carrying exactly one bond. CDK silently ignores an m: block pointing anywhere else and other toolkits reject the string outright, so the component is written *O: the * takes the variable bond, the O is the hydroxyl it carries. The oxygen adds no carbon, so the formula stays exact. Every unlocalised group follows the same shape — *=O for a ketone, *C(=O)O for an extra carboxyl, *[N+](=O)[O-] for a nitro.

Stored string vs depicted image

The structure view does not draw the stored string verbatim. Before depiction it is rewritten, and the rewrite is deliberately lossy in two respects.

Stored (exact)DepictedWhy
Sg: runsliteral CH₂ carbons at one arbitrary even splitmost depicters ignore Sg: and would draw a chain many carbons short
$snN$ + swappable(...)droppedthe molecule underneath is already complete; only the note that the assignment was arbitrary is lost

What that costs: a depicted double-bond position is a representative candidate, not a determination, and the image alone cannot distinguish a depicted Δ6 from a measured one. Trust the stored string; read the image as a diagram.

Two things worth knowing if you consume the SMILES column. A renderer that ignores Sg: fails silently — no warning, just a molecule with most of the chain missing — which is the dangerous case precisely because it looks like it worked. And the trailer does not survive a round trip through a toolkit: the |...| block is renumbered correctly, but constrain(...) and swappable(...) live in the title field and are dropped, leaving Sg: runs with no length and snN labels with no permission to permute. Preserve the trailer yourself if something rewrites these strings.

CXSMILES output is validated against CDK, the reference implementation for this encoding and the renderer used for every depiction in the dashboard.

3. Localisation confidence

At idlevel 4, where positions are consolidated across candidates, the confidence behind each call is appended to the name in brackets:

FA 20:4;11OH [C=C: Δ5 100%, Δ8 100%, Δ12 100% | Δ14 50% or Δ15 50%; OH: 11 100%]

Positions are comma-separated and each carries its own support. Aspects (DB, OH, oxo) and chains are separated by ;. Read this as: a hydroxyl is present and the evidence puts it at C11 with full support; three double bonds are called at Δ5/Δ8/Δ12 with no dissent, and the fourth is supported half at Δ14 and half at Δ15.

Note where the hydroxyl position lives — in the tail, not the name body. Writing it into the body (FA 20:4;11OH [...]) would make the name unrepresentable, because a group positioned mid-chain alongside unlocalised double bonds does not say how those bonds divide around it. Leaving the group unpositioned in the body and stating its position as consensus is both representable and a truer record of what was measured.

The same numbers ride along in the CXSMILES, anchored to labels:

OC(=O)CC=CC=CC=CC=CC.*O
|$;sn1;;;;;;;;;;;;OH1$,Sg:n:3:a:ht,Sg:n:5:b:ht,Sg:n:7:c:ht,Sg:n:9:d:ht,Sg:n:12:e:ht,m:13:3.4.5.6.7.8.9.10.11.12|
constrain(a+b+c+d+e=14);dbPos(sn1:5@100,8@100,12@100,14@50,15@50);mPos(sn1:11OH@100)

Read the two halves separately. The CXSMILES commits only to what the evidence determines: the markers all stay and no position is asserted. The trailer then adds the odds. Converting back recovers the name in full, percentages included.

What the percentage means

It depends on which selection method produced it, and the two are not interchangeable:

See Acyl-chain analysis for how candidates are retained and why the default changed.

Consensus percentages apply per chain and are independent of sn-position ambiguity:

PC 16:0_18:1 [C=C sn2: Δ9 80% or Δ11 20%]
   ↑                    ↑
   │                    └─ within that chain, Δ9 is favoured 4:1 over Δ11
   └─ which chain is sn-1 vs sn-2 was not determined

If you need every alternative as its own row rather than as odds on one row, read the full annotation CSV: it preserves the confidence tail in name and lists each candidate individually at idlevel 3.

References