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.
16:0— 16 carbons, saturated.18:1(9)— one double bond at Δ9, geometry not determined.18:1(9Z)— the same bond, determined as cis.20:4— four double bonds, none of them localised.
Separator semantics: / vs _
The separator between chains carries the regiochemistry, and is not cosmetic.
| Separator | Meaning | Example |
|---|---|---|
/ | sn-positions determined | PC 16:0/18:1(9Z) |
_ | sn-positions not determined | PC 16:0_18:1(9) |
| none | species level — only the totals are known | PC 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:
- A group on C1 of an acyl chain (
FA 18:0;1OMe) — there the shorthand names the ester or amide linkage, not a substituent. - A localised group combined with unlocalised double bonds when the group sits far enough along the chain to leave room for a bond on either side (
FA 18:2;5OH). The name states a total and never says how the bonds divide across the split. Give the positions (18:2(11,14);5OH) and it resolves. - Groups naming a class of attachment rather than one structure (
;G,;T,;oxy,;OO), and Table 1C carbohydrate headgroups, which never state the glycosidic linkage positions.
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.
| Undetermined | Encoded as | Source |
|---|---|---|
| Double-bond geometry | bare C=C | plain SMILES |
| Double-bond position | Sg: flexible run | CXSMILES standard |
| …and the length of that run | constrain(a+b=15) | LipidOracle extension |
| Modification position | m: position variation | CXSMILES standard |
| sn assignment | $snN$ atom labels | CXSMILES standard |
| …and permission to permute them | swappable(sn1,sn2) | LipidOracle extension |
| Confidence behind a double-bond call | dbPos(sn1:9@92,12@88) | LipidOracle extension |
| Confidence behind a modification's position | mPos(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)
- The molecule is an ordinary, connected, fully parseable phosphatidylcholine. Nothing is detached and nothing is missing.
- The
$…$block gives one;-separated slot per atom; the two non-empty slots name the ester oxygen each chain hangs from. swappable(sn1,sn2)says those labelled positions may be permuted.
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) | Depicted | Why |
|---|---|---|
Sg: runs | literal CH₂ carbons at one arbitrary even split | most depicters ignore Sg: and would draw a chain many carbons short |
$snN$ + swappable(...) | dropped | the 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:
- Under
s3_selection: posterior(the default since v1.0.173), each figure is that position's marginal probability under the posterior over candidates. - Under
s3_selection: legacy, it is the fraction of retained candidate hypotheses supporting the position — candidate support, not a calibrated probability.
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
- Lipid shorthand and ID levels: Liebisch G, et al. "Update on LIPID MAPS classification, nomenclature, and shorthand notation for MS-derived lipid structures." J Lipid Res. 2020;61(12):1539–1555.
- Lipid classification: Fahy E, et al. "Lipid classification, structures and tools." Biochim Biophys Acta. 2011;1811(11):637–647.
- CXSMILES specification: ChemAxon Extended SMILES and SMARTS.
- Reference implementation: lipidoracle-smiles.