Rdisop mass decomposition (`decomposeMass`)
Rdisop_decomposeMass.RmdAlgorithms: Böcker et al. (DECOMP / Money Changing Problem). See Bioconductor vignette Mass decomposition with the Rdisop package.
1. High-level workflow (formula calculator)
m/z + polarity/adduct + ppm + element set
↓
1. Convert ion m/z → neutral (or charged) mass consistently
↓
2. Enumerate formulas (Rdisop::decomposeMass / decomposeIsotopes)
↓
3. Filter chemically (parity, H/C, heteroatom rules, DBE / Senior)
↓
4. Rank (ppm, RDBe, isotope fit if MS1 pattern available)
↓
5. Return tidy table of candidates
| Input | Role | Example |
|---|---|---|
mz / mass
|
Measured ion m/z or neutral mass | 203.0526 |
ppm / mzabs
|
Mass tolerance |
5 ppm |
z |
Charge (sign = polarity) |
+1 / -1
|
adduct |
Optional ion type |
[M+H]+, [M-H]-
|
elements |
Allowed CHNOPS… | C,H,N,O |
Decide explicitly whether the input is ion m/z or
neutral mass. Do not mix “neutral mass +
z = 1” unless that is intentional.
Important: z does not convert m/z →
formula mass
Rdisop’s z is not a full ESI
charge-state converter.
| Call | What z actually does |
|---|---|
decomposeMass(..., z = k) |
Does not multiply the input by \|k\|.
Same mass with z = 1 or z = 2
yields the same formulas (mass window still centered on
the value you passed). z mainly affects charge-related
bookkeeping (e.g. parity / validity / how masses are reported). |
getMolecule(formula, z = k) |
Adjusts by
,
then for
divides so the returned value looks like an
m/z. Example: C4H7N6O4 → ~203.05
(z = 0/1) vs ~101.53 (z = 2),
i.e. . |
Empirical check (mass = 203.0526, CHNO, 5 ppm):
getFormula(decomposeMass(203.0526, ppm = 5, z = 1, elements = elements))
# C4H7N6O4, C3H11N2O8, ...
getFormula(decomposeMass(203.0526, ppm = 5, z = 2, elements = elements))
# same list — still ~203 Da formulas, not ~406 Da
getMass(getMolecule("C4H7N6O4", z = 2))
# ~101.5259 ← display m/z only, not what decomposeMass searchesCorrect pre-conversion before calling
decomposeMass (bare charge / electron correction; adducts
still separate):
For m/z = 203.0526, z = 2 you must
decompose ~406.1 Da, not 203 and not 101.5.
-
101.5 is what
getMolecule(..., z = 2)reports for a ~203 Da formula (output m/z). - 406 is the mass scale of a 2+ ion whose observed m/z is 203.
MassTools::calcMF only does mz + z * m_e
then calls decomposeMass — it also does
not multiply by |z|, so it has the same
gap for
.
Rule for a formula calculator: convert m/z → search
mass yourself (mz * |z| ± z*me and/or adduct correction via
MSCC), then call decomposeMass(..., z = 0) (or
z = ±1 only if you intentionally want ion-parity semantics
on an already-converted mass).
In the MSdev / MSCC split:
| Layer | Responsibility |
|---|---|
| Rdisop | Enumerate candidates from mass |
| MSCC | Adduct mass, formula format, isotope pattern |
| MSdev | Call calculator on features (mzmed), attach
candidate.formula
|
2. What decomposeMass does
decomposeMass is a thin wrapper:
decomposeMass(mass, ppm, ...)
→ decomposeIsotopes(c(mass), intensity = 1, ...)
→ C++ Money-Changing / mass-decomposition solver
Core problem (Money Changing Problem / MCP):
Find non-negative integers such that
lies within the mass tolerance window.
Typical R call:
library(Rdisop)
elements <- initializeElements(c("C", "H", "N", "O"))
results <- decomposeMass(
mass = 203.0526,
ppm = 5,
z = 1,
elements = elements
)
getFormula(results)Useful accessors: getFormula(), getMass(),
getScore(), getValid(),
getIsotope().
With measured isotope peaks, prefer
decomposeIsotopes(masses, intensities, ...) — same
enumeration core, better ranking.
3. Internal steps
target mass + ppm (+ mzabs)
│
▼
build element alphabet (monoisotopic masses), sorted by mass
│
▼
MCP / mass decomposition
→ all integer vectors n with |Σ n·m − mass| ≤ tol
│
▼
optional chemical validity (DBE, nitrogen rule, …)
│
▼
molecule objects (formula, exactmass, score, isotopes, …)
4. Brute force vs Rdisop
Naive enumeration (nested loops over atom counts) scales roughly as — exponential in the number of element types when bounds grow with mass.
Rdisop / DECOMP does not do that. It uses efficient MCP algorithms (dynamic programming + smart backtracking; Böcker & Lipták):
- Finds all compositions whose mass falls in the tolerance window
- Runtime is typically closer to proportional to the number of solutions, not to a full nested-loop lattice walk
- Far better memory profile than classical full DP tables for this problem
So: yes, it enumerates all mass-matching compositions for the allowed elements; no, it is not a dumb “try every combination” search.
5. Does adding elements explode the cost?
Yes in practice — mainly because the solution space grows, not because the search is naive.
| Factor | Effect |
|---|---|
| More element species | Larger alphabet → more ways to hit the same mass → more candidates |
| Higher mass | More atoms possible → more solutions |
Wider ppm / mzabs
|
Wider window → more solutions |
| Algorithm | MCP-style; pay per solution + DP overhead, not nested loops |
Rdisop’s vignette notes that the result list grows with mass, allowed ppm, and the allowed elements list.
6. Practical controls
- Keep the alphabet small (CHNO or CHNOPS first).
- Tighten
ppm/mzabs. - Use
minElements/maxElementsto cap atom counts. - Prefer
decomposeIsotopeswhen M+1 / M+2 intensities exist. - Post-filter (H/C ranges, RDBE, nitrogen rule) and keep top- by ppm / score.
- Expect a sharp jump in candidates when adding Cl, Br, metals, or many heteroatoms.
7. Suggested return table
After decomposition, tidy to something like:
| Column | Meaning |
|---|---|
formula |
Sum formula string |
exactmass |
Calculated exact mass |
ppm |
|
score |
Rdisop / isotope score |
DBE / valid
|
Chemical plausibility hints |
8. Bottom line
-
decomposeMassreturns essentially all compositions for the allowed elements that fit the mass window. - The engine is an MCP algorithm, not brute-force nested loops.
- Adding element types still hurts a lot: the number of valid formulas grows combinatorially, so CPU and memory grow with output size.
-
zis not a substitute for m/z → mass conversion. For , multiply (and correct electrons/adducts) yourself before decomposing. - A usable formula calculator = charge/adduct mass handling + Rdisop enumeration + chemical filters + ranking (isotope / DB).